LCOV - code coverage report
Current view: top level - vnsw/agent/oper - instance_manager.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 78 518 15.1 %
Date: 2026-11-09 02:10:49 Functions: 8 42 19.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "oper/instance_manager.h"
       7             : 
       8             : #include <boost/bind/bind.hpp>
       9             : #include <boost/functional/hash.hpp>
      10             : #include <boost/filesystem.hpp>
      11             : #include <boost/tokenizer.hpp>
      12             : #include <sys/wait.h>
      13             : #include "cmn/agent.h"
      14             : #include "db/db.h"
      15             : #include "io/event_manager.h"
      16             : #include "oper/instance_task.h"
      17             : #include "oper/operdb_init.h"
      18             : #include "oper/service_instance.h"
      19             : #include "oper/vm.h"
      20             : #include "oper/docker_instance_adapter.h"
      21             : #include "oper/netns_instance_adapter.h"
      22             : #ifdef WITH_LIBVIRT
      23             :     #include "oper/libvirt_instance_adapter.h"
      24             : #endif
      25             : #include "base/util.h"
      26             : 
      27             : using namespace boost::placeholders;
      28             : 
      29             : using boost::uuids::uuid;
      30             : SandeshTraceBufferPtr InstanceManagerTraceBuf(
      31             :         SandeshTraceBufferCreate("InstanceManager", 1000));
      32             : 
      33             : static const char loadbalancer_config_path_default[] =
      34             :         "/var/lib/contrail/loadbalancer/";
      35             : static const char namespace_store_path_default[] =
      36             :         "/var/run/netns";
      37             : static const char namespace_prefix[] = "vrouter-";
      38             : 
      39             : class InstanceManager::NamespaceStaleCleaner {
      40             : public:
      41          19 :     NamespaceStaleCleaner(Agent *agent, InstanceManager *manager)
      42          19 :             : agent_(agent), manager_(manager) {
      43          19 :     }
      44             : 
      45          19 :     void CleanStaleEntries() {
      46             :         namespace fs = boost::filesystem;
      47             : 
      48             :         //Read all the Namepaces in the system
      49          19 :         fs::path ns(manager_->namespace_store_path_);
      50          19 :         if ( !fs::exists(ns) || !fs::is_directory(ns)) {
      51          19 :             return;
      52             :         }
      53             : 
      54             :         typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
      55           0 :         boost::char_separator<char> slash_sep("/");
      56           0 :         boost::char_separator<char> colon_sep(":");
      57           0 :         fs::directory_iterator end_iter;
      58           0 :         for(fs::directory_iterator iter(ns); iter != end_iter; iter++) {
      59             : 
      60             :             // Get to the name of namespace by removing complete path
      61           0 :             tokenizer tokens(iter->path().string(), slash_sep);
      62           0 :             std::string ns_name;
      63           0 :             for(tokenizer::iterator it=tokens.begin(); it!=tokens.end(); it++){
      64           0 :                 ns_name = *it;
      65           0 :             }
      66             : 
      67             :             //We are interested only in namespaces starting with a given
      68             :             //prefix
      69             :             std::size_t vrouter_found;
      70           0 :             vrouter_found = ns_name.find(namespace_prefix);
      71           0 :             if (vrouter_found == std::string::npos) {
      72           0 :                 continue;
      73             :             }
      74             : 
      75             :             //Remove the standard prefix
      76           0 :             ns_name.replace(vrouter_found, strlen(namespace_prefix), "");
      77             : 
      78             :             //Namespace might have a ":". Extract both left and right of
      79             :             //":" Left of ":" is the VM uuid. If not found in Agent's VM
      80             :             //DB, it can be deleted
      81           0 :             tokenizer tok(ns_name, colon_sep);
      82           0 :             boost::uuids::uuid vm_uuid = StringToUuid(*tok.begin());
      83           0 :             VmKey key(vm_uuid);
      84           0 :             if (agent_->vm_table()->Find(&key, true)) {
      85           0 :                 continue;
      86             :             }
      87             : 
      88           0 :             ServiceInstance::Properties prop;
      89           0 :             prop.instance_id = vm_uuid;
      90           0 :             prop.service_type = ServiceInstance::SourceNAT;
      91           0 :             tokenizer::iterator next_tok = ++(tok.begin());
      92             :             //Loadbalancer namespace
      93           0 :             if (next_tok != tok.end()) {
      94           0 :                 prop.loadbalancer_id = *next_tok;
      95           0 :                 prop.service_type = ServiceInstance::LoadBalancer;
      96             :             }
      97             : 
      98             :             //Delete Namespace
      99           0 :             manager_->StopStaleNetNS(prop);
     100             : 
     101             :             //If Loadbalncer, delete the config files as well
     102           0 :             if (prop.service_type == ServiceInstance::LoadBalancer) {
     103             :                 //Delete the complete directory
     104           0 :                 std::stringstream pathgen;
     105           0 :                 pathgen << manager_->loadbalancer_config_path_
     106           0 :                         << prop.loadbalancer_id << ".conf";
     107             : 
     108           0 :                 boost::system::error_code error;
     109           0 :                 if (fs::exists(pathgen.str())) {
     110           0 :                     fs::remove(pathgen.str(), error);
     111           0 :                     if (error) {
     112           0 :                         std::stringstream ss;
     113           0 :                         ss << "Stale loadbalancer cfg fle delete error ";
     114           0 :                         ss << error.message();
     115           0 :                         INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     116           0 :                     }
     117             :                 }
     118           0 :             }
     119           0 :         }
     120          19 :     }
     121             : 
     122             : private:
     123             :     Agent *agent_;
     124             :     InstanceManager *manager_;
     125             : };
     126             : 
     127           2 : InstanceManager::~InstanceManager() {
     128           2 :     TimerManager::DeleteTimer(stale_timer_);
     129           2 :     STLDeleteValues(&adapters_);
     130           2 : }
     131             : 
     132           2 : InstanceManager::InstanceManager(Agent *agent)
     133           2 :         : si_listener_(DBTableBase::kInvalidId),
     134           2 :           netns_timeout_(-1),
     135           2 :           work_queue_(TaskScheduler::GetInstance()->GetTaskId(INSTANCE_MANAGER_TASK_NAME), 0,
     136             :                       boost::bind(&InstanceManager::DequeueEvent, this, _1)),
     137           2 :           loadbalancer_config_path_(loadbalancer_config_path_default),
     138           2 :           namespace_store_path_(namespace_store_path_default),
     139           2 :           stale_timer_interval_(5 * 60 * 1000),
     140           2 :           stale_timer_(TimerManager::CreateTimer(*(agent->event_manager()->io_service()),
     141             :                       "NameSpaceStaleTimer", TaskScheduler::GetInstance()->
     142           6 :                       GetTaskId(INSTANCE_MANAGER_TASK_NAME), 0)), agent_(agent) {
     143           2 :           if (agent->isMockMode()) {
     144           0 :               loadbalancer_config_path_ = "/tmp/" + agent->AgentGUID()
     145           0 :               + loadbalancer_config_path_default;
     146           0 :               namespace_store_path_ = "/tmp/" +  agent->AgentGUID()
     147           0 :               + namespace_store_path_default;
     148             :           }
     149           2 :           work_queue_.set_name("Instance Manager");
     150             : 
     151           2 : }
     152             : 
     153           2 : void InstanceManager::Initialize(DB *database, const std::string &netns_cmd,
     154             :                                  const std::string &docker_cmd,
     155             :                                  const int netns_workers,
     156             :                                  const int netns_timeout) {
     157           2 :     DBTableBase *si_table = agent_->service_instance_table();
     158           2 :     assert(si_table);
     159           2 :     si_listener_ = si_table->Register(
     160             :         boost::bind(&InstanceManager::EventObserver, this, _1, _2));
     161             : 
     162           2 :     netns_cmd_ = netns_cmd;
     163           2 :     if (netns_cmd_.length() == 0) {
     164           2 :         LOG(ERROR, "NetNS path for network namespace command not specified "
     165             :                    "in the config file, the namespaces won't be started");
     166             :     }
     167           2 :     if (docker_cmd.length() == 0) {
     168           2 :         LOG(ERROR, "Path for Docker starter command not specified "
     169             :                    "in the config file, the Docker instances won't be started");
     170             :     }
     171             : 
     172           2 :     std::stringstream pathgen;
     173           2 :     pathgen << loadbalancer_config_path_;
     174           2 :     boost::filesystem::path dir(pathgen.str());
     175           2 :     boost::system::error_code error;
     176           2 :     boost::filesystem::create_directories(dir, error);
     177           2 :     if (error) {
     178           0 :         LOG(ERROR, "Falied to create Loadbalancer Directory " << pathgen.str());
     179             :     }
     180             : 
     181           2 :     adapters_.push_back(new DockerInstanceAdapter(docker_cmd, agent_));
     182           2 :     adapters_.push_back(new NetNSInstanceAdapter(netns_cmd,
     183           2 :                         loadbalancer_config_path_, agent_));
     184             : #ifdef WITH_LIBVIRT
     185             :     adapters_.push_back(new LibvirtInstanceAdapter(agent_,
     186             :                         "qemu:///system"));
     187             : #endif
     188             : 
     189           2 :     netns_timeout_ = kTimeoutDefault;
     190           2 :     if (netns_timeout >= 1) {
     191           0 :         netns_timeout_ = netns_timeout;
     192             :     }
     193             : 
     194           2 :     netns_reattempts_ = kReattemptsDefault;
     195             : 
     196           2 :     int workers = kWorkersDefault;
     197           2 :     if (netns_workers > 0) {
     198           0 :        workers = netns_workers;
     199             :     }
     200             : 
     201           2 :     task_queues_.resize(workers);
     202           2 :     for (std::vector<InstanceTaskQueue *>::iterator iter = task_queues_.begin();
     203           4 :          iter != task_queues_.end(); ++iter) {
     204             :         InstanceTaskQueue *task_queue =
     205           2 :                 new InstanceTaskQueue(agent_->event_manager());
     206           2 :         assert(task_queue);
     207           2 :         task_queue->set_on_timeout_cb(
     208             :                         boost::bind(&InstanceManager::OnTaskTimeout,
     209             :                                     this, _1));
     210           2 :         *iter = task_queue;
     211             :     }
     212           2 :     stale_timer_->Start(StaleTimerInterval(),
     213             :                         boost::bind(&InstanceManager::StaleTimeout, this));
     214             : 
     215           2 : }
     216             : 
     217           0 : void InstanceManager::SetNetNSCmd(const std::string &netns_cmd) {
     218           0 :     ServiceInstance::Properties prop;
     219           0 :     prop.virtualization_type =
     220             :         ServiceInstance::ServiceInstance::NetworkNamespace;
     221             :     NetNSInstanceAdapter *adapter = static_cast<NetNSInstanceAdapter
     222           0 :         *>(FindApplicableAdapter(prop));
     223           0 :     if (adapter)
     224           0 :         adapter->set_cmd(netns_cmd);
     225           0 : }
     226             : 
     227           0 : void InstanceManager::SetStaleTimerInterval(int minutes) {
     228           0 :     stale_timer_interval_ = minutes * 60 * 1000;
     229           0 : }
     230             : 
     231           0 : void InstanceManager::OnTaskTimeout(InstanceTaskQueue *task_queue) {
     232           0 :     InstanceManagerChildEvent event;
     233           0 :     event.type = OnTaskTimeoutEvent;
     234           0 :     event.task_queue = task_queue;
     235             : 
     236           0 :     work_queue_.Enqueue(event);
     237           0 : }
     238             : 
     239           0 : void InstanceManager::OnTaskTimeoutEventHandler(InstanceManagerChildEvent event) {
     240           0 :     std::stringstream ss;
     241           0 :     ss << "TaskTimeOut for the TaskQ " << event.task_queue;
     242           0 :     INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     243             : 
     244           0 :     ScheduleNextTask(event.task_queue);
     245           0 : }
     246             : 
     247           0 : void InstanceManager::OnErrorEventHandler(InstanceManagerChildEvent event) {
     248           0 :     ServiceInstance *svc_instance = GetSvcInstance(event.task);
     249           0 :     if (!svc_instance) {
     250           0 :        return;
     251             :     }
     252             : 
     253           0 :     std::stringstream ss;
     254           0 :     ss << "Error for the Task " << event.task << " " << event.errors;
     255           0 :     INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     256             : 
     257           0 :     InstanceState *state = GetState(svc_instance);
     258           0 :     if (state != NULL) {
     259           0 :        state->set_errors(event.errors);
     260             :     }
     261           0 : }
     262             : 
     263           0 : void InstanceManager::OnExitEventHandler(InstanceManagerChildEvent event) {
     264           0 :     ServiceInstance *svc_instance = GetSvcInstance(event.task);
     265           0 :     if (!svc_instance) {
     266           0 :        return;
     267             :     }
     268             : 
     269           0 :     std::stringstream ss;
     270           0 :     ss << "Exit event for the Task " << event.task;
     271           0 :     INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     272             : 
     273           0 :     UpdateStateStatusType(event);
     274           0 :     for (std::vector<InstanceTaskQueue *>::iterator iter =
     275           0 :                   task_queues_.begin();
     276           0 :           iter != task_queues_.end(); ++iter) {
     277           0 :          InstanceTaskQueue *task_queue = *iter;
     278           0 :          if (!task_queue->Empty()) {
     279           0 :              if (task_queue->Front() == event.task) {
     280           0 :                  task_queue->Pop();
     281           0 :                  delete event.task;
     282           0 :                  task_queue->StopTimer();
     283           0 :                  DeleteState(svc_instance);
     284           0 :                  ScheduleNextTask(task_queue);
     285           0 :                  return;
     286             :              }
     287             :          }
     288             :     }
     289             : 
     290           0 : }
     291             : 
     292           0 : bool InstanceManager::DequeueEvent(InstanceManagerChildEvent event) {
     293           0 :     if (event.type == OnErrorEvent) {
     294           0 :         OnErrorEventHandler(event);
     295           0 :     } else if (event.type == OnTaskTimeoutEvent) {
     296           0 :         OnTaskTimeoutEventHandler(event);
     297           0 :     } else if (event.type == OnExitEvent) {
     298           0 :         OnExitEventHandler(event);
     299             :     }
     300             : 
     301           0 :     return true;
     302             : }
     303             : 
     304           0 : void InstanceManager::UpdateStateStatusType(InstanceManagerChildEvent event) {
     305           0 :     ServiceInstance* svc_instance = UnregisterSvcInstance(event.task);
     306           0 :     if (svc_instance) {
     307           0 :         InstanceState *state = GetState(svc_instance);
     308             : 
     309             :         // The below code might not really capture the errors that
     310             :         // occured in the child process. As we are relying on the pipe
     311             :         // status to identify child exit, even if child process ends up
     312             :         // in error state, pipe might return "success" because pipe is
     313             :         // closed without erros. But what we want to reflect is the
     314             :         // error of child process. If there is any error in the pipe
     315             :         // status, we show that as is. If not, if there is any error string
     316             :         // in error_, we mark the error status as -1.
     317             :         // pipe returning boost::system::errc::no_such_file_or_directory
     318             :         // error is considered as no pipe errors
     319             : 
     320           0 :         if (state != NULL) {
     321           0 :             int error_status = event.error_val;
     322           0 :             if (error_status ==
     323             :                         boost::system::errc::no_such_file_or_directory) {
     324           0 :                 error_status = 0;
     325             :             }
     326           0 :             if (!state->errors().empty()) {
     327           0 :                 if (error_status == 0) {
     328           0 :                     error_status = -1;
     329             :                 }
     330             :             }
     331             : 
     332           0 :             state->set_status(error_status);
     333             : 
     334           0 :             if (error_status != 0) {
     335           0 :                 if (state->status_type() != InstanceState::Timeout) {
     336           0 :                     state->set_status_type(InstanceState::Error);
     337             :                 }
     338           0 :             } else if (state->status_type() == InstanceState::Starting) {
     339           0 :                 state->set_status_type(InstanceState::Started);
     340           0 :             } else if (state->status_type() == InstanceState::Stopping) {
     341           0 :                 state->set_status_type(InstanceState::Stopped);
     342             :             }
     343             : 
     344           0 :             std::stringstream ss;
     345           0 :             ss << "For the task " << event.task << " error status " <<
     346           0 :                 error_status << " status type " << state->status_type();
     347           0 :             INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     348           0 :         }
     349             :     }
     350           0 : }
     351             : 
     352           0 : InstanceState *InstanceManager::GetState(ServiceInstance *svc_instance) const {
     353             :     return static_cast<InstanceState *>(
     354           0 :         svc_instance->GetState(agent_->service_instance_table(),
     355           0 :                                si_listener_));
     356             : }
     357             : 
     358           0 : InstanceState *InstanceManager::GetState(InstanceTask* task) const {
     359           0 :     ServiceInstance* svc_instance = GetSvcInstance(task);
     360           0 :     if (svc_instance) {
     361           0 :         InstanceState *state = GetState(svc_instance);
     362           0 :         return state;
     363             :     }
     364           0 :     return NULL;
     365             : }
     366             : 
     367           0 : void InstanceManager::SetState(ServiceInstance *svc_instance,
     368             :                                 InstanceState *state) {
     369           0 :     svc_instance->SetState(agent_->service_instance_table(),
     370             :                            si_listener_,state);
     371           0 : }
     372             : 
     373           0 : void InstanceManager::ClearState(ServiceInstance *svc_instance) {
     374           0 :     svc_instance->ClearState(agent_->service_instance_table(), si_listener_);
     375           0 : }
     376             : 
     377           0 : bool InstanceManager::DeleteState(ServiceInstance *svc_instance) {
     378             : 
     379           0 :     if (!svc_instance || !svc_instance->IsDeleted()) {
     380           0 :         return false;
     381             :     }
     382             : 
     383           0 :     InstanceState *state = GetState(svc_instance);
     384           0 :     if (state && !state->tasks_running()) {
     385           0 :         ClearState(svc_instance);
     386           0 :         delete state;
     387           0 :         ClearLastCmdType(svc_instance);
     388           0 :         return true;
     389             :     }
     390             : 
     391           0 :     return false;
     392             : }
     393             : 
     394             : 
     395           2 : void InstanceManager::StateClear() {
     396             :     DBTablePartition *partition = static_cast<DBTablePartition *>(
     397           2 :         agent_->service_instance_table()->GetTablePartition(0));
     398             : 
     399           2 :     if (!partition)
     400           0 :         return;
     401             : 
     402           2 :     DBEntryBase *next = NULL;
     403           2 :     for (DBEntryBase *entry = partition->GetFirst(); entry; entry = next) {
     404           0 :         next = partition->GetNext(entry);
     405             :         DBState *state =
     406           0 :             entry->GetState(agent_->service_instance_table(), si_listener_);
     407           0 :         if (state != NULL) {
     408           0 :             entry->ClearState(agent_->service_instance_table(), si_listener_);
     409           0 :             delete state;
     410           0 :             ClearLastCmdType(static_cast<ServiceInstance *>(entry));
     411             :         }
     412             :     }
     413             : }
     414             : 
     415           2 : void InstanceManager::Terminate() {
     416           2 :     StateClear();
     417           2 :     agent_->service_instance_table()->Unregister(si_listener_);
     418           2 :     agent_->service_instance_table()->Clear();
     419             : 
     420             :     InstanceTaskQueue *task_queue;
     421           2 :     for (std::vector<InstanceTaskQueue *>::iterator iter = task_queues_.begin();
     422           4 :          iter != task_queues_.end(); ++iter) {
     423           2 :         if ((task_queue = *iter) == NULL) {
     424           0 :             continue;
     425             :         }
     426           2 :         task_queue->Clear();
     427             : 
     428           2 :         delete task_queue;
     429             :     }
     430           2 :     work_queue_.Shutdown();
     431           2 : }
     432             : 
     433           0 : void InstanceManager::Enqueue(InstanceTask *task,
     434             :                               const boost::uuids::uuid &uuid) {
     435           0 :     std::stringstream ss;
     436           0 :     ss << uuid;
     437           0 :     InstanceTaskQueue *task_queue = GetTaskQueue(ss.str());
     438           0 :     task_queue->Push(task);
     439           0 :     ScheduleNextTask(task_queue);
     440           0 : }
     441             : 
     442           0 : InstanceTaskQueue *InstanceManager::GetTaskQueue(const std::string &str) {
     443             :     boost::hash<std::string> hash;
     444           0 :     int index = hash(str) % task_queues_.size();
     445           0 :     return task_queues_[index];
     446             : }
     447             : 
     448             : //After Run(), if child process is running, we keep the task status as
     449             : //"Starting" or "Stopping". We start a timer to track TaskTimeout time.
     450             : //if process is not runnning, we verify how many times we already attempted
     451             : //to run. If netns_reattempts_ are already crossed, we return false,
     452             : // so that caller deletes the task without running any further.
     453             : //If required reattempts are not done, we start a timer and return true
     454             : // so that same task is run again after the timeout. The task status is set to
     455             : //"reattempt" to track reattempt case
     456           0 : bool InstanceManager::StartTask(InstanceTaskQueue *task_queue,
     457             :                                 InstanceTask *task) {
     458             : 
     459             : 
     460           0 :     InstanceState *state = GetState(task);
     461           0 :     if (state) {
     462           0 :         state->reset_errors();
     463             :     }
     464             : 
     465             :     pid_t pid;
     466           0 :     bool status = task->Run();
     467             : 
     468           0 :     std::stringstream ss;
     469           0 :     ss << "Run status for the task " << task << " " << status;
     470           0 :     ss << " With running status " << task->is_running();
     471           0 :     INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     472             : 
     473           0 :     if (status || task->is_running()) {
     474           0 :         pid = task->pid();
     475           0 :         if (state != NULL) {
     476           0 :             state->set_pid(pid);
     477           0 :             state->set_cmd(task->cmd());
     478           0 :             if (task->cmd_type() == Start) {
     479           0 :                 state->set_status_type(InstanceState::Starting);
     480             :             } else {
     481           0 :                 state->set_status_type(InstanceState::Stopping);
     482             :             }
     483             :         }
     484             :     } else {
     485             : 
     486           0 :         ss.str(std::string());
     487           0 :         ss << "Run failure for the task " << task << " attempt " << task->reattempts();
     488           0 :         INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     489             : 
     490           0 :         if (state) {
     491           0 :             state->set_status_type(InstanceState::Reattempt);
     492           0 :             state->set_cmd(task->cmd());
     493             :         }
     494           0 :         if (task->incr_reattempts() > netns_reattempts_) {
     495           0 :             ss.str(std::string());
     496           0 :             ss << "Run failure for the task " << task << " attempts exceeded";
     497           0 :             INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     498           0 :             return false;
     499             :         }
     500             :     }
     501             : 
     502           0 :     task_queue->StartTimer(netns_timeout_ * 1000);
     503             : 
     504           0 :     return true;
     505           0 : }
     506             : 
     507             : //If Starting the task succeds we wait for another event on that task.
     508             : //If not the task is removed from the front of the queue and is delted.
     509           0 : void InstanceManager::ScheduleNextTask(InstanceTaskQueue *task_queue) {
     510           0 :     while (!task_queue->Empty()) {
     511             : 
     512           0 :         InstanceTask *task = task_queue->Front();
     513           0 :         InstanceState *state = GetState(task);
     514             : 
     515           0 :         if (!task->is_running()) {
     516           0 :             bool status = StartTask(task_queue, task);
     517           0 :             if (status) {
     518           0 :                 return;
     519             :             }
     520             :         } else {
     521           0 :             int delay = time(NULL) - task->start_time();
     522           0 :             if (delay < netns_timeout_) {
     523           0 :                return;
     524             :             }
     525           0 :             if (state) {
     526           0 :                 state->set_status_type(InstanceState::Timeout);
     527             :             }
     528             : 
     529           0 :             std::stringstream ss;
     530           0 :             ss << "Timeout for the Task " << task << " delay " << delay;
     531           0 :             ss << " netns timeout " << netns_timeout_ << " ";
     532           0 :             ss << task->cmd();
     533           0 :             INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     534             : 
     535           0 :             if (delay >= (netns_timeout_ * 2)) {
     536           0 :                task->Terminate();
     537           0 :                if (task->IsSetup())
     538           0 :                    return;
     539             :             } else {
     540           0 :                task->Stop();
     541           0 :                return;
     542             :             }
     543           0 :         }
     544             : 
     545           0 :         task_queue->StopTimer();
     546           0 :         task_queue->Pop();
     547             : 
     548           0 :         ServiceInstance* svc_instance = GetSvcInstance(task);
     549           0 :         if (state && svc_instance)
     550           0 :             state->decr_tasks_running();
     551             : 
     552           0 :         task_svc_instances_.erase(task);
     553             : 
     554           0 :         std::stringstream ss;
     555           0 :         ss << "Delete of the Task " << task;
     556           0 :         INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     557             : 
     558           0 :         DeleteState(svc_instance);
     559             : 
     560           0 :         delete task;
     561           0 :     }
     562             : }
     563             : 
     564           0 : ServiceInstance *InstanceManager::GetSvcInstance(InstanceTask *task) const {
     565             :     TaskSvcMap::const_iterator iter =
     566           0 :                     task_svc_instances_.find(task);
     567           0 :     if (iter != task_svc_instances_.end()) {
     568           0 :         return iter->second;
     569             :     }
     570           0 :     return NULL;
     571             : }
     572             : 
     573           0 : void InstanceManager::RegisterSvcInstance(InstanceTask *task,
     574             :                                           ServiceInstance *svc_instance) {
     575             :     pair<TaskSvcMap::iterator, bool> result =
     576           0 :          task_svc_instances_.insert(std::make_pair(task, svc_instance));
     577           0 :     assert(result.second);
     578             : 
     579           0 :     InstanceState *state = GetState(svc_instance);
     580           0 :     assert(state);
     581           0 :     state->incr_tasks_running();
     582           0 : }
     583             : 
     584           0 : ServiceInstance *InstanceManager::UnregisterSvcInstance(InstanceTask *task) {
     585           0 :     for (TaskSvcMap::iterator iter =
     586           0 :                     task_svc_instances_.begin();
     587           0 :          iter != task_svc_instances_.end(); ++iter) {
     588           0 :         if (task == iter->first) {
     589           0 :             ServiceInstance *svc_instance = iter->second;
     590           0 :             InstanceState *state = GetState(svc_instance);
     591           0 :             assert(state);
     592           0 :             state->decr_tasks_running();
     593           0 :             task_svc_instances_.erase(iter);
     594           0 :             return svc_instance;
     595             :         }
     596             :     }
     597             : 
     598           0 :     return NULL;
     599             : }
     600             : 
     601           0 : void InstanceManager::UnregisterSvcInstance(ServiceInstance *svc_instance) {
     602             : 
     603           0 :     InstanceState *state = GetState(svc_instance);
     604           0 :     assert(state);
     605             : 
     606             :     TaskSvcMap::iterator iter =
     607           0 :         task_svc_instances_.begin();
     608           0 :     while(iter != task_svc_instances_.end()) {
     609           0 :         if (svc_instance == iter->second) {
     610           0 :             task_svc_instances_.erase(iter++);
     611           0 :             state->decr_tasks_running();
     612             :         } else {
     613           0 :             ++iter;
     614             :         }
     615             :     }
     616           0 : }
     617             : 
     618           0 : InstanceManagerAdapter* InstanceManager::FindApplicableAdapter(const ServiceInstance::Properties &props) {
     619           0 :     for (std::vector<InstanceManagerAdapter *>::iterator iter = adapters_.begin();
     620           0 :          iter != adapters_.end(); ++iter) {
     621           0 :          InstanceManagerAdapter *adapter = *iter;
     622           0 :         if (adapter != NULL && adapter->isApplicable(props)) {
     623           0 :             return adapter;
     624             :         }
     625             :     }
     626           0 :     return NULL;
     627             : }
     628             : 
     629           0 : void InstanceManager::StartServiceInstance(ServiceInstance *svc_instance,
     630             :                                  InstanceState *state, bool update) {
     631           0 :     const ServiceInstance::Properties &props = svc_instance->properties();
     632           0 :     InstanceManagerAdapter *adapter = this->FindApplicableAdapter(props);
     633           0 :     std::stringstream ss;
     634           0 :     if (adapter != NULL) {
     635           0 :         InstanceTask *task = adapter->CreateStartTask(props, update);
     636           0 :         if (task != NULL) {
     637           0 :             ss << "Starting the Task " << task << " " << task->cmd();
     638           0 :             ss << " for " << props.instance_id;
     639           0 :             INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     640           0 :             task->set_on_data_cb(boost::bind(&InstanceManager::OnError,
     641             :                                               this, _1, _2));
     642           0 :             task->set_on_exit_cb(boost::bind(&InstanceManager::OnExit,
     643             :                         this, _1, _2));
     644           0 :             state->set_properties(props);
     645           0 :             RegisterSvcInstance(task, svc_instance);
     646           0 :             std::stringstream info;
     647           0 :             Enqueue(task, props.instance_id);
     648           0 :         } else {
     649           0 :             ss << "Error Starting the Task for " << props.instance_id;
     650           0 :             INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     651             :         }
     652             :     } else {
     653           0 :         ss << "Unknown virtualization type " << props.virtualization_type;
     654           0 :         ss << " for " << svc_instance->ToString();
     655           0 :         INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     656             :     }
     657           0 : }
     658             : 
     659             : 
     660           0 : void InstanceManager::StopServiceInstance(ServiceInstance *svc_instance,
     661             :                                 InstanceState *state) {
     662           0 :     const ServiceInstance::Properties &props = state->properties();
     663           0 :     InstanceManagerAdapter *adapter = this->FindApplicableAdapter(props);
     664           0 :     std::stringstream ss;
     665           0 :     if (adapter != NULL) {
     666           0 :         InstanceTask *task = adapter->CreateStopTask(props);
     667           0 :         if (task != NULL) {
     668           0 :             ss << "Stopping the Task " << task << " " << task->cmd();
     669           0 :             ss << " for " << props.instance_id;
     670           0 :             INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     671           0 :             task->set_on_data_cb(boost::bind(&InstanceManager::OnError,
     672             :                                               this, _1, _2));
     673           0 :             task->set_on_exit_cb(boost::bind(&InstanceManager::OnExit,
     674             :                         this, _1, _2));
     675           0 :             RegisterSvcInstance(task, svc_instance);
     676           0 :             std::stringstream info;
     677           0 :             Enqueue(task, props.instance_id);
     678           0 :         } else {
     679           0 :             std::stringstream ss;
     680           0 :             ss << "Error Stopping the Task for " << props.instance_id;
     681           0 :             INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     682           0 :         }
     683             :     } else {
     684           0 :         ss << "Unknown virtualization type " << props.virtualization_type;
     685           0 :         ss << " for " << svc_instance->ToString();
     686           0 :         INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     687             :     }
     688           0 : }
     689             : 
     690           0 : void InstanceManager::OnError(InstanceTask *task,
     691             :                               const std::string errors) {
     692             : 
     693           0 :     InstanceManagerChildEvent event;
     694           0 :     event.type = OnErrorEvent;
     695           0 :     event.task = task;
     696           0 :     event.errors = errors;
     697             : 
     698           0 :     work_queue_.Enqueue(event);
     699           0 : }
     700             : 
     701           0 : void InstanceManager::OnExit(InstanceTask *task,
     702             :                     const boost::system::error_code &ec) {
     703             : 
     704           0 :     InstanceManagerChildEvent event;
     705           0 :     event.type = OnExitEvent;
     706           0 :     event.task = task;
     707           0 :     event.error_val = ec.value();
     708             : 
     709           0 :     work_queue_.Enqueue(event);
     710           0 : }
     711             : 
     712           0 : void InstanceManager::StopStaleNetNS(ServiceInstance::Properties &props) {
     713           0 :     std::stringstream cmd_str;
     714             : 
     715           0 :     if (netns_cmd_.length() == 0) {
     716           0 :         return;
     717             :     }
     718           0 :     cmd_str << netns_cmd_ << " destroy";
     719             : 
     720           0 :     cmd_str << " " << props.ServiceTypeString();
     721           0 :     cmd_str << " " << UuidToString(props.instance_id);
     722           0 :     cmd_str << " " << UuidToString(boost::uuids::nil_uuid());
     723           0 :     cmd_str << " " << UuidToString(boost::uuids::nil_uuid());
     724           0 :     if (props.service_type == ServiceInstance::LoadBalancer) {
     725           0 :         if (props.loadbalancer_id.empty()) {
     726           0 :             LOG(ERROR, "loadbalancer id is missing for service instance: "
     727             :                         << UuidToString(props.instance_id));
     728           0 :             return;
     729             :         }
     730           0 :         cmd_str << " --loadbalancer-id " << props.loadbalancer_id;
     731             :     }
     732             : 
     733           0 :     std::string cmd = cmd_str.str();
     734           0 :     std::vector<std::string> argv;
     735           0 :     boost::split(argv, cmd, boost::is_any_of(" "), boost::token_compress_on);
     736           0 :     std::vector<const char *> c_argv(argv.size() + 1);
     737           0 :     for (std::size_t i = 0; i != argv.size(); ++i) {
     738           0 :         c_argv[i] = argv[i].c_str();
     739             :     }
     740             : 
     741           0 :     std::stringstream ss;
     742           0 :     ss << "StaleNetNS " << cmd;
     743           0 :     INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     744             : 
     745           0 :     pid_t pid = vfork();
     746           0 :     if (pid == 0) {
     747           0 :         CloseTaskFds();
     748           0 :         execvp(c_argv[0], (char **) c_argv.data());
     749           0 :         perror("execvp");
     750             : 
     751           0 :         _exit(127);
     752             :     }
     753           0 : }
     754             : 
     755           0 : void InstanceManager::SetLastCmdType(ServiceInstance *svc_instance,
     756             :                                      int last_cmd_type) {
     757           0 :     std::string uuid = UuidToString(svc_instance->uuid());
     758             :     std::map<std::string, int>::iterator iter =
     759           0 :             last_cmd_types_.find(uuid);
     760           0 :     if (iter != last_cmd_types_.end()) {
     761           0 :         iter->second = last_cmd_type;
     762             :     } else {
     763           0 :         last_cmd_types_.insert(std::make_pair(uuid, last_cmd_type));
     764             :     }
     765           0 : }
     766             : 
     767           0 : int InstanceManager::GetLastCmdType(ServiceInstance *svc_instance) const {
     768           0 :     std::string uuid = UuidToString(svc_instance->uuid());
     769             :     std::map<std::string, int>::const_iterator iter =
     770           0 :         last_cmd_types_.find(uuid);
     771           0 :     if (iter != last_cmd_types_.end()) {
     772           0 :         return iter->second;
     773             :     }
     774             : 
     775           0 :     return 0;
     776           0 : }
     777             : 
     778           0 : void InstanceManager::ClearLastCmdType(ServiceInstance *svc_instance) {
     779           0 :     std::string uuid = UuidToString(svc_instance->uuid());
     780             :         std::map<std::string, int>::iterator iter =
     781           0 :             last_cmd_types_.find(uuid);
     782           0 :     if (iter != last_cmd_types_.end()) {
     783           0 :         last_cmd_types_.erase(iter);
     784             :     }
     785           0 : }
     786             : 
     787           0 : void InstanceManager::EventObserver(
     788             :     DBTablePartBase *db_part, DBEntryBase *entry) {
     789           0 :     ServiceInstance *svc_instance = static_cast<ServiceInstance *>(entry);
     790             : 
     791           0 :     InstanceState *state = GetState(svc_instance);
     792           0 :     if (svc_instance->IsDeleted()) {
     793           0 :         if (state) {
     794           0 :             if (GetLastCmdType(svc_instance) == Start) {
     795           0 :                 StopServiceInstance(svc_instance, state);
     796           0 :                 SetLastCmdType(svc_instance, Stop);
     797             :             }
     798           0 :             if (DeleteState(svc_instance)) {
     799           0 :                 return;
     800             :             }
     801             :         }
     802           0 :         ClearLastCmdType(svc_instance);
     803             :     } else {
     804           0 :         if (state == NULL) {
     805           0 :             state = new InstanceState();
     806           0 :             SetState(svc_instance, state);
     807             :         }
     808             : 
     809           0 :         bool usable = svc_instance->IsUsable();
     810             : 
     811           0 :         std::stringstream ss;
     812           0 :         ss << "NetNS event notification for uuid: " << svc_instance->ToString();
     813           0 :         ss << (usable ? " usable" : " not usable");
     814           0 :         INSTANCE_MANAGER_TRACE(Trace, ss.str().c_str());
     815             : 
     816           0 :         if (!usable && GetLastCmdType(svc_instance) == Start) {
     817           0 :             StopServiceInstance(svc_instance, state);
     818           0 :             SetLastCmdType(svc_instance, Stop);
     819           0 :         } else if (usable) {
     820           0 :             if (GetLastCmdType(svc_instance) == Start && state->properties().CompareTo(
     821             :                             svc_instance->properties()) != 0) {
     822           0 :                 StartServiceInstance(svc_instance, state, true);
     823           0 :             } else if (GetLastCmdType(svc_instance) != Start) {
     824           0 :                 StartServiceInstance(svc_instance, state, false);
     825           0 :                 SetLastCmdType(svc_instance, Start);
     826             :             }
     827             :         }
     828           0 :     }
     829             : }
     830             : 
     831          19 : bool InstanceManager::StaleTimeout() {
     832             : 
     833          19 :     if (stale_cleaner_.get())
     834           0 :         return false;
     835          19 :     stale_cleaner_.reset(new NamespaceStaleCleaner(agent_, this));
     836          19 :     stale_cleaner_->CleanStaleEntries();
     837          19 :     stale_cleaner_.reset(NULL);
     838          19 :     return false;
     839             : }
     840             : 
     841           0 : void InstanceManager::SetNamespaceStorePath(std::string path) {
     842           0 :     namespace_store_path_ = path;
     843           0 : }
     844             : 
     845             : /*
     846             :  * InstanceState class
     847             :  */
     848           0 : InstanceState::InstanceState() : DBState(),
     849           0 :         pid_(0), status_(0), status_type_(0), tasks_running_(0) {
     850           0 : }
     851             : 
     852           0 : void InstanceState::Clear() {
     853           0 :     pid_ = 0;
     854           0 :     status_ = 0;
     855           0 :     errors_.clear();
     856           0 :     cmd_.clear();
     857           0 : }

Generated by: LCOV version 1.14