OpenSDN source code
health_check.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include "http_parser/http_parser.h"
6 
7 #include <boost/uuid/uuid_io.hpp>
8 #include <boost/algorithm/string/case_conv.hpp>
9 
10 #include <cmn/agent_cmn.h>
11 
12 #include <vnc_cfg_types.h>
13 #include <agent_types.h>
14 
15 #include <init/agent_param.h>
16 #include <cfg/cfg_init.h>
17 
18 #include <ifmap/ifmap_node.h>
19 #include <cmn/agent_cmn.h>
21 #include <oper/config_manager.h>
22 #include <oper/agent_sandesh.h>
23 #include <oper/instance_task.h>
24 #include <oper/interface_common.h>
25 #include <oper/metadata_ip.h>
26 #include <oper/health_check.h>
27 
28 #include <oper/vn.h>
29 #include <oper/vrf.h>
30 
32 
35 
37 ("/usr/bin/contrail-vrouter-agent-health-check.py");
38 
40 
42  MetaDataIpAllocator *allocator,
43  VmInterface *intf,
44  bool ignore_status_event) :
45  service_(NULL), intf_(intf),
46  ip_(new MetaDataIp(allocator, intf, MetaDataIp::HEALTH_CHECK, service->IsInstanceTaskBased())),
47  last_update_time_("-"), deleted_(false),
48  ignore_status_event_(ignore_status_event) {
49  // start with health check instance state as active, unless reported
50  // down by the attached health check service, so that the existing
51  // running traffic is not affected by attaching health check service
52  active_ = true;
53  ip_->set_active(true);
55  intf->InsertHealthCheckInstance(this);
56  }
58 }
59 
61  VmInterface *intf = static_cast<VmInterface *>(intf_.get());
62  if (!service_.get()->IsVnIpListHealthCheckService()) {
63  intf->DeleteHealthCheckInstance(this);
64  }
65  ResyncTarget(service_.get());
66 }
67 
69  Interface *itf) const {
70  DBRequest req;
72  req.key.reset(new VmInterfaceKey(AgentKey::RESYNC, itf->GetUuid(), ""));
73  req.data.reset(new VmInterfaceHealthCheckData());
74  service->table()->agent()->interface_table()->Enqueue(&req);
75 }
76 
78  const {
79  EnqueueResync(service, intf_.get());
80 }
81 
83  // It is possible that the instance is queued for deletion at this point
84  // since this can be called in the Agent::heathCheck Task, don't need to
85  // set the service in this case because it is not needed.
86  if (deleted_)
87  return;
88  if (service_ == service) {
90  return;
91  }
92  // The instance is not expected to be associated with different instance
93  // during its lifetime. Adding a check to make sure that service is null
94  // in this case.
95  assert(service_ == NULL);
96  service_ = service;
98 }
99 
101  std::string str("Instance for service ");
102  str += service_->name();
103  str += " interface " + intf_->name();
104  return str;
105 }
106 
107 void HealthCheckInstanceBase::OnRead(const std::string &data) {
108  HealthCheckInstanceEvent *event =
109  new HealthCheckInstanceEvent(this, service_.get(),
111  data);
112  service_->table()->InstanceEventEnqueue(event);
113 }
114 
115 void HealthCheckInstanceBase::OnExit(const boost::system::error_code &ec) {
116  HealthCheckInstanceEvent *event =
117  new HealthCheckInstanceEvent(this, service_.get(),
119  service_->table()->InstanceEventEnqueue(event);
120 }
121 
123  HealthCheckInstanceEvent *event =
127 }
128 
130  HealthCheckInstanceEvent *event =
134 }
135 
137  if (source_ip_.is_unspecified()) {
138  VmInterface *itf = static_cast<VmInterface *>(interface().get());
139  if (itf) {
140  source_ip_ = itf->GetGatewayIp(itf->primary_ip_addr());
141  }
142  }
143  return source_ip_;
144 }
145 
147  if (source_ip_.is_unspecified() && ip_)
148  return ip_->service_ip();
149  return source_ip_;
150 }
151 
153  if (destination_ip_.is_unspecified() && ip_)
154  return ip_->destination_ip();
155  return destination_ip_;
156 }
157 
159  ip_->set_destination_ip(ip);
161 }
162 
164 
166  MetaDataIpAllocator *allocator,
167  VmInterface *intf,
168  bool ignore_status_event) :
169  HealthCheckInstanceBase(service, allocator, intf, ignore_status_event),
170  task_(NULL) {
171 }
172 
174 }
175 
177  if (task_.get() != NULL) {
178  return false;
179  }
180 
181  assert(deleted_ == false);
182 
183  HEALTH_CHECK_TRACE(Trace, "Starting " + this->to_string());
184 
185  task_.reset(new HeathCheckProcessInstance("HealthCheckInstance", "", 0,
186  service_->table()->agent()->event_manager()));
187  if (task_.get() != NULL) {
188  task_->set_pipe_stdout(true);
189  task_->set_on_data_cb(
190  boost::bind(&HealthCheckInstanceBase::OnRead, this, _2));
191  task_->set_on_exit_cb(
192  boost::bind(&HealthCheckInstanceBase::OnExit, this, _2));
193  return RunInstanceTask();
194  }
195 
196  return false;
197 }
198 
200  if (deleted_) {
201  return true;
202  }
203 
204  if (task_.get() == NULL) {
205  return false;
206  }
207 
208  HEALTH_CHECK_TRACE(Trace, "Deleting " + this->to_string());
209  deleted_ = true;
211  return true;
212 }
213 
216  return task_->Run();
217 }
218 
220  task_->Stop();
221  return true;
222 }
223 
225  if (service_->table()->agent()->test_mode()) {
226  // in test mode, set task instance to run no-op shell
227  task_->set_cmd("sleep 1");
228  return;
229  }
230 
231  std::stringstream cmd_str;
232  cmd_str << kHealthCheckCmd << " -m " << service_->monitor_type();
233  cmd_str << " -d " << ip_->GetLinkLocalIp().to_string();
234  cmd_str << " -t " << service_->timeout() +
235  service_->timeout_usecs() / 1000000;
236  cmd_str << " -r " << service_->max_retries();
237  cmd_str << " -i " << service_->delay() +
238  service_->delay_usecs() / 1000000;
239 
240  if (service_->monitor_type().find("HTTP") != std::string::npos &&
241  !service_->url_path().empty()) {
242  // append non empty url string to script for HTTP
243  cmd_str << " -u " << service_->url_path();
244  }
245 
246  task_->set_cmd(cmd_str.str());
247 }
248 
250  return (task_.get() != NULL ? task_->is_running(): false);
251 }
252 
254 
256  HealthCheckService *service, MetaDataIpAllocator *allocator,
257  VmInterface *intf, VmInterface *other_intf, bool ignore_status_event,
258  bool multi_hop) :
259  HealthCheckInstanceBase(service, allocator, intf, ignore_status_event),
260  other_intf_(other_intf), multi_hop_(multi_hop), bfd_up_(false) {
261  if (service->IsSegmentHealthCheckService() && other_intf) {
262  other_intf->InsertHealthCheckInstance(this);
263  }
264 }
265 
267  if (up) {
268  bfd_up_ = true;
269  return;
270  }
271 
272  if (!bfd_up_) {
273  // BFD reports its initial state as Down when the session is created.
274  // Do not tear down the BGP flow until this session has been Up.
275  return;
276  }
277 
278  bfd_up_ = false;
279  if (!bfd_down_callback_.empty()) {
281  }
282 }
283 
285  if (service()->IsSegmentHealthCheckService() && other_intf_.get()) {
286  VmInterface *vmi = static_cast<VmInterface *>(other_intf_.get());
287  vmi->DeleteHealthCheckInstance(this);
289  }
290 }
291 
293  assert(deleted_ == false);
294  HealthCheckService::HealthCheckType type = service_->health_check_type();
295  HEALTH_CHECK_TRACE(Trace, "Starting " + this->to_string());
296  assert(type == HealthCheckService::SEGMENT ||
298  if (service_->table()->health_check_service_callback(type).empty() ||
299  service_->table()->health_check_service_callback(type)
300  (HealthCheckTable::CREATE_SERVICE, this) == false) {
301  HEALTH_CHECK_TRACE(Trace, "Failed to start " + this->to_string());
302  return false;
303  }
304  return true;
305 }
306 
308  if (deleted_) {
309  return true;
310  }
311 
312  HealthCheckService::HealthCheckType type = service_->health_check_type();
313  if (!service_->table()->health_check_service_callback(type).empty()) {
314  HEALTH_CHECK_TRACE(Trace, "Deleting " + this->to_string());
315  service_->table()->health_check_service_callback(type)
317  }
318 
319  deleted_ = true;
320  return false;
321 }
322 
324  HealthCheckService::HealthCheckType type = service_->health_check_type();
325  if (!service_->table()->health_check_service_callback(type).empty()) {
326  HEALTH_CHECK_TRACE(Trace, "Run Instance " + this->to_string());
327  assert(type == HealthCheckService::SEGMENT ||
329  return service_->table()->health_check_service_callback(type)
331  }
332  HEALTH_CHECK_TRACE(Trace, "Run Instance failed " + this->to_string());
333  return false;
334 }
335 
337  HealthCheckService::HealthCheckType type = service_->health_check_type();
338  if (!service_->table()->health_check_service_callback(type).empty()) {
339  HEALTH_CHECK_TRACE(Trace, "Stop Instance " + this->to_string());
340  return service_->table()->health_check_service_callback(type)
342  }
343  return false;
344 }
345 
347  bool success = false;
348  HealthCheckService::HealthCheckType type = service_->health_check_type();
349  if (!service_->table()->health_check_service_callback(type).empty()) {
350  HEALTH_CHECK_TRACE(Trace, "Updating " + this->to_string());
351  assert(type == HealthCheckService::SEGMENT ||
353  success = service_->table()->health_check_service_callback(type)
355  }
356  if (!success) {
357  HEALTH_CHECK_TRACE(Trace, "Failed to Update " + this->to_string());
358  }
359  return success;
360 }
361 
363  *service) const {
367  }
368 }
369 
371  HealthCheckService *service, MetaDataIpAllocator *allocator,
372  VmInterface *intf, VmInterface *other_intf, bool ignore_status_event,
373  bool multi_hop) :
374  HealthCheckInstanceService(service, allocator, intf, other_intf,
375  ignore_status_event, multi_hop) {
376 
377  // Override this value done in the base class to prevent mac-ip
378  // learnt entry from being deleted on bfd startup
379  active_ = false;
380 }
381 
383 }
384 
386  *service) const {
387  if (!active_) {
388  if (!service_->table()->health_check_notify_callback().empty()) {
389  service_->table()->health_check_notify_callback()(this);
390  }
391  }
392 }
393 
395 
398  EventType type, const std::string &message) :
399  instance_(inst), service_(service), type_(type), message_(message) {
400 }
401 
403 }
404 
406 
408  const boost::uuids::uuid &id) :
409  AgentOperDBEntry(), table_(table), uuid_(id) {
411 }
412 
414  // Call DeleteInstances() so that the instances can be gracefully removed
415  // after all events queued are flushed.
416  // TODO pdsouza: This code doesn't seem to be required since the instances
417  // should already have been deleted via the same call on processing DB entry
418  // delete on the Health Check Table ( i.e., the list should be empty so it
419  // is benign.
420  DeleteInstances();
421 }
422 
423 bool HealthCheckService::IsLess(const DBEntry &rhs) const {
424  const HealthCheckService &a =
425  static_cast<const HealthCheckService &>(rhs);
426  return (uuid_ < a.uuid_);
427 }
428 
429 std::string HealthCheckService::ToString() const {
430  return UuidToString(uuid_);
431 }
432 
435  return DBEntryBase::KeyPtr(key);
436 }
437 
439  const HealthCheckServiceKey *k =
440  static_cast<const HealthCheckServiceKey *>(key);
441  uuid_ = k->uuid_;
442 }
443 
445  std::string &name) const {
446  HealthCheckSandeshResp *resp = static_cast<HealthCheckSandeshResp *>(sresp);
447 
448  HealthCheckSandeshData data;
449  data.set_uuid(UuidToString(uuid()));
450  data.set_name(name_);
451  data.set_service_type(service_type_);
452  data.set_monitor_type(monitor_type_);
453  data.set_http_method(http_method_);
454  data.set_url_path(url_path_);
455  data.set_expected_codes(expected_codes_);
456  data.set_delay(delay_);
457  data.set_delay_usecs(delay_usecs_);
458  data.set_timeout(timeout_);
459  data.set_timeout_usecs(timeout_usecs_);
460  data.set_max_retries(max_retries_);
461 
462  std::vector<HealthCheckInstanceSandeshData> inst_list;
463  InstanceList::const_iterator it = intf_list_.begin();
464  while (it != intf_list_.end()) {
465  HealthCheckInstanceSandeshData inst_data;
466  inst_data.set_vm_interface(UuidToString(it->first));
467  inst_data.set_metadata_ip
468  (it->second->ip()->GetLinkLocalIp().to_string());
469  inst_data.set_service_ip(it->second->source_ip().to_string());
470  inst_data.set_health_check_ip
471  (it->second->destination_ip().to_string());
472  inst_data.set_active(it->second->active());
473  inst_data.set_running(it->second->IsRunning());
474  inst_data.set_last_update_time(it->second->last_update_time());
475  inst_list.push_back(inst_data);
476  it++;
477  }
478  data.set_inst_list(inst_list);
479 
480  std::vector<HealthCheckSandeshData> &list =
481  const_cast<std::vector<HealthCheckSandeshData>&>(resp->get_hc_list());
482  list.push_back(data);
483  return true;
484 }
485 
488 }
489 
491  return (service_type_.find("segment") != std::string::npos);
492 }
493 
495  return ((monitor_type_.find("BFD") == std::string::npos) &&
497 }
498 
500  return (service_type_.find("vn-ip-list") != std::string::npos);
501 }
502 
505  VmInterface *paired_vmi,
506  const IpAddress &source_ip,
507  const IpAddress &destination_ip,
508  const MacAddress &destination_mac,
509  bool ignore_status_event,
510  bool multi_hop
511  ) {
512  HealthCheckInstanceBase *instance = NULL;
513  if (IsInstanceTaskBased()) {
514  instance = new HealthCheckInstanceTask(
515  this, table_->agent()->metadata_ip_allocator(),
516  intrface, ignore_status_event);
517  } else if (IsVnIpListHealthCheckService()) {
518  instance = new HealthCheckMacIpInstanceService(
519  this, table_->agent()->metadata_ip_allocator(),
520  intrface, paired_vmi, ignore_status_event, multi_hop);
521  HealthCheckMacIpInstanceService *mac_ip_inst =
522  static_cast<HealthCheckMacIpInstanceService *>(instance);
523  mac_ip_inst->set_destination_mac(destination_mac);
524  } else {
525  instance = new HealthCheckInstanceService(
526  this, table_->agent()->metadata_ip_allocator(),
527  intrface, paired_vmi, ignore_status_event, multi_hop);
528  }
529 
530  instance->set_source_ip(source_ip);
531  instance->set_destination_ip(destination_ip);
532  return instance;
533 }
534 
535 void
537  if (!instance->DestroyInstanceTask()) {
538  // Delete instance in Agent::HealthCheck task bacause there may be
539  // events queued for this instance that need to be processed without
540  // crashing while trying to access the instance.
541  // Note that db::DBTable Task and Agent::HealthCheck task are mutually
542  // exclusive, so there are no concurrency issues to be addressed.
543  instance->StopTask(instance->service());
544  }
545 }
546 
551  if (monitor_type_.find("BFD") != std::string::npos)
553  if (monitor_type_.find("HTTP") != std::string::npos)
556 }
557 
559  const HealthCheckServiceData *data) {
560  bool ret = false;
561  bool dest_ip_changed = false;
562  bool service_type_changed = false;
563  bool monitor_type_changed = false;
564  bool is_prev_hc_segment = IsSegmentHealthCheckService();
565 
566  HealthCheckService::HealthCheckType old_health_check_type =
568  if (monitor_type_ != data->monitor_type_) {
570  monitor_type_changed = true;
571  ret = true;
572  }
573 
574  if (service_type_ != data->service_type_) {
576  service_type_changed = true;
577  ret = true;
578  }
579 
580  if (http_method_ != data->http_method_) {
581  http_method_ = data->http_method_;
582  ret = true;
583  }
584 
585  if (ip_proto_ != data->ip_proto_) {
586  ip_proto_ = data->ip_proto_;
587  ret = true;
588  }
589 
590  if (url_path_ != data->url_path_) {
591  url_path_ = data->url_path_;
592  ret = true;
593  }
594 
595  if (url_port_ != data->url_port_) {
596  url_port_ = data->url_port_;
597  ret = true;
598  }
599 
600  if (expected_codes_ != data->expected_codes_) {
602  ret = true;
603  }
604 
605  if (delay_ != data->delay_) {
606  delay_ = data->delay_;
607  ret = true;
608  }
609 
610  if (delay_usecs_ != data->delay_usecs_) {
611  delay_usecs_ = data->delay_usecs_;
612  ret = true;
613  }
614 
615  if (timeout_ != data->timeout_) {
616  timeout_ = data->timeout_;
617  ret = true;
618  }
619 
620  if (timeout_usecs_ != data->timeout_usecs_) {
622  ret = true;
623  }
624 
625  if (max_retries_ != data->max_retries_) {
626  max_retries_ = data->max_retries_;
627  ret = true;
628  }
629 
630  if (target_ip_list_ != data->new_target_ip_list_) {
632  ret = true;
633  }
634 
635  if (is_hc_enable_all_ip_ != data->is_all_ip_) {
637  ret = true;
638  }
639 
640  if (vn_uuid_list_ != data->vn_uuid_list_) {
642  ret = true;
643  }
644 
645  if (dest_ip_ != data->dest_ip_) {
646  dest_ip_ = data->dest_ip_;
647  dest_ip_changed = true;
648  ret = true;
649  }
650 
651  if (ret) {
652  /* If service-type of health-check changes from segment to non-segment
653  * or vice-versa, remove all the health-check instance objects.
654  * Addition of new health-check instances with updated config happens
655  * later in this function */
656  if ((service_type_changed &&
657  is_prev_hc_segment != IsSegmentHealthCheckService()) ||
658  (monitor_type_changed &&
660  old_health_check_type == HealthCheckService::BFD))) {
661  DeleteInstances();
662  } else {
663  // stop previously allocated health check instances
664  // to force them restart with updated values.
665  InstanceList::iterator it = intf_list_.begin();
666  while (it != intf_list_.end()) {
667  it->second->StopInstanceTask();
668  it++;
669  }
670  }
671  // update type after deleting the previous instance
673  }
674 
675  if (name_ != data->name_) {
676  name_ = data->name_;
677  ret = true;
678  }
679 
680  std::set<boost::uuids::uuid>::iterator it_cfg =
681  data->intf_uuid_list_.begin();
682  InstanceList::iterator it = intf_list_.begin();
683  while (it_cfg != data->intf_uuid_list_.end() ||
684  it != intf_list_.end()) {
685  if (it_cfg == data->intf_uuid_list_.end() ||
686  ((it != intf_list_.end()) && ((*it_cfg) > it->first))) {
687  InstanceList::iterator it_prev = it;
688  it++;
689  StopHealthCheckService(it_prev->second);
690  intf_list_.erase(it_prev);
691  ret = true;
692  } else {
693  if ((it == intf_list_.end()) || ((*it_cfg) < it->first)) {
694  VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, (*it_cfg), "");
695  VmInterface *intf = static_cast<VmInterface *>
696  (table_->agent()->interface_table()->Find(&key, false));
697  // interface might be unavailable if config is received
698  // before nova message for interface creation, in such case
699  // skip adding instancee for this interface
700  // config dependency manager will then ensure re-notification
701  // of dependent config Health-Check-Service in this case to
702  // handle creation of interface later
703  if (intf != NULL) {
704  IpAddress source_ip;
705  IpAddress destination_ip = dest_ip_;
706  VmInterface *paired_vmi = NULL;
708  paired_vmi = intf->PortTuplePairedInterface();
709  if (paired_vmi == NULL) {
710  it_cfg++;
711  continue;
712  }
713  destination_ip = paired_vmi->GetServiceIp
714  (paired_vmi->primary_ip_addr());
715  if (destination_ip.is_unspecified()) {
716  it_cfg++;
717  continue;
718  }
719  }
721  source_ip = intf->GetGatewayIp(intf->primary_ip_addr());
723  // Note that a new instance is alway used when starting
724  // hence the same instance will not be re-used for a
725  // different service. From this we can be sure that once
726  // an instance is deleted it will not be re-used.
727  StartHealthCheckService(intf, paired_vmi, source_ip,
728  destination_ip, MacAddress(),
729  false, false);
730  intf_list_.insert(std::pair<boost::uuids::uuid,
731  HealthCheckInstanceBase *>(*(it_cfg), inst));
732  ret = true;
733  }
734  } else {
735  if (dest_ip_changed || IsInstanceTaskBased()) {
736  // change in destination IP needs to be propagated
737  // explicitly to metadata-IP object
738  it->second->set_destination_ip(dest_ip_);
739  }
740  it++;
741  }
742  it_cfg++;
743  }
744  }
745 
746  return ret;
747 }
748 
750  InstanceList::iterator it = intf_list_.begin();
751  while (it != intf_list_.end()) {
752  it->second->set_service(this);
753  it++;
754  }
755 }
756 
758  const HealthCheckService *service,
759  const VmInterface *itf) const {
760  DBRequest req;
763  req.data.reset(new HealthCheckResyncInterfaceData(NULL, NULL, itf));
764  service->table()->agent()->health_check_table()->Enqueue(&req);
765 }
766 
768  const HealthCheckService *service,
769  const VmInterface *intf) {
770  InstanceList::iterator it;
771 
772  it = intf_list_.find(intf->vmi_cfg_uuid());
773  if (it != intf_list_.end()) {
774  HEALTH_CHECK_TRACE(Trace, "Enqueue instance " + intf->name());
775  it->second->EnqueueHealthCheckResync(service, intf);
776  } else {
777  HEALTH_CHECK_TRACE(Trace, "Enqueue instance not found " + intf->name());
778  }
779 }
780 
782  const VmInterface *intf) {
783  InstanceList::iterator it;
784 
785  it = intf_list_.find(intf->vmi_cfg_uuid());
786  if (it != intf_list_.end()) {
787  it->second->set_service(this);
788  } else {
789  HEALTH_CHECK_TRACE(Trace, "Service not found :" + intf->name());
790  }
791 }
792 
794  InstanceList::iterator it = intf_list_.begin();
795  while (it != intf_list_.end()) {
796  StopHealthCheckService(it->second);
797  intf_list_.erase(it);
798  it = intf_list_.begin();
799  }
800 }
801 
803 
805  const std::string &name) :
806  AgentOperDBTable(db, name) {
807  set_agent(agent);
810  boost::bind(&HealthCheckTable::InstanceEventProcess, this, _1));
811  inst_event_queue_->set_name("HealthCheck instance event queue");
812 }
813 
816  delete inst_event_queue_;
817 }
818 
820  const std::string &name) {
821  HealthCheckTable *health_check_table =
822  new HealthCheckTable(agent, db, name);
823  (static_cast<DBTable *>(health_check_table))->Init();
824  return health_check_table;
825 };
826 
827 std::unique_ptr<DBEntry>
829  const HealthCheckServiceKey *key =
830  static_cast<const HealthCheckServiceKey *>(k);
831  HealthCheckService *service = new HealthCheckService(this, key->uuid_);
832  return std::unique_ptr<DBEntry>(static_cast<DBEntry *>(service));
833 }
834 
836  HealthCheckServiceKey *key =
837  static_cast<HealthCheckServiceKey *>(req->key.get());
838  HealthCheckServiceData *data =
839  static_cast<HealthCheckServiceData *>(req->data.get());
840  HealthCheckService *service = new HealthCheckService(this, key->uuid_);
841  service->Copy(this, data);
842  return service;
843 }
844 
846  /*
847  * Ideally db-infra should have removed the delete mark for the db-entry
848  * when Add/Update happens for the db-entry. It has to be root-caused.
849  * For now it is handled here and doing here wont give any side-effects.
850  */
851  bool ret = false;
852  if (entry->IsDeleted()) {
853  entry->ClearDelete();
854  ret = true;
855  }
856  HealthCheckService *service = static_cast<HealthCheckService *>(entry);
857  HealthCheckServiceData *data =
858  dynamic_cast<HealthCheckServiceData *>(req->data.get());
859  assert(data);
860  ret |= service->Copy(this, data);
862  return ret;
863 }
864 
866  HealthCheckResyncInterfaceData *resync_data =
867  dynamic_cast<HealthCheckResyncInterfaceData *>(req->data.get());
868  if (resync_data) {
869  // resync triggered from Vmi for which there is no source ip specified
870  // in the interface health check service instance.
871  HEALTH_CHECK_TRACE(Trace, "Resync interface " + resync_data->intf_->name());
872  HealthCheckService *service = static_cast<HealthCheckService *>(entry);
873  service->UpdateInterfaceInstanceServiceReference(resync_data->intf_);
874  return false;
875  }
876 
877  return OperDBOnChange(entry, req);
878 }
879 
881  HealthCheckService *service = static_cast<HealthCheckService *>(entry);
882  service->DeleteInstances();
883  return true;
884 }
885 
886 
888  return new HealthCheckServiceKey(u);
889 }
890 
892  const autogen::ServiceHealthCheck *s) {
893  boost::system::error_code ec;
894  const autogen::ServiceHealthCheckType &p = s->properties();
895  Ip4Address dest_ip;
896  std::string url_path;
897  uint8_t ip_proto = 0;
898  uint16_t url_port = 0;
899  if (p.monitor_type.find("BFD") != std::string::npos) {
900  boost::system::error_code ec;
901  dest_ip = Ip4Address::from_string(p.url_path, ec);
902  url_path = p.url_path;
903  ip_proto = IPPROTO_UDP;
904  } else if (p.monitor_type.find("HTTP") == std::string::npos) {
905  boost::system::error_code ec;
906  dest_ip = Ip4Address::from_string(p.url_path, ec);
907  url_path = p.url_path;
908  ip_proto = IPPROTO_ICMP;
909  } else if (!p.url_path.empty()) {
910  ip_proto = IPPROTO_TCP;
911  // parse url if available
912  struct http_parser_url urldata;
913  int ret = http_parser_parse_url(p.url_path.c_str(), p.url_path.size(),
914  false, &urldata);
915  if (ret == 0) {
916  if (urldata.field_set & (1 << UF_HOST)) {
917  std::string dest_ip_str =
918  p.url_path.substr(urldata.field_data[UF_HOST].off,
919  urldata.field_data[UF_HOST].len);
920  // Parse dest-ip from the url to translate to metadata IP
921  dest_ip = Ip4Address::from_string(dest_ip_str, ec);
922  // keep rest of the url string as is
923  url_path = p.url_path.substr(urldata.field_data[UF_HOST].off +\
924  urldata.field_data[UF_HOST].len);
925  }
926  url_port = urldata.port;
927  if ((urldata.field_set & (1 << UF_PORT)) == 0) {
928  url_port = 80;
929  }
930  }
931  }
932 
933  bool is_all_ip = false;
934  if (p.target_ip_all) {
935  is_all_ip = true;
936  }
937  std::set<IpAddress> ip_address_list;
938  for (unsigned int i = 0; i < p.target_ip_list.ip_address.size(); ++i) {
939  boost::system::error_code ec;
940  IpAddress ip = Ip4Address::from_string(p.target_ip_list.ip_address[i], ec);
941  if (ec.value() != 0) {
942  ip = Ip6Address::from_string(p.target_ip_list.ip_address[i], ec);
943  }
944  if (ec.value() != 0) {
945  continue;
946  }
947 
948  ip_address_list.insert(ip);
949  }
950 
951  HealthCheckServiceData *data =
952  new HealthCheckServiceData(agent, dest_ip, node->name(),
953  p.monitor_type, p.health_check_type,
954  ip_proto, p.http_method,
955  url_path, url_port, p.expected_codes,
956  p.delay, p.delayUsecs, p.timeout,
957  p.timeoutUsecs, p.max_retries,
958  is_all_ip, ip_address_list, node);
959 
960  IFMapAgentTable *table = static_cast<IFMapAgentTable *>(node->table());
962  node->begin(table->GetGraph());
963  iter != node->end(table->GetGraph()); ++iter) {
964  IFMapNode *adj_node = static_cast<IFMapNode *>(iter.operator->());
965  if (agent->config_manager()->SkipNode(adj_node)) {
966  continue;
967  }
968 
969  if (adj_node->table() == agent->cfg()->cfg_vm_interface_table()) {
970  boost::uuids::uuid intf_uuid;
971  autogen::VirtualMachineInterface *intf =
972  dynamic_cast<autogen::VirtualMachineInterface *>(adj_node->GetObject());
973  assert(intf);
974  const autogen::IdPermsType &id_perms = intf->id_perms();
975  CfgUuidSet(id_perms.uuid.uuid_mslong,
976  id_perms.uuid.uuid_lslong, intf_uuid);
977 
978  data->intf_uuid_list_.insert(intf_uuid);
979  }
980  if (adj_node->table() == agent->cfg()->cfg_vn_table()) {
981  boost::uuids::uuid vn_uuid;
982  autogen::VirtualNetwork *vn =
983  dynamic_cast<autogen::VirtualNetwork *>(adj_node->GetObject());
984  assert(vn);
985  const autogen::IdPermsType &id_perms = vn->id_perms();
986  CfgUuidSet(id_perms.uuid.uuid_mslong,
987  id_perms.uuid.uuid_lslong, vn_uuid);
988 
989  data->vn_uuid_list_.insert(vn_uuid);
990  }
991  }
992  return data;
993 }
994 
996  const boost::uuids::uuid &u) {
997  autogen::ServiceHealthCheck *service =
998  static_cast<autogen::ServiceHealthCheck *>(node->GetObject());
999  assert(service);
1000 
1001  assert(!u.is_nil());
1002 
1003  req.key.reset(BuildKey(u));
1004  if ((req.oper == DBRequest::DB_ENTRY_DELETE) || node->IsDeleted()) {
1006  return true;
1007  }
1008 
1010  return false;
1011 }
1012 
1014  const boost::uuids::uuid &u) {
1015  autogen::ServiceHealthCheck *service =
1016  static_cast <autogen::ServiceHealthCheck *>(node->GetObject());
1017  assert(service);
1018 
1019  req.key.reset(BuildKey(u));
1020  if (node->IsDeleted()) {
1022  return true;
1023  }
1024 
1026  req.data.reset(BuildData(agent(), node, service));
1027  Enqueue(&req);
1028 
1029  return false;
1030 }
1031 
1033  autogen::ServiceHealthCheck *service =
1034  static_cast<autogen::ServiceHealthCheck *>(node->GetObject());
1035  autogen::IdPermsType id_perms = service->id_perms();
1036  CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u);
1037  return true;
1038 }
1039 
1040 
1042  HealthCheckServiceKey key(u);
1043  return static_cast<HealthCheckService *>(FindActiveEntry(&key));
1044 }
1045 
1046 void
1048  inst_event_queue_->Enqueue(event);
1049 }
1050 
1052  HealthCheckInstanceBase *inst = event->instance_;
1053  switch (event->type_) {
1055  {
1056  // We dont want to process status messages as the instance delete
1057  // has ben queued.
1058  if (inst->deleted_) {
1060  "Read Event while deleted! " + inst->to_string());
1061  break;
1062  }
1063  if (inst->IsStatusEventIgnored())
1064  break;
1066  std::string msg = event->message_;
1067  boost::algorithm::to_lower(msg);
1068  if (msg.find("success") != std::string::npos) {
1069  if (!inst->active_) {
1070  inst->active_ = true;
1071  inst->ResyncTarget(inst->service_.get());
1072  }
1073  }
1074  if (msg.find("failure") != std::string::npos) {
1075  if (inst->active_) {
1076  inst->active_ = false;
1077  inst->ResyncTarget(inst->service_.get());
1078  }
1079  }
1081  " Received msg = " + event->message_);
1082  }
1083  break;
1084 
1086  if (inst->IsStatusEventIgnored())
1087  break;
1088  if (!inst->deleted_) {
1089  HEALTH_CHECK_TRACE(Trace, "Restarting " + inst->to_string());
1090  inst->RunInstanceTask();
1091  } else {
1092  HEALTH_CHECK_TRACE(Trace, "Stopped " + inst->to_string());
1093  delete inst;
1094  }
1095  break;
1096 
1098  inst->set_service(event->service_);
1099  break;
1100 
1102  inst->DestroyInstanceTask();
1103  // Freeing instance is handled here and not in any other task context.
1104  // Unconditionally delete here since DestroyInstanceTask() may have
1105  // alrady been called in the db::DBTable task context before queueing
1106  // this event.
1107  delete inst;
1108  break;
1109 
1110  default:
1111  // unhandled event
1112  assert(0);
1113  }
1114 
1115  delete event;
1116  return true;
1117 }
1118 
1121  const std::string &context) {
1122  return AgentSandeshPtr(new AgentHealthCheckSandesh(context,
1123  args->GetString("uuid")));
1124 }
1125 
1126 void HealthCheckSandeshReq::HandleRequest() const {
1127  AgentSandeshPtr sand(new AgentHealthCheckSandesh(context(), get_uuid()));
1128  sand->DoSandesh(sand);
1129 }
1130 
boost::asio::ip::address IpAddress
Definition: address.h:13
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
#define kTaskHealthCheck
Definition: agent.h:335
static void CfgUuidSet(uint64_t ms_long, uint64_t ls_long, boost::uuids::uuid &u)
Definition: agent_cmn.h:66
class boost::shared_ptr< AgentSandesh > AgentSandeshPtr
Definition: agent_db.h:20
IFMapAgentTable * cfg_vn_table() const
Definition: cfg_init.h:26
IFMapAgentTable * cfg_vm_interface_table() const
Definition: cfg_init.h:22
AgentDBEntry * FindActiveEntry(const DBEntry *key)
Definition: agent_db.cc:110
AgentDBEntry * Find(const DBEntry *key, bool ret_del)
Definition: agent_db.cc:134
Agent * agent() const
Definition: agent_db.h:215
void set_agent(Agent *agent)
Definition: agent_db.h:214
std::string GetString(const std::string &key) const
Definition: agent.h:360
InterfaceTable * interface_table() const
Definition: agent.h:467
ConfigManager * config_manager() const
Definition: agent.cc:892
AgentConfig * cfg() const
Definition: agent.cc:868
TaskScheduler * task_scheduler() const
Definition: agent.h:1122
HealthCheckTable * health_check_table() const
Definition: agent.cc:936
MetaDataIpAllocator * metadata_ip_allocator() const
Definition: agent.cc:952
bool SkipNode(IFMapNode *node)
void AddHealthCheckServiceNode(IFMapNode *node)
std::unique_ptr< DBRequestKey > KeyPtr
Definition: db_entry.h:24
void ClearDelete()
Definition: db_entry.h:47
bool IsDeleted() const
Definition: db_entry.h:48
adjacency_iterator end(DBGraph *graph)
adjacency_iterator begin(DBGraph *graph)
bool Enqueue(DBRequest *req)
Definition: db_table.cc:220
const std::string & name() const
Definition: db_table.h:110
Definition: db.h:24
virtual bool RunInstanceTask()=0
void set_service(HealthCheckService *service)
Definition: health_check.cc:82
IpAddress destination_ip() const
MetaDataIp * ip() const
Definition: health_check.h:148
IpAddress update_source_ip()
bool IsStatusEventIgnored() const
Definition: health_check.h:150
HealthCheckInstanceBase(HealthCheckService *service, MetaDataIpAllocator *allocator, VmInterface *intf, bool ignore_status_event)
Definition: health_check.cc:41
InterfaceRef interface() const
Definition: health_check.h:147
void set_source_ip(const IpAddress &ip)
Definition: health_check.h:151
virtual bool UpdateInstanceTask()
Definition: health_check.h:130
void StopTask(HealthCheckService *service)
void set_destination_ip(const IpAddress &ip)
std::string last_update_time_
Definition: health_check.h:173
void OnExit(const boost::system::error_code &ec)
void EnqueueHealthCheckResync(const HealthCheckService *service, const VmInterface *itf) const
virtual bool DestroyInstanceTask()=0
HealthCheckServiceRef service_
Definition: health_check.h:165
virtual ~HealthCheckInstanceBase()
Definition: health_check.cc:60
IpAddress source_ip() const
void OnRead(const std::string &data)
boost::scoped_ptr< MetaDataIp > ip_
Definition: health_check.h:169
void SetService(HealthCheckService *service)
virtual void ResyncTarget(const HealthCheckService *service) const
Definition: health_check.cc:77
virtual bool CreateInstanceTask()=0
HealthCheckService * service() const
Definition: health_check.h:146
void EnqueueResync(const HealthCheckService *service, Interface *itf) const
Definition: health_check.cc:68
virtual bool DestroyInstanceTask()
HealthCheckInstanceService(HealthCheckService *service, MetaDataIpAllocator *allocator, VmInterface *intf, VmInterface *other_intf, bool ignore_status_event, bool multi_hop)
virtual bool RunInstanceTask()
BfdDownCallback bfd_down_callback_
Definition: health_check.h:255
virtual void ResyncTarget(const HealthCheckService *service) const
virtual bool StopInstanceTask()
virtual bool CreateInstanceTask()
virtual bool UpdateInstanceTask()
virtual bool DestroyInstanceTask()
virtual ~HealthCheckInstanceTask()
HealthCheckInstanceTask(HealthCheckService *service, MetaDataIpAllocator *allocator, VmInterface *intf, bool ignore_status_event)
virtual bool StopInstanceTask()
virtual bool RunInstanceTask()
InstanceTaskExecvp HeathCheckProcessInstance
Definition: health_check.h:191
virtual bool CreateInstanceTask()
virtual bool IsRunning() const
static const std::string kHealthCheckCmd
Definition: health_check.h:192
virtual void set_destination_mac(const MacAddress &mac)
Definition: health_check.h:269
HealthCheckMacIpInstanceService(HealthCheckService *service, MetaDataIpAllocator *allocator, VmInterface *intf, VmInterface *other_intf, bool ignore_status_event, bool multi_hop)
virtual void ResyncTarget(const HealthCheckService *service) const
uint64_t timeout_usecs_
Definition: health_check.h:395
HealthCheckType health_check_type_
Definition: health_check.h:399
bool IsVnIpListHealthCheckService() const
const HealthCheckTable * table() const
Definition: health_check.h:348
virtual std::string ToString() const
std::string http_method_
Definition: health_check.h:387
HealthCheckType GetHealthCheckType() const
void StopHealthCheckService(HealthCheckInstanceBase *instance)
void ResyncHealthCheckInterface(const HealthCheckService *service, const VmInterface *intf)
std::set< IpAddress > target_ip_list_
Definition: health_check.h:402
HealthCheckService(const HealthCheckTable *table, const boost::uuids::uuid &id)
virtual bool IsLess(const DBEntry &rhs) const
const HealthCheckTable * table_
Definition: health_check.h:377
std::set< boost::uuids::uuid > vn_uuid_list_
Definition: health_check.h:401
boost::uuids::uuid uuid_
Definition: health_check.h:378
bool IsSegmentHealthCheckService() const
void UpdateInterfaceInstanceServiceReference(const VmInterface *intf)
InstanceList intf_list_
Definition: health_check.h:398
bool DBEntrySandesh(Sandesh *resp, std::string &name) const
std::string monitor_type_
Definition: health_check.h:382
bool IsInstanceTaskBased() const
virtual void SetKey(const DBRequestKey *key)
virtual KeyPtr GetDBRequestKey() const
HealthCheckInstanceBase * StartHealthCheckService(VmInterface *intrface, VmInterface *paired_vmi, const IpAddress &source_ip, const IpAddress &destination_ip, const MacAddress &destination_mac, bool ignore_status_event, bool multi_hop)
std::string expected_codes_
Definition: health_check.h:391
std::string url_path_
Definition: health_check.h:388
std::string name_
Definition: health_check.h:380
std::string service_type_
Definition: health_check.h:384
const boost::uuids::uuid & uuid() const
Definition: health_check.h:336
bool Copy(HealthCheckTable *table, const HealthCheckServiceData *data)
void UpdateInstanceServiceReference()
WorkQueue< HealthCheckInstanceEvent * > * inst_event_queue_
Definition: health_check.h:469
virtual AgentSandeshPtr GetAgentSandesh(const AgentSandeshArguments *args, const std::string &context)
HealthCheckTable(Agent *agent, DB *db, const std::string &name)
virtual std::unique_ptr< DBEntry > AllocEntry(const DBRequestKey *k) const
virtual ~HealthCheckTable()
bool ProcessConfig(IFMapNode *node, DBRequest &req, const boost::uuids::uuid &u)
virtual bool OperDBResync(DBEntry *entry, const DBRequest *req)
HealthCheckService * Find(const boost::uuids::uuid &u)
virtual bool OperDBOnChange(DBEntry *entry, const DBRequest *req)
virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u)
virtual DBEntry * OperDBAdd(const DBRequest *req)
static DBTableBase * CreateTable(Agent *agent, DB *db, const std::string &name)
virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req, const boost::uuids::uuid &u)
bool InstanceEventProcess(HealthCheckInstanceEvent *event)
virtual bool OperDBDelete(DBEntry *entry, const DBRequest *req)
void InstanceEventEnqueue(HealthCheckInstanceEvent *event) const
const DBGraph * GetGraph() const
IFMapTable * table()
Definition: ifmap_node.h:29
const std::string & name() const
Definition: ifmap_node.h:48
IFMapObject * GetObject()
Definition: ifmap_node.cc:63
const std::string & name() const
Definition: interface.h:116
const boost::uuids::uuid & GetUuid() const
Definition: interface.h:115
int GetTaskId(const std::string &name)
Definition: task.cc:883
Definition: trace.h:288
VmInterface * PortTuplePairedInterface() const
IpAddress GetServiceIp(const IpAddress &ip) const
const boost::uuids::uuid & vmi_cfg_uuid() const
void InsertHealthCheckInstance(HealthCheckInstanceBase *hc_inst)
void DeleteHealthCheckInstance(HealthCheckInstanceBase *hc_inst)
const Ip4Address & primary_ip_addr() const
IpAddress GetGatewayIp(const IpAddress &ip) const
bool Enqueue(QueueEntryT entry)
Definition: queue_task.h:248
void Shutdown(bool delete_entries=true)
Definition: queue_task.h:152
void set_name(const std::string &name)
Definition: queue_task.h:307
static HealthCheckServiceKey * BuildKey(const boost::uuids::uuid &u)
static HealthCheckServiceData * BuildData(Agent *agent, IFMapNode *node, const autogen::ServiceHealthCheck *s)
SandeshTraceBufferPtr HealthCheckTraceBuf(SandeshTraceBufferCreate("HealthCheck", 5000))
#define HEALTH_CHECK_TRACE(obj,...)
Definition: health_check.h:13
uint8_t type
Definition: load_balance.h:2
boost::shared_ptr< TraceBuffer< SandeshTrace > > SandeshTraceBufferPtr
Definition: sandesh_trace.h:18
SandeshTraceBufferPtr SandeshTraceBufferCreate(const std::string &buf_name, size_t buf_size, bool trace_enable=true)
Definition: sandesh_trace.h:46
static std::string UuidToString(const boost::uuids::uuid &id)
Definition: string_util.h:138
@ ADD_DEL_CHANGE
Definition: agent_db.h:100
@ RESYNC
Definition: agent_db.h:103
DBOperation oper
Definition: db_table.h:42
@ DB_ENTRY_DELETE
Definition: db_table.h:39
@ DB_ENTRY_ADD_CHANGE
Definition: db_table.h:38
std::unique_ptr< DBRequestKey > key
Definition: db_table.h:48
std::unique_ptr< DBRequestData > data
Definition: db_table.h:49
virtual ~HealthCheckInstanceEvent()
HealthCheckInstanceEvent(HealthCheckInstanceBase *inst, HealthCheckService *service, EventType type, const std::string &message)
HealthCheckService * service_
Definition: health_check.h:107
const VmInterface * intf_
Definition: health_check.h:479
std::set< boost::uuids::uuid > intf_uuid_list_
Definition: health_check.h:85
std::string monitor_type_
Definition: health_check.h:72
std::string expected_codes_
Definition: health_check.h:79
std::string http_method_
Definition: health_check.h:76
std::string service_type_
Definition: health_check.h:74
std::set< IpAddress > new_target_ip_list_
Definition: health_check.h:88
std::set< boost::uuids::uuid > vn_uuid_list_
Definition: health_check.h:86
boost::uuids::uuid uuid_
Definition: health_check.h:40
Definition: task_int.h:10
static std::string UTCUsecToString(uint64_t tstamp)
Definition: time_util.h:54
static uint64_t UTCTimestampUsec()
Definition: time_util.h:13
boost::uuids::uuid uuid