OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 
34 HealthCheckTraceBuf(SandeshTraceBufferCreate("HealthCheck", 5000));
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);
54  if (!service->IsVnIpListHealthCheckService()) {
55  intf->InsertHealthCheckInstance(this);
56  }
57  ResyncTarget(service);
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 =
124  new HealthCheckInstanceEvent(this, service,
126  service->table()->InstanceEventEnqueue(event);
127 }
128 
130  HealthCheckInstanceEvent *event =
131  new HealthCheckInstanceEvent(this, service,
133  service->table()->InstanceEventEnqueue(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) {
261  if (service->IsSegmentHealthCheckService() && other_intf) {
262  other_intf->InsertHealthCheckInstance(this);
263  }
264 }
265 
267  if (service()->IsSegmentHealthCheckService() && other_intf_.get()) {
268  VmInterface *vmi = static_cast<VmInterface *>(other_intf_.get());
269  vmi->DeleteHealthCheckInstance(this);
271  }
272 }
273 
275  assert(deleted_ == false);
276  HealthCheckService::HealthCheckType type = service_->health_check_type();
277  HEALTH_CHECK_TRACE(Trace, "Starting " + this->to_string());
278  assert(type == HealthCheckService::SEGMENT ||
279  type == HealthCheckService::BFD);
280  if (service_->table()->health_check_service_callback(type).empty() ||
281  service_->table()->health_check_service_callback(type)
282  (HealthCheckTable::CREATE_SERVICE, this) == false) {
283  HEALTH_CHECK_TRACE(Trace, "Failed to start " + this->to_string());
284  return false;
285  }
286  return true;
287 }
288 
290  if (deleted_) {
291  return true;
292  }
293 
294  HealthCheckService::HealthCheckType type = service_->health_check_type();
295  if (!service_->table()->health_check_service_callback(type).empty()) {
296  HEALTH_CHECK_TRACE(Trace, "Deleting " + this->to_string());
297  service_->table()->health_check_service_callback(type)
299  }
300 
301  deleted_ = true;
302  return false;
303 }
304 
306  HealthCheckService::HealthCheckType type = service_->health_check_type();
307  if (!service_->table()->health_check_service_callback(type).empty()) {
308  HEALTH_CHECK_TRACE(Trace, "Run Instance " + this->to_string());
309  assert(type == HealthCheckService::SEGMENT ||
310  type == HealthCheckService::BFD);
311  return service_->table()->health_check_service_callback(type)
313  }
314  HEALTH_CHECK_TRACE(Trace, "Run Instance failed " + this->to_string());
315  return false;
316 }
317 
319  HealthCheckService::HealthCheckType type = service_->health_check_type();
320  if (!service_->table()->health_check_service_callback(type).empty()) {
321  HEALTH_CHECK_TRACE(Trace, "Stop Instance " + this->to_string());
322  return service_->table()->health_check_service_callback(type)
324  }
325  return false;
326 }
327 
329  bool success = false;
330  HealthCheckService::HealthCheckType type = service_->health_check_type();
331  if (!service_->table()->health_check_service_callback(type).empty()) {
332  HEALTH_CHECK_TRACE(Trace, "Updating " + this->to_string());
333  assert(type == HealthCheckService::SEGMENT ||
334  type == HealthCheckService::BFD);
335  success = service_->table()->health_check_service_callback(type)
337  }
338  if (!success) {
339  HEALTH_CHECK_TRACE(Trace, "Failed to Update " + this->to_string());
340  }
341  return success;
342 }
343 
345  *service) const {
347  if (service->IsSegmentHealthCheckService() && other_intf_.get()) {
348  EnqueueResync(service, other_intf_.get());
349  }
350 }
351 
353  HealthCheckService *service, MetaDataIpAllocator *allocator,
354  VmInterface *intf, VmInterface *other_intf, bool ignore_status_event,
355  bool multi_hop) :
356  HealthCheckInstanceService(service, allocator, intf, other_intf,
357  ignore_status_event, multi_hop) {
358 
359  // Override this value done in the base class to prevent mac-ip
360  // learnt entry from being deleted on bfd startup
361  active_ = false;
362 }
363 
365 }
366 
368  *service) const {
369  if (!active_) {
370  if (!service_->table()->health_check_notify_callback().empty()) {
371  service_->table()->health_check_notify_callback()(this);
372  }
373  }
374 }
375 
377 
380  EventType type, const std::string &message) :
381  instance_(inst), service_(service), type_(type), message_(message) {
382 }
383 
385 }
386 
388 
390  const boost::uuids::uuid &id) :
391  AgentOperDBEntry(), table_(table), uuid_(id) {
393 }
394 
396  // Call DeleteInstances() so that the instances can be gracefully removed
397  // after all events queued are flushed.
398  // TODO pdsouza: This code doesn't seem to be required since the instances
399  // should already have been deleted via the same call on processing DB entry
400  // delete on the Health Check Table ( i.e., the list should be empty so it
401  // is benign.
402  DeleteInstances();
403 }
404 
405 bool HealthCheckService::IsLess(const DBEntry &rhs) const {
406  const HealthCheckService &a =
407  static_cast<const HealthCheckService &>(rhs);
408  return (uuid_ < a.uuid_);
409 }
410 
411 std::string HealthCheckService::ToString() const {
412  return UuidToString(uuid_);
413 }
414 
417  return DBEntryBase::KeyPtr(key);
418 }
419 
421  const HealthCheckServiceKey *k =
422  static_cast<const HealthCheckServiceKey *>(key);
423  uuid_ = k->uuid_;
424 }
425 
427  std::string &name) const {
428  HealthCheckSandeshResp *resp = static_cast<HealthCheckSandeshResp *>(sresp);
429 
430  HealthCheckSandeshData data;
431  data.set_uuid(UuidToString(uuid()));
432  data.set_name(name_);
433  data.set_service_type(service_type_);
434  data.set_monitor_type(monitor_type_);
435  data.set_http_method(http_method_);
436  data.set_url_path(url_path_);
437  data.set_expected_codes(expected_codes_);
438  data.set_delay(delay_);
439  data.set_delay_usecs(delay_usecs_);
440  data.set_timeout(timeout_);
441  data.set_timeout_usecs(timeout_usecs_);
442  data.set_max_retries(max_retries_);
443 
444  std::vector<HealthCheckInstanceSandeshData> inst_list;
445  InstanceList::const_iterator it = intf_list_.begin();
446  while (it != intf_list_.end()) {
447  HealthCheckInstanceSandeshData inst_data;
448  inst_data.set_vm_interface(UuidToString(it->first));
449  inst_data.set_metadata_ip
450  (it->second->ip()->GetLinkLocalIp().to_string());
451  inst_data.set_service_ip(it->second->source_ip().to_string());
452  inst_data.set_health_check_ip
453  (it->second->destination_ip().to_string());
454  inst_data.set_active(it->second->active());
455  inst_data.set_running(it->second->IsRunning());
456  inst_data.set_last_update_time(it->second->last_update_time());
457  inst_list.push_back(inst_data);
458  it++;
459  }
460  data.set_inst_list(inst_list);
461 
462  std::vector<HealthCheckSandeshData> &list =
463  const_cast<std::vector<HealthCheckSandeshData>&>(resp->get_hc_list());
464  list.push_back(data);
465  return true;
466 }
467 
470 }
471 
473  return (service_type_.find("segment") != std::string::npos);
474 }
475 
477  return ((monitor_type_.find("BFD") == std::string::npos) &&
479 }
480 
482  return (service_type_.find("vn-ip-list") != std::string::npos);
483 }
484 
487  VmInterface *paired_vmi,
488  const IpAddress &source_ip,
489  const IpAddress &destination_ip,
490  const MacAddress &destination_mac,
491  bool ignore_status_event,
492  bool multi_hop
493  ) {
494  HealthCheckInstanceBase *instance = NULL;
495  if (IsInstanceTaskBased()) {
496  instance = new HealthCheckInstanceTask(
497  this, table_->agent()->metadata_ip_allocator(),
498  intrface, ignore_status_event);
499  } else if (IsVnIpListHealthCheckService()) {
500  instance = new HealthCheckMacIpInstanceService(
501  this, table_->agent()->metadata_ip_allocator(),
502  intrface, paired_vmi, ignore_status_event, multi_hop);
503  HealthCheckMacIpInstanceService *mac_ip_inst =
504  static_cast<HealthCheckMacIpInstanceService *>(instance);
505  mac_ip_inst->set_destination_mac(destination_mac);
506  } else {
507  instance = new HealthCheckInstanceService(
508  this, table_->agent()->metadata_ip_allocator(),
509  intrface, paired_vmi, ignore_status_event, multi_hop);
510  }
511 
512  instance->set_source_ip(source_ip);
513  instance->set_destination_ip(destination_ip);
514  return instance;
515 }
516 
517 void
519  if (!instance->DestroyInstanceTask()) {
520  // Delete instance in Agent::HealthCheck task bacause there may be
521  // events queued for this instance that need to be processed without
522  // crashing while trying to access the instance.
523  // Note that db::DBTable Task and Agent::HealthCheck task are mutually
524  // exclusive, so there are no concurrency issues to be addressed.
525  instance->StopTask(instance->service());
526  }
527 }
528 
533  if (monitor_type_.find("BFD") != std::string::npos)
535  if (monitor_type_.find("HTTP") != std::string::npos)
538 }
539 
541  const HealthCheckServiceData *data) {
542  bool ret = false;
543  bool dest_ip_changed = false;
544  bool service_type_changed = false;
545  bool monitor_type_changed = false;
546  bool is_prev_hc_segment = IsSegmentHealthCheckService();
547 
548  HealthCheckService::HealthCheckType old_health_check_type =
550  if (monitor_type_ != data->monitor_type_) {
552  monitor_type_changed = true;
553  ret = true;
554  }
555 
556  if (service_type_ != data->service_type_) {
558  service_type_changed = true;
559  ret = true;
560  }
561 
562  if (http_method_ != data->http_method_) {
563  http_method_ = data->http_method_;
564  ret = true;
565  }
566 
567  if (ip_proto_ != data->ip_proto_) {
568  ip_proto_ = data->ip_proto_;
569  ret = true;
570  }
571 
572  if (url_path_ != data->url_path_) {
573  url_path_ = data->url_path_;
574  ret = true;
575  }
576 
577  if (url_port_ != data->url_port_) {
578  url_port_ = data->url_port_;
579  ret = true;
580  }
581 
582  if (expected_codes_ != data->expected_codes_) {
584  ret = true;
585  }
586 
587  if (delay_ != data->delay_) {
588  delay_ = data->delay_;
589  ret = true;
590  }
591 
592  if (delay_usecs_ != data->delay_usecs_) {
593  delay_usecs_ = data->delay_usecs_;
594  ret = true;
595  }
596 
597  if (timeout_ != data->timeout_) {
598  timeout_ = data->timeout_;
599  ret = true;
600  }
601 
602  if (timeout_usecs_ != data->timeout_usecs_) {
604  ret = true;
605  }
606 
607  if (max_retries_ != data->max_retries_) {
608  max_retries_ = data->max_retries_;
609  ret = true;
610  }
611 
612  if (target_ip_list_ != data->new_target_ip_list_) {
614  ret = true;
615  }
616 
617  if (is_hc_enable_all_ip_ != data->is_all_ip_) {
619  ret = true;
620  }
621 
622  if (vn_uuid_list_ != data->vn_uuid_list_) {
624  ret = true;
625  }
626 
627  if (dest_ip_ != data->dest_ip_) {
628  dest_ip_ = data->dest_ip_;
629  dest_ip_changed = true;
630  ret = true;
631  }
632 
633  if (ret) {
634  /* If service-type of health-check changes from segment to non-segment
635  * or vice-versa, remove all the health-check instance objects.
636  * Addition of new health-check instances with updated config happens
637  * later in this function */
638  if ((service_type_changed &&
639  is_prev_hc_segment != IsSegmentHealthCheckService()) ||
640  (monitor_type_changed &&
642  old_health_check_type == HealthCheckService::BFD))) {
643  DeleteInstances();
644  } else {
645  // stop previously allocated health check instances
646  // to force them restart with updated values.
647  InstanceList::iterator it = intf_list_.begin();
648  while (it != intf_list_.end()) {
649  it->second->StopInstanceTask();
650  it++;
651  }
652  }
653  // update type after deleting the previous instance
655  }
656 
657  if (name_ != data->name_) {
658  name_ = data->name_;
659  ret = true;
660  }
661 
662  std::set<boost::uuids::uuid>::iterator it_cfg =
663  data->intf_uuid_list_.begin();
664  InstanceList::iterator it = intf_list_.begin();
665  while (it_cfg != data->intf_uuid_list_.end() ||
666  it != intf_list_.end()) {
667  if (it_cfg == data->intf_uuid_list_.end() ||
668  ((it != intf_list_.end()) && ((*it_cfg) > it->first))) {
669  InstanceList::iterator it_prev = it;
670  it++;
671  StopHealthCheckService(it_prev->second);
672  intf_list_.erase(it_prev);
673  ret = true;
674  } else {
675  if ((it == intf_list_.end()) || ((*it_cfg) < it->first)) {
676  VmInterfaceKey key(AgentKey::ADD_DEL_CHANGE, (*it_cfg), "");
677  VmInterface *intf = static_cast<VmInterface *>
678  (table_->agent()->interface_table()->Find(&key, false));
679  // interface might be unavailable if config is received
680  // before nova message for interface creation, in such case
681  // skip adding instancee for this interface
682  // config dependency manager will then ensure re-notification
683  // of dependent config Health-Check-Service in this case to
684  // handle creation of interface later
685  if (intf != NULL) {
686  IpAddress source_ip;
687  IpAddress destination_ip = dest_ip_;
688  VmInterface *paired_vmi = NULL;
690  paired_vmi = intf->PortTuplePairedInterface();
691  if (paired_vmi == NULL) {
692  it_cfg++;
693  continue;
694  }
695  destination_ip = paired_vmi->GetServiceIp
696  (paired_vmi->primary_ip_addr());
697  if (destination_ip.is_unspecified()) {
698  it_cfg++;
699  continue;
700  }
701  }
703  source_ip = intf->GetGatewayIp(intf->primary_ip_addr());
705  // Note that a new instance is alway used when starting
706  // hence the same instance will not be re-used for a
707  // different service. From this we can be sure that once
708  // an instance is deleted it will not be re-used.
709  StartHealthCheckService(intf, paired_vmi, source_ip,
710  destination_ip, MacAddress(),
711  false, false);
712  intf_list_.insert(std::pair<boost::uuids::uuid,
713  HealthCheckInstanceBase *>(*(it_cfg), inst));
714  ret = true;
715  }
716  } else {
717  if (dest_ip_changed || IsInstanceTaskBased()) {
718  // change in destination IP needs to be propagated
719  // explicitly to metadata-IP object
720  it->second->set_destination_ip(dest_ip_);
721  }
722  it++;
723  }
724  it_cfg++;
725  }
726  }
727 
728  return ret;
729 }
730 
732  InstanceList::iterator it = intf_list_.begin();
733  while (it != intf_list_.end()) {
734  it->second->set_service(this);
735  it++;
736  }
737 }
738 
740  const HealthCheckService *service,
741  const VmInterface *itf) const {
742  DBRequest req;
744  req.key.reset(new HealthCheckServiceKey(service->uuid(), AgentKey::RESYNC));
745  req.data.reset(new HealthCheckResyncInterfaceData(NULL, NULL, itf));
746  service->table()->agent()->health_check_table()->Enqueue(&req);
747 }
748 
750  const HealthCheckService *service,
751  const VmInterface *intf) {
752  InstanceList::iterator it;
753 
754  it = intf_list_.find(intf->vmi_cfg_uuid());
755  if (it != intf_list_.end()) {
756  HEALTH_CHECK_TRACE(Trace, "Enqueue instance " + intf->name());
757  it->second->EnqueueHealthCheckResync(service, intf);
758  } else {
759  HEALTH_CHECK_TRACE(Trace, "Enqueue instance not found " + intf->name());
760  }
761 }
762 
764  const VmInterface *intf) {
765  InstanceList::iterator it;
766 
767  it = intf_list_.find(intf->vmi_cfg_uuid());
768  if (it != intf_list_.end()) {
769  it->second->set_service(this);
770  } else {
771  HEALTH_CHECK_TRACE(Trace, "Service not found :" + intf->name());
772  }
773 }
774 
776  InstanceList::iterator it = intf_list_.begin();
777  while (it != intf_list_.end()) {
778  StopHealthCheckService(it->second);
779  intf_list_.erase(it);
780  it = intf_list_.begin();
781  }
782 }
783 
785 
787  const std::string &name) :
788  AgentOperDBTable(db, name) {
789  set_agent(agent);
792  boost::bind(&HealthCheckTable::InstanceEventProcess, this, _1));
793  inst_event_queue_->set_name("HealthCheck instance event queue");
794 }
795 
798  delete inst_event_queue_;
799 }
800 
802  const std::string &name) {
803  HealthCheckTable *health_check_table =
804  new HealthCheckTable(agent, db, name);
805  (static_cast<DBTable *>(health_check_table))->Init();
806  return health_check_table;
807 };
808 
809 std::unique_ptr<DBEntry>
811  const HealthCheckServiceKey *key =
812  static_cast<const HealthCheckServiceKey *>(k);
813  HealthCheckService *service = new HealthCheckService(this, key->uuid_);
814  return std::unique_ptr<DBEntry>(static_cast<DBEntry *>(service));
815 }
816 
818  HealthCheckServiceKey *key =
819  static_cast<HealthCheckServiceKey *>(req->key.get());
820  HealthCheckServiceData *data =
821  static_cast<HealthCheckServiceData *>(req->data.get());
822  HealthCheckService *service = new HealthCheckService(this, key->uuid_);
823  service->Copy(this, data);
824  return service;
825 }
826 
828  /*
829  * Ideally db-infra should have removed the delete mark for the db-entry
830  * when Add/Update happens for the db-entry. It has to be root-caused.
831  * For now it is handled here and doing here wont give any side-effects.
832  */
833  bool ret = false;
834  if (entry->IsDeleted()) {
835  entry->ClearDelete();
836  ret = true;
837  }
838  HealthCheckService *service = static_cast<HealthCheckService *>(entry);
839  HealthCheckServiceData *data =
840  dynamic_cast<HealthCheckServiceData *>(req->data.get());
841  assert(data);
842  ret |= service->Copy(this, data);
844  return ret;
845 }
846 
848  HealthCheckResyncInterfaceData *resync_data =
849  dynamic_cast<HealthCheckResyncInterfaceData *>(req->data.get());
850  if (resync_data) {
851  // resync triggered from Vmi for which there is no source ip specified
852  // in the interface health check service instance.
853  HEALTH_CHECK_TRACE(Trace, "Resync interface " + resync_data->intf_->name());
854  HealthCheckService *service = static_cast<HealthCheckService *>(entry);
855  service->UpdateInterfaceInstanceServiceReference(resync_data->intf_);
856  return false;
857  }
858 
859  return OperDBOnChange(entry, req);
860 }
861 
863  HealthCheckService *service = static_cast<HealthCheckService *>(entry);
864  service->DeleteInstances();
865  return true;
866 }
867 
868 
870  return new HealthCheckServiceKey(u);
871 }
872 
874  const autogen::ServiceHealthCheck *s) {
875  boost::system::error_code ec;
876  const autogen::ServiceHealthCheckType &p = s->properties();
877  Ip4Address dest_ip;
878  std::string url_path;
879  uint8_t ip_proto = 0;
880  uint16_t url_port = 0;
881  if (p.monitor_type.find("BFD") != std::string::npos) {
882  boost::system::error_code ec;
883  dest_ip = Ip4Address::from_string(p.url_path, ec);
884  url_path = p.url_path;
885  ip_proto = IPPROTO_UDP;
886  } else if (p.monitor_type.find("HTTP") == std::string::npos) {
887  boost::system::error_code ec;
888  dest_ip = Ip4Address::from_string(p.url_path, ec);
889  url_path = p.url_path;
890  ip_proto = IPPROTO_ICMP;
891  } else if (!p.url_path.empty()) {
892  ip_proto = IPPROTO_TCP;
893  // parse url if available
894  struct http_parser_url urldata;
895  int ret = http_parser_parse_url(p.url_path.c_str(), p.url_path.size(),
896  false, &urldata);
897  if (ret == 0) {
898  if (urldata.field_set & (1 << UF_HOST)) {
899  std::string dest_ip_str =
900  p.url_path.substr(urldata.field_data[UF_HOST].off,
901  urldata.field_data[UF_HOST].len);
902  // Parse dest-ip from the url to translate to metadata IP
903  dest_ip = Ip4Address::from_string(dest_ip_str, ec);
904  // keep rest of the url string as is
905  url_path = p.url_path.substr(urldata.field_data[UF_HOST].off +\
906  urldata.field_data[UF_HOST].len);
907  }
908  url_port = urldata.port;
909  if ((urldata.field_set & (1 << UF_PORT)) == 0) {
910  url_port = 80;
911  }
912  }
913  }
914 
915  bool is_all_ip = false;
916  if (p.target_ip_all) {
917  is_all_ip = true;
918  }
919  std::set<IpAddress> ip_address_list;
920  for (unsigned int i = 0; i < p.target_ip_list.ip_address.size(); ++i) {
921  boost::system::error_code ec;
922  IpAddress ip = Ip4Address::from_string(p.target_ip_list.ip_address[i], ec);
923  if (ec.value() != 0) {
924  ip = Ip6Address::from_string(p.target_ip_list.ip_address[i], ec);
925  }
926  if (ec.value() != 0) {
927  continue;
928  }
929 
930  ip_address_list.insert(ip);
931  }
932 
933  HealthCheckServiceData *data =
934  new HealthCheckServiceData(agent, dest_ip, node->name(),
935  p.monitor_type, p.health_check_type,
936  ip_proto, p.http_method,
937  url_path, url_port, p.expected_codes,
938  p.delay, p.delayUsecs, p.timeout,
939  p.timeoutUsecs, p.max_retries,
940  is_all_ip, ip_address_list, node);
941 
942  IFMapAgentTable *table = static_cast<IFMapAgentTable *>(node->table());
944  node->begin(table->GetGraph());
945  iter != node->end(table->GetGraph()); ++iter) {
946  IFMapNode *adj_node = static_cast<IFMapNode *>(iter.operator->());
947  if (agent->config_manager()->SkipNode(adj_node)) {
948  continue;
949  }
950 
951  if (adj_node->table() == agent->cfg()->cfg_vm_interface_table()) {
952  boost::uuids::uuid intf_uuid;
953  autogen::VirtualMachineInterface *intf =
954  dynamic_cast<autogen::VirtualMachineInterface *>(adj_node->GetObject());
955  assert(intf);
956  const autogen::IdPermsType &id_perms = intf->id_perms();
957  CfgUuidSet(id_perms.uuid.uuid_mslong,
958  id_perms.uuid.uuid_lslong, intf_uuid);
959 
960  data->intf_uuid_list_.insert(intf_uuid);
961  }
962  if (adj_node->table() == agent->cfg()->cfg_vn_table()) {
963  boost::uuids::uuid vn_uuid;
964  autogen::VirtualNetwork *vn =
965  dynamic_cast<autogen::VirtualNetwork *>(adj_node->GetObject());
966  assert(vn);
967  const autogen::IdPermsType &id_perms = vn->id_perms();
968  CfgUuidSet(id_perms.uuid.uuid_mslong,
969  id_perms.uuid.uuid_lslong, vn_uuid);
970 
971  data->vn_uuid_list_.insert(vn_uuid);
972  }
973  }
974  return data;
975 }
976 
978  const boost::uuids::uuid &u) {
979  autogen::ServiceHealthCheck *service =
980  static_cast<autogen::ServiceHealthCheck *>(node->GetObject());
981  assert(service);
982 
983  assert(!u.is_nil());
984 
985  req.key.reset(BuildKey(u));
986  if ((req.oper == DBRequest::DB_ENTRY_DELETE) || node->IsDeleted()) {
988  return true;
989  }
990 
992  return false;
993 }
994 
996  const boost::uuids::uuid &u) {
997  autogen::ServiceHealthCheck *service =
998  static_cast <autogen::ServiceHealthCheck *>(node->GetObject());
999  assert(service);
1000 
1001  req.key.reset(BuildKey(u));
1002  if (node->IsDeleted()) {
1004  return true;
1005  }
1006 
1008  req.data.reset(BuildData(agent(), node, service));
1009  Enqueue(&req);
1010 
1011  return false;
1012 }
1013 
1015  autogen::ServiceHealthCheck *service =
1016  static_cast<autogen::ServiceHealthCheck *>(node->GetObject());
1017  autogen::IdPermsType id_perms = service->id_perms();
1018  CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u);
1019  return true;
1020 }
1021 
1022 
1024  HealthCheckServiceKey key(u);
1025  return static_cast<HealthCheckService *>(FindActiveEntry(&key));
1026 }
1027 
1028 void
1030  inst_event_queue_->Enqueue(event);
1031 }
1032 
1034  HealthCheckInstanceBase *inst = event->instance_;
1035  switch (event->type_) {
1037  {
1038  // We dont want to process status messages as the instance delete
1039  // has ben queued.
1040  if (inst->deleted_) {
1042  "Read Event while deleted! " + inst->to_string());
1043  break;
1044  }
1045  if (inst->IsStatusEventIgnored())
1046  break;
1048  std::string msg = event->message_;
1049  boost::algorithm::to_lower(msg);
1050  if (msg.find("success") != std::string::npos) {
1051  if (!inst->active_) {
1052  inst->active_ = true;
1053  inst->ResyncTarget(inst->service_.get());
1054  }
1055  }
1056  if (msg.find("failure") != std::string::npos) {
1057  if (inst->active_) {
1058  inst->active_ = false;
1059  inst->ResyncTarget(inst->service_.get());
1060  }
1061  }
1063  " Received msg = " + event->message_);
1064  }
1065  break;
1066 
1068  if (inst->IsStatusEventIgnored())
1069  break;
1070  if (!inst->deleted_) {
1071  HEALTH_CHECK_TRACE(Trace, "Restarting " + inst->to_string());
1072  inst->RunInstanceTask();
1073  } else {
1074  HEALTH_CHECK_TRACE(Trace, "Stopped " + inst->to_string());
1075  delete inst;
1076  }
1077  break;
1078 
1080  inst->set_service(event->service_);
1081  break;
1082 
1084  inst->DestroyInstanceTask();
1085  // Freeing instance is handled here and not in any other task context.
1086  // Unconditionally delete here since DestroyInstanceTask() may have
1087  // alrady been called in the db::DBTable task context before queueing
1088  // this event.
1089  delete inst;
1090  break;
1091 
1092  default:
1093  // unhandled event
1094  assert(0);
1095  }
1096 
1097  delete event;
1098  return true;
1099 }
1100 
1103  const std::string &context) {
1104  return AgentSandeshPtr(new AgentHealthCheckSandesh(context,
1105  args->GetString("uuid")));
1106 }
1107 
1108 void HealthCheckSandeshReq::HandleRequest() const {
1109  AgentSandeshPtr sand(new AgentHealthCheckSandesh(context(), get_uuid()));
1110  sand->DoSandesh(sand);
1111 }
1112 
void ResyncHealthCheckInterface(const HealthCheckService *service, const VmInterface *intf)
virtual bool OperDBDelete(DBEntry *entry, const DBRequest *req)
InterfaceRef interface() const
Definition: health_check.h:147
virtual void ResyncTarget(const HealthCheckService *service) const
Definition: health_check.cc:77
virtual ~HealthCheckInstanceEvent()
virtual bool IFNodeToUuid(IFMapNode *node, boost::uuids::uuid &u)
virtual bool OperDBOnChange(DBEntry *entry, const DBRequest *req)
virtual bool DestroyInstanceTask()=0
void EnqueueResync(const HealthCheckService *service, Interface *itf) const
Definition: health_check.cc:68
bool DBEntrySandesh(Sandesh *resp, std::string &name) const
bool InstanceEventProcess(HealthCheckInstanceEvent *event)
HealthCheckService(const HealthCheckTable *table, const boost::uuids::uuid &id)
virtual AgentSandeshPtr GetAgentSandesh(const AgentSandeshArguments *args, const std::string &context)
static void CfgUuidSet(uint64_t ms_long, uint64_t ls_long, boost::uuids::uuid &u)
Definition: agent_cmn.h:67
void set_source_ip(const IpAddress &ip)
Definition: health_check.h:151
boost::uuids::uuid uuid_
Definition: health_check.h:367
void Shutdown(bool delete_entries=true)
Definition: queue_task.h:152
std::set< boost::uuids::uuid > vn_uuid_list_
Definition: health_check.h:86
virtual bool StopInstanceTask()
virtual bool DestroyInstanceTask()
#define HEALTH_CHECK_TRACE(obj,...)
Definition: health_check.h:13
void AddHealthCheckServiceNode(IFMapNode *node)
std::string GetString(const std::string &key) const
const boost::uuids::uuid & GetUuid() const
Definition: interface.h:113
HealthCheckService * service() const
Definition: health_check.h:146
HealthCheckInstanceService(HealthCheckService *service, MetaDataIpAllocator *allocator, VmInterface *intf, VmInterface *other_intf, bool ignore_status_event, bool multi_hop)
bool ProcessConfig(IFMapNode *node, DBRequest &req, const boost::uuids::uuid &u)
IpAddress destination_ip() const
virtual bool IFNodeToReq(IFMapNode *node, DBRequest &req, const boost::uuids::uuid &u)
HealthCheckType health_check_type_
Definition: health_check.h:388
void InsertHealthCheckInstance(HealthCheckInstanceBase *hc_inst)
bool IsDeleted() const
Definition: db_entry.h:49
void UpdateInterfaceInstanceServiceReference(const VmInterface *intf)
ConfigManager * config_manager() const
Definition: agent.cc:889
std::string url_path_
Definition: health_check.h:377
void StopTask(HealthCheckService *service)
std::string http_method_
Definition: health_check.h:376
std::set< IpAddress > new_target_ip_list_
Definition: health_check.h:88
boost::asio::ip::address IpAddress
Definition: address.h:13
virtual void ResyncTarget(const HealthCheckService *service) const
virtual ~HealthCheckTable()
Agent * agent() const
Definition: agent_db.h:213
std::unique_ptr< DBRequestData > data
Definition: db_table.h:49
const HealthCheckTable * table() const
Definition: health_check.h:337
HealthCheckService * service_
Definition: health_check.h:107
AgentDBEntry * FindActiveEntry(const DBEntry *key)
Definition: agent_db.cc:110
InterfaceTable * interface_table() const
Definition: agent.h:465
bool Enqueue(DBRequest *req)
Definition: db_table.cc:194
virtual bool RunInstanceTask()=0
boost::uuids::uuid uuid
#define kTaskHealthCheck
Definition: agent.h:333
Definition: task_int.h:10
WorkQueue< HealthCheckInstanceEvent * > * inst_event_queue_
Definition: health_check.h:458
HealthCheckMacIpInstanceService(HealthCheckService *service, MetaDataIpAllocator *allocator, VmInterface *intf, VmInterface *other_intf, bool ignore_status_event, bool multi_hop)
adjacency_iterator end(DBGraph *graph)
static std::string UuidToString(const boost::uuids::uuid &id)
Definition: string_util.h:138
void set_destination_ip(const IpAddress &ip)
virtual std::string ToString() const
virtual std::unique_ptr< DBEntry > AllocEntry(const DBRequestKey *k) const
IFMapTable * table()
Definition: ifmap_node.h:29
boost::scoped_ptr< MetaDataIp > ip_
Definition: health_check.h:169
MetaDataIp * ip() const
Definition: health_check.h:148
IpAddress GetServiceIp(const IpAddress &ip) const
boost::shared_ptr< TraceBuffer< SandeshTrace > > SandeshTraceBufferPtr
Definition: sandesh_trace.h:18
void set_service(HealthCheckService *service)
Definition: health_check.cc:82
std::unique_ptr< DBRequestKey > KeyPtr
Definition: db_entry.h:25
virtual bool UpdateInstanceTask()
HealthCheckInstanceTask(HealthCheckService *service, MetaDataIpAllocator *allocator, VmInterface *intf, bool ignore_status_event)
std::string monitor_type_
Definition: health_check.h:72
virtual bool OperDBResync(DBEntry *entry, const DBRequest *req)
int GetTaskId(const std::string &name)
Definition: task.cc:856
const VmInterface * intf_
Definition: health_check.h:468
virtual DBEntry * OperDBAdd(const DBRequest *req)
void StopHealthCheckService(HealthCheckInstanceBase *instance)
HealthCheckTable(Agent *agent, DB *db, const std::string &name)
virtual bool StopInstanceTask()
Definition: db.h:24
static const std::string kHealthCheckCmd
Definition: health_check.h:192
MetaDataIpAllocator * metadata_ip_allocator() const
Definition: agent.cc:949
IFMapAgentTable * cfg_vm_interface_table() const
Definition: cfg_init.h:22
uint64_t timeout_usecs_
Definition: health_check.h:384
const HealthCheckTable * table_
Definition: health_check.h:366
virtual ~HealthCheckInstanceTask()
InstanceList intf_list_
Definition: health_check.h:387
TaskScheduler * task_scheduler() const
Definition: agent.h:1120
uint8_t type
Definition: load_balance.h:109
virtual void SetKey(const DBRequestKey *key)
Definition: agent.h:358
bool IsSegmentHealthCheckService() const
HealthCheckServiceRef service_
Definition: health_check.h:165
std::unique_ptr< DBRequestKey > key
Definition: db_table.h:48
void InstanceEventEnqueue(HealthCheckInstanceEvent *event) const
DBOperation oper
Definition: db_table.h:42
Definition: trace.h:220
void OnExit(const boost::system::error_code &ec)
void SetService(HealthCheckService *service)
std::string http_method_
Definition: health_check.h:76
virtual KeyPtr GetDBRequestKey() const
virtual bool IsLess(const DBEntry &rhs) const
HealthCheckInstanceEvent(HealthCheckInstanceBase *inst, HealthCheckService *service, EventType type, const std::string &message)
static HealthCheckServiceData * BuildData(Agent *agent, IFMapNode *node, const autogen::ServiceHealthCheck *s)
class boost::shared_ptr< AgentSandesh > AgentSandeshPtr
Definition: agent_db.h:18
boost::uuids::uuid uuid_
Definition: health_check.h:40
AgentDBEntry * Find(const DBEntry *key, bool ret_del)
Definition: agent_db.cc:134
std::string expected_codes_
Definition: health_check.h:79
void ClearDelete()
Definition: db_entry.h:48
virtual bool UpdateInstanceTask()
Definition: health_check.h:130
IpAddress source_ip() const
InstanceTaskExecvp HeathCheckProcessInstance
Definition: health_check.h:191
const std::string & name() const
Definition: ifmap_node.h:48
std::set< boost::uuids::uuid > vn_uuid_list_
Definition: health_check.h:390
boost::asio::ip::address_v4 Ip4Address
Definition: address.h:14
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 service_type_
Definition: health_check.h:74
static DBTableBase * CreateTable(Agent *agent, DB *db, const std::string &name)
void DeleteHealthCheckInstance(HealthCheckInstanceBase *hc_inst)
const Ip4Address & primary_ip_addr() const
const boost::uuids::uuid & uuid() const
Definition: health_check.h:325
IFMapObject * GetObject()
Definition: ifmap_node.cc:63
HealthCheckInstanceBase(HealthCheckService *service, MetaDataIpAllocator *allocator, VmInterface *intf, bool ignore_status_event)
Definition: health_check.cc:41
virtual void ResyncTarget(const HealthCheckService *service) const
bool Copy(HealthCheckTable *table, const HealthCheckServiceData *data)
HealthCheckTable * health_check_table() const
Definition: agent.cc:933
std::string name_
Definition: health_check.h:369
HealthCheckService * Find(const boost::uuids::uuid &u)
static uint64_t UTCTimestampUsec()
Definition: time_util.h:13
void EnqueueHealthCheckResync(const HealthCheckService *service, const VmInterface *itf) const
std::string expected_codes_
Definition: health_check.h:380
virtual bool CreateInstanceTask()
IpAddress update_source_ip()
const boost::uuids::uuid & vmi_cfg_uuid() const
static HealthCheckServiceKey * BuildKey(const boost::uuids::uuid &u)
SandeshTraceBufferPtr HealthCheckTraceBuf
std::set< IpAddress > target_ip_list_
Definition: health_check.h:391
std::string last_update_time_
Definition: health_check.h:173
virtual void set_destination_mac(const MacAddress &mac)
Definition: health_check.h:258
std::set< boost::uuids::uuid > intf_uuid_list_
Definition: health_check.h:85
const std::string & name() const
Definition: interface.h:114
std::string monitor_type_
Definition: health_check.h:371
IFMapAgentTable * cfg_vn_table() const
Definition: cfg_init.h:26
VmInterface * PortTuplePairedInterface() const
IpAddress GetGatewayIp(const IpAddress &ip) const
bool IsVnIpListHealthCheckService() const
bool IsInstanceTaskBased() const
AgentConfig * cfg() const
Definition: agent.cc:865
virtual bool RunInstanceTask()
void OnRead(const std::string &data)
bool SkipNode(IFMapNode *node)
std::string service_type_
Definition: health_check.h:373
void UpdateInstanceServiceReference()
virtual bool DestroyInstanceTask()
virtual bool IsRunning() const
adjacency_iterator begin(DBGraph *graph)
HealthCheckType GetHealthCheckType() const
virtual ~HealthCheckInstanceBase()
Definition: health_check.cc:60
bool Enqueue(QueueEntryT entry)
Definition: queue_task.h:248
void set_name(const std::string &name)
Definition: queue_task.h:307
virtual bool RunInstanceTask()
bool IsStatusEventIgnored() const
Definition: health_check.h:150
virtual bool CreateInstanceTask()=0
void set_agent(Agent *agent)
Definition: agent_db.h:212
SandeshTraceBufferPtr SandeshTraceBufferCreate(const std::string &buf_name, size_t buf_size, bool trace_enable=true)
Definition: sandesh_trace.h:46
static std::string UTCUsecToString(uint64_t tstamp)
Definition: time_util.h:54
virtual bool CreateInstanceTask()