diff --git a/src/scheduler/include/Scheduler.h b/src/scheduler/include/Scheduler.h index 52b0f32da5..13925a13fa 100644 --- a/src/scheduler/include/Scheduler.h +++ b/src/scheduler/include/Scheduler.h @@ -133,6 +133,9 @@ protected: */ virtual int set_up_pools(); + + virtual int scheduled_actions(); + private: Scheduler(Scheduler const&){}; diff --git a/src/scheduler/include/VirtualMachinePoolXML.h b/src/scheduler/include/VirtualMachinePoolXML.h index 02f3ac8989..3aa091847b 100644 --- a/src/scheduler/include/VirtualMachinePoolXML.h +++ b/src/scheduler/include/VirtualMachinePoolXML.h @@ -43,6 +43,15 @@ public: */ int set_up(); + /** + * Retrieves the VMs with scheduled actions + * + * @return 0 on success + * -1 on error + * -2 if no VMs need to be scheduled + */ + int set_up_actions(); + /** * Gets an object from the pool * @param oid the object unique identifier @@ -66,12 +75,16 @@ public: * Update the VM template * @param vid the VM id * @param st the template string + * + * @return 0 on success, -1 otherwise */ int update(int vid, const string &st) const; /** * Update the VM template * @param the VM + * + * @return 0 on success, -1 otherwise */ int update(VirtualMachineXML * vm) const { @@ -80,20 +93,35 @@ public: return update(vm->get_oid(), vm->get_template(xml)); }; + /** + * Calls one.vm.action + * + * @param vid The VM id + * @param action Action argument (shutdown, hold, release...) + * @param error_msg Error reason, if any + * + * @return 0 on success, -1 otherwise + */ + int action(int vid, const string &action, string &error_msg) const; + protected: - int get_suitable_nodes(vector& content) - { - return get_nodes("/VM_POOL/VM[STATE=1 or (LCM_STATE=3 and RESCHED=1)]", - content); - }; + int get_suitable_nodes(vector& content); virtual void add_object(xmlNodePtr node); virtual int load_info(xmlrpc_c::value &result); - /* Do live migrations to resched VMs*/ + /** + * Do live migrations to resched VMs + */ bool live_resched; + + /** + * True to retrieve pending/resched VMs, false to get VMs with scheduled + * actions + */ + bool retrieve_pending; }; #endif /* VM_POOL_XML_H_ */ diff --git a/src/scheduler/include/VirtualMachineXML.h b/src/scheduler/include/VirtualMachineXML.h index 3261d4a012..47fb24d86e 100644 --- a/src/scheduler/include/VirtualMachineXML.h +++ b/src/scheduler/include/VirtualMachineXML.h @@ -124,6 +124,16 @@ public: return xml_str; } + /** + * Returns a the VM Template + * + * @return A pointer to the VM Template (not to a copy) + */ + VirtualMachineTemplate* get_template() + { + return vm_template; + }; + /** * Function to write a Virtual Machine in an output stream */ diff --git a/src/scheduler/src/pool/VirtualMachinePoolXML.cc b/src/scheduler/src/pool/VirtualMachinePoolXML.cc index c48b131e82..0d6080d649 100644 --- a/src/scheduler/src/pool/VirtualMachinePoolXML.cc +++ b/src/scheduler/src/pool/VirtualMachinePoolXML.cc @@ -22,6 +22,8 @@ int VirtualMachinePoolXML::set_up() ostringstream oss; int rc; + retrieve_pending = true; + rc = PoolXML::set_up(); if ( rc == 0 ) @@ -50,6 +52,63 @@ int VirtualMachinePoolXML::set_up() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +int VirtualMachinePoolXML::set_up_actions() +{ + ostringstream oss; + int rc; + + retrieve_pending = false; + + rc = PoolXML::set_up(); + + if ( rc == 0 ) + { + if (objects.empty()) + { + return -2; + } + + oss.str(""); + oss << "VMs with scheduled actions:" << endl; + + map::iterator it; + + for (it=objects.begin();it!=objects.end();it++) + { + oss << " " << it->first; + } + + NebulaLog::log("VM",Log::DEBUG,oss); + } + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualMachinePoolXML::get_suitable_nodes(vector& content) +{ + if (retrieve_pending) + { + return get_nodes( + "/VM_POOL/VM[STATE=1 or (LCM_STATE=3 and RESCHED=1)]", + content); + } + + ostringstream oss; + + oss << "/VM_POOL/VM/USER_TEMPLATE/SCHED_ACTION[TIME < " << time(0) + << " and not(DONE > 0)]/../.."; + + return get_nodes( + oss.str().c_str(), + content); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void VirtualMachinePoolXML::add_object(xmlNodePtr node) { if ( node == 0 || node->children == 0 || node->children->next==0 ) @@ -209,3 +268,45 @@ int VirtualMachinePoolXML::update(int vid, const string &st) const return 0; } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualMachinePoolXML::action( + int vid, + const string& action, + string& error_msg) const +{ + xmlrpc_c::value result; + bool success; + + try + { + client->call( client->get_endpoint(), // serverUrl + "one.vm.action", // methodName + "ssi", // arguments format + &result, // resultP + client->get_oneauth().c_str(), // session + action.c_str(), // action + vid // VM ID + ); + } + catch (exception const& e) + { + return -1; + } + + vector values = + xmlrpc_c::value_array(result).vectorValueValue(); + + success = xmlrpc_c::value_boolean(values[0]); + + if (!success) + { + error_msg = xmlrpc_c::value_string( values[1] ); + + return -1; + } + + return 0; +} diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 87474a7e8a..a7fbf549ca 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -623,12 +623,150 @@ void Scheduler::dispatch() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +int Scheduler::scheduled_actions() +{ + int rc = vmpool->set_up_actions(); + + if ( rc != 0 ) + { + return rc; + } + + VirtualMachineXML* vm; + VirtualMachineTemplate* vm_template; + + vector v_st; + + map::const_iterator vm_it; + + vector attributes; + vector::iterator it; + + VectorAttribute* vatt; + + time_t the_time = time(0); + + int action_time, done_time, has_time, has_done; + string action_st, error_msg; + + // TODO: Move the time string creation to a common place + + char time_str[26]; + + ostringstream oss; + ostringstream oss_aux; + +#ifdef SOLARIS + ctime_r(&(the_time),time_str,sizeof(char)*26); +#else + ctime_r(&(the_time),time_str); +#endif + + time_str[24] = '\0'; // Get rid of final enter character + + + const map vms = vmpool->get_objects(); + + for (vm_it=vms.begin(); vm_it != vms.end(); vm_it++) + { + vm = static_cast(vm_it->second); + vm_template = vm->get_template(); + + attributes.clear(); + vm_template->remove("SCHED_ACTION", attributes); + + // TODO: Sort actions by TIME + + for (it=attributes.begin(); it != attributes.end(); it++) + { + vatt = dynamic_cast(*it); + + if (vatt == 0) + { + continue; + } + + has_time = vatt->vector_value("TIME", action_time); + has_done = vatt->vector_value("DONE", done_time); + + // TODO: Transform to lower case + action_st = vatt->vector_value("ACTION"); + + if (has_time == 0 && has_done == -1 && action_time < the_time) + { + oss.str(""); + + // onevm delete command uses the xml-rpc finalize action + if (action_st == "delete") + { + action_st = "finalize"; + } + + oss << "Executing action '" << action_st << "' for VM " + << vm->get_oid() << " : "; + + if ( action_st != "shutdown" + && action_st != "hold" + && action_st != "release" + && action_st != "stop" + && action_st != "cancel" + && action_st != "suspend" + && action_st != "resume" + && action_st != "restart" + && action_st != "resubmit" + && action_st != "reboot" + && action_st != "reset" + && action_st != "poweroff" + && action_st != "finalize") + { + error_msg = "This action is not supported."; + rc = -1; + } + else + { + rc = vmpool->action(vm->get_oid(), action_st, error_msg); + } + + if (rc == 0) + { + vatt->remove("MESSAGE"); + vatt->replace("DONE", static_cast(the_time)); + + oss << "Success."; + } + else + { + oss_aux.str(""); + oss_aux << time_str << " : " << error_msg; + + vatt->replace("MESSAGE", oss_aux.str()); + + oss << "Failure. " << error_msg; + } + + NebulaLog::log("VM",Log::INFO,oss); + } + + vm_template->set(vatt); + } + + vmpool->update(vm); + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void Scheduler::do_action(const string &name, void *args) { int rc; if (name == ACTION_TIMER) { + scheduled_actions(); + rc = set_up_pools(); if ( rc != 0 )