LCOV - code coverage report
Current view: top level - vnsw/agent/oper - health_check.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 17 675 2.5 %
Date: 2026-11-09 02:10:49 Functions: 4 81 4.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14