diff --git a/SConstruct b/SConstruct index 2632d2d..cc6e98a 100644 --- a/SConstruct +++ b/SConstruct @@ -54,6 +54,7 @@ main_env.Append(LIBPATH=[ cwd+'/src/rm', cwd+'/src/vnm', cwd+'/src/hm', + cwd+'/src/um', ]) # Compile flags @@ -135,6 +136,7 @@ build_scripts=[ 'src/scheduler/SConstruct', 'src/vnm/SConstruct', 'src/hm/SConstruct', + 'src/um/SConstruct', ] for script in build_scripts: diff --git a/include/DispatchManager.h b/include/DispatchManager.h index f2a486a..50c78b4 100644 --- a/include/DispatchManager.h +++ b/include/DispatchManager.h @@ -193,6 +193,15 @@ class DispatchManager : public ActionListener int resume( int vid); + /** + * Restart a previusly deployed VM. + * @param vid VirtualMachine identification + * @return 0 on success, -1 if the VM does not exits or -2 if the VM is + * in a wrong a state + */ + int restart( + int vid); + /** * Ends a VM life cycle inside ONE. * @param vid VirtualMachine identification diff --git a/include/History.h b/include/History.h index 2996a58..a06936d 100644 --- a/include/History.h +++ b/include/History.h @@ -58,6 +58,27 @@ class History:public ObjectSQL ~History(){}; + /** + * Function to write the History Record in an output stream + */ + friend ostream& operator<<(ostream& os, const History& history); + + /** + * Function to print the History object into a string in + * plain text + * @param str the resulting string + * @return a reference to the generated string + */ + string& to_str(string& str) const; + + /** + * Function to print the History object into a string in + * XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(string& xml) const; + private: friend class VirtualMachine; @@ -192,6 +213,20 @@ class History:public ObjectSQL * @return 0 on success */ int unmarshall(int num, char **names, char ** values); + + /** + * Function to unmarshall a History object into an output stream with XML + * format. + * @param oss the output stream + * @param num the number of columns read from the DB + * @param names the column names + * @param vaues the column values + * @return 0 on success + */ + static int unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values); }; #endif /*HISTORY_H_*/ diff --git a/include/Host.h b/include/Host.h index eb47ae2..3d0e810 100644 --- a/include/Host.h +++ b/include/Host.h @@ -24,8 +24,15 @@ using namespace std; -extern "C" int host_select_cb (void * _host, int num,char ** values, char ** names); - +extern "C" int host_select_cb (void * _host, + int num, + char ** values, + char ** names); + +extern "C" int host_dump_cb (void * _oss, + int num, + char ** values, + char ** names); /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -54,6 +61,20 @@ class Host : public PoolObjectSQL */ friend ostream& operator<<(ostream& os, Host& h); + /** + * Function to print the Host object into a string in plain text + * @param str the resulting string + * @return a reference to the generated string + */ + string& to_str(string& str) const; + + /** + * Function to print the Host object into a string in XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(string& xml) const; + /** * Get the Host unique identifier HID, that matches the OID of the object * @return HID Host identifier @@ -62,15 +83,6 @@ class Host : public PoolObjectSQL { return oid; }; - - /** - * Check if the host is managed - * @return true if the host is managed - */ - bool isManaged() const - { - return managed; - } /** * Check if the host is enabled @@ -310,15 +322,17 @@ class Host : public PoolObjectSQL // ------------------------------------------------------------------------- // Friends // ------------------------------------------------------------------------- - friend class HostPool; - friend int host_select_cb ( - void * _host, - int num, - char ** values, - char ** names); - + friend int host_select_cb (void * _host, + int num, + char ** values, + char ** names); + + friend int host_dump_cb (void * _oss, + int num, + char ** values, + char ** names); // ------------------------------------------------------------------------- // Host Description // ------------------------------------------------------------------------- @@ -349,13 +363,8 @@ class Host : public PoolObjectSQL * If Host State = MONITORED last time it got fully monitored or 1 Jan 1970 * Host State = MONITORING last time it got a signal to be monitored */ - time_t last_monitored; - - /** - * This tells if this host pertains to a local managed cluster - */ - bool managed; - + time_t last_monitored; + // ------------------------------------------------------------------------- // Host Attributes // ------------------------------------------------------------------------- @@ -363,12 +372,12 @@ class Host : public PoolObjectSQL /** * The Host template, holds the Host attributes. */ - HostTemplate host_template; + HostTemplate host_template; /** - * This map holds pointers to all the Host's HostShares + * The Share represents the logical capacity associated with the host */ - HostShare host_share; + HostShare host_share; // ------------------------------------------------------------------------- // Lex & bison @@ -386,12 +395,24 @@ class Host : public PoolObjectSQL /** * Function to unmarshall a Host object * @param num the number of columns read from the DB - * @para names the column names - * @para vaues the column values + * @param names the column names + * @param vaues the column values * @return 0 on success */ int unmarshall(int num, char **names, char ** values); + /** + * Function to unmarshall a Host object in to an output stream in XML + * @param oss the output stream + * @param num the number of columns read from the DB + * @param names the column names + * @param vaues the column values + * @return 0 on success + */ + static int unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values); /** * Bootstraps the database table(s) associated to the Host */ @@ -399,9 +420,9 @@ class Host : public PoolObjectSQL { db->exec(Host::db_bootstrap); - db->exec(HostTemplate::db_bootstrap); - db->exec(HostShare::db_bootstrap); + + db->exec(HostTemplate::db_bootstrap); }; protected: @@ -414,8 +435,7 @@ class Host : public PoolObjectSQL string _hostname="", string _im_mad_name="", string _vmm_mad_name="", - string _tm_mad_name="", - bool _managed=true); + string _tm_mad_name=""); virtual ~Host(); @@ -431,9 +451,8 @@ class Host : public PoolObjectSQL IM_MAD = 3, VM_MAD = 4, TM_MAD = 5, - LAST_MON_TIME = 6, - MANAGED = 7, - LIMIT = 8 + LAST_MON_TIME = 6, + LIMIT = 7 }; static const char * db_names; @@ -468,7 +487,17 @@ class Host : public PoolObjectSQL * @param db pointer to the db * @return 0 on success */ - virtual int drop(SqliteDB *db); + virtual int drop(SqliteDB *db); + + /** + * Dumps the contect of a set of Host objects in the given stream + * using XML format + * @param db pointer to the db + * @param oss the output stream + * @param where string to filter the VirtualMachine objects + * @return 0 on success + */ + static int dump(SqliteDB * db, ostringstream& oss, const string& where); }; #endif /*HOST_H_*/ diff --git a/include/HostPool.h b/include/HostPool.h index 84c7cad..98a59b3 100644 --- a/include/HostPool.h +++ b/include/HostPool.h @@ -51,8 +51,7 @@ class HostPool : public PoolSQL string hostname, string im_mad_name, string vmm_mad_name, - string tm_mad_name, - bool managed = true); + string tm_mad_name); /** * Function to get a Host from the pool, if the object is not in memory @@ -78,36 +77,37 @@ class HostPool : public PoolSQL }; - /** Drops a host from the cache & DB, the host mutex MUST BE locked + /** Drops a host from the DB, the host mutex MUST BE locked * @param host pointer to Host */ int drop(Host * host) { - int rc = host->drop(db); - - if ( rc == 0) - { - remove(static_cast(host)); - } - - return rc; + return host->drop(db); }; /** * Bootstraps the database table(s) associated to the Host pool */ - void bootstrap() + static void bootstrap(SqliteDB *_db) { - Host::bootstrap(db); + Host::bootstrap(_db); }; /** * Get the 10 least monitored hosts - * param discovered hosts map to store the retrieved hosts hids and hostnames are - * return int 0 if success + * @param discovered hosts, map to store the retrieved hosts hids and + * hostnames + * @return int 0 if success */ int discover(map * discovered_hosts); + /** + * Allocates a given capacity to the host + * @param oid the id of the host to allocate the capacity + * @param cpu amount of CPU + * @param mem amount of main memory + * @param disk amount of disk + */ void add_capacity(int oid,int cpu, int mem, int disk) { Host * host = get(oid, true); @@ -121,7 +121,13 @@ class HostPool : public PoolSQL host->unlock(); } }; - + /** + * De-Allocates a given capacity to the host + * @param oid the id of the host to allocate the capacity + * @param cpu amount of CPU + * @param mem amount of main memory + * @param disk amount of disk + */ void del_capacity(int oid,int cpu, int mem, int disk) { Host * host = get(oid, true); @@ -135,6 +141,27 @@ class HostPool : public PoolSQL host->unlock(); } }; + + /** + * Dumps the HOST pool in XML format. A filter can be also added to the + * query + * @param oss the output stream to dump the pool contents + * @param where filter for the objects, defaults to all + * + * @return 0 on success + */ + int dump(ostringstream& oss, const string& where) + { + int rc; + + oss << ""; + + rc = Host::dump(db,oss,where); + + oss << ""; + + return rc; + } private: /** diff --git a/include/HostShare.h b/include/HostShare.h index bf17650..b0f2c7e 100644 --- a/include/HostShare.h +++ b/include/HostShare.h @@ -24,7 +24,10 @@ using namespace std; -extern "C" int host_share_select_cb (void * _host_share, int num,char ** values, char ** names); +extern "C" int host_share_select_cb (void * _hs, + int num, + char ** values, + char ** names); /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -44,15 +47,6 @@ class HostShare : public ObjectSQL ~HostShare(){}; - /** - * Gets the HostShare identifier - * @return HSID HostShare identifier - */ - int get_hsid() const - { - return hsid; - }; - /** * Add a new VM to this share * @param cpu requested by the VM @@ -104,55 +98,44 @@ class HostShare : public ObjectSQL */ friend ostream& operator<<(ostream& os, HostShare& hs); -private: - /** - * HostShare identifier - */ - int hsid; - /** - * HostShare's Endpoint + * Function to print the HostShare object into a string in + * plain text + * @param str the resulting string + * @return a reference to the generated string */ - string endpoint; + string& to_str(string& str) const; /** - * HostShare disk usage (in Kb) + * Function to print the HostShare object into a string in + * XML format + * @param xml the resulting XML string + * @return a reference to the generated string */ - int disk_usage; - - /** - * HostShare memory usage (in Kb) - */ - int mem_usage; - - /** - * HostShare cpu usage (in percentage) - */ - int cpu_usage; + string& to_xml(string& xml) const; + +private: - /** - * HostShare disk share (in GB), 0 means that the share will use all the - * avialable disk in the host - */ - int max_disk; + int hsid; /**< HostShare identifier */ + + int disk_usage; /**< Disk allocated to VMs (in Mb). */ + int mem_usage; /**< Memory allocated to VMs (in Mb) */ + int cpu_usage; /**< CPU allocated to VMs (in percentage) */ + + int max_disk; /**< Total disk capacity (in Mb) */ + int max_mem; /**< Total memory capacity (in Mb) */ + int max_cpu; /**< Total cpu capacity (in percentage) */ - /** - * HostShare memory share (in MB), 0 means that the share will use all the - * avialable disk in the host - */ - int max_mem; + int free_disk; /**< Free disk from the IM monitor */ + int free_mem; /**< Free memory from the IM monitor */ + int free_cpu; /**< Free cpu from the IM monitor */ - /** - * HostShare cpu usage (in percentage), 0 means that the share will use all - * the avialable disk in the host - */ - int max_cpu; + int used_disk; /**< Used disk from the IM monitor */ + int used_mem; /**< Used memory from the IM monitor */ + int used_cpu; /**< Used cpu from the IM monitor */ - /** - * Number of running Virtual Machines in this HostShare - */ - int running_vms; - + int running_vms; /**< Number of running VMs in this Host */ + // ---------------------------------------- // Friends // ---------------------------------------- @@ -160,9 +143,9 @@ class HostShare : public ObjectSQL friend class Host; friend int host_share_select_cb ( - void * _hostshare, - int num, - char ** values, + void * _hostshare, + int num, + char ** values, char ** names); // ---------------------------------------- @@ -171,17 +154,22 @@ class HostShare : public ObjectSQL enum ColNames { - HID = 0, - ENDPOINT = 1, - DISK_USAGE = 2, - MEM_USAGE = 3, - CPU_USAGE = 4, - MAX_DISK = 5, - MAX_MEMORY = 6, - MAX_CPU = 7, - RUNNING_VMS = 8, - LIMIT = 9 - }; + HID = 0, + DISK_USAGE = 1, + MEM_USAGE = 2, + CPU_USAGE = 3, + MAX_DISK = 4, + MAX_MEMORY = 5, + MAX_CPU = 6, + FREE_DISK = 7, + FREE_MEMORY = 8, + FREE_CPU = 9, + USED_DISK = 10, + USED_MEMORY = 11, + USED_CPU = 12, + RUNNING_VMS = 13, + LIMIT = 14 + }; static const char * table; @@ -228,7 +216,20 @@ class HostShare : public ObjectSQL * @para vaues the column values * @return 0 on success */ - int unmarshall(int num, char **names, char ** values); + int unmarshall(int num, char **names, char ** values); + + /** + * Function to unmarshall a HostShare object in to an output stream in XML + * @param oss the output stream + * @param num the number of columns read from the DB + * @param names the column names + * @param vaues the column values + * @return 0 on success + */ + static int unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values); }; diff --git a/include/HostTemplate.h b/include/HostTemplate.h index 5ee56aa..0c3bcaa 100644 --- a/include/HostTemplate.h +++ b/include/HostTemplate.h @@ -30,7 +30,7 @@ class HostTemplate : public TemplateSQL public: HostTemplate(int tid = -1, const char separator = '='): - TemplateSQL(table,tid,true,separator,"HOST_TEMPLATE"){}; + TemplateSQL(table,tid,true,separator,"TEMPLATE"){}; ~HostTemplate(){}; diff --git a/include/Leases.h b/include/Leases.h index 8aaa647..3e5ce7e 100644 --- a/include/Leases.h +++ b/include/Leases.h @@ -129,7 +129,7 @@ class Leases : public ObjectSQL * @param ip ip of the lease in string * @param mac mac of the lease in string */ - void to_string(string& _ip, string& _mac); + void to_string(string& _ip, string& _mac) const; /** * Conversion from string IP to unsigned int IP @@ -157,7 +157,23 @@ class Leases : public ObjectSQL * Prints a Lease in a single line */ friend ostream& operator<<(ostream& os, Lease& _lease); - + + /** + * Function to print the Lease object into a string in + * plain text + * @param str the resulting string + * @return a reference to the generated string + */ + string& to_str(string& str) const; + + /** + * Function to print the Lease object into a string in + * XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(string& xml) const; + /** * Constants to access the array storing the MAC address */ @@ -176,9 +192,8 @@ class Leases : public ObjectSQL bool used; }; - friend ostream& operator<<(ostream& os, Lease& _lease); - friend class VirtualNetwork; + // ------------------------------------------------------------------------- // Leases fields @@ -242,6 +257,24 @@ class Leases : public ObjectSQL */ virtual int select(SqliteDB * db); + friend ostream& operator<<(ostream& os, Lease& _lease); + + /** + * Function to print the Leases object into a string in + * plain text + * @param str the resulting string + * @return a reference to the generated string + */ + string& to_str(string& str) const; + + /** + * Function to print the Leases object into a string in + * XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(string& xml) const; + private: friend int leases_select_cb ( diff --git a/include/LifeCycleManager.h b/include/LifeCycleManager.h index 38e3de0..52c3a13 100644 --- a/include/LifeCycleManager.h +++ b/include/LifeCycleManager.h @@ -44,29 +44,31 @@ class LifeCycleManager : public ActionListener enum Actions { - SAVE_SUCCESS, /**< Send by the VMM when a save action succeeds */ - SAVE_FAILURE, /**< Send by the VMM when a save action fails */ - DEPLOY_SUCCESS, /**< Send by the VMM when a deploy/restore/migrate action succeeds */ - DEPLOY_FAILURE, /**< Send by the VMM when a deploy/restore/migrate action fails */ - SHUTDOWN_SUCCESS, /**< Send by the VMM when a shutdown action succeeds*/ - SHUTDOWN_FAILURE, /**< Send by the VMM when a shutdown action fails */ - CANCEL_SUCCESS, /**< Send by the VMM when a cancel action succeeds */ - CANCEL_FAILURE, /**< Send by the VMM when a cancel action fails */ - MONITOR_FAILURE, /**< Send by the VMM when a VM has failed while active */ - MONITOR_SUSPEND, /**< Send by the VMM when a VM is paused while active */ - MONITOR_DONE, /**< Send by the VMM when a VM is not found */ - PROLOG_SUCCESS, /**< Send by the TM when the prolog phase succeeds */ - PROLOG_FAILURE, /**< Send by the TM when the prolog phase fails */ - EPILOG_SUCCESS, /**< Send by the TM when the epilog phase succeeds */ - EPILOG_FAILURE, /**< Send by the TM when the epilog phase fails */ - DEPLOY, /**< Send by the DM to deploy a VM on a host */ - SUSPEND, /**< Send by the DM to suspend an running VM */ - RESTORE, /**< Send by the DM to restore a suspended VM */ - STOP, /**< Send by the DM to stop an running VM */ - CANCEL, /**< Send by the DM to cancel an running VM */ - MIGRATE, /**< Send by the DM to migrate a VM to other host */ - LIVE_MIGRATE, /**< Send by the DM to live-migrate a VM */ - SHUTDOWN, /**< Send by the DM to shutdown an running VM */ + SAVE_SUCCESS, /**< Sent by the VMM when a save action succeeds */ + SAVE_FAILURE, /**< Sent by the VMM when a save action fails */ + DEPLOY_SUCCESS, /**< Sent by the VMM when a deploy/restore/migrate action succeeds */ + DEPLOY_FAILURE, /**< Sent by the VMM when a deploy/restore/migrate action fails */ + SHUTDOWN_SUCCESS, /**< Sent by the VMM when a shutdown action succeeds*/ + SHUTDOWN_FAILURE, /**< Sent by the VMM when a shutdown action fails */ + CANCEL_SUCCESS, /**< Sent by the VMM when a cancel action succeeds */ + CANCEL_FAILURE, /**< Sent by the VMM when a cancel action fails */ + MONITOR_FAILURE, /**< Sent by the VMM when a VM has failed while active */ + MONITOR_SUSPEND, /**< Sent by the VMM when a VM is paused while active */ + MONITOR_DONE, /**< Sent by the VMM when a VM is not found */ + PROLOG_SUCCESS, /**< Sent by the TM when the prolog phase succeeds */ + PROLOG_FAILURE, /**< Sent by the TM when the prolog phase fails */ + EPILOG_SUCCESS, /**< Sent by the TM when the epilog phase succeeds */ + EPILOG_FAILURE, /**< Sent by the TM when the epilog phase fails */ + DEPLOY, /**< Sent by the DM to deploy a VM on a host */ + SUSPEND, /**< Sent by the DM to suspend an running VM */ + RESTORE, /**< Sent by the DM to restore a suspended VM */ + STOP, /**< Sent by the DM to stop an running VM */ + CANCEL, /**< Sent by the DM to cancel an running VM */ + MIGRATE, /**< Sent by the DM to migrate a VM to other host */ + LIVE_MIGRATE, /**< Sent by the DM to live-migrate a VM */ + SHUTDOWN, /**< Sent by the DM to shutdown a running VM */ + RESTART, /**< Sent by the DM to restart a deployed VM */ + DELETE, /**< Sent by the DM to delete a VM */ FINALIZE }; @@ -181,6 +183,12 @@ class LifeCycleManager : public ActionListener void shutdown_action(int vid); + void failure_action(VirtualMachine * vm); + + void restart_action(int vid); + + void delete_action(int vid); + void timer_action(); }; diff --git a/include/Mad.h b/include/Mad.h index a05cd81..7b5b30b 100644 --- a/include/Mad.h +++ b/include/Mad.h @@ -74,7 +74,21 @@ class Mad cstr = str.c_str(); ::write(nebula_mad_pipe, cstr, str.size()); - }; + }; + + /** + * Send a DRIVER_CANCEL command to the driver + * @param oid identifies the action (that associated with oid) + */ + void driver_cancel (const int oid) const + { + ostringstream os; + + os << "DRIVER_CANCEL " << oid << endl; + + write(os); + }; + private: friend class MadManager; diff --git a/include/Nebula.h b/include/Nebula.h index 732494b..e77987a 100644 --- a/include/Nebula.h +++ b/include/Nebula.h @@ -26,6 +26,7 @@ #include "VirtualMachinePool.h" #include "VirtualNetworkPool.h" #include "HostPool.h" +#include "UserPool.h" #include "VirtualMachineManager.h" #include "LifeCycleManager.h" @@ -94,6 +95,11 @@ class Nebula { return vnpool; }; + + UserPool * get_upool() + { + return upool; + }; // -------------------------------------------------------------- // Manager Accessors @@ -237,8 +243,8 @@ class Nebula //Constructors and = are private to only access the class through instance // ----------------------------------------------------------------------- - Nebula():nebula_configuration(0),db(0),vmpool(0),hpool(0),vnpool(0),lcm(0), - vmm(0),im(0),tm(0),dm(0),rm(0) + Nebula():nebula_configuration(0),db(0),vmpool(0),hpool(0),vnpool(0),upool(0), + lcm(0),vmm(0),im(0),tm(0),dm(0),rm(0) { const char * nl = getenv("ONE_LOCATION"); @@ -284,6 +290,11 @@ class Nebula delete hpool; } + if ( upool != 0) + { + delete upool; + } + if ( vmm != 0) { delete vmm; @@ -360,6 +371,7 @@ class Nebula VirtualMachinePool * vmpool; HostPool * hpool; VirtualNetworkPool * vnpool; + UserPool * upool; // --------------------------------------------------------------- // Nebula Managers diff --git a/include/PoolSQL.h b/include/PoolSQL.h index f12e9ac..010dbb9 100644 --- a/include/PoolSQL.h +++ b/include/PoolSQL.h @@ -106,25 +106,12 @@ class PoolSQL: public Hookable return rc; }; - - /** - * Removes an object from the pool cache. The object mutex MUST be locked. - * The resources of the object are freed, but its record is kept in the DB. - * @param objsql a pointer to the object - */ - void remove( - PoolObjectSQL * objsql); /** * Removes all the elements from the pool */ void clean(); - /** - * Bootstraps the database table(s) associated to the pool - */ - virtual void bootstrap() = 0; - protected: /** diff --git a/include/RequestManager.h b/include/RequestManager.h index 2e744e6..fd97e25 100644 --- a/include/RequestManager.h +++ b/include/RequestManager.h @@ -21,6 +21,7 @@ #include "ActionManager.h" #include "VirtualMachinePool.h" #include "HostPool.h" +#include "UserPool.h" #include "VirtualNetworkPool.h" #include @@ -41,10 +42,11 @@ class RequestManager : public ActionListener VirtualMachinePool * _vmpool, HostPool * _hpool, VirtualNetworkPool * _vnpool, + UserPool * _upool, int _port, string _xml_log_file) - :vmpool(_vmpool),hpool(_hpool),vnpool(_vnpool),port(_port),socket_fd(-1), - xml_log_file(_xml_log_file) + :vmpool(_vmpool),hpool(_hpool),vnpool(_vnpool),upool(_upool), + port(_port),socket_fd(-1),xml_log_file(_xml_log_file) { am.addListener(this); }; @@ -106,12 +108,17 @@ class RequestManager : public ActionListener /** * Pointer to the Host Pool, to access hosts */ - HostPool * hpool; + HostPool * hpool; /** * Pointer to the VN Pool, to access Virtual Netowrks */ VirtualNetworkPool * vnpool; + + /** + * Pointer to the User Pool, to access users + */ + UserPool * upool; /** * Port number where the connection will be open @@ -154,14 +161,21 @@ class RequestManager : public ActionListener int setup_socket(); + // ---------------------------------------------------------------------- // ---------------------------------------------------------------------- // XML-RPC Methods // ---------------------------------------------------------------------- + // ---------------------------------------------------------------------- + /* ---------------------------------------------------------------------- */ + /* Virtual Machine Interface */ + /* ---------------------------------------------------------------------- */ class VirtualMachineAllocate: public xmlrpc_c::method { public: - VirtualMachineAllocate() + VirtualMachineAllocate( + UserPool * _upool): + upool(_upool) { _signature="A:ss"; _help="Allocates a virtual machine in the pool"; @@ -172,7 +186,8 @@ class RequestManager : public ActionListener void execute( xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retval); - + private: + UserPool * upool; }; /* ---------------------------------------------------------------------- */ @@ -182,9 +197,11 @@ class RequestManager : public ActionListener public: VirtualMachineDeploy( VirtualMachinePool * _vmpool, - HostPool * _hpool): + HostPool * _hpool, + UserPool * _upool): vmpool(_vmpool), - hpool(_hpool) + hpool(_hpool), + upool(_upool) { _signature="A:sii"; _help="Deploys a virtual machine"; @@ -198,7 +215,8 @@ class RequestManager : public ActionListener private: VirtualMachinePool * vmpool; - HostPool * hpool; + HostPool * hpool; + UserPool * upool; }; /* ---------------------------------------------------------------------- */ @@ -206,7 +224,11 @@ class RequestManager : public ActionListener class VirtualMachineAction: public xmlrpc_c::method { public: - VirtualMachineAction() + VirtualMachineAction( + VirtualMachinePool * _vmpool, + UserPool * _upool): + vmpool(_vmpool), + upool(_upool) { _signature="A:ssi"; _help="Performs an action on a virtual machine"; @@ -220,7 +242,7 @@ class RequestManager : public ActionListener private: VirtualMachinePool * vmpool; - HostPool * hpool; + UserPool * upool; }; /* ---------------------------------------------------------------------- */ @@ -230,9 +252,11 @@ class RequestManager : public ActionListener public: VirtualMachineMigrate( VirtualMachinePool * _vmpool, - HostPool * _hpool): + HostPool * _hpool, + UserPool * _upool): vmpool(_vmpool), - hpool(_hpool) + hpool(_hpool), + upool(_upool) { _signature="A:siib"; _help="Migrates a virtual machine"; @@ -247,6 +271,7 @@ class RequestManager : public ActionListener private: VirtualMachinePool * vmpool; HostPool * hpool; + UserPool * upool; }; /* ---------------------------------------------------------------------- */ @@ -255,8 +280,10 @@ class RequestManager : public ActionListener { public: VirtualMachineInfo( - VirtualMachinePool * _vmpool): - vmpool(_vmpool) + VirtualMachinePool * _vmpool, + UserPool * _upool): + vmpool(_vmpool), + upool(_upool) { _signature="A:si"; _help="Returns virtual machine information"; @@ -270,6 +297,7 @@ class RequestManager : public ActionListener private: VirtualMachinePool * vmpool; + UserPool * upool; }; @@ -279,8 +307,10 @@ class RequestManager : public ActionListener { public: VirtualMachinePoolInfo( - VirtualMachinePool * _vmpool): - vmpool(_vmpool) + VirtualMachinePool * _vmpool, + UserPool * _upool): + vmpool(_vmpool), + upool(_upool) { _signature="A:si"; _help="Returns the virtual machine pool"; @@ -294,16 +324,23 @@ class RequestManager : public ActionListener private: VirtualMachinePool * vmpool; + UserPool * upool; }; /* ---------------------------------------------------------------------- */ - + /* Host Interface */ + /* ---------------------------------------------------------------------- */ + class HostAllocate: public xmlrpc_c::method { public: - HostAllocate(HostPool * _hpool):hpool(_hpool) + HostAllocate( + HostPool * _hpool, + UserPool * _upool): + hpool(_hpool), + upool(_upool) { - _signature="A:sssssb"; + _signature="A:sssss"; _help="Allocates a host in the pool"; }; @@ -315,7 +352,7 @@ class RequestManager : public ActionListener private: HostPool * hpool; - + UserPool * upool; }; /* ---------------------------------------------------------------------- */ @@ -323,7 +360,11 @@ class RequestManager : public ActionListener class HostInfo: public xmlrpc_c::method { public: - HostInfo(HostPool * _hpool):hpool(_hpool) + HostInfo( + HostPool * _hpool, + UserPool * _upool): + hpool(_hpool), + upool(_upool) { _signature="A:si"; _help="Returns host information"; @@ -337,7 +378,32 @@ class RequestManager : public ActionListener private: HostPool * hpool; + UserPool * upool; + }; + + /* ---------------------------------------------------------------------- */ + + class HostPoolInfo: public xmlrpc_c::method + { + public: + HostPoolInfo(HostPool * _hpool, + UserPool * _upool): + hpool(_hpool), + upool(_upool) + { + _signature="A:s"; + _help="Returns the host pool information"; + }; + + ~HostPoolInfo(){}; + + void execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP); + private: + HostPool * hpool; + UserPool * upool; }; /* ---------------------------------------------------------------------- */ @@ -345,7 +411,11 @@ class RequestManager : public ActionListener class HostDelete: public xmlrpc_c::method { public: - HostDelete(HostPool * _hpool):hpool(_hpool) + HostDelete( + HostPool * _hpool, + UserPool * _upool): + hpool(_hpool), + upool(_upool) { _signature="A:si"; _help="Deletes a host from the pool"; @@ -359,7 +429,7 @@ class RequestManager : public ActionListener private: HostPool * hpool; - + UserPool * upool; }; /* ---------------------------------------------------------------------- */ @@ -367,7 +437,11 @@ class RequestManager : public ActionListener class HostEnable: public xmlrpc_c::method { public: - HostEnable(HostPool * _hpool):hpool(_hpool) + HostEnable( + HostPool * _hpool, + UserPool * _upool): + hpool(_hpool), + upool(_upool) { _signature="A:sib"; _help="Enables or disables a host"; @@ -381,7 +455,7 @@ class RequestManager : public ActionListener private: HostPool * hpool; - + UserPool * upool; }; /* ---------------------------------------------------------------------- */ @@ -392,7 +466,11 @@ class RequestManager : public ActionListener class VirtualNetworkAllocate: public xmlrpc_c::method { public: - VirtualNetworkAllocate(VirtualNetworkPool * _vnpool):vnpool(_vnpool) + VirtualNetworkAllocate( + VirtualNetworkPool * _vnpool, + UserPool * _upool): + vnpool(_vnpool), + upool(_upool) { _signature="A:ss"; _help="Creates a virtual network"; @@ -406,6 +484,7 @@ class RequestManager : public ActionListener private: VirtualNetworkPool * vnpool; + UserPool * upool; }; /* ---------------------------------------------------------------------- */ @@ -413,7 +492,11 @@ class RequestManager : public ActionListener class VirtualNetworkInfo: public xmlrpc_c::method { public: - VirtualNetworkInfo(VirtualNetworkPool * _vnpool):vnpool(_vnpool) + VirtualNetworkInfo( + VirtualNetworkPool * _vnpool, + UserPool * _upool): + vnpool(_vnpool), + upool(_upool) { _signature="A:si"; _help="Returns virtual network information"; @@ -424,18 +507,47 @@ class RequestManager : public ActionListener void execute( xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retvalP); - + private: VirtualNetworkPool * vnpool; - + UserPool * upool; }; + /* ---------------------------------------------------------------------- */ + + class VirtualNetworkPoolInfo: public xmlrpc_c::method + { + public: + VirtualNetworkPoolInfo(VirtualNetworkPool * _vnpool, + UserPool * _upool): + vnpool(_vnpool), + upool(_upool) + { + _signature="A:si"; + _help="Returns the virtual network pool information"; + }; + + ~VirtualNetworkPoolInfo(){}; + + void execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP); + + private: + VirtualNetworkPool * vnpool; + UserPool * upool; + }; + /* ---------------------------------------------------------------------- */ class VirtualNetworkDelete: public xmlrpc_c::method { public: - VirtualNetworkDelete(VirtualNetworkPool * _vnpool):vnpool(_vnpool) + VirtualNetworkDelete( + VirtualNetworkPool * _vnpool, + UserPool * _upool): + vnpool(_vnpool), + upool(_upool) { _signature="A:si"; _help="Deletes a virtual network"; @@ -449,10 +561,99 @@ class RequestManager : public ActionListener private: VirtualNetworkPool * vnpool; + UserPool * upool; + }; + + /* ---------------------------------------------------------------------- */ + /* User Management Interface */ + /* ---------------------------------------------------------------------- */ + + + class UserAllocate: public xmlrpc_c::method + { + public: + UserAllocate(UserPool * _upool):upool(_upool) + { + _signature="A:sss"; + _help="Creates a new user"; + }; + + ~UserAllocate(){}; + + void execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP); + private: + UserPool * upool; }; -}; + + /* ---------------------------------------------------------------------- */ + + class UserInfo: public xmlrpc_c::method + { + public: + UserInfo(UserPool * _upool):upool(_upool) + { + _signature="A:si"; + _help="Returns the Info of the user"; + }; + + ~UserInfo(){}; + + void execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP); + + private: + UserPool * upool; + }; + + /* ---------------------------------------------------------------------- */ + + class UserDelete: public xmlrpc_c::method + { + public: + UserDelete(UserPool * _upool):upool(_upool) + { + _signature="A:si"; + _help="Deletes a user account"; + }; + + ~UserDelete(){}; + + void execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP); + + private: + UserPool * upool; + }; + + + /* ---------------------------------------------------------------------- */ + + class UserPoolInfo: public xmlrpc_c::method + { + public: + UserPoolInfo(UserPool * _upool):upool(_upool) + { + _signature="A:s"; + _help="Creates a new user"; + }; + + ~UserPoolInfo(){}; + + void execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP); + + private: + UserPool * upool; + }; + +}; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/Scheduler.h b/include/Scheduler.h index 2050344..ddfe3ce 100644 --- a/include/Scheduler.h +++ b/include/Scheduler.h @@ -187,7 +187,12 @@ class Scheduler: public ActionListener // --------------------------------------------------------------- // XML_RPC related variables // --------------------------------------------------------------- - + + /** + * The authentication token + */ + string secret; + /** * NOTE (from lib doc): "you may not have more than one object of this * class in a program. The code is not re-entrant -- it uses global @@ -196,5 +201,4 @@ class Scheduler: public ActionListener xmlrpc_c::clientSimple xmlrpc_client; }; - #endif /*SCHEDULER_H_*/ diff --git a/include/TransferManager.h b/include/TransferManager.h index 16966de..67ccfe1 100644 --- a/include/TransferManager.h +++ b/include/TransferManager.h @@ -52,7 +52,10 @@ class TransferManager : public MadManager, public ActionListener PROLOG_RESUME, EPILOG, EPILOG_STOP, + EPILOG_DELETE, + EPILOG_DELETE_PREVIOUS, CHECKPOINT, + DRIVER_CANCEL, FINALIZE }; @@ -187,10 +190,25 @@ class TransferManager : public MadManager, public ActionListener */ void epilog_stop_action(int vid); + /** + * This function starts the epilog_delete sequence + */ + void epilog_delete_action(int vid); + + /** + * This function starts the epilog_delete sequence on the previous host + */ + void epilog_delete_previous_action(int vid); + /** * This function starts the epilog sequence */ void checkpoint_action(int vid); + + /** + * This function cancels the operation being performed by the driver + */ + void driver_cancel_action(int vid); }; #endif /*TRANSFER_MANAGER_H*/ diff --git a/include/User.h b/include/User.h new file mode 100644 index 0000000..0d0609f --- /dev/null +++ b/include/User.h @@ -0,0 +1,301 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad */ +/* Complutense de Madrid (dsa-research.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#ifndef USER_H_ +#define USER_H_ + +#include "PoolSQL.h" + +using namespace std; + +extern "C" int user_select_cb (void * _host, + int num, + char ** values, + char ** names); + +extern "C" int user_dump_cb (void * _oss, + int num, + char ** values, + char ** names); + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +/** + * The User class. It represents a User... + */ +class User : public PoolObjectSQL +{ +public: + + /** + * Function to write a User on an output stream + */ + friend ostream& operator<<(ostream& os, User& u); + + /** + * Function to print the User object into a string in plain text + * @param str the resulting string + * @return a reference to the generated string + */ + string& to_str(string& str) const; + + /** + * Function to print the User object into a string in XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(string& xml) const; + + + /** + * Get the User unique identifier UID, that matches the OID of the object + * @return UID User identifier + */ + int get_uid() const + { + return oid; + }; + + // ----- Getters --------------------------------- + + /** + * Check if the user is enabled + * @return true if the user is enabled + */ + bool isEnabled() const + { + return enabled; + } + + /** + * Returns user username + * @return username User's hostname + */ + const string& get_username() const + { + return username; + }; + + /** + * Returns user password + * @return username User's hostname + */ + const string& get_password() const + { + return password; + }; + + // ----- Setters --------------------------------- + + /** + * Enables the current user + */ + void enable() + { + enabled = true; + }; + + /** + * Disables the current user + */ + void disable() + { + enabled = false; + }; + + /** + * Sets user username + */ + void set_username(string _username) + { + username = _username; + }; + + /** + * Sets user password + */ + void set_password(string _password) + { + password = _password; + }; + + /** + * Looks for a match between _password and user password + * @return -1 if disabled or wrong password, uid otherwise + **/ + int authenticate(string _password); + + /** + * Splits an authentication token (:) + * @param secret, the authentication token + * @param username + * @param password + * @return 0 on success + **/ + static int split_secret(const string secret, string& user, string& pass); + + /** + * "Encrypts" the password with SHA1 digest + * @param password + * @return sha1 encrypted password + */ + static string sha1_digest(const string& pass); + +private: + // ------------------------------------------------------------------------- + // Friends + // ------------------------------------------------------------------------- + + friend class UserPool; + + friend int user_select_cb (void * _host, + int num, + char ** values, + char ** names); + + friend int user_dump_cb (void * _oss, + int num, + char ** values, + char ** names); + + // ------------------------------------------------------------------------- + // User Attributes + // ------------------------------------------------------------------------- + + /** + * User's username + */ + string username; + + /** + * User's password + */ + string password; + + /** + * Flag marking user enabled/disabled + */ + bool enabled; + + + // ************************************************************************* + // DataBase implementation (Private) + // ************************************************************************* + + /** + * Function to unmarshall a User object + * @param num the number of columns read from the DB + * @para names the column names + * @para vaues the column values + * @return 0 on success + */ + int unmarshall(int num, char **names, char ** values); + + /** + * Function to unmarshall a User object in to an output stream in XML + * @param oss the output stream + * @param num the number of columns read from the DB + * @param names the column names + * @param vaues the column values + * @return 0 on success + */ + static int unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values); + + /** + * Bootstraps the database table(s) associated to the User + */ + static void bootstrap(SqliteDB * db) + { + db->exec(User::db_bootstrap); + }; + +protected: + + // ************************************************************************* + // Constructor + // ************************************************************************* + + User(int id=-1, + string _username="", + string _password="", + bool _enabled=true); + + virtual ~User(); + + // ************************************************************************* + // DataBase implementation + // ************************************************************************* + + enum ColNames + { + OID = 0, + USERNAME = 1, + PASSWORD = 2, + ENABLED = 3, // 0 = false, 1 = true + LIMIT = 4 + }; + + static const char * db_names; + + static const char * db_bootstrap; + + static const char * table; + + /** + * Reads the User (identified with its OID=UID) from the database. + * @param db pointer to the db + * @return 0 on success + */ + virtual int select(SqliteDB *db); + + /** + * Writes the User in the database. + * @param db pointer to the db + * @return 0 on success + */ + virtual int insert(SqliteDB *db); + + /** + * Writes/updates the User data fields in the database. + * @param db pointer to the db + * @return 0 on success + */ + virtual int update(SqliteDB *db); + + /** + * Drops USer from the database + * @param db pointer to the db + * @return 0 on success + */ + virtual int drop(SqliteDB *db); + + /** + * Dumps the contect of a set of User objects in the given stream + * using XML format + * @param db pointer to the db + * @param oss the output stream + * @param where string to filter the VirtualMachine objects + * @return 0 on success + */ + static int dump(SqliteDB * db, ostringstream& oss, const string& where); +}; + +#endif /*USER_H_*/ diff --git a/include/UserPool.h b/include/UserPool.h new file mode 100644 index 0000000..3916719 --- /dev/null +++ b/include/UserPool.h @@ -0,0 +1,173 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad */ +/* Complutense de Madrid (dsa-research.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#ifndef USER_POOL_H_ +#define USER_POOL_H_ + +#include "PoolSQL.h" +#include "User.h" + +#include +#include + +#include + +#include + +using namespace std; + +/** + * The User Pool class. ... + */ +class UserPool : public PoolSQL +{ +public: + + UserPool(SqliteDB * db); + + ~UserPool(){}; + + /** + * Function to allocate a new User object + * @param oid the id assigned to the User + * @return 0 on success + */ + int allocate ( + int * oid, + string hostname, + string password, + bool enabled); + + /** + * Function to get a User from the pool, if the object is not in memory + * it is loaded from the DB + * @param oid User unique id + * @param lock locks the User mutex + * @return a pointer to the Host, 0 if the User could not be loaded + */ + User * get( + int oid, + bool lock) + { + User * user = static_cast(PoolSQL::get(oid,lock)); + + return user; + } + + + /** + * Function to get a User from the pool, if the object is not in memory + * it is loaded from the DB + * @param username + * @param lock locks the User mutex + * @return a pointer to the User, 0 if the User could not be loaded + */ + User * get( + string username, + bool lock) + { + map::iterator index; + + index = known_users.find(username); + + if ( index != known_users.end() ) + { + return get((int)index->second,lock); + } + + return 0; + } + + /** Update a particular User + * @param user pointer to User + * @return 0 on success + */ + int update(User * user) + { + return user->update(db); + }; + + + /** Drops a user from the DB, the user mutex MUST BE locked + * @param user pointer to User + */ + int drop(User * user) + { + int rc = user->drop(db); + + if ( rc == 0) + { + known_users.erase(user->get_username()); + } + + return rc; + }; + + /** + * Bootstraps the database table(s) associated to the User pool + */ + static void bootstrap(SqliteDB * _db) + { + User::bootstrap(_db); + }; + + /** + * Returns whether there is a user with given username/password or not + * @param session, colon separated username and password string + * @return -1 if there is no such a user, uid of the user if it exists + */ + int authenticate(string& session); + + /** + * Dumps the User pool in XML format. A filter can be also added to the + * query + * @param oss the output stream to dump the pool contents + * @param where filter for the objects, defaults to all + * + * @return 0 on success + */ + int dump(ostringstream& oss, const string& where) + { + int rc; + + oss << ""; + + rc = User::dump(db,oss,where); + + oss << ""; + + return rc; + } + +private: + /** + * Factory method to produce User objects + * @return a pointer to the new User + */ + PoolObjectSQL * create() + { + return new User; + }; + + /** + * This map stores the association between UIDs and Usernames + */ + map known_users; + +}; + +#endif /*USER_POOL_H_*/ diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 7b5d7e4..850a24e 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -77,7 +77,10 @@ class VirtualMachine : public PoolObjectSQL EPILOG_STOP = 10, EPILOG = 11, SHUTDOWN = 12, - CANCEL = 13 + CANCEL = 13, + FAILURE = 14, + DELETE = 15, + UNKNOWN = 16 }; // ------------------------------------------------------------------------- @@ -183,6 +186,16 @@ class VirtualMachine : public PoolObjectSQL } }; + + /** + * Returns the name of the VM + * @return the VM name + */ + const string& get_name() const + { + return name; + }; + /** * Returns the deployment ID * @return the VMM driver specific ID @@ -247,6 +260,7 @@ class VirtualMachine : public PoolObjectSQL { return (previous_history!=0); }; + /** * Returns the VMM driver name for the current host. The hasHistory() * function MUST be called before this one. @@ -257,6 +271,16 @@ class VirtualMachine : public PoolObjectSQL return history->vmm_mad_name; }; + /** + * Returns the VMM driver name for the previous host. The hasPreviousHistory() + * function MUST be called before this one. + * @return the VMM mad name + */ + const string & get_previous_vmm_mad() const + { + return previous_history->vmm_mad_name; + }; + /** * Returns the TM driver name for the current host. The hasHistory() * function MUST be called before this one. @@ -267,6 +291,16 @@ class VirtualMachine : public PoolObjectSQL return history->tm_mad_name; }; + /** + * Returns the TM driver name for the previous host. The + * hasPreviousHistory() function MUST be called before this one. + * @return the TM mad name + */ + const string & get_previous_tm_mad() const + { + return previous_history->tm_mad_name; + }; + /** * Returns the transfer filename. The transfer file is in the form: * $ONE_LOCATION/var/$VM_ID/transfer.$SEQ @@ -750,6 +784,12 @@ class VirtualMachine : public PoolObjectSQL // ------------------------------------------------------------------------- // Virtual Machine Description // ------------------------------------------------------------------------- + + /** + * Name of the VM + */ + string name; + /** * The Virtual Machine template, holds the VM attributes. */ @@ -849,6 +889,20 @@ class VirtualMachine : public PoolObjectSQL */ int unmarshall(int num, char **names, char ** values); + /** + * Function to unmarshall a VM object into an output stream with XML + * format. + * @param oss the output stream + * @param num the number of columns read from the DB + * @param names the column names + * @param vaues the column values + * @return 0 on success + */ + static int unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values); + /** * Updates the VM history record * @param db pointer to the db @@ -963,18 +1017,19 @@ class VirtualMachine : public PoolObjectSQL { OID = 0, UID = 1, - LAST_POLL = 2, - TEMPLATE_ID = 3, - STATE = 4, - LCM_STATE = 5, - STIME = 6, - ETIME = 7, - DEPLOY_ID = 8, - MEMORY = 9, - CPU = 10, - NET_TX = 11, - NET_RX = 12, - LIMIT = 13 + NAME = 2, + LAST_POLL = 3, + TEMPLATE_ID = 4, + STATE = 5, + LCM_STATE = 6, + STIME = 7, + ETIME = 8, + DEPLOY_ID = 9, + MEMORY = 10, + CPU = 11, + NET_TX = 12, + NET_RX = 13, + LIMIT = 14 }; static const char * table; @@ -1003,17 +1058,6 @@ class VirtualMachine : public PoolObjectSQL * @return 0 on success */ virtual int update(SqliteDB * db); - - /** - * Dumps the contect of a set of VirtualMachine objects in the given stream - * using XML format - * @param db pointer to the db - * @param oss the output stream - * @param where string to filter the VirtualMachine objects - * @return 0 on success - */ - static int dump(SqliteDB * db, ostringstream& oss, const string& -where); /** * Deletes a VM from the database and all its associated information: @@ -1035,6 +1079,16 @@ where); return rc; } + + /** + * Dumps the contect of a set of VirtualMachine objects in the given stream + * using XML format + * @param db pointer to the db + * @param oss the output stream + * @param where string to filter the VirtualMachine objects + * @return 0 on success + */ + static int dump(SqliteDB * db, ostringstream& oss, const string& where); }; #endif /*VIRTUAL_MACHINE_H_*/ diff --git a/include/VirtualMachineManager.h b/include/VirtualMachineManager.h index dd9451d..cab24c6 100644 --- a/include/VirtualMachineManager.h +++ b/include/VirtualMachineManager.h @@ -48,10 +48,12 @@ class VirtualMachineManager : public MadManager, public ActionListener SAVE, SHUTDOWN, CANCEL, + CANCEL_PREVIOUS, MIGRATE, RESTORE, POLL, TIMER, + DRIVER_CANCEL, FINALIZE }; @@ -201,6 +203,14 @@ class VirtualMachineManager : public MadManager, public ActionListener void cancel_action( int vid); + /** + * Cancels a VM (in the previous host) when a CANCEL action is received. + * Note that the domain-id is the last one returned by a boot action + * @param vid the id of the VM. + */ + void cancel_previous_action( + int vid); + /** * Function to migrate (live) a VM (MIGRATE action). * @param vid the id of the VM. @@ -226,6 +236,12 @@ class VirtualMachineManager : public MadManager, public ActionListener * This function is executed periodically to poll the running VMs */ void timer_action(); + + /** + * This function cancels the current driver operation + */ + void driver_cancel_action( + int vid); }; #endif /*VIRTUAL_MACHINE_MANAGER_H*/ diff --git a/include/VirtualMachinePool.h b/include/VirtualMachinePool.h index 3c6f6e8..fcded8b 100644 --- a/include/VirtualMachinePool.h +++ b/include/VirtualMachinePool.h @@ -127,9 +127,9 @@ class VirtualMachinePool : public PoolSQL /** * Bootstraps the database table(s) associated to the VirtualMachine pool */ - void bootstrap() + static void bootstrap(SqliteDB * _db) { - VirtualMachine::bootstrap(db); + VirtualMachine::bootstrap(_db); }; /** diff --git a/include/VirtualMachineTemplate.h b/include/VirtualMachineTemplate.h index d62b0f7..1392a07 100644 --- a/include/VirtualMachineTemplate.h +++ b/include/VirtualMachineTemplate.h @@ -29,7 +29,7 @@ class VirtualMachineTemplate : public TemplateSQL { public: VirtualMachineTemplate(int tid = -1): - TemplateSQL(table,tid,false,'=',"VM_TEMPLATE"){}; + TemplateSQL(table,tid,false,'=',"TEMPLATE"){}; ~VirtualMachineTemplate(){}; diff --git a/include/VirtualNetwork.h b/include/VirtualNetwork.h index 6d464f1..7aae346 100644 --- a/include/VirtualNetwork.h +++ b/include/VirtualNetwork.h @@ -34,6 +34,8 @@ using namespace std; extern "C" int vn_select_cb (void * _vn, int num,char ** values, char ** names); +extern "C" int vn_dump_cb (void * _oss, int num, char ** values, char ** names); + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -60,6 +62,17 @@ class VirtualNetwork : public PoolObjectSQL // ************************************************************************* // Virtual Network Public Methods // ************************************************************************* + + + /** + * Gets the uid of the owner of the Virtual Network + * @return uid + **/ + int get_uid() + { + return uid; + } + /** * Gets a new lease for a specific VM * @param vid VM identifier @@ -112,6 +125,22 @@ class VirtualNetwork : public PoolObjectSQL */ friend ostream& operator<<(ostream& os, VirtualNetwork& vn); + /** + * Function to print the VirtualNetwork object into a string in + * plain text + * @param str the resulting string + * @return a reference to the generated string + */ + string& to_str(string& str) const; + + /** + * Function to print the VirtualNetwork object into a string in + * XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(string& xml) const; + private: // ------------------------------------------------------------------------- @@ -125,6 +154,12 @@ class VirtualNetwork : public PoolObjectSQL char ** values, char ** names); + friend int vn_dump_cb ( + void * _oss, + int num, + char ** values, + char ** names); + // ************************************************************************* // Virtual Network Private Attributes // ************************************************************************* @@ -209,6 +244,18 @@ class VirtualNetwork : public PoolObjectSQL */ int unmarshall(int num, char **names, char ** values); + /** + * Function to unmarshall a VNW object into an stream in XML format. + * @param oss the output stream + * @param num the number of columns read from the DB + * @para names the column names + * @para vaues the column values + * @return 0 on success + */ + static int unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values); /** * Function to drop VN entry in vn_pool * @return 0 on success @@ -369,6 +416,16 @@ class VirtualNetwork : public PoolObjectSQL return rc; } + + /** + * Dumps the contect of a set of Host objects in the given stream + * using XML format + * @param db pointer to the db + * @param oss the output stream + * @param where string to filter the VirtualMachine objects + * @return 0 on success + */ + static int dump(SqliteDB * db, ostringstream& oss, const string& where); }; #endif /*VIRTUAL_NETWORK_H_*/ diff --git a/include/VirtualNetworkPool.h b/include/VirtualNetworkPool.h index f723d5a..31c0113 100644 --- a/include/VirtualNetworkPool.h +++ b/include/VirtualNetworkPool.h @@ -100,9 +100,9 @@ class VirtualNetworkPool : public PoolSQL /** * Bootstraps the database table(s) associated to the VirtualNetwork pool */ - void bootstrap() + static void bootstrap(SqliteDB * _db) { - VirtualNetwork::bootstrap(db); + VirtualNetwork::bootstrap(_db); }; /** Drops a VN from the cache & DB, the VN mutex MUST BE locked @@ -110,26 +110,31 @@ class VirtualNetworkPool : public PoolSQL */ int drop(VirtualNetwork * vn) { - int rc = vn->drop(db); - - if ( rc == 0) - { - remove(static_cast(vn)); - } - - return rc; + return vn->drop(db); }; -private: /** - * Factory method to produce VN objects - * @return a pointer to the new VN + * Dumps the HOST pool in XML format. A filter can be also added to the + * query + * @param oss the output stream to dump the pool contents + * @param where filter for the objects, defaults to all + * + * @return 0 on success */ - PoolObjectSQL * create() + int dump(ostringstream& oss, const string& where) { - return new VirtualNetwork(mac_prefix, default_size); - }; - + int rc; + + oss << ""; + + rc = VirtualNetwork::dump(db,oss,where); + + oss << ""; + + return rc; + } + +private: /** * Holds the system-wide MAC prefix */ @@ -139,6 +144,16 @@ class VirtualNetworkPool : public PoolSQL * Default size for Virtual Networks */ unsigned int default_size; + + /** + * Factory method to produce VN objects + * @return a pointer to the new VN + */ + PoolObjectSQL * create() + { + return new VirtualNetwork(mac_prefix, default_size); + }; + }; #endif /*VIRTUAL_NETWORK_POOL_H_*/ diff --git a/include/VirtualNetworkTemplate.h b/include/VirtualNetworkTemplate.h index daad262..92536c4 100644 --- a/include/VirtualNetworkTemplate.h +++ b/include/VirtualNetworkTemplate.h @@ -29,7 +29,7 @@ class VirtualNetworkTemplate : public TemplateSQL { public: VirtualNetworkTemplate(int tid = -1): - TemplateSQL(table,tid,false,'=',"NETWORK_TEMPLATE"){}; + TemplateSQL(table,tid,false,'=',"TEMPLATE"){}; ~VirtualNetworkTemplate(){}; diff --git a/install.sh b/install.sh index 36291a0..e330ce9 100755 --- a/install.sh +++ b/install.sh @@ -125,6 +125,7 @@ ETC_DIRS="$ETC_LOCATION/im_kvm \ LIB_DIRS="$LIB_LOCATION/im_probes \ $LIB_LOCATION/ruby \ + $LIB_LOCATION/ruby/OpenNebula \ $LIB_LOCATION/tm_commands \ $LIB_LOCATION/tm_commands/nfs \ $LIB_LOCATION/tm_commands/ssh \ @@ -143,13 +144,14 @@ INSTALL_FILES[0]="BIN_FILES:$BIN_LOCATION" INSTALL_FILES[1]="INCLUDE_FILES:$INCLUDE_LOCATION" INSTALL_FILES[2]="LIB_FILES:$LIB_LOCATION" INSTALL_FILES[3]="RUBY_LIB_FILES:$LIB_LOCATION/ruby" -INSTALL_FILES[4]="MADS_LIB_FILES:$LIB_LOCATION/mads" -INSTALL_FILES[5]="IM_PROBES_LIB_FILES:$LIB_LOCATION/im_probes" -INSTALL_FILES[6]="NFS_TM_COMMANDS_LIB_FILES:$LIB_LOCATION/tm_commands/nfs" -INSTALL_FILES[7]="SSH_TM_COMMANDS_LIB_FILES:$LIB_LOCATION/tm_commands/ssh" -INSTALL_FILES[8]="DUMMY_TM_COMMANDS_LIB_FILES:$LIB_LOCATION/tm_commands/dummy" -INSTALL_FILES[9]="EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples" -INSTALL_FILES[10]="TM_EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples/tm" +INSTALL_FILES[4]="RUBY_OPENNEBULA_LIB_FILES:$LIB_LOCATION/ruby/OpenNebula" +INSTALL_FILES[5]="MADS_LIB_FILES:$LIB_LOCATION/mads" +INSTALL_FILES[6]="IM_PROBES_LIB_FILES:$LIB_LOCATION/im_probes" +INSTALL_FILES[7]="NFS_TM_COMMANDS_LIB_FILES:$LIB_LOCATION/tm_commands/nfs" +INSTALL_FILES[8]="SSH_TM_COMMANDS_LIB_FILES:$LIB_LOCATION/tm_commands/ssh" +INSTALL_FILES[9]="DUMMY_TM_COMMANDS_LIB_FILES:$LIB_LOCATION/tm_commands/dummy" +INSTALL_FILES[10]="EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples" +INSTALL_FILES[11]="TM_EXAMPLE_SHARE_FILES:$SHARE_LOCATION/examples/tm" INSTALL_ETC_FILES[0]="ETC_FILES:$ETC_LOCATION" INSTALL_ETC_FILES[1]="VMM_XEN_ETC_FILES:$ETC_LOCATION/vmm_xen" @@ -172,6 +174,7 @@ BIN_FILES="src/nebula/oned \ src/client/ruby/onevm \ src/client/ruby/onehost \ src/client/ruby/onevnet \ + src/client/ruby/oneuser \ share/scripts/one" #------------------------------------------------------------------------------- @@ -198,8 +201,20 @@ RUBY_LIB_FILES="src/mad/ruby/one_mad.rb \ src/client/ruby/one.rb \ src/client/ruby/client_utilities.rb \ src/client/ruby/command_parse.rb \ + src/client/ruby/lib/OpenNebula.rb \ src/tm_mad/TMScript.rb" +RUBY_OPENNEBULA_LIB_FILES="src/client/ruby/lib/OpenNebula/Host.rb \ + src/client/ruby/lib/OpenNebula/HostPool.rb \ + src/client/ruby/lib/OpenNebula/Pool.rb \ + src/client/ruby/lib/OpenNebula/User.rb \ + src/client/ruby/lib/OpenNebula/UserPool.rb \ + src/client/ruby/lib/OpenNebula/VirtualMachine.rb \ + src/client/ruby/lib/OpenNebula/VirtualMachinePool.rb \ + src/client/ruby/lib/OpenNebula/VirtualNetwork.rb \ + src/client/ruby/lib/OpenNebula/VirtualNetworkPool.rb \ + src/client/ruby/lib/OpenNebula/XMLUtils.rb" + #------------------------------------------------------------------------------- # Driver executable files, to be installed under $LIB_LOCATION/mads #------------------------------------------------------------------------------- diff --git a/src/client/ruby/client_utilities.rb b/src/client/ruby/client_utilities.rb index 0c33b5e..b5a8fd1 100644 --- a/src/client/ruby/client_utilities.rb +++ b/src/client/ruby/client_utilities.rb @@ -15,6 +15,8 @@ # limitations under the License. # #--------------------------------------------------------------------------- # +require 'OpenNebula' + ##################### # CONSOLE UTILITIES # ##################### @@ -44,7 +46,14 @@ def scr_move(x,y) print "\33[#{x};#{y}H" end - +# Print header +def print_header(format_str, str, underline) + scr_bold + scr_underline if underline + print format_str % str + scr_restore + puts +end ################################## # Class show configurable tables # @@ -207,6 +216,22 @@ def print_help # Miscelaneous # ################ +def get_one_client(session=nil) + if !ENV["ONE_AUTH"] or ENV["ONE_AUTH"].empty? or !ENV["ONE_AUTH"].match(".+:.+") + puts "$ONE_AUTH not defined or malformed" + exit -1 + end + OpenNebula::Client.new(session) +end + +def is_error?(result) + OpenNebula.is_error?(result) +end + +def is_successful?(result) + !OpenNebula.is_error?(result) +end + def check_parameters(name, number) if ARGV.length < number print "Command #{name} requires " @@ -220,62 +245,59 @@ def check_parameters(name, number) end -def get_vm_id(vm, name) - vm_id=vm.get_vm_id(name) + +def get_entity_id(name, pool_class) + return name if name.match(/^[0123456789]+$/) + + # TODO: get vm's from the actual user + pool=pool_class.new(get_one_client) + result=pool.info + + # TODO: Check for errors + + objects=pool.select {|object| object.name==name } - result=nil + class_name=pool_class.name.split('::').last.gsub(/Pool$/, '') - if vm_id - if vm_id.kind_of?(Array) - puts "There are multiple VM's with name #{name}." + if objects.length>0 + if objects.length>1 + puts "There are multiple #{class_name}'s with name #{name}." exit -1 else - result=vm_id + result=objects.first.id end else - puts "VM named #{name} not found." + puts "#{class_name} named #{name} not found." exit -1 end result end -def get_host_id(host, name) - host_id=host.get_host_id(name) - - result=nil - - if host_id - if host_id.kind_of?(Array) - puts "There are multiple hosts with name #{name}." - exit -1 - else - result=host_id - end - else - puts "Host named #{name} not found." - exit -1 - end - - result +def get_vm_id(name) + get_entity_id(name, OpenNebula::VirtualMachinePool) end -def get_vn_id(vn, name) - vn_id=vn.get_vn_id(name) - - result=nil - - if vn_id - if vn_id.kind_of?(Array) - puts "There are multiple virtual networks with name #{name}." - exit -1 - else - result=vn_id - end +def get_host_id(name) + get_entity_id(name, OpenNebula::HostPool) +end + +def get_vn_id(name) + get_entity_id(name, OpenNebula::VirtualNetworkPool) +end + +def get_user_id(name) + get_entity_id(name, OpenNebula::UserPool) +end + +def str_running_time(data) + stime=Time.at(data["stime"].to_i) + if data["etime"]=="0" + etime=Time.now else - puts "Virtual networks named #{name} not found." - exit -1 + etime=Time.at(data["etime"].to_i) end - - result + dtime=Time.at(etime-stime).getgm + + "%02d %02d:%02d:%02d" % [dtime.yday-1, dtime.hour, dtime.min, dtime.sec] end diff --git a/src/client/ruby/command_parse.rb b/src/client/ruby/command_parse.rb index 118949f..3d90997 100644 --- a/src/client/ruby/command_parse.rb +++ b/src/client/ruby/command_parse.rb @@ -81,6 +81,11 @@ def initialize "is successful") do |o| @options[:verbose]=true end + + opts.on("-x", "--xml", + "Returns xml instead of human readable text") do |o| + @options[:xml]=true + end opts.on_tail("-h", "--help", "Shows this help message") do |o| print_help diff --git a/src/client/ruby/lib/OpenNebula.rb b/src/client/ruby/lib/OpenNebula.rb new file mode 100644 index 0000000..fdb33da --- /dev/null +++ b/src/client/ruby/lib/OpenNebula.rb @@ -0,0 +1,99 @@ +begin # require 'rubygems' + require 'rubygems' +rescue Exception +end +require 'xmlrpc/client' +require 'digest/sha1' +require 'rexml/document' +require 'pp' + +require 'OpenNebula/XMLUtils' +require 'OpenNebula/VirtualMachine' +require 'OpenNebula/VirtualMachinePool' +require 'OpenNebula/VirtualNetwork' +require 'OpenNebula/VirtualNetworkPool' +require 'OpenNebula/User' +require 'OpenNebula/UserPool' +require 'OpenNebula/Host' +require 'OpenNebula/HostPool' + +module OpenNebula + + # ------------------------------------------------------------------------- + # The Error Class represents a generic error in the OpenNebula + # library. It contains a readable representation of the error. + # Any function in the OpenNebula module will return an Error + # object in case of error. + # ------------------------------------------------------------------------- + class Error + attr_reader :message + + # +message+ a description of the error + def initialize(message=nil) + @message=message + end + + def to_str() + @message + end + end + + # ------------------------------------------------------------------------- + # Returns true if the object returned by a method of the OpenNebula + # library is an Error + # ------------------------------------------------------------------------- + def self.is_error?(value) + value.class==OpenNebula::Error + end + + # ------------------------------------------------------------------------- + # The client class, represents the connection with the core and handles the + # xml-rpc calls. + # ------------------------------------------------------------------------- + class Client + begin + require 'xmlparser' + XMLPARSER=true + rescue LoadError + XMLPARSER=false + end + + def initialize(secret=nil, endpoint=nil) + if secret + one_secret = secret + elsif ENV["ONE_AUTH"] + one_secret = ENV["ONE_AUTH"] + end + + one_secret=~/(\w+):(\w+)/ + @one_auth = "#{$1}:#{Digest::SHA1.hexdigest($2)}" + + if endpoint + @one_endpoint=endpoint + elsif ENV["ONE_XMLRPC"] + @one_endpoint=ENV["ONE_XMLRPC"] + else + @one_endpoint="http://localhost:2633/RPC2" + end + end + + def call(action, *args) + server=XMLRPC::Client.new2(@one_endpoint) + if XMLPARSER + server.set_parser(XMLRPC::XMLParser::XMLStreamParser.new) + end + + begin + response = server.call("one."+action, @one_auth, *args) + + if response[0] == false + Error.new(response[1]) + else + response[1] #response[1..-1] + end + rescue Exception => e + Error.new(e.message) + end + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/Host.rb b/src/client/ruby/lib/OpenNebula/Host.rb new file mode 100644 index 0000000..ceb718e --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/Host.rb @@ -0,0 +1,106 @@ +require 'OpenNebula/Pool' + +module OpenNebula + class Host < PoolElement + ####################################################################### + # Constants and Class Methods + ####################################################################### + HOST_METHODS = { + :info => "host.info", + :allocate => "host.allocate", + :delete => "host.delete", + :enable => "host.enable" + } + + HOST_STATES=%w{INIT MONITORING MONITORED ERROR DISABLED} + + SHORT_HOST_STATES={ + "INIT" => "on", + "MONITORING" => "on", + "MONITORED" => "on", + "ERROR" => "err", + "DISABLED" => "off" + } + + # Creates a Host description with just its identifier + # this method should be used to create plain Host objects. + # +id+ the id of the host + # + # Example: + # host = Host.new(Host.build_xml(3),rpc_client) + # + def Host.build_xml(pe_id=nil) + if pe_id + host_xml = "#{pe_id}" + else + host_xml = "" + end + + XMLUtilsElement.initialize_xml(host_xml, 'HOST') + end + + ####################################################################### + # Class constructor + ####################################################################### + def initialize(xml, client) + super(xml,client) + + @client = client + @pe_id = self['ID'].to_i if self['ID'] + end + + ####################################################################### + # XML-RPC Methods for the Host + ####################################################################### + def info() + super(HOST_METHODS[:info], 'HOST') + end + + def allocate(hostname,im,vmm,tm) + super(HOST_METHODS[:allocate],hostname,im,vmm,tm) + end + + def delete() + super(HOST_METHODS[:delete]) + end + + def enable() + set_enabled(true) + end + + def disable() + set_enabled(false) + end + + ####################################################################### + # Helpers to get Host information + ####################################################################### + + # Returns the state of the Host (numeric value) + def state + self['STATE'].to_i + end + + # Returns the state of the Host (string value) + def state_str + HOST_STATES[state] + end + + + # Returns the state of the Host (string value) + def short_state_str + SHORT_HOST_STATES[state_str] + end + + + private + def set_enabled(enabled) + return Error.new('ID not defined') if !@pe_id + + rc = @client.call(HOST_METHODS[:enable], @pe_id, enabled) + rc = nil if !OpenNebula.is_error?(rc) + + return rc + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/HostPool.rb b/src/client/ruby/lib/OpenNebula/HostPool.rb new file mode 100644 index 0000000..2231b5b --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/HostPool.rb @@ -0,0 +1,35 @@ +require 'OpenNebula/Pool' + +module OpenNebula + class HostPool < Pool + ####################################################################### + # Constants and Class attribute accessors + ####################################################################### + + HOST_POOL_METHODS = { + :info => "hostpool.info" + } + + ####################################################################### + # Class constructor & Pool Methods + ####################################################################### + + # +client+ a Client object that represents a XML-RPC connection + def initialize(client) + super('HOST_POOL','HOST',client) + end + + # Factory Method for the Host Pool + def factory(element_xml) + OpenNebula::Host.new(element_xml,@client) + end + + ####################################################################### + # XML-RPC Methods for the Host Pool + ####################################################################### + + def info() + super(HOST_POOL_METHODS[:info]) + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/Pool.rb b/src/client/ruby/lib/OpenNebula/Pool.rb new file mode 100644 index 0000000..b6ad4df --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/Pool.rb @@ -0,0 +1,173 @@ + +module OpenNebula + # The Pool class represents a generic OpenNebula Pool in XML format + # and provides the basic functionality to handle the Pool elements + class Pool + include Enumerable + include XMLUtilsPool + + protected + + #pool:: _String_ XML name of the root element + #element:: _String_ XML name of the Pool elements + #client:: _Client_ represents a XML-RPC connection + def initialize(pool,element,client) + @pool_name = pool.upcase + @element_name = element.upcase + + @client = client + @xml = nil + end + + # Default Factory Method for the Pools. The factory method returns an + # suitable PoolElement object. Each Pool MUST implement the + # corresponding factory method + # element_xml:: _XML_ XML element describing the pool element + # [return] a PoolElement object + def factory(element_xml) + OpenNebula::PoolElement.new(element_xml,client) + end + + ####################################################################### + # Common XML-RPC Methods for all the Pool Types + ####################################################################### + + # Calls to the corresponding info method to retreive the pool + # representation in XML format + # xml_method:: _String_ the name of the XML-RPC method + # args:: _Array_ with additional arguments for the info call + # [return] nil in case of success or an Error object + def info(xml_method,*args) + rc = @client.call(xml_method,*args) + + if !OpenNebula.is_error?(rc) + @xml = initialize_xml(rc) + rc = nil + end + + return rc + end + + public + + # Iterates over every PoolElement in the Pool and calls the block with a + # a PoolElement obtained calling the factory method + # block:: _Block_ + def each(&block) + each_element(block) if @xml + end + + # DO NOT USE - ONLY REXML BACKEND + def to_str + str = "" + REXML::Formatters::Pretty.new(1).write(@xml,str) + + return str + end + end + + # The PoolElement Class represents a generic element of a Pool in + # XML format + class PoolElement + include XMLUtilsElement + + protected + # node:: _XML_is a XML element that represents the Pool element + # client:: _Client_ represents a XML-RPC connection + def initialize(node, client) + @xml = node + @client = client + + if self['ID'] + @pe_id = self['ID'].to_i + else + @pe_id = nil + end + @name = self['NAME'] if self['NAME'] + end + + ####################################################################### + # Common XML-RPC Methods for all the Pool Element Types + ####################################################################### + + # Calls to the corresponding info method to retreive the element + # detailed information in XML format + # xml_method:: _String_ the name of the XML-RPC method + # root_element:: _String_ Base XML element + # [return] nil in case of success or an Error object + def info(xml_method, root_element) + return Error.new('ID not defined') if !@pe_id + + rc = @client.call(xml_method,@pe_id) + + if !OpenNebula.is_error?(rc) + @xml = XMLUtilsElement::initialize_xml(rc, root_element) + rc = nil + + @pe_id = self['ID'].to_i if self['ID'] + @name = self['NAME'] if self['NAME'] + end + + return rc + end + + # Calls to the corresponding allocate method to create a new element + # in the OpenNebula core + # xml_method:: _String_ the name of the XML-RPC method + # args:: _Array_ additional arguments including the template for the + # new element + # [return] nil in case of success or an Error object + def allocate(xml_method, *args) + rc = @client.call(xml_method, *args) + + if !OpenNebula.is_error?(rc) + @pe_id = rc + rc = nil + end + + return rc + end + + # Calls to the corresponding delete method to remove this element + # from the OpenNebula core + # xml_method:: _String_ the name of the XML-RPC method + # [return] nil in case of success or an Error object + def delete(xml_method) + return Error.new('ID not defined') if !@pe_id + + rc = @client.call(xml_method,@pe_id) + rc = nil if !OpenNebula.is_error?(rc) + + return rc + end + + public + + # Creates new element specifying its id + # id:: identifyier of the element + # client:: initialized OpenNebula::Client object + def self.new_with_id(id, client=nil) + self.new(self.build_xml(id), client) + end + + # Returns element identifier + # [return] _Integer_ the PoolElement ID + def id + @pe_id + end + + # Gets element name + # [return] _String_ the PoolElement name + def name + @name + end + + # DO NOT USE - ONLY REXML BACKEND + def to_str + str = "" + REXML::Formatters::Pretty.new(1).write(@xml,str) + + return str + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/User.rb b/src/client/ruby/lib/OpenNebula/User.rb new file mode 100644 index 0000000..e345086 --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/User.rb @@ -0,0 +1,55 @@ +require 'OpenNebula/Pool' + +module OpenNebula + class User < PoolElement + # --------------------------------------------------------------------- + # Constants and Class Methods + # --------------------------------------------------------------------- + USER_METHODS = { + :info => "user.info", + :allocate => "user.allocate", + :delete => "user.delete" + } + + # Creates a User description with just its identifier + # this method should be used to create plain User objects. + # +id+ the id of the user + # + # Example: + # user = User.new(User.build_xml(3),rpc_client) + # + def User.build_xml(pe_id=nil) + if pe_id + user_xml = "#{pe_id}" + else + user_xml = "" + end + + XMLUtilsElement.initialize_xml(user_xml, 'USER') + end + + # --------------------------------------------------------------------- + # Class constructor + # --------------------------------------------------------------------- + def initialize(xml, client) + super(xml,client) + + @client = client + end + + # --------------------------------------------------------------------- + # XML-RPC Methods for the User Object + # --------------------------------------------------------------------- + def info() + super(USER_METHODS[:info], 'USER') + end + + def allocate(username, password) + super(USER_METHODS[:allocate], username, password) + end + + def delete() + super(USER_METHODS[:delete]) + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/UserPool.rb b/src/client/ruby/lib/OpenNebula/UserPool.rb new file mode 100644 index 0000000..1d84904 --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/UserPool.rb @@ -0,0 +1,35 @@ +require 'OpenNebula/Pool' + +module OpenNebula + class UserPool < Pool + # --------------------------------------------------------------------- + # Constants and Class attribute accessors + # --------------------------------------------------------------------- + + USER_POOL_METHODS = { + :info => "userpool.info" + } + + # --------------------------------------------------------------------- + # Class constructor & Pool Methods + # --------------------------------------------------------------------- + + # +client+ a Client object that represents a XML-RPC connection + def initialize(client) + super('USER_POOL','USER',client) + end + + # Factory method to create User objects + def factory(element_xml) + OpenNebula::User.new(element_xml,@client) + end + + # --------------------------------------------------------------------- + # XML-RPC Methods for the User Object + # --------------------------------------------------------------------- + + def info() + super(USER_POOL_METHODS[:info]) + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/VirtualMachine.rb b/src/client/ruby/lib/OpenNebula/VirtualMachine.rb new file mode 100644 index 0000000..0c81b19 --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/VirtualMachine.rb @@ -0,0 +1,216 @@ +require 'OpenNebula/Pool' + +module OpenNebula + class VirtualMachine < PoolElement + ####################################################################### + # Constants and Class Methods + ####################################################################### + VM_METHODS = { + :info => "vm.info", + :allocate => "vm.allocate", + :action => "vm.action", + :migrate => "vm.migrate", + :deploy => "vm.deploy" + } + + VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED} + + LCM_STATE=%w{LCM_INIT PROLOG BOOT RUNNING MIGRATE SAVE_STOP SAVE_SUSPEND + SAVE_MIGRATE PROLOG_MIGRATE PROLOG_RESUME EPILOG_STOP EPILOG + SHUTDOWN CANCEL FAILURE DELETE UNKNOWN} + + SHORT_VM_STATES={ + "INIT" => "init", + "PENDING" => "pend", + "HOLD" => "hold", + "ACTIVE" => "actv", + "STOPPED" => "stop", + "SUSPENDED" => "susp", + "DONE" => "done", + "FAILED" => "fail" + } + + SHORT_LCM_STATES={ + "PROLOG" => "prol", + "BOOT" => "boot", + "RUNNING" => "runn", + "MIGRATE" => "migr", + "SAVE_STOP" => "save", + "SAVE_SUSPEND" => "save", + "SAVE_MIGRATE" => "save", + "PROLOG_MIGRATE"=> "migr", + "PROLOG_RESUME" => "prol", + "EPILOG_STOP" => "epil", + "EPILOG" => "epil", + "SHUTDOWN" => "shut", + "CANCEL" => "shut", + "FAILURE" => "fail", + "DELETE" => "dele", + "UNKNOWN" => "unkn" + } + + MIGRATE_REASON=%w{NONE ERROR STOP_RESUME USER CANCEL} + + SHORT_MIGRATE_REASON={ + "NONE" => "none", + "ERROR" => "erro", + "STOP_RESUME" => "stop", + "USER" => "user", + "CANCEL" => "canc" + } + + # Creates a VirtualMachine description with just its identifier + # this method should be used to create plain VirtualMachine objects. + # +id+ the id of the vm + # + # Example: + # vnet = VirtualMachine.new(VirtualMachine.build_xml(3),rpc_client) + # + def VirtualMachine.build_xml(pe_id=nil) + if pe_id + vm_xml = "#{pe_id}" + else + vm_xml = "" + end + + XMLUtilsElement.initialize_xml(vm_xml, 'VM') + end + + def VirtualMachine.get_reason(reason) + reason=MIGRATE_REASON[reason.to_i] + reason_str=SHORT_MIGRATE_REASON[reason] + + reason_str + end + + ####################################################################### + # Class constructor + ####################################################################### + def initialize(xml, client) + super(xml,client) + + @element_name = "VM" + @client = client + end + + ####################################################################### + # XML-RPC Methods for the Virtual Machine Object + ####################################################################### + + def info() + super(VM_METHODS[:info], 'VM') + end + + def allocate(description) + super(VM_METHODS[:allocate],description) + end + + def deploy(host_id) + return Error.new('ID not defined') if !@pe_id + + rc = @client.call(VM_METHODS[:deploy], @pe_id, host_id.to_i) + rc = nil if !OpenNebula.is_error?(rc) + + return rc + end + + def shutdown + action('shutdown') + end + + def cancel + action('cancel') + end + + def hold + action('hold') + end + + def release + action('release') + end + + def stop + action('stop') + end + + def suspend + action('suspend') + end + + def resume + action('resume') + end + + def finalize + action('finalize') + end + + def restart + action('restart') + end + + def migrate(host_id) + return Error.new('ID not defined') if !@pe_id + + rc = @client.call(VM_METHODS[:migrate], @pe_id, host_id.to_i, false) + rc = nil if !OpenNebula.is_error?(rc) + + return rc + end + + def live_migrate(host_id) + return Error.new('ID not defined') if !@pe_id + + rc = @client.call(VM_METHODS[:migrate], @pe_id, host_id.to_i, true) + rc = nil if !OpenNebula.is_error?(rc) + + return rc + end + + ####################################################################### + # Helpers to get VirtualMachine information + ####################################################################### + + # Returns the VM state of the VirtualMachine (numeric value) + def state + self['STATE'].to_i + end + + # Returns the VM state of the VirtualMachine (string value) + def state_str + VM_STATE[state] + end + + # Returns the LCM state of the VirtualMachine (numeric value) + def lcm_state + self['LCM_STATE'].to_i + end + + # Returns the LCM state of the VirtualMachine (string value) + def lcm_state_str + LCM_STATE[lcm_state] + end + + # Returns the short status string for the VirtualMachine + def status + short_state_str=SHORT_VM_STATES[state_str] + + if short_state_str=="actv" + short_state_str=SHORT_LCM_STATES[lcm_state_str] + end + + short_state_str + end + + private + def action(name) + return Error.new('ID not defined') if !@pe_id + + rc = @client.call(VM_METHODS[:action], name, @pe_id) + rc = nil if !OpenNebula.is_error?(rc) + + return rc + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/VirtualMachinePool.rb b/src/client/ruby/lib/OpenNebula/VirtualMachinePool.rb new file mode 100644 index 0000000..8649c17 --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/VirtualMachinePool.rb @@ -0,0 +1,38 @@ +require 'OpenNebula/Pool' + +module OpenNebula + class VirtualMachinePool < Pool + ####################################################################### + # Constants and Class attribute accessors + ####################################################################### + + VM_POOL_METHODS = { + :info => "vmpool.info" + } + + ####################################################################### + # Class constructor & Pool Methods + ####################################################################### + + # +client+ a Client object that represents a XML-RPC connection + # +user_id+ is to refer to a Pool with VirtualNetworks from that user + def initialize(client, user_id=0) + super('VM_POOL','VM',client) + + @user_id = user_id + end + + # Default Factory Method for the Pools + def factory(element_xml) + OpenNebula::VirtualMachine.new(element_xml,@client) + end + + ####################################################################### + # XML-RPC Methods for the Virtual Network Object + ####################################################################### + + def info() + super(VM_POOL_METHODS[:info],@user_id) + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/VirtualNetwork.rb b/src/client/ruby/lib/OpenNebula/VirtualNetwork.rb new file mode 100644 index 0000000..4fd43eb --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/VirtualNetwork.rb @@ -0,0 +1,54 @@ +require 'OpenNebula/Pool' + +module OpenNebula + class VirtualNetwork < PoolElement + # --------------------------------------------------------------------- + # Constants and Class Methods + # --------------------------------------------------------------------- + VN_METHODS = { + :info => "vn.info", + :allocate => "vn.allocate", + :delete => "vn.delete" + } + + # Creates a VirtualNetwork description with just its identifier + # this method should be used to create plain VirtualNetwork objects. + # +id+ the id of the network + # + # Example: + # vnet = VirtualNetwork.new(VirtualNetwork.build_xml(3),rpc_client) + # + def VirtualNetwork.build_xml(pe_id=nil) + if pe_id + vn_xml = "#{pe_id}" + else + vn_xml = "" + end + + XMLUtilsElement.initialize_xml(vn_xml, 'VNET') + end + + # Class constructor + def initialize(xml, client) + super(xml,client) + + @client = client + end + + ####################################################################### + # XML-RPC Methods for the Virtual Network Object + ####################################################################### + + def info() + super(VN_METHODS[:info], 'VNET') + end + + def allocate(description) + super(VN_METHODS[:allocate],description) + end + + def delete() + super(VN_METHODS[:delete]) + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/VirtualNetworkPool.rb b/src/client/ruby/lib/OpenNebula/VirtualNetworkPool.rb new file mode 100644 index 0000000..6ce370b --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/VirtualNetworkPool.rb @@ -0,0 +1,38 @@ +require 'OpenNebula/Pool' + +module OpenNebula + class VirtualNetworkPool < Pool + ####################################################################### + # Constants and Class attribute accessors + ####################################################################### + + VN_POOL_METHODS = { + :info => "vnpool.info" + } + + ####################################################################### + # Class constructor & Pool Methods + ####################################################################### + + # +client+ a Client object that represents a XML-RPC connection + # +user_id+ is to refer to a Pool with VirtualNetworks from that user + def initialize(client, user_id=0) + super('VNET_POOL','VNET',client) + + @user_id = user_id + end + + # Default Factory Method for the Pools + def factory(element_xml) + OpenNebula::VirtualNetwork.new(element_xml,@client) + end + + ####################################################################### + # XML-RPC Methods for the Virtual Network Object + ####################################################################### + + def info() + super(VN_POOL_METHODS[:info],@user_id) + end + end +end diff --git a/src/client/ruby/lib/OpenNebula/XMLUtils.rb b/src/client/ruby/lib/OpenNebula/XMLUtils.rb new file mode 100644 index 0000000..67681aa --- /dev/null +++ b/src/client/ruby/lib/OpenNebula/XMLUtils.rb @@ -0,0 +1,144 @@ + +module OpenNebula + + begin + require 'nokogiri' + NOKOGIRI=true + rescue LoadError + NOKOGIRI=false + end + + ########################################################################### + # The XMLUtilsElement module provides an abstraction of the underlying + # XML parser engine. It provides XML-related methods for the Pool Elements + ########################################################################### + module XMLUtilsElement + # Initialize a XML document for the element + # xml:: _String_ the XML document of the object + # root_element:: _String_ Base xml element + # [return] _XML_ object for the underlying XML engine + def self.initialize_xml(xml, root_element) + if NOKOGIRI + Nokogiri::XML(xml).xpath("/#{root_element}") + else + REXML::Document.new(xml).root + end + end + + # Extract an element from the XML description of the PoolElement. + # key::_String_ The name of the element + # [return] _String_ the value of the element + # Examples: + # ['VID'] # gets VM id + # ['HISTORY/HOSTNAME'] # get the hostname from the history + def [](key) + if NOKOGIRI + element=@xml.xpath(key.to_s.upcase) + else + element=@xml.elements[key.to_s.upcase] + end + + if element + element.text + end + end + + def template_str(indent=true) + template_like_str('TEMPLATE', indent) + end + + def template_like_str(root_element, indent=true) + if NOKOGIRI + xml_template=@xml.xpath(root_element).to_s + rexml=REXML::Document.new(xml_template).root + else + rexml=@xml.elements[root_element] + end + + if indent + ind_enter="\n" + ind_tab=' ' + else + ind_enter='' + ind_tab=' ' + end + + str=rexml.collect {|n| + if n.class==REXML::Element + str_line="" + if n.has_elements? + str_line << n.name << "=[" << ind_enter + + str_line << n.collect {|n2| + if n2.class==REXML::Element + ind_tab+n2.name+"="+n2.text + end + }.compact.join(","+ind_enter) + str_line<<" ]" + else + str_line< "HID", :desc => "ONE identifier for host", :size => 4, - :proc => lambda {|d,e| d["oid"] } + :proc => lambda {|d,e| d.id } }, :name => { :name => "NAME", :desc => "Hostname", :size => 25, :left => true, - :proc => lambda {|d,e| d["host_name"] } + :proc => lambda {|d,e| d.name } }, :rvm => { :name => "RVM", :desc => "Number of virtual machines running", :size => 3, - :proc => lambda {|d,e| d["hs_running_vms"] } + :proc => lambda {|d,e| d["HOST_SHARE/RUNNING_VMS"] } }, :tcpu => { :name => "TCPU", :desc => "Total cpu percentage", :size => 6, - :proc => lambda {|d,e| d["TOTALCPU"] } + :proc => lambda {|d,e| d["HOST_SHARE/MAX_CPU"] } }, :fcpu => { :name => "FCPU", :desc => "Free cpu percentage", :size => 6, - :proc => lambda {|d,e| d["TOTALCPU"].to_i-d["USEDCPU"].to_i } + :proc => lambda {|d,e| d["HOST_SHARE/MAX_CPU"].to_i-d["HOST_SHARE/USED_CPU"].to_i } }, :acpu => { :name => "ACPU", :desc => "Available cpu percentage (not reserved by VMs)", :size => 6, :proc => lambda {|d,e| - max_cpu=d["hs_max_cpu"].to_i + max_cpu=d["HOST_SHARE/MAX_CPU"].to_i max_cpu=100 if max_cpu==0 - max_cpu-d["hs_cpu_usage"].to_i + max_cpu-d["HOST_SHARE/USED_CPU"].to_i } }, :tmem => { :name => "TMEM", :desc => "Total memory", :size => 7, - :proc => lambda {|d,e| d["TOTALMEMORY"] } + :proc => lambda {|d,e| d["HOST_SHARE/MAX_MEM"] } }, :fmem => { :name => "FMEM", :desc => "Free memory", :size => 7, - :proc => lambda {|d,e| d["FREEMEMORY"] } + :proc => lambda {|d,e| d["HOST_SHARE/FREE_MEM"] } }, :stat => { :name => "STAT", :desc => "Host status", :size => 4, - :proc => lambda {|d,e| e[:host].get_state(d) } + :proc => lambda {|d,e| + d.short_state_str() + } }, @@ -97,9 +101,9 @@ ShowTableHost={ } class HostShow - def initialize(host) - @host=host - @table=ShowTable.new(ShowTableHost, :host => @host) + def initialize(client) + @hostpool=OpenNebula::HostPool.new(client) + @table=ShowTable.new(ShowTableHost) end def close @@ -114,41 +118,22 @@ class HostShow end def list_short(options=nil) - res=@host.get + res=@hostpool.info if options @table.columns=options[:columns] if options[:columns] end - if res[0] + if OpenNebula.is_error?(res) result=res + else + result=[true,""] header_host_small - res[1].each {|row| - res2=@host.get_host_attributes(row["oid"]) - if res2[0] - attributes=res2[1] - attributes.each {|a| - if %w{USEDCPU TOTALMEMORY FREEMEMORY TOTALCPU}.include? a["name"] - row[a["name"]]=a["value"] - end - } - end - - res2=@host.get_host_share(row["oid"]) - if res2[0] - attributes=res2[1] - attributes.each {|a| - row["hs_running_vms"]=a["running_vms"] - row["hs_max_mem"]=a["max_mem"] - row["hs_max_cpu"]=a["max_cpu"] - row["hs_mem_usage"]=a["mem_usage"] - row["hs_cpu_usage"]=a["cpu_usage"] - } - end - } - puts @table.data_str(result[1], options) + if options + puts @table.data_str(@hostpool, options) + else + puts @table.data_str(@hostpool) + end result - else - result=res end end @@ -214,28 +199,20 @@ EOT end -server=ONE::Server.new -$host=host=ONE::Host.new(server) -#$vm=vm=ONE::VM.new(server) - -def command_exit(code) - $host.close_db - exit(code) -end - # Returns true if there are non DONE VM's in a host, false otherwise -def vms_in_host?(host) - sql_statement="select history.vid,history.hid,history.seq,vm_pool.state"+ - " from history,vm_pool where vm_pool.oid=history.vid and"+ - " vm_pool.state<>6 and history.hid=#{host} group by vid" +def vms_in_host?(host_id) - result=$host.get_db.db.execute(sql_statement) + host = OpenNebula::Host.new_with_id(host_id,get_one_client) - if result.length>0 - true - else - false + rc = host.info + + if OpenNebula::is_error?(rc) + puts rc.message + exit -1 end + + host['host_shares/running_vms'].to_i + end @@ -250,76 +227,135 @@ command=ARGV.shift case command when "add", "create" check_parameters("create", 4) - result=host.allocate(*[ARGV[0], ARGV[1], ARGV[2], ARGV[3], "true"]) + host=OpenNebula::Host.new(OpenNebula::Host.build_xml, get_one_client) + result=host.allocate(ARGV[0], ARGV[1], ARGV[2], ARGV[3]) + + if is_successful?(result) + puts "ID: " + host.id.to_s if ops[:verbose] + exit 0 + end when "show" check_parameters("show", 1) - host_id=get_host_id(host, ARGV[0]) - result=host.info(host_id) - if result[0] - puts result[1] + host_id=get_host_id(ARGV[0]) + + host=OpenNebula::Host.new_with_id(host_id, get_one_client) + + result=host.info + if is_successful?(result) + #puts host.template_str else - puts "Error: "+result[1] - command_exit -1 + puts "Error: "+result.message + exit -1 end + if !ops[:xml] + str = "%-22s: %-20s" + str_h1 = "%-80s" + + print_header(str_h1, "HOST #{host_id} INFORMATION", true) + + puts str % ["ID", host[:id]] + puts str % ["NAME", host[:name]] + puts str % ["STATE", host.state_str] + puts str % ["IM_MAD", host[:im_mad]] + puts str % ["VM_MAD", host[:vm_mad]] + puts str % ["TM_MAD", host[:tm_mad]] + puts + + print_header(str_h1, "HOST SHARES", false) + + puts str % ["MAX MEM", host['host_share/max_mem']] + puts str % ["USED MEM (REAL)", host['host_share/used_mem']] + puts str % ["USED MEM (ALLOCATED)", host['host_share/mem_usage']] + puts str % ["MAX CPU", host['host_share/max_cpu']] + puts str % ["USED CPU (REAL)", host['host_share/used_cpu']] + puts str % ["USED CPU (ALLOCATED)", host['host_share/cpu_usage']] + puts str % ["RUNNING VMS", host['host_share/running_vms']] + puts + + print_header(str_h1, "MONITORING INFORMATION", false) + + puts host.template_str + else + puts host.to_xml + end + when "delete" check_parameters("delete", 1) - host_id=get_host_id(host, ARGV[0]) - if vms_in_host?(host_id) + host_id=get_host_id(ARGV[0]) + + host = OpenNebula::Host.new_with_id(host_id,get_one_client) + + rc = host.info + + if OpenNebula::is_error?(rc) + puts rc.message + exit -1 + end + + if host['host_shares/running_vms'].to_i != 0 puts "Host still has associated VMs. It will be disabled instead." - result=host.disable(host_id) - if result[0] + result=host.disable + if is_successful?(result) puts "Host disabled" if ops[:verbose] - command_exit 0 + exit 0 end else - result=host.delete(host_id) - if result[0] + result=host.delete + if is_successful?(result) puts "Host deleted" if ops[:verbose] - command_exit 0 + exit 0 end end when "list" - hostlist=HostShow.new(host) - ops[:columns]=ops[:list] if ops[:list] - result=hostlist.list_short(ops) - hostlist.close + if !ops[:xml] + hostlist=HostShow.new(get_one_client) + ops[:columns]=ops[:list] if ops[:list] + result=hostlist.list_short(ops) + hostlist.close + else + hostpool=OpenNebula::HostPool.new(get_one_client) + hostpool.info + puts hostpool.to_xml + end when "top" - hostlist=HostShow.new(host) + hostlist=HostShow.new(get_one_client) ops[:columns]=ops[:list] if ops[:list] result=hostlist.top(ops) hostlist.close when "enable" check_parameters("enable", 1) - host_id=get_host_id(host, ARGV[0]) - result=host.enable(host_id) - if result[0] + host_id=get_host_id(ARGV[0]) + host = OpenNebula::Host.new_with_id(host_id,get_one_client) + result=host.enable + if is_successful?(result) puts "Host enabled" if ops[:verbose] - command_exit 0 + exit 0 end when "disable" check_parameters("disable", 1) - host_id=get_host_id(host, ARGV[0]) - result=host.disable(host_id) - if result[0] + host_id=get_host_id(ARGV[0]) + host = OpenNebula::Host.new_with_id(host_id,get_one_client) + result=host.disable + if is_successful?(result) puts "Host disabled" if ops[:verbose] - command_exit 0 + exit 0 end else onehost_opts.print_help - command_exit -1 + exit -1 end -if !result[0] - puts "Error: " + result[1].to_s - command_exit -1 +if is_error?(result) + puts "Error: " + result.message + exit -1 end -command_exit 0 +exit 0 diff --git a/src/client/ruby/oneuser b/src/client/ruby/oneuser new file mode 100755 index 0000000..662f4a8 --- /dev/null +++ b/src/client/ruby/oneuser @@ -0,0 +1,203 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad # +# Complutense de Madrid (dsa-research.org) # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +ONE_LOCATION=ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" +end + +$: << RUBY_LIB_LOCATION + +$: << "./lib" + +#require 'one' +require 'OpenNebula' +require 'client_utilities' +require 'command_parse' + +ShowTableUP={ + :uid => { + :name => "UID", + :desc => "ONE identifier for user", + :size => 4, + :proc => lambda {|d,e| d.id } + }, + :name => { + :name => "NAME", + :desc => "name of the user", + :size => 15, + :left => true, + :proc => lambda {|d,e| d.name } + }, + :password => { + :name => "PASSWORD", + :desc => "password of the user", + :size => 50, + :left => true, + :proc => lambda {|d,e| d[:password] } + }, + :enable => { + :name => "ENABLE", + :desc => "Wether the user is active or not", + :size => 6, + :proc => lambda {|d,e| d[:enabled] } + }, + + :default => [:uid, :name, :password, :enable] +} + +class UPShow + def initialize + @userpool=OpenNebula::UserPool.new(get_one_client) + @table=ShowTable.new(ShowTableUP) + end + + def close + end + + def header_up_small + scr_bold + scr_underline + print @table.header_str + scr_restore + puts "" + end + + def list_short(options=nil) + res=@userpool.info + if options + @table.columns=options[:columns] if options[:columns] + end + + if OpenNebula.is_error?(res) + result=res + else + result=res + header_up_small + + puts @table.data_str(@userpool, options) + result + end + end + + def top(options=nil) + delay=1 + delay=options[:delay] if options && options[:delay] + + result=nil + + begin + while true + scr_cls + scr_move(0,0) + result=list_short(options) + sleep delay + end + rescue Exception + end + result + end +end + +class OneUPParse < CommandParse + + COMMANDS_HELP=<<-EOT +Commands: + +* create (Creates a new user) + oneuser create username password + +* delete (Removes a user) + oneuser delete + +* list (Lists virtual networks in the pool) + oneuser list + +EOT + + def text_commands + COMMANDS_HELP + end + + def text_command_name + "oneuser" + end + + def list_options + table=ShowTable.new(ShowTableUP) + table.print_help + end + +end + +oneup_opts=OneUPParse.new +oneup_opts.parse(ARGV) +ops=oneup_opts.options + +result=[false, "Unknown error"] + +command=ARGV.shift + +case command +when "create" + check_parameters("create", 2) + user=OpenNebula::User.new( + OpenNebula::User.build_xml, get_one_client) + sha_password = Digest::SHA1.hexdigest(ARGV[1]) + result=user.allocate(ARGV[0],sha_password) + if !OpenNebula.is_error?(result) + puts "UID: " + user.id.to_s if ops[:verbose] + exit 0 + end + +when "delete" + check_parameters("delete", 1) + user_id=get_user_id(ARGV[0]) + user=OpenNebula::User.new( + OpenNebula::User.build_xml(user_id), get_one_client) + result=user.delete + if !OpenNebula.is_error?(result) + puts "User deleted" if ops[:verbose] + exit 0 + end + +when "list" + if !ops[:xml] + uplist=UPShow.new + ops[:columns]=ops[:list] if ops[:list] + result=uplist.list_short(ops) + uplist.close + else + userpool=OpenNebula::UserPool.new(get_one_client) + userpool.info + puts userpool.to_xml + end + +else + oneup_opts.print_help + exit -1 +end + +if OpenNebula.is_error?(result) + puts "Error: " + result.message + exit -1 +end diff --git a/src/client/ruby/onevm b/src/client/ruby/onevm index 810dd0b..abe5ad0 100755 --- a/src/client/ruby/onevm +++ b/src/client/ruby/onevm @@ -25,40 +25,56 @@ else RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" end +$: << './lib' $: << RUBY_LIB_LOCATION -require 'one' + +#require 'one' +require 'OpenNebula' + require 'client_utilities' require 'command_parse' +require 'profiler' + ShowTableVM={ :id => { :name => "ID", :desc => "ONE identifier for the VM", :size => 4, - :proc => lambda {|d,e| d["oid"] } + :proc => lambda {|d,e| d.id } }, :name => { :name => "NAME", :desc => "Name of the domain", :size => 8, :proc => lambda {|d,e| - tid=d["template_id"] - template=e[:vm].get_template(tid) - template["NAME"] + d.name + } + }, + :username => { + :name => "USER", + :desc => "Name of the owner", + :size => 8, + :proc => lambda {|d,e| + d["USERNAME"] } }, :stat => { :name => "STAT", :desc => "Actual status of the VM", :size => 4, - :proc => lambda {|d,e| e[:vm].get_state(d) } + :proc => lambda {|d,e| + d.status + } }, :cpu => { :name => "CPU", :desc => "CPU percentage used by the VM", :size => 3, - :proc => lambda {|d,e| d["cpu"] } + :proc => lambda {|d,e| + d["cpu"] + } }, :mem => { :name => "MEM", @@ -70,16 +86,18 @@ ShowTableVM={ :name => "HOSTNAME", :desc => "Machine where the VM is running", :size => 15, - :proc => lambda {|d,e| e[:vm].get_history_host(d["oid"]) } + :proc => lambda {|d,e| + d["HISTORY/HOSTNAME"] + } }, :time => { :name => "TIME", :desc => "Time since the VM was submitted", :size => 11, - :proc => lambda {|d,e| e[:vm].str_running_time(d) } + :proc => lambda {|d,e| str_running_time(d) } }, - :default => [:id, :name, :stat, :cpu, :mem, :hostname, :time] + :default => [:id, :username, :name, :stat, :cpu, :mem, :hostname, :time] } ShowTableHistory={ @@ -87,7 +105,7 @@ ShowTableHistory={ :name => "ID", :desc => "ONE identifier for the VM", :size => 4, - :proc => lambda {|d,e| d["oid"] } + :proc => lambda {|d,e| d["id"] } }, :seq => { :name => "SEQ", @@ -127,13 +145,17 @@ ShowTableHistory={ :name => "TIME", :desc => "Total time", :size => 11, - :proc => lambda {|d,e| e[:vm].str_running_time(d) } + :proc => lambda {|d,e| + d["time"] + } }, :reason => { :name => "REASON", :desc => "Reason for state change", :size => "6", - :proc => lambda {|d,e| e[:vm].get_reason(d) } + :proc => lambda {|d,e| + OpenNebula::VirtualMachine.get_reason(d["reason"]) + } }, :default => [:id, :seq, :hostname, :stime, :etime, :time, :reason] @@ -141,10 +163,10 @@ ShowTableHistory={ class VmShow - def initialize(vm) - @vm=vm - @table=ShowTable.new(ShowTableVM, :vm => @vm) - @table_history=ShowTable.new(ShowTableHistory, :vm => @vm) + def initialize(client, filter_flag="-2") + @vmpool=OpenNebula::VirtualMachinePool.new(client, filter_flag.to_i) + @table=ShowTable.new(ShowTableVM) + @table_history=ShowTable.new(ShowTableHistory) end def close @@ -167,7 +189,9 @@ class VmShow end def print_vm_long(data) + str="%-10s: %-20s" + puts str % ["ID", data["oid"]] puts str % ["NAME", data["deploy_id"]] puts str % ["STATE", ONE::VM_STATE[data["state"].to_i]] @@ -175,7 +199,7 @@ class VmShow puts str % ["MEMORY", data["memory"]] puts str % ["CPU", data["cpu"]] puts - puts "Template" + str=" %-20s: %-20s" data.each {|key,value| puts str % [key, value] if !%w{oid deploy_id state lcm_state memory cpu template_id}.include? key @@ -183,42 +207,35 @@ class VmShow end def list_short(options=nil) - res=@vm.get_vms(:where => "state <> 6") + res=@vmpool.info() + if options @table.columns=options[:columns] if options[:columns] end - if res[0] + if OpenNebula.is_error?(res) + result=res + puts res.message + exit -1 + else + + if options[:filter_flag] + vms=@vmpool.select{|element| + element['USERNAME']==options[:filter_flag] } + else + vms=@vmpool + end + result=[true, ""] header_vm_small - + if options - puts @table.data_str(res[1], options) + puts @table.data_str(vms, options) else - puts @table.data_str(res[1]) + puts @table.data_str(vms) end result - else - result=res - end - end - - def list_long(id) - res=@vm.get(:where => "oid="+id) - - if res && res[0] && res[1] && res[1].length>0 - result=[true, ""] - res[1].each {|row| - print_vm_long(row) - } - result - else - if res[0] - [false, "VM not found"] - else - result=res - end end end @@ -239,47 +256,71 @@ class VmShow end result end + + def get_vm_history(vm) + { + 'id' => vm.id, + 'seq' => vm['history/seq'], + 'host_name' => vm['history/hostname'], + 'stime' => vm['history/stime'], + 'etime' => vm['history/etime'], + 'time' => str_running_time(vm), + 'reason' => vm['history/reason'] + } + end + + def get_vms_history(vms) + vms.collect do |vmid| + vm=OpenNebula::VirtualMachine.new_with_id(vmid, get_one_client) + result=vm.info + + if is_error?(result) + puts "Error: "+result.message + exit -1 + end + + get_vm_history(vm) + end + end - def list_vm_history(id, options=nil) - res=@vm.get_history(id) + def list_vm_history(vm, options=nil) + #res=@vm.get_history(id) if options @table_history.columns=options[:columns] if options[:columns] end - if res[0] - result=[true, ""] - header_history_small - - if options - puts @table_history.data_str(res[1], options) - else - puts @table_history.data_str(res[1]) - end - - result + header_history_small + + if options + puts @table_history.data_str([vm], options) else - result=res + puts @table_history.data_str([vm]) end end def list_vm_history_array(ids, options=nil) - res=[false, "No VMs found"] - ids.each {|id| - vm_id=get_vm_id(@vm, id) - puts "History for VM #{id}" + get_vms_history(ids).each {|vm| + puts "History for VM #{vm['id']}" puts - res=list_vm_history(vm_id, options) + list_vm_history(vm, options) puts } - res end def list_vm_history_all(options=nil) - res=@vm.get - res[1].each {|vm| - list_vm_history_array(vm["oid"], options) + result=@vmpool.info + + if is_error?(result) + puts "Error: "+result.message + exit -1 + end + + @vmpool.each {|vm| + puts "History for VM #{vm.id}" + puts + list_vm_history(get_vm_history(vm), options) + puts } - res end end @@ -331,8 +372,16 @@ Commands: * delete (Deletes a VM from the pool and DB) onevm delete +* restart (...) + onevm restart + * list (Shows VMs in the pool) - onevm list + onevm list + where filter_flag can be + a, all --> all the known VMs + m, mine --> the VMs belonging to the user in ONE_AUTH + uid --> VMs of the user identified by this uid + username --> VMs of the user identified by the username * show (Gets information about a specific VM) onevm show @@ -362,17 +411,6 @@ EOT end - -server=ONE::Server.new -$vm=vm=ONE::VM.new(server) -host=ONE::Host.new(server) - -def command_exit(code) - $vm.close_db - exit(code) -end - - onevm_opts=OnevmParse.new onevm_opts.parse(ARGV) ops=onevm_opts.options @@ -384,117 +422,195 @@ command=ARGV.shift case command when "submit", "create" check_parameters("create", 1) - result=vm.allocate(*ARGV) - if result[0] - puts "ID: " + result[1].to_s if ops[:verbose] - command_exit 0 + vm=OpenNebula::VirtualMachine.new( + OpenNebula::VirtualMachine.build_xml, get_one_client) + begin + template=File.read(ARGV[0]) + result=vm.allocate(template) + rescue + result=OpenNebula::Error.new("Can not read template: #{ARGV[0]}") + end + if is_successful?(result) + puts "ID: " + vm.id.to_s if ops[:verbose] + exit 0 end when "deploy" check_parameters("deploy", 2) - vm_id=get_vm_id(vm, ARGV[0]) - host_id=get_host_id(host, ARGV[1]) - result=vm.deploy(vm_id, host_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + host_id=get_host_id(ARGV[1]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.deploy(host_id) + if is_successful?(result) puts "Deploying VM" if ops[:verbose] - command_exit 0 + exit 0 end when "shutdown" check_parameters("shutdown", 1) - vm_id=get_vm_id(vm, ARGV[0]) - result=vm.shutdown(vm_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + result=vm.shutdown + if is_successful?(result) puts "Shutting down VM" if ops[:verbose] - command_exit 0 + exit 0 end when "livemigrate" check_parameters("livemigrate", 2) - vm_id=get_vm_id(vm, ARGV[0]) - host_id=get_host_id(host, ARGV[1]) - result=vm.livemigrate(vm_id, host_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + host_id=get_host_id(ARGV[1]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.live_migrate(host_id) + if is_successful?(result) puts "Migrating VM" if ops[:verbose] - command_exit 0 + exit 0 end when "migrate" check_parameters("migrate", 2) - vm_id=get_vm_id(vm, ARGV[0]) - host_id=get_host_id(host, ARGV[1]) - result=vm.migrate(vm_id, host_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + host_id=get_host_id(ARGV[1]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.migrate(host_id) + if is_successful?(result) puts "Migrating VM" if ops[:verbose] - command_exit 0 + exit 0 end when "hold" check_parameters("hold", 1) - vm_id=get_vm_id(vm, ARGV[0]) - result=vm.hold(vm_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.hold + if is_successful?(result) puts "Setting VM to hold state" if ops[:verbose] - command_exit 0 + exit 0 end when "release" check_parameters("release", 1) - vm_id=get_vm_id(vm, ARGV[0]) - result=vm.release(vm_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.release + if is_successful?(result) puts "Releasing VM" if ops[:verbose] - command_exit 0 + exit 0 end when "stop" check_parameters("stop", 1) - vm_id=get_vm_id(vm, ARGV[0]) - result=vm.stop(vm_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.stop + if is_successful?(result) puts "Stopping VM" if ops[:verbose] - command_exit 0 + exit 0 end when "cancel" check_parameters("cancel", 1) - result=vm.cancel(*ARGV) - if result[0] + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.cancel + if is_successful?(result) puts "Cancelling VM" if ops[:verbose] - command_exit 0 + exit 0 end when "suspend" check_parameters("suspend", 1) - vm_id=get_vm_id(vm, ARGV[0]) - result=vm.suspend(vm_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.suspend + if is_successful?(result) puts "Suspending VM" if ops[:verbose] - command_exit 0 + exit 0 end when "resume" check_parameters("resume", 1) - vm_id=get_vm_id(vm, ARGV[0]) - result=vm.resume(vm_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.resume + if is_successful?(result) puts "Resuming VM" if ops[:verbose] - command_exit 0 + exit 0 end - + +when "restart" + check_parameters("restart") + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.restart + if is_successful?(result) + puts "Restarting VM" if ops[:verbose] + exit 0 + end + when "list" - vmlist=VmShow.new(vm) - ops[:columns]=ops[:list] if ops[:list] - result=vmlist.list_short(ops) - vmlist.close + + if ARGV[0] + case ARGV[0] + when "a", "all" + filter_flag="-2" + when "m", "mine" + filter_flag="-1" + else + if !ARGV[0].match(/^[0123456789]+$/) + filter_flag="-2" + ops[:filter_flag]=ARGV[0] + + else + filter_flag=ARGV[0] + end + end + else + filter_flag="-2" + end + + if !ops[:xml] + vmlist=VmShow.new(get_one_client, filter_flag) + + ops[:columns]=ops[:list] if ops[:list] + result=vmlist.list_short(ops) + vmlist.close + else + vmpool=OpenNebula::VirtualMachinePool.new(get_one_client, + filter_flag.to_i) + vmpool.info + puts vmpool.to_xml + end when "top" - vmlist=VmShow.new(vm) + vmlist=VmShow.new(get_one_client) ops[:columns]=ops[:list] if ops[:list] result=vmlist.top(ops) vmlist.close when "show_db" + # TODO: delete? check_parameters("show", 1) vmlist=VmShow.new(vm) @@ -508,10 +624,11 @@ when "show_db" end when "history" - vmlist=VmShow.new(vm) + # TODO: change this to new API + vmlist=VmShow.new(get_one_client) ops[:columns]=ops[:list] if ops[:list] if ARGV[0] - ids=ARGV.collect {|arg| get_vm_id(vm, arg)} + ids=ARGV.collect {|arg| get_vm_id(arg)} ids=ids.flatten.compact result=vmlist.list_vm_history_array(ids) else @@ -521,16 +638,65 @@ when "history" when "delete" check_parameters("delete", 1) - vm_id=get_vm_id(vm, ARGV[0]) - result=vm.delete(vm_id) - if result[0] + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + + result=vm.finalize + if is_successful?(result) puts "VM correctly deleted" if ops[:verbose] - command_exit 0 + exit 0 end when "show" - check_parameters("get_info", 1) - vm_id=get_vm_id(vm, ARGV[0]) + # TODO: change this to the new API + check_parameters("get_info", 1) + vm_id=get_vm_id(ARGV[0]) + + vm=OpenNebula::VirtualMachine.new_with_id(vm_id, get_one_client) + vm.info + + if !ops[:xml] + str="%-15s: %-20s" + str_h1="%-80s" + + print_header(str_h1, "VIRTUAL MACHINE #{vm[:id]} INFORMATION", true) + + puts str % ["ID", vm[:id]] + puts str % ["NAME", vm[:name]] + puts str % ["STATE", vm.state_str] + puts str % ["LCM_STATE", vm.lcm_state_str] + + value=vm[:stime].to_i + if value==0 + value='-' + else + value=Time.at(value).strftime("%m/%d %H:%M:%S") + end + puts str % ["START TIME", value] + + value=vm[:etime].to_i + if value==0 + value='-' + else + value=Time.at(value).strftime("%m/%d %H:%M:%S") + end + puts str % ["END TIME", value] + + value=vm[:deploy_id] + puts str % ["DEPLOY ID:", value=="" ? "-" : value] + + puts + + print_header(str_h1,"VIRTUAL MACHINE TEMPLATE",false) + + puts vm.template_str + else + puts vm.to_xml + end + + +=begin result = res = vm.get_info(vm_id) if res[0] res[1].gsub!(/^\n/, '') @@ -564,18 +730,21 @@ when "show" command_exit 0 end - +=end + else onevm_opts.print_help - command_exit -1 + exit -1 end -if !result[0] - puts "Error: " + result[1].to_s - command_exit -1 +if OpenNebula.is_error?(result) + puts "Error: " + result.message + exit -1 end -command_exit 0 + + +#command_exit 0 diff --git a/src/client/ruby/onevnet b/src/client/ruby/onevnet index 39d719c..3145c40 100755 --- a/src/client/ruby/onevnet +++ b/src/client/ruby/onevnet @@ -27,7 +27,10 @@ end $: << RUBY_LIB_LOCATION -require 'one' +$: << "./lib" + +#require 'one' +require 'OpenNebula' require 'client_utilities' require 'command_parse' @@ -36,14 +39,21 @@ ShowTableVN={ :name => "NID", :desc => "ONE identifier for virtual network", :size => 4, - :proc => lambda {|d,e| d["oid"] } + :proc => lambda {|d,e| d.id } }, :name => { :name => "NAME", :desc => "name of the virtual network", :size => 15, :left => true, - :proc => lambda {|d,e| d["name"] } + :proc => lambda {|d,e| d.name } + }, + :username => { + :name => "USER", + :desc => "Username of the virtual network owner", + :size => 8, + :left => true, + :proc => lambda {|d,e| d["USERNAME"] } }, :type => { :name => "TYPE", @@ -71,15 +81,20 @@ ShowTableVN={ :size => 6, :proc => lambda {|d,e| d["bridge"] } }, - + :totalleases => { + :name => "#LEASES", + :desc => "Number of this virtual network's given leases", + :size => 7, + :proc => lambda {|d,e| d["TOTAL_LEASES"] } + }, - :default => [:nid, :name, :type, :bridge] + :default => [:nid, :username, :name, :type, :bridge, :totalleases] } class VNShow - def initialize(vn) - @vn=vn - @table=ShowTable.new(ShowTableVN, :vn => @vn) + def initialize(filter_flag="-2") + @vnpool=OpenNebula::VirtualNetworkPool.new(get_one_client,filter_flag.to_i) + @table=ShowTable.new(ShowTableVN) end def close @@ -94,29 +109,25 @@ class VNShow end def list_short(options=nil) - res=@vn.get + res=@vnpool.info if options @table.columns=options[:columns] if options[:columns] end - if res[0] + if OpenNebula.is_error?(res) result=res - header_vn_small - res[1].each {|row| - res2=@vn.get_vn_attributes(row["oid"]) - if res2[0] - attributes=res2[1] - attributes.each {|a| - if %w{SIZE}.include? a["name"] - row[a["name"]]=a["value"] - end - } - end - } - puts @table.data_str(result[1], options) - result else result=res + header_vn_small + if options[:filter_flag] + vns=@vnpool.select{|element| + element["USERNAME"]==options[:filter_flag] + } + else + vns=@vnpool + end + puts @table.data_str(vns, options) + result end end @@ -156,8 +167,12 @@ Commands: onevnet delete * list (Lists virtual networks in the pool) - onevnet list - + onevnet list + where filter_flag can be + a, all --> all the known VNs + m, mine --> the VNs belonging to the user in ONE_AUTH + uid --> VNs of the user identified by this uid + username --> VNs of the user identified by the username EOT def text_commands @@ -175,9 +190,6 @@ EOT end -server=ONE::Server.new -vn=ONE::VN.new(server) - onevn_opts=OneVNParse.new onevn_opts.parse(ARGV) ops=onevn_opts.options @@ -189,44 +201,97 @@ command=ARGV.shift case command when "create" check_parameters("create", 1) - result=vn.allocate(*ARGV) - if result[0] - puts "NID: " + result[1].to_s if ops[:verbose] + vn=OpenNebula::VirtualNetwork.new( + OpenNebula::VirtualNetwork.build_xml, get_one_client) + template=File.read(ARGV[0]) + result=vn.allocate(template) + if !OpenNebula.is_error?(result) + puts "NID: " + vn.id.to_s if ops[:verbose] exit 0 end when "show" check_parameters("show", 1) - vn_id=get_vn_id(vn, ARGV[0]) - result=vn.info(vn_id) - if result[0] - puts result[1] + vn_id=get_vn_id(ARGV[0]) + vn=OpenNebula::VirtualNetwork.new_with_id(vn_id, get_one_client) + result=vn.info + if is_successful?(result) + if !ops[:xml] + str_h1="%-80s" + str="%-10s: %-20s" + print_header(str_h1, + "VIRTUAL NETWORK #{vn.id.to_s} INFORMATION",true) + + puts str % ["ID: ",vn.id.to_s] + puts str % ["UID: ",vn["UID"]] + puts + print_header(str_h1,"VIRTUAL NETWORK TEMPLATE",false) + + puts vn.template_str(false) + + leases_str = vn.template_like_str('/VNET/LEASES', false) + + if !leases_str.empty? + puts + print_header(str_h1,"LEASES INFORMATION",false) + puts leases_str + end + else + puts vn.to_xml + end else - puts "Error: "+result[1] + puts "Error: "+result.message exit -1 end when "delete" check_parameters("delete", 1) - vn_id=get_vn_id(vn, ARGV[0]) - result=vn.delete(vn_id) - if result[0] + vn_id=get_vn_id(ARGV[0]) + vn=OpenNebula::VirtualNetwork.new( + OpenNebula::VirtualNetwork.build_xml(vn_id), get_one_client) + result=vn.delete + if !OpenNebula.is_error?(result) puts "Virtual Network deleted" if ops[:verbose] exit 0 end when "list" - vnlist=VNShow.new(vn) - ops[:columns]=ops[:list] if ops[:list] - result=vnlist.list_short(ops) - vnlist.close + if ARGV[0] + case ARGV[0] + when "a", "all" + filter_flag="-2" + when "m", "mine" + filter_flag="-1" + else + if !ARGV[0].match(/^[0123456789]+$/) + filter_flag="-2" + ops[:filter_flag]=ARGV[0] + else + filter_flag=ARGV[0] + end + end + else + filter_flag="-2" + end + + if !ops[:xml] + vnlist=VNShow.new(filter_flag) + ops[:columns]=ops[:list] if ops[:list] + result=vnlist.list_short(ops) + vnlist.close + else + vnpool=OpenNebula::VirtualNetworkPool.new(get_one_client, + filter_flag.to_i) + vnpool.info + puts vnpool.to_xml + end else onevn_opts.print_help exit -1 end -if !result[0] - puts "Error: " + result[1].to_s +if OpenNebula.is_error?(result) + puts "Error: " + result.message exit -1 end diff --git a/src/dm/DispatchManagerActions.cc b/src/dm/DispatchManagerActions.cc index 81b9b45..2ea44cf 100644 --- a/src/dm/DispatchManagerActions.cc +++ b/src/dm/DispatchManagerActions.cc @@ -505,8 +505,7 @@ int DispatchManager::resume( /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int DispatchManager::finalize( - int vid) +int DispatchManager::restart(int vid) { VirtualMachine * vm; ostringstream oss; @@ -518,37 +517,93 @@ int DispatchManager::finalize( return -1; } - if (vm->get_state() != VirtualMachine::ACTIVE && - vm->get_state() != VirtualMachine::DONE ) + oss << "Restarting VM " << vid; + Nebula::log("DiM",Log::DEBUG,oss); + + if (vm->get_state() == VirtualMachine::ACTIVE && + (vm->get_lcm_state() == VirtualMachine::UNKNOWN || + vm->get_lcm_state() == VirtualMachine::BOOT)) + { + Nebula& nd = Nebula::instance(); + LifeCycleManager * lcm = nd.get_lcm(); + + lcm->trigger(LifeCycleManager::RESTART,vid); + } + else { - oss << "Finalizing VM " << vid; - Nebula::log("DiM",Log::DEBUG,oss); + goto error; + } - vm->set_state(VirtualMachine::LCM_INIT); + vm->unlock(); - vm->set_state(VirtualMachine::DONE); + return 0; - vm->set_exit_time(time(0)); +error: + oss.str(""); + oss << "Could not restart VM " << vid << ", wrong state."; + Nebula::log("DiM",Log::ERROR,oss); - vmpool->update(vm); + vm->unlock(); + + return -2; +} - vm->log("DiM", Log::INFO, "New VM state is DONE."); +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ - vm->release_network_leases(); +int DispatchManager::finalize( + int vid) +{ + VirtualMachine * vm; + ostringstream oss; + VirtualMachine::VmState state; - vmpool->remove(vm); + vm = vmpool->get(vid,true); - return 0; + if ( vm == 0 ) + { + return -1; } - oss.str(""); - oss << "Could not finalize VM " << vid << ", wrong state."; - Nebula::log("DiM",Log::ERROR,oss); + state = vm->get_state(); + + oss << "Finalizing VM " << vid; + Nebula::log("DiM",Log::DEBUG,oss); + + Nebula& nd = Nebula::instance(); + TransferManager * tm = nd.get_tm(); + LifeCycleManager * lcm = nd.get_lcm(); + + switch (state) + { + case VirtualMachine::SUSPENDED: + tm->trigger(TransferManager::EPILOG_DELETE,vid); + + case VirtualMachine::INIT: + case VirtualMachine::PENDING: + case VirtualMachine::HOLD: + case VirtualMachine::STOPPED: + vm->set_exit_time(time(0)); + + case VirtualMachine::FAILED: + vm->set_state(VirtualMachine::LCM_INIT); + vm->set_state(VirtualMachine::DONE); + vmpool->update(vm); + + vm->release_network_leases(); + + vm->log("DiM", Log::INFO, "New VM state is DONE."); + break; + + case VirtualMachine::ACTIVE: + lcm->trigger(LifeCycleManager::DELETE,vid); + break; + case VirtualMachine::DONE: + break; + } vm->unlock(); - return -2; + return 0; } -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ diff --git a/src/dm/DispatchManagerStates.cc b/src/dm/DispatchManagerStates.cc index 3c8b110..6cc76aa 100644 --- a/src/dm/DispatchManagerStates.cc +++ b/src/dm/DispatchManagerStates.cc @@ -41,21 +41,16 @@ void DispatchManager::suspend_success_action(int vid) } else { - goto error; + ostringstream oss; + + oss << "suspend_success action received but VM " << vid + << " not in ACTIVE state"; + Nebula::log("DiM",Log::ERROR,oss); } vm->unlock(); return; - -error: - ostringstream oss; - - oss << "suspend_success action received but VM " << vid - << " not in ACTIVE state"; - Nebula::log("DiM",Log::ERROR,oss); - - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -84,21 +79,16 @@ void DispatchManager::stop_success_action(int vid) } else { - goto error; + ostringstream oss; + + oss << "stop_success action received but VM " << vid + << " not in ACTIVE state"; + Nebula::log("DiM",Log::ERROR,oss); } vm->unlock(); return; - -error: - ostringstream oss; - - oss << "stop_success action received but VM " << vid - << " not in ACTIVE state"; - Nebula::log("DiM",Log::ERROR,oss); - - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -128,23 +118,18 @@ void DispatchManager::done_action(int vid) vm->log("DiM", Log::INFO, "New VM state is DONE"); vm->release_network_leases(); - - vmpool->remove(vm); } else { - goto error; - } - - return; - -error: - ostringstream oss; + ostringstream oss; - oss << "done action received but VM " << vid << " not in ACTIVE state"; - Nebula::log("DiM",Log::ERROR,oss); + oss << "done action received but VM " << vid << " not in ACTIVE state"; + Nebula::log("DiM",Log::ERROR,oss); + } vm->unlock(); + + return; } /* -------------------------------------------------------------------------- */ @@ -178,3 +163,4 @@ void DispatchManager::failed_action(int vid) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + diff --git a/src/host/Host.cc b/src/host/Host.cc index c8c4b4c..649893c 100644 --- a/src/host/Host.cc +++ b/src/host/Host.cc @@ -32,8 +32,7 @@ Host::Host( string _hostname, string _im_mad_name, string _vmm_mad_name, - string _tm_mad_name, - bool _managed): + string _tm_mad_name): PoolObjectSQL(id), hostname(_hostname), state(INIT), @@ -41,9 +40,8 @@ Host::Host( vmm_mad_name(_vmm_mad_name), tm_mad_name(_tm_mad_name), last_monitored(time(0)), - managed(_managed), - host_template(id), - host_share(id){}; + host_template(id) + {}; Host::~Host(){}; @@ -55,43 +53,39 @@ Host::~Host(){}; const char * Host::table = "host_pool"; const char * Host::db_names = "(oid,host_name,state,im_mad,vm_mad," - "tm_mad,last_mon_time,managed)"; + "tm_mad,last_mon_time)"; const char * Host::db_bootstrap = "CREATE TABLE host_pool (" "oid INTEGER PRIMARY KEY,host_name TEXT,state INTEGER," - "im_mad TEXT,vm_mad TEXT,tm_mad TEXT,last_mon_time INTEGER," - "managed INTEGER)"; + "im_mad TEXT,vm_mad TEXT,tm_mad TEXT,last_mon_time INTEGER)"; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int Host::unmarshall(int num, char **names, char ** values) { - if ((values[OID] == 0) || - (values[HOST_NAME] == 0) || - (values[STATE] == 0) || - (values[IM_MAD] == 0) || - (values[VM_MAD] == 0) || - (values[TM_MAD] == 0) || - (values[LAST_MON_TIME] == 0) || - (values[MANAGED] == 0) || - (num != LIMIT )) + if ((!values[OID]) || + (!values[HOST_NAME]) || + (!values[STATE]) || + (!values[IM_MAD]) || + (!values[VM_MAD]) || + (!values[TM_MAD]) || + (!values[LAST_MON_TIME]) || + (num != LIMIT )) { return -1; } - oid = atoi(values[OID]); - hostname = values[HOST_NAME]; - state = static_cast(atoi(values[STATE])); + oid = atoi(values[OID]); + hostname = values[HOST_NAME]; + state = static_cast(atoi(values[STATE])); - im_mad_name = values[IM_MAD]; - vmm_mad_name = values[VM_MAD]; - tm_mad_name = values[TM_MAD]; - - last_monitored = static_cast(atoi(values[LAST_MON_TIME])); - - managed = atoi(values[MANAGED]) == 1?true:false; + im_mad_name = values[IM_MAD]; + vmm_mad_name = values[VM_MAD]; + tm_mad_name = values[TM_MAD]; + last_monitored = static_cast(atoi(values[LAST_MON_TIME])); + host_template.id = oid; host_share.hsid = oid; @@ -154,8 +148,8 @@ int Host::select(SqliteDB *db) if ( rc != 0 ) { - return rc; - } + return rc; + } return 0; } @@ -201,14 +195,13 @@ int Host::update(SqliteDB *db) ostringstream oss; int rc; - int managed_i = managed?1:0; char * sql_hostname; char * sql_im_mad_name; char * sql_tm_mad_name; char * sql_vmm_mad_name; - //Update template. + // Update the Template rc = host_template.update(db); @@ -217,7 +210,7 @@ int Host::update(SqliteDB *db) return rc; } - // Let's get the HostShares before the host + // Update the HostShare rc = host_share.update(db); @@ -226,6 +219,8 @@ int Host::update(SqliteDB *db) return rc; } + // Update the Host + sql_hostname = sqlite3_mprintf("%q",hostname.c_str()); if ( sql_hostname == 0 ) @@ -253,17 +248,17 @@ int Host::update(SqliteDB *db) { goto error_vmm; } + // Construct the SQL statement to Insert or Replace (effectively, update) - oss << "INSERT OR REPLACE INTO " << table << " "<< db_names <<" VALUES ("<< - oid << "," << - "'" << sql_hostname << "'," << - state << "," << - "'" << sql_im_mad_name << "'," << - "'" << sql_vmm_mad_name << "'," << - "'" << sql_tm_mad_name << "'," << - last_monitored << "," << - managed_i << ")"; + oss << "INSERT OR REPLACE INTO " << table << " "<< db_names <<" VALUES (" + << oid << "," + << "'" << sql_hostname << "'," + << state << "," + << "'" << sql_im_mad_name << "'," + << "'" << sql_vmm_mad_name << "'," + << "'" << sql_tm_mad_name << "'," + << last_monitored << ")"; rc = db->exec(oss); @@ -287,11 +282,87 @@ int Host::update(SqliteDB *db) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +int Host::unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values) +{ + if ((!values[OID]) || + (!values[HOST_NAME]) || + (!values[STATE]) || + (!values[IM_MAD]) || + (!values[VM_MAD]) || + (!values[TM_MAD]) || + (!values[LAST_MON_TIME]) || + (num != LIMIT + HostShare::LIMIT )) + { + return -1; + } + + oss << + "" << + "" << values[OID] <<"" << + "" << values[HOST_NAME] <<"" << + "" << values[STATE] <<"" << + "" << values[IM_MAD] <<"" << + "" << values[VM_MAD] <<"" << + "" << values[TM_MAD] <<"" << + ""<< values[LAST_MON_TIME]<<""; + + HostShare::unmarshall(oss,num - LIMIT, names + LIMIT, values + LIMIT); + + oss << ""; + + return 0; + +} + +/* -------------------------------------------------------------------------- */ + +extern "C" int host_dump_cb ( + void * _oss, + int num, + char ** values, + char ** names) +{ + ostringstream * oss; + + oss = static_cast(_oss); + + if (oss == 0) + { + return -1; + } + + return Host::unmarshall(*oss,num,names,values); +}; + +/* -------------------------------------------------------------------------- */ + +int Host::dump(SqliteDB * db, ostringstream& oss, const string& where) +{ + int rc; + ostringstream cmd; + + cmd << "SELECT * FROM " << Host::table << "," << HostShare::table + << " ON " << Host::table << ".oid = " << HostShare::table << ".hid"; + + if ( !where.empty() ) + { + cmd << " WHERE " << where; + } + + rc = db->exec(cmd,host_dump_cb,(void *) &oss); + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + int Host::drop(SqliteDB * db) { ostringstream oss; - - map::iterator iter; // First, drop the template host_template.drop(db); @@ -312,23 +383,26 @@ int Host::update_info(string &parse_str) { char * error_msg; int rc; - - // If we have a default rc = host_template.parse(parse_str, &error_msg); if ( rc != 0 ) { - /* - Nebula::log("ONE", Log::ERROR, error_msg); - */ + //Nebula::log("ONE", Log::ERROR, error_msg); + free(error_msg); return -1; } get_template_attribute("TOTALCPU",host_share.max_cpu); get_template_attribute("TOTALMEMORY",host_share.max_mem); - + + get_template_attribute("FREECPU",host_share.free_cpu); + get_template_attribute("FREEMEMORY",host_share.free_mem); + + get_template_attribute("USEDCPU",host_share.used_cpu); + get_template_attribute("USEDMEMORY",host_share.used_mem); + return 0; } @@ -338,18 +412,68 @@ int Host::update_info(string &parse_str) ostream& operator<<(ostream& os, Host& host) { - os << "HID = " << host.oid << endl; - os << "HOSTNAME = " << host.hostname << endl; - os << "IM MAD = " << host.im_mad_name << endl; - os << "VMM MAD = " << host.vmm_mad_name << endl; - os << "TM MAD = " << host.tm_mad_name << endl; - os << "MANAGED = " << host.managed << endl; - os << "ATTRIBUTES" << endl << host.host_template<< endl; - os << "HOST SHARES" << endl << host.host_share <" + "" << oid << "" << + "" << hostname << "" << + "" << state << "" << + "" << im_mad_name << "" << + "" << vmm_mad_name << "" << + "" << tm_mad_name << "" << + "" << last_monitored << "" << + host_share.to_xml(share_xml) << + host_template.to_xml(template_xml) << + ""; + + xml = oss.str(); + + return xml; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& Host::to_str(string& str) const +{ + string template_str; + string share_str; + + ostringstream os; + + os << + "ID = " << oid << endl << + "NAME = " << hostname << endl << + "STATE = " << state << endl << + "IM MAD = " << im_mad_name << endl << + "VMM MAD = " << vmm_mad_name << endl << + "TM MAD = " << tm_mad_name << endl << + "LAST_MON = " << last_monitored << endl << + "ATTRIBUTES" << endl << host_template.to_str(template_str) << endl << + "HOST SHARES" << endl << host_share.to_str(share_str) <" << + "" << values[HID] << "" << + ""<< values[DISK_USAGE] << ""<< + "" << values[MEM_USAGE] << "" << + "" << values[CPU_USAGE] << "" << + "" << values[MAX_DISK] << "" << + "" << values[MAX_MEMORY] << "" << + "" << values[MAX_CPU] << "" << + "" << values[FREE_DISK] << "" << + "" << values[FREE_MEMORY] << "" << + "" << values[FREE_CPU] << "" << + "" << values[USED_DISK] << "" << + "" << values[USED_MEMORY] << "" << + "" << values[USED_CPU] << "" << + ""<"<< + ""; + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + extern "C" int host_share_select_cb ( void * _hs, int num, @@ -143,7 +217,6 @@ int HostShare::insert(SqliteDB * db) { int rc; - //Insert the HostShare rc = update(db); if ( rc != 0 ) @@ -161,17 +234,14 @@ int HostShare::update(SqliteDB * db) { ostringstream oss; int rc; - - oss << "INSERT OR REPLACE INTO " << table << " "<< db_names <<" VALUES ("<< - hsid << "," << - "'" << endpoint << "'," << - disk_usage << "," << - mem_usage << "," << - cpu_usage << "," << - max_disk << "," << - max_mem << "," << - max_cpu << "," << - running_vms << ")"; + + oss << "INSERT OR REPLACE INTO " << table << " "<< db_names <<" VALUES (" + << hsid << "," + << disk_usage <<","<< mem_usage <<","<< cpu_usage<< "," + << max_disk <<","<< max_mem <<","<< max_cpu << "," + << free_disk <<","<< free_mem <<","<< free_cpu << "," + << used_disk <<","<< used_mem <<","<< used_cpu << "," + << running_vms<< ")"; rc = db->exec(oss); @@ -185,7 +255,6 @@ int HostShare::drop(SqliteDB * db) { ostringstream oss; - // Drop the HostShare itself oss << "DELETE FROM " << table << " WHERE hid=" << hsid; return db->exec(oss); @@ -197,18 +266,70 @@ int HostShare::drop(SqliteDB * db) ostream& operator<<(ostream& os, HostShare& hs) { - os << "\tHID = " << hs.hsid << endl; - os << "\tENDPOINT = " << hs.endpoint<< endl; - - os << "\tMAX_CPU = " << hs.max_cpu << endl; - os << "\tMAX_MEMORY = " << hs.max_mem << endl; - os << "\tMAX_DISK = " << hs.max_disk<< endl; + string str; - os << "\tCPU_USAGE = " << hs.cpu_usage << endl; - os << "\tMEMORY_USAGE = " << hs.mem_usage << endl; - os << "\tDISK_USAGE = " << hs.disk_usage<< endl; - - os << "\tRUNNING_VMS = " << hs.running_vms<< endl; + os << hs.to_xml(str); return os; }; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& HostShare::to_xml(string& xml) const +{ + string template_xml; + ostringstream oss; + + oss << "" + << "" << hsid << "" + << "" << disk_usage << "" + << "" << mem_usage << "" + << "" << cpu_usage << "" + << "" << max_disk << "" + << "" << max_mem << "" + << "" << max_cpu << "" + << "" << free_disk << "" + << "" << free_mem << "" + << "" << free_cpu << "" + << "" << used_disk << "" + << "" << used_mem << "" + << "" << used_cpu << "" + << ""<" + << ""; + + xml = oss.str(); + + return xml; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& HostShare::to_str(string& str) const +{ + string template_xml; + ostringstream oss; + + oss<< "\tHID = " << hsid + << "\tCPU_USAGE = " << cpu_usage << endl + << "\tMEMORY_USAGE = " << mem_usage << endl + << "\tDISK_USAGE = " << disk_usage<< endl + << "\tMAX_CPU = " << max_cpu << endl + << "\tMAX_MEMORY = " << max_mem << endl + << "\tMAX_DISK = " << max_disk<< endl + << "\tFREE_CPU = " << free_cpu << endl + << "\tFREE_MEMORY = " << free_mem << endl + << "\tFREE_DISK = " << free_disk<< endl + << "\tUSED_CPU = " << used_cpu << endl + << "\tUSED_MEMORY = " << used_mem << endl + << "\tUSED_DISK = " << used_disk<< endl + << "\tRUNNING_VMS = " << running_vms<< endl; + + str = oss.str(); + + return str; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/im_mad/ec2/one_im_ec2.rb b/src/im_mad/ec2/one_im_ec2.rb index 2f25bcb..4a9ceac 100755 --- a/src/im_mad/ec2/one_im_ec2.rb +++ b/src/im_mad/ec2/one_im_ec2.rb @@ -59,8 +59,8 @@ def initialize() totalmemory = smem + lmem + xlmem totalcpu = scpu + lcpu + xlcpu - @info = "TOTALMEMORY=#{totalmemory},TOTALCPU=#{totalcpu}," \ - "CPUSPEED=1000,FREEMEMORY=#{totalmemory},FREECPU=#{totalcpu}" + @info ="HYPERVISOR=ec2,TOTALMEMORY=#{totalmemory},TOTALCPU=#{totalcpu}," \ + "CPUSPEED=1000,FREEMEMORY=#{totalmemory},FREECPU=#{totalcpu}" end #--------------------------------------------------------------------------- diff --git a/src/im_mad/kvm/kvm.rb b/src/im_mad/kvm/kvm.rb index e800b06..19aa2c2 100755 --- a/src/im_mad/kvm/kvm.rb +++ b/src/im_mad/kvm/kvm.rb @@ -79,6 +79,8 @@ end } +puts "HYPERVISOR=kvm" + puts "TOTALCPU=#{$total_cpu}" puts "CPUSPEED=#{$cpu_speed}" diff --git a/src/im_mad/vmware/GetProperty.java b/src/im_mad/vmware/GetProperty.java index e6d4960..aa3a38c 100644 --- a/src/im_mad/vmware/GetProperty.java +++ b/src/im_mad/vmware/GetProperty.java @@ -281,4 +281,4 @@ protected void finalize() throws Throwable { cb.disConnect(); } -} \ No newline at end of file +} diff --git a/src/im_mad/vmware/OneImVmware.java b/src/im_mad/vmware/OneImVmware.java index b63d840..e6da877 100644 --- a/src/im_mad/vmware/OneImVmware.java +++ b/src/im_mad/vmware/OneImVmware.java @@ -113,7 +113,7 @@ else if (action.equals("FINALIZE")) GetProperty gP; boolean rf; - String response = ""; + String response = "HYPERVISOR=vmware"; try { @@ -122,12 +122,11 @@ else if (action.equals("FINALIZE")) for(int i=0;i> $MAD_LOG_PATH + exec nice -n $PRIORITY java -cp $ONE_LOCATION/lib/mads:$CLASSPATH -Ddatastore=$VMWARE_DATASTORE -Ddatacenter=$VMWARE_DATACENTER -Djavax.net.ssl.trustStore=$VMWARE_TRUSTORE -Xmx1024M $MAD_FILE $* 2>> $MAD_LOG_PATH else - exec nice -n $PRIORITY java -cp $ONE_LOCATION/lib/mads:$CLASSPATH -Djavax.net.ssl.trustStore=$VMWARE_TRUSTORE -Xmx1024M $MAD_FILE $* 2> /dev/null + exec nice -n $PRIORITY java -cp $ONE_LOCATION/lib/mads:$CLASSPATH -Ddatastore=$VMWARE_DATASTORE -Ddatacenter=$VMWARE_DATACENTER -Djavax.net.ssl.trustStore=$VMWARE_TRUSTORE -Xmx1024M $MAD_FILE $* 2> /dev/null fi diff --git a/src/im_mad/xen/xen.rb b/src/im_mad/xen/xen.rb index 9b7edc9..dcd3558 100755 --- a/src/im_mad/xen/xen.rb +++ b/src/im_mad/xen/xen.rb @@ -86,6 +86,7 @@ # WRITE INFO +puts "HYPERVISOR=xen" puts "TOTALCPU=" + cpu_info[:total].round.to_s puts "CPUSPEED=" + cpu_info[:speed] puts "TOTALMEMORY=" + memory_info[:total].to_s @@ -95,4 +96,3 @@ puts "FREECPU=" + (cpu_info[:total]-vm_info[:cpu]).round.to_s puts "NETTX=" + vm_info[:nettx].to_s puts "NETRX=" + vm_info[:netrx].to_s - diff --git a/src/lcm/LifeCycleActions.cc b/src/lcm/LifeCycleActions.cc index b5fec4d..a254088 100644 --- a/src/lcm/LifeCycleActions.cc +++ b/src/lcm/LifeCycleActions.cc @@ -78,16 +78,12 @@ void LifeCycleManager::deploy_action(int vid) } else { - goto error; + vm->log("LCM", Log::ERROR, "deploy_action, VM in a wrong state."); } vm->unlock(); return; - -error: - vm->log("LCM", Log::ERROR, "deploy_action, VM in a wrong state."); - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -126,16 +122,12 @@ void LifeCycleManager::suspend_action(int vid) } else { - goto error; + vm->log("LCM", Log::ERROR, "suspend_action, VM in a wrong state."); } vm->unlock(); return; - -error: - vm->log("LCM", Log::ERROR, "suspend_action, VM in a wrong state."); - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -174,16 +166,12 @@ void LifeCycleManager::stop_action(int vid) } else { - goto error; + vm->log("LCM", Log::ERROR, "stop_action, VM in a wrong state."); } vm->unlock(); return; - -error: - vm->log("LCM", Log::ERROR, "stop_action, VM in a wrong state."); - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -231,16 +219,12 @@ void LifeCycleManager::migrate_action(int vid) } else { - goto error; + vm->log("LCM", Log::ERROR, "migrate_action, VM in a wrong state."); } vm->unlock(); return; - -error: - vm->log("LCM", Log::ERROR, "migrate_action, VM in a wrong state."); - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -289,19 +273,12 @@ void LifeCycleManager::live_migrate_action(int vid) } else { - os << "VM not in a suitable state to migrate"; - vm->log("LCM", Log::ERROR, os); - - goto error; + vm->log("LCM", Log::ERROR, "live_migrate_action, VM in a wrong state."); } vm->unlock(); return; - -error: - vm->log("LCM", Log::ERROR, "live_migrate_action, VM in a wrong state."); - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -340,16 +317,12 @@ void LifeCycleManager::shutdown_action(int vid) } else { - goto error; + vm->log("LCM", Log::ERROR, "shutdown_action, VM in a wrong state."); } vm->unlock(); return; - -error: - vm->log("LCM", Log::ERROR, "shutdown_action, VM in a wrong state."); - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -404,16 +377,12 @@ void LifeCycleManager::restore_action(int vid) } else { - goto error; + vm->log("LCM", Log::ERROR, "restore_action, VM in a wrong state."); } vm->unlock(); return; - -error: - vm->log("LCM", Log::ERROR, "restore_action, VM in a wrong state."); - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -452,14 +421,203 @@ void LifeCycleManager::cancel_action(int vid) } else { - goto error; + vm->log("LCM", Log::ERROR, "cancel_action, VM in a wrong state."); + } + + vm->unlock(); + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void LifeCycleManager::restart_action(int vid) +{ + VirtualMachine * vm; + + vm = vmpool->get(vid,true); + + if ( vm == 0 ) + { + return; + } + + if (vm->get_state() == VirtualMachine::ACTIVE && + (vm->get_lcm_state() == VirtualMachine::UNKNOWN || + vm->get_lcm_state() == VirtualMachine::BOOT)) + { + Nebula& nd = Nebula::instance(); + VirtualMachineManager * vmm = nd.get_vmm(); + + //---------------------------------------------------- + // RE-START THE VM IN THE SAME HOST + //---------------------------------------------------- + + if (vm->get_lcm_state() == VirtualMachine::BOOT) + { + vm->log("LCM", Log::INFO, "Sending BOOT command to VM again"); + } + else + { + vm->set_state(VirtualMachine::BOOT); + + vmpool->update(vm); + + vm->log("LCM", Log::INFO, "New VM state is BOOT"); + } + + //---------------------------------------------------- + + vmm->trigger(VirtualMachineManager::DEPLOY,vid); + } + else + { + vm->log("LCM", Log::ERROR, "restart_action, VM in a wrong state."); } vm->unlock(); return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void LifeCycleManager::delete_action(int vid) +{ + VirtualMachine * vm; + + + vm = vmpool->get(vid,true); -error: - vm->log("LCM", Log::ERROR, "cancel_action, VM in a wrong state."); + if ( vm == 0 ) + { + return; + } + + VirtualMachine::LcmState state = vm->get_lcm_state(); + + if ((state == VirtualMachine::LCM_INIT) || + (state == VirtualMachine::DELETE) || + (state == VirtualMachine::FAILURE)) + { + vm->unlock(); + return; + } + + int cpu; + int mem; + int disk; + time_t the_time = time(0); + + Nebula& nd = Nebula::instance(); + + TransferManager * tm = nd.get_tm(); + DispatchManager * dm = nd.get_dm(); + VirtualMachineManager * vmm = nd.get_vmm(); + + vm->set_state(VirtualMachine::DELETE); + vmpool->update(vm); + + vm->set_etime(the_time); + vm->set_reason(History::USER); + + vm->get_requirements(cpu,mem,disk); + hpool->del_capacity(vm->get_hid(),cpu,mem,disk); + + switch (state) + { + case VirtualMachine::PROLOG: + case VirtualMachine::PROLOG_RESUME: + vm->set_prolog_etime(the_time); + vmpool->update_history(vm); + + tm->trigger(TransferManager::DRIVER_CANCEL,vid); + tm->trigger(TransferManager::EPILOG_DELETE,vid); + break; + case VirtualMachine::BOOT: + case VirtualMachine::RUNNING: + case VirtualMachine::UNKNOWN: + case VirtualMachine::SHUTDOWN: + case VirtualMachine::CANCEL: + vm->set_running_etime(the_time); + vmpool->update_history(vm); + + vmm->trigger(VirtualMachineManager::DRIVER_CANCEL,vid); + vmm->trigger(VirtualMachineManager::CANCEL,vid); + + tm->trigger(TransferManager::EPILOG_DELETE,vid); + break; + + case VirtualMachine::MIGRATE: + vm->set_running_etime(the_time); + vmpool->update_history(vm); + + vm->set_previous_etime(the_time); + vm->set_previous_running_etime(the_time); + vm->set_previous_reason(History::USER); + vmpool->update_previous_history(vm); + + hpool->del_capacity(vm->get_previous_hid(),cpu,mem,disk); + + vmm->trigger(VirtualMachineManager::DRIVER_CANCEL,vid); + + vmm->trigger(VirtualMachineManager::CANCEL,vid); + vmm->trigger(VirtualMachineManager::CANCEL_PREVIOUS,vid); + + tm->trigger(TransferManager::EPILOG_DELETE,vid); + break; + case VirtualMachine::SAVE_STOP: + case VirtualMachine::SAVE_SUSPEND: + vm->set_running_etime(the_time); + vmpool->update_history(vm); + + vmm->trigger(VirtualMachineManager::DRIVER_CANCEL,vid); + vmm->trigger(VirtualMachineManager::CANCEL,vid); + + tm->trigger(TransferManager::EPILOG_DELETE,vid); + break; + case VirtualMachine::SAVE_MIGRATE: + vm->set_running_etime(the_time); + vmpool->update_history(vm); + + vm->set_previous_etime(the_time); + vm->set_previous_running_etime(the_time); + vm->set_previous_reason(History::USER); + vmpool->update_previous_history(vm); + + hpool->del_capacity(vm->get_previous_hid(),cpu,mem,disk); + + vmm->trigger(VirtualMachineManager::DRIVER_CANCEL,vid); + vmm->trigger(VirtualMachineManager::CANCEL_PREVIOUS,vid); + + tm->trigger(TransferManager::EPILOG_DELETE_PREVIOUS,vid); + break; + case VirtualMachine::PROLOG_MIGRATE: + vm->set_prolog_etime(the_time); + vmpool->update_history(vm); + + tm->trigger(TransferManager::DRIVER_CANCEL,vid); + tm->trigger(TransferManager::EPILOG_DELETE,vid); + tm->trigger(TransferManager::EPILOG_DELETE_PREVIOUS,vid); + break; + case VirtualMachine::EPILOG_STOP: + case VirtualMachine::EPILOG: + vm->set_epilog_etime(the_time); + vmpool->update_history(vm); + + tm->trigger(TransferManager::DRIVER_CANCEL,vid); + tm->trigger(TransferManager::EPILOG_DELETE,vid); + break; + default: //FAILURE,LCM_INIT,DELETE + break; + } + + dm->trigger(DispatchManager::DONE,vid); + vm->unlock(); + + return; } + diff --git a/src/lcm/LifeCycleManager.cc b/src/lcm/LifeCycleManager.cc index 9a9a3cd..7200bfd 100644 --- a/src/lcm/LifeCycleManager.cc +++ b/src/lcm/LifeCycleManager.cc @@ -162,6 +162,14 @@ void LifeCycleManager::trigger(Actions action, int _vid) aname = "SHUTDOWN"; break; + case RESTART: + aname = "RESTART"; + break; + + case DELETE: + aname = "DELETE"; + break; + case FINALIZE: aname = ACTION_FINALIZE; break; @@ -283,6 +291,14 @@ void LifeCycleManager::do_action(const string &action, void * arg) { shutdown_action(vid); } + else if (action == "RESTART") + { + restart_action(vid); + } + else if (action == "DELETE") + { + delete_action(vid); + } else if (action == ACTION_FINALIZE) { Nebula::log("LCM",Log::INFO,"Stopping Life-cycle Manager..."); diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index aa75290..61dbfba 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -340,29 +340,11 @@ void LifeCycleManager::deploy_failure_action(int vid) } else if (vm->get_lcm_state() == VirtualMachine::BOOT) { - int cpu,mem,disk; - time_t the_time = time(0); - - Nebula& nd = Nebula::instance(); - DispatchManager * dm = nd.get_dm(); + time_t the_time = time(0); vm->set_running_etime(the_time); - - vm->set_etime(the_time); - - vm->set_reason(History::ERROR); - vmpool->update_history(vm); - - vm->get_requirements(cpu,mem,disk); - - hpool->del_capacity(vm->get_hid(),cpu,mem,disk); - - vm->log("LCM", Log::INFO, "Fail to boot VM."); - - //---------------------------------------------------- - - dm->trigger(DispatchManager::FAILED,vid); + failure_action(vm); } vm->unlock(); @@ -477,7 +459,10 @@ void LifeCycleManager::prolog_success_action(int vid) } else { - goto error; + vm->log("LCM",Log::ERROR,"prolog_success_action, VM in a wrong state"); + vm->unlock(); + + return; } //---------------------------------------------------- @@ -503,10 +488,6 @@ void LifeCycleManager::prolog_success_action(int vid) vm->unlock(); return; - -error: - vm->log("LCM",Log::ERROR,"prolog_success_action, VM in a wrong state"); - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -515,12 +496,8 @@ void LifeCycleManager::prolog_success_action(int vid) void LifeCycleManager::prolog_failure_action(int vid) { VirtualMachine * vm; - time_t the_time = time(0); - int cpu,mem,disk; - - Nebula& nd = Nebula::instance(); - DispatchManager * dm = nd.get_dm(); - + time_t the_time = time(0); + vm = vmpool->get(vid,true); if ( vm == 0 ) @@ -529,21 +506,9 @@ void LifeCycleManager::prolog_failure_action(int vid) } vm->set_prolog_etime(the_time); - - vm->set_etime(the_time); - - vm->set_reason(History::ERROR); - - vmpool->update_history(vm); - - vm->get_requirements(cpu,mem,disk); - - hpool->del_capacity(vm->get_hid(),cpu,mem,disk); - //---------------------------------------------------- + failure_action(vm); - dm->trigger(DispatchManager::FAILED,vid); - vm->unlock(); return; @@ -580,7 +545,10 @@ void LifeCycleManager::epilog_success_action(int vid) } else { - goto error; + vm->log("LCM",Log::ERROR,"epilog_success_action, VM in a wrong state"); + vm->unlock(); + + return; } vm->set_epilog_etime(the_time); @@ -600,10 +568,6 @@ void LifeCycleManager::epilog_success_action(int vid) vm->unlock(); return; - -error: - vm->log("LCM",Log::ERROR,"epilog_success_action, VM in a wrong state"); - vm->unlock(); } /* -------------------------------------------------------------------------- */ @@ -611,12 +575,8 @@ void LifeCycleManager::epilog_success_action(int vid) void LifeCycleManager::epilog_failure_action(int vid) { - Nebula& nd = Nebula::instance(); - DispatchManager * dm = nd.get_dm(); - - VirtualMachine * vm; - time_t the_time = time(0); - int cpu,mem,disk; + VirtualMachine * vm; + time_t the_time = time(0); vm = vmpool->get(vid,true); @@ -627,20 +587,8 @@ void LifeCycleManager::epilog_failure_action(int vid) vm->set_epilog_etime(the_time); - vm->set_etime(the_time); - - vm->set_reason(History::ERROR); - - vmpool->update_history(vm); - - vm->get_requirements(cpu,mem,disk); - - hpool->del_capacity(vm->get_hid(),cpu,mem,disk); - - //---------------------------------------------------- - - dm->trigger(DispatchManager::FAILED,vid); - + failure_action(vm); + vm->unlock(); return; @@ -722,13 +670,9 @@ void LifeCycleManager::cancel_failure_action(int vid) void LifeCycleManager::monitor_failure_action(int vid) { - VirtualMachine * vm; + VirtualMachine * vm; - int cpu,mem,disk; time_t the_time = time(0); - - Nebula& nd = Nebula::instance(); - DispatchManager * dm = nd.get_dm(); vm = vmpool->get(vid,true); @@ -738,22 +682,8 @@ void LifeCycleManager::monitor_failure_action(int vid) } vm->set_running_etime(the_time); - - vm->set_etime(the_time); - - vm->set_reason(History::ERROR); - - vmpool->update_history(vm); - - vm->get_requirements(cpu,mem,disk); - - hpool->del_capacity(vm->get_hid(),cpu,mem,disk); - vm->log("LCM", Log::INFO, "VM failed."); - - //---------------------------------------------------- - - dm->trigger(DispatchManager::FAILED,vid); + failure_action(vm); vm->unlock(); } @@ -806,10 +736,6 @@ void LifeCycleManager::monitor_suspend_action(int vid) void LifeCycleManager::monitor_done_action(int vid) { VirtualMachine * vm; - time_t the_time = time(0); - - Nebula& nd = Nebula::instance(); - TransferManager * tm = nd.get_tm(); vm = vmpool->get(vid,true); @@ -822,21 +748,55 @@ void LifeCycleManager::monitor_done_action(int vid) // EPILOG STATE //---------------------------------------------------- - vm->set_state(VirtualMachine::EPILOG); + vm->set_state(VirtualMachine::UNKNOWN); vmpool->update(vm); - vm->set_epilog_stime(the_time); + vm->log("LCM", Log::INFO, "New VM state is UNKNOWN"); - vm->set_running_etime(the_time); + //---------------------------------------------------- - vmpool->update_history(vm); + vm->unlock(); +} + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void LifeCycleManager::failure_action(VirtualMachine * vm) +{ + Nebula& nd = Nebula::instance(); + TransferManager * tm = nd.get_tm(); + DispatchManager * dm = nd.get_dm(); - vm->log("LCM", Log::INFO, "New VM state is EPILOG"); + time_t the_time = time(0); + int cpu,mem,disk; //---------------------------------------------------- + // LCM FAILURE STATE + //---------------------------------------------------- + + vm->set_state(VirtualMachine::FAILURE); + + vmpool->update(vm); + + vm->set_etime(the_time); - tm->trigger(TransferManager::EPILOG,vid); - - vm->unlock(); + vm->set_reason(History::ERROR); + + vmpool->update_history(vm); + + vm->get_requirements(cpu,mem,disk); + + hpool->del_capacity(vm->get_hid(),cpu,mem,disk); + + //------------- Clean up remote files ---------------- + + dm->trigger(DispatchManager::FAILED,vm->get_oid()); + + tm->trigger(TransferManager::EPILOG_DELETE,vm->get_oid()); } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + diff --git a/src/mad/ruby/ActionManager.rb b/src/mad/ruby/ActionManager.rb index 3223a13..4f62a2d 100644 --- a/src/mad/ruby/ActionManager.rb +++ b/src/mad/ruby/ActionManager.rb @@ -70,8 +70,10 @@ def initialize(concurrency=10, threaded=true) @threaded = threaded @concurrency = concurrency + @num_running = 0 + @action_queue = Array.new - @running_actions= 0 + @action_running = Hash.new @threads_mutex = Mutex.new @threads_cond = ConditionVariable.new @@ -94,15 +96,16 @@ def register_action(aname, method, threaded=nil) # Triggers the execution of the action. # # +aname+ name of the action + # +action_id+ an id to identify the action (to cancel it later) # +aargs+ arguments to call the action - def trigger_action(aname,*aargs) + def trigger_action(aname, action_id, *aargs) @threads_mutex.synchronize { return if @finalize if aname == :FINALIZE @finalize = true - @threads_cond.signal if @running_actions == 0 + @threads_cond.signal if @num_running == 0 return end @@ -127,22 +130,41 @@ def trigger_action(aname,*aargs) end end - @action_queue << @actions[aname].merge(:args => aargs) + @action_queue << @actions[aname].merge(:args => aargs, + :id => action_id) - if @running_actions < @concurrency + if @num_running < @concurrency @threads_cond.signal end } end + def cancel_action(action_id) + @threads_mutex.synchronize { + thread = @action_running[action_id] + + if thread + thread.kill! + + @num_running -= 1 + @action_running.delete(action_id) + + @threads_cond.signal + else + i = @action_queue.index{|x| x[:id] == action_id} + @action_queue.delete_at(i) if i + end + } + end + def start_listener while true @threads_mutex.synchronize { - while ((@concurrency - @running_actions)==0) || + while ((@concurrency - @num_running)==0) || @action_queue.size==0 @threads_cond.wait(@threads_mutex) - return if (@finalize && @running_actions == 0) + return if (@finalize && @num_running == 0) end run_action @@ -156,21 +178,25 @@ def run_action action = @action_queue.shift if action - @running_actions += 1 + @num_running += 1 if action[:threaded] - Thread.new { + thread = Thread.new { action[:method].call(*action[:args]) @threads_mutex.synchronize { - @running_actions -= 1 + @num_running -= 1 + @action_running.delete(action[:id]) + @threads_cond.signal } } + + @action_running[action[:id]] = thread else action[:method].call(*action[:args]) - @running_actions -= 1 + @num_running -= 1 end end end @@ -204,15 +230,20 @@ def nop_action Thread.new { sleep 1 + 100.times {|n| - s.am.trigger_action(:SLEEP,rand(3)+1,n) - s.am.trigger_action(:NOP) + s.am.trigger_action(:SLEEP,n,rand(3)+1,n) + s.am.trigger_action(:NOP,100+n) } - s.am.trigger_action(:FINALIZE) + s.am.trigger_action(:SLEEP,301,5,301) + + s.am.cancel_action(301) + + s.am.trigger_action(:FINALIZE,0) - s.am.trigger_action(:SLEEP,rand(3)+1,999) - s.am.trigger_action(:SLEEP,rand(3)+1,333) + s.am.trigger_action(:SLEEP,999,rand(3)+1,999) + s.am.trigger_action(:SLEEP,333,rand(3)+1,333) } s.am.start_listener diff --git a/src/mad/ruby/OpenNebulaDriver.rb b/src/mad/ruby/OpenNebulaDriver.rb index 5427e46..3c69d99 100644 --- a/src/mad/ruby/OpenNebulaDriver.rb +++ b/src/mad/ruby/OpenNebulaDriver.rb @@ -39,6 +39,7 @@ def initialize(concurrency=10, threaded=true) super(concurrency,threaded) register_action(:INIT, method("init")) + @send_mutex=Mutex.new end @@ -92,7 +93,18 @@ def loop action = args.shift.upcase.to_sym - trigger_action(action,*args) + if (args.length == 0) || (!args[0]) + action_id = 0 + else + action_id = args[0].to_i + end + + if action == :DRIVER_CANCEL + cancel_action(action_id) + log(action_id,"Driver command for #{action_id} cancelled") + else + trigger_action(action,action_id,*args) + end end end end @@ -106,7 +118,7 @@ def initialize register_action(:SLEEP,method("my_sleep")) end - def my_sleep(timeout, num) + def my_sleep(num, timeout) log(num,"Sleeping #{timeout} seconds") sleep(timeout.to_i) log(num,"Done with #{num}") @@ -117,5 +129,4 @@ def my_sleep(timeout, num) sd = SampleDriver.new sd.start_driver - -end \ No newline at end of file +end diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index 55b17a9..0697479 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -126,9 +126,21 @@ void Nebula::start() try { - string db_name = var_location + "one.db"; + string db_name = var_location + "one.db"; + struct stat db_stat; + bool db_bootstrap = stat(db_name.c_str(), &db_stat) != 0; db = new SqliteDB(db_name,Nebula::log); + + if (db_bootstrap) + { + Nebula::log("ONE",Log::INFO,"Bootstraping OpenNebula database."); + + VirtualMachinePool::bootstrap(db); + HostPool::bootstrap(db); + VirtualNetworkPool::bootstrap(db); + UserPool::bootstrap(db); + } } catch (exception&) { @@ -151,18 +163,14 @@ void Nebula::start() nebula_configuration->get("NETWORK_SIZE", size); vnpool = new VirtualNetworkPool(db,mac_prefix,size); + + upool = new UserPool(db); } catch (exception&) { throw; } - Nebula::log("ONE",Log::INFO,"Bootstraping OpenNebula database."); - - vmpool->bootstrap(); - hpool->bootstrap(); - vnpool->bootstrap(); - // ----------------------------------------------------------- // Close stds, we no longer need them // ----------------------------------------------------------- @@ -316,6 +324,7 @@ void Nebula::start() vmpool, hpool, vnpool, + upool, rm_port, log_location + "one_xmlrpc.log"); } @@ -382,12 +391,14 @@ void Nebula::start() vmm->trigger(VirtualMachineManager::FINALIZE,0); lcm->trigger(LifeCycleManager::FINALIZE,0); + tm->trigger(TransferManager::FINALIZE,0); dm->trigger(DispatchManager::FINALIZE,0); im->finalize(); rm->finalize(); - + hm->finalize(); + //sleep to wait drivers??? pthread_join(vmm->get_thread_id(),0); @@ -397,6 +408,7 @@ void Nebula::start() pthread_join(im->get_thread_id(),0); pthread_join(rm->get_thread_id(),0); + pthread_join(hm->get_thread_id(),0); Nebula::log("ONE", Log::INFO, "All modules finalized, exiting.\n"); } diff --git a/src/nebula/SConstruct b/src/nebula/SConstruct index 2805da0..a5715bc 100644 --- a/src/nebula/SConstruct +++ b/src/nebula/SConstruct @@ -41,6 +41,7 @@ env.Append(LIBS=[ 'nebula_rm', 'nebula_dm', 'nebula_tm', + 'nebula_um', 'nebula_mad', 'nebula_template', 'nebula_pool', @@ -49,6 +50,7 @@ env.Append(LIBS=[ 'nebula_vm', 'nebula_common', 'sqlite3', + 'crypto' ]) diff --git a/src/oca/ec2/OcaConfiguration.rb b/src/oca/ec2/OcaConfiguration.rb new file mode 100644 index 0000000..259b559 --- /dev/null +++ b/src/oca/ec2/OcaConfiguration.rb @@ -0,0 +1,73 @@ + +class OcaConfiguration + + NAME_REG=/[\w\d_-]+/ + VARIABLE_REG=/\s*(#{NAME_REG})\s*=\s*/ + SIMPLE_VARIABLE_REG=/#{VARIABLE_REG}([^\[]+?)(#.*)?/ + SINGLE_VARIABLE_REG=/^#{SIMPLE_VARIABLE_REG}$/ + ARRAY_VARIABLE_REG=/^#{VARIABLE_REG}\[(.*?)\]/m + + def initialize(file) + @conf=parse_conf(file) + end + + def add_value(conf, key, value) + if conf[key] + if !conf[key].kind_of?(Array) + conf[key]=[conf[key]] + end + conf[key]< ACCESS_KEY_ID, + :secret_access_key => SECRET_ACCESS_KEY, + :server => SERVER, + :port => PORT, + :use_ssl => false +) + +#pp base.describe_images + +#pp base.register_image( +# :image_location => 'eco.rb' +#) + +#pp base.run_instances( +# :image_id => "b8329b60-4227-012c-da6e-0019e333ebc5" +#) + +pp base.describe_instances + + diff --git a/src/oca/ec2/eco.rb b/src/oca/ec2/eco.rb new file mode 100644 index 0000000..4e997ab --- /dev/null +++ b/src/oca/ec2/eco.rb @@ -0,0 +1,293 @@ + +require 'rubygems' +require 'sinatra' +require 'EC2' + +$: << './OpenNebulaApi' +$: << './lib' + +require 'OpenNebula' +require 'repo_manager' +require 'OcaConfiguration' + +require 'pp' + +include OpenNebula + + + + +CONFIG=OcaConfiguration.new('oca.conf') +AUTH="#{CONFIG[:user]}:#{CONFIG[:password]}" + +INSTANCE_TYPES=Hash.new + +pp CONFIG + +if CONFIG[:vm_type].kind_of?(Array) + # Multiple instance types + CONFIG[:vm_type].each {|type| + INSTANCE_TYPES[type['NAME']]=type + } +else + # When only one instance type is defined + INSTANCE_TYPES[CONFIG[:vm_type]['NAME']]=CONFIG[:vm_type] +end + +pp INSTANCE_TYPES + +set :host, CONFIG[:server] +set :port, CONFIG[:port] + + +EC2_STATES={ + :pending => {:code => 0, :name => 'pending'}, + :running => {:code => 16, :name => 'running'}, + :shutdown => {:code => 32, :name => 'shutting-down'}, + :terminated => {:code => 48, :name => 'terminated'} +} + +ONE_STATES={ + 'init' => :pending, + 'pend' => :pending, + 'hold' => :pending, + 'stop' => :pending, + 'susp' => :pending, + 'done' => :terminated, + 'fail' => :terminated, + 'prol' => :pend, + 'boot' => :running, + 'runn' => :running, + 'migr' => :running, + 'save' => :pend, + 'epil' => :shutdown, + 'shut' => :shutdown, + 'fail' => :terminated, + 'dele' => :terminated, + 'unkn' => :terminated +} + +$repoman=RepoManager.new + +def get_one_client + Client.new(AUTH) +end + +def get_user(name) + user=nil + + user_pool=UserPool.new(get_one_client) + user_pool.info + user_pool.each{|u| + if u.name==name + user=Hash.new + user[:id]=u.id + user[:name]=u.name + user[:password]=u[:password] + end + } + + user +end + +def render_state(vm) + one_state=vm.status + ec2_state=EC2_STATES[ONE_STATES[one_state]] + + "#{ec2_state[:code]} + #{ec2_state[:name]}" +end + +def authenticate(params) + user_name=params['AWSAccessKeyId'] + user=get_user(user_name) + + halt 401, "User does not exist" if !user + + signature_params=params.reject {|key,value| key=='Signature' } + canonical=EC2.canonical_string(signature_params, CONFIG[:server]) + signature=EC2.encode(user[:password], canonical, false) + + halt 401, "Bad password" if params['Signature']!=signature +end + +before do + authenticate(params) +end + + +def register_image(params) + user=get_user(params['AWSAccessKeyId']) + + img=$repoman.add(user[:id], params["ImageLocation"]) + @img_id=img.uuid + + erb :register_image +end + +def describe_images(params) + @user=get_user(params['AWSAccessKeyId']) + + @images=Image.filter(:owner => @user[:id]) + + pp @images + + erb :describe_images +end + + +def run_instances(params) + @user=get_user(params['AWSAccessKeyId']) + + image_id=params['ImageId'] + image=$repoman.get(image_id) + + @vm_info=Hash.new + @vm_info[:img_path]=image.path + @vm_info[:img_id]=image_id + + instance_type_name=params['InstanceType'] + instance_type=INSTANCE_TYPES[instance_type_name] + + halt 400, "Bad instance type" if !instance_type + + @vm_info[:instance_type]=instance_type_name + + template=ERB.new(File.read("templates/#{instance_type['TEMPLATE']}")) + template_text=template.result(binding) + + pp template_text + + vm=VirtualMachine.new(VirtualMachine.build_xml, get_one_client) + response=vm.allocate(template_text) + + pp response + + @vm_info[:vm_id]=vm.id + + erb :run_instances +end + +def describe_instances(params) + @user=get_user(params['AWSAccessKeyId']) + + @vmpool=VirtualMachinePool.new(get_one_client) + @vmpool.info + + erb :describe_instances +end + +post '/' do + pp params + + case params['Action'] + when 'RegisterImage' + register_image(params) + when 'DescribeImages' + describe_images(params) + when 'RunInstances' + run_instances(params) + when 'DescribeInstances' + describe_instances(params) + end +end + + +__END__ + +@@ register_image + + <%= @img_id %> + + + +@@ describe_images + + + <% for image in @images %> + + <%= image.uuid %> + <%= image.path %> + available + <%= @user[:name] %> + false + i386 + machine + + <% end %> + + + + +@@ run_instances + + r-47a5402e + <%= @user[:name] %> + + + default + + + + + <%= @vm_info[:vm_id] %> + <%= @vm_info[:img_id] %> + + 0 + pending + + + + example-key-name + 0 + m1.small + 2007-08-07T11:51:50.000Z + + us-east-1b + + + true + + + + + +@@ describe_instances + + + + default + <%= @user[:name] %> + + + default + + + + <% @vmpool.each do |vm| %> + + <%= vm.id %> + <%= vm.id %> + + <%= render_state(vm) %> + + 10-251-50-132.ec2.internal + ec2-72-44-33-4.compute-1.amazonaws.com + example-key-name + 23 + + 774F4FF8 + + m1.large + 2007-08-07T11:54:42.000Z + + us-east-1b + + + <% end %> + + + + + + diff --git a/src/oca/ec2/oca.conf b/src/oca/ec2/oca.conf new file mode 100644 index 0000000..2cfae09 --- /dev/null +++ b/src/oca/ec2/oca.conf @@ -0,0 +1,24 @@ +# OpenNebula administrator user +USER=jfontan +PASSWORD=opennebula + +# OpenNebula sever contact information +ONE_XMLRPC=http://localhost:2633/RPC2 + +# Host and port where OCA server will run +SERVER=127.0.0.1 +PORT=4567 + +# Configuration for the image repository +DATABASE=./database.db +IMAGE_DIR=./images + +# VM types allowed and its template file (inside templates directory) +VM_TYPE=[NAME=m1.small, TEMPLATE=m1.small.erb] +VM_TYPE=[NAME=m1.medium, TEMPLATE=m1.small.erb] +VM_TYPE=[NAME=m1.large, TEMPLATE=m1.small.erb] + +VM_TYPE=[ + NAME=m2.small, + TEMPLATE=m1.small.erb +] diff --git a/src/oca/ec2/templates/m1.small.erb b/src/oca/ec2/templates/m1.small.erb new file mode 100644 index 0000000..97a2ce3 --- /dev/null +++ b/src/oca/ec2/templates/m1.small.erb @@ -0,0 +1,20 @@ + +NAME = eco-vm + +CPU = 0.2 +MEMORY = 256 + +OS = [ kernel = /vmlinuz, + initrd = /initrd.img, + root = sda1, + kernel_cmd = "ro xencons=tty console=tty1"] + +DISK = [ source = <%= @vm_info[:img_path] %>, + clone = no, + target = sda1, + readonly = no] + + +IMAGE_ID = <%= @vm_info[:img_id] %> +INSTANCE_TYPE = <%= @vm_info[:instance_type ]%> + diff --git a/src/oca/rm/image.rb b/src/oca/rm/image.rb new file mode 100644 index 0000000..9048193 --- /dev/null +++ b/src/oca/rm/image.rb @@ -0,0 +1,151 @@ + +module OpenNebula + class Image < Sequel::Model + # Creates the database table asociated with the model. It first + # checks for table existence before creating it so it is reasonably + # safe to call it when you load the library. + def self.initialize_table + set_schema do + primary_key :id, :type => Integer + varchar :uuid + int :owner + varchar :name + varchar :description + varchar :path + int :size + varchar :md5 + end + + create_table unless table_exists? + end + + # Makes sure the image is deleted from the repository after + # the record is deleted. Make sure that you use destroy and not + # delete as delete method does not call hooks. + before_destroy do + FileUtils.rm(self.path) + end + + # Specifies the directory where images will be stored + # dir:: _String_ directory where the images are stored + def self.image_dir=(dir) + @@image_dir=dir + end + + # Strips out non user writable columns + # metadata:: _Hash_ hash containing the data to add to the db + # [return] _Hash_ clean metadata + def self.sanitize_metadata(metadata) + metadata.reject {|key,value| + ![:name, :description].include? key + } + end + + # Creates a new Image object, fills it, copies the image + # to the repository and saves to the database + # uuid:: _String_ UUID identifier for the image + # owner:: _Integer_ identifier of the user that owns this image + # path:: _String_ place where to copy the image from + # metadata:: _Hash_ extra data to add to the image, like name and description + # [return] _Image_ newly created image + def self.create_image(uuid, owner, path, metadata={}) + sanitized_metadata=sanitize_metadata(metadata) + + data={ + :uuid => uuid, + :owner => owner, + }.merge(sanitized_metadata) + + image=Image.new(data) + + image.copy_image(path) + image.get_image_info + image.save + + # set metadata + end + + # Updates the image with the metadata provided. Currently only + # name and description can be changed + def change_metadata(metadata) + update(Image.sanitize_metadata(metadata)) + end + + # Copies the image from the source path to the image repository. + # Its name will be the image uuid. It also stores its new location + # in the object. + def copy_image(path) + FileUtils.cp(path, image_path) + self.path=image_path + end + + # Returns the filename and path of the image file associated with + # this Image object. + def image_path + @@image_dir||='images' + File.join(@@image_dir, uuid) + end + + # Extracts md5 and size from the image file and stores these data + # in the object. + def get_image_info + self.md5=`md5sum #{image_path}`.split.first + self.size=File.size(image_path) + end + + # Adds a user to the list of allowed users of this image + def add_acl(user) + acl=ImageAcl.new({:uuid => self.uuid, :user => user}) + acl.save + end + + # Deletes a user fom the list of allowed users of this image + def del_acl(user) + acl=ImageAcl[:uuid => self.uuid, :user => user] + acl.destroy if acl + end + + # Checks if a user has permissions to use this image + def has_permission?(user) + return true if self.owner==user + ImageAcl[:uuid => self.uuid, :user => user]!=nil + end + + # Returns the xml representation of the image. + def to_xml + xml="\n" + xml<<" #{uuid}\n" + xml<<" #{owner}\n" + xml<<" #{name}\n" + xml<<" #{description}\n" + xml<<" #{path}\n" + xml<<" #{size}\n" + xml<<" #{md5}\n" + xml<<"\n" + end + + # Like to_xml but does not show image file path data + def to_xml_lite + xml="\n" + xml<<" #{uuid}\n" + xml<<" #{owner}\n" + xml<<" #{name}\n" + xml<<" #{description}\n" + xml<<" #{size}\n" + xml<<" #{md5}\n" + xml<<"\n" + end + end + + class ImageAcl < Sequel::Model + def self.initialize_table + set_schema do + primary_key :id, :type => Integer + varchar :uuid + int :user + end + + create_table unless table_exists? + end + end +end \ No newline at end of file diff --git a/src/oca/rm/repo_manager.rb b/src/oca/rm/repo_manager.rb new file mode 100644 index 0000000..cb57a49 --- /dev/null +++ b/src/oca/rm/repo_manager.rb @@ -0,0 +1,59 @@ + +require 'rubygems' +#require 'storage_pool' +require 'uuid' +require 'fileutils' +require 'sequel' +require 'logger' + +# Seems that database should be opened before defining models +# TODO: fix this +DB=Sequel.sqlite('database.db') +#DB.loggers << Logger.new($stdout) +require 'image' + + +IMAGE_DIR='images' + +module OpenNebula + class RepoManager + def initialize + @uuid=UUID.new + Image.initialize_table + ImageAcl.initialize_table + end + + def add(owner, path, metadata={}) + uuid=@uuid.generate + + Image.create_image(uuid, owner, path, metadata) + end + + def get(uuid) + Image[:uuid => uuid] + end + + def update(uuid, metadata) + image=get(uuid) + image.update(metadata) + end + + + end + +end + +=begin +OpenNebula::Image.create_image('uid', 10, 'repo_manager.rb', + :name => 'nombre', + :noexiste => 'nada' +) +=end + +if $0 == __FILE__ + rm=OpenNebula::RepoManager.new + img=rm.add_image(rand(100), 'image.rb', + :name => 'nombre', + :description => 'desc') + puts img.to_xml +end diff --git a/src/pool/PoolSQL.cc b/src/pool/PoolSQL.cc index 44e1d27..b523a5f 100644 --- a/src/pool/PoolSQL.cc +++ b/src/pool/PoolSQL.cc @@ -254,33 +254,6 @@ void PoolSQL::replace() /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void PoolSQL::remove(PoolObjectSQL * obj) -{ - map::iterator index; - - if (obj == 0) - { - return; - } - - index = pool.find(obj->oid); - - if ( index != pool.end()) - { - delete obj; - - lock(); - - pool.erase(index); - - unlock(); - - } -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - void PoolSQL::clean() { map::iterator it; diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index e38c0a6..c31bd52 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -215,65 +215,97 @@ void RequestManager::do_action( void RequestManager::register_xml_methods() { xmlrpc_c::methodPtr vm_allocate(new - RequestManager::VirtualMachineAllocate); + RequestManager::VirtualMachineAllocate(upool)); xmlrpc_c::methodPtr vm_deploy(new - RequestManager::VirtualMachineDeploy(vmpool,hpool)); + RequestManager::VirtualMachineDeploy(vmpool,hpool,upool)); xmlrpc_c::methodPtr vm_migrate(new - RequestManager::VirtualMachineMigrate(vmpool,hpool)); + RequestManager::VirtualMachineMigrate(vmpool,hpool,upool)); xmlrpc_c::methodPtr vm_action(new - RequestManager::VirtualMachineAction); + RequestManager::VirtualMachineAction(vmpool,upool)); xmlrpc_c::methodPtr vm_info(new - RequestManager::VirtualMachineInfo(vmpool)); + RequestManager::VirtualMachineInfo(vmpool,upool)); xmlrpc_c::methodPtr vm_pool_info(new - RequestManager::VirtualMachinePoolInfo(vmpool)); + RequestManager::VirtualMachinePoolInfo(vmpool,upool)); xmlrpc_c::methodPtr host_allocate(new - RequestManager::HostAllocate(hpool)); + RequestManager::HostAllocate(hpool,upool)); xmlrpc_c::methodPtr host_info(new - RequestManager::HostInfo(hpool)); + RequestManager::HostInfo(hpool, upool)); + + xmlrpc_c::methodPtr hostpool_info(new + RequestManager::HostPoolInfo(hpool,upool)); xmlrpc_c::methodPtr host_delete(new - RequestManager::HostDelete(hpool)); + RequestManager::HostDelete(hpool,upool)); xmlrpc_c::methodPtr host_enable(new - RequestManager::HostEnable(hpool)); + RequestManager::HostEnable(hpool,upool)); xmlrpc_c::methodPtr vn_allocate(new - RequestManager::VirtualNetworkAllocate(vnpool)); + RequestManager::VirtualNetworkAllocate(vnpool,upool)); xmlrpc_c::methodPtr vn_info(new - RequestManager::VirtualNetworkInfo(vnpool)); + RequestManager::VirtualNetworkInfo(vnpool,upool)); + xmlrpc_c::methodPtr vnpool_info(new + RequestManager::VirtualNetworkPoolInfo(vnpool,upool)); + xmlrpc_c::methodPtr vn_delete(new - RequestManager::VirtualNetworkDelete(vnpool)); + RequestManager::VirtualNetworkDelete(vnpool, upool)); + + xmlrpc_c::methodPtr user_allocate(new + RequestManager::UserAllocate(upool)); + + xmlrpc_c::methodPtr user_info(new + RequestManager::UserInfo(upool)); + + xmlrpc_c::methodPtr user_delete(new + RequestManager::UserDelete(upool)); + + xmlrpc_c::methodPtr userpool_info(new + RequestManager::UserPoolInfo(upool)); /* VM related methods */ - RequestManagerRegistry.addMethod("one.vmallocate", vm_allocate); - RequestManagerRegistry.addMethod("one.vmdeploy", vm_deploy); - RequestManagerRegistry.addMethod("one.vmaction", vm_action); - RequestManagerRegistry.addMethod("one.vmmigrate", vm_migrate); - RequestManagerRegistry.addMethod("one.vmget_info", vm_info); - RequestManagerRegistry.addMethod("one.vmget_pool_info", vm_pool_info); + RequestManagerRegistry.addMethod("one.vm.allocate",vm_allocate); + RequestManagerRegistry.addMethod("one.vm.deploy", vm_deploy); + RequestManagerRegistry.addMethod("one.vm.action", vm_action); + RequestManagerRegistry.addMethod("one.vm.migrate", vm_migrate); + RequestManagerRegistry.addMethod("one.vm.info", vm_info); + + RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info); /* Host related methods*/ - RequestManagerRegistry.addMethod("one.hostallocate", host_allocate); - RequestManagerRegistry.addMethod("one.hostinfo", host_info); - RequestManagerRegistry.addMethod("one.hostdelete", host_delete); - RequestManagerRegistry.addMethod("one.hostenable", host_enable); + RequestManagerRegistry.addMethod("one.host.allocate", host_allocate); + RequestManagerRegistry.addMethod("one.host.info", host_info); + RequestManagerRegistry.addMethod("one.host.delete", host_delete); + RequestManagerRegistry.addMethod("one.host.enable", host_enable); + RequestManagerRegistry.addMethod("one.hostpool.info", hostpool_info); + /* Network related methods*/ - RequestManagerRegistry.addMethod("one.vnallocate", vn_allocate); - RequestManagerRegistry.addMethod("one.vninfo", vn_info); - RequestManagerRegistry.addMethod("one.vndelete", vn_delete); + RequestManagerRegistry.addMethod("one.vn.allocate", vn_allocate); + RequestManagerRegistry.addMethod("one.vn.info", vn_info); + RequestManagerRegistry.addMethod("one.vn.delete", vn_delete); + + RequestManagerRegistry.addMethod("one.vnpool.info", vnpool_info); + + + /* User related methods*/ + + RequestManagerRegistry.addMethod("one.user.allocate", user_allocate); + RequestManagerRegistry.addMethod("one.user.info", user_info); + RequestManagerRegistry.addMethod("one.user.delete", user_delete); + + RequestManagerRegistry.addMethod("one.userpool.info", userpool_info); }; diff --git a/src/rm/RequestManagerAction.cc b/src/rm/RequestManagerAction.cc index 6804c27..0cab979 100644 --- a/src/rm/RequestManagerAction.cc +++ b/src/rm/RequestManagerAction.cc @@ -29,19 +29,46 @@ void RequestManager::VirtualMachineAction::execute( string action; int vid; int rc; - + + int uid; + vector arrayData; - + xmlrpc_c::value_array * arrayresult; + Nebula& nd = Nebula::instance(); DispatchManager * dm = nd.get_dm(); + VirtualMachine * vm; + + ostringstream oss; + Nebula::log("ReM",Log::DEBUG,"VirtualMachineAction invoked"); session = xmlrpc_c::value_string(paramList.getString(0)); action = xmlrpc_c::value_string(paramList.getString(1)); - vid = xmlrpc_c::value_int(paramList.getInt(2)); + + // Get the VM + vm = VirtualMachineAction::vmpool->get(vid,true); + + if ( vm == 0 ) + { + goto error_vm_get; + } + + uid = vm->get_uid(); + + vm->unlock(); + + // Only oneadmin or the VM owner can perform operations upon the VM + rc = VirtualMachineAction::upool->authenticate(session); + + if ( rc != 0 && rc != uid) + { + goto error_authenticate; + } + if (action == "shutdown") { rc = dm->shutdown(vid); @@ -70,6 +97,10 @@ void RequestManager::VirtualMachineAction::execute( { rc = dm->resume(vid); } + else if (action == "restart") + { + rc = dm->restart(vid); + } else if (action == "finalize") { rc = dm->finalize(vid); @@ -79,34 +110,52 @@ void RequestManager::VirtualMachineAction::execute( rc = -3; } - if (rc == 0) + if (rc != 0) { - arrayData.push_back(xmlrpc_c::value_boolean(true)); + goto error_operation; + } - else + + arrayData.push_back(xmlrpc_c::value_boolean(true)); + arrayresult = new xmlrpc_c::value_array(arrayData); + *retval = *arrayresult; + delete arrayresult; + return; + +error_operation: + if (rc == -1) { - ostringstream oss; - - if (rc == -1) - { - oss << "Virtual machine does not exist"; - } - else if ( rc == -2 ) - { - oss << "Wrong state to perform action"; - } - else if ( rc == -3 ) - { - oss << "Unknown action"; - } - - arrayData.push_back(xmlrpc_c::value_boolean(false)); - arrayData.push_back(xmlrpc_c::value_string(oss.str())); - } - - xmlrpc_c::value_array arrayresult(arrayData); - - *retval = arrayresult; + oss << "Virtual machine does not exist"; + } + else if ( rc == -2 ) + { + oss << "Wrong state to perform action"; + } + else if ( rc == -3 ) + { + oss << "Unknown action"; + } + goto error_common; + +error_vm_get: + oss << "The virtual machine " << vid << " does not exists"; + goto error_common; + +error_authenticate: + oss << "User not authorized to perform operation upon VirtualMachine [" << vid << "]"; + goto error_common; + +error_common: + + arrayData.push_back(xmlrpc_c::value_boolean(false)); + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; + } /* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerAllocate.cc b/src/rm/RequestManagerAllocate.cc index 7beec63..cb6f571 100644 --- a/src/rm/RequestManagerAllocate.cc +++ b/src/rm/RequestManagerAllocate.cc @@ -26,49 +26,104 @@ void RequestManager::VirtualMachineAllocate::execute( xmlrpc_c::value * const retval) { string session; + string username; + string password; string vm_template; + int vid; + int uid; int rc; - + Nebula& nd = Nebula::instance(); DispatchManager * dm = nd.get_dm(); + User * user; + + ostringstream oss; + vector arrayData; + xmlrpc_c::value_array * arrayresult; + Nebula::log("ReM",Log::DEBUG,"VirtualMachineAllocate invoked"); session = xmlrpc_c::value_string(paramList.getString(0)); vm_template = xmlrpc_c::value_string(paramList.getString(1)); vm_template += "\n"; + + + // First, we need to authenticate the user + rc = VirtualMachineAllocate::upool->authenticate(session); + + if ( rc == -1 ) + { + goto error_authenticate; + } + + User::split_secret(session,username,password); + + // Now let's get the user + user = VirtualMachineAllocate::upool->get(username,true); + + if ( user == 0 ) + { + goto error_get_user; + } + + uid = user->get_uid(); + + user->unlock(); - rc = dm->allocate(0,vm_template,&vid); + rc = dm->allocate(uid,vm_template,&vid); if ( rc != 0 ) { - ostringstream oss; - - if (rc == -1) - { - oss << "Error inserting VM in the database, check oned.log"; - } - else - { - oss << "Error parsing VM template"; - } - - arrayData.push_back(xmlrpc_c::value_boolean(false)); - arrayData.push_back(xmlrpc_c::value_string(oss.str())); + goto error_allocate; + + } + + arrayData.push_back(xmlrpc_c::value_boolean(true)); + arrayData.push_back(xmlrpc_c::value_int(vid)); + + // Copy arrayresult into retval mem space + arrayresult = new xmlrpc_c::value_array(arrayData); + *retval = *arrayresult; + + delete arrayresult; // and get rid of the original + + + return; +error_authenticate: + oss << "User not authenticated, aborting RequestManagerAllocate call."; + goto error_common; + +error_get_user: + oss << "User not recognized, cannot allocate VirtualMachine"; + goto error_common; + +error_allocate: + if (rc == -1) + { + oss << "Error inserting VM in the database, check oned.log"; } else { - arrayData.push_back(xmlrpc_c::value_boolean(true)); - arrayData.push_back(xmlrpc_c::value_int(vid)); + oss << "Error parsing VM template"; } + goto error_common; - xmlrpc_c::value_array arrayresult(arrayData); - - *retval = arrayresult; +error_common: + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + Nebula::log("ReM",Log::ERROR,oss); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; } /* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerCancel.cc b/src/rm/RequestManagerCancel.cc index 35aeb35..fa4599d 100644 --- a/src/rm/RequestManagerCancel.cc +++ b/src/rm/RequestManagerCancel.cc @@ -29,7 +29,8 @@ void RequestManager::VirtualMachineCancel::execute( // of the vid to retrieve the information for int vid; - + int uid; + VirtualMachine * vm; ostringstream oss; @@ -44,19 +45,31 @@ void RequestManager::VirtualMachineCancel::execute( Nebula::log("ReM",Log::DEBUG,"VirtualMachineCancel method invoked"); // Get the parameters - //TODO the session id to validate with the SessionManager session = xmlrpc_c::value_string(paramList.getString(0)); vid = xmlrpc_c::value_int (paramList.getInt(1)); - // Perform the allocation in the vmpool - vm = VirtualMachineCancel::vmpool->get(vid,false); + + // Retrieve the VM from the vmpool + vm = VirtualMachineCancel::vmpool->get(vid,true); if ( vm == 0 ) { goto error_vm_get; } - //Deploy the VM + uid = vm->get_uid(); + + vm->unlock(); + + // Only oneadmin or the VM owner can perform operations upon the VM + rc = VirtualMachineCancel::upool->authenticate(session); + + if ( rc != 0 && rc != uid) + { + goto error_authenticate; + } + + //Cancel the VM dm->cancel(vid); @@ -72,6 +85,10 @@ void RequestManager::VirtualMachineCancel::execute( return; +error_authenticate: + oss << "User not authorized to cancel VM"; + goto error_common; + error_vm_get: oss << "Error getting vm for cancelling with VID = " << vid; goto error_common; diff --git a/src/rm/RequestManagerDeploy.cc b/src/rm/RequestManagerDeploy.cc index 6144275..7e7d0f7 100644 --- a/src/rm/RequestManagerDeploy.cc +++ b/src/rm/RequestManagerDeploy.cc @@ -28,6 +28,7 @@ void RequestManager::VirtualMachineDeploy::execute( string session; int vid; int hid; + int uid; int rc; string hostname; @@ -69,15 +70,8 @@ void RequestManager::VirtualMachineDeploy::execute( vmm_mad = host->get_vmm_mad(); tm_mad = host->get_tm_mad(); - if (host->isManaged() == true) - { - nd.get_configuration_attribute("VM_DIR",vmdir); - } - else - { - goto error_host_managed; - } - + nd.get_configuration_attribute("VM_DIR",vmdir); + host->unlock(); //Get the VM @@ -88,7 +82,17 @@ void RequestManager::VirtualMachineDeploy::execute( { goto error_vm_get; } + + uid = vm->get_uid(); + // Only oneadmin or the VM owner can perform operations upon the VM + rc = VirtualMachineDeploy::upool->authenticate(session); + + if ( rc != 0 && rc != uid) + { + goto error_authenticate; + } + if ( vm->get_state() != VirtualMachine::PENDING ) { goto error_state; @@ -122,11 +126,10 @@ void RequestManager::VirtualMachineDeploy::execute( delete arrayresult; return; - -error_host_managed: - host->unlock(); - - oss << "Not managed hosts (id:" << hid << ") not supported"; + +error_authenticate: + vm->unlock(); + oss << "User not authorized to perform the deploy"; goto error_common; error_host_get: diff --git a/src/rm/RequestManagerHostAllocate.cc b/src/rm/RequestManagerHostAllocate.cc index 2631907..9f57a24 100644 --- a/src/rm/RequestManagerHostAllocate.cc +++ b/src/rm/RequestManagerHostAllocate.cc @@ -31,7 +31,6 @@ void RequestManager::HostAllocate::execute( string im_mad_name; string vmm_mad_name; string tm_mad_name; - bool managed; int hid; @@ -45,22 +44,25 @@ void RequestManager::HostAllocate::execute( Nebula::log("ReM",Log::DEBUG,"HostAllocate method invoked"); // Get the parameters - //TODO the session id to validate with the SessionManager session = xmlrpc_c::value_string(paramList.getString(0)); hostname = xmlrpc_c::value_string(paramList.getString(1)); im_mad_name = xmlrpc_c::value_string(paramList.getString(2)); vmm_mad_name = xmlrpc_c::value_string(paramList.getString(3)); tm_mad_name = xmlrpc_c::value_string(paramList.getString(4)); - managed = xmlrpc_c::value_boolean(paramList.getBoolean(5)); + // Only oneadmin can add new hosts + rc = HostAllocate::upool->authenticate(session); + + if ( rc != 0 ) + { + goto error_authenticate; + } // Perform the allocation in the hostpool rc = HostAllocate::hpool->allocate(&hid, hostname, im_mad_name, vmm_mad_name, - tm_mad_name, - managed); - + tm_mad_name); if ( rc != 0 ) { goto error_host_allocate; @@ -77,6 +79,10 @@ void RequestManager::HostAllocate::execute( return; +error_authenticate: + oss << "User not authorized to add new hosts"; + goto error_common; + error_host_allocate: oss << "Can not allocate host " << hostname << " in the HostPool, returned error code [" << rc << "]"; diff --git a/src/rm/RequestManagerHostDelete.cc b/src/rm/RequestManagerHostDelete.cc index 741cf98..c3df23e 100644 --- a/src/rm/RequestManagerHostDelete.cc +++ b/src/rm/RequestManagerHostDelete.cc @@ -40,10 +40,17 @@ void RequestManager::HostDelete::execute( Nebula::log("ReM",Log::DEBUG,"HostDelete method invoked"); // Get the parameters - //TODO the session id to validate with the SessionManager session = xmlrpc_c::value_string(paramList.getString(0)); hid = xmlrpc_c::value_int (paramList.getInt(1)); - + + // Only oneadmin can delete hosts + rc = HostDelete::upool->authenticate(session); + + if ( rc != 0 ) + { + goto error_authenticate; + } + // Perform the allocation in the hostpool host = HostDelete::hpool->get(hid,true); @@ -65,9 +72,15 @@ void RequestManager::HostDelete::execute( return; -error_host_get: +error_authenticate: + oss << "User not authorized to delete hosts"; + goto error_common; +error_host_get: oss << "Error getting host with HID = " <authenticate(session); + + if ( rc != 0) + { + goto error_authenticate; + } + host = HostEnable::hpool->get(hid,true); if ( host == 0 ) @@ -74,9 +83,15 @@ void RequestManager::HostEnable::execute( return; +error_authenticate: + oss << "Only oneadmin can enable hosts"; + goto error_common; + error_host_get: - - oss << "Error getting host with HID = " << hid; + oss << "Error getting host with HID = " << hid; + goto error_common; + +error_common: Nebula::log("ReM",Log::ERROR,oss); arrayData.push_back(xmlrpc_c::value_boolean(false)); diff --git a/src/rm/RequestManagerHostInfo.cc b/src/rm/RequestManagerHostInfo.cc index c0fdf3e..ef7928d 100644 --- a/src/rm/RequestManagerHostInfo.cc +++ b/src/rm/RequestManagerHostInfo.cc @@ -25,14 +25,13 @@ void RequestManager::HostInfo::execute( xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retval) { - string session; + string session; - // of the host to retrieve the information for - int hid; + int hid; + int rc; + Host * host; - Host * host; - - ostringstream oss; + ostringstream oss; /* -- RPC specific vars -- */ vector arrayData; @@ -41,10 +40,17 @@ void RequestManager::HostInfo::execute( Nebula::log("ReM",Log::DEBUG,"HostInfo method invoked"); // Get the parameters - //TODO the session id to validate with the SessionManager session = xmlrpc_c::value_string(paramList.getString(0)); hid = xmlrpc_c::value_int (paramList.getInt(1)); + // Check if it is a valid user + rc = HostInfo::upool->authenticate(session); + + if ( rc == -1 ) + { + goto error_authenticate; + } + // Perform the allocation in the hostpool host = HostInfo::hpool->get(hid,true); @@ -53,22 +59,26 @@ void RequestManager::HostInfo::execute( goto error_host_get; } - // All nice, return the host info to the client - arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS - oss.str(""); oss << *host; host->unlock(); + // All nice, return the host info to the client + arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS arrayData.push_back(xmlrpc_c::value_string(oss.str())); - arrayresult = new xmlrpc_c::value_array(arrayData); + // Copy arrayresult into retval mem space + arrayresult = new xmlrpc_c::value_array(arrayData); *retval = *arrayresult; - // and get rid of the original - delete arrayresult; + + delete arrayresult; // and get rid of the original return; +error_authenticate: + oss << "User not authenticated, HostInfo call aborted."; + goto error_common; + error_host_get: oss << "Error getting host with HID = " << hid; goto error_common; diff --git a/src/rm/RequestManagerHostPoolInfo.cc b/src/rm/RequestManagerHostPoolInfo.cc new file mode 100755 index 0000000..318a587 --- /dev/null +++ b/src/rm/RequestManagerHostPoolInfo.cc @@ -0,0 +1,95 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad */ +/* Complutense de Madrid (dsa-research.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#include "RequestManager.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManager::HostPoolInfo::execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retval) +{ + string session; + ostringstream oss; + int rc; + + /* -- RPC specific vars -- */ + vector arrayData; + xmlrpc_c::value_array * arrayresult; + + Nebula::log("ReM",Log::DEBUG,"HostPoolInfo method invoked"); + + // Get the parameters + session = xmlrpc_c::value_string(paramList.getString(0)); + + + // Check if it is a valid user + rc = HostPoolInfo::upool->authenticate(session); + + if ( rc == -1 ) + { + goto error_authenticate; + } + + // Perform the allocation in the vmpool + rc = HostPoolInfo::hpool->dump(oss,""); + + if ( rc != 0 ) + { + goto error_dump; + } + + //All nice, return the host info to the client + arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + arrayresult = new xmlrpc_c::value_array(arrayData); + + // Copy arrayresult into retval mem space + *retval = *arrayresult; + + // and get rid of the original + delete arrayresult; + + return; + +error_authenticate: + oss << "User not authenticated, RequestManagerHostPoolInfo aborted."; + goto error_common; + +error_dump: + oss << "Error getting host pool"; + goto error_common; + +error_common: + + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + Nebula::log("ReM",Log::ERROR,oss); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerInfo.cc b/src/rm/RequestManagerInfo.cc index 1e54f78..1859f5a 100644 --- a/src/rm/RequestManagerInfo.cc +++ b/src/rm/RequestManagerInfo.cc @@ -25,14 +25,12 @@ void RequestManager::VirtualMachineInfo::execute( xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retval) { - string session; + string session; - // of the vid to retrieve the information for - int vid; - - VirtualMachine * vm; - - ostringstream oss; + int vid; + VirtualMachine * vm; + + ostringstream oss; /* -- RPC specific vars -- */ vector arrayData; @@ -41,32 +39,30 @@ void RequestManager::VirtualMachineInfo::execute( Nebula::log("ReM",Log::DEBUG,"VirtualMachineInfo method invoked"); // Get the parameters - //TODO the session id to validate with the SessionManager session = xmlrpc_c::value_string(paramList.getString(0)); vid = xmlrpc_c::value_int (paramList.getInt(1)); // Perform the allocation in the vmpool vm = VirtualMachineInfo::vmpool->get(vid,true); - - + if ( vm == 0 ) { goto error_vm_get; } - // All nice, return the vm info to the client - arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS - oss.str(""); oss << *vm; vm->unlock(); + // All nice, return the vm info to the client + arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS arrayData.push_back(xmlrpc_c::value_string(oss.str())); - arrayresult = new xmlrpc_c::value_array(arrayData); + // Copy arrayresult into retval mem space + arrayresult = new xmlrpc_c::value_array(arrayData); *retval = *arrayresult; - // and get rid of the original - delete arrayresult; + + delete arrayresult; // and get rid of the original return; diff --git a/src/rm/RequestManagerMigrate.cc b/src/rm/RequestManagerMigrate.cc index d2d7014..5907d5d 100644 --- a/src/rm/RequestManagerMigrate.cc +++ b/src/rm/RequestManagerMigrate.cc @@ -28,6 +28,7 @@ void RequestManager::VirtualMachineMigrate::execute( string session; int vid; int hid; + int uid; int rc; bool live; @@ -65,20 +66,13 @@ void RequestManager::VirtualMachineMigrate::execute( { goto error_host_get; } - + hostname = host->get_hostname(); vmm_mad = host->get_vmm_mad(); tm_mad = host->get_tm_mad(); - - if (host->isManaged() == true) - { - nd.get_configuration_attribute("VM_DIR",vmdir); - } - else - { - goto error_host_managed; - } - + + nd.get_configuration_attribute("VM_DIR",vmdir); + host->unlock(); //Get the VM and migrate it @@ -89,6 +83,16 @@ void RequestManager::VirtualMachineMigrate::execute( { goto error_vm_get; } + + uid = vm->get_uid(); + + // Only oneadmin or the VM owner can perform operations upon the VM + rc = VirtualMachineMigrate::upool->authenticate(session); + + if ( rc != 0 && rc != uid) + { + goto error_authenticate; + } if ((vm->get_state() != VirtualMachine::ACTIVE) || (vm->get_lcm_state() != VirtualMachine::RUNNING)) @@ -130,10 +134,9 @@ void RequestManager::VirtualMachineMigrate::execute( return; -error_host_managed: - host->unlock(); - - oss << "Not managed hosts (id:" << hid << ") not supported"; +error_authenticate: + vm->unlock(); + oss << "User not authorized to perform migration upon this VM"; goto error_common; error_host_get: diff --git a/src/rm/RequestManagerPoolInfo.cc b/src/rm/RequestManagerPoolInfo.cc index 5a7a1f7..a3dec04 100644 --- a/src/rm/RequestManagerPoolInfo.cc +++ b/src/rm/RequestManagerPoolInfo.cc @@ -26,11 +26,16 @@ void RequestManager::VirtualMachinePoolInfo::execute( xmlrpc_c::value * const retval) { string session; + string username; + string password; - // of the vid to retrieve the information for - int vid, rc; + int filter_flag; + int rc; ostringstream oss; + ostringstream where_string; + + User * user; /* -- RPC specific vars -- */ vector arrayData; @@ -39,12 +44,47 @@ void RequestManager::VirtualMachinePoolInfo::execute( Nebula::log("ReM",Log::DEBUG,"VirtualMachinePoolInfo method invoked"); // Get the parameters - //TODO the session id to validate with the SessionManager session = xmlrpc_c::value_string(paramList.getString(0)); - vid = xmlrpc_c::value_int (paramList.getInt(1)); + filter_flag = xmlrpc_c::value_int (paramList.getInt(1)); + + // Check if it is a valid user + rc = VirtualMachinePoolInfo::upool->authenticate(session); + + if ( rc == -1 ) + { + goto error_authenticate; + } + + where_string.str(""); + + /** Filter flag meaning table + * <=-2 :: ALL VMs + * -1 :: User's VMs + * >=0 :: UID User's VMs + **/ + if (filter_flag == -1) + { + User::split_secret(session,username,password); + + // Now let's get the user + user = VirtualMachinePoolInfo::upool->get(username,true); + + if ( user == 0 ) + { + goto error_get_user; + } + + where_string << "UID=" << user->get_uid(); + + user->unlock(); + } + else if (filter_flag>=0) + { + where_string << "UID=" << filter_flag; + } // Perform the allocation in the vmpool - rc = VirtualMachinePoolInfo::vmpool->dump(oss,""); + rc = VirtualMachinePoolInfo::vmpool->dump(oss,where_string.str()); if ( rc != 0 ) { @@ -63,6 +103,14 @@ void RequestManager::VirtualMachinePoolInfo::execute( return; +error_authenticate: + oss << "User not authenticated, aborting RequestManagerPoolInfo call."; + goto error_common; + +error_get_user: + oss << "An error ocurred getting the user from the UserPool, aborting RequestManagerPoolInfo call"; + goto error_common; + error_dump: oss << "Error getting the pool info"; goto error_common; diff --git a/src/rm/RequestManagerUserAllocate.cc b/src/rm/RequestManagerUserAllocate.cc new file mode 100644 index 0000000..8a4cbf4 --- /dev/null +++ b/src/rm/RequestManagerUserAllocate.cc @@ -0,0 +1,116 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad */ +/* Complutense de Madrid (dsa-research.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#include "RequestManager.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManager::UserAllocate::execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retval) +{ + string session; + + string username; + string password; + + int uid; + + int rc; + ostringstream oss; + + User * user; + + /* -- RPC specific vars -- */ + vector arrayData; + xmlrpc_c::value_array * arrayresult; + + Nebula::log("ReM",Log::DEBUG,"UserAllocate method invoked"); + + // Get the parameters + session = xmlrpc_c::value_string(paramList.getString(0)); + + username = xmlrpc_c::value_string(paramList.getString(1)); + password = xmlrpc_c::value_string(paramList.getString(2)); + + // Only oneadmin can add users + rc = UserAllocate::upool->authenticate(session); + + if ( rc != 0 ) + { + goto error_authenticate; + } + + // Let's make sure that the user doesn't exist in the database + user = UserAllocate::upool->get(username,false); + + if (user != 0 ) + { + goto error_duplicate; + } + + // Now let's add the user + rc = UserAllocate::upool->allocate(&uid,username,password,true); + + if ( rc != 0 ) + { + goto error_allocate; + } + + // All nice, return the new uid to client + arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS + arrayData.push_back(xmlrpc_c::value_int(uid)); + + // Copy arrayresult into retval mem space + arrayresult = new xmlrpc_c::value_array(arrayData); + *retval = *arrayresult; + + delete arrayresult; // and get rid of the original + + return; + +error_authenticate: + oss << "User not authorized to add new users"; + goto error_common; + +error_duplicate: + oss << "Existing user, cannot duplicate"; + goto error_common; + + +error_allocate: + oss << "Error allocating user"; + goto error_common; + +error_common: + + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + Nebula::log("ReM",Log::ERROR,oss); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerUserDelete.cc b/src/rm/RequestManagerUserDelete.cc new file mode 100644 index 0000000..f3975da --- /dev/null +++ b/src/rm/RequestManagerUserDelete.cc @@ -0,0 +1,116 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad */ +/* Complutense de Madrid (dsa-research.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#include "RequestManager.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManager::UserDelete::execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retval) +{ + string session; + + int uid; + User * user; + + int rc; + ostringstream oss; + + /* -- RPC specific vars -- */ + vector arrayData; + xmlrpc_c::value_array * arrayresult; + + Nebula::log("ReM",Log::DEBUG,"UserDelete method invoked"); + + // Get the parameters + session = xmlrpc_c::value_string(paramList.getString(0)); + uid = xmlrpc_c::value_int(paramList.getInt(1)); + + // oneadmin cannot be deleted + if ( uid == 0 ) + { + goto error_oneadmin_deletion; + } + + // Only oneadmin can delete users + rc = UserDelete::upool->authenticate(session); + + if ( rc != 0 ) + { + goto error_authenticate; + } + + // Now let's get the user + user = UserDelete::upool->get(uid,true); + + if ( user == 0) + { + goto error_get_user; + } + + rc = UserDelete::upool->drop(user); + + if ( rc != 0 ) + { + goto error_delete; + } + + // All nice, return the new uid to client + arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS + + // Copy arrayresult into retval mem space + arrayresult = new xmlrpc_c::value_array(arrayData); + *retval = *arrayresult; + + delete arrayresult; // and get rid of the original + + return; + +error_oneadmin_deletion: + oss << "User oneadmin cannot be deleted"; + goto error_common; + +error_authenticate: + oss << "User not authorized to add new users"; + goto error_common; + +error_get_user: + oss << "Error retrieving user " << uid; + goto error_common; + +error_delete: + oss << "Error deleting user " << uid; + goto error_common; + +error_common: + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + Nebula::log("ReM",Log::ERROR,oss); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerUserInfo.cc b/src/rm/RequestManagerUserInfo.cc new file mode 100644 index 0000000..391d0e2 --- /dev/null +++ b/src/rm/RequestManagerUserInfo.cc @@ -0,0 +1,101 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad */ +/* Complutense de Madrid (dsa-research.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#include "RequestManager.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManager::UserInfo::execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retval) +{ + string session; + int uid; + + User * user; + + int rc; + ostringstream oss; + + /* -- RPC specific vars -- */ + vector arrayData; + xmlrpc_c::value_array * arrayresult; + + Nebula::log("ReM",Log::DEBUG,"UserInfo method invoked"); + + // Get the parameters + session = xmlrpc_c::value_string(paramList.getString(0)); + uid = xmlrpc_c::value_int(paramList.getInt(1)); + + // Only oneadmin can retrieve user information + rc = UserInfo::upool->authenticate(session); + + if ( rc != 0 ) + { + goto error_authenticate; + } + + // Now let's get the user + user = UserInfo::upool->get(uid,true); + + if ( user == 0 ) + { + goto error_get_user; + } + + oss << *user; + + user->unlock(); + + // All nice, return the new uid to client + arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + // Copy arrayresult into retval mem space + arrayresult = new xmlrpc_c::value_array(arrayData); + *retval = *arrayresult; + + delete arrayresult; // and get rid of the original + + return; + +error_authenticate: + oss << "User not authorized to retrieve user information"; + goto error_common; + +error_get_user: + oss << "Error getting user"; + goto error_common; + +error_common: + + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + Nebula::log("ReM",Log::ERROR,oss); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerUserPoolInfo.cc b/src/rm/RequestManagerUserPoolInfo.cc new file mode 100644 index 0000000..2ba3cc9 --- /dev/null +++ b/src/rm/RequestManagerUserPoolInfo.cc @@ -0,0 +1,93 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad */ +/* Complutense de Madrid (dsa-research.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#include "RequestManager.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManager::UserPoolInfo::execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retval) +{ + string session; + + int rc; + ostringstream oss; + + /* -- RPC specific vars -- */ + vector arrayData; + xmlrpc_c::value_array * arrayresult; + + Nebula::log("ReM",Log::DEBUG,"UserPoolInfo method invoked"); + + // Get the parameters + session = xmlrpc_c::value_string(paramList.getString(0)); + + // Only oneadmin can list the whole user pool + rc = UserPoolInfo::upool->authenticate(session); + + if ( rc != 0 ) + { + goto error_authenticate; + } + + // Now let's get the info + + rc = UserPoolInfo::upool->dump(oss,""); + + if ( rc != 0 ) + { + goto error_dumping; + } + + // All nice, return the new uid to client + arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + arrayresult = new xmlrpc_c::value_array(arrayData); + // Copy arrayresult into retval mem space + *retval = *arrayresult; + // and get rid of the original + delete arrayresult; + + return; + +error_authenticate: + oss << "User not authorized to pull user pool info. Error code: " << rc; + goto error_common; + +error_dumping: + oss << "Error dumping pool info"; + goto error_common; + +error_common: + + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + Nebula::log("ReM",Log::ERROR,oss); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerVirtualNetworkAllocate.cc b/src/rm/RequestManagerVirtualNetworkAllocate.cc index e7e3d01..31b85fd 100644 --- a/src/rm/RequestManagerVirtualNetworkAllocate.cc +++ b/src/rm/RequestManagerVirtualNetworkAllocate.cc @@ -26,14 +26,17 @@ void RequestManager::VirtualNetworkAllocate::execute( xmlrpc_c::value * const retval) { string session; - + string username; + string password; string name; string stemplate; int nid; - + int uid; int rc; + User * user; + ostringstream oss; /* -- RPC specific vars -- */ @@ -45,8 +48,25 @@ void RequestManager::VirtualNetworkAllocate::execute( // Get the parameters & host session = xmlrpc_c::value_string(paramList.getString(0)); stemplate = xmlrpc_c::value_string(paramList.getString(1)); + + if ( User::split_secret(session,username,password) != 0 ) + { + goto error_session; + } - rc = vnpool->allocate(0,stemplate,&nid); + // Now let's get the user + user = VirtualNetworkAllocate::upool->get(username,true); + + if ( user == 0 ) + { + goto error_get_user; + } + + uid = user->get_uid(); + + user->unlock(); + + rc = vnpool->allocate(uid,stemplate,&nid); if ( rc != 0 ) { @@ -64,9 +84,20 @@ void RequestManager::VirtualNetworkAllocate::execute( return; + +error_session: + oss << "Session information malformed, cannot allocate VirtualNetwork"; + goto error_common; + +error_get_user: + oss << "User not recognized, cannot allocate VirtualNetwork"; + goto error_common; + error_vn_allocate: - oss << "Error allocating VN with template: " << endl << stemplate; + goto error_common; + +error_common: Nebula::log("ReM",Log::ERROR,oss); arrayData.push_back(xmlrpc_c::value_boolean(false)); diff --git a/src/rm/RequestManagerVirtualNetworkDelete.cc b/src/rm/RequestManagerVirtualNetworkDelete.cc index 4e2da80..5bf628a 100644 --- a/src/rm/RequestManagerVirtualNetworkDelete.cc +++ b/src/rm/RequestManagerVirtualNetworkDelete.cc @@ -29,7 +29,8 @@ void RequestManager::VirtualNetworkDelete::execute( string name; int nid; - + int uid; + VirtualNetwork * vn; int rc; @@ -45,13 +46,23 @@ void RequestManager::VirtualNetworkDelete::execute( session = xmlrpc_c::value_string(paramList.getString(0)); nid = xmlrpc_c::value_int (paramList.getInt (1)); - // Perform the allocation in the hostpool + // Retrieve VN from the pool vn = vnpool->get(nid,true); if ( vn == 0 ) { goto error_vn_get; } + + uid = vn->get_uid(); + + // Only oneadmin or the VN owner can perform operations upon the VN + rc = VirtualNetworkDelete::upool->authenticate(session); + + if ( rc != 0 && rc != uid) + { + goto error_authenticate; + } rc = vnpool->drop(vn); @@ -66,9 +77,16 @@ void RequestManager::VirtualNetworkDelete::execute( return; -error_vn_get: +error_authenticate: + vn->unlock(); + oss << "User cannot delete VN"; + goto error_common; +error_vn_get: oss << "Error getting Virtual Network with NID = " << nid; + goto error_common; + +error_common: Nebula::log ("Rem",Log::ERROR,oss); arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE diff --git a/src/rm/RequestManagerVirtualNetworkInfo.cc b/src/rm/RequestManagerVirtualNetworkInfo.cc index e9a7c31..3190596 100644 --- a/src/rm/RequestManagerVirtualNetworkInfo.cc +++ b/src/rm/RequestManagerVirtualNetworkInfo.cc @@ -28,6 +28,7 @@ void RequestManager::VirtualNetworkInfo::execute( string session; int nid; + int rc; string info; VirtualNetwork * vn; @@ -43,30 +44,42 @@ void RequestManager::VirtualNetworkInfo::execute( // Get the parameters & host session = xmlrpc_c::value_string(paramList.getString(0)); nid = xmlrpc_c::value_int (paramList.getInt (1)); - + + // Check if it is a valid user + rc = VirtualNetworkInfo::upool->authenticate(session); + + if ( rc == -1 ) + { + goto error_authenticate; + } + vn = vnpool->get(nid,true); if ( vn == 0 ) { goto error_vn_get; } - - // All nice, return the Virtual Network info to the client - arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS - oss.str(""); + oss << *vn; vn->unlock(); - + + // All nice, return the Virtual Network info to the client + arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS arrayData.push_back(xmlrpc_c::value_string(oss.str())); - arrayresult = new xmlrpc_c::value_array(arrayData); + // Copy arrayresult into retval mem space + arrayresult = new xmlrpc_c::value_array(arrayData); *retval = *arrayresult; - // and get rid of the original - delete arrayresult; + + delete arrayresult; // and get rid of the original return; +error_authenticate: + oss << "User not authenticated, VirtualNetworkInfo call aborted."; + goto error_common; + error_vn_get: oss << "Error getting Virtual Network with NID = " << nid; goto error_common; diff --git a/src/rm/RequestManagerVirtualNetworkPoolInfo.cc b/src/rm/RequestManagerVirtualNetworkPoolInfo.cc new file mode 100755 index 0000000..767c495 --- /dev/null +++ b/src/rm/RequestManagerVirtualNetworkPoolInfo.cc @@ -0,0 +1,135 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad */ +/* Complutense de Madrid (dsa-research.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#include "RequestManager.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManager::VirtualNetworkPoolInfo::execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retval) +{ + string session; + string username; + string password; + + ostringstream oss; + ostringstream where_string; + + int rc; + int filter_flag; + + User * user; + + /* -- RPC specific vars -- */ + vector arrayData; + xmlrpc_c::value_array * arrayresult; + + Nebula::log("ReM",Log::DEBUG,"VirtualNetworkPoolInfo method invoked"); + + // Get the parameters + session = xmlrpc_c::value_string(paramList.getString(0)); + filter_flag = xmlrpc_c::value_int(paramList.getInt(1)); + + // Check if it is a valid user + rc = VirtualNetworkPoolInfo::upool->authenticate(session); + + if ( rc == -1 ) + { + goto error_authenticate; + } + + where_string.str(""); + + /** Filter flag meaning table + * <=-2 :: ALL VMs + * -1 :: User's VMs + * >=0 :: UID User's VMs + **/ + if (filter_flag == -1) + { + User::split_secret(session,username,password); + + // Now let's get the user + user = VirtualNetworkPoolInfo::upool->get(username,true); + + if ( user == 0 ) + { + goto error_get_user; + } + + where_string << "UID=" << user->get_uid(); + + user->unlock(); + } + else if (filter_flag>=0) + { + where_string << "UID=" << filter_flag; + } + + // Perform the allocation in the vmpool + rc = VirtualNetworkPoolInfo::vnpool->dump(oss,where_string.str()); + + if ( rc != 0 ) + { + goto error_dump; + } + + //All nice, return the host info to the client + arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + arrayresult = new xmlrpc_c::value_array(arrayData); + + // Copy arrayresult into retval mem space + *retval = *arrayresult; + + // and get rid of the original + delete arrayresult; + + return; + +error_authenticate: + oss << "User not authenticated, NetworkPoolInfo call aborted."; + goto error_common; + +error_get_user: + oss << "Error getting user, aborting NetworkPoolInfo call"; + goto error_common; + +error_dump: + oss << "Error getting virtual network pool"; + goto error_common; + +error_common: + + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(oss.str())); + + Nebula::log("ReM",Log::ERROR,oss); + + xmlrpc_c::value_array arrayresult_error(arrayData); + + *retval = arrayresult_error; + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ diff --git a/src/rm/SConstruct b/src/rm/SConstruct index cbf9755..9fa0236 100644 --- a/src/rm/SConstruct +++ b/src/rm/SConstruct @@ -33,10 +33,16 @@ source_files=[ 'RequestManagerHostAllocate.cc', 'RequestManagerHostDelete.cc', 'RequestManagerHostInfo.cc', + 'RequestManagerHostPoolInfo.cc', 'RequestManagerHostEnable.cc', 'RequestManagerVirtualNetworkAllocate.cc', 'RequestManagerVirtualNetworkInfo.cc', + 'RequestManagerVirtualNetworkPoolInfo.cc', 'RequestManagerVirtualNetworkDelete.cc', + 'RequestManagerUserAllocate.cc', + 'RequestManagerUserInfo.cc', + 'RequestManagerUserDelete.cc', + 'RequestManagerUserPoolInfo.cc' ] # Build library diff --git a/src/scheduler/SConstruct b/src/scheduler/SConstruct index 4a0cbc3..d0ebfc3 100644 --- a/src/scheduler/SConstruct +++ b/src/scheduler/SConstruct @@ -41,6 +41,7 @@ env.StaticLibrary(lib_name, source_files) env.Append(LIBS=[ 'sqlite3', + 'crypto', lib_name, 'nebula_core', 'nebula_host', @@ -49,6 +50,7 @@ env.Append(LIBS=[ 'nebula_pool', 'nebula_template', 'nebula_common', + 'nebula_um', ]) diff --git a/src/scheduler/Scheduler.cc b/src/scheduler/Scheduler.cc index d965890..864e8b6 100644 --- a/src/scheduler/Scheduler.cc +++ b/src/scheduler/Scheduler.cc @@ -31,6 +31,7 @@ #include "Scheduler.h" #include "RankPolicy.h" #include "Nebula.h" +#include "User.h" using namespace std; @@ -87,6 +88,24 @@ void Scheduler::start() throw; } + const char * one_auth; + string one_name; + string one_pass; + + one_auth = getenv("ONE_AUTH"); + + if (!one_auth) + { + throw runtime_error("ONE_AUTH variable not defined"); + } + + if ( User::split_secret(one_auth,one_name,one_pass) != 0 ) + { + throw runtime_error("ONE_AUTH must be :"); + } + + secret = one_name + ":" + User::sha1_digest(one_pass); + // ----------------------------------------------------------- // Pools // ----------------------------------------------------------- @@ -421,10 +440,10 @@ void Scheduler::dispatch() { xmlrpc_client.call( one_url, - "one.vmdeploy", + "one.vm.deploy", "sii", &deploy_result, - "session", + secret.c_str(), vm->get_oid(), hid); } diff --git a/src/tm/TransferManager.cc b/src/tm/TransferManager.cc index 06ae3b5..3ad2a86 100644 --- a/src/tm/TransferManager.cc +++ b/src/tm/TransferManager.cc @@ -97,10 +97,22 @@ void TransferManager::trigger(Actions action, int _vid) aname = "EPILOG_STOP"; break; + case EPILOG_DELETE: + aname = "EPILOG_DELETE"; + break; + + case EPILOG_DELETE_PREVIOUS: + aname = "EPILOG_DELETE_PREVIOUS"; + break; + case CHECKPOINT: aname = "CHECKPOINT"; break; + case DRIVER_CANCEL: + aname = "DRIVER_CANCEL"; + break; + case FINALIZE: aname = ACTION_FINALIZE; break; @@ -149,10 +161,22 @@ void TransferManager::do_action(const string &action, void * arg) { epilog_stop_action(vid); } + else if (action == "EPILOG_DELETE") + { + epilog_delete_action(vid); + } + else if (action == "EPILOG_DELETE_PREVIOUS") + { + epilog_delete_previous_action(vid); + } else if (action == "CHECKPOINT") { checkpoint_action(vid); } + else if (action == "DRIVER_CANCEL") + { + driver_cancel_action(vid); + } else if (action == ACTION_FINALIZE) { Nebula::log("TrM",Log::INFO,"Stopping Transfer Manager..."); @@ -217,7 +241,8 @@ void TransferManager::prolog_action(int vid) goto error_driver; } - xfr.open(vm->get_transfer_file().c_str(), ios::out | ios::trunc); + xfr_name = vm->get_transfer_file() + ".prolog"; + xfr.open(xfr_name.c_str(), ios::out | ios::trunc); if (xfr.fail() == true) { @@ -356,7 +381,7 @@ void TransferManager::prolog_action(int vid) xfr.close(); - tm_md->transfer(vid,vm->get_transfer_file()); + tm_md->transfer(vid,xfr_name); vm->unlock(); @@ -374,7 +399,7 @@ void TransferManager::prolog_action(int vid) error_file: os.str(""); - os << "prolog, could not open file: " << vm->get_transfer_file(); + os << "prolog, could not open file: " << xfr_name; goto error_common; error_driver: @@ -386,7 +411,6 @@ void TransferManager::prolog_action(int vid) os.str(""); os << "prolog, undefined source disk image in VM template"; xfr.close(); - goto error_common; error_common: (nd.get_lcm())->trigger(LifeCycleManager::PROLOG_FAILURE,vid); @@ -403,6 +427,7 @@ void TransferManager::prolog_migr_action(int vid) { ofstream xfr; ostringstream os; + string xfr_name; VirtualMachine * vm; Nebula& nd = Nebula::instance(); @@ -433,7 +458,8 @@ void TransferManager::prolog_migr_action(int vid) goto error_driver; } - xfr.open(vm->get_transfer_file().c_str(), ios::out | ios::trunc); + xfr_name = vm->get_transfer_file() + ".migrate"; + xfr.open(xfr_name.c_str(), ios::out | ios::trunc); if (xfr.fail() == true) { @@ -450,7 +476,7 @@ void TransferManager::prolog_migr_action(int vid) xfr.close(); - tm_md->transfer(vid,vm->get_transfer_file()); + tm_md->transfer(vid,xfr_name); vm->unlock(); @@ -463,13 +489,12 @@ void TransferManager::prolog_migr_action(int vid) error_file: os.str(""); - os << "prolog_migr, could not open file: " << vm->get_transfer_file(); + os << "prolog_migr, could not open file: " << xfr_name; goto error_common; error_driver: os.str(""); os << "prolog_migr, error getting driver " << vm->get_tm_mad(); - goto error_common; error_common: (nd.get_lcm())->trigger(LifeCycleManager::PROLOG_FAILURE,vid); @@ -477,8 +502,6 @@ void TransferManager::prolog_migr_action(int vid) vm->unlock(); return; - - (nd.get_lcm())->trigger(LifeCycleManager::PROLOG_SUCCESS,vid); } /* -------------------------------------------------------------------------- */ @@ -488,6 +511,7 @@ void TransferManager::prolog_resume_action(int vid) { ofstream xfr; ostringstream os; + string xfr_name; VirtualMachine * vm; Nebula& nd = Nebula::instance(); @@ -518,7 +542,8 @@ void TransferManager::prolog_resume_action(int vid) goto error_driver; } - xfr.open(vm->get_transfer_file().c_str(), ios::out | ios::trunc); + xfr_name = vm->get_transfer_file() + ".resume"; + xfr.open(xfr_name.c_str(), ios::out | ios::trunc); if (xfr.fail() == true) { @@ -535,7 +560,7 @@ void TransferManager::prolog_resume_action(int vid) xfr.close(); - tm_md->transfer(vid,vm->get_transfer_file()); + tm_md->transfer(vid,xfr_name); vm->unlock(); @@ -548,13 +573,12 @@ void TransferManager::prolog_resume_action(int vid) error_file: os.str(""); - os << "prolog_resume, could not open file: " << vm->get_transfer_file(); + os << "prolog_resume, could not open file: " << xfr_name; goto error_common; error_driver: os.str(""); os << "prolog_resume, error getting driver " << vm->get_tm_mad(); - goto error_common; error_common: (nd.get_lcm())->trigger(LifeCycleManager::PROLOG_FAILURE,vid); @@ -575,9 +599,7 @@ void TransferManager::epilog_action(int vid) string xfr_name; const VectorAttribute * disk; - string source; string save; - string clon; VirtualMachine * vm; Nebula& nd = Nebula::instance(); @@ -587,7 +609,6 @@ void TransferManager::epilog_action(int vid) vector attrs; int num; - // ------------------------------------------------------------------------ // Setup & Transfer script // ------------------------------------------------------------------------ @@ -611,7 +632,8 @@ void TransferManager::epilog_action(int vid) goto error_driver; } - xfr.open(vm->get_transfer_file().c_str(), ios::out | ios::trunc); + xfr_name = vm->get_transfer_file() + ".epilog"; + xfr.open(xfr_name.c_str(), ios::out | ios::trunc); if (xfr.fail() == true) { @@ -655,7 +677,7 @@ void TransferManager::epilog_action(int vid) xfr.close(); - tm_md->transfer(vid,vm->get_transfer_file()); + tm_md->transfer(vid,xfr_name); vm->unlock(); @@ -668,13 +690,12 @@ void TransferManager::epilog_action(int vid) error_file: os.str(""); - os << "epilog, could not open file: " << vm->get_transfer_file(); + os << "epilog, could not open file: " << xfr_name; goto error_common; error_driver: os.str(""); os << "epilog, error getting driver " << vm->get_vmm_mad(); - goto error_common; error_common: (nd.get_lcm())->trigger(LifeCycleManager::EPILOG_FAILURE,vid); @@ -691,6 +712,7 @@ void TransferManager::epilog_stop_action(int vid) { ofstream xfr; ostringstream os; + string xfr_name; VirtualMachine * vm; Nebula& nd = Nebula::instance(); @@ -721,7 +743,8 @@ void TransferManager::epilog_stop_action(int vid) goto error_driver; } - xfr.open(vm->get_transfer_file().c_str(), ios::out | ios::trunc); + xfr_name = vm->get_transfer_file() + ".stop"; + xfr.open(xfr_name.c_str(), ios::out | ios::trunc); if (xfr.fail() == true) { @@ -738,7 +761,7 @@ void TransferManager::epilog_stop_action(int vid) xfr.close(); - tm_md->transfer(vid,vm->get_transfer_file()); + tm_md->transfer(vid,xfr_name); vm->unlock(); @@ -751,13 +774,12 @@ void TransferManager::epilog_stop_action(int vid) error_file: os.str(""); - os << "epilog_stop, could not open file: " << vm->get_transfer_file(); + os << "epilog_stop, could not open file: " << xfr_name; goto error_common; error_driver: os.str(""); os << "epilog_stop, error getting driver " << vm->get_tm_mad(); - goto error_common; error_common: (nd.get_lcm())->trigger(LifeCycleManager::EPILOG_FAILURE,vid); @@ -767,6 +789,236 @@ void TransferManager::epilog_stop_action(int vid) return; } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void TransferManager::epilog_delete_action(int vid) +{ + ofstream xfr; + ostringstream os; + string xfr_name; + + VirtualMachine * vm; + + const TransferManagerDriver * tm_md; + + // ------------------------------------------------------------------------ + // Setup & Transfer script + // ------------------------------------------------------------------------ + + vm = vmpool->get(vid,true); + + if (vm == 0) + { + return; + } + + if (!vm->hasHistory()) + { + goto error_history; + } + + tm_md = get(vm->get_uid(),vm->get_tm_mad()); + + if ( tm_md == 0 ) + { + goto error_driver; + } + + xfr_name = vm->get_transfer_file() + ".delete"; + xfr.open(xfr_name.c_str(), ios::out | ios::trunc); + + if (xfr.fail() == true) + { + goto error_file; + } + + // ------------------------------------------------------------------------ + // Delete the remote VM Directory + // ------------------------------------------------------------------------ + + xfr << "DELETE " << vm->get_hostname() <<":"<< vm->get_remote_dir() << endl; + + xfr.close(); + + tm_md->transfer(vid,xfr_name); + + vm->unlock(); + + return; + +error_history: + os.str(""); + os << "epilog_delete, VM " << vid << " has no history"; + goto error_common; + +error_file: + os.str(""); + os << "epilog_delete, could not open file: " << xfr_name; + os << ". You may need to manually clean " << vm->get_hostname() + << ":" << vm->get_remote_dir(); + goto error_common; + +error_driver: + os.str(""); + os << "epilog_delete, error getting driver " << vm->get_vmm_mad(); + os << ". You may need to manually clean " << vm->get_hostname() + << ":" << vm->get_remote_dir(); + +error_common: + vm->log("TM", Log::ERROR, os); + vm->unlock(); + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void TransferManager::epilog_delete_previous_action(int vid) +{ + ofstream xfr; + ostringstream os; + string xfr_name; + + VirtualMachine * vm; + + const TransferManagerDriver * tm_md; + + // ------------------------------------------------------------------------ + // Setup & Transfer script + // ------------------------------------------------------------------------ + + vm = vmpool->get(vid,true); + + if (vm == 0) + { + return; + } + + if (!vm->hasHistory() || !vm->hasPreviousHistory()) + { + goto error_history; + } + + tm_md = get(vm->get_uid(),vm->get_previous_tm_mad()); + + if ( tm_md == 0 ) + { + goto error_driver; + } + + xfr_name = vm->get_transfer_file() + ".delete_prev"; + xfr.open(xfr_name.c_str(),ios::out | ios::trunc); + + if (xfr.fail() == true) + { + goto error_file; + } + + // ------------------------------------------------------------------------ + // Delete the remote VM Directory + // ------------------------------------------------------------------------ + + xfr << "DELETE " << vm->get_previous_hostname() <<":"<< vm->get_remote_dir() + << endl; + + xfr.close(); + + tm_md->transfer(vid,xfr_name); + + vm->unlock(); + + return; + +error_history: + os.str(""); + os << "epilog_delete_previous, VM " << vid << " has no history"; + goto error_common; + +error_file: + os.str(""); + os << "epilog_delete, could not open file: " << xfr_name; + os << ". You may need to manually clean " << vm->get_previous_hostname() + << ":" << vm->get_remote_dir(); + goto error_common; + +error_driver: + os.str(""); + os << "epilog_delete, error getting driver " << vm->get_vmm_mad(); + os << ". You may need to manually clean " << vm->get_previous_hostname() + << ":" << vm->get_remote_dir(); + +error_common: + vm->log("TM", Log::ERROR, os); + vm->unlock(); + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void TransferManager::driver_cancel_action(int vid) +{ + ofstream xfr; + ostringstream os; + string xfr_name; + + VirtualMachine * vm; + + const TransferManagerDriver * tm_md; + + // ------------------------------------------------------------------------ + // Get the Driver for this host + // ------------------------------------------------------------------------ + + vm = vmpool->get(vid,true); + + if (vm == 0) + { + return; + } + + if (!vm->hasHistory()) + { + goto error_history; + } + + tm_md = get(vm->get_uid(),vm->get_tm_mad()); + + if ( tm_md == 0 ) + { + goto error_driver; + } + + // ------------------------------------------------------------------------ + // Cancel the current operation + // ------------------------------------------------------------------------ + + tm_md->driver_cancel(vid); + + vm->unlock(); + + return; + +error_history: + os.str(""); + os << "driver_cancel, VM " << vid << " has no history"; + goto error_common; + +error_driver: + os.str(""); + os << "driver_cancel, error getting driver " << vm->get_vmm_mad(); + +error_common: + vm->log("TM", Log::ERROR, os); + vm->unlock(); + + return; +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/src/tm/TransferManagerDriver.cc b/src/tm/TransferManagerDriver.cc index 0c817bb..9191eb0 100644 --- a/src/tm/TransferManagerDriver.cc +++ b/src/tm/TransferManagerDriver.cc @@ -95,6 +95,18 @@ void TransferManagerDriver::protocol( return; } + if ( vm->get_lcm_state() == VirtualMachine::DELETE || + vm->get_lcm_state() == VirtualMachine::FAILURE|| + vm->get_lcm_state() == VirtualMachine::LCM_INIT ) + { + os.str(""); + os << "Ignored: " << message; + vm->log("TM",Log::WARNING,os); + + vm->unlock(); + return; + } + // Driver Actions if (action == "TRANSFER") { diff --git a/src/tm_mad/ssh/tm_clone.sh b/src/tm_mad/ssh/tm_clone.sh index 3492cb4..f6a2852 100755 --- a/src/tm_mad/ssh/tm_clone.sh +++ b/src/tm_mad/ssh/tm_clone.sh @@ -46,7 +46,7 @@ exec_and_log "ssh $DST_HOST mkdir -p $DST_DIR" case $SRC in http://*) log "Downloading $SRC" - exec_and_log "ssh $DST_HOST wget -O $DST_PATH $SRC_PATH" + exec_and_log "ssh $DST_HOST wget -O $DST_PATH $SRC" ;; *) diff --git a/src/um/SConstruct b/src/um/SConstruct new file mode 100644 index 0000000..7f92eba --- /dev/null +++ b/src/um/SConstruct @@ -0,0 +1,31 @@ +# SConstruct for src/vm + +# -------------------------------------------------------------------------- # +# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad # +# Complutense de Madrid (dsa-research.org) # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +Import('env') + +lib_name='nebula_um' + +# Sources to generate the library +source_files=[ + 'User.cc', + 'UserPool.cc' +] + +# Build library +env.StaticLibrary(lib_name, source_files) diff --git a/src/um/User.cc b/src/um/User.cc new file mode 100644 index 0000000..a5565bc --- /dev/null +++ b/src/um/User.cc @@ -0,0 +1,396 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2009, Distributed Systems Architecture Group, Universidad */ +/* Complutense de Madrid (dsa-research.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include "User.h" + +/* ************************************************************************** */ +/* User :: Constructor/Destructor */ +/* ************************************************************************** */ + +User::User( + int id, + string _username, + string _password, + bool _enabled): + PoolObjectSQL(id), + username (_username), + password (_password), + enabled (_enabled) + {}; + + +User::~User(){}; + +/* ************************************************************************** */ +/* User :: Database Access Functions */ +/* ************************************************************************** */ + +const char * User::table = "user_pool"; + +const char * User::db_names = "(oid,user_name,password,enabled)"; + +const char * User::db_bootstrap = "CREATE TABLE user_pool (" + "oid INTEGER,user_name TEXT,password TEXT," + "enabled INTEGER, PRIMARY KEY(oid,user_name), UNIQUE(user_name))"; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int User::unmarshall(int num, char **names, char ** values) +{ + if ((!values[OID]) || + (!values[USERNAME]) || + (!values[PASSWORD]) || + (!values[ENABLED]) || + (num != LIMIT )) + { + return -1; + } + + oid = atoi(values[OID]); + username = values[USERNAME]; + password = values[PASSWORD]; + enabled = (atoi(values[ENABLED])==0)?false:true; + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +extern "C" int user_select_cb ( + void * _user, + int num, + char ** values, + char ** names) +{ + User * user; + + user = static_cast(_user); + + if (user == 0) + { + return -1; + } + + return user->unmarshall(num,names,values); +}; + +/* -------------------------------------------------------------------------- */ + +int User::select(SqliteDB *db) +{ + ostringstream oss; + int rc; + int boid; + + oss << "SELECT * FROM " << table << " WHERE oid = " << oid; + + boid = oid; + oid = -1; + + rc = db->exec(oss, user_select_cb, (void *) this); + + if ((rc != 0) || (oid != boid )) + { + return -1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int User::insert(SqliteDB *db) +{ + int rc; + + rc = update(db); + + if ( rc != 0 ) + { + return rc; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int User::update(SqliteDB *db) +{ + ostringstream oss; + + int rc; + + char * sql_username; + char * sql_password; + + int str_enabled = enabled?1:0; + + // Update the User + + sql_username = sqlite3_mprintf("%q",username.c_str()); + + if ( sql_username == 0 ) + { + goto error_username; + } + + sql_password = sqlite3_mprintf("%q",password.c_str()); + + if ( sql_password == 0 ) + { + goto error_password; + } + + // Construct the SQL statement to Insert or Replace (effectively, update) + + oss << "INSERT OR REPLACE INTO " << table << " "<< db_names <<" VALUES (" + << oid << "," + << "'" << sql_username << "'," + << "'" << sql_password << "'," + << str_enabled << ")"; + + rc = db->exec(oss); + + sqlite3_free(sql_username); + sqlite3_free(sql_password); + + return rc; + +error_password: + sqlite3_free(sql_username); +error_username: + return -1; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int User::unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values) +{ + if ((!values[OID]) || + (!values[USERNAME]) || + (!values[PASSWORD]) || + (!values[ENABLED]) || + (num != LIMIT)) + { + return -1; + } + + string str_enabled = (atoi(values[ENABLED])==0)?"Fase":"True"; + + oss << + "" << + "" << values[OID] <<"" << + "" << values[USERNAME] <<"" << + "" << values[PASSWORD] <<"" << + "" << str_enabled <<"" << + ""; + + return 0; + +} + +/* -------------------------------------------------------------------------- */ + +extern "C" int user_dump_cb ( + void * _oss, + int num, + char ** values, + char ** names) +{ + ostringstream * oss; + + oss = static_cast(_oss); + + if (oss == 0) + { + return -1; + } + + return User::unmarshall(*oss,num,names,values); +}; + +/* -------------------------------------------------------------------------- */ + +int User::dump(SqliteDB * db, ostringstream& oss, const string& where) +{ + int rc; + ostringstream cmd; + + cmd << "SELECT * FROM " << User::table; + + if ( !where.empty() ) + { + cmd << " WHERE " << where; + } + + rc = db->exec(cmd,user_dump_cb,(void *) &oss); + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int User::drop(SqliteDB * db) +{ + ostringstream oss; + + oss << "DELETE FROM " << table << " WHERE oid=" << oid; + + return db->exec(oss); +} + +/* ************************************************************************** */ +/* User :: Misc */ +/* ************************************************************************** */ + +ostream& operator<<(ostream& os, User& user) +{ + string user_str; + + os << user.to_xml(user_str); + + return os; +}; + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& User::to_xml(string& xml) const +{ + ostringstream oss; + + int enabled_int = enabled?1:0; + + oss << + "" + "" << oid <<"" << + "" << username <<"" << + "" << password <<"" << + "" << enabled_int <<"" << + ""; + + xml = oss.str(); + + return xml; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& User::to_str(string& str) const +{ + ostringstream os; + + string enabled_str = enabled?"True":"False"; + + os << + "ID = " << oid << endl << + "NAME = " << username << endl << + "PASSWORD = " << password << endl << + "ENABLED = " << enabled_str; + + str = os.str(); + + return str; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int User::authenticate(string _password) +{ + if (enabled && _password==password) + { + return oid; + } + else + { + return -1; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int User::split_secret(const string secret, string& user, string& pass) +{ + size_t pos; + int rc = -1; + + pos=secret.find(":"); + + if (pos != string::npos) + { + user = secret.substr(0,pos); + pass = secret.substr(pos+1); + + rc = 0; + } + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string User::sha1_digest(const string& pass) +{ + EVP_MD_CTX mdctx; + unsigned char md_value[EVP_MAX_MD_SIZE]; + unsigned int md_len; + ostringstream oss; + + EVP_MD_CTX_init(&mdctx); + EVP_DigestInit_ex(&mdctx, EVP_sha1(), NULL); + + EVP_DigestUpdate(&mdctx, pass.c_str(), pass.length()); + + EVP_DigestFinal_ex(&mdctx,md_value,&md_len); + EVP_MD_CTX_cleanup(&mdctx); + + for(unsigned int i = 0; i +#include + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +extern "C" +{ + static int getuids_cb( + void * _known_users, + int num, + char ** values, + char ** names) + { + map * known_users; + + known_users = static_cast *>(_known_users); + + if ( num == 0 || values == 0 || values[0] == 0 ) + { + return -1; + } + + known_users->insert(make_pair(values[1],atoi(values[0]))); + + return 0; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +UserPool::UserPool(SqliteDB * db):PoolSQL(db,User::table) +{ + // The known_users table needs to be rebuilt + + ostringstream sql; + + sql << "SELECT oid,user_name FROM " << User::table; + + db->exec(sql, getuids_cb, (void *) &known_users); + + if ((int) known_users.size() == 0) + { + // User oneadmin needs to be added in the bootstrap + struct passwd * pw_ent; + int one_uid = -1; + + ostringstream oss; + + pw_ent = getpwuid(getuid()); + + if ((pw_ent != NULL) && (pw_ent->pw_name != NULL)) + { + string one_name; + string one_pass; + + const char * one_auth; + + one_name = pw_ent->pw_name; + one_auth = getenv("ONE_AUTH"); + + if ( one_auth != 0 ) + { + if ( User::split_secret(one_auth,one_name,one_pass) == 0 ) + { + string sha1_pass = User::sha1_digest(one_pass); + + allocate(&one_uid, one_name, sha1_pass, true); + } + else + { + oss << "ONE_AUTH must be :"; + } + } + else + { + oss << "Environment variable ONE_AUTH is not set"; + } + } + else + { + oss << "Error getting the user info"; + } + + if (one_uid != 0) + { + Nebula::log("ONE",Log::ERROR,oss); + throw; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int UserPool::allocate ( + int * oid, + string username, + string password, + bool enabled) +{ + User * user; + + // Build a new User object + + user = new User(-1, + username, + password, + enabled); + + // Insert the Object in the pool + + *oid = PoolSQL::allocate(user); + + // Add the user to the map of known_users + known_users.insert(make_pair(username,*oid)); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int UserPool::authenticate(string& session) +{ + map::iterator index; + + string username; + string password; + + int user_id = -1; + + // session holds username:password + + if ( User::split_secret(session,username,password) == 0 ) + { + index = known_users.find(username); + + if ( index != known_users.end() ) + { + User * user = get((int)index->second,false); + user_id = user->authenticate(password); + } + } + + return user_id; +} diff --git a/src/vm/History.cc b/src/vm/History.cc index 3e494dd..ac2dc4f 100644 --- a/src/vm/History.cc +++ b/src/vm/History.cc @@ -221,51 +221,51 @@ int History::insert(SqliteDB * db) int History::unmarshall(int num, char **names, char ** values) { - if ((values[VID] == 0) || - (values[SEQ] == 0) || - (values[HOSTNAME] == 0) || - (values[VM_DIR] == 0) || - (values[HID] == 0) || - (values[VMMMAD] == 0) || - (values[TMMAD] == 0) || - (values[STIME] == 0) || - (values[ETIME] == 0) || - (values[PROLOG_STIME] == 0) || - (values[PROLOG_ETIME] == 0) || - (values[RUNNING_STIME] == 0) || - (values[RUNNING_ETIME] == 0) || - (values[EPILOG_STIME] == 0) || - (values[EPILOG_ETIME] == 0) || - (values[REASON] == 0) || - (num != LIMIT )) + if ((!values[VID]) || + (!values[SEQ]) || + (!values[HOSTNAME]) || + (!values[VM_DIR]) || + (!values[HID]) || + (!values[VMMMAD]) || + (!values[TMMAD]) || + (!values[STIME]) || + (!values[ETIME]) || + (!values[PROLOG_STIME]) || + (!values[PROLOG_ETIME]) || + (!values[RUNNING_STIME]) || + (!values[RUNNING_ETIME]) || + (!values[EPILOG_STIME]) || + (!values[EPILOG_ETIME]) || + (!values[REASON]) || + (num != LIMIT )) { return -1; } - oid = atoi(values[VID]); - seq = atoi(values[SEQ]); + oid = atoi(values[VID]); + seq = atoi(values[SEQ]); + + hostname = values[HOSTNAME]; + vm_dir = values[VM_DIR]; + + hid = atoi(values[HID]); - hostname = values[HOSTNAME]; - vm_dir = values[VM_DIR]; + vmm_mad_name = values[VMMMAD]; + tm_mad_name = values[TMMAD]; - hid = atoi(values[HID]); + stime = static_cast(atoi(values[STIME])); + etime = static_cast(atoi(values[ETIME])); - vmm_mad_name = values[VMMMAD]; - tm_mad_name = values[TMMAD]; - - stime = static_cast(atoi(values[STIME])); - etime = static_cast(atoi(values[ETIME])); - - prolog_stime = static_cast(atoi(values[PROLOG_STIME])); - prolog_etime = static_cast(atoi(values[PROLOG_ETIME])); + prolog_stime = static_cast(atoi(values[PROLOG_STIME])); + prolog_etime = static_cast(atoi(values[PROLOG_ETIME])); running_stime = static_cast(atoi(values[RUNNING_STIME])); running_etime = static_cast(atoi(values[RUNNING_ETIME])); - epilog_stime = static_cast(atoi(values[EPILOG_STIME])); - epilog_etime = static_cast(atoi(values[EPILOG_ETIME])); + epilog_stime = static_cast(atoi(values[EPILOG_STIME])); + epilog_etime = static_cast(atoi(values[EPILOG_ETIME])); - reason = static_cast(atoi(values[REASON])); + reason = static_cast(atoi(values[REASON])); return 0; } @@ -273,6 +273,51 @@ int History::unmarshall(int num, char **names, char ** values) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +int History::unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values) +{ + if ((!values[VID])|| + (!values[SEQ])|| + (!values[HOSTNAME])|| + (!values[HID])|| + (!values[STIME])|| + (!values[ETIME])|| + (!values[PROLOG_STIME])|| + (!values[PROLOG_ETIME])|| + (!values[RUNNING_STIME])|| + (!values[RUNNING_ETIME])|| + (!values[EPILOG_STIME])|| + (!values[EPILOG_ETIME])|| + (!values[REASON])|| + (num != LIMIT)) + { + return -1; + } + + oss << + "" << + "" << values[SEQ] << "" << + ""<< values[HOSTNAME] << ""<< + "" << values[HID] << "" << + "" << values[STIME] << "" << + "" << values[ETIME] << "" << + "" << values[PROLOG_STIME] << "" << + "" << values[PROLOG_ETIME] << "" << + "" << values[RUNNING_STIME] << "" << + "" << values[RUNNING_ETIME] << "" << + "" << values[EPILOG_STIME] << "" << + "" << values[EPILOG_ETIME] << "" << + "" << values[REASON] << "" << + ""; + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + extern "C" int history_select_cb ( void * _history, int num, @@ -337,3 +382,67 @@ int History::drop(SqliteDB * db) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +ostream& operator<<(ostream& os, const History& history) +{ + string history_str; + + os << history.to_xml(history_str); + + return os; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + + +string& History::to_str(string& str) const +{ + ostringstream oss; + + oss<< "\tSEQ = " << seq << endl + << "\tHOSTNAME = " << hostname << endl + << "\tHID = " << hid << endl + << "\tSTIME = " << stime << endl + << "\tETIME = " << etime << endl + << "\tPSTIME = " << prolog_stime << endl + << "\tPETIME = " << prolog_etime << endl + << "\tRSTIME = " << running_stime << endl + << "\tRETIME = " << running_etime << endl + << "\tESTIME = " << epilog_stime << endl + << "\tEETIME = " << epilog_etime << endl + << "\tREASON = " << reason; + + str = oss.str(); + + return str; + +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& History::to_xml(string& xml) const +{ + ostringstream oss; + + oss << + "" << + "" << seq << "" << + ""<< hostname << ""<< + "" << hid << "" << + "" << stime << "" << + "" << etime << "" << + "" << prolog_stime << ""<< + "" << prolog_etime << ""<< + "" << running_stime << ""<< + "" << running_etime << ""<< + "" << epilog_stime << ""<< + "" << epilog_etime << ""<< + "" << reason << ""<< + ""; + + xml = oss.str(); + + return xml; +} \ No newline at end of file diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 851fc4e..cece25b 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -39,6 +39,7 @@ VirtualMachine::VirtualMachine(int id): PoolObjectSQL(id), uid(-1), last_poll(0), + name(""), vm_template(), state(INIT), lcm_state(LCM_INIT), @@ -74,12 +75,12 @@ VirtualMachine::~VirtualMachine() const char * VirtualMachine::table = "vm_pool"; -const char * VirtualMachine::db_names = "(oid,uid,last_poll,template_id,state" +const char * VirtualMachine::db_names = "(oid,uid,name,last_poll,template_id,state" ",lcm_state,stime,etime,deploy_id" ",memory,cpu,net_tx,net_rx)"; const char * VirtualMachine::db_bootstrap = "CREATE TABLE vm_pool (" - "oid INTEGER PRIMARY KEY,uid INTEGER," + "oid INTEGER PRIMARY KEY,uid INTEGER,name TEXT," "last_poll INTEGER, template_id INTEGER,state INTEGER,lcm_state INTEGER," "stime INTEGER,etime INTEGER,deploy_id TEXT,memory INTEGER,cpu INTEGER," "net_tx INTEGER,net_rx INTEGER)"; @@ -91,6 +92,7 @@ int VirtualMachine::unmarshall(int num, char **names, char ** values) { if ((values[OID] == 0) || (values[UID] == 0) || + (values[NAME] == 0) || (values[LAST_POLL] == 0) || (values[TEMPLATE_ID] == 0) || (values[STATE] == 0) || @@ -106,8 +108,9 @@ int VirtualMachine::unmarshall(int num, char **names, char ** values) return -1; } - oid = atoi(values[OID]); - uid = atoi(values[UID]); + oid = atoi(values[OID]); + uid = atoi(values[UID]); + name = values[NAME]; last_poll = static_cast(atoi(values[LAST_POLL])); @@ -274,30 +277,30 @@ int VirtualMachine::insert(SqliteDB * db) string value; ostringstream oss; - // ------------------------------------------------------------------------ + // ----------------------------------------------------------------------- // Set a name if the VM has not got one and VM_ID // ------------------------------------------------------------------------ + oss << oid; + value = oss.str(); + + attr = new SingleAttribute("VMID",value); + vm_template.set(attr); + + get_template_attribute("NAME",name); if ( name.empty() == true ) { + oss.str(""); oss << "one-" << oid; - value = oss.str(); - - attr = new SingleAttribute("NAME",value); + name = oss.str(); + attr = new SingleAttribute("NAME",name); vm_template.set(attr); } - oss.str(""); - - oss << oid; - value = oss.str(); - - attr = new SingleAttribute("VMID",value); - - vm_template.set(attr); + this->name = name; // ------------------------------------------------------------------------ // Get network leases @@ -354,16 +357,28 @@ int VirtualMachine::update(SqliteDB * db) ostringstream oss; int rc; - char * sql_deploy_id = sqlite3_mprintf("%q",deploy_id.c_str()); + char * sql_deploy_id; + char * sql_name; + + sql_deploy_id = sqlite3_mprintf("%q",deploy_id.c_str()); if ( sql_deploy_id == 0 ) { return -1; } - + + sql_name = sqlite3_mprintf("%q",name.c_str()); + + if ( sql_name == 0 ) + { + sqlite3_free(sql_deploy_id); + return -1; + } + oss << "INSERT OR REPLACE INTO " << table << " "<< db_names <<" VALUES ("<< oid << "," << uid << "," << + "'" << sql_name << "'," << last_poll << "," << vm_template.id << "," << state << "," << @@ -377,16 +392,65 @@ int VirtualMachine::update(SqliteDB * db) net_rx << ")"; sqlite3_free(sql_deploy_id); + sqlite3_free(sql_name); rc = db->exec(oss); return rc; } - /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +int VirtualMachine::unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values) +{ + if ((!values[OID])|| + (!values[UID])|| + (!values[NAME]) || + (!values[LAST_POLL])|| + (!values[STATE])|| + (!values[LCM_STATE])|| + (!values[STIME])|| + (!values[ETIME])|| + (!values[DEPLOY_ID])|| + (!values[MEMORY])|| + (!values[CPU])|| + (!values[NET_TX])|| + (!values[NET_RX])|| + (num != LIMIT + History::LIMIT + 2 )) + { + return -1; + } + + oss << + "" << + "" << values[OID] << "" << + "" << values[UID] << "" << + "" << values[LIMIT] << ""<< + "" << values[NAME] << "" << + ""<< values[LAST_POLL]<< ""<< + "" << values[STATE] << "" << + ""<< values[LCM_STATE]<< ""<< + "" << values[STIME] << "" << + "" << values[ETIME] << "" << + ""<< values[DEPLOY_ID]<< ""<< + "" << values[MEMORY] << "" << + "" << values[CPU] << "" << + "" << values[NET_TX] << "" << + "" << values[NET_RX] << ""; + + History::unmarshall(oss, num-LIMIT-2, names+LIMIT+1, values+LIMIT+1); + + oss << ""; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + extern "C" int vm_dump_cb ( void * _oss, int num, @@ -403,75 +467,30 @@ extern "C" int vm_dump_cb ( return -1; } - if ((!values[VirtualMachine::OID]) || - (!values[VirtualMachine::UID]) || - (!values[VirtualMachine::LAST_POLL]) || - (!values[VirtualMachine::TEMPLATE_ID]) || - (!values[VirtualMachine::STATE]) || - (!values[VirtualMachine::LCM_STATE]) || - (!values[VirtualMachine::STIME]) || - (!values[VirtualMachine::ETIME]) || - (!values[VirtualMachine::MEMORY]) || - (!values[VirtualMachine::CPU]) || - (!values[VirtualMachine::NET_TX]) || - (!values[VirtualMachine::NET_RX]) || - (num != VirtualMachine::LIMIT+1 )) - { - return -1; - } - - *oss << "" - << "" << atoi(values[VirtualMachine::OID]) << "" - << "" << atoi(values[VirtualMachine::UID]) << "" - << "" - << static_cast(atoi(values[VirtualMachine::LAST_POLL])) - << "" - << "" << atoi(values[VirtualMachine::STATE]) << "" - << "" - << atoi(values[VirtualMachine::LCM_STATE]) - << "" - << "" - << static_cast(atoi(values[VirtualMachine::STIME])) - << "" - << "" - << static_cast(atoi(values[VirtualMachine::ETIME])) - << "" - << "" << atoi(values[VirtualMachine::MEMORY]) << "" - << "" << atoi(values[VirtualMachine::CPU]) << "" - << "" << atoi(values[VirtualMachine::NET_TX]) << "" - << "" << atoi(values[VirtualMachine::NET_RX]) << ""; - - if ( values[VirtualMachine::DEPLOY_ID] != 0 ) - { - *oss << "" << values[VirtualMachine::DEPLOY_ID] - << ""; - } - - if (values[VirtualMachine::LIMIT] != 0) - { - *oss << "" << values[VirtualMachine::LIMIT] << ""; - } - - *oss<< ""; - - return 0; + return VirtualMachine::unmarshall(*oss,num,names,values); }; +/* -------------------------------------------------------------------------- */ + int VirtualMachine::dump(SqliteDB * db, ostringstream& oss, const string& where) { int rc; ostringstream cmd; cmd << "SELECT " << VirtualMachine::table << ".*, " - << History::table << ".host_name FROM " << VirtualMachine::table - << " LEFT OUTER JOIN (SELECT vid, host_name, MAX(seq) FROM " + << "user_pool.user_name, " << History::table << ".* FROM " + << VirtualMachine::table + << " LEFT OUTER JOIN (SELECT *,MAX(seq) FROM " << History::table << " GROUP BY vid) AS " << History::table << " ON " << VirtualMachine::table << ".oid = " - << History::table << ".vid"; + << History::table << ".vid LEFT OUTER JOIN (SELECT oid,user_name FROM " + << "user_pool) AS user_pool ON " + << VirtualMachine::table << ".uid = user_pool.oid WHERE " + << VirtualMachine::table << ".state != " << VirtualMachine::DONE; if ( !where.empty() ) { - cmd << " WHERE" << where; + cmd << " AND " << where; } rc = db->exec(cmd,vm_dump_cb,(void *) &oss); @@ -483,11 +502,11 @@ int VirtualMachine::dump(SqliteDB * db, ostringstream& oss, const string& where) /* -------------------------------------------------------------------------- */ void VirtualMachine::add_history( - int hid, - string& hostname, - string& vm_dir, - string& vmm_mad, - string& tm_mad) + int hid, + string& hostname, + string& vm_dir, + string& vmm_mad, + string& tm_mad) { ostringstream os; int seq; @@ -887,7 +906,7 @@ ostream& operator<<(ostream& os, const VirtualMachine& vm) { string vm_str; - os << vm.to_str(vm_str); + os << vm.to_xml(vm_str); return os; }; @@ -897,27 +916,30 @@ ostream& operator<<(ostream& os, const VirtualMachine& vm) string& VirtualMachine::to_xml(string& xml) const { string template_xml; + string history_xml; + ostringstream oss; oss << "" - << "" << oid << "" - << "" << uid << "" - << "" << last_poll << "" - << "" << state << "" - << "" << lcm_state << "" - << "" << stime << "" - << "" << etime << "" - << "" << memory << "" - << "" << cpu << "" - << "" << net_tx << "" - << "" << net_rx << ""; - - if ( !deploy_id.empty() != 0 ) - { - oss << "" << deploy_id << ""; - } - - oss << vm_template.to_xml(template_xml); + << "" << oid << "" + << "" << uid << "" + << "" << name << "" + << "" << last_poll << "" + << "" << state << "" + << "" << lcm_state << "" + << "" << stime << "" + << "" << etime << "" + << "" << deploy_id << "" + << "" << memory << "" + << "" << cpu << "" + << "" << net_tx << "" + << "" << net_rx << "" + << vm_template.to_xml(template_xml); + + if ( hasHistory() ) + { + oss << history->to_xml(history_xml); + } oss << ""; xml = oss.str(); @@ -929,11 +951,14 @@ string& VirtualMachine::to_xml(string& xml) const string& VirtualMachine::to_str(string& str) const { - string template_xml; + string template_str; + string history_str; + ostringstream oss; - oss<< "VID : " << oid << endl + oss<< "ID : " << oid << endl << "UID : " << uid << endl + << "NAME : " << name << endl << "STATE : " << state << endl << "LCM STATE : " << lcm_state << endl << "DEPLOY ID : " << deploy_id << endl @@ -944,7 +969,12 @@ string& VirtualMachine::to_str(string& str) const << "STOP TIME : " << etime << endl << "NET TX : " << net_tx << endl << "NET RX : " << net_rx << endl - << "Template" << endl << vm_template << endl; + << "Template" << endl << vm_template.to_str(template_str) << endl; + + if ( hasHistory() ) + { + oss << "Last History Record" << endl << history->to_str(history_str); + } str = oss.str(); diff --git a/src/vm/VirtualMachinePool.cc b/src/vm/VirtualMachinePool.cc index 8f711af..37c5dac 100644 --- a/src/vm/VirtualMachinePool.cc +++ b/src/vm/VirtualMachinePool.cc @@ -145,6 +145,7 @@ int VirtualMachinePool::allocate ( bool on_hold) { VirtualMachine * vm; + string name; char * error_msg; int rc, num_attr; @@ -185,9 +186,11 @@ int VirtualMachinePool::allocate ( vm->vm_template.remove("CONTEXT",attrs); + // ------------------------------------------------------------------------ // Insert the Object in the pool // ------------------------------------------------------------------------ + *oid = PoolSQL::allocate(vm); if ( *oid == -1 ) @@ -198,6 +201,7 @@ int VirtualMachinePool::allocate ( // ------------------------------------------------------------------------ // Insert parsed context in the VM template and clean-up // ------------------------------------------------------------------------ + if ((num_attr = (int) attrs.size()) > 0) { generate_context(*oid,attrs[0]); @@ -224,7 +228,8 @@ int VirtualMachinePool::get_running( string where; os << "state == " << VirtualMachine::ACTIVE - << " and lcm_state == " << VirtualMachine::RUNNING; + << " and ( lcm_state == " << VirtualMachine::RUNNING + << " or lcm_state == " << VirtualMachine::UNKNOWN << " )"; where = os.str(); diff --git a/src/vmm/VirtualMachineManager.cc b/src/vmm/VirtualMachineManager.cc index ff37a80..9ee0b22 100644 --- a/src/vmm/VirtualMachineManager.cc +++ b/src/vmm/VirtualMachineManager.cc @@ -122,6 +122,10 @@ void VirtualMachineManager::trigger(Actions action, int _vid) aname = "CANCEL"; break; + case CANCEL_PREVIOUS: + aname = "CANCEL_PREVIOUS"; + break; + case MIGRATE: aname = "MIGRATE"; break; @@ -130,6 +134,10 @@ void VirtualMachineManager::trigger(Actions action, int _vid) aname = "POLL"; break; + case DRIVER_CANCEL: + aname = "DRIVER_CANCEL"; + break; + case FINALIZE: aname = ACTION_FINALIZE; break; @@ -182,6 +190,10 @@ void VirtualMachineManager::do_action(const string &action, void * arg) { cancel_action(vid); } + else if (action == "CANCEL_PREVIOUS") + { + cancel_previous_action(vid); + } else if (action == "MIGRATE") { migrate_action(vid); @@ -190,6 +202,10 @@ void VirtualMachineManager::do_action(const string &action, void * arg) { poll_action(vid); } + else if (action == "DRIVER_CANCEL") + { + driver_cancel_action(vid); + } else if (action == ACTION_TIMER) { timer_action(); @@ -274,7 +290,6 @@ void VirtualMachineManager::deploy_action(int vid) error_file: os.str(""); os << "deploy_action, error generating deployment file: " << vm->get_deployment_file(); - goto error_common; error_common: Nebula &ne = Nebula::instance(); @@ -283,7 +298,6 @@ void VirtualMachineManager::deploy_action(int vid) lcm->trigger(LifeCycleManager::DEPLOY_FAILURE, vid); vm->log("VMM", Log::ERROR, os); - vm->unlock(); return; } @@ -366,7 +380,6 @@ void VirtualMachineManager::save_action( lcm->trigger(LifeCycleManager::SAVE_FAILURE, vid); vm->log("VMM", Log::ERROR, os); - vm->unlock(); return; } @@ -416,7 +429,6 @@ void VirtualMachineManager::shutdown_action( error_driver: os.str(""); os << "shutdown_action, error getting driver " << vm->get_vmm_mad(); - goto error_common; error_common: Nebula &ne = Nebula::instance(); @@ -425,7 +437,6 @@ void VirtualMachineManager::shutdown_action( lcm->trigger(LifeCycleManager::SHUTDOWN_FAILURE, vid); vm->log("VMM", Log::ERROR, os); - vm->unlock(); return; } @@ -436,9 +447,10 @@ void VirtualMachineManager::shutdown_action( void VirtualMachineManager::cancel_action( int vid) { - VirtualMachine * vm; + VirtualMachine * vm; + ostringstream os; + const VirtualMachineManagerDriver * vmd; - ostringstream os; // Get the VM from the pool vm = vmpool->get(vid,true); @@ -475,18 +487,72 @@ void VirtualMachineManager::cancel_action( error_driver: os.str(""); os << "cancel_action, error getting driver " << vm->get_vmm_mad(); - goto error_common; error_common: - Nebula &ne = Nebula::instance(); - LifeCycleManager * lcm = ne.get_lcm(); + if ( vm->get_lcm_state() == VirtualMachine::CANCEL ) //not in DELETE + { + Nebula &ne = Nebula::instance(); + LifeCycleManager * lcm = ne.get_lcm(); - lcm->trigger(LifeCycleManager::CANCEL_FAILURE, vid); + lcm->trigger(LifeCycleManager::CANCEL_FAILURE, vid); + } vm->log("VMM", Log::ERROR, os); + vm->unlock(); + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualMachineManager::cancel_previous_action( + int vid) +{ + VirtualMachine * vm; + ostringstream os; + + const VirtualMachineManagerDriver * vmd; + + // Get the VM from the pool + vm = vmpool->get(vid,true); + + if (vm == 0) + { + return; + } + + if (!vm->hasHistory() || !vm->hasPreviousHistory()) + { + goto error_history; + } + + // Get the driver for this VM + vmd = get(vm->get_uid(),vm->get_previous_vmm_mad()); + + if ( vmd == 0 ) + { + goto error_driver; + } + + // Invoke driver method + vmd->cancel(vid,vm->get_previous_hostname(),vm->get_deploy_id()); vm->unlock(); return; + +error_history: + os.str(""); + os << "cancel_previous_action, VM has no history"; + goto error_common; + +error_driver: + os.str(""); + os << "cancel_previous_action, error getting driver " << vm->get_vmm_mad(); + +error_common: + vm->log("VMM", Log::ERROR, os); + vm->unlock(); + return; } /* -------------------------------------------------------------------------- */ @@ -548,7 +614,6 @@ void VirtualMachineManager::migrate_action( error_previous_history: os.str(""); os << "migrate_action, error VM has no previous history"; - goto error_common; error_common: Nebula &ne = Nebula::instance(); @@ -557,7 +622,6 @@ void VirtualMachineManager::migrate_action( lcm->trigger(LifeCycleManager::DEPLOY_FAILURE, vid); vm->log("VMM", Log::ERROR, os); - vm->unlock(); return; } @@ -610,7 +674,6 @@ void VirtualMachineManager::restore_action( error_driver: os.str(""); os << "restore_action, error getting driver " << vm->get_vmm_mad(); - goto error_common; error_common: Nebula &ne = Nebula::instance(); @@ -619,7 +682,6 @@ void VirtualMachineManager::restore_action( lcm->trigger(LifeCycleManager::DEPLOY_FAILURE, vid); vm->log("VMM", Log::ERROR, os); - vm->unlock(); return; } @@ -669,16 +731,62 @@ void VirtualMachineManager::poll_action( error_driver: os.str(""); os << "poll_action, error getting driver " << vm->get_vmm_mad(); - goto error_common; error_common: - Nebula &ne = Nebula::instance(); - LifeCycleManager * lcm = ne.get_lcm(); + vm->log("VMM", Log::ERROR, os); + vm->unlock(); + return; +} - lcm->trigger(LifeCycleManager::CANCEL_FAILURE, vid); +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ - vm->log("VMM", Log::ERROR, os); +void VirtualMachineManager::driver_cancel_action( + int vid) +{ + VirtualMachine * vm; + ostringstream os; + + const VirtualMachineManagerDriver * vmd; + // Get the VM from the pool + vm = vmpool->get(vid,true); + + if (vm == 0) + { + return; + } + + if (!vm->hasHistory()) + { + goto error_history; + } + + // Get the driver for this VM + vmd = get(vm->get_uid(),vm->get_vmm_mad()); + + if ( vmd == 0 ) + { + goto error_driver; + } + + // Invoke driver method + vmd->driver_cancel(vid); + + vm->unlock(); + return; + +error_history: + os.str(""); + os << "driver_cacncel_action, VM has no history"; + goto error_common; + +error_driver: + os.str(""); + os << "driver_cancel_action, error getting driver " << vm->get_vmm_mad(); + +error_common: + vm->log("VMM", Log::ERROR, os); vm->unlock(); return; } @@ -818,6 +926,5 @@ void VirtualMachineManager::load_mads(int uid) Nebula::log("VMM",Log::INFO,oss); } - } } diff --git a/src/vmm/VirtualMachineManagerDriver.cc b/src/vmm/VirtualMachineManagerDriver.cc index aa897f8..1483a90 100644 --- a/src/vmm/VirtualMachineManagerDriver.cc +++ b/src/vmm/VirtualMachineManagerDriver.cc @@ -281,6 +281,18 @@ void VirtualMachineManagerDriver::protocol( return; } + if ( vm->get_lcm_state() == VirtualMachine::DELETE || + vm->get_lcm_state() == VirtualMachine::FAILURE|| + vm->get_lcm_state() == VirtualMachine::LCM_INIT ) + { + os.str(""); + os << "Ignored: " << message; + vm->log("VMM",Log::WARNING,os); + + vm->unlock(); + return; + } + // Driver Actions if ( action == "DEPLOY" ) { @@ -306,7 +318,10 @@ void VirtualMachineManagerDriver::protocol( getline(is,info); os.str(""); - os << "Error deploying virtual machine: " << info; + os << "Error deploying virtual machine"; + + if (info[0] != '-') + os << ": " << info; vm->log("VMM",Log::ERROR,os); @@ -509,7 +524,9 @@ void VirtualMachineManagerDriver::protocol( vmpool->update(vm); - if (state != '-' && vm->get_lcm_state() == VirtualMachine::RUNNING) + if (state != '-' && + (vm->get_lcm_state() == VirtualMachine::RUNNING || + vm->get_lcm_state() == VirtualMachine::UNKNOWN)) { Nebula &ne = Nebula::instance(); LifeCycleManager * lcm = ne.get_lcm(); @@ -519,38 +536,41 @@ void VirtualMachineManagerDriver::protocol( case 'a': // Still active, good! os.str(""); os << "Monitor Information:\n" - << "\tCPU : "<< cpu << "\n" + << "\tCPU : "<< cpu << "\n" << "\tMemory: "<< memory << "\n" << "\tNet_TX: "<< net_tx << "\n" - << "\tNet_RX: "<< net_rx << "\n"; - vm->log("VMM",Log::INFO,os); + << "\tNet_RX: "<< net_rx; + vm->log("VMM",Log::DEBUG,os); + + if ( vm->get_lcm_state() == VirtualMachine::UNKNOWN) + { + vm->log("VMM",Log::INFO,"VM was now found, new state is" + " RUNNING"); + vm->set_state(VirtualMachine::RUNNING); + vmpool->update(vm); + } break; case 'p': // It's paused - os.str(""); - os << "VM running but new state from monitor is PAUSED.\n"; - vm->log("VMM",Log::INFO,os); + vm->log("VMM",Log::INFO,"VM running but new state " + "from monitor is PAUSED."); lcm->trigger(LifeCycleManager::MONITOR_SUSPEND, id); - break; case 'e': //Failed - os.str(""); - os << "VM running but new state from monitor is ERROR.\n"; - vm->log("VMM",Log::INFO,os); + vm->log("VMM",Log::INFO,"VM running but new state " + "from monitor is ERROR."); lcm->trigger(LifeCycleManager::MONITOR_FAILURE, id); - break; - case 'd': //Failed - os.str(""); - os << "VM running but it was not found. Assuming it is done.\n"; - vm->log("VMM",Log::INFO,os); + case 'd': //The VM was not found + vm->log("VMM",Log::INFO,"VM running but it was not found." + " Restart and delete actions available or try to" + " recover it manually"); lcm->trigger(LifeCycleManager::MONITOR_DONE, id); - break; } } diff --git a/src/vmm_mad/ec2/one_vmm_ec2.rb b/src/vmm_mad/ec2/one_vmm_ec2.rb index bebbb8d..1fc6254 100755 --- a/src/vmm_mad/ec2/one_vmm_ec2.rb +++ b/src/vmm_mad/ec2/one_vmm_ec2.rb @@ -1,20 +1,20 @@ #!/usr/bin/env ruby -# -------------------------------------------------------------------------- # -# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad # -# Complutense de Madrid (dsa-research.org) # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); you may # -# not use this file except in compliance with the License. You may obtain # -# a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -#--------------------------------------------------------------------------- # +# ---------------------------------------------------------------------------- # +# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad # +# Complutense de Madrid (dsa-research.org) # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # # ---------------------------------------------------------------------------- # # Set up the environment for the driver # @@ -65,16 +65,17 @@ class EC2Driver < VirtualMachineDriver # EC2 constructor, loads defaults for the EC2Driver # # ------------------------------------------------------------------------ # def initialize(ec2_conf = nil) - super(15,true) + super(5,true) @defaults = Hash.new if ec2_conf && File.exists?(ec2_conf) fd = File.new(ec2_conf) xml = REXML::Document.new fd - return if !xml || !xml.root fd.close() + return if !xml || !xml.root + ec2 = xml.root.elements["EC2"] return if !ec2 diff --git a/src/vmm_mad/ec2/vmm_ec2.conf b/src/vmm_mad/ec2/vmm_ec2.conf index 4addf42..8cbae6e 100644 --- a/src/vmm_mad/ec2/vmm_ec2.conf +++ b/src/vmm_mad/ec2/vmm_ec2.conf @@ -5,17 +5,17 @@ - ec2[keypair,authorizedports,instancetype] Use XML syntax to specify defaults, note elements are UPCASE Example: - + --> - + diff --git a/src/vmm_mad/kvm/one_vmm_kvm.rb b/src/vmm_mad/kvm/one_vmm_kvm.rb index e5c4217..2af9c30 100755 --- a/src/vmm_mad/kvm/one_vmm_kvm.rb +++ b/src/vmm_mad/kvm/one_vmm_kvm.rb @@ -97,7 +97,17 @@ def deploy(id, host, remote_dfile, not_used) # Basic Domain Management Operations # # ------------------------------------------------------------------------ # def shutdown(id, host, deploy_id, not_used) - ssh_action("#{LIBVIRT[:shutdown]} #{deploy_id}", id, host, :shutdown) + cmd="#{LIBVIRT[:shutdown]} #{deploy_id} && " \ + "while [ $(#{LIBVIRT[:poll]} #{deploy_id} > /dev/null 2>&1; " \ + "echo $?) -eq \"0\" ]; do sleep 2; done ; sleep 4" + + execution=SSHCommand.run('bash', host, log_method(id), cmd) + + if execution.code !=0 + send_message(ACTION[:shutdown], RESULT[:failure], id) + else + send_message(ACTION[:shutdown], RESULT[:success], id) + end end def cancel(id, host, deploy_id, not_used) diff --git a/src/vmm_mad/vmware/DeployVM.java b/src/vmm_mad/vmware/DeployVM.java index afcbb92..714be3a 100644 --- a/src/vmm_mad/vmware/DeployVM.java +++ b/src/vmm_mad/vmware/DeployVM.java @@ -198,7 +198,7 @@ public boolean shapeVM() throws Exception // Memory sharesInfo.setLevel(SharesLevel.custom); - sharesInfo.setShares(Integer.parseInt(pXML.getMemory())); + sharesInfo.setShares(Integer.parseInt(pXML.getMemory())*1024); raInfo.setShares(sharesInfo); @@ -392,7 +392,7 @@ private String getDataStoreName(int size) throws Exception{ } */ - DeployVM(String[] args, String hostName, String vid, ParseXML _pXML) throws Exception + DeployVM(String[] args, String hostName, String vid, ParseXML _pXML, String _datastore, String _datacenter) throws Exception { String[] argsWithHost = new String[args.length+2]; @@ -404,15 +404,15 @@ private String getDataStoreName(int size) throws Exception{ argsWithHost[args.length] = "--url"; //argsWithHost[args.length + 1 ] = "https://" + hostName + ":443/sdk"; + argsWithHost[args.length + 1 ] = "https://localhost:8008/sdk"; - + cb = AppUtil.initialize("DeployVM", null, argsWithHost); cb.connect(); - // TODO get this dynamically - datastoreName = "datastore1"; - datacenterName = "ha-datacenter"; + datastoreName = _datastore; + datacenterName = _datacenter; vmName = _pXML.getName() + "-" + vid; vmDiskName = _pXML.getName(); @@ -427,7 +427,7 @@ private String getDataStoreName(int size) throws Exception{ service = sc.getService(); } - DeployVM(String[] args, String hostName, String _vmName) throws Exception + DeployVM(String[] args, String hostName, String _vmName, String _datastore, String _datacenter) throws Exception { String[] argsWithHost = new String[args.length+2]; @@ -438,17 +438,15 @@ private String getDataStoreName(int size) throws Exception{ } argsWithHost[args.length] = "--url"; -// argsWithHost[args.length + 1 ] = "https://" + hostName + ":443/sdk"; + //argsWithHost[args.length + 1 ] = "https://" + hostName + ":443/sdk"; argsWithHost[args.length + 1 ] = "https://localhost:8008/sdk"; - cb = AppUtil.initialize("DeployVM", null, argsWithHost); cb.connect(); - - // TODO get this dynamically - datastoreName = "datastore1"; - datacenterName = "ha-datacenter"; + + datastoreName = _datastore; + datacenterName = _datacenter; vmName = _vmName; vmDiskName = _vmName.substring(0,_vmName.lastIndexOf("-")); diff --git a/src/vmm_mad/vmware/OneVmmVmware.java b/src/vmm_mad/vmware/OneVmmVmware.java index 7d770fd..3259220 100644 --- a/src/vmm_mad/vmware/OneVmmVmware.java +++ b/src/vmm_mad/vmware/OneVmmVmware.java @@ -52,7 +52,7 @@ public static void main(String[] args) { debug_flag=false; } - + OneVmmVmware omv = new OneVmmVmware(args, debug_flag); omv.loop(); } @@ -123,7 +123,7 @@ else if (action.equals("FINALIZE")) { if (action.equals("DEPLOY")) { - if (str_split.length != 4) + if (str_split.length != 5) { System.out.println("FAILURE Wrong number of arguments for DEPLOY action. Number args = [" + str_split.length + "]."); @@ -140,12 +140,19 @@ else if (action.equals("FINALIZE")) fileName = str_split[3]; try - { + { + fileName = fileName.replace("/images", ""); + // let's read the XML file and extract needed info ParseXML pXML = new ParseXML(fileName); // First, register the VM - DeployVM dVM = new DeployVM(arguments, hostName, vid_str, pXML); + DeployVM dVM = new DeployVM(arguments, + hostName, + vid_str, + pXML, + System.getProperty("datastore"), + System.getProperty("datacenter")); if(!dVM.registerVirtualMachine()) { @@ -198,7 +205,7 @@ else if (action.equals("FINALIZE")) synchronized (System.err) { System.err.println("DEPLOY FAILURE " + vid_str + " Failed deploying VM in host " + - hostName + ". Please check the VM log."); + hostName + "."); } } // catch } // else if (str_split.length != 4) @@ -247,6 +254,16 @@ else if (action.equals("FINALIZE")) hostName); } } + + if(!oVM.deregisterVM(vmName)) + { + synchronized (System.err) + { + System.err.println(action + " FAILURE " + vid_str + " Failed deregistering of " +vmName + + " in host " + hostName +"."); + } + continue; + } else { synchronized (System.err) @@ -293,7 +310,7 @@ else if (action.equals("FINALIZE")) continue; } - if(!oVM.save(vmName,checkpointName)) + if(!oVM.save(vmName)) { synchronized (System.err) { @@ -346,7 +363,7 @@ else if (action.equals("FINALIZE")) continue; } - if(!oVM.createCheckpoint(vmName,checkpointName)) + if(!oVM.createCheckpoint(vmName)) { synchronized (System.err) { @@ -382,8 +399,7 @@ else if (action.equals("FINALIZE")) { vid_str = str_split[1]; hostName = str_split[2]; - String checkpointName = str_split[3]; - + String vmName = str_split[3]; boolean result; try @@ -400,7 +416,7 @@ else if (action.equals("FINALIZE")) } } - if(!oVM.restoreCheckpoint("one-"+vid_str,checkpointName)) + if(!oVM.restoreCheckpoint(vmName)) { synchronized (System.err) { @@ -410,12 +426,33 @@ else if (action.equals("FINALIZE")) } else { - synchronized (System.err) + try { - System.err.println(action + " SUCCESS " + vid_str); + if(!oVM.powerOn(vmName)) + { + System.err.println(action + " FAILURE " + vid_str + " Failed restoring VM in host " + + hostName); + } + else + { + synchronized (System.err) + { + System.err.println(action + " SUCCESS " + vid_str); + } + } } + catch(Exception e) + { + synchronized (System.err) + { + System.err.println(action + " FAILURE " + vid_str + " Failed connection to host " + + hostName +". Reason: " + e.getMessage()); + continue; + } + } + } - + continue; } } // if (action.equals("RESTORE")) @@ -461,9 +498,7 @@ else if (action.equals("FINALIZE")) // First, checkpoint the running virtual machine - String checkpointName = "one-migrate-" + vid_str; - - if(!oVM.save(vmName,checkpointName)) + if(!oVM.save(vmName)) { synchronized (System.err) { @@ -490,7 +525,11 @@ else if (action.equals("FINALIZE")) try { oVM = new OperationsOverVM(arguments,destHostName); - dVM = new DeployVM(arguments, destHostName, vmName); + dVM = new DeployVM(arguments, + destHostName, + vmName, + System.getProperty("datastore"), + System.getProperty("datacenter")); if(!dVM.registerVirtualMachine()) { @@ -521,7 +560,7 @@ else if (action.equals("FINALIZE")) // Restore the virtual machine checkpoint - if(!oVM.restoreCheckpoint(vmName,checkpointName)) + if(!oVM.restoreCheckpoint(vmName)) { synchronized (System.err) { @@ -556,49 +595,55 @@ else if (action.equals("FINALIZE")) else { vid_str = str_split[1]; - hostName = str_split[2]; + hostName = str_split[2]; String vmName = str_split[3]; - // First, create the checkpoint + String pollInfo; try - { - oVM = new OperationsOverVM(arguments,hostName); - } - catch(Exception e) - { - synchronized (System.err) + { + + String[] argsWithHost = new String[arguments.length+2]; + + for(int i=0;i /dev/null cd ../../tm_mad/vmware -mkdir $ONE_LOCATION/lib/tm_commands/vmware +mkdir -p $ONE_LOCATION/lib/tm_commands/vmware cp *sh $ONE_LOCATION/lib/tm_commands/vmware echo -n "." -mkdir $ONE_LOCATION/etc/im_vmware -mkdir $ONE_LOCATION/etc/vmm_vmware -mkdir $ONE_LOCATION/etc/tm_vmware +mkdir -p $ONE_LOCATION/etc/im_vmware +mkdir -p $ONE_LOCATION/etc/vmm_vmware +mkdir -p $ONE_LOCATION/etc/tm_vmware cp ../../vmm_mad/vmware/vmm_vmware.conf ../../vmm_mad/vmware/vmm_vmwarerc $ONE_LOCATION/etc/vmm_vmware cp ../../im_mad/vmware/im_vmware.conf ../../im_mad/vmware/im_vmwarerc $ONE_LOCATION/etc/im_vmware diff --git a/src/vmm_mad/vmware/one_vmm_vmware b/src/vmm_mad/vmware/one_vmm_vmware index 2ce7229..f8acd18 100755 --- a/src/vmm_mad/vmware/one_vmm_vmware +++ b/src/vmm_mad/vmware/one_vmm_vmware @@ -19,7 +19,7 @@ #Setup driver variables -DRIVER_NAME=`basename $0` +DRIVER_NAME="vmm_vmware" if [ -z "${ONE_LOCATION}" ]; then DRIVERRC=/etc/one/${DRIVER_NAME}/${DRIVER_NAME}rc @@ -49,12 +49,12 @@ if [ -z "${ONE_LOCATION}" ]; then else MAD_LOG_PATH=$ONE_LOCATION/var/$LOG_FILE.log fi -ONE_MAD_DEBUG=neno + # Execute the actual MAD if [ -n "${ONE_MAD_DEBUG}" ]; then - exec nice -n $PRIORITY java -cp $ONE_LOCATION/lib/mads:$CLASSPATH -Djavax.net.ssl.trustStore=$VMWARE_TRUSTORE -Ddebug=$ONE_MAD_DEBUG -Xmx1024M $MAD_FILE $* 2>> $MAD_LOG_PATH + exec nice -n $PRIORITY java -cp $ONE_LOCATION/lib/mads:$CLASSPATH -Ddatastore=$VMWARE_DATASTORE -Ddatacenter=$VMWARE_DATACENTER -Djavax.net.ssl.trustStore=$VMWARE_TRUSTORE -Ddebug=$ONE_MAD_DEBUG -Xmx1024M $MAD_FILE $* 2>> $MAD_LOG_PATH else - exec nice -n $PRIORITY java -cp $ONE_LOCATION/lib/mads:$CLASSPATH -Djavax.net.ssl.trustStore=$VMWARE_TRUSTORE -Xmx1024M $MAD_FILE $* 2> /dev/null + exec nice -n $PRIORITY java -cp $ONE_LOCATION/lib/mads:$CLASSPATH -Ddatastore=$VMWARE_DATASTORE -Ddatacenter=$VMWARE_DATACENTER -Djavax.net.ssl.trustStore=$VMWARE_TRUSTORE -Xmx1024M $MAD_FILE $* 2> /dev/null fi diff --git a/src/vmm_mad/vmware/vmm_vmwarerc b/src/vmm_mad/vmware/vmm_vmwarerc index 8265c36..35f2531 100644 --- a/src/vmm_mad/vmware/vmm_vmwarerc +++ b/src/vmm_mad/vmware/vmm_vmwarerc @@ -20,5 +20,10 @@ #VMWARE_TRUSTORE= # Uncomment the following line to active MAD debug -#ONE_MAD_DEBUG=1 +ONE_MAD_DEBUG=1 +# Datastore name +VMWARE_DATASTORE=datastore1 + +# Datacenter name +VMWARE_DATACENTER=ha-datacenter diff --git a/src/vmm_mad/xen/one_vmm_xen.rb b/src/vmm_mad/xen/one_vmm_xen.rb index c5f6860..8f33b57 100755 --- a/src/vmm_mad/xen/one_vmm_xen.rb +++ b/src/vmm_mad/xen/one_vmm_xen.rb @@ -125,7 +125,35 @@ def deploy(id, host, remote_dfile, not_used) # Basic Domain Management Operations # # ------------------------------------------------------------------------ # def shutdown(id, host, deploy_id, not_used) - ssh_action("#{XEN[:shutdown]} #{deploy_id}", id, host, :shutdown) + cmd=<<-EOS +function gdm { + sudo xm list | grep '#{deploy_id}\\>' +} + +#{XEN[:shutdown]} #{deploy_id} || exit -1 + +OUT=$(gdm) + +while [ -n "$OUT" -a $(echo $OUT | awk '{print $5}') != "---s--" ]; do + sleep 1 + OUT=$(gdm) +done + +OUT=$(gdm) + +if [ -n "$OUT" ]; then + #{XEN[:cancel]} '#{deploy_id}' +fi +sleep 2 +EOS + + execution=SSHCommand.run('bash', host, log_method(id), cmd) + + if execution.code !=0 + send_message(ACTION[:shutdown], RESULT[:failure], id) + else + send_message(ACTION[:shutdown], RESULT[:success], id) + end end def cancel(id, host, deploy_id, not_used) diff --git a/src/vnm/Leases.cc b/src/vnm/Leases.cc index b9fcf15..566a742 100644 --- a/src/vnm/Leases.cc +++ b/src/vnm/Leases.cc @@ -29,7 +29,7 @@ /* -------------------------------------------------------------------------- */ void Leases::Lease::to_string(string &_ip, - string &_mac) + string &_mac) const { mac_to_string(mac, _mac); @@ -184,11 +184,22 @@ void Leases::Lease::mac_to_string(const unsigned int i_mac[], string& mac) ostream& operator<<(ostream& os, Leases::Lease& _lease) +{ + string xml; + + os << _lease.to_xml(xml); + + return os; +} + +string& Leases::Lease::to_str(string& str) const { string ip; string mac; - _lease.to_string(ip,mac); + ostringstream os; + + to_string(ip,mac); ip = "IP = " + ip; mac = "MAC = " + mac; @@ -199,10 +210,35 @@ ostream& operator<<(ostream& os, Leases::Lease& _lease) os.width(24); os << left << mac; - os << left << " USED = " << _lease.used; - os << left << " VID = " << _lease.vid; + os << left << " USED = " << used; + os << left << " VID = " << vid; - return os; + str = os.str(); + + return str; +} + + +string& Leases::Lease::to_xml(string& str) const +{ + string ip; + string mac; + + ostringstream os; + + to_string(ip,mac); + + os << + "" << + ""<< ip << "" << + "" << mac << "" << + "" << used << "" << + "" << vid << "" << + ""; + + str = os.str(); + + return str; } /* ************************************************************************** */ @@ -393,16 +429,54 @@ bool Leases::check(unsigned int ip) /* Leases :: Misc */ /* ************************************************************************** */ -ostream& operator<<(ostream& os, Leases& _leases) +string& Leases::to_xml(string& xml) const { - map::iterator it; - - // Iterate all the leases - for(it=_leases.leases.begin();it!=_leases.leases.end();it++) + map::const_iterator it; + ostringstream os; + string lease_xml; + + os << ""; + + for(it=leases.begin();it!=leases.end();it++) { - os << *(it->second) << endl; + os << it->second->to_xml(lease_xml); } + os << ""; + + xml = os.str(); + + return xml; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& Leases::to_str(string& str) const +{ + map::const_iterator it; + ostringstream os; + string lease_str; + + for(it=leases.begin();it!=leases.end();it++) + { + os << it->second->to_str(lease_str) << endl; + } + + str = os.str(); + + return str; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +ostream& operator<<(ostream& os, Leases& _leases) +{ + string xml; + + os << _leases.to_xml(xml); + return os; }; diff --git a/src/vnm/VirtualNetwork.cc b/src/vnm/VirtualNetwork.cc index 29667dd..dc152ba 100644 --- a/src/vnm/VirtualNetwork.cc +++ b/src/vnm/VirtualNetwork.cc @@ -64,12 +64,12 @@ const char * VirtualNetwork::db_bootstrap = "CREATE TABLE network_pool (" int VirtualNetwork::unmarshall(int num, char **names, char ** values) { - if ((values[OID] == 0) || - (values[UID] == 0) || - (values[NAME] == 0) || - (values[TYPE] == 0) || - (values[BRIDGE] == 0) || - (num != LIMIT )) + if ((!values[OID]) || + (!values[UID]) || + (!values[NAME]) || + (!values[TYPE]) || + (!values[BRIDGE]) || + (num != LIMIT )) { return -1; } @@ -225,6 +225,88 @@ int VirtualNetwork::select(SqliteDB * db) return -1; } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualNetwork::unmarshall(ostringstream& oss, + int num, + char ** names, + char ** values) +{ + if ((!values[OID]) || + (!values[UID]) || + (!values[NAME]) || + (!values[TYPE]) || + (!values[BRIDGE])|| + (!values[LIMIT]) || + (num != LIMIT + 2 )) + { + return -1; + } + + oss << + "" << + "" << values[OID] << "" << + "" << values[UID] << "" << + "" << values[LIMIT+1] << "" << + "" << values[NAME] << "" << + "" << values[TYPE] << "" << + "" << values[BRIDGE] << "" << + "" << values[LIMIT]<< "" << + ""; + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +extern "C" int vn_dump_cb ( + void * _oss, + int num, + char ** values, + char ** names) +{ + ostringstream * oss; + + oss = static_cast(_oss); + + if (oss == 0) + { + return -1; + } + + return VirtualNetwork::unmarshall(*oss,num,names,values); +}; + +/* -------------------------------------------------------------------------- */ + +int VirtualNetwork::dump(SqliteDB * db, ostringstream& oss, const string& where) +{ + int rc; + ostringstream cmd; + + cmd << "SELECT " << VirtualNetwork::table << ".*,COUNT(" + << Leases::table << ".used), user_pool.user_name FROM " + << VirtualNetwork::table + << " LEFT OUTER JOIN " << Leases::table << " ON " + << VirtualNetwork::table << ".oid = " << Leases::table << ".oid" + << " AND " << Leases::table << ".used = 1" + << " LEFT OUTER JOIN (SELECT oid,user_name FROM user_pool) " + << " AS user_pool ON "<< VirtualNetwork::table << ".uid = user_pool.oid"; + + if ( !where.empty() ) + { + cmd << " WHERE " << where; + } + + cmd << " GROUP BY " << VirtualNetwork::table << ".oid"; + + rc = db->exec(cmd,vn_dump_cb,(void *) &oss); + + return rc; +} + + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -403,17 +485,62 @@ int VirtualNetwork::vn_drop(SqliteDB * db) } + /* ************************************************************************** */ /* Virtual Network :: Misc */ /* ************************************************************************** */ ostream& operator<<(ostream& os, VirtualNetwork& vn) { - os << "NID : " << vn.oid << endl; - os << "UID : " << vn.uid << endl; - os << "Network Name : " << vn.name << endl; + string vnet_xml; + + os << vn.to_xml(vnet_xml); + + return os; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& VirtualNetwork::to_xml(string& xml) const +{ + ostringstream os; + + string template_xml; + string leases_xml; + + os << + "" << + "" << oid << "" << + "" << uid << "" << + "" << name << "" << + "" << type << "" << + ""<< bridge<< "" << + vn_template.to_xml(template_xml); + if (leases) + os << leases->to_xml(leases_xml); + os << ""; + + xml = os.str(); + + return xml; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string& VirtualNetwork::to_str(string& str) const +{ + ostringstream os; + + string template_str; + string leases_str; + + os << "ID : " << oid << endl; + os << "UID : " << uid << endl; + os << "NAME : " << name << endl; os << "Type : "; - if ( vn.type==VirtualNetwork::RANGED ) + if ( type==VirtualNetwork::RANGED ) { os << "Ranged" << endl; } @@ -422,11 +549,20 @@ ostream& operator<<(ostream& os, VirtualNetwork& vn) os << "Fixed" << endl; } - os << "Bridge : " << vn.bridge << endl << endl; + os << "Bridge : " << bridge << endl << endl; - os << "....: Template :...." << vn.vn_template << endl << endl; - - os << "....: Leases :...." << endl << *(vn.leases) << endl; + os << "....: Template :...." << vn_template.to_str(template_str) << endl << endl; + + if (leases) + { + os << "....: Leases :...." << endl << leases->to_str(leases_str) << endl; + } - return os; -}; + str = os.str(); + + return str; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +