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 666 2.6 %
Date: 2026-06-04 02:06:09 Functions: 4 80 5.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14