diff --git a/README b/README.md similarity index 100% rename from README rename to README.md diff --git a/SConstruct b/SConstruct index 54b3e6aab3..1c3203d935 100644 --- a/SConstruct +++ b/SConstruct @@ -57,6 +57,7 @@ main_env.Append(LIBPATH=[ cwd+'/src/log', cwd+'/src/sql', cwd+'/src/host', + cwd+'/src/cluster', cwd+'/src/mad', cwd+'/src/nebula', cwd+'/src/pool', @@ -73,6 +74,7 @@ main_env.Append(LIBPATH=[ cwd+'/src/hm', cwd+'/src/um', cwd+'/src/authm', + cwd+'/src/xml', ]) # Compile flags @@ -171,6 +173,7 @@ build_scripts=[ 'src/common/SConstruct', 'src/template/SConstruct', 'src/host/SConstruct', + 'src/cluster/SConstruct', 'src/mad/SConstruct', 'src/nebula/SConstruct', 'src/pool/SConstruct', @@ -187,6 +190,7 @@ build_scripts=[ 'src/hm/SConstruct', 'src/um/SConstruct', 'src/authm/SConstruct', + 'src/xml/SConstruct', ] # Testing @@ -214,6 +218,7 @@ if testing=='yes': 'src/authm/test/SConstruct', 'src/common/test/SConstruct', 'src/host/test/SConstruct', + 'src/cluster/test/SConstruct', 'src/image/test/SConstruct', 'src/lcm/test/SConstruct', 'src/pool/test/SConstruct', @@ -222,6 +227,7 @@ if testing=='yes': 'src/um/test/SConstruct', 'src/vm/test/SConstruct', 'src/vnm/test/SConstruct', + 'src/xml/test/SConstruct', ]) else: main_env.Append(testing='no') diff --git a/include/Cluster.h b/include/Cluster.h new file mode 100644 index 0000000000..bf0c2d6a11 --- /dev/null +++ b/include/Cluster.h @@ -0,0 +1,132 @@ +/* ------------------------------------------------------------------------ */ +/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.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 CLUSTER_H_ +#define CLUSTER_H_ + +#include "PoolSQL.h" +#include "Host.h" + +using namespace std; + +/** + * The Cluster class. + */ +class Cluster : public PoolObjectSQL +{ +public: + /** + * Adds the host to this cluster + * @param host The host to add + * + * @return 0 on success + */ +/* + int add_host(Host * host) + { + return host->set_cluster(name); + }; +*/ + + /** + * Removes the host from this cluster + * @param host The host to add + * + * @return 0 on success + */ +// May be needed in a future +// int remove_host(Host * host); + + /** + * Function to write a Cluster on an output stream + */ + friend ostream& operator<<(ostream& os, Cluster& cluster); + + /** + * Function to print the Cluster 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; + + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + int from_xml(const string &xml_str); + +private: + + // ------------------------------------------------------------------------- + // Friends + // ------------------------------------------------------------------------- + + friend class ClusterPool; + + // ************************************************************************* + // Constructor + // ************************************************************************* + + Cluster(int id, const string& name); + + virtual ~Cluster(); + + // ************************************************************************* + // DataBase implementation (Private) + // ************************************************************************* + + static const char * db_names; + + static const char * db_bootstrap; + + static const char * table; + + /** + * Execute an INSERT or REPLACE Sql query. + * @param db The SQL DB + * @param replace Execute an INSERT or a REPLACE + * @return 0 one success + */ + int insert_replace(SqlDB *db, bool replace); + + /** + * Bootstraps the database table(s) associated to the Cluster + */ + static void bootstrap(SqlDB * db) + { + ostringstream oss_cluster(Cluster::db_bootstrap); + + db->exec(oss_cluster); + }; + + /** + * Writes the Cluster in the database. + * @param db pointer to the db + * @return 0 on success + */ + int insert(SqlDB *db, string& error_str); + + /** + * Writes/updates the Cluster's data fields in the database. + * @param db pointer to the db + * @return 0 on success + */ + int update(SqlDB *db); +}; + +#endif /*CLUSTER_H_*/ diff --git a/include/ClusterPool.h b/include/ClusterPool.h index f9f92fe10b..13b5ac7fab 100644 --- a/include/ClusterPool.h +++ b/include/ClusterPool.h @@ -17,124 +17,123 @@ #ifndef CLUSTER_POOL_H_ #define CLUSTER_POOL_H_ -#include -#include -#include - +#include "Cluster.h" +#include "Host.h" #include "SqlDB.h" using namespace std; - /** * A cluster helper class. It is not a normal PoolSQL, * but a series of static methods related to clusters. */ -class ClusterPool +class ClusterPool : public PoolSQL { public: + ClusterPool(SqlDB * db); + + ~ClusterPool(){}; + + /** + * Removes the host from the given cluster setting the default one. + * @param host The host to assign + * + * @return 0 on success + */ + int set_default_cluster(Host * host) + { + return host->set_cluster(ClusterPool::DEFAULT_CLUSTER_NAME); + }; + /** * Cluster name for the default cluster */ static const string DEFAULT_CLUSTER_NAME; -private: - // ------------------------------------------------------------------------- - // Friends - // ------------------------------------------------------------------------- - friend class HostPool; - /* ---------------------------------------------------------------------- */ - /* Attributes */ + /* Methods for DB management */ /* ---------------------------------------------------------------------- */ - /** - * This map stores the clusters - */ - map cluster_names; - - - /* ---------------------------------------------------------------------- */ - /* Methods for cluster management */ - /* ---------------------------------------------------------------------- */ - - /** - * Returns true if the clid is an id for an existing cluster - * @param clid ID of the cluster - * - * @return true if the clid is an id for an existing cluster - */ - bool exists(int clid) - { - return cluster_names.count(clid) > 0; - }; /** * Allocates a new cluster in the pool * @param clid the id assigned to the cluster * @return the id assigned to the cluster or -1 in case of failure */ - int allocate(int * clid, string name, SqlDB *db, string& error_str); + int allocate(int * oid, string name, string& error_str); /** - * Returns the xml representation of the given cluster - * @param clid ID of the cluster - * - * @return the xml representation of the given cluster + * Function to get a Cluster from the pool, if the object is not in memory + * it is loaded from the DB + * @param oid Cluster unique id + * @param lock locks the Cluster mutex + * @return a pointer to the Cluster, 0 if the Cluster could not be loaded */ - string info(int clid); - - /** - * Removes the given cluster from the pool and the DB - * @param clid ID of the cluster - * - * @return 0 on success - */ - int drop(int clid, SqlDB *db); - - /** - * Dumps the cluster pool in XML format. - * @param oss the output stream to dump the pool contents - * - * @return 0 on success - */ - int dump(ostringstream& oss); - - /** - * Bootstraps the database table(s) associated to the Cluster - */ - static void bootstrap(SqlDB * db) + Cluster * get(int oid, bool lock) { - ostringstream oss(ClusterPool::db_bootstrap); - db->exec(oss); + return static_cast(PoolSQL::get(oid,lock)); }; /** - * Function to insert new Cluster in the pool - * @param oid the id assigned to the Cluster - * @param name the Cluster's name - * @return 0 on success, -1 in case of failure - */ - int insert (int oid, string name, SqlDB *db); - - /** - * Formats as XML the given id and name. - * @param oss the output stream to dump the pool contents + * Gets an object from the pool (if needed the object is loaded from the + * database). + * @param name of the object + * @param lock locks the object if true * + * @return a pointer to the object, 0 in case of failure + */ + Cluster * get(const string& name, bool lock) + { + return static_cast(PoolSQL::get(name,-1,lock)); + }; + + /** Update a particular Cluster + * @param user pointer to Cluster * @return 0 on success */ - void dump_cluster(ostringstream& oss, int id, string name); + int update(Cluster * cluster) + { + return cluster->update(db); + }; + /** + * Drops the Cluster from the data base. The object mutex SHOULD be + * locked. + * @param cluster a pointer to the object + * @return 0 on success. + */ + int drop(Cluster * cluster); - /* ---------------------------------------------------------------------- */ - /* DB manipulation */ - /* ---------------------------------------------------------------------- */ + /** + * Bootstraps the database table(s) associated to the Cluster pool + */ + static void bootstrap(SqlDB * _db) + { + Cluster::bootstrap(_db); + }; - static const char * db_names; + /** + * Dumps the Cluster 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) + { + return PoolSQL::dump(oss, "CLUSTER_POOL", Cluster::table, where); + }; - static const char * db_bootstrap; - - static const char * table; +private: + /** + * Factory method to produce objects + * @return a pointer to the new object + */ + PoolObjectSQL * create() + { + return new Cluster(-1,""); + }; }; #endif /*CLUSTER_POOL_H_*/ diff --git a/include/FixedLeases.h b/include/FixedLeases.h index ba7e146324..fc1c420d08 100644 --- a/include/FixedLeases.h +++ b/include/FixedLeases.h @@ -150,6 +150,13 @@ private: * @return 0 if success */ int unset(const string& ip); + + /** + * Updates the DB entry for this lease + * @param lease Lease to be updated + * @return 0 if success + */ + int update_lease(Lease * lease); }; #endif /*FIXED_LEASES_H_*/ diff --git a/include/History.h b/include/History.h index bdb202d336..35e38a3569 100644 --- a/include/History.h +++ b/include/History.h @@ -25,7 +25,7 @@ using namespace std; * The History class, it represents an execution record of a Virtual Machine. */ -class History:public ObjectSQL +class History:public ObjectSQL, public ObjectXML { public: enum MigrationReason @@ -40,13 +40,13 @@ public: History(int oid, int _seq = -1); History( - int oid, - int seq, - int hid, - string& hostname, - string& vm_dir, - string& vmm, - string& tm); + int oid, + int seq, + int hid, + const string& hostname, + const string& vm_dir, + const string& vmm, + const string& tm); ~History(){}; @@ -55,14 +55,6 @@ public: */ 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 @@ -78,52 +70,15 @@ private: // ---------------------------------------- // DataBase implementation variables // ---------------------------------------- - enum ColNames - { - VID = 0, - SEQ = 1, - HOSTNAME = 2, - VM_DIR = 3, - HID = 4, - VMMMAD = 5, - TMMAD = 6, - STIME = 7, - ETIME = 8, - PROLOG_STIME = 9, - PROLOG_ETIME = 10, - RUNNING_STIME = 11, - RUNNING_ETIME = 12, - EPILOG_STIME = 13, - EPILOG_ETIME = 14, - REASON = 15, - LIMIT = 16 - }; static const char * table; static const char * db_names; - static const char * extended_db_names; - static const char * db_bootstrap; void non_persistent_data(); - static string column_name(const ColNames column) - { - switch (column) - { - case HID: - return "hid"; - case ETIME: - return "etime"; - case RUNNING_ETIME: - return "retime"; - default: - return ""; - } - } - // ---------------------------------------- // History fields // ---------------------------------------- @@ -167,7 +122,12 @@ private: * @param db pointer to the database. * @return 0 on success. */ - int insert(SqlDB * db, string& error_str); + int insert(SqlDB * db, string& error_str) + { + error_str.clear(); + + return insert_replace(db, false); + } /** * Reads the history record from the DB @@ -181,7 +141,10 @@ private: * @param db pointer to the database. * @return 0 on success. */ - int update(SqlDB * db); + int update(SqlDB * db) + { + return insert_replace(db, true); + } /** * Removes the all history records from the DB @@ -208,15 +171,35 @@ private: int select_cb(void *nil, int num, char **values, char **names); /** - * 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 + * Rebuilds the object from an xml node + * @param node The xml node pointer + * + * @return 0 on success, -1 otherwise */ - static int dump(ostringstream& oss, int num, char **names, char **values); + int from_xml_node(const xmlNodePtr node) + { + ObjectXML::update_from_node(node); + + return rebuild_attributes(); + } + + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + int from_xml(const string &xml_str) + { + ObjectXML::update_from_str(xml_str); + + return rebuild_attributes(); + } + + /** + * Rebuilds the internal attributes using xpath + */ + int rebuild_attributes(); }; #endif /*HISTORY_H_*/ diff --git a/include/Host.h b/include/Host.h index 72039a9cd9..6f7982413f 100644 --- a/include/Host.h +++ b/include/Host.h @@ -20,7 +20,6 @@ #include "PoolSQL.h" #include "HostTemplate.h" #include "HostShare.h" -#include "ClusterPool.h" using namespace std; @@ -49,28 +48,20 @@ public: */ 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; + /** + * 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 + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise */ - int get_hid() const - { - return oid; - }; + int from_xml(const string &xml_str); /** * Check if the host is enabled @@ -120,15 +111,6 @@ public: state = INIT; }; - /** - * Returns host host_name - * @return host_name Host's hostname - */ - const string& get_hostname() const - { - return hostname; - }; - /** Update host counters and update the whole host on the DB * @param parse_str string with values to be parsed * @return 0 on success @@ -378,9 +360,6 @@ private: // ------------------------------------------------------------------------- // Host Description // ------------------------------------------------------------------------- - - string hostname; - /** * The state of the Host */ @@ -402,7 +381,7 @@ private: string tm_mad_name; /** - * If Host State = MONITORED last time it got fully monitored or 1 Jan 1970 + * 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; @@ -426,10 +405,29 @@ private: */ HostShare host_share; + // ************************************************************************* + // Constructor + // ************************************************************************* + + Host(int id=-1, + const string& hostname="", + const string& im_mad_name="", + const string& vmm_mad_name="", + const string& tm_mad_name="", + const string& cluster=""); + + virtual ~Host(); + // ************************************************************************* // DataBase implementation (Private) // ************************************************************************* + static const char * db_names; + + static const char * db_bootstrap; + + static const char * table; + /** * Execute an INSERT or REPLACE Sql query. * @param db The SQL DB @@ -438,102 +436,29 @@ private: */ int insert_replace(SqlDB *db, bool replace); - /** - * Callback function to unmarshall a Host object (Host::select) - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int select_cb(void *nil, int num, char **values, char **names); - /** * Bootstraps the database table(s) associated to the Host */ static void bootstrap(SqlDB * db) { ostringstream oss_host(Host::db_bootstrap); - ostringstream oss_share(HostShare::db_bootstrap); db->exec(oss_host); - db->exec(oss_share); }; -protected: - - // ************************************************************************* - // Constructor - // ************************************************************************* - - Host(int id=-1, - string _hostname="", - string _im_mad_name="", - string _vmm_mad_name="", - string _tm_mad_name=""); - - virtual ~Host(); - - // ************************************************************************* - // DataBase implementation - // ************************************************************************* - - enum ColNames - { - OID = 0, - HOST_NAME = 1, - STATE = 2, - IM_MAD = 3, - VM_MAD = 4, - TM_MAD = 5, - LAST_MON_TIME = 6, - CLUSTER = 7, - TEMPLATE = 8, - LIMIT = 9 - }; - - static const char * db_names; - - static const char * db_bootstrap; - - static const char * table; - - /** - * Reads the Host (identified with its OID=HID) from the database. - * @param db pointer to the db - * @return 0 on success - */ - virtual int select(SqlDB *db); - /** * Writes the Host and its associated HostShares in the database. * @param db pointer to the db * @return 0 on success */ - virtual int insert(SqlDB *db, string& error_str); + int insert(SqlDB *db, string& error_str); /** * Writes/updates the Hosts data fields in the database. * @param db pointer to the db * @return 0 on success */ - virtual int update(SqlDB *db); - - /** - * Drops host from the database - * @param db pointer to the db - * @return 0 on success - */ - virtual int drop(SqlDB *db); - - /** - * Function to output a Host object in to an stream in 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 dump(ostringstream& oss, int num, char **values, char **names); + int update(SqlDB *db); }; #endif /*HOST_H_*/ diff --git a/include/HostPool.h b/include/HostPool.h index ff2ffda2b9..4dcf149bbe 100644 --- a/include/HostPool.h +++ b/include/HostPool.h @@ -19,7 +19,6 @@ #include "PoolSQL.h" #include "Host.h" -#include "ClusterPool.h" #include #include @@ -69,14 +68,24 @@ public: return static_cast(PoolSQL::get(oid,lock)); }; + /** + * Function to get a Host from the pool, if the object is not in memory + * it is loaded from the DB + * @param hostname + * @param lock locks the Host mutex + * @return a pointer to the Host, 0 if the Host could not be loaded + */ + Host * get(string name, bool lock) + { + return static_cast(PoolSQL::get(name,-1,lock)); + }; + /** * Bootstraps the database table(s) associated to the Host pool */ static void bootstrap(SqlDB *_db) { Host::bootstrap(_db); - - ClusterPool::bootstrap(_db); }; /** @@ -138,102 +147,25 @@ public: * * @return 0 on success */ - int dump(ostringstream& oss, const string& where); - - /* ---------------------------------------------------------------------- */ - /* ---------------------------------------------------------------------- */ - /* Methods for cluster management */ - /* ---------------------------------------------------------------------- */ - /* ---------------------------------------------------------------------- */ - - /** - * Returns true if the clid is an id for an existing cluster - * @param clid ID of the cluster - * - * @return true if the clid is an id for an existing cluster - */ - /* bool exists_cluster(int clid) + int dump(ostringstream& oss, const string& where) { - return cluster_pool.exists(clid); - };*/ - - /** - * Allocates a new cluster in the pool - * @param clid the id assigned to the cluster - * @return the id assigned to the cluster or -1 in case of failure - */ - int allocate_cluster(int * clid, const string& name, string& error_str) - { - return cluster_pool.allocate(clid, name, db, error_str); + return PoolSQL::dump(oss, "HOST_POOL", Host::table, where); }; /** - * Returns the xml representation of the given cluster - * @param clid ID of the cluster + * Finds a set objects that satisfies a given condition + * @param oids a vector with the oids of the objects. + * @param the name of the DB table. + * @param where condition in SQL format. * - * @return the xml representation of the given cluster + * @return 0 on success */ - string info_cluster(int clid) + int search(vector& oids, const string& where) { - return cluster_pool.info(clid); - }; - - /** - * Removes the given cluster from the pool and the DB - * @param clid ID of the cluster - * - * @return 0 on success - */ - int drop_cluster(int clid); - - /** - * Dumps the cluster pool in XML format. - * @param oss the output stream to dump the pool contents - * - * @return 0 on success - */ - int dump_cluster(ostringstream& oss) - { - return cluster_pool.dump(oss); - }; - - /** - * Assigns the host to the given cluster - * @param host The host to assign - * @param clid ID of the cluster - * - * @return 0 on success - */ - int set_cluster(Host* host, int clid) - { - map::iterator it; - - it = cluster_pool.cluster_names.find(clid); - - if (it == cluster_pool.cluster_names.end()) - { - return -1; - } - - return host->set_cluster( it->second ); - }; - - /** - * Removes the host from the given cluster setting the default one. - * @param host The host to assign - * - * @return 0 on success - */ - int set_default_cluster(Host* host) - { - return host->set_cluster(ClusterPool::DEFAULT_CLUSTER_NAME); + return PoolSQL::search(oids, Host::table, where); }; private: - /** - * ClusterPool, clusters defined and persistance functionality - */ - ClusterPool cluster_pool; /** * Factory method to produce Host objects @@ -244,15 +176,6 @@ private: return new Host; }; - /** - * Callback function to build the cluster pool - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int init_cb(void *nil, int num, char **values, char **names); - /** * Callback function to get the IDs of the hosts to be monitored * (Host::discover) @@ -262,16 +185,6 @@ private: * @return 0 on success */ int discover_cb(void * _map, int num, char **values, char **names); - - /** - * Callback function to get output the host pool in XML format - * (Host::dump) - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int dump_cb(void * _oss, int num, char **values, char **names); }; #endif /*HOST_POOL_H_*/ diff --git a/include/HostShare.h b/include/HostShare.h index 29e0dc9960..9cd1422a51 100644 --- a/include/HostShare.h +++ b/include/HostShare.h @@ -17,8 +17,7 @@ #ifndef HOST_SHARE_H_ #define HOST_SHARE_H_ -#include "SqlDB.h" -#include "ObjectSQL.h" +#include "ObjectXML.h" #include using namespace std; @@ -29,12 +28,11 @@ using namespace std; /** * The HostShare class. It represents a logical partition of a host... */ -class HostShare : public ObjectSQL +class HostShare : public ObjectXML { public: HostShare( - int _hsid=-1, int _max_disk=0, int _max_mem=0, int _max_cpu=0); @@ -92,14 +90,6 @@ public: */ friend ostream& operator<<(ostream& os, HostShare& hs); - /** - * 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& to_str(string& str) const; - /** * Function to print the HostShare object into a string in * XML format @@ -110,8 +100,6 @@ public: private: - 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) */ @@ -128,7 +116,7 @@ private: int used_mem; /**< Used memory from the IM monitor */ int used_cpu; /**< Used cpu from the IM monitor */ - int running_vms; /**< Number of running VMs in this Host */ + int running_vms;/**< Number of running VMs in this Host */ // ---------------------------------------- // Friends @@ -137,95 +125,13 @@ private: friend class Host; friend class HostPool; - // ---------------------------------------- - // DataBase implementation variables - // ---------------------------------------- - - enum ColNames - { - 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; - - static const char * db_names; - - static const char * db_bootstrap; - - // ---------------------------------------- - // Database methods - // ---------------------------------------- - /** - * Reads the HostShare (identified with its HSID) from the database. - * @param db pointer to the db - * @return 0 on success + * Rebuilds the object from an xml node + * @param node The xml node pointer + * + * @return 0 on success, -1 otherwise */ - int select(SqlDB * db); - - /** - * Writes the HostShare in the database. - * @param db pointer to the db - * @return 0 on success - */ - int insert(SqlDB * db, string& error_str); - - /** - * Writes/updates the HostShare data fields in the database. - * @param db pointer to the db - * @return 0 on success - */ - int update(SqlDB * db); - - /** - * Drops hostshare from the database - * @param db pointer to the db - * @return 0 on success - */ - int drop(SqlDB * db); - - /** - * Execute an INSERT or REPLACE Sql query. - * @param db The SQL DB - * @param replace Execute an INSERT or a REPLACE - * @return 0 one success - */ - int insert_replace(SqlDB *db, bool replace); - - /** - * Callback function to unmarshall a HostShare object (HostShare::select) - * @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 select_cb(void * nil, int num, char **values, char **names); - - /** - * 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 dump(ostringstream& oss, int num, char **values, char **names); - + int from_xml_node(const xmlNodePtr node); }; - #endif /*HOST_SHARE_H_*/ diff --git a/include/Image.h b/include/Image.h index 72aa5bab52..90b4a116ee 100644 --- a/include/Image.h +++ b/include/Image.h @@ -59,13 +59,6 @@ public: // Image Public Methods // ************************************************************************* - /** - * Function to print the Image 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 Image object into a string in XML format * @param xml the resulting XML string @@ -74,31 +67,12 @@ public: string& to_xml(string& xml) const; /** - * Get the Image unique identifier IID, that matches the OID of the object - * @return IID Image identifier + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise */ - int get_iid() const - { - return oid; - }; - - /** - * Gets the uid of the owner of the Image - * @return uid - **/ - int get_uid() - { - return uid; - } - - /** - * Returns Image's name - * @return name Image's name - */ - const string& get_name() const - { - return name; - }; + int from_xml(const string &xml_str); /** * Returns true if the image is public @@ -356,34 +330,29 @@ private: // ------------------------------------------------------------------------- /** - * Owner if the image + * Image owner's name */ - int uid; - - /** - * The name of the Image - */ - string name; + string user_name; /** * Type of the Image */ - ImageType type; + ImageType type; /** * Public scope of the Image */ - int public_img; + int public_img; /** * Persistency of the Image */ - int persistent_img; + int persistent_img; /** * Registration time */ - time_t regtime; + time_t regtime; /** * Path to the image @@ -422,15 +391,6 @@ private: */ int insert_replace(SqlDB *db, bool replace); - /** - * Callback function to unmarshall a Image object (Image::select) - * @param num the number of columns read from the DB - * @param names the column names - * @param values the column values - * @return 0 on success - */ - int select_cb(void *nil, int num, char **values, char **names); - /** * Bootstraps the database table(s) associated to the Image */ @@ -455,7 +415,9 @@ protected: // Constructor // ************************************************************************* - Image(int uid=-1, ImageTemplate *img_template = 0); + Image(int uid, + const string& user_name, + ImageTemplate* img_template); virtual ~Image(); @@ -463,37 +425,12 @@ protected: // DataBase implementation // ************************************************************************* - enum ColNames - { - OID = 0, /* Image identifier (IID) */ - UID = 1, /* Image owner id */ - NAME = 2, /* Image name */ - TYPE = 3, /* 0) OS 1) CDROM 2) DATABLOCK */ - PUBLIC = 4, /* Public scope (YES OR NO) */ - PERSISTENT = 5, /* Peristency (YES OR NO) */ - REGTIME = 6, /* Time of registration */ - SOURCE = 7, /* Path to the image */ - STATE = 8, /* 0) INIT 1) ALLOCATED */ - RUNNING_VMS = 9, /* Number of VMs using the img */ - TEMPLATE = 10, /* Image template xml data */ - LIMIT = 11 - }; - - static const char * extended_db_names; - static const char * db_names; static const char * db_bootstrap; static const char * table; - /** - * Reads the Image (identified with its OID=IID) from the database. - * @param db pointer to the db - * @return 0 on success - */ - virtual int select(SqlDB *db); - /** * Writes the Image in the database. * @param db pointer to the db @@ -507,23 +444,6 @@ protected: * @return 0 on success */ virtual int update(SqlDB *db); - - /** - * Drops Image and associated template from the database - * @param db pointer to the db - * @return 0 on success - */ - virtual int drop(SqlDB *db); - - /** - * Function to output an Image object in to an stream in 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 dump(ostringstream& oss, int num, char **values, char **names); }; #endif /*IMAGE_H_*/ diff --git a/include/ImagePool.h b/include/ImagePool.h index e65d6f2a27..d319ff1dda 100644 --- a/include/ImagePool.h +++ b/include/ImagePool.h @@ -38,10 +38,10 @@ class ImagePool : public PoolSQL { public: - ImagePool(SqlDB * db, - const string& _source_prefix, - const string& _default_type, - const string& _default_dev_prefix); + ImagePool(SqlDB * db, + const string& _source_prefix, + const string& _default_type, + const string& _default_dev_prefix); ~ImagePool(){}; @@ -56,20 +56,19 @@ public: */ int allocate ( int uid, + string user_name, ImageTemplate * img_template, int * oid, string& error_str); /** - * Function to get a Image from the pool, if the object is not in memory + ** Function to get a Image from the pool, if the object is not in memory * it is loaded from the DB * @param oid Image unique id * @param lock locks the Image mutex * @return a pointer to the Image, 0 if the Image could not be loaded */ - Image * get( - int oid, - bool lock) + Image * get(int oid, bool lock) { return static_cast(PoolSQL::get(oid,lock)); }; @@ -78,25 +77,15 @@ public: * Function to get an Image from the pool using the image name * @param name of the image * @param lock locks the User mutex - * @return a pointer to the Image, 0 if the User could not be loaded + * @return a pointer to the Image, 0 if the image could not be loaded */ - Image * get( - const string& name, - bool lock) + Image * get(const string& name, int uid, bool lock) { - map::iterator index; - - index = image_names.find(name); - - if ( index != image_names.end() ) - { - return get((int)index->second,lock); - } - - return 0; + return static_cast(PoolSQL::get(name,uid,lock)); } - /** Update a particular Image + /** + * Update a particular Image * @param image pointer to Image * @return 0 on success */ @@ -111,14 +100,7 @@ public: */ int drop(Image * image) { - int rc = PoolSQL::drop(image); - - if ( rc == 0) - { - image_names.erase(image->get_name()); - } - - return rc; + return PoolSQL::drop(image); }; /** @@ -136,7 +118,10 @@ public: * @param where filter for the objects, defaults to all * @return 0 on success */ - int dump(ostringstream& oss, const string& where); + int dump(ostringstream& oss, const string& where) + { + return PoolSQL::dump(oss, "IMAGE_POOL", Image::table, where); + } /** * Generates a DISK attribute for VM templates using the Image metadata @@ -145,18 +130,21 @@ public: * @param index number of datablock images used by the same VM. Will be * automatically increased. * @param img_type will be set to the used image's type + * @param uid of VM owner (to look for the image id within its images) * @return 0 on success, -1 error, -2 not using the pool */ int disk_attribute(VectorAttribute * disk, int disk_id, int * index, - Image::ImageType * img_type); + Image::ImageType * img_type, + int uid); /** * Generates an Authorization token for the DISK attribute * @param disk the disk to be authorized + * @param uid of owner (to look for the image id within her images) * @param ar the AuthRequest */ - void authorize_disk(VectorAttribute * disk, AuthRequest * ar); + void authorize_disk(VectorAttribute * disk, int uid, AuthRequest * ar); static const string& source_prefix() { @@ -180,54 +168,29 @@ private: /** * Path to the image repository **/ - static string _source_prefix; + static string _source_prefix; /** * Default image type **/ - static string _default_type; + static string _default_type; /** * Default device prefix **/ - static string _default_dev_prefix; + static string _default_dev_prefix; //-------------------------------------------------------------------------- // Pool Attributes // ------------------------------------------------------------------------- - /** - * This map stores the association between IIDs and Image names - */ - map image_names; - /** * Factory method to produce Image objects * @return a pointer to the new Image */ PoolObjectSQL * create() { - return new Image; + return new Image(-1,"",0); }; - - /** - * Callback function to get output the image pool in XML format - * (Image::dump) - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int dump_cb(void * _oss, int num, char **values, char **names); - - /** - * Callback function to build the image_names map - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int init_cb(void *nil, int num, char **values, char **names); - }; #endif /*IMAGE_POOL_H_*/ diff --git a/include/Leases.h b/include/Leases.h index 280e051953..ef38c2c13b 100644 --- a/include/Leases.h +++ b/include/Leases.h @@ -18,6 +18,7 @@ #define LEASES_H_ #include "ObjectSQL.h" +#include "ObjectXML.h" #include "Attribute.h" #include @@ -40,7 +41,8 @@ public: * @param _size the max number of leases */ Leases(SqlDB * _db, int _oid, unsigned long _size): - oid(_oid), size(_size), db(_db){}; + ObjectSQL(), + oid(_oid), size(_size), n_used(0), db(_db){}; virtual ~Leases() { @@ -108,7 +110,7 @@ protected: * The Lease class, it represents a pair of IP and MAC assigned to * a Virtual Machine */ - class Lease + class Lease : public ObjectXML { public: /** @@ -129,13 +131,19 @@ protected: * @param _used, the lease is in use */ Lease(unsigned int _ip, unsigned int _mac[], int _vid, bool _used=true) - :ip(_ip), vid(_vid), used(_used) + :ObjectXML(),ip(_ip), vid(_vid), used(_used) { // TODO check size mac[PREFIX]=_mac[PREFIX]; mac[SUFFIX]=_mac[SUFFIX]; }; + /** + * Creates a new empty lease. Method from_xml should be called right + * after this constructor. + */ + Lease():ObjectXML(){}; + ~Lease(){}; /** @@ -172,14 +180,6 @@ protected: */ 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 @@ -188,6 +188,23 @@ protected: */ string& to_xml(string& xml) const; + /** + * Function to print the Lease object into a string in + * XML format. The output contains all the internal attributes, + * to be saved in the DB as a blob + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml_db(string& xml) const; + + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + int from_xml(const string &xml_str); + /** * Constants to access the array storing the MAC address */ @@ -227,6 +244,11 @@ protected: */ map leases; + /** + * Number of used leases + */ + int n_used; + // ------------------------------------------------------------------------- // DataBase implementation variables // ------------------------------------------------------------------------- @@ -235,17 +257,6 @@ protected: */ SqlDB * db; - enum ColNames - { - OID = 0, - IP = 1, - MAC_PREFIX = 2, - MAC_SUFFIX = 3, - VID = 4, - USED = 5, - LIMIT = 6 - }; - static const char * table; static const char * db_names; @@ -274,14 +285,6 @@ protected: 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 diff --git a/include/Nebula.h b/include/Nebula.h index ccfbcf7e04..9019ae8ddb 100644 --- a/include/Nebula.h +++ b/include/Nebula.h @@ -75,6 +75,11 @@ public: return ipool; }; + ClusterPool * get_cpool() + { + return cpool; + }; + // -------------------------------------------------------------- // Manager Accessors // -------------------------------------------------------------- @@ -224,7 +229,7 @@ private: // ----------------------------------------------------------------------- Nebula():nebula_configuration(0),db(0),vmpool(0),hpool(0),vnpool(0),upool(0), - ipool(0),lcm(0),vmm(0),im(0),tm(0),dm(0),rm(0),hm(0),authm(0) + ipool(0),cpool(0),lcm(0),vmm(0),im(0),tm(0),dm(0),rm(0),hm(0),authm(0) { const char * nl = getenv("ONE_LOCATION"); @@ -284,6 +289,11 @@ private: delete ipool; } + if ( cpool != 0) + { + delete cpool; + } + if ( vmm != 0) { delete vmm; @@ -370,6 +380,7 @@ private: VirtualNetworkPool * vnpool; UserPool * upool; ImagePool * ipool; + ClusterPool * cpool; // --------------------------------------------------------------- // Nebula Managers diff --git a/src/scheduler/include/ObjectXML.h b/include/ObjectXML.h similarity index 65% rename from src/scheduler/include/ObjectXML.h rename to include/ObjectXML.h index 186309d437..72fa91d878 100644 --- a/src/scheduler/include/ObjectXML.h +++ b/include/ObjectXML.h @@ -60,6 +60,61 @@ public: */ vector operator[] (const char * xpath_expr); + /** + * Gets and sets a xpath attribute, if the attribute is not found a default + * is used + * @param value to set + * @param xpath_expr of the xml element + * @param def default value if the element is not found + * + * @return -1 if default was set + */ + int xpath(string& value, const char * xpath_expr, const char * def); + + /** + * Gets and sets a xpath attribute, if the attribute is not found a default + * is used + * @param value to set + * @param xpath_expr of the xml element + * @param def default value if the element is not found + * + * @return -1 if default was set + */ + int xpath(int& value, const char * xpath_expr, const int& def); + + /** + * Gets and sets a xpath attribute, if the attribute is not found a default + * is used + * @param value to set + * @param xpath_expr of the xml element + * @param def default value if the element is not found + * + * @return -1 if default was set + */ + int xpath(unsigned int& value, const char * xpath_expr, + const unsigned int& def); + + /** + * Gets and sets a xpath attribute, if the attribute is not found a default + * is used + * @param value to set + * @param xpath_expr of the xml element + * @param def default value if the element is not found + * + * @return -1 if default was set + */ + int xpath(time_t& value, const char * xpath_expr, const time_t& def); + + /** + * Gets the value of an element from an xml string + * @param value the value of the element + * @param xml the xml string + * @param xpath the xpath of the target element + * + * @return -1 if the element was not found + */ + static int xpath_value(string& value, const char *xml, const char *xpath); + /** * Get xml nodes by Xpath * @param xpath_expr the Xpath for the elements @@ -67,14 +122,21 @@ public: * returned as pointers to the object nodes. * @return the number of nodes found */ - int get_nodes (const char * xpath_expr, vector& content); + int get_nodes(const char * xpath_expr, vector& content); /** * Updates the object representation with a new XML document. Previous * XML resources are freed * @param xml_doc the new xml document */ - int update(const string &xml_doc); + int update_from_str(const string &xml_doc); + + /** + * Updates the object representation with a new XML document. Previous + * XML resources are freed + * @param xml_doc the new xml document + */ + int update_from_node(const xmlNodePtr node); // --------------------------------------------------------- // Lex & bison parser for requirements and rank expressions diff --git a/include/PoolObjectSQL.h b/include/PoolObjectSQL.h index b64c35c76f..fc8727004c 100644 --- a/include/PoolObjectSQL.h +++ b/include/PoolObjectSQL.h @@ -18,7 +18,9 @@ #define POOL_OBJECT_SQL_H_ #include "ObjectSQL.h" +#include "ObjectXML.h" #include +#include using namespace std; @@ -31,11 +33,13 @@ using namespace std; * is called. */ -class PoolObjectSQL : public ObjectSQL +class PoolObjectSQL : public ObjectSQL, public ObjectXML { public: - PoolObjectSQL(int id=-1):oid(id),valid(true) + PoolObjectSQL(int id, const string& _name, int _uid,const char *_table) + :ObjectSQL(),ObjectXML(),oid(id),name(_name),uid(_uid), + valid(true),table(_table) { pthread_mutex_init(&mutex,0); }; @@ -47,11 +51,25 @@ public: pthread_mutex_destroy(&mutex); }; + /* --------------------------------------------------------------------- */ + int get_oid() const { return oid; }; + const string& get_name() const + { + return name; + }; + + int get_uid() + { + return uid; + }; + + /* --------------------------------------------------------------------- */ + /** * Check if the object is valid * @return true if object is valid @@ -68,7 +86,7 @@ public: void set_valid(const bool _valid) { valid = _valid; - } + }; /** * Function to lock the object @@ -86,17 +104,99 @@ public: pthread_mutex_unlock(&mutex); }; + /** + * Function to print the object into a string in XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + virtual string& to_xml(string& xml) const = 0; + + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + virtual int from_xml(const string &xml_str) = 0; + protected: /** - * The object unique ID + * Callback function to unmarshall a PoolObjectSQL + * @param num the number of columns read from the DB + * @param names the column names + * @param vaues the column values + * @return 0 on success */ - int oid; + int select_cb(void *nil, int num, char **values, char **names) + { + if ( (!values[0]) || (num != 1) ) + { + return -1; + } + + return from_xml(values[0]); + }; /** - * The contents ob this object are valid + * Reads the PoolObjectSQL (identified by its OID) from the database. + * @param db pointer to the db + * @return 0 on success */ - bool valid; + virtual int select(SqlDB *db); + + /** + * Reads the PoolObjectSQL (identified by its OID) from the database. + * @param db pointer to the db + * @return 0 on success + */ + virtual int select(SqlDB *db, const string& _name, int _uid); + + /** + * Drops object from the database + * @param db pointer to the db + * @return 0 on success + */ + virtual int drop(SqlDB *db); + + /** + * Function to output a pool object into a stream in 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 dump(ostringstream& oss, int num, char **values, char **names) + { + if ( (!values[0]) || (num != 1) ) + { + return -1; + } + + oss << values[0]; + return 0; + }; + + /** + * The object's unique ID + */ + int oid; + + /** + * The object's name + */ + string name; + + /** + * Object's owner, set it to -1 if owner is not used + */ + int uid; + + /** + * The contents of this object are valid + */ + bool valid; private: @@ -110,6 +210,11 @@ private: * IS LOCKED when the class destructor is called. */ pthread_mutex_t mutex; + + /** + * Pointer to the SQL table for the PoolObjectSQL + */ + const char * table; }; #endif /*POOL_OBJECT_SQL_H_*/ diff --git a/include/PoolSQL.h b/include/PoolSQL.h index d095e692ab..fef4fee546 100644 --- a/include/PoolSQL.h +++ b/include/PoolSQL.h @@ -45,6 +45,7 @@ public: * @param _db a pointer to the database * @param table the name of the table supporting the pool (to set the oid * counter). If null the OID counter is not updated. + * @param with_uid the Pool objects have an owner id (uid) */ PoolSQL(SqlDB * _db, const char * table); @@ -68,9 +69,18 @@ public: * * @return a pointer to the object, 0 in case of failure */ - virtual PoolObjectSQL * get( - int oid, - bool lock); + PoolObjectSQL * get(int oid, bool lock); + + /** + * Gets an object from the pool (if needed the object is loaded from the + * database). + * @param name of the object + * @param uid id of owner + * @param lock locks the object if true + * + * @return a pointer to the object, 0 in case of failure + */ + PoolObjectSQL * get(const string& name, int uid, bool lock); /** * Finds a set objects that satisfies a given condition @@ -141,6 +151,27 @@ protected: */ SqlDB * db; + /** + * Dumps the pool in XML format. A filter can be also added to the + * query + * @param oss the output stream to dump the pool contents + * @param elem_name Name of the root xml pool name + * @param table Pool table name + * @param where filter for the objects, defaults to all + * + * @return 0 on success + */ + int dump(ostringstream& oss, const string& elem_name, + const char * table, const string& where); + + /** + * Returns the value of the last identifier assigned by the pool + */ + int get_lastOID() + { + return lastOID; + }; + private: pthread_mutex_t mutex; @@ -156,7 +187,7 @@ private: * Last object ID assigned to an object. It must be initialized by the * target pool. */ - int lastOID; + int lastOID; /** * The pool is implemented with a Map of SQL object pointers, using the @@ -164,6 +195,12 @@ private: */ map pool; + /** + * This is a name index for the pool map. The key is the name of the object + * , that may be combained with the owner id. + */ + map name_pool; + /** * Factory method, must return an ObjectSQL pointer to an allocated pool * specific object. @@ -200,6 +237,25 @@ private: */ void replace(); + /** + * Generate an index key for the object + * @param name of the object + * @param uid owner of the object, only used if needed + * + * @return the key, a string + */ + string key(const string& name, int uid) + { + ostringstream key; + + key << name << ':' << uid; + + return key.str(); + }; + + /* ---------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ + /** * Callback to set the lastOID (PoolSQL::PoolSQL) */ @@ -209,6 +265,15 @@ private: * Callback to store the IDs of pool objects (PoolSQL::search) */ int search_cb(void *_oids, int num, char **values, char **names); + + /** + * Callback function to get output in XML format + * @param num the number of columns read from the DB + * @param names the column names + * @param vaues the column values + * @return 0 on success + */ + int dump_cb(void * _oss, int num, char **values, char **names); }; #endif /*POOL_SQL_H_*/ diff --git a/include/RequestManager.h b/include/RequestManager.h index 11d589f88b..ca45567335 100644 --- a/include/RequestManager.h +++ b/include/RequestManager.h @@ -23,6 +23,7 @@ #include "UserPool.h" #include "VirtualNetworkPool.h" #include "ImagePool.h" +#include "ClusterPool.h" #include #include @@ -44,10 +45,12 @@ public: VirtualNetworkPool * _vnpool, UserPool * _upool, ImagePool * _ipool, + ClusterPool * _cpool, int _port, string _xml_log_file) :vmpool(_vmpool),hpool(_hpool),vnpool(_vnpool),upool(_upool), - ipool(_ipool),port(_port),socket_fd(-1),xml_log_file(_xml_log_file) + ipool(_ipool),cpool(_cpool),port(_port),socket_fd(-1), + xml_log_file(_xml_log_file) { am.addListener(this); }; @@ -126,6 +129,11 @@ private: */ ImagePool * ipool; + /** + * Pointer to the Image Pool, to access images + */ + ClusterPool * cpool; + /** * Port number where the connection will be open */ @@ -478,7 +486,7 @@ private: vmpool(_vmpool), upool(_upool) { - _signature="A:sibi"; + _signature="A:sii"; _help="Returns the virtual machine pool"; }; @@ -632,10 +640,10 @@ private: { public: ClusterAllocate( - HostPool * _hpool, - UserPool * _upool): - hpool(_hpool), - upool(_upool) + UserPool * _upool, + ClusterPool * _cpool): + upool(_upool), + cpool(_cpool) { _signature="A:ss"; _help="Allocates a cluster in the pool"; @@ -648,8 +656,8 @@ private: xmlrpc_c::value * const retvalP); private: - HostPool * hpool; - UserPool * upool; + UserPool * upool; + ClusterPool * cpool; }; /* ---------------------------------------------------------------------- */ @@ -658,10 +666,10 @@ private: { public: ClusterInfo( - HostPool * _hpool, - UserPool * _upool): - hpool(_hpool), - upool(_upool) + UserPool * _upool, + ClusterPool * _cpool): + upool(_upool), + cpool(_cpool) { _signature="A:si"; _help="Returns cluster information"; @@ -674,8 +682,8 @@ private: xmlrpc_c::value * const retvalP); private: - HostPool * hpool; - UserPool * upool; + UserPool * upool; + ClusterPool * cpool; }; /* ---------------------------------------------------------------------- */ @@ -684,10 +692,10 @@ private: { public: ClusterDelete( - HostPool * _hpool, - UserPool * _upool): - hpool(_hpool), - upool(_upool) + UserPool * _upool, + ClusterPool * _cpool): + upool(_upool), + cpool(_cpool) { _signature="A:si"; _help="Deletes a cluster from the pool"; @@ -700,8 +708,8 @@ private: xmlrpc_c::value * const retvalP); private: - HostPool * hpool; - UserPool * upool; + UserPool * upool; + ClusterPool * cpool; }; /* ---------------------------------------------------------------------- */ @@ -710,10 +718,12 @@ private: { public: ClusterAdd( - HostPool * _hpool, - UserPool * _upool): + HostPool * _hpool, + UserPool * _upool, + ClusterPool * _cpool): hpool(_hpool), - upool(_upool) + upool(_upool), + cpool(_cpool) { _signature="A:sii"; _help="Adds a host to a cluster"; @@ -726,8 +736,9 @@ private: xmlrpc_c::value * const retvalP); private: - HostPool * hpool; - UserPool * upool; + HostPool * hpool; + UserPool * upool; + ClusterPool * cpool; }; /* ---------------------------------------------------------------------- */ @@ -736,10 +747,12 @@ private: { public: ClusterRemove( - HostPool * _hpool, - UserPool * _upool): + HostPool * _hpool, + UserPool * _upool, + ClusterPool * _cpool): hpool(_hpool), - upool(_upool) + upool(_upool), + cpool(_cpool) { _signature="A:si"; _help="Removes a host from its cluster"; @@ -752,8 +765,9 @@ private: xmlrpc_c::value * const retvalP); private: - HostPool * hpool; - UserPool * upool; + HostPool * hpool; + UserPool * upool; + ClusterPool * cpool; }; /* ---------------------------------------------------------------------- */ @@ -762,10 +776,10 @@ private: { public: ClusterPoolInfo( - HostPool * _hpool, - UserPool * _upool): - hpool(_hpool), - upool(_upool) + UserPool * _upool, + ClusterPool * _cpool): + upool(_upool), + cpool(_cpool) { _signature="A:s"; _help="Returns the cluster pool information"; @@ -778,8 +792,8 @@ private: xmlrpc_c::value * const retvalP); private: - HostPool * hpool; - UserPool * upool; + UserPool * upool; + ClusterPool * cpool; }; @@ -1034,6 +1048,27 @@ private: /* ---------------------------------------------------------------------- */ + class UserAuthenticate: public xmlrpc_c::method + { + public: + UserAuthenticate(UserPool * _upool):upool(_upool) + { + _signature="A:s"; + _help="Authenticates the user."; + }; + + ~UserAuthenticate(){}; + + void execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retvalP); + + private: + UserPool * upool; + }; + + /* ---------------------------------------------------------------------- */ + class UserInfo: public xmlrpc_c::method { public: diff --git a/include/Template.h b/include/Template.h index 1f4a703302..d81cf4b8c2 100644 --- a/include/Template.h +++ b/include/Template.h @@ -176,6 +176,14 @@ public: */ int from_xml(const string &xml_str); + /** + * Rebuilds the object from an xml node + * @param node The xml node pointer + * + * @return 0 on success, -1 otherwise + */ + int from_xml_node(const xmlNodePtr node); + protected: /** * The template attributes @@ -215,6 +223,12 @@ private: * Name of the Root element for the XML document */ string xml_root; + + /** + * Builds the template attribute from the node + * @param root_element The xml element to build the template from. + */ + void rebuild_attributes(const xmlNode * root_element); }; /* -------------------------------------------------------------------------- */ diff --git a/include/User.h b/include/User.h index 9806b4839a..c2437bc617 100644 --- a/include/User.h +++ b/include/User.h @@ -36,13 +36,6 @@ public: */ 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 @@ -50,15 +43,6 @@ public: */ 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; - }; - /** * Check if the user is enabled * @return true if the user is enabled @@ -68,15 +52,6 @@ public: 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 @@ -102,14 +77,6 @@ public: enabled = false; }; - /** - * Sets user username - */ - void set_username(string _username) - { - username = _username; - }; - /** * Sets user password */ @@ -145,11 +112,6 @@ private: // User Attributes // ------------------------------------------------------------------------- - /** - * User's username - */ - string username; - /** * User's password */ @@ -191,16 +153,24 @@ private: db->exec(oss_user); }; + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + int from_xml(const string &xml_str); + protected: // ************************************************************************* // Constructor // ************************************************************************* - User(int id=-1, - string _username="", - string _password="", - bool _enabled=true); + User(int id, + string _username, + string _password, + bool _enabled); virtual ~User(); @@ -208,58 +178,28 @@ protected: // 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(SqlDB *db); - /** * Writes the User in the database. * @param db pointer to the db * @return 0 on success */ - virtual int insert(SqlDB *db, string& error_str); + int insert(SqlDB *db, string& error_str); /** * Writes/updates the User data fields in the database. * @param db pointer to the db * @return 0 on success */ - virtual int update(SqlDB *db); - - /** - * Drops USer from the database - * @param db pointer to the db - * @return 0 on success - */ - virtual int drop(SqlDB *db); - - /** - * Function to output a User object in to an stream in 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 dump(ostringstream& oss, int num, char **values, char **names); + int update(SqlDB *db) + { + return insert_replace(db, true); + } }; #endif /*USER_H_*/ diff --git a/include/UserPool.h b/include/UserPool.h index 4a68ae2e99..e381deb017 100644 --- a/include/UserPool.h +++ b/include/UserPool.h @@ -59,17 +59,12 @@ public: * 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 + * @return a pointer to the User, 0 if the User could not be loaded */ - User * get( - int oid, - bool lock) + User * get(int oid, bool lock) { - User * user = static_cast(PoolSQL::get(oid,lock)); - - return user; - } - + return static_cast(PoolSQL::get(oid,lock)); + }; /** * Function to get a User from the pool, if the object is not in memory @@ -78,21 +73,10 @@ public: * @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) + User * get(string name, bool lock) { - map::iterator index; - - index = known_users.find(username); - - if ( index != known_users.end() ) - { - return get((int)index->second,lock); - } - - return 0; - } + return static_cast(PoolSQL::get(name,-1,lock)); + }; /** Update a particular User * @param user pointer to User @@ -103,20 +87,12 @@ public: 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 = PoolSQL::drop(user); - - if ( rc == 0) - { - known_users.erase(user->get_username()); - } - - return rc; + return PoolSQL::drop(user); }; /** @@ -149,7 +125,10 @@ public: * * @return 0 on success */ - int dump(ostringstream& oss, const string& where); + int dump(ostringstream& oss, const string& where) + { + return PoolSQL::dump(oss, "USER_POOL", User::table, where); + }; private: /** @@ -158,33 +137,8 @@ private: */ PoolObjectSQL * create() { - return new User; + return new User(-1,"","",true); }; - - /** - * This map stores the association between UIDs and Usernames - */ - map known_users; - - /** - * Callback function to get output the user pool in XML format - * (User::dump) - * @param _oss pointer to 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 - */ - int dump_cb(void * _oss, int num, char **values, char **names); - - /** - * Callback function to build the knwon_user map (User::User) - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int init_cb(void *nil, int num, char **values, char **names); }; #endif /*USER_POOL_H_*/ diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 789f0ad095..970a0ae22f 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -119,14 +119,6 @@ public: */ friend ostream& operator<<(ostream& os, const VirtualMachine& vm); - /** - * Function to print the VirtualMachine 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 VirtualMachine object into a string in * XML format @@ -135,6 +127,14 @@ public: */ string& to_xml(string& xml) const; + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + int from_xml(const string &xml_str); + // ------------------------------------------------------------------------ // Dynamic Info // ------------------------------------------------------------------------ @@ -183,16 +183,6 @@ public: } }; - - /** - * 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 @@ -218,11 +208,11 @@ public: * Adds a new history record an writes it in the database. */ void add_history( - int hid, - string& hostname, - string& vm_dir, - string& vmm_mad, - string& tm_mad); + int hid, + const string& hostname, + const string& vm_dir, + const string& vmm_mad, + const string& tm_mad); /** * Duplicates the last history record. Only the host related fields are @@ -678,16 +668,6 @@ public: lcm_state = s; }; - /** - * Gets the user id of the owner of this VM - * @return the VM uid - */ - int get_uid() const - { - return uid; - }; - - // ------------------------------------------------------------------------ // Timers // ------------------------------------------------------------------------ @@ -733,6 +713,7 @@ public: /** * Get all disk images for this Virtual Machine + * @param error_str Returns the error reason, if any * @return 0 if success */ int get_disk_images(string &error_str); @@ -753,7 +734,6 @@ public: */ int generate_context(string &files); - // ------------------------------------------------------------------------ // Image repository related functions // ------------------------------------------------------------------------ @@ -779,11 +759,10 @@ private: // ------------------------------------------------------------------------- // Identification variables // ------------------------------------------------------------------------- - /** - * User (owner) id + * Owner's name */ - int uid; + string user_name; // ------------------------------------------------------------------------- // VM Scheduling & Managing Information @@ -797,11 +776,6 @@ private: // Virtual Machine Description // ------------------------------------------------------------------------- - /** - * Name of the VM - */ - string name; - /** * The Virtual Machine template, holds the VM attributes. */ @@ -854,11 +828,6 @@ private: */ int net_rx; - /** - * Sequence number of the last history item. - */ - int last_seq; - /** * History record, for the current host */ @@ -958,16 +927,18 @@ private: /** * Parse the "CONTEXT" attribute of the template by substituting * $VARIABLE, $VARIABLE[ATTR] and $VARIABLE[ATTR, ATTR = VALUE] + * @param error_str Returns the error reason, if any * @return 0 on success */ - int parse_context(); + int parse_context(string& error_str); /** * Parse the "REQUIREMENTS" attribute of the template by substituting * $VARIABLE, $VARIABLE[ATTR] and $VARIABLE[ATTR, ATTR = VALUE] + * @param error_str Returns the error reason, if any * @return 0 on success */ - int parse_requirements(); + int parse_requirements(string& error_str); /** * Parse the "GRAPHICS" attribute and generates a default PORT if not @@ -981,7 +952,8 @@ protected: // Constructor //************************************************************************** - VirtualMachine(int id=-1, VirtualMachineTemplate * _vm_template = 0); + VirtualMachine(int id, int uid, string _user_name, + VirtualMachineTemplate * _vm_template); virtual ~VirtualMachine(); @@ -989,32 +961,10 @@ protected: // DataBase implementation // ************************************************************************* - enum ColNames - { - OID = 0, - UID = 1, - NAME = 2, - LAST_POLL = 3, - STATE = 4, - LCM_STATE = 5, - STIME = 6, - ETIME = 7, - DEPLOY_ID = 8, - MEMORY = 9, - CPU = 10, - NET_TX = 11, - NET_RX = 12, - LAST_SEQ = 13, - TEMPLATE = 14, - LIMIT = 15 - }; - static const char * table; static const char * db_names; - static const char * extended_db_names; - static const char * db_bootstrap; /** @@ -1029,48 +979,28 @@ protected: * @param db pointer to the db * @return 0 on success */ - virtual int insert(SqlDB * db, string& error_str); + int insert(SqlDB * db, string& error_str); /** * Writes/updates the Virtual Machine data fields in the database. * @param db pointer to the db * @return 0 on success */ - virtual int update(SqlDB * db); + int update(SqlDB * db) + { + return insert_replace(db, true); + } /** * Deletes a VM from the database and all its associated information * @param db pointer to the db * @return -1 */ - virtual int drop(SqlDB * db) + int drop(SqlDB * db) { NebulaLog::log("ONE",Log::ERROR, "VM Drop not implemented!"); return -1; } - - /** - * Dumps the contect of a set of VirtualMachine objects in the given stream - * using 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 dump(ostringstream& oss, int num, char ** values, char ** names); - - /** - * Dumps the contect of a set of VirtualMachine objects in the given stream - * using 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 dump_extended( ostringstream& oss, - int num, char ** values, char ** names); }; #endif /*VIRTUAL_MACHINE_H_*/ diff --git a/include/VirtualMachinePool.h b/include/VirtualMachinePool.h index 94f12a2c32..c069357f61 100644 --- a/include/VirtualMachinePool.h +++ b/include/VirtualMachinePool.h @@ -48,11 +48,12 @@ public: * the template */ int allocate ( - int uid, - VirtualMachineTemplate *vm_template, - int * oid, - string& error_str, - bool on_hold = false); + int uid, + string user_name, + VirtualMachineTemplate * vm_template, + int * oid, + string& error_str, + bool on_hold = false); /** * Function to get a VM from the pool, if the object is not in memory @@ -134,7 +135,7 @@ public: */ int dump(ostringstream& oss, const string& where) { - return dump(oss, true, -1, where); + return dump(oss, -1, where); } /** @@ -149,7 +150,7 @@ public: * * @return 0 on success */ - int dump(ostringstream& oss, bool extended, int state, const string& where); + int dump(ostringstream& oss, int state, const string& where); private: /** @@ -158,29 +159,8 @@ private: */ PoolObjectSQL * create() { - return new VirtualMachine; + return new VirtualMachine(-1,-1,"", 0); }; - - /** - * Callback function to get output the vm pool in XML format - * (VirtualMachinePool::dump) - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int dump_cb(void * _oss, int num, char **values, char **names); - - /** - * Callback function to get output the vm pool in XML format - * (VirtualMachinePool::dump) - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int dump_extended_cb(void * _oss, int num, char **values, char **names); - }; #endif /*VIRTUAL_MACHINE_POOL_H_*/ diff --git a/include/VirtualNetwork.h b/include/VirtualNetwork.h index 2a67f3bf58..daf20f5d62 100644 --- a/include/VirtualNetwork.h +++ b/include/VirtualNetwork.h @@ -58,24 +58,6 @@ public: // Virtual Network Public Methods // ************************************************************************* - /** - * Get the Vnet unique identifier VNID, that matches the OID of the object - * @return VNID Image identifier - */ - int get_vnid() const - { - return oid; - }; - - /** - * Gets the uid of the owner of the Virtual Network - * @return uid - **/ - int get_uid() - { - return uid; - } - /** * Returns true if the Virtual Network is public * @return true if the Virtual Network is public @@ -175,14 +157,6 @@ public: */ 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 @@ -274,14 +248,9 @@ private: // Identification variables // ------------------------------------------------------------------------- /** - * Name of the Virtual Network + * Owner's name */ - string name; - - /** - * Owner of the Virtual Network - */ - int uid; + string user_name; // ------------------------------------------------------------------------- // Binded physical attributes @@ -341,28 +310,29 @@ private: }; /** - * Callback function to unmarshall a VNW object (VirtualNetwork::select) - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success + * Function to print the VirtualNetwork object into a string in + * XML format + * @param xml the resulting XML string + * @param extended If true, leases are included + * @return a reference to the generated string */ - int select_cb(void * nil, int num, char **values, char **names); + string& to_xml_extended(string& xml, bool extended) const; /** - * Function to drop VN entry in vn_pool - * @return 0 on success + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise */ - int vn_drop(SqlDB * db); - - -protected: + int from_xml(const string &xml_str); //************************************************************************** // Constructor //************************************************************************** - VirtualNetwork(VirtualNetworkTemplate * _vn_template = 0); + VirtualNetwork(int uid, + string _user_name, + VirtualNetworkTemplate * _vn_template = 0); ~VirtualNetwork(); @@ -370,24 +340,10 @@ protected: // DataBase implementation // ************************************************************************* - enum ColNames - { - OID = 0, - UID = 1, - NAME = 2, - TYPE = 3, - BRIDGE = 4, - PUBLIC = 5, - TEMPLATE = 6, - LIMIT = 7 - }; - static const char * table; static const char * db_names; - static const char * extended_db_names; - static const char * db_bootstrap; /** @@ -397,6 +353,23 @@ protected: */ int select(SqlDB * db); + /** + * Reads the Virtual Network (identified with its OID) from the database. + * @param db pointer to the db + * @param name of the network + * @param uid of the owner + * + * @return 0 on success + */ + int select(SqlDB * db, const string& name, int uid); + + /** + * Reads the Virtual Network leases from the database. + * @param db pointer to the db + * @return 0 on success + */ + int select_leases(SqlDB * db); + /** * Writes the Virtual Network and its associated template and leases in the database. * @param db pointer to the db @@ -409,7 +382,10 @@ protected: * @param db pointer to the db * @return 0 on success */ - int update(SqlDB * db); + int update(SqlDB * db) + { + return insert_replace(db, true); + } /** * Deletes a VNW from the database and all its associated information: @@ -418,27 +394,7 @@ protected: * @param db pointer to the db * @return 0 on success */ - int drop(SqlDB * db) - { - int rc; - - rc = leases->drop(db); - - rc += vn_drop(db); - - return rc; - } - - /** - * Dumps the contect of a VirtualNetwork object in the given stream using - * 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 dump(ostringstream& oss, int num, char **values, char **names); + int drop(SqlDB * db); }; #endif /*VIRTUAL_NETWORK_H_*/ diff --git a/include/VirtualNetworkPool.h b/include/VirtualNetworkPool.h index c49aec9323..09e908cf93 100644 --- a/include/VirtualNetworkPool.h +++ b/include/VirtualNetworkPool.h @@ -48,6 +48,7 @@ public: */ int allocate ( int uid, + string user_name, VirtualNetworkTemplate * vn_template, int * oid, string& error_str); @@ -59,9 +60,7 @@ public: * @param lock locks the VN mutex * @return a pointer to the VN, 0 if the VN could not be loaded */ - VirtualNetwork * get( - int oid, - bool lock) + VirtualNetwork * get(int oid, bool lock) { return static_cast(PoolSQL::get(oid,lock)); }; @@ -70,12 +69,14 @@ public: * Function to get a VN from the pool using the network name * If the object is not in memory it is loaded from the DB * @param name VN unique name + * @param uid of the VN owner * @param lock locks the VN mutex * @return a pointer to the VN, 0 if the VN could not be loaded */ - VirtualNetwork * get( - const string& name, - bool lock); + VirtualNetwork * get(const string& name, int uid, bool lock) + { + return static_cast(PoolSQL::get(name,uid,lock)); + }; //-------------------------------------------------------------------------- // Virtual Network DB access functions @@ -88,14 +89,14 @@ public: * @param vid of the VM requesting the lease * @return 0 on success, -1 error, -2 not using the pool */ - int nic_attribute(VectorAttribute * nic, int vid); + int nic_attribute(VectorAttribute * nic, int uid, int vid); /** * Generates an Authorization token for a NIC attribute * @param nic the nic to be authorized * @param ar the AuthRequest */ - void authorize_nic(VectorAttribute * nic, AuthRequest * ar); + void authorize_nic(VectorAttribute * nic, int uid, AuthRequest * ar); /** * Bootstraps the database table(s) associated to the VirtualNetwork pool @@ -113,7 +114,10 @@ public: * * @return 0 on success */ - int dump(ostringstream& oss, const string& where); + int dump(ostringstream& oss, const string& where) + { + return PoolSQL::dump(oss, "VNET_POOL", VirtualNetwork::table,where); + } /** * Get the mac prefix @@ -150,28 +154,8 @@ private: */ PoolObjectSQL * create() { - return new VirtualNetwork(); + return new VirtualNetwork(0,"",0); }; - - /** - * Callback function to get output the virtual network pool in XML format - * (VirtualNetworkPool::dump) - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int dump_cb(void * _oss, int num, char **values, char **names); - - /** - * Callback function to get the ID of a given virtual network - * (VirtualNetworkPool::get) - * @param num the number of columns read from the DB - * @param names the column names - * @param vaues the column values - * @return 0 on success - */ - int get_cb(void * _oss, int num, char **values, char **names); }; #endif /*VIRTUAL_NETWORK_POOL_H_*/ diff --git a/include/test/NebulaTest.h b/include/test/NebulaTest.h index b02cdc3056..18589b0da4 100644 --- a/include/test/NebulaTest.h +++ b/include/test/NebulaTest.h @@ -25,6 +25,7 @@ #include "VirtualNetworkPool.h" #include "HostPool.h" #include "UserPool.h" +#include "ClusterPool.h" #include "VirtualMachineManager.h" #include "LifeCycleManager.h" @@ -41,7 +42,7 @@ protected: NebulaTest():mysql(false), need_host_pool(false), need_vm_pool(false), need_vnet_pool(false), need_image_pool(false), - need_user_pool(false), need_vmm(false), + need_user_pool(false), need_cluster_pool(false),need_vmm(false), need_im(false), need_tm(false), need_lcm(false), need_dm(false), need_rm(false), need_hm(false), @@ -60,6 +61,7 @@ public: bool need_vnet_pool; bool need_image_pool; bool need_user_pool; + bool need_cluster_pool; bool need_vmm; bool need_im; @@ -94,6 +96,8 @@ public: string default_image_type, string default_device_prefix); + virtual ClusterPool* create_cpool(SqlDB* db); + // ------------------------------------------------------------------------ // Managers // ------------------------------------------------------------------------ @@ -122,6 +126,7 @@ public: VirtualNetworkPool * vnpool, UserPool * upool, ImagePool * ipool, + ClusterPool * cpool, string log_file); virtual HookManager* create_hm(VirtualMachinePool * vmpool); diff --git a/include/test/PoolTest.h b/include/test/PoolTest.h index ce952ed3e0..1e5afe32d9 100644 --- a/include/test/PoolTest.h +++ b/include/test/PoolTest.h @@ -166,14 +166,14 @@ public: { // The pool is empty // Non existing oid - obj = pool->get(13, true); + obj = pool->get(13, false); CPPUNIT_ASSERT( obj == 0 ); // Allocate an object allocate(0); // Ask again for a non-existing oid - obj = pool->get(213, true); + obj = pool->get(213, false); CPPUNIT_ASSERT( obj == 0 ); } diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 521791f9f5..9d2bfc2c08 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -363,7 +363,7 @@ VM_HOOK = [ # on = "ERROR", # command = "host_error.rb", # arguments = "$HID -r n", -# remote = no ] +# remote = "no" ] #------------------------------------------------------------------------------- # This two hooks can be used to automatically delete or resubmit VMs that reach # the "failed" state. This way, the administrator doesn't have to interact @@ -374,14 +374,14 @@ VM_HOOK = [ # #VM_HOOK = [ # name = "on_failure_delete", -# on = "FAILURE", -# command = "onevm delete", +# on = "FAILED", +# command = "/usr/bin/env onevm delete", # arguments = "$VMID" ] # #VM_HOOK = [ # name = "on_failure_resubmit", -# on = "FAILURE", -# command = "onevm resubmit", +# on = "FAILED", +# command = "/usr/bin/env onevm resubmit", # arguments = "$VMID" ] #------------------------------------------------------------------------------- diff --git a/share/test/do_tests.sh b/share/test/do_tests.sh index 6eb634a459..c56fa0a3e6 100755 --- a/share/test/do_tests.sh +++ b/share/test/do_tests.sh @@ -6,10 +6,11 @@ TWD_DIR="../../src" BASE_DIR=$PWD TESTS="$TWD_DIR/vnm/test \ - $TWD_DIR/scheduler/src/xml/test \ + $TWD_DIR/xml/test \ $TWD_DIR/scheduler/src/pool/test \ $TWD_DIR/common/test \ $TWD_DIR/host/test \ + $TWD_DIR/cluster/test \ $TWD_DIR/template/test \ $TWD_DIR/image/test \ $TWD_DIR/authm/test \ diff --git a/src/cluster/Cluster.cc b/src/cluster/Cluster.cc new file mode 100644 index 0000000000..185604d78f --- /dev/null +++ b/src/cluster/Cluster.cc @@ -0,0 +1,184 @@ +/* ------------------------------------------------------------------------ */ +/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.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 "Cluster.h" + + +const char * Cluster::table = "cluster_pool"; + +const char * Cluster::db_names = "oid, name, body"; + +const char * Cluster::db_bootstrap = "CREATE TABLE IF NOT EXISTS cluster_pool (" + "oid INTEGER PRIMARY KEY, name VARCHAR(256), body TEXT, UNIQUE(name))"; + + +/* ************************************************************************ */ +/* Cluster :: Constructor/Destructor */ +/* ************************************************************************ */ + +Cluster::Cluster(int id, const string& name):PoolObjectSQL(id,name,-1,table){}; + +Cluster::~Cluster(){}; + +/* ************************************************************************ */ +/* Cluster :: Database Access Functions */ +/* ************************************************************************ */ + +/* ------------------------------------------------------------------------ */ +/* ------------------------------------------------------------------------ */ + +int Cluster::insert(SqlDB *db, string& error_str) +{ + int rc; + + rc = insert_replace(db, false); + + if ( rc != 0 ) + { + error_str = "Error inserting Cluster in DB."; + } + + return rc; +} + +/* ------------------------------------------------------------------------ */ +/* ------------------------------------------------------------------------ */ + +int Cluster::update(SqlDB *db) +{ + int rc; + + rc = insert_replace(db, true); + + return rc; +} + +/* ------------------------------------------------------------------------ */ +/* ------------------------------------------------------------------------ */ + +int Cluster::insert_replace(SqlDB *db, bool replace) +{ + ostringstream oss; + + int rc; + string xml_body; + + char * sql_name; + char * sql_xml; + + // Update the Cluster + + sql_name = db->escape_str(name.c_str()); + + if ( sql_name == 0 ) + { + goto error_name; + } + + sql_xml = db->escape_str(to_xml(xml_body).c_str()); + + if ( sql_xml == 0 ) + { + goto error_body; + } + + if(replace) + { + oss << "REPLACE"; + } + else + { + oss << "INSERT"; + } + + // Construct the SQL statement to Insert or Replace + + oss <<" INTO "<exec(oss); + + db->free_str(sql_name); + db->free_str(sql_xml); + + return rc; + +error_body: + db->free_str(sql_name); +error_name: + return -1; +} + +/* ************************************************************************ */ +/* Cluster :: Misc */ +/* ************************************************************************ */ + +ostream& operator<<(ostream& os, Cluster& cluster) +{ + string cluster_str; + + os << cluster.to_xml(cluster_str); + + return os; +} + +/* ------------------------------------------------------------------------ */ +/* ------------------------------------------------------------------------ */ + +string& Cluster::to_xml(string& xml) const +{ + ostringstream oss; + + oss << + "" << + "" << oid << "" << + "" << name << "" << + ""; + + xml = oss.str(); + + return xml; +} + +/* ------------------------------------------------------------------------ */ +/* ------------------------------------------------------------------------ */ + +int Cluster::from_xml(const string& xml) +{ + int rc = 0; + + // Initialize the internal XML object + update_from_str(xml); + + // Get class base attributes + rc += xpath(oid, "/CLUSTER/ID", -1); + rc += xpath(name,"/CLUSTER/NAME", "not_found"); + + if (rc != 0) + { + return -1; + } + + return 0; +} diff --git a/src/cluster/ClusterPool.cc b/src/cluster/ClusterPool.cc new file mode 100644 index 0000000000..ef1280e8ef --- /dev/null +++ b/src/cluster/ClusterPool.cc @@ -0,0 +1,150 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.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 "ClusterPool.h" +#include "Nebula.h" +#include "NebulaLog.h" + +#include + +const string ClusterPool::DEFAULT_CLUSTER_NAME = "default"; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +ClusterPool::ClusterPool(SqlDB * db):PoolSQL(db, Cluster::table) +{ + // lastOID is set in PoolSQL::init_cb + if (get_lastOID() == -1) + { + int rc; + Cluster * cluster; + string error_str; + + // Build a new Cluster object + cluster = new Cluster(0, ClusterPool::DEFAULT_CLUSTER_NAME); + + // Insert the Object in the pool + rc = PoolSQL::allocate(cluster, error_str); + + if(rc != 0) + { + ostringstream oss; + + oss << "Error trying to create default cluster: " << error_str; + NebulaLog::log("CLUSTER",Log::ERROR,oss); + + throw runtime_error(oss.str()); + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int ClusterPool::allocate(int * oid, string name, string& error_str) +{ + Cluster * cluster; + ostringstream oss; + + if ( name.empty() ) + { + goto error_name; + } + + // Check for duplicates + cluster = get(name, false); + + if( cluster != 0 ) + { + goto error_duplicated; + } + + // Build a new Cluster object + cluster = new Cluster(-1, name); + + // Insert the Object in the pool + *oid = PoolSQL::allocate(cluster, error_str); + + return *oid; + + +error_name: + oss << "NAME cannot be empty."; + goto error_common; + +error_duplicated: + oss << "NAME is already taken by CLUSTER " << cluster->get_oid() << "."; + +error_common: + *oid = -1; + error_str = oss.str(); + + return *oid; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int ClusterPool::drop(Cluster * cluster) +{ + int rc; + + Host* host; + vector hids; + vector::iterator hid_it; + + Nebula& nd = Nebula::instance(); + HostPool * hpool = nd.get_hpool(); + + string cluster_name = cluster->get_name(); + string where = "cluster = '" + cluster_name + "'"; + + // Return error if cluster is 'default' + if( cluster->get_oid() == 0 ) + { + NebulaLog::log("CLUSTER",Log::WARNING, + "Default cluster cannot be deleted."); + + return -1; + } + + rc = cluster->drop(db); + + // Move the hosts assigned to the deleted cluster to the default one + if( rc == 0 ) + { + hpool->search(hids, where); + + for ( hid_it=hids.begin() ; hid_it < hids.end(); hid_it++ ) + { + host = hpool->get(*hid_it, true); + + if ( host == 0 ) + { + continue; + } + + set_default_cluster(host); + + hpool->update(host); + + host->unlock(); + } + } + + return rc; +} diff --git a/src/cluster/SConstruct b/src/cluster/SConstruct new file mode 100644 index 0000000000..9112f8fbba --- /dev/null +++ b/src/cluster/SConstruct @@ -0,0 +1,30 @@ +# SConstruct for src/cluster + +# -------------------------------------------------------------------------- # +# Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.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_cluster' + +# Sources to generate the library +source_files=[ + 'ClusterPool.cc', + 'Cluster.cc' +] + +# Build library +env.StaticLibrary(lib_name, source_files) diff --git a/src/cluster/test/ClusterPoolTest.cc b/src/cluster/test/ClusterPoolTest.cc new file mode 100644 index 0000000000..bdb102dd05 --- /dev/null +++ b/src/cluster/test/ClusterPoolTest.cc @@ -0,0 +1,415 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.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 "ClusterPool.h" +#include "PoolTest.h" + +using namespace std; + +const string names[] = {"cluster_a", "Second cluster"}; + +const string xmls[] = +{ + "1cluster_a", + "2Second cluster" +}; + +const string cluster_default = + "0default"; + +const string cluster_xml_dump = + "0default1cluster_a3cluster_c4cluster_d"; + +const string host_0_cluster = + "0Host one0im_madvmm_madtm_mad0cluster_a0000000000000"; + +const string host_0_default = + "0Host one0" + "im_madvmm_madtm_mad" + "0default" + "000" + "000" + "000" + "000" + "0"; + +/* ************************************************************************* */ +/* ************************************************************************* */ + + +#include "NebulaTest.h" + +class NebulaTestCluster: public NebulaTest +{ +public: + NebulaTestCluster():NebulaTest() + { + NebulaTest::the_tester = this; + + need_host_pool = true; + need_cluster_pool= true; + } +}; + +class ClusterPoolTest : public PoolTest +{ + CPPUNIT_TEST_SUITE (ClusterPoolTest); + + // Not all tests from PoolTest can be used. Because + // of the initial default cluster added to the DB, the + // oid_assignment would fail. + CPPUNIT_TEST (get_from_cache); + CPPUNIT_TEST (get_from_db); + CPPUNIT_TEST (wrong_get); + CPPUNIT_TEST (drop_and_get); + + CPPUNIT_TEST (name_pool); + + CPPUNIT_TEST (duplicates); + CPPUNIT_TEST (set_cluster); + CPPUNIT_TEST (remove_cluster); + CPPUNIT_TEST (delete_cluster); + CPPUNIT_TEST (dump); + + CPPUNIT_TEST_SUITE_END (); + +protected: + + NebulaTestCluster * tester; + HostPool * hpool; + ClusterPool * cpool; + + + + void bootstrap(SqlDB* db) + { + // setUp overwritten + }; + + PoolSQL* create_pool(SqlDB* db) + { + // setUp overwritten + return cpool; + }; + + int allocate(int index) + { + int oid; + string err; + + return cpool->allocate(&oid, names[index], err); + }; + + void check(int index, PoolObjectSQL* obj) + { + Cluster * cluster = static_cast(obj); + + CPPUNIT_ASSERT( obj != 0 ); + + string xml_str = ""; + string name = cluster->get_name(); + + CPPUNIT_ASSERT( name == names[index] ); + + // Get the xml + cluster->to_xml(xml_str); + +// A little help for debugging +/* + if( xml_str != xmls[index] ) + { + cout << endl << xml_str << endl << "========" + << endl << xmls[index]; + } +//*/ + CPPUNIT_ASSERT( xml_str == xmls[index]); + }; + +private: + + /** + * Allocates a Host. + */ + void init_hp() + { + int oid; + string err; + + // Allocate a host + oid = hpool->allocate(&oid, "Host one","im_mad","vmm_mad", "tm_mad", err); + CPPUNIT_ASSERT(oid == 0); + + hpool->clean(); + }; + +public: + ClusterPoolTest() + { + xmlInitParser(); + }; + + ~ClusterPoolTest() + { + xmlCleanupParser(); + }; + + void setUp() + { + create_db(); + + tester = new NebulaTestCluster(); + + Nebula& neb = Nebula::instance(); + neb.start(); + + hpool = neb.get_hpool(); + cpool = neb.get_cpool(); + + pool = cpool; + }; + + void tearDown() + { + delete_db(); + + delete tester; + }; + + /* ********************************************************************* */ + /* ********************************************************************* */ + + // Test intended to check the PoolSQL name index functionallity + void name_pool() + { + Cluster * cluster; + int oid; + string err; + + + // Allocate some clusters + cpool->allocate(&oid, "name_1", err); + CPPUNIT_ASSERT( oid == 1 ); + + cpool->allocate(&oid, "name_2", err); + CPPUNIT_ASSERT( oid == 2 ); + + cpool->allocate(&oid, "name_3", err); + CPPUNIT_ASSERT( oid == 3 ); + + // Clean the cache + cpool->clean(); + + cpool->allocate(&oid, "name_4", err); + CPPUNIT_ASSERT( oid == 4 ); + + cpool->allocate(&oid, "name_5", err); + CPPUNIT_ASSERT( oid == 5 ); + + // Cluster names 0-3 should be unknown, and 4-5 cached + // Ask for a cached object + cluster = cpool->get("name_5", false); + CPPUNIT_ASSERT( cluster != 0 ); + CPPUNIT_ASSERT( cluster->get_oid() == 5 ); + CPPUNIT_ASSERT( cluster->get_name() == "name_5" ); + + // Ask for non-cached object + cluster = cpool->get("name_2", false); + CPPUNIT_ASSERT( cluster != 0 ); + CPPUNIT_ASSERT( cluster->get_oid() == 2 ); + CPPUNIT_ASSERT( cluster->get_name() == "name_2" ); + + // Ask for non-existing object + cluster = cpool->get("name_X", false); + CPPUNIT_ASSERT( cluster == 0 ); + }; + + /* ********************************************************************* */ + + void duplicates() + { + int rc, oid; + string err; + + // Allocate a cluster. + rc = cpool->allocate(&oid, names[1], err); + CPPUNIT_ASSERT( oid == 1 ); + CPPUNIT_ASSERT( oid == rc ); + + // Try to allocate twice the same cluster, should fail + rc = cpool->allocate(&oid, names[1], err); + CPPUNIT_ASSERT( rc == -1 ); + CPPUNIT_ASSERT( oid == rc ); + } + + /* ********************************************************************* */ + + void set_cluster() + { + Host* host; + int rc; + string xml_str, err; + + init_hp(); + + host = hpool->get(0, false); + CPPUNIT_ASSERT(host != 0); + + rc = host->set_cluster("cluster_a"); + CPPUNIT_ASSERT( rc == 0 ); + + hpool->update(host); + + host->to_xml(xml_str); + CPPUNIT_ASSERT( xml_str == host_0_cluster); + } + + /* ********************************************************************* */ + + void remove_cluster() + { + Host* host; + + int rc; + string xml_str; + + init_hp(); + + host = hpool->get(0, false); + CPPUNIT_ASSERT(host != 0); + + // Set cluster + rc = host->set_cluster("cluster_a"); + CPPUNIT_ASSERT( rc == 0 ); + + hpool->update(host); + + host->to_xml(xml_str); + CPPUNIT_ASSERT( xml_str == host_0_cluster); + + // Remove from the cluster + rc = cpool->set_default_cluster(host); + CPPUNIT_ASSERT( rc == 0 ); + + hpool->update(host); + + // The host should have been moved to the default cluster + + host = hpool->get(0, false); + CPPUNIT_ASSERT(host != 0); + + host->to_xml(xml_str); + CPPUNIT_ASSERT( xml_str == host_0_default); + } + + /* ********************************************************************* */ + + void delete_cluster() + { + Host * host; + Cluster * cluster; + + int rc, oid; + string xml_str; + + init_hp(); + host = hpool->get(0, false); + CPPUNIT_ASSERT(host != 0); + + // Allocate a cluster + oid = allocate(0); + CPPUNIT_ASSERT(oid == 1); + + cluster = cpool->get(1, false); + + // Set cluster + rc = host->set_cluster(cluster->get_name()); + CPPUNIT_ASSERT( rc == 0 ); + + hpool->update(host); + + host->to_xml(xml_str); + CPPUNIT_ASSERT( xml_str == host_0_cluster); + + // Delete the cluster + rc = cpool->drop(cluster); + CPPUNIT_ASSERT( rc == 0 ); + + // The host should have been moved to the default cluster + host = hpool->get(0, false); + host->to_xml(xml_str); +/* + if( xml_str != host_0_default ) + { + cout << endl << xml_str << endl << "========" + << endl << host_0_default; + } +//*/ + CPPUNIT_ASSERT( xml_str == host_0_default); + } + + /* ********************************************************************* */ + + void dump() + { + Cluster * cluster; + int oid, rc; + ostringstream oss; + string err; + + // Allocate some clusters + rc = cpool->allocate(&oid, "cluster_a", err); + CPPUNIT_ASSERT( rc == 1 ); + + rc = cpool->allocate(&oid, "cluster_b", err); + CPPUNIT_ASSERT( rc == 2 ); + + rc = cpool->allocate(&oid, "cluster_c", err); + CPPUNIT_ASSERT( rc == 3 ); + + rc = cpool->allocate(&oid, "cluster_d", err); + CPPUNIT_ASSERT( rc == 4 ); + + // Drop one of them + cluster = cpool->get(2, false); + CPPUNIT_ASSERT( cluster != 0 ); + + rc = cpool->drop(cluster); + CPPUNIT_ASSERT( rc == 0 ); + + // dump the pool + rc = cpool->dump(oss,""); +/* + if( oss.str() != cluster_xml_dump ) + { + cout << endl << oss.str() << endl << "========" + << endl << cluster_xml_dump; + } +//*/ + CPPUNIT_ASSERT( oss.str() == cluster_xml_dump ); + } +}; + +/* ************************************************************************* */ +/* ************************************************************************* */ + +int main(int argc, char ** argv) +{ + return PoolTest::main(argc, argv, ClusterPoolTest::suite()); +} diff --git a/src/cluster/test/SConstruct b/src/cluster/test/SConstruct new file mode 100644 index 0000000000..b55dee66c1 --- /dev/null +++ b/src/cluster/test/SConstruct @@ -0,0 +1,56 @@ +# -------------------------------------------------------------------------- +# Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.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') + +env.Prepend(LIBS=[ + 'nebula_cluster', + 'nebula_host', + 'nebula_pool', + 'nebula_template', + 'nebula_xml', + 'nebula_log', + 'nebula_common', + 'nebula_sql', + + +### TODO: delete not needed + 'nebula_core_test', + 'nebula_host', + 'nebula_cluster', + 'nebula_xml', + 'nebula_vmm', + 'nebula_im', + 'nebula_rm', + 'nebula_tm', + 'nebula_um', + 'nebula_mad', + 'nebula_template', + 'nebula_vm', + 'nebula_vnm', + 'nebula_image', + 'nebula_pool', + 'nebula_hm', + 'nebula_authm', + 'nebula_common', + 'nebula_lcm', + 'nebula_dm', + 'nebula_sql', + 'nebula_log', + 'crypto' +]) + +env.Program('test','ClusterPoolTest.cc') diff --git a/src/host/ClusterPool.cc b/src/host/ClusterPool.cc deleted file mode 100644 index 9376bec747..0000000000 --- a/src/host/ClusterPool.cc +++ /dev/null @@ -1,185 +0,0 @@ -/* -------------------------------------------------------------------------- */ -/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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 "ClusterPool.h" -#include "NebulaLog.h" - -const char * ClusterPool::table = "cluster_pool"; - -const char * ClusterPool::db_names = "oid, cluster_name"; - -const char * ClusterPool::db_bootstrap = - "CREATE TABLE IF NOT EXISTS cluster_pool (" - "oid INTEGER PRIMARY KEY, cluster_name VARCHAR(128), " - "UNIQUE(cluster_name) )"; - -const string ClusterPool::DEFAULT_CLUSTER_NAME = "default"; - -/* -------------------------------------------------------------------------- */ - -int ClusterPool::allocate(int * clid, string name, SqlDB *db, string& error_str) -{ - int rc; - map::iterator it; - - ostringstream oss; - - // Return error if name already exists - for(it=cluster_names.begin();it!=cluster_names.end();it++) - { - if(it->second == name) - { - goto error_existing_name; - } - } - - // Get the highest key, and add 1 - *clid = cluster_names.rbegin()->first + 1; - - rc = insert(*clid, name, db); - - if(rc != 0) - { - goto error_db; - } - - return *clid; - - -error_existing_name: - oss << "Could not allocate new cluster: " - << name << ", already exists."; - - goto error_common; -error_db: - oss << "Could not allocate new cluster " << name << "."; - goto error_common; - -error_common: - error_str = oss.str(); - NebulaLog::log("CLUSTER", Log::ERROR, oss); - - *clid = -1; - return *clid; -} - -/* -------------------------------------------------------------------------- */ - -string ClusterPool::info(int clid) -{ - ostringstream oss; - - map::iterator it; - - it = cluster_names.find(clid); - - if(it != cluster_names.end()) - { - dump_cluster(oss, it->first, it->second); - } - - return oss.str(); -} - -/* -------------------------------------------------------------------------- */ - -int ClusterPool::drop(int clid, SqlDB *db) -{ - int rc; - ostringstream oss; - - // Return error if cluster is 'default' or if it doesn't exist - if( clid == 0 || cluster_names.count(clid) == 0 ) - { - return -1; - } - - oss << "DELETE FROM " << table << " WHERE oid=" << clid; - - rc = db->exec(oss); - - if(rc == 0) - { - cluster_names.erase(clid); - } - - return rc; -} - -/* -------------------------------------------------------------------------- */ - -int ClusterPool::dump(ostringstream& oss) -{ - map::iterator it; - - - oss << ""; - - for(it=cluster_names.begin();it!=cluster_names.end();it++) - { - dump_cluster(oss, it->first, it->second); - } - - oss << ""; - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int ClusterPool::insert(int oid, string name, SqlDB *db) -{ - ostringstream oss; - - int rc; - - char * sql_name; - - sql_name = db->escape_str(name.c_str()); - - if ( sql_name == 0 ) - { - return -1; - } - - oss << "INSERT INTO "<< table <<" ("<< db_names <<") VALUES (" - << oid << "," - << "'" << sql_name << "')"; - - rc = db->exec(oss); - - db->free_str(sql_name); - - if( rc == 0 ) - { - cluster_names.insert( make_pair(oid, name) ); - } - - return rc; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -void ClusterPool::dump_cluster(ostringstream& oss, int id, string name) -{ - oss << - "" << - "" << id << "" << - "" << name << "" << - ""; -} diff --git a/src/host/Host.cc b/src/host/Host.cc index 519b1d76fe..f8095c24c5 100644 --- a/src/host/Host.cc +++ b/src/host/Host.cc @@ -29,18 +29,18 @@ Host::Host( int id, - string _hostname, - string _im_mad_name, - string _vmm_mad_name, - string _tm_mad_name): - PoolObjectSQL(id), - hostname(_hostname), + const string& _hostname, + const string& _im_mad_name, + const string& _vmm_mad_name, + const string& _tm_mad_name, + const string& _cluster): + PoolObjectSQL(id,_hostname,-1,table), state(INIT), im_mad_name(_im_mad_name), vmm_mad_name(_vmm_mad_name), tm_mad_name(_tm_mad_name), last_monitored(0), - cluster(ClusterPool::DEFAULT_CLUSTER_NAME), + cluster(_cluster), host_template() {} @@ -52,92 +52,11 @@ 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, cluster, template"; +const char * Host::db_names = "oid, name, body, state, last_mon_time, cluster"; const char * Host::db_bootstrap = "CREATE TABLE IF NOT EXISTS host_pool (" - "oid INTEGER PRIMARY KEY,host_name VARCHAR(256), state INTEGER," - "im_mad VARCHAR(128),vm_mad VARCHAR(128),tm_mad VARCHAR(128)," - "last_mon_time INTEGER, cluster VARCHAR(128), template TEXT, " - "UNIQUE(host_name))"; - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int Host::select_cb(void * nil, int num, char **values, char ** names) -{ - if ((!values[OID]) || - (!values[HOST_NAME]) || - (!values[STATE]) || - (!values[IM_MAD]) || - (!values[VM_MAD]) || - (!values[TM_MAD]) || - (!values[LAST_MON_TIME]) || - (!values[CLUSTER]) || - (!values[TEMPLATE]) || - (num != LIMIT )) - { - return -1; - } - - 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])); - - cluster = values[CLUSTER]; - - host_template.from_xml(values[TEMPLATE]); - - host_share.hsid = oid; - - return 0; -} - -/* ------------------------------------------------------------------------ */ - -int Host::select(SqlDB *db) -{ - ostringstream oss; - int rc; - int boid; - - set_callback(static_cast(&Host::select_cb)); - - oss << "SELECT " << db_names << " FROM " << table << " WHERE oid = " << oid; - - boid = oid; - oid = -1; - - rc = db->exec(oss, this); - - unset_callback(); - - if ((rc != 0) || (oid != boid )) - { - return -1; - } - - if ( rc != 0 ) - { - return -1; - } - - // Select the host shares from the DB - rc = host_share.select(db); - - if ( rc != 0 ) - { - return rc; - } - - return 0; -} + "oid INTEGER PRIMARY KEY, name VARCHAR(256), body TEXT, state INTEGER, " + "last_mon_time INTEGER, cluster VARCHAR(128), UNIQUE(name))"; /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ @@ -145,34 +64,15 @@ int Host::select(SqlDB *db) int Host::insert(SqlDB *db, string& error_str) { int rc; - map::iterator iter; - // Set up the share ID, to insert it - if ( host_share.hsid == -1 ) - { - host_share.hsid = oid; - } - - // Update the HostShare - rc = host_share.insert(db, error_str); - - if ( rc != 0 ) - { - return rc; - } - - //Insert the Host rc = insert_replace(db, false); if ( rc != 0 ) { error_str = "Error inserting Host in DB."; - host_share.drop(db); - - return rc; } - return 0; + return rc; } /* ------------------------------------------------------------------------ */ @@ -182,24 +82,9 @@ int Host::update(SqlDB *db) { int rc; - // Update the HostShare - rc = host_share.update(db); - - if ( rc != 0 ) - { - return rc; - } - rc = insert_replace(db, true); - if ( rc != 0 ) - { - return rc; - } - - return 0; - - + return rc; } /* ------------------------------------------------------------------------ */ @@ -210,45 +95,21 @@ int Host::insert_replace(SqlDB *db, bool replace) ostringstream oss; int rc; - string xml_template; + string xml_body; char * sql_hostname; - char * sql_im_mad_name; - char * sql_tm_mad_name; - char * sql_vmm_mad_name; char * sql_cluster; - char * sql_template; + char * sql_xml; // Update the Host - sql_hostname = db->escape_str(hostname.c_str()); + sql_hostname = db->escape_str(name.c_str()); if ( sql_hostname == 0 ) { goto error_hostname; } - sql_im_mad_name = db->escape_str(im_mad_name.c_str()); - - if ( sql_im_mad_name == 0 ) - { - goto error_im; - } - - sql_tm_mad_name = db->escape_str(tm_mad_name.c_str()); - - if ( sql_tm_mad_name == 0 ) - { - goto error_tm; - } - - sql_vmm_mad_name = db->escape_str(vmm_mad_name.c_str()); - - if ( sql_vmm_mad_name == 0 ) - { - goto error_vmm; - } - sql_cluster = db->escape_str(cluster.c_str()); if ( sql_cluster == 0 ) @@ -256,12 +117,11 @@ int Host::insert_replace(SqlDB *db, bool replace) goto error_cluster; } - host_template.to_xml(xml_template); - sql_template = db->escape_str(xml_template.c_str()); + sql_xml = db->escape_str(to_xml(xml_body).c_str()); - if ( sql_template == 0 ) + if ( sql_xml == 0 ) { - goto error_template; + goto error_body; } if(replace) @@ -275,37 +135,25 @@ int Host::insert_replace(SqlDB *db, bool replace) // Construct the SQL statement to Insert or Replace - oss <<" INTO "<< table <<" ("<< db_names <<") VALUES (" + oss <<" INTO "<
exec(oss); db->free_str(sql_hostname); - db->free_str(sql_im_mad_name); - db->free_str(sql_tm_mad_name); - db->free_str(sql_vmm_mad_name); db->free_str(sql_cluster); - db->free_str(sql_template); + db->free_str(sql_xml); return rc; -error_template: +error_body: db->free_str(sql_cluster); error_cluster: - db->free_str(sql_vmm_mad_name); -error_vmm: - db->free_str(sql_tm_mad_name); -error_tm: - db->free_str(sql_im_mad_name); -error_im: db->free_str(sql_hostname); error_hostname: return -1; @@ -314,66 +162,6 @@ error_hostname: /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ -int Host::dump(ostringstream& oss, int num, char **values, char **names) -{ - if ((!values[OID]) || - (!values[HOST_NAME]) || - (!values[STATE]) || - (!values[IM_MAD]) || - (!values[VM_MAD]) || - (!values[TM_MAD]) || - (!values[LAST_MON_TIME]) || - (!values[CLUSTER]) || - (!values[TEMPLATE]) || - (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]<<""<< - "" << values[CLUSTER] <<"" << - values[TEMPLATE]; - - HostShare::dump(oss,num - LIMIT, values + LIMIT, names + LIMIT); - - oss << ""; - - return 0; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int Host::drop(SqlDB * db) -{ - ostringstream oss; - int rc; - - host_share.drop(db); - - oss << "DELETE FROM " << table << " WHERE oid=" << oid; - - rc = db->exec(oss); - - if ( rc == 0 ) - { - set_valid(false); - } - - return rc; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - int Host::update_info(string &parse_str) { char * error_msg; @@ -426,7 +214,7 @@ string& Host::to_xml(string& xml) const oss << "" "" << oid << "" << - "" << hostname << "" << + "" << name << "" << "" << state << "" << "" << im_mad_name << "" << "" << vmm_mad_name << "" << @@ -445,26 +233,55 @@ string& Host::to_xml(string& xml) const /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ -string& Host::to_str(string& str) const +int Host::from_xml(const string& xml) { - string template_str; - string share_str; + vector content; + + int int_state; + int rc = 0; - ostringstream os; + // Initialize the internal XML object + update_from_str(xml); - 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 << - "CLUSTER = " << cluster << endl << - "ATTRIBUTES" << endl << host_template.to_str(template_str) << endl << - "HOST SHARES" << endl << host_share.to_str(share_str) <( int_state ); + + // Get associated classes + ObjectXML::get_nodes("/HOST/HOST_SHARE", content); + + if( content.size() < 1 ) + { + return -1; + } + + rc += host_share.from_xml_node( content[0] ); + + content.clear(); + + ObjectXML::get_nodes("/HOST/TEMPLATE", content); + + if( content.size() < 1 ) + { + return -1; + } + + rc += host_template.from_xml_node( content[0] ); + + if (rc != 0) + { + return -1; + } + + return 0; } diff --git a/src/host/HostHook.cc b/src/host/HostHook.cc index 8d72f0ed13..060bc6b56d 100644 --- a/src/host/HostHook.cc +++ b/src/host/HostHook.cc @@ -55,7 +55,7 @@ void HostAllocateHook::do_hook(void *arg) { hmd->execute(host->get_oid(), name, - host->get_hostname(), + host->get_name(), cmd, parsed_args); } @@ -179,7 +179,7 @@ void HostStateHook::do_hook(void *arg) { hmd->execute(host->get_oid(), name, - host->get_hostname(), + host->get_name(), cmd, parsed_args); } diff --git a/src/host/HostPool.cc b/src/host/HostPool.cc index e93275785b..785facd3e3 100644 --- a/src/host/HostPool.cc +++ b/src/host/HostPool.cc @@ -22,54 +22,17 @@ #include "HostPool.h" #include "HostHook.h" -#include "ClusterPool.h" #include "NebulaLog.h" +#include "ClusterPool.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int HostPool::init_cb(void *nil, int num, char **values, char **names) -{ - if ( num != 2 || values == 0 || values[0] == 0 ) - { - return -1; - } - - cluster_pool.cluster_names.insert( make_pair(atoi(values[0]), values[1]) ); - - return 0; -} - -/* -------------------------------------------------------------------------- */ - HostPool::HostPool(SqlDB* db, vector hook_mads, const string& hook_location) : PoolSQL(db,Host::table) { - // ------------------ Initialize Cluster Array ---------------------- - - ostringstream sql; - - set_callback(static_cast(&HostPool::init_cb)); - - sql << "SELECT " << ClusterPool::db_names << " FROM " - << ClusterPool::table; - - db->exec(sql, this); - - unset_callback(); - - if (cluster_pool.cluster_names.empty()) - { - int rc = cluster_pool.insert(0, ClusterPool::DEFAULT_CLUSTER_NAME, db); - - if(rc != 0) - { - throw runtime_error("Could not create default cluster HostPool"); - } - } - // ------------------ Initialize Hooks fot the pool ---------------------- const VectorAttribute * vattr; @@ -180,6 +143,34 @@ int HostPool::allocate ( string& error_str) { Host * host; + ostringstream oss; + + if ( hostname.empty() ) + { + goto error_name; + } + + if ( im_mad_name.empty() ) + { + goto error_im; + } + + if ( vmm_mad_name.empty() ) + { + goto error_vmm; + } + + if ( tm_mad_name.empty() ) + { + goto error_tm; + } + + host = get(hostname,false); + + if ( host !=0) + { + goto error_duplicated; + } // Build a new Host object @@ -187,13 +178,40 @@ int HostPool::allocate ( hostname, im_mad_name, vmm_mad_name, - tm_mad_name); + tm_mad_name, + ClusterPool::DEFAULT_CLUSTER_NAME); // Insert the Object in the pool *oid = PoolSQL::allocate(host, error_str); return *oid; + + +error_name: + oss << "NAME cannot be empty."; + goto error_common; + +error_im: + oss << "IM_MAD_NAME cannot be empty."; + goto error_common; + +error_vmm: + oss << "VMM_MAD_NAME cannot be empty."; + goto error_common; + +error_tm: + oss << "TM_MAD_NAME cannot be empty."; + goto error_common; + +error_duplicated: + oss << "NAME is already taken by HOST " << host->get_oid() << "."; + +error_common: + *oid = -1; + error_str = oss.str(); + + return *oid; } /* -------------------------------------------------------------------------- */ @@ -202,18 +220,24 @@ int HostPool::allocate ( int HostPool::discover_cb(void * _map, int num, char **values, char **names) { map * discovered_hosts; - string im_mad(values[1]); + string im_mad; int hid; + int rc; discovered_hosts = static_cast *>(_map); - if ( (num<=0) || (values[0] == 0) ) + if ( (num<2) || (values[0] == 0) || (values[1] == 0) ) { return -1; } - hid = atoi(values[0]); - im_mad = values[1]; + hid = atoi(values[0]); + rc = ObjectXML::xpath_value(im_mad,values[1],"/HOST/IM_MAD"); + + if( rc != 0) + { + return -1; + } discovered_hosts->insert(make_pair(hid,im_mad)); @@ -230,7 +254,7 @@ int HostPool::discover(map * discovered_hosts, int host_limit) set_callback(static_cast(&HostPool::discover_cb), static_cast(discovered_hosts)); - sql << "SELECT oid, im_mad FROM " + sql << "SELECT oid, body FROM " << Host::table << " WHERE state != " << Host::DISABLED << " ORDER BY last_mon_time ASC LIMIT " << host_limit; @@ -240,97 +264,3 @@ int HostPool::discover(map * discovered_hosts, int host_limit) return rc; } - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int HostPool::dump_cb(void * _oss, int num, char **values, char **names) -{ - ostringstream * oss; - - oss = static_cast(_oss); - - return Host::dump(*oss, num, values, names); -} - -/* -------------------------------------------------------------------------- */ - -int HostPool::dump(ostringstream& oss, const string& where) -{ - int rc; - ostringstream cmd; - - oss << ""; - - set_callback(static_cast(&HostPool::dump_cb), - static_cast(&oss)); - - cmd << "SELECT " << Host::db_names << " , " << HostShare::db_names - << " FROM " << Host::table << " JOIN " << HostShare::table - << " ON " << Host::table << ".oid = " << HostShare::table << ".hid"; - - if ( !where.empty() ) - { - cmd << " WHERE " << where; - } - - rc = db->exec(cmd, this); - - oss << ""; - - unset_callback(); - - return rc; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int HostPool::drop_cluster(int clid) -{ - int rc; - map::iterator it; - string cluster_name; - - it = cluster_pool.cluster_names.find(clid); - - if ( it == cluster_pool.cluster_names.end() ) - { - return -1; - } - - cluster_name = it->second; - - // try to drop the cluster from the pool and DB - rc = cluster_pool.drop(clid, db); - - // Move the hosts assigned to the deleted cluster to the default one - if( rc == 0 ) - { - Host* host; - vector hids; - vector::iterator hid_it; - - string where = "cluster = '" + cluster_name + "'"; - - search(hids, Host::table, where); - - for ( hid_it=hids.begin() ; hid_it < hids.end(); hid_it++ ) - { - host = get(*hid_it, true); - - if ( host == 0 ) - { - continue; - } - - set_default_cluster(host); - - update(host); - - host->unlock(); - } - } - - return rc; -} diff --git a/src/host/HostShare.cc b/src/host/HostShare.cc index 0e3583fb0b..51b324d5a4 100644 --- a/src/host/HostShare.cc +++ b/src/host/HostShare.cc @@ -28,12 +28,10 @@ /* ************************************************************************ */ HostShare::HostShare( - int _hsid, int _max_disk, int _max_mem, int _max_cpu): - ObjectSQL(), - hsid(_hsid), + ObjectXML(), disk_usage(0), mem_usage(0), cpu_usage(0), @@ -46,228 +44,7 @@ HostShare::HostShare( used_disk(0), used_mem(0), used_cpu(0), - running_vms(0) -{ -} - -/* ************************************************************************ */ -/* HostShare :: Database Access Functions */ -/* ************************************************************************ */ - -const char * HostShare::table = "host_shares"; - -const char * HostShare::db_names = "hid," - "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"; - -const char * HostShare::db_bootstrap = "CREATE TABLE IF NOT EXISTS host_shares(" - "hid INTEGER PRIMARY KEY," - "disk_usage INTEGER, mem_usage INTEGER, cpu_usage INTEGER," - "max_disk INTEGER, max_mem INTEGER, max_cpu INTEGER," - "free_disk INTEGER, free_mem INTEGER, free_cpu INTEGER," - "used_disk INTEGER, used_mem INTEGER, used_cpu INTEGER," - "running_vms INTEGER)"; - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int HostShare::select_cb(void * nil, int num, char **values, char **names) -{ - if ((!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]) || - (!values[RUNNING_VMS]) || - (num != LIMIT )) - { - return -1; - } - - hsid = atoi(values[HID]); - - disk_usage = atoi(values[DISK_USAGE]); - mem_usage = atoi(values[MEM_USAGE]); - cpu_usage = atoi(values[CPU_USAGE]); - - max_disk = atoi(values[MAX_DISK]); - max_mem = atoi(values[MAX_MEMORY]); - max_cpu = atoi(values[MAX_CPU]); - - free_disk = atoi(values[FREE_DISK]); - free_mem = atoi(values[FREE_MEMORY]); - free_cpu = atoi(values[FREE_CPU]); - - used_disk = atoi(values[USED_DISK]); - used_mem = atoi(values[USED_MEMORY]); - used_cpu = atoi(values[USED_CPU]); - - running_vms = atoi(values[RUNNING_VMS]); - - return 0; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int HostShare::dump(ostringstream& oss, - int num, - char ** values, - char ** names) -{ - if ((!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]) || - (!values[RUNNING_VMS]) || - (num != LIMIT)) - { - return -1; - } - - oss << - "" << - "" << 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; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int HostShare::select(SqlDB * db) -{ - ostringstream oss; - int rc; - int bhsid; - - set_callback(static_cast(&HostShare::select_cb)); - - oss << "SELECT "<< db_names << " FROM " << table << " WHERE hid = " << hsid; - - bhsid = hsid; - hsid = -1; - - rc = db->exec(oss,this); - - unset_callback(); - - if (hsid != bhsid ) - { - rc = -1; - } - - return rc; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int HostShare::insert(SqlDB * db, string& error_str) -{ - int rc; - - rc = insert_replace(db, false); - - if ( rc == -1 ) - { - error_str = "Error inserting Host Share in DB."; - } - - return rc; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int HostShare::update(SqlDB * db) -{ - int rc; - - rc = insert_replace(db, true); - - return rc; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int HostShare::insert_replace(SqlDB *db, bool replace) -{ - ostringstream oss; - int rc; - - if(replace) - { - oss << "REPLACE"; - } - else - { - oss << "INSERT"; - } - - oss << " 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); - - return rc; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int HostShare::drop(SqlDB * db) -{ - ostringstream oss; - - oss << "DELETE FROM " << table << " WHERE hid=" << hsid; - - return db->exec(oss); -} - -/* ************************************************************************ */ -/* HostShare :: Misc */ -/* ************************************************************************ */ + running_vms(0){}; ostream& operator<<(ostream& os, HostShare& hs) { @@ -287,7 +64,6 @@ string& HostShare::to_xml(string& xml) const ostringstream oss; oss << "" - << "" << hsid << "" << "" << disk_usage << "" << "" << mem_usage << "" << "" << cpu_usage << "" @@ -311,30 +87,35 @@ string& HostShare::to_xml(string& xml) const /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ -string& HostShare::to_str(string& str) const +int HostShare::from_xml_node(const xmlNodePtr node) { - string template_xml; - ostringstream oss; + int rc = 0; - 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; + // Initialize the internal XML object + ObjectXML::update_from_node(node); - str = oss.str(); + rc += xpath(disk_usage, "/HOST_SHARE/DISK_USAGE", -1); + rc += xpath(mem_usage, "/HOST_SHARE/MEM_USAGE", -1); + rc += xpath(cpu_usage, "/HOST_SHARE/CPU_USAGE", -1); - return str; + rc += xpath(max_disk, "/HOST_SHARE/MAX_DISK", -1); + rc += xpath(max_mem , "/HOST_SHARE/MAX_MEM", -1); + rc += xpath(max_cpu , "/HOST_SHARE/MAX_CPU", -1); + + rc += xpath(free_disk, "/HOST_SHARE/FREE_DISK", -1); + rc += xpath(free_mem , "/HOST_SHARE/FREE_MEM", -1); + rc += xpath(free_cpu , "/HOST_SHARE/FREE_CPU", -1); + + rc += xpath(used_disk, "/HOST_SHARE/USED_DISK", -1); + rc += xpath(used_mem , "/HOST_SHARE/USED_MEM", -1); + rc += xpath(used_cpu , "/HOST_SHARE/USED_CPU", -1); + + rc += xpath(running_vms,"/HOST_SHARE/RUNNING_VMS",-1); + + if (rc != 0) + { + return -1; + } + + return 0; } - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ diff --git a/src/host/SConstruct b/src/host/SConstruct index f76294a26b..acba39ff73 100644 --- a/src/host/SConstruct +++ b/src/host/SConstruct @@ -25,7 +25,6 @@ source_files=[ 'Host.cc', 'HostShare.cc', 'HostPool.cc', - 'ClusterPool.cc', 'HostHook.cc' ] diff --git a/src/host/test/HostPoolTest.cc b/src/host/test/HostPoolTest.cc index 32051bb19b..5a658b2307 100644 --- a/src/host/test/HostPoolTest.cc +++ b/src/host/test/HostPoolTest.cc @@ -33,7 +33,7 @@ const string xmls[] = { "0Host one0" "im_madvmm_madtm_mad" - "0default0" + "0default" "000" "000" "000" @@ -42,7 +42,7 @@ const string xmls[] = "1Second host0" "im_madvmm_madtm_mad" - "0default1" + "0default" "000" "000" "000" @@ -54,72 +54,72 @@ const string xmls[] = const string xml_dump = "0a0im_madvmm_madtm_mad0" - "default00default0000000000000" + "SED_CPU>00" "1a name0im_madvmm_madtm_mad0default100default00000" "00000000202a_name0im_madvmm_madtm_mad0default200tm_mad0default00000000000003another " + "NING_VMS>03another " "name0im_madvmm_mad" - "tm_mad0default300tm_mad0default00000000000004host04host0im_madvmm_madtm_mad" - "0default4" + "0default" "000" "0000" "000000"; + "VMS>"; const string xml_dump_like_a = "0a0im_madvmm_madtm_mad0" - "default00default0000000000000" + "SED_CPU>00" "1a name0im_madvmm_madtm_mad0default100default00000" "00000000202a_name0im_madvmm_madtm_mad0default200tm_mad0default00000000000003another " + "NING_VMS>03another " "name0im_madvmm_mad" - "tm_mad0default300tm_mad0default0000000000000"; + "MS>0"; const string host0_updated = - "0Host one0im_madvmm_madtm_mad0default00000000000000"; + "0Host one0im_madvmm_madtm_mad0default0000000000000"; const string cluster_default = "0default"; @@ -128,7 +128,7 @@ const string cluster_xml_dump = "0default1cluster_a3cluster_c4cluster_d"; const string host_0_cluster = - "0Host one0im_madvmm_madtm_mad0cluster_a00000000000000"; + "0Host one0im_madvmm_madtm_mad0cluster_a0000000000000"; /* ************************************************************************* */ /* ************************************************************************* */ @@ -143,16 +143,10 @@ class HostPoolTest : public PoolTest CPPUNIT_TEST (dump_where); CPPUNIT_TEST (discover); CPPUNIT_TEST (duplicates); - - CPPUNIT_TEST (cluster_init); - CPPUNIT_TEST (cluster_allocate); - CPPUNIT_TEST (cluster_drop); - CPPUNIT_TEST (cluster_id); - CPPUNIT_TEST (cluster_dump); - CPPUNIT_TEST (set_cluster); - CPPUNIT_TEST (remove_cluster); CPPUNIT_TEST (update_info); +// CPPUNIT_TEST (scale_test); + CPPUNIT_TEST_SUITE_END (); protected: @@ -184,12 +178,21 @@ protected: CPPUNIT_ASSERT( obj != 0 ); string xml_str = ""; - string name = host->get_hostname(); + string name = host->get_name(); CPPUNIT_ASSERT( name == names[index] ); // Get the xml host->to_xml(xml_str); + +// A little help for debugging +/* + if( xml_str != xmls[index] ) + { + cout << endl << xml_str << endl << "========" + << endl << xmls[index]; + } +//*/ CPPUNIT_ASSERT( xml_str == xmls[index]); }; @@ -285,6 +288,15 @@ public: string result = oss.str(); +// A little help for debugging +/* + if( result != xml_dump ) + { + cout << endl << result << endl << "========" + << endl << xml_dump; + } +//*/ + CPPUNIT_ASSERT( result == xml_dump ); } @@ -304,12 +316,21 @@ public: ostringstream oss; - rc = ((HostPool*)pool)->dump(oss, "host_name LIKE 'a%'"); + rc = ((HostPool*)pool)->dump(oss, "name LIKE 'a%' ORDER BY oid"); CPPUNIT_ASSERT(rc == 0); string result = oss.str(); +// A little help for debugging +/* + if( result != xml_dump_like_a ) + { + cout << endl << result << endl << "========" + << endl << xml_dump_like_a; + } +//*/ + CPPUNIT_ASSERT( result == xml_dump_like_a ); } @@ -360,201 +381,87 @@ public: } } - /* ********************************************************************* */ /* ********************************************************************* */ - void cluster_init() + void scale_test() { + time_t the_time, the_time2; + int oid,i,j,rc; + + ostringstream oss,ossdump; + string err; + Host * host; + + string monitor = "ARCH=x86_64 MODELNAME=\"Intel(R) Core(TM)2 Duo CPU P9300 @ 2.26GHz\" HYPERVISOR=kvm TOTALCPU=200 CPUSPEED=800 TOTALMEMORY=4005416 USEDMEMORY=2351928 FREEMEMORY=2826904 FREECPU=188.4 USEDCPU=11.599999999999994 NETRX=0 NETTX=0 HOSTNAME=pc-ruben"; + + cout << endl << "Allocate Test" << endl; + + tearDown(); + + for (i=1000; i<30000 ; i = i + 5000) + { + setUp(); + + HostPool * hp = static_cast(pool); + + the_time = time(0); + + for (j=0,oss.str(""); jallocate(&oid, oss.str().c_str(),im_mad,vmm_mad,tm_mad,err); + } + + the_time2 = time(0) - the_time; + + hp->clean(); + + the_time = time(0); + + rc = hp->dump(ossdump, ""); + + cout <<"\t"<(pool); - CPPUNIT_ASSERT( hp->info_cluster(0) == cluster_default ); - } + for (i=10000,oss.str(""); i<30000 ; i++,oss.str("")) + { + oss << "host" << i; + hp->allocate(&oid,oss.str().c_str(),im_mad,vmm_mad,tm_mad,err); - /* ********************************************************************* */ + host = hp->get(oid, false); - void cluster_allocate() - { - HostPool * hp = static_cast(pool); - int clid, rc; - string err; + host->update_info(monitor); + hp->update(host); + } + + //Load test + for (i=0; i<25000; i=i+5000) + { + hp->clean(); - rc = hp->allocate_cluster(&clid, "new_cluster", err); - CPPUNIT_ASSERT( rc == clid ); - CPPUNIT_ASSERT( clid == 1 ); + the_time = time(0); - CPPUNIT_ASSERT( hp->info_cluster(clid) == - "1new_cluster"); + for (j=0; jget(j,true); + host->unlock(); + } - // Try to allocate using the same name - rc = hp->allocate_cluster(&clid, "new_cluster", err); - CPPUNIT_ASSERT( rc == clid ); - CPPUNIT_ASSERT( clid == -1 ); - } - - /* ********************************************************************* */ - - void cluster_drop() - { - HostPool * hp = static_cast(pool); - int clid, rc; - string err; - - // Drop a non-existing cluster - rc = hp->drop_cluster(20); - CPPUNIT_ASSERT( rc == -1 ); - - // Allocate a cluster and drop it - rc = hp->allocate_cluster(&clid, "new_cluster", err); - CPPUNIT_ASSERT( clid == 1); - - rc = hp->drop_cluster(clid); - CPPUNIT_ASSERT( rc == 0 ); - - // Try to drop the default cluster, should fail - rc = hp->drop_cluster(0); - CPPUNIT_ASSERT( rc == -1 ); - } - - /* ********************************************************************* */ - - void cluster_id() - { - HostPool * hp = static_cast(pool); - int clid, rc; - ostringstream oss; - string err; - - // Allocate some clusters - rc = hp->allocate_cluster(&clid, "cluster_a", err); - CPPUNIT_ASSERT( rc == 1 ); - - rc = hp->allocate_cluster(&clid, "cluster_b", err); - CPPUNIT_ASSERT( rc == 2 ); - - rc = hp->allocate_cluster(&clid, "cluster_c", err); - CPPUNIT_ASSERT( rc == 3 ); - - rc = hp->allocate_cluster(&clid, "cluster_d", err); - CPPUNIT_ASSERT( rc == 4 ); - - // Drop id 2 - rc = hp->drop_cluster(2); - CPPUNIT_ASSERT( rc == 0 ); - - // Next one should use id 5, because the biggest id is 4 - rc = hp->allocate_cluster(&clid, "cluster_e", err); - CPPUNIT_ASSERT( rc == 5 ); - - // Drop id 5 - rc = hp->drop_cluster(5); - CPPUNIT_ASSERT( rc == 0 ); - - // Next one should use id 5, because the biggest id is 4 again - rc = hp->allocate_cluster(&clid, "cluster_f", err); - CPPUNIT_ASSERT( rc == 5 ); - - } - - /* ********************************************************************* */ - - void cluster_dump() - { - HostPool * hp = static_cast(pool); - int clid, rc; - ostringstream oss; - string err; - - // Allocate some clusters - rc = hp->allocate_cluster(&clid, "cluster_a", err); - CPPUNIT_ASSERT( rc == 1 ); - - rc = hp->allocate_cluster(&clid, "cluster_b", err); - CPPUNIT_ASSERT( rc == 2 ); - - rc = hp->allocate_cluster(&clid, "cluster_c", err); - CPPUNIT_ASSERT( rc == 3 ); - - rc = hp->allocate_cluster(&clid, "cluster_d", err); - CPPUNIT_ASSERT( rc == 4 ); - - - // Drop one of them - rc = hp->drop_cluster(2); - CPPUNIT_ASSERT( rc == 0 ); - - // dump the pool - rc = hp->dump_cluster(oss); - CPPUNIT_ASSERT( oss.str() == cluster_xml_dump ); - } - - /* ********************************************************************* */ - - void set_cluster() - { - HostPool * hp = static_cast(pool); - Host* host; - int clid, rc, oid; - string xml_str, err; - - // Allocate a host - oid = allocate(0); - CPPUNIT_ASSERT(oid >= 0); - - host = hp->get(0, false); - CPPUNIT_ASSERT(host != 0); - - rc = hp->allocate_cluster(&clid, "cluster_a", err); - CPPUNIT_ASSERT( rc == 1 ); - - rc = hp->set_cluster(host, clid); - CPPUNIT_ASSERT( rc == 0 ); - - host->to_xml(xml_str); - CPPUNIT_ASSERT( xml_str == host_0_cluster); - - - // Try to set a non-existing cluster - rc = hp->set_cluster(host, 20); - CPPUNIT_ASSERT( rc == -1 ); - - CPPUNIT_ASSERT( xml_str == host_0_cluster); - - } - - /* ********************************************************************* */ - - void remove_cluster() - { - HostPool * hp = static_cast(pool); - Host* host; - int clid, rc, oid; - string xml_str, err; - - // Allocate a host - oid = allocate(0); - CPPUNIT_ASSERT(oid >= 0); - - host = hp->get(0, false); - CPPUNIT_ASSERT(host != 0); - - rc = hp->allocate_cluster(&clid, "cluster_a", err); - CPPUNIT_ASSERT( rc == 1 ); - - // Set host 0 to cluster 1 - rc = hp->set_cluster(host, clid); - CPPUNIT_ASSERT( rc == 0 ); - - // Check - host->to_xml(xml_str); - CPPUNIT_ASSERT( xml_str == host_0_cluster); - - // Remove the cluster - rc = hp->set_default_cluster(host); - CPPUNIT_ASSERT( rc == 0 ); - - // The host should have been moved to the default cluster - host->to_xml(xml_str); - check(0, host); + cout << "\t" << i << "\t" << time(0) - the_time << endl; + } } /* ********************************************************************* */ diff --git a/src/host/test/SConstruct b/src/host/test/SConstruct index 5b660b8371..1c44bf24bb 100644 --- a/src/host/test/SConstruct +++ b/src/host/test/SConstruct @@ -21,6 +21,8 @@ Import('env') env.Prepend(LIBS=[ 'nebula_core_test', 'nebula_host', + 'nebula_cluster', + 'nebula_xml', 'nebula_vmm', 'nebula_im', 'nebula_rm', diff --git a/src/im/InformationManager.cc b/src/im/InformationManager.cc index 235142d06f..fc662ed910 100644 --- a/src/im/InformationManager.cc +++ b/src/im/InformationManager.cc @@ -201,7 +201,7 @@ void InformationManager::timer_action() (thetime - host->get_last_monitored() >= monitor_period)) { oss.str(""); - oss << "Monitoring host " << host->get_hostname() + oss << "Monitoring host " << host->get_name() << " (" << it->first << ")"; NebulaLog::log("InM",Log::INFO,oss); @@ -225,7 +225,7 @@ void InformationManager::timer_action() update_remotes = true; } - imd->monitor(it->first,host->get_hostname(),update_remotes); + imd->monitor(it->first,host->get_name(),update_remotes); host->set_state(Host::MONITORING); } diff --git a/src/image/Image.cc b/src/image/Image.cc index c333c56df4..a261558507 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -28,14 +28,17 @@ #include "AuthManager.h" #include "UserPool.h" +#define TO_UPPER(S) transform(S.begin(),S.end(),S.begin(),(int(*)(int))toupper) + /* ************************************************************************ */ -/* Image :: Constructor/Destructor */ +/* Image :: Constructor/Destructor */ /* ************************************************************************ */ -Image::Image(int _uid, ImageTemplate * _image_template): - PoolObjectSQL(-1), - uid(_uid), - name(""), +Image::Image(int _uid, + const string& _user_name, + ImageTemplate * _image_template): + PoolObjectSQL(-1,"",_uid,table), + user_name(_user_name), type(OS), regtime(time(0)), source(""), @@ -61,92 +64,16 @@ Image::~Image() } /* ************************************************************************ */ -/* Image :: Database Access Functions */ +/* Image :: Database Access Functions */ /* ************************************************************************ */ const char * Image::table = "image_pool"; -const char * Image::db_names = "oid, uid, name, type, public, persistent, regtime, " - "source, state, running_vms, template"; - -const char * Image::extended_db_names = "image_pool.oid, image_pool.uid, " - "image_pool.name, image_pool.type, image_pool.public, " - "image_pool.persistent, image_pool.regtime, image_pool.source, " - "image_pool.state, image_pool.running_vms, image_pool.template"; +const char * Image::db_names = "oid, name, body, uid, public"; const char * Image::db_bootstrap = "CREATE TABLE IF NOT EXISTS image_pool (" - "oid INTEGER PRIMARY KEY, uid INTEGER, name VARCHAR(128), " - "type INTEGER, public INTEGER, persistent INTEGER, regtime INTEGER, source TEXT, state INTEGER, " - "running_vms INTEGER, template TEXT, UNIQUE(name) )"; - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int Image::select_cb(void * nil, int num, char **values, char ** names) -{ - if ((!values[OID]) || - (!values[UID]) || - (!values[NAME]) || - (!values[TYPE]) || - (!values[PUBLIC]) || - (!values[PERSISTENT]) || - (!values[REGTIME]) || - (!values[SOURCE]) || - (!values[STATE]) || - (!values[RUNNING_VMS]) || - (!values[TEMPLATE]) || - (num != LIMIT )) - { - return -1; - } - - oid = atoi(values[OID]); - uid = atoi(values[UID]); - - name = values[NAME]; - - type = static_cast(atoi(values[TYPE])); - public_img = atoi(values[PUBLIC]); - persistent_img = atoi(values[PERSISTENT]); - regtime = static_cast(atoi(values[REGTIME])); - - source = values[SOURCE]; - - state = static_cast(atoi(values[STATE])); - - running_vms = atoi(values[RUNNING_VMS]); - - image_template->from_xml(values[TEMPLATE]); - - return 0; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int Image::select(SqlDB *db) -{ - ostringstream oss; - int rc; - int boid; - - set_callback(static_cast(&Image::select_cb)); - - oss << "SELECT " << db_names << " FROM " << table << " WHERE oid = " << oid; - - boid = oid; - oid = -1; - - rc = db->exec(oss, this); - - if ((rc != 0) || (oid != boid )) - { - return -1; - } - - return 0; -} - + "oid INTEGER PRIMARY KEY, name VARCHAR(256), body TEXT, uid INTEGER, " + "public INTEGER, UNIQUE(name,uid) )"; /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ @@ -155,11 +82,11 @@ int Image::insert(SqlDB *db, string& error_str) { int rc; - string source_att; - string type_att; - string public_attr; - string persistent_attr; - string dev_prefix; + string path_attr; + string type_att; + string public_attr; + string persistent_attr; + string dev_prefix; // --------------------------------------------------------------------- // Check default image attributes @@ -169,17 +96,11 @@ int Image::insert(SqlDB *db, string& error_str) get_template_attribute("NAME", name); - if ( name.empty() == true ) - { - goto error_name; - } - // ------------ TYPE -------------------- get_template_attribute("TYPE", type_att); - transform (type_att.begin(), type_att.end(), type_att.begin(), - (int(*)(int))toupper); + TO_UPPER(type_att); if ( type_att.empty() == true ) { @@ -194,20 +115,20 @@ int Image::insert(SqlDB *db, string& error_str) // ------------ PUBLIC -------------------- get_template_attribute("PUBLIC", public_attr); + image_template->erase("PUBLIC"); - transform (public_attr.begin(), public_attr.end(), public_attr.begin(), - (int(*)(int))toupper); + TO_UPPER(public_attr); public_img = (public_attr == "YES"); // ------------ PERSISTENT -------------------- get_template_attribute("PERSISTENT", persistent_attr); + image_template->erase("PERSISTENT"); - transform (persistent_attr.begin(), persistent_attr.end(), persistent_attr.begin(), - (int(*)(int))toupper); + TO_UPPER(persistent_attr); persistent_img = (persistent_attr == "YES"); @@ -230,10 +151,32 @@ int Image::insert(SqlDB *db, string& error_str) image_template->set(dev_att); } - // ------------ SOURCE (path to store the image)-------------------- + // ------------ PATH -------------------- + get_template_attribute("PATH", path_attr); + // ------------ SOURCE (path to store the image) -------------------- get_template_attribute("SOURCE", source); + // The template should contain PATH or SOURCE + if ( source.empty() && path_attr.empty() ) + { + string size_attr; + string fstype_attr; + + get_template_attribute("SIZE", size_attr); + get_template_attribute("FSTYPE", fstype_attr); + + // It could be an empty DATABLOCK image, if it declares SIZE and FSTYPE + if ( type_att != "DATABLOCK" || size_attr.empty() || fstype_attr.empty() ) + { + goto error_no_path; + } + } + else if ( !source.empty() && !path_attr.empty() ) + { + goto error_path_and_source; + } + if (source.empty()) { ostringstream tmp_hashstream; @@ -262,18 +205,30 @@ int Image::insert(SqlDB *db, string& error_str) return rc; -error_name: - error_str = "NAME not present in image template."; - goto error_common; - error_type: - error_str = "Incorrect TYPE in image template."; + error_str = "Incorrect TYPE in template."; goto error_common; error_public_and_persistent: error_str = "Image cannot be public and persistent."; goto error_common; +error_no_path: + if ( type_att == "DATABLOCK" ) + { + error_str = "A DATABLOCK type IMAGE has to declare a PATH, or both " + "SIZE and FSTYPE."; + } + else + { + error_str = "No PATH in template."; + } + goto error_common; + +error_path_and_source: + error_str = "Template malformed, PATH and SOURCE are mutuallly exclusive."; + goto error_common; + error_common: NebulaLog::log("IMG", Log::ERROR, error_str); return -1; @@ -296,11 +251,10 @@ int Image::insert_replace(SqlDB *db, bool replace) int rc; - string xml_template; + string xml_body; char * sql_name; - char * sql_source; - char * sql_template; + char * sql_xml; // Update the Image @@ -311,19 +265,11 @@ int Image::insert_replace(SqlDB *db, bool replace) goto error_name; } - sql_source = db->escape_str(source.c_str()); + sql_xml = db->escape_str(to_xml(xml_body).c_str()); - if ( sql_source == 0 ) + if ( sql_xml == 0 ) { - goto error_source; - } - - image_template->to_xml(xml_template); - sql_template = db->escape_str(xml_template.c_str()); - - if ( sql_template == 0 ) - { - goto error_template; + goto error_body; } if(replace) @@ -339,100 +285,24 @@ int Image::insert_replace(SqlDB *db, bool replace) oss <<" INTO "<< table <<" ("<< db_names <<") VALUES (" << oid << "," - << uid << "," << "'" << sql_name << "'," - << type << "," - << public_img << "," - << persistent_img << "," - << regtime << "," - << "'" << sql_source << "'," - << state << "," - << running_vms << "," - << "'" << sql_template << "')"; + << "'" << sql_xml << "'," + << uid << "," + << public_img << ")"; rc = db->exec(oss); db->free_str(sql_name); - db->free_str(sql_source); - db->free_str(sql_template); + db->free_str(sql_xml); return rc; -error_template: - db->free_str(sql_source); -error_source: +error_body: db->free_str(sql_name); error_name: return -1; } -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int Image::dump(ostringstream& oss, int num, char **values, char **names) -{ - if ((!values[OID]) || - (!values[UID]) || - (!values[NAME]) || - (!values[TYPE]) || - (!values[PUBLIC]) || - (!values[PERSISTENT]) || - (!values[REGTIME]) || - (!values[SOURCE]) || - (!values[STATE]) || - (!values[RUNNING_VMS]) || - (!values[TEMPLATE]) || - (num != LIMIT + 1)) - { - return -1; - } - - oss << - "" << - "" << values[OID] << "" << - "" << values[UID] << "" << - "" << values[LIMIT] << "" << - "" << values[NAME] << "" << - "" << values[TYPE] << "" << - "" << values[PUBLIC] << "" << - "" << values[PERSISTENT] << "" << - "" << values[REGTIME] << "" << - "" << values[SOURCE] << "" << - "" << values[STATE] << "" << - "" << values[RUNNING_VMS] << "" << - values[TEMPLATE] << - ""; - - return 0; -} - -/* ------------------------------------------------------------------------ */ -/* ------------------------------------------------------------------------ */ - -int Image::drop(SqlDB * db) -{ - ostringstream oss; - int rc; - - // Only delete the VM - if (running_vms != 0) - { - return -1; - } - - oss << "DELETE FROM " << table << " WHERE oid=" << oid; - - rc = db->exec(oss); - - if ( rc == 0 ) - { - set_valid(false); - } - - return rc; -} - - /* ************************************************************************ */ /* Image :: Misc */ /* ************************************************************************ */ @@ -458,6 +328,7 @@ string& Image::to_xml(string& xml) const "" << "" << oid << "" << "" << uid << "" << + "" << user_name << "" << "" << name << "" << "" << type << "" << "" << public_img << "" << @@ -477,30 +348,50 @@ string& Image::to_xml(string& xml) const /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ -string& Image::to_str(string& str) const +int Image::from_xml(const string& xml) { - string template_str; + vector content; + int int_state; + int int_type; - ostringstream os; + int rc = 0; - os << - "ID = " << oid << endl << - "UID = " << uid << endl << - "NAME = " << name << endl << - "TYPE = " << type << endl << - "PUBLIC = " << public_img << endl << - "PERSISTENT = " << persistent_img << endl << - "REGTIME = " << regtime << endl << - "SOURCE = " << source << endl << - "STATE = " << state << endl << - "RUNNING_VMS = " << running_vms << endl << - "TEMPLATE" << endl - << image_template->to_str(template_str) - << endl; + // Initialize the internal XML object + update_from_str(xml); - str = os.str(); + // Get class base attributes + rc += xpath(oid, "/IMAGE/ID", -1); + rc += xpath(uid, "/IMAGE/UID", -1); + rc += xpath(user_name, "/IMAGE/USERNAME", "not_found"); + rc += xpath(name, "/IMAGE/NAME", "not_found"); - return str; + rc += xpath(int_type, "/IMAGE/TYPE", 0); + rc += xpath(public_img, "/IMAGE/PUBLIC", 0); + rc += xpath(persistent_img, "/IMAGE/PERSISTENT", 0); + rc += xpath(regtime, "/IMAGE/REGTIME", 0); + + rc += xpath(source, "/IMAGE/SOURCE", "not_found"); + rc += xpath(int_state, "/IMAGE/STATE", 0); + rc += xpath(running_vms, "/IMAGE/RUNNING_VMS", -1); + + type = static_cast(int_type); + state = static_cast(int_state); + + // Get associated classes + ObjectXML::get_nodes("/IMAGE/TEMPLATE", content); + if( content.size() < 1 ) + { + return -1; + } + + rc += image_template->from_xml_node(content[0]); + + if (rc != 0) + { + return -1; + } + + return 0; } /* ------------------------------------------------------------------------ */ diff --git a/src/image/ImagePool.cc b/src/image/ImagePool.cc index fc43d6f043..45e200915e 100644 --- a/src/image/ImagePool.cc +++ b/src/image/ImagePool.cc @@ -27,61 +27,30 @@ string ImagePool::_source_prefix; string ImagePool::_default_type; string ImagePool::_default_dev_prefix; -int ImagePool::init_cb(void *nil, int num, char **values, char **names) -{ - if ( num == 0 || values == 0 || values[0] == 0 ) - { - return -1; - } - - image_names.insert(make_pair(values[1],atoi(values[0]))); - - return 0; -} - /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ - -ImagePool::ImagePool( SqlDB * db, - const string& __source_prefix, - const string& __default_type, - const string& __default_dev_prefix): - +ImagePool::ImagePool(SqlDB * db, + const string& __source_prefix, + const string& __default_type, + const string& __default_dev_prefix): PoolSQL(db,Image::table) { - ostringstream sql; - int rc; + ostringstream sql; // Init static defaults - _source_prefix = __source_prefix; - _default_type = __default_type; - _default_dev_prefix = __default_dev_prefix; + _source_prefix = __source_prefix; + _default_type = __default_type; + _default_dev_prefix = __default_dev_prefix; // Set default type if (_default_type != "OS" && _default_type != "CDROM" && _default_type != "DATABLOCK" ) { - NebulaLog::log("IMG", Log::ERROR, - "Bad default for image type, setting OS"); + NebulaLog::log("IMG", Log::ERROR, "Bad default for type, setting OS"); _default_type = "OS"; } - - // Read from the DB the existing images, and build the ID:Name map - set_callback(static_cast(&ImagePool::init_cb)); - - sql << "SELECT oid, name FROM " << Image::table; - - rc = db->exec(sql, this); - - unset_callback(); - - if ( rc != 0 ) - { - NebulaLog::log("IMG", Log::ERROR, - "Could not load the existing images from the DB."); - } } /* -------------------------------------------------------------------------- */ @@ -89,32 +58,57 @@ ImagePool::ImagePool( SqlDB * db, int ImagePool::allocate ( int uid, + string user_name, ImageTemplate* img_template, int * oid, string& error_str) { - Image * img; - string name; + Image * img; + Image * img_aux; + string name; + ostringstream oss; // --------------------------------------------------------------------- // Build a new Image object // --------------------------------------------------------------------- - img = new Image(uid,img_template); + img = new Image(uid, user_name, img_template); + // Check name img->get_template_attribute("NAME", name); + if ( name.empty() ) + { + goto error_name; + } + + // Check for duplicates + img_aux = get(name,uid,false); + + if( img_aux != 0 ) + { + goto error_duplicated; + } + // --------------------------------------------------------------------- // Insert the Object in the pool // --------------------------------------------------------------------- *oid = PoolSQL::allocate(img, error_str); - // --------------------------------------------------------------------- - // Add the image name to the map of image_names - // --------------------------------------------------------------------- - if ( *oid != -1 ) - { - image_names.insert(make_pair(name, *oid)); - } + return *oid; + + +error_name: + oss << "NAME cannot be empty."; + goto error_common; + +error_duplicated: + oss << "NAME is already taken by IMAGE " << img_aux->get_oid() << "."; + +error_common: + delete img; + + *oid = -1; + error_str = oss.str(); return *oid; } @@ -122,54 +116,11 @@ int ImagePool::allocate ( /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int ImagePool::dump_cb(void * _oss, int num, char **values, char **names) -{ - ostringstream * oss; - - oss = static_cast(_oss); - - return Image::dump(*oss, num, values, names); -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int ImagePool::dump(ostringstream& oss, const string& where) -{ - int rc; - ostringstream cmd; - - oss << ""; - - set_callback(static_cast(&ImagePool::dump_cb), - static_cast(&oss)); - - cmd << "SELECT "<< Image::extended_db_names << ", user_pool.user_name FROM " - << Image::table - << " LEFT OUTER JOIN (SELECT oid, user_name FROM user_pool) " - << "AS user_pool ON " << Image::table << ".uid = user_pool.oid"; - - if ( !where.empty() ) - { - cmd << " WHERE " << where; - } - - rc = db->exec(cmd, this); - - oss << ""; - - unset_callback(); - - return rc; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - int ImagePool::disk_attribute(VectorAttribute * disk, int disk_id, int * index, - Image::ImageType * img_type) + Image::ImageType * img_type, + int uid) { string source; Image * img = 0; @@ -204,7 +155,7 @@ int ImagePool::disk_attribute(VectorAttribute * disk, } else { - img = get(source,true); + img = get(source,uid,true); if (img == 0) { @@ -255,7 +206,7 @@ int ImagePool::disk_attribute(VectorAttribute * disk, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void ImagePool::authorize_disk(VectorAttribute * disk, AuthRequest * ar) +void ImagePool::authorize_disk(VectorAttribute * disk,int uid, AuthRequest * ar) { string source; Image * img = 0; @@ -284,7 +235,7 @@ void ImagePool::authorize_disk(VectorAttribute * disk, AuthRequest * ar) } else { - img = get(source,true); + img = get(source,uid,true); } if (img == 0) @@ -293,7 +244,7 @@ void ImagePool::authorize_disk(VectorAttribute * disk, AuthRequest * ar) } ar->add_auth(AuthRequest::IMAGE, - img->get_iid(), + img->get_oid(), AuthRequest::USE, img->get_uid(), img->isPublic()); diff --git a/src/image/test/ImagePoolTest.cc b/src/image/test/ImagePoolTest.cc index ed0efdb4e5..041076cbba 100644 --- a/src/image/test/ImagePoolTest.cc +++ b/src/image/test/ImagePoolTest.cc @@ -24,6 +24,7 @@ using namespace std; const int uids[] = {0,1,2}; +const string user_names[] = {"A user","B user","C user"}; const string names[] = {"Image one", "Second Image", "The third image"}; @@ -49,19 +50,19 @@ const string templates[] = const string xmls[] = { - "00Image one0010000000000source_prefix/9ab4a4e021ee2883f57e3aeecc9e2aed7c3fa19830", + "00A userImage one0010000000000source_prefix/9ab4a4e021ee2883f57e3aeecc9e2aed7c3fa19830", - "11Second Image0100000000000source_prefix/c9d51800847467911c755e5e4c13dfe28c3a79f330", + "11B userSecond Image0100000000000source_prefix/c9d51800847467911c755e5e4c13dfe28c3a79f330", - "02The third image0000000000000source_prefix/e50b0c738be9d431475bf5859629e5580301a7d630" + "02C userThe third image0000000000000source_prefix/e50b0c738be9d431475bf5859629e5580301a7d630" }; // This xml dump result has the STIMEs modified to 0000000000 const string xml_dump = -"00one_user_testImage one0010000000000source_prefix/9ab4a4e021ee2883f57e3aeecc9e2aed7c3fa1983011A userSecond Image0100000000000source_prefix/c9d51800847467911c755e5e4c13dfe28c3a79f33022B userThe third image0000000000000source_prefix/e50b0c738be9d431475bf5859629e5580301a7d630"; +"00A userImage one0010000000000source_prefix/9ab4a4e021ee2883f57e3aeecc9e2aed7c3fa1983011B userSecond Image0100000000000source_prefix/c9d51800847467911c755e5e4c13dfe28c3a79f33022C userThe third image0000000000000source_prefix/e50b0c738be9d431475bf5859629e5580301a7d630"; const string xml_dump_where = -"00one_user_testImage one0010000000000source_prefix/9ab4a4e021ee2883f57e3aeecc9e2aed7c3fa1983011A userSecond Image0100000000000source_prefix/c9d51800847467911c755e5e4c13dfe28c3a79f330"; +"00A userImage one0010000000000source_prefix/9ab4a4e021ee2883f57e3aeecc9e2aed7c3fa1983011B userSecond Image0100000000000source_prefix/c9d51800847467911c755e5e4c13dfe28c3a79f330"; const string replacement = "0000000000"; @@ -91,7 +92,7 @@ public: if( rc == 0 ) { - return ImagePool::allocate(uid, img_template, oid, err); + return ImagePool::allocate(uid, user_names[uid], img_template, oid, err); } else { @@ -167,33 +168,17 @@ protected: ((Image*)obj)->to_xml(xml_str); xml_str.replace( xml_str.find("")+9, 10, replacement); - //cout << endl << xml_str << endl << xmls[index] << endl; +/* + if( xml_str != xmls[index] ) + { + cout << endl << xml_str << endl << xmls[index] << endl; + } +//*/ CPPUNIT_ASSERT( ((Image*)obj)->get_name() == names[index] ); CPPUNIT_ASSERT( xml_str == xmls[index]); }; - void set_up_user_pool() - { - string err; - - UserPool::bootstrap(db); - UserPool * user_pool = new UserPool(db); - int uid_1, uid_2; - - string username_1 = "A user"; - string username_2 = "B user"; - - string pass_1 = "A pass"; - string pass_2 = "B pass"; - - user_pool->allocate(&uid_1, username_1, pass_1, true, err); - user_pool->allocate(&uid_2, username_2, pass_2, true, err); - - delete user_pool; - }; - - public: ImagePoolTest(){xmlInitParser();}; @@ -207,7 +192,7 @@ public: ImagePool * imp; Image * img; - // Allocate 2 users, so they are written to the DB. + // Allocate 2 images, so they are written to the DB. allocate(0); allocate(2); @@ -215,13 +200,13 @@ public: // allocated images. imp = new ImagePool(db, "source_prefix", "OS", "hd"); - img = imp->get(names[0], false); + img = imp->get(names[0], uids[0], false); CPPUNIT_ASSERT( img != 0 ); - img = imp->get(names[1], false); + img = imp->get(names[1], uids[1], false); CPPUNIT_ASSERT( img == 0 ); - img = imp->get(names[2], false); + img = imp->get(names[2], uids[2], false); CPPUNIT_ASSERT( img != 0 ); @@ -312,7 +297,7 @@ public: check(0, obj); // Get using its name - obj = imp->get(names[1], true); + obj = imp->get(names[1], uids[1], true); CPPUNIT_ASSERT( obj != 0 ); obj->unlock(); @@ -324,7 +309,7 @@ public: pool->clean(); // Get first object and check its integrity - obj = imp->get(names[0], false); + obj = imp->get(names[0], uids[0], false); check(0, obj); // Get using its name @@ -341,14 +326,14 @@ public: // The pool is empty // Non existing name - obj = imp->get("Wrong name", true); + obj = imp->get("Wrong name", 0, true); CPPUNIT_ASSERT( obj == 0 ); // Allocate an object allocate(0); // Ask again for a non-existing name - obj = imp->get("Non existing name", true); + obj = imp->get("Non existing name",uids[0], true); CPPUNIT_ASSERT( obj == 0 ); } @@ -370,9 +355,9 @@ public: CPPUNIT_ASSERT( rc == -1 ); CPPUNIT_ASSERT( oid == rc ); - // Try again, with different uid + // Try again, this time with different uid. Should be allowed rc = imp->allocate(uids[1], templates[0], &oid); - CPPUNIT_ASSERT( rc == -1 ); + CPPUNIT_ASSERT( rc >= 0 ); CPPUNIT_ASSERT( oid == rc ); } @@ -487,6 +472,7 @@ public: CPPUNIT_ASSERT(oid >= 0); img = imp->get(oid, false); + CPPUNIT_ASSERT( img != 0 ); img->enable(true); img->disk_attribute(disk, &index, &img_type); @@ -508,6 +494,7 @@ public: CPPUNIT_ASSERT(oid >= 0); img = imp->get(oid, false); + CPPUNIT_ASSERT( img != 0 ); img->enable(true); img->disk_attribute(disk, &index, &img_type); @@ -529,6 +516,7 @@ public: CPPUNIT_ASSERT(oid >= 0); img = imp->get(oid, false); + CPPUNIT_ASSERT( img != 0 ); img->enable(true); img->disk_attribute(disk, &index, &img_type); @@ -557,6 +545,7 @@ public: // Allocate an OS type image oid = allocate(0); img = imp->get(oid, false); + CPPUNIT_ASSERT( img != 0 ); // --------------------------------------------------------------------- // A disk without a BUS attribute should not have it added. @@ -643,7 +632,7 @@ public: disk = new VectorAttribute("DISK"); disk->replace("IMAGE", "Image 0"); - ((ImagePool*)imp)->disk_attribute(disk, 0, &index, &img_type); + ((ImagePool*)imp)->disk_attribute(disk, 0, &index, &img_type,0); value = ""; value = disk->vector_value("TARGET"); @@ -660,7 +649,7 @@ public: disk = new VectorAttribute("DISK"); disk->replace("IMAGE_ID", "1"); - ((ImagePool*)imp)->disk_attribute(disk, 0, &index, &img_type); + ((ImagePool*)imp)->disk_attribute(disk, 0, &index, &img_type,0); value = ""; value = disk->vector_value("TARGET"); @@ -865,8 +854,6 @@ public: int rc; string nan; - set_up_user_pool(); - allocate(0); allocate(1); allocate(2); @@ -876,9 +863,16 @@ public: string result = oss.str(); - result.replace(164, 10, replacement); - result.replace(1154, 10, replacement); - result.replace(1684, 10, replacement); + result.replace(157, 10, replacement); + result.replace(1147, 10, replacement); + result.replace(1677, 10, replacement); + +/* + if( result != xml_dump ) + { + cout << endl << result << endl << xml_dump << endl; + } +//*/ CPPUNIT_ASSERT( result == xml_dump ); } @@ -894,8 +888,6 @@ public: ostringstream oss; ostringstream where; - set_up_user_pool(); - allocate(0); allocate(1); allocate(2); @@ -906,8 +898,15 @@ public: CPPUNIT_ASSERT(rc == 0); string result = oss.str(); - result.replace(164, 10, replacement); - result.replace(1154, 10, replacement); + result.replace(157, 10, replacement); + result.replace(1147, 10, replacement); + +/* + if( result != xml_dump_where ) + { + cout << endl << result << endl << xml_dump_where << endl; + } +//*/ CPPUNIT_ASSERT( result == xml_dump_where ); } @@ -921,7 +920,5 @@ public: int main(int argc, char ** argv) { - OneUnitTest::set_one_auth(); - return PoolTest::main(argc, argv, ImagePoolTest::suite()); } diff --git a/src/image/test/SConstruct b/src/image/test/SConstruct index 958db2137b..4d5bc99d00 100644 --- a/src/image/test/SConstruct +++ b/src/image/test/SConstruct @@ -30,6 +30,7 @@ env.Prepend(LIBS=[ 'nebula_core', 'nebula_sql', 'nebula_log', + 'nebula_xml', 'crypto' ]) diff --git a/src/lcm/test/LifeCycleManagerTest.cc b/src/lcm/test/LifeCycleManagerTest.cc index 70d0adbc42..23672f7c21 100644 --- a/src/lcm/test/LifeCycleManagerTest.cc +++ b/src/lcm/test/LifeCycleManagerTest.cc @@ -185,7 +185,7 @@ private: if( rc == 0 ) { - return vmpool->allocate(uids[index], vm_template, &oid, + return vmpool->allocate(uids[index], "username", vm_template, &oid, err, false); } else diff --git a/src/lcm/test/SConstruct b/src/lcm/test/SConstruct index 7e3b2867f2..21f5bea0c7 100644 --- a/src/lcm/test/SConstruct +++ b/src/lcm/test/SConstruct @@ -21,6 +21,7 @@ Import('env') env.Prepend(LIBS=[ 'nebula_core_test', 'nebula_host', + 'nebula_cluster', 'nebula_vmm', 'nebula_im', 'nebula_rm', @@ -32,6 +33,7 @@ env.Prepend(LIBS=[ 'nebula_vnm', 'nebula_image', 'nebula_pool', + 'nebula_xml', 'nebula_hm', 'nebula_authm', 'nebula_common', diff --git a/src/nebula/Nebula.cc b/src/nebula/Nebula.cc index 69f350d37c..d05290d690 100644 --- a/src/nebula/Nebula.cc +++ b/src/nebula/Nebula.cc @@ -234,6 +234,7 @@ void Nebula::start() VirtualNetworkPool::bootstrap(db); UserPool::bootstrap(db); ImagePool::bootstrap(db); + ClusterPool::bootstrap(db); } catch (exception&) { @@ -273,6 +274,8 @@ void Nebula::start() repository_path, default_image_type, default_device_prefix); + + cpool = new ClusterPool(db); } catch (exception&) { @@ -438,6 +441,7 @@ void Nebula::start() vnpool, upool, ipool, + cpool, rm_port, log_location + "one_xmlrpc.log"); } diff --git a/src/nebula/SConstruct b/src/nebula/SConstruct index 9879736c12..90c3d33dfd 100644 --- a/src/nebula/SConstruct +++ b/src/nebula/SConstruct @@ -46,12 +46,14 @@ env.Prepend(LIBS=[ 'nebula_template', 'nebula_image', 'nebula_pool', + 'nebula_cluster', 'nebula_host', 'nebula_vnm', 'nebula_vm', 'nebula_common', 'nebula_sql', 'nebula_log', + 'nebula_xml', 'crypto' ]) diff --git a/src/pool/PoolObjectSQL.cc b/src/pool/PoolObjectSQL.cc new file mode 100644 index 0000000000..103ab92e50 --- /dev/null +++ b/src/pool/PoolObjectSQL.cc @@ -0,0 +1,110 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.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 "PoolObjectSQL.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int PoolObjectSQL::select(SqlDB *db) +{ + ostringstream oss; + int rc; + int boid; + + set_callback( + static_cast(&PoolObjectSQL::select_cb)); + + oss << "SELECT body FROM " << table << " WHERE oid = " << oid; + + boid = oid; + oid = -1; + + rc = db->exec(oss, this); + + unset_callback(); + + if ((rc != 0) || (oid != boid )) + { + return -1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int PoolObjectSQL::select(SqlDB *db, const string& _name, int _uid) +{ + ostringstream oss; + + int rc; + char * sql_name; + + sql_name = db->escape_str(_name.c_str()); + + if ( sql_name == 0 ) + { + return -1; + } + + set_callback( + static_cast(&PoolObjectSQL::select_cb)); + + oss << "SELECT body FROM " << table << " WHERE name = '" <<_name << "'"; + + if ( _uid != -1 ) + { + oss << " AND uid = " << _uid; + } + + name = ""; + uid = -1; + + rc = db->exec(oss, this); + + unset_callback(); + + db->free_str(sql_name); + + if ((rc != 0) || (_name != name) || (_uid != uid)) + { + return -1; + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int PoolObjectSQL::drop(SqlDB *db) +{ + ostringstream oss; + int rc; + + oss << "DELETE FROM " << table << " WHERE oid=" << oid; + + rc = db->exec(oss); + + if ( rc == 0 ) + { + set_valid(false); + } + + return rc; +} diff --git a/src/pool/PoolSQL.cc b/src/pool/PoolSQL.cc index c813d934c0..c698e51581 100644 --- a/src/pool/PoolSQL.cc +++ b/src/pool/PoolSQL.cc @@ -86,6 +86,7 @@ PoolSQL::~PoolSQL() pthread_mutex_destroy(&mutex); } + /* ************************************************************************** */ /* PoolSQL public interface */ /* ************************************************************************** */ @@ -185,7 +186,82 @@ PoolObjectSQL * PoolSQL::get( return 0; } + string okey = key(objectsql->name,objectsql->uid); + pool.insert(make_pair(objectsql->oid,objectsql)); + name_pool.insert(make_pair(okey, objectsql)); + + if ( olock == true ) + { + objectsql->lock(); + } + + oid_queue.push(objectsql->oid); + + if ( pool.size() > MAX_POOL_SIZE ) + { + replace(); + } + + unlock(); + + return objectsql; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +PoolObjectSQL * PoolSQL::get(const string& name, int ouid, bool olock) +{ + map::iterator index; + + PoolObjectSQL * objectsql; + int rc; + + lock(); + + index = name_pool.find(key(name,ouid)); + + if ( index != name_pool.end() ) + { + if ( index->second->isValid() == false ) + { + objectsql = 0; + } + else + { + objectsql = index->second; + + if ( olock == true ) + { + objectsql->lock(); + } + } + + unlock(); + + return objectsql; + } + else + { + objectsql = create(); + + rc = objectsql->select(db,name,ouid); + + if ( rc != 0 ) + { + delete objectsql; + + unlock(); + + return 0; + } + + string okey = key(objectsql->name,objectsql->uid); + + pool.insert(make_pair(objectsql->oid, objectsql)); + name_pool.insert(make_pair(okey, objectsql)); if ( olock == true ) { @@ -236,10 +312,11 @@ void PoolSQL::replace() } else { - PoolObjectSQL * tmp_ptr; + PoolObjectSQL * tmp_ptr = index->second; + string okey = key(tmp_ptr->name,tmp_ptr->uid); - tmp_ptr = index->second; pool.erase(index); + name_pool.erase(okey); delete tmp_ptr; @@ -266,12 +343,63 @@ void PoolSQL::clean() } pool.clear(); + name_pool.clear(); unlock(); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +int PoolSQL::dump_cb(void * _oss, int num, char **values, char **names) +{ + ostringstream * oss; + + oss = static_cast(_oss); + + if ( (!values[0]) || (num != 1) ) + { + return -1; + } + + *oss << values[0]; + return 0; +} + +/* -------------------------------------------------------------------------- */ + +int PoolSQL::dump(ostringstream& oss, + const string& elem_name, + const char * table, + const string& where) +{ + int rc; + ostringstream cmd; + + oss << "<" << elem_name << ">"; + + set_callback(static_cast(&PoolSQL::dump_cb), + static_cast(&oss)); + + cmd << "SELECT body FROM " << table; + + if ( !where.empty() ) + { + cmd << " WHERE " << where; + } + + rc = db->exec(cmd, this); + + oss << ""; + + unset_callback(); + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + int PoolSQL:: search_cb(void * _oids, int num, char **values, char **names) { vector * oids; @@ -309,3 +437,4 @@ int PoolSQL::search( return rc; } + diff --git a/src/pool/SConstruct b/src/pool/SConstruct index 47ceedfdf6..734ce963e5 100644 --- a/src/pool/SConstruct +++ b/src/pool/SConstruct @@ -22,7 +22,8 @@ lib_name='nebula_pool' # Sources to generate the library source_files=[ - 'PoolSQL.cc' + 'PoolSQL.cc', + 'PoolObjectSQL.cc' ] # Build library diff --git a/src/pool/test/SConstruct b/src/pool/test/SConstruct index bdec5bdd9e..085b413a2b 100644 --- a/src/pool/test/SConstruct +++ b/src/pool/test/SConstruct @@ -23,6 +23,7 @@ env.Append(LIBPATH=[ env.Prepend(LIBS=[ 'nebula_pool', + 'nebula_xml', 'nebula_common', 'nebula_log', 'nebula_core', diff --git a/src/pool/test/TestPoolSQL.cc b/src/pool/test/TestPoolSQL.cc index 82f307c9df..4442d62e96 100644 --- a/src/pool/test/TestPoolSQL.cc +++ b/src/pool/test/TestPoolSQL.cc @@ -32,10 +32,10 @@ const char * TestObjectSQL::table = "test_pool"; -const char * TestObjectSQL::db_names = "(oid,number,text)"; +const char * TestObjectSQL::db_names = "(oid,number,name)"; const char * TestObjectSQL::db_bootstrap = "CREATE TABLE test_pool (" - "oid INTEGER, number INTEGER, text TEXT, PRIMARY KEY(oid))"; + "oid INTEGER, number INTEGER, name TEXT, PRIMARY KEY(oid))"; /* -------------------------------------------------------------------------- */ diff --git a/src/pool/test/TestPoolSQL.h b/src/pool/test/TestPoolSQL.h index ca8e0c891e..0ef0b23cf8 100644 --- a/src/pool/test/TestPoolSQL.h +++ b/src/pool/test/TestPoolSQL.h @@ -30,7 +30,7 @@ class TestObjectSQL : public PoolObjectSQL { public: //OBJECT ATTRIBUTES - TestObjectSQL(int n=-1, string t="default"):number(n),text(t){}; + TestObjectSQL(int n=-1, string t="default"):PoolObjectSQL(-1,"",0,0),number(n),text(t){}; ~TestObjectSQL(){}; @@ -71,6 +71,16 @@ public: db->exec(oss,0); }; + + string& to_xml(string& xml) const + { + return xml; + }; + + int from_xml(const string &xml_str) + { + return 0; + }; }; // THE POOL diff --git a/src/pool/test/pool.cc b/src/pool/test/pool.cc index b976dadf26..e0df566f90 100644 --- a/src/pool/test/pool.cc +++ b/src/pool/test/pool.cc @@ -141,7 +141,7 @@ public: vector results; const char * table = "test_pool"; - string where = "text = '" + stB + "'"; + string where = "name = '" + stB + "'"; int ret; ret = pool->search(results, table, where); @@ -205,4 +205,4 @@ public: int main(int argc, char ** argv) { return OneUnitTest::main(argc, argv, PoolTest::suite()); -} \ No newline at end of file +} diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index a4271f480a..8960062ac4 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -250,22 +250,22 @@ void RequestManager::register_xml_methods() RequestManager::HostEnable(hpool,upool)); xmlrpc_c::methodPtr cluster_allocate(new - RequestManager::ClusterAllocate(hpool,upool)); + RequestManager::ClusterAllocate(upool,cpool)); xmlrpc_c::methodPtr cluster_info(new - RequestManager::ClusterInfo(hpool,upool)); + RequestManager::ClusterInfo(upool,cpool)); xmlrpc_c::methodPtr cluster_delete(new - RequestManager::ClusterDelete(hpool,upool)); + RequestManager::ClusterDelete(upool,cpool)); xmlrpc_c::methodPtr cluster_add(new - RequestManager::ClusterAdd(hpool,upool)); + RequestManager::ClusterAdd(hpool,upool,cpool)); xmlrpc_c::methodPtr cluster_remove(new - RequestManager::ClusterRemove(hpool,upool)); + RequestManager::ClusterRemove(hpool,upool,cpool)); xmlrpc_c::methodPtr clusterpool_info(new - RequestManager::ClusterPoolInfo(hpool,upool)); + RequestManager::ClusterPoolInfo(upool,cpool)); xmlrpc_c::methodPtr vn_allocate(new RequestManager::VirtualNetworkAllocate(vnpool,upool)); @@ -300,6 +300,9 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr user_change_password(new RequestManager::UserChangePassword(upool)); + xmlrpc_c::methodPtr user_authenticate(new + RequestManager::UserAuthenticate(upool)); + xmlrpc_c::methodPtr userpool_info(new RequestManager::UserPoolInfo(upool)); @@ -378,6 +381,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.user.delete", user_delete); RequestManagerRegistry.addMethod("one.user.info", user_info); RequestManagerRegistry.addMethod("one.user.passwd", user_change_password); + RequestManagerRegistry.addMethod("one.user.authenticate",user_authenticate); RequestManagerRegistry.addMethod("one.userpool.info", userpool_info); diff --git a/src/rm/RequestManagerAllocate.cc b/src/rm/RequestManagerAllocate.cc index 9aaeef590e..6ae73f60bc 100644 --- a/src/rm/RequestManagerAllocate.cc +++ b/src/rm/RequestManagerAllocate.cc @@ -29,6 +29,7 @@ void RequestManager::VirtualMachineAllocate::execute( string session; string str_template; string error_str; + string user_name; const string method_name = "VirtualMachineAllocate"; @@ -41,6 +42,7 @@ void RequestManager::VirtualMachineAllocate::execute( xmlrpc_c::value_array * arrayresult; VirtualMachineTemplate * vm_template; + User * user; char * error_msg = 0; int num; @@ -92,7 +94,7 @@ void RequestManager::VirtualMachineAllocate::execute( continue; } - VirtualMachineAllocate::ipool->authorize_disk(vector,&ar); + VirtualMachineAllocate::ipool->authorize_disk(vector,uid,&ar); } vectors.clear(); @@ -108,7 +110,7 @@ void RequestManager::VirtualMachineAllocate::execute( continue; } - VirtualMachineAllocate::vnpool->authorize_nic(vector,&ar); + VirtualMachineAllocate::vnpool->authorize_nic(vector,uid,&ar); } ar.add_auth(AuthRequest::VM, @@ -123,10 +125,26 @@ void RequestManager::VirtualMachineAllocate::execute( } } + //-------------------------------------------------------------------------- + // Get the User Name + //-------------------------------------------------------------------------- + + user = VirtualMachineAllocate::upool->get(uid,true); + + if ( user == 0 ) + { + goto error_user_get; + } + + user_name = user->get_name(); + + user->unlock(); + //-------------------------------------------------------------------------- // Allocate the VirtualMAchine //-------------------------------------------------------------------------- rc = VirtualMachineAllocate::vmpool->allocate(uid, + user_name, vm_template, &vid, error_str, @@ -147,6 +165,13 @@ void RequestManager::VirtualMachineAllocate::execute( return; + +error_user_get: + oss.str(get_error(method_name, "USER", uid)); + + delete vm_template; + goto error_common; + error_authenticate: oss.str(authenticate_error(method_name)); goto error_common; diff --git a/src/rm/RequestManagerClusterAdd.cc b/src/rm/RequestManagerClusterAdd.cc index 9e0391f30e..0ffe63f389 100644 --- a/src/rm/RequestManagerClusterAdd.cc +++ b/src/rm/RequestManagerClusterAdd.cc @@ -34,7 +34,8 @@ void RequestManager::ClusterAdd::execute( const string method_name = "ClusterAdd"; - Host * host; + Host * host; + Cluster * cluster; ostringstream oss; @@ -71,6 +72,14 @@ void RequestManager::ClusterAdd::execute( } } + // Check if cluster exists + cluster = ClusterAdd::cpool->get(clid,true); + + if ( cluster == 0 ) + { + goto error_cluster_get; + } + // Check if host exists host = ClusterAdd::hpool->get(hid,true); @@ -80,7 +89,7 @@ void RequestManager::ClusterAdd::execute( } // Set cluster - rc = ClusterAdd::hpool->set_cluster(host, clid); + rc = host->set_cluster(cluster->get_name()); if ( rc != 0 ) { @@ -92,6 +101,8 @@ void RequestManager::ClusterAdd::execute( host->unlock(); + cluster->unlock(); + // All nice, return success to the client arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS @@ -112,11 +123,17 @@ error_authorize: goto error_common; error_host_get: + cluster->unlock(); oss.str(get_error(method_name, "HOST", hid)); goto error_common; +error_cluster_get: + oss.str(get_error(method_name, "CLUSTER", clid)); + goto error_common; + error_cluster_add: host->unlock(); + cluster->unlock(); oss.str(action_error(method_name, "USE", "CLUSTER", clid, rc)); goto error_common; diff --git a/src/rm/RequestManagerClusterAllocate.cc b/src/rm/RequestManagerClusterAllocate.cc index 5184f925d8..54fff40ccc 100644 --- a/src/rm/RequestManagerClusterAllocate.cc +++ b/src/rm/RequestManagerClusterAllocate.cc @@ -69,7 +69,7 @@ void RequestManager::ClusterAllocate::execute( } // Perform the allocation in the hostpool - rc = ClusterAllocate::hpool->allocate_cluster(&id, clustername, error_str); + rc = ClusterAllocate::cpool->allocate(&id, clustername, error_str); if ( rc == -1 ) { diff --git a/src/rm/RequestManagerClusterDelete.cc b/src/rm/RequestManagerClusterDelete.cc index b403b52b7c..a1a938faa4 100644 --- a/src/rm/RequestManagerClusterDelete.cc +++ b/src/rm/RequestManagerClusterDelete.cc @@ -26,14 +26,14 @@ void RequestManager::ClusterDelete::execute( xmlrpc_c::paramList const& paramList, xmlrpc_c::value * const retval) { - string session; + string session; - // of the cluster to delete from the HostPool - int clid; - ostringstream oss; - int rc; + int clid; + Cluster * cluster; + ostringstream oss; + int rc; - const string method_name = "ClusterDelete"; + const string method_name = "ClusterDelete"; /* -- RPC specific vars -- */ vector arrayData; @@ -66,7 +66,17 @@ void RequestManager::ClusterDelete::execute( } } - rc = ClusterDelete::hpool->drop_cluster(clid); + // Perform the deletion from the pool + cluster = ClusterDelete::cpool->get(clid,true); + + if ( cluster == 0 ) + { + goto error_cluster_get; + } + + rc = ClusterDelete::cpool->drop(cluster); + + cluster->unlock(); if ( rc != 0 ) { @@ -92,6 +102,10 @@ error_authorize: oss.str(authorization_error(method_name, "DELETE", "CLUSTER", rc, clid)); goto error_common; +error_cluster_get: + oss.str(get_error(method_name, "CLUSTER", clid)); + goto error_common; + error_cluster_delete: oss.str(action_error(method_name, "DELETE", "CLUSTER", clid, rc)); goto error_common; diff --git a/src/rm/RequestManagerClusterInfo.cc b/src/rm/RequestManagerClusterInfo.cc index 5f09d56b83..d446e7677e 100644 --- a/src/rm/RequestManagerClusterInfo.cc +++ b/src/rm/RequestManagerClusterInfo.cc @@ -29,12 +29,14 @@ void RequestManager::ClusterInfo::execute( string session; string info; - int clid; - int rc; - + Cluster * cluster; + ostringstream oss; + + int clid; + int rc; + const string method_name = "ClusterInfo"; - ostringstream oss; /* -- RPC specific vars -- */ vector arrayData; @@ -54,14 +56,18 @@ void RequestManager::ClusterInfo::execute( goto error_authenticate; } - info = ClusterInfo::hpool->info_cluster(clid); + // Get the cluster + cluster = ClusterInfo::cpool->get(clid,true); - // Cluster does not exists - if ( info.empty() ) + if ( cluster == 0 ) { - goto error_cluster; + goto error_cluster_get; } + oss << *cluster; + + cluster->unlock(); + // All nice, return the cluster info to the client arrayData.push_back(xmlrpc_c::value_boolean(true)); // SUCCESS arrayData.push_back(xmlrpc_c::value_string(info)); @@ -78,7 +84,7 @@ error_authenticate: oss.str(authenticate_error(method_name)); goto error_common; -error_cluster: +error_cluster_get: oss.str(get_error(method_name, "CLUSTER", clid)); goto error_common; diff --git a/src/rm/RequestManagerClusterPoolInfo.cc b/src/rm/RequestManagerClusterPoolInfo.cc old mode 100755 new mode 100644 index fb9ba26b8f..ece06d4274 --- a/src/rm/RequestManagerClusterPoolInfo.cc +++ b/src/rm/RequestManagerClusterPoolInfo.cc @@ -29,7 +29,7 @@ void RequestManager::ClusterPoolInfo::execute( string session; ostringstream oss; int rc; - + const string method_name = "ClusterPoolInfo"; /* -- RPC specific vars -- */ @@ -49,8 +49,8 @@ void RequestManager::ClusterPoolInfo::execute( goto error_authenticate; } - // Perform the allocation in the vmpool - rc = ClusterPoolInfo::hpool->dump_cluster(oss); + // Dump the pool + rc = ClusterPoolInfo::cpool->dump(oss, ""); if ( rc != 0 ) { diff --git a/src/rm/RequestManagerClusterRemove.cc b/src/rm/RequestManagerClusterRemove.cc index f18e75c6a7..1fe7fa9b80 100644 --- a/src/rm/RequestManagerClusterRemove.cc +++ b/src/rm/RequestManagerClusterRemove.cc @@ -27,10 +27,10 @@ void RequestManager::ClusterRemove::execute( xmlrpc_c::value * const retval) { string session; - + int hid; int rc; - + const string method_name = "ClusterRemove"; Host * host; @@ -77,7 +77,7 @@ void RequestManager::ClusterRemove::execute( } // Remove host from cluster - rc = ClusterRemove::hpool->set_default_cluster(host); + rc = ClusterRemove::cpool->set_default_cluster(host); if ( rc != 0 ) { diff --git a/src/rm/RequestManagerDeploy.cc b/src/rm/RequestManagerDeploy.cc index 44643d23bf..5c982e95b3 100644 --- a/src/rm/RequestManagerDeploy.cc +++ b/src/rm/RequestManagerDeploy.cc @@ -107,7 +107,7 @@ void RequestManager::VirtualMachineDeploy::execute( goto error_host_get; } - hostname = host->get_hostname(); + hostname = host->get_name(); vmm_mad = host->get_vmm_mad(); tm_mad = host->get_tm_mad(); diff --git a/src/rm/RequestManagerHostDelete.cc b/src/rm/RequestManagerHostDelete.cc index 67a8f2f6e5..fa8bc3e968 100644 --- a/src/rm/RequestManagerHostDelete.cc +++ b/src/rm/RequestManagerHostDelete.cc @@ -67,7 +67,7 @@ void RequestManager::HostDelete::execute( } } - // Perform the allocation in the hostpool + // Perform the deletion from the hostpool host = HostDelete::hpool->get(hid,true); if ( host == 0 ) diff --git a/src/rm/RequestManagerHostPoolInfo.cc b/src/rm/RequestManagerHostPoolInfo.cc old mode 100755 new mode 100644 diff --git a/src/rm/RequestManagerImageAllocate.cc b/src/rm/RequestManagerImageAllocate.cc index 7c0e307006..a572d38059 100644 --- a/src/rm/RequestManagerImageAllocate.cc +++ b/src/rm/RequestManagerImageAllocate.cc @@ -31,8 +31,10 @@ void RequestManager::ImageAllocate::execute( string session; string str_template; string error_str; + string user_name; - ImageTemplate * img_template; + ImageTemplate * img_template = 0; + User * user; int iid; int uid; @@ -96,10 +98,28 @@ void RequestManager::ImageAllocate::execute( } } + + //-------------------------------------------------------------------------- + // Get the User Name + //-------------------------------------------------------------------------- + + user = ImageAllocate::upool->get(uid,true); + + if ( user == 0 ) + { + goto error_user_get; + } + + user_name = user->get_name(); + + user->unlock(); + //-------------------------------------------------------------------------- // Allocate the Image //-------------------------------------------------------------------------- - rc = ImageAllocate::ipool->allocate(uid,img_template,&iid, error_str); + + rc = ImageAllocate::ipool->allocate(uid,user_name, + img_template,&iid, error_str); if ( rc < 0 ) { @@ -118,6 +138,12 @@ void RequestManager::ImageAllocate::execute( return; + +error_user_get: + oss.str(get_error(method_name, "USER", uid)); + delete img_template; + goto error_common; + error_authenticate: oss.str(authenticate_error(method_name)); goto error_common; diff --git a/src/rm/RequestManagerImagePoolInfo.cc b/src/rm/RequestManagerImagePoolInfo.cc old mode 100755 new mode 100644 diff --git a/src/rm/RequestManagerMigrate.cc b/src/rm/RequestManagerMigrate.cc index 2fe2d1b513..9761692b33 100644 --- a/src/rm/RequestManagerMigrate.cc +++ b/src/rm/RequestManagerMigrate.cc @@ -67,7 +67,7 @@ void RequestManager::VirtualMachineMigrate::execute( goto error_host_get; } - hostname = host->get_hostname(); + hostname = host->get_name(); vmm_mad = host->get_vmm_mad(); tm_mad = host->get_tm_mad(); diff --git a/src/rm/RequestManagerPoolInfo.cc b/src/rm/RequestManagerPoolInfo.cc index 95ba3b7879..cfbb31d162 100644 --- a/src/rm/RequestManagerPoolInfo.cc +++ b/src/rm/RequestManagerPoolInfo.cc @@ -32,8 +32,6 @@ void RequestManager::VirtualMachinePoolInfo::execute( int rc; int state; - bool extended; - ostringstream oss; ostringstream where_string; @@ -45,18 +43,17 @@ void RequestManager::VirtualMachinePoolInfo::execute( NebulaLog::log("ReM",Log::DEBUG,"VirtualMachinePoolInfo method invoked"); + // For backwards compatibility, 2 or 3 arguments can be present. switch (paramList.size()) { case 2: - extended = true; state = -1; break; - case 4: - extended = xmlrpc_c::value_boolean(paramList.getBoolean(2)); + case 3: state = xmlrpc_c::value_int (paramList.getInt(3)); break; default: - paramList.verifyEnd(4); + paramList.verifyEnd(3); return; } @@ -86,7 +83,7 @@ void RequestManager::VirtualMachinePoolInfo::execute( where_string << "UID=" << filter_flag; } - rc = VirtualMachinePoolInfo::vmpool->dump(oss, extended, state, where_string.str()); + rc = VirtualMachinePoolInfo::vmpool->dump(oss, state, where_string.str()); if ( rc != 0 ) { diff --git a/src/rm/RequestManagerUserAuthenticate.cc b/src/rm/RequestManagerUserAuthenticate.cc new file mode 100644 index 0000000000..6b0137e021 --- /dev/null +++ b/src/rm/RequestManagerUserAuthenticate.cc @@ -0,0 +1,79 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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 "NebulaLog.h" + +#include "AuthManager.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void RequestManager::UserAuthenticate::execute( + xmlrpc_c::paramList const& paramList, + xmlrpc_c::value * const retval) +{ + string session; + int uid; + + ostringstream oss; + const string method_name = "UserAuthenticate"; + + + /* -- RPC specific vars -- */ + vector arrayData; + xmlrpc_c::value_array * arrayresult; + + NebulaLog::log("ReM",Log::DEBUG,"UserAuthenticate method invoked"); + + // Get the parameters + session = xmlrpc_c::value_string(paramList.getString(0)); + + // Try to authenticate the user + uid = UserAuthenticate::upool->authenticate(session); + + if( uid == -1 ) + { + goto error_common; + } + + //Result + arrayData.push_back(xmlrpc_c::value_boolean( true )); + arrayData.push_back(xmlrpc_c::value_int(uid)); + arrayresult = new xmlrpc_c::value_array(arrayData); + + *retval = *arrayresult; + + delete arrayresult; + + return; + +error_common: + oss.str(authenticate_error(method_name)); + + arrayData.push_back(xmlrpc_c::value_boolean(false)); // FAILURE + arrayData.push_back(xmlrpc_c::value_string(authenticate_error(method_name))); + + NebulaLog::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 d010505af6..ef687ad5f9 100644 --- a/src/rm/RequestManagerVirtualNetworkAllocate.cc +++ b/src/rm/RequestManagerVirtualNetworkAllocate.cc @@ -28,10 +28,12 @@ void RequestManager::VirtualNetworkAllocate::execute( { string session; string name; + string user_name; string str_template; string error_str; VirtualNetworkTemplate * vn_template; + User * user; int nid; int uid; @@ -96,10 +98,25 @@ void RequestManager::VirtualNetworkAllocate::execute( } } + //-------------------------------------------------------------------------- + // Get the User Name + //-------------------------------------------------------------------------- + + user = VirtualNetworkAllocate::upool->get(uid,true); + + if ( user == 0 ) + { + goto error_user_get; + } + + user_name = user->get_name(); + + user->unlock(); + //-------------------------------------------------------------------------- // Allocate the Virtual Network //-------------------------------------------------------------------------- - rc = vnpool->allocate(uid,vn_template,&nid,error_str); + rc = vnpool->allocate(uid,user_name,vn_template,&nid,error_str); if ( rc < 0 ) { @@ -118,6 +135,12 @@ void RequestManager::VirtualNetworkAllocate::execute( return; +error_user_get: + oss.str(get_error(method_name, "USER", uid)); + + delete vn_template; + goto error_common; + error_authenticate: oss.str(authenticate_error(method_name)); goto error_common; diff --git a/src/rm/RequestManagerVirtualNetworkPoolInfo.cc b/src/rm/RequestManagerVirtualNetworkPoolInfo.cc old mode 100755 new mode 100644 diff --git a/src/rm/SConstruct b/src/rm/SConstruct index 2bdab14e9f..b9f285550e 100644 --- a/src/rm/SConstruct +++ b/src/rm/SConstruct @@ -60,6 +60,7 @@ source_files=[ 'RequestManagerUserAllocate.cc', 'RequestManagerUserDelete.cc', 'RequestManagerUserChangePassword.cc', + 'RequestManagerUserAuthenticate.cc', 'RequestManagerUserInfo.cc', 'RequestManagerUserPoolInfo.cc' ] diff --git a/src/scheduler/SConstruct b/src/scheduler/SConstruct index a41d005437..7a69cab7c7 100644 --- a/src/scheduler/SConstruct +++ b/src/scheduler/SConstruct @@ -28,7 +28,7 @@ env.Append(CPPPATH=[ # Library dirs env.Append(LIBPATH=[ - cwd+'/src/xml', + cwd+'/src/client', cwd+'/src/pool', cwd+'/src/sched' ]) @@ -38,7 +38,7 @@ env.Append(LIBPATH=[ ################################################################################ build_scripts=[ - 'src/xml/SConstruct', + 'src/client/SConstruct', 'src/pool/SConstruct', 'src/sched/SConstruct' ] @@ -46,7 +46,6 @@ build_scripts=[ if env['testing']=='yes': build_scripts.extend([ 'src/pool/test/SConstruct', - 'src/xml/test/SConstruct', ]) for script in build_scripts: diff --git a/src/scheduler/include/PoolXML.h b/src/scheduler/include/PoolXML.h index 146bd1bbad..428cf10d69 100644 --- a/src/scheduler/include/PoolXML.h +++ b/src/scheduler/include/PoolXML.h @@ -84,7 +84,7 @@ public: return -1; } - update(message); + update_from_str(message); vector nodes; int num_objs; diff --git a/src/scheduler/src/xml/Client.cc b/src/scheduler/src/client/Client.cc similarity index 100% rename from src/scheduler/src/xml/Client.cc rename to src/scheduler/src/client/Client.cc diff --git a/src/scheduler/src/client/SConstruct b/src/scheduler/src/client/SConstruct new file mode 100644 index 0000000000..d9509465b1 --- /dev/null +++ b/src/scheduler/src/client/SConstruct @@ -0,0 +1,26 @@ +# SConstruct for src/pool + +# -------------------------------------------------------------------------- # +# Copyright 2002-2010, OpenNebula Project Leads (OpenNebula.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('sched_env') + +lib_name='scheduler_client' + +source_files=['Client.cc'] + +# Build library +sched_env.StaticLibrary(lib_name, source_files) diff --git a/src/scheduler/src/pool/test/SConstruct b/src/scheduler/src/pool/test/SConstruct index 964b474ae2..69d4ce0b46 100644 --- a/src/scheduler/src/pool/test/SConstruct +++ b/src/scheduler/src/pool/test/SConstruct @@ -18,7 +18,7 @@ Import('sched_env') # Libraries sched_env.Prepend(LIBS=[ - 'scheduler_xml', + 'nebula_xml', 'scheduler_pool', 'nebula_log', 'nebula_common', diff --git a/src/scheduler/src/sched/SConstruct b/src/scheduler/src/sched/SConstruct index 7d30c335c7..41cb064c98 100644 --- a/src/scheduler/src/sched/SConstruct +++ b/src/scheduler/src/sched/SConstruct @@ -31,7 +31,8 @@ sched_env.Prepend(LIBS=[ 'scheduler_sched', 'scheduler_pool', 'nebula_log', - 'scheduler_xml', + 'scheduler_client', + 'nebula_xml', 'nebula_common', 'crypto', ]) diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb index a548c159b0..55f6cada51 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb @@ -46,15 +46,16 @@ module OpenNebulaJSON when "deploy" then self.deploy(action_hash['params']) when "finalize" then self.finalize when "hold" then self.hold - when "livemigrate" then self.live_migrate(action_hash['params']) + when "livemigrate" then self.live_migrate(action_hash['params']) when "migrate" then self.migrate(action_hash['params']) when "resume" then self.resume when "release" then self.release when "stop" then self.stop when "suspend" then self.suspend when "restart" then self.restart - when "saveas" then self.save_as(action_hash['params']) + when "saveas" then self.save_as(action_hash['params']) when "shutdown" then self.shutdown + when "resubmit" then self.resubmit else error_msg = "#{action_hash['perform']} action not " << " available for this resource" diff --git a/src/sunstone/public/css/application.css b/src/sunstone/public/css/application.css index 4d2a4ad743..4e0ca48f29 100644 --- a/src/sunstone/public/css/application.css +++ b/src/sunstone/public/css/application.css @@ -407,7 +407,7 @@ tr.even:hover{ .top_button { font-size: 0.8em; height: 25px; - margin: 3px 0; + margin: 3px 2px; vertical-align: middle; /*width: 89px;*/ } @@ -417,6 +417,13 @@ tr.even:hover{ vertical-align: middle; } +.image_button { + font-size: 0.8em; + margin: 3px 2px; + vertical-align: middle; + border:0; +} + /* .multi_action_slct{ font-size: 0.7em; diff --git a/src/sunstone/public/js/layout.js b/src/sunstone/public/js/layout.js index fd1da90ed4..f094c9a914 100644 --- a/src/sunstone/public/js/layout.js +++ b/src/sunstone/public/js/layout.js @@ -57,7 +57,7 @@ function showTab(tabname){ $(document).ready(function () { $(".tab").hide(); - $(".outer-west ul li a").click(function(){ + $(".outer-west ul li a").live("click",function(){ var tab = $(this).attr('href'); showTab(tab); return false; @@ -97,6 +97,5 @@ $(document).ready(function () { , spacing_closed: 12 // ALL panes }); - showTab("#dashboard"); }); diff --git a/src/sunstone/public/js/one-ui_views.js b/src/sunstone/public/js/one-ui_views.js deleted file mode 100644 index eaa2e221cc..0000000000 --- a/src/sunstone/public/js/one-ui_views.js +++ /dev/null @@ -1,3283 +0,0 @@ -/* -------------------------------------------------------------------------- */ -/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ -/* -------------------------------------------------------------------------- */ - - -/*###################################################################### - * GLOBAL VARIABLES - * ###################################################################*/ - -var dataTable_hosts=null; -//~ var dataTable_clusters=null; -var dataTable_vMachines=null; -var dataTable_vNetworks=null; -var dataTable_users=null; -var dataTable_images=null; -var host_list_json = {}; -var cluster_list_json = {}; -var vmachine_list_json = {}; -var network_list_json = {}; -var user_list_json = {}; -var image_list_json = {}; -var hosts_select=""; -var clusters_select=""; -var vnetworks_select=""; -var images_select=""; -var cookie = {}; -var username = ''; -var uid = ''; -var spinner = 'retrieving'; - -/*###################################################################### - * DOCUMENT READY FUNCTIONS - * ###################################################################*/ - -$(document).ready(function() { - - readCookie(); - setLogin(); - insertTemplates(); //put templates in place - initDataTables(); - initCheckAllBoxes(); - initListButtons(); - setupCreateDialogs(); - setupTips(); - hideUnauthorizedDivs(); - refreshButtonListener(); //listen to manual refresh image clicks - confirmButtonListener(); //listen to buttons that require confirmation - confirmWithSelectListener(); //listen to buttons requiring a selector - actionButtonListener(); //listens to all simple actions (not creates) - - hostInfoListener(); - vMachineInfoListener(); - vNetworkInfoListener(); - imageInfoListener(); - - - - setupImageAttributesDialogs(); //setups the add/update/remove attr dialogs - - //Jquery-ui eye-candy - $('button').button(); - $('div#select_helpers').hide(); - emptyDashboard(); - preloadTables(); - setupAutoRefresh(); - - tableCheckboxesListener(dataTable_hosts); - tableCheckboxesListener(dataTable_vMachines); - tableCheckboxesListener(dataTable_vNetworks); - if (uid == 0){ - tableCheckboxesListener(dataTable_users); - } - tableCheckboxesListener(dataTable_images); - - $(".ui-widget-overlay").live("click", function (){ - $("div:ui-dialog:visible").dialog("close"); - }); - - //Dashboard link listener - $("#dashboard_table h3 a").live("click", function (){ - var tab = $(this).attr('href'); - showTab(tab); - return false; - }); - - //Close select lists... - $('*:not(.action_list,.list_button)').click(function(){ - $('.action_list:visible').hide(); - }); - - -}); - -//reads the cookie and places its info in the 'cookie' var -function readCookie(){ - $.each(document.cookie.split("; "), function(i,e){ - var e_split = e.split("="); - var key = e_split[0]; - var value = e_split[1]; - cookie[key] = value; - }); -} - -//sets the user info in the top bar and creates a listner in the signout button -function setLogin(){ - username = cookie["one-user"]; - uid = cookie["one-user_id"]; - - $("#user").html(username); - $("#logout").click(function(){ - OpenNebula.Auth.logout({success:function(){ - window.location.href = "/login"; - } - }); - return false; - }); -} - -function hideUnauthorizedDivs(){ - // hide all the oneadmin divs if user is not oneadmin - if (uid != 0) { - $(".oneadmin").hide(); - } -} -//puts predifined templates into the document body -//templates can be found in one-ui_views.templates.js -function insertTemplates(){ - $('div#dashboard').html(dashboard_tmpl); - $('div#hosts').html(hostlist_tmpl); - //$('div#clusters').html(clusterlist_tmpl); - $('div#virtualMachines').html(vmachinelist_tmpl); - $('div#virtualNetworks').html(vnetworklist_tmpl); - $('div#users').html(userlist_tmpl); - $('div#images').html(imagelist_tmpl); -} - - -//initializes the dataTables and sets the options -function initDataTables(){ - - dataTable_hosts = $("#datatable_hosts").dataTable({ - "bJQueryUI": true, - "bSortClasses": false, - "bAutoWidth":false, - "sPaginationType": "full_numbers", - "aoColumnDefs": [ - { "bSortable": false, "aTargets": ["check"] }, - { "sWidth": "60px", "aTargets": [0,4] }, - { "sWidth": "35px", "aTargets": [1] }, - { "sWidth": "120px", "aTargets": [5,6] } - ] - }); - - - //~ dataTable_clusters = $("#datatable_clusters").dataTable({ - //~ "bJQueryUI": true, - //~ "bSortClasses": false, - //~ "sPaginationType": "full_numbers", - //~ "aoColumnDefs": [ - //~ { "bSortable": false, "aTargets": ["check"] } - //~ ] - //~ }); - - dataTable_vMachines = $("#datatable_vmachines").dataTable({ - "bJQueryUI": true, - "bSortClasses": false, - "sPaginationType": "full_numbers", - "bAutoWidth":false, - "aoColumnDefs": [ - { "bSortable": false, "aTargets": ["check"] }, - { "sWidth": "60px", "aTargets": [0] }, - { "sWidth": "35px", "aTargets": [1] }, - { "sWidth": "100px", "aTargets": [2] } - ] - }); - - dataTable_vNetworks = $("#datatable_vnetworks").dataTable({ - "bJQueryUI": true, - "bSortClasses": false, - "bAutoWidth":false, - "sPaginationType": "full_numbers", - "aoColumnDefs": [ - { "bSortable": false, "aTargets": ["check"] }, - { "sWidth": "60px", "aTargets": [0,4,5,6,7] }, - { "sWidth": "35px", "aTargets": [1] }, - { "sWidth": "100px", "aTargets": [2] } - ] - }); - - if (uid == 0) { - dataTable_users = $("#datatable_users").dataTable({ - "bJQueryUI": true, - "bSortClasses": false, - "sPaginationType": "full_numbers", - "bAutoWidth":false, - "aoColumnDefs": [ - { "bSortable": false, "aTargets": ["check"] }, - { "sWidth": "60px", "aTargets": [0] }, - { "sWidth": "35px", "aTargets": [1] } - ] - }); - } - - dataTable_images = $("#datatable_images").dataTable({ - "bJQueryUI": true, - "bSortClasses": false, - "bAutoWidth":false, - "sPaginationType": "full_numbers", - "aoColumnDefs": [ - { "bSortable": false, "aTargets": ["check"] }, - { "sWidth": "60px", "aTargets": [0,3] }, - { "sWidth": "35px", "aTargets": [1] }, - { "sWidth": "100px", "aTargets": [2,3] } - ] - }); - -} - -//Adds a listener to checks all the elements of a table -function initCheckAllBoxes(){ - //not showing nice in that position - //$('.check_all').button({ icons: {primary : "ui-icon-check" }, - // text : true}); - $('.check_all').css({"border":"2px"}); - $('.check_all').click(function(){ - if ($(this).attr("checked")) { - $('tbody input:checkbox', - $(this).parents("table")).each(function(){ - $(this).attr("checked","checked"); - }); - - } else { - $('tbody input:checkbox', - $(this).parents("table")).each(function(){ - $(this).removeAttr("checked"); - }); } - }); -} - -//Converts selects into buttons which show a of actions when clicked -function initListButtons(){ - - //for each multi_action select - $('.multi_action_slct').each(function(){ - //prepare replacement buttons - buttonset = $('
Previous action').button(); - button1.attr("disabled","disabled"); - button2 = $('').button({ - text:false, - icons: { primary: "ui-icon-triangle-1-s" } - }); - buttonset.append(button1); - buttonset.append(button2); - buttonset.buttonset(); - - //prepare list - options = $('option', $(this)); - list = $('
    '); - $.each(options,function(){ - classes = $(this).attr("class"); - item = $('
  • '); - a = $(''+$(this).text()+''); - a.val($(this).val()); - item.html(a); - list.append(item); - }); - list.css({ - "display":"none" - }); - - - //replace the select and insert the buttons - $(this).before(buttonset); - $(this).parents('.action_blocks').append(list); - $(this).remove(); - //$(this).replaceWith(list); - - }); - - - //listen for events on this buttons and list - - //enable run the last action button - $('.action_list li a').click(function(){ - //enable run last action button - prev_action_button = $('.last_action_button',$(this).parents('.action_blocks')); - prev_action_button.val($(this).val()); - prev_action_button.removeClass("confirm_with_select_button"); - prev_action_button.removeClass("confirm_button"); - prev_action_button.removeClass("action_button"); - prev_action_button.addClass($(this).attr("class")); - prev_action_button.button("option","label",$(this).text()); - prev_action_button.button("enable"); - $(this).parents('ul').hide("blind",100); - //return false; - }); - - - //Show the list of actions in place - $('.list_button').click(function(){ - $('.action_list',$(this).parents('.action_blocks')).css({ - "left": $(this).prev().position().left, - "top": $(this).prev().position().top+13, - "width": $(this).parent().outerWidth()-11 - }); - $('.action_list',$(this).parents('.action_blocks')).toggle("blind",100); - return false; - }); - - -} - -//Sets up all the "+ New Thing" dialogs. -function setupCreateDialogs(){ - createHostDialog(); - createClusterDialog(); - createVMachineDialog(); - createVNetworkDialog(); - createUserDialog(); - createImageDialog(); -} - -function refreshButtonListener(){ - $('.refresh_image').click(function(){ - action = $(this).attr('alt'); - callback = null; - - waiting_nodes = function(dataTable){ - nodes = dataTable.fnGetData(); - for (var i=0;i
    '); - }; - - $('div#confirm_dialog').html( - '
    \ -
    Do you want to proceed?
    \ -
    \ -
    Do you want to proceed?
    \ -
    \ -
    \ - \ - \ -
    \ - '); - - //prepare the jquery dialog - $('div#confirm_dialog').dialog({ - resizable:false, - modal:true, - width:300, - heigth:200, - autoOpen:false - }); - - $('div#confirm_dialog button').button(); - - $('.confirm_button').live("click",function(){ - val=$(this).val(); - tip=""; - //supported cases - switch (val) { - case "OpenNebula.VM.deploy": - tip="This will deploy the selected VMs on the selected host."; - break; - case "OpenNebula.VM.migrate": - tip="This will migrate the selected VMs to the selected host. "; - tip+="This is a \"cold\" migration, as the VMs will be stopped "; - tip+="prior to that migration"; - break; - case "OpenNebula.VM.livemigrate": - tip="This will live-migrate the selected VMs to the selected host."; - break; - case "OpenNebula.VM.hold": - tip="This will pause the selected VMs."; - break; - case "OpenNebula.VM.release": - tip="This will release the selected VMs"; - break; - case "OpenNebula.VM.suspend": - tip="This will suspend the selected VMs. You can resume them later."; - break; - case "OpenNebula.VM.resume": - tip="This will resume the selected VMs from their suspend state"; - break; - case "OpenNebula.VM.stop": - tip="This will shutdown the selected VMs."; - break; - case "OpenNebula.VM.restart": - tip="This will reboot the selected VMs."; - break; - case "OpenNebula.VM.shutdown": - tip="This will try to properly shutdown the selected VMs."; - break; - case "OpenNebula.VM.cancel": - tip="This will destroy the selected VMs"; - break; - case "OpenNebula.VM.delete": - tip="This will delete the selected VMs"; - break; - default: return false; - - } - $('div#confirm_tip').text(tip); - $('div#confirm_dialog button#proceed').val(val); - $('div#confirm_dialog').dialog("open"); - - return false; - }); - - $('div#confirm_dialog #cancel').click(function(){ - $('div#confirm_dialog').dialog("close"); - return false; - }); - -} - -//Listens to ".confirm_with_select_button" elements. Shows a dialog -//allowing to confirm or cancel an action, with a tip and a -//select input field. Depending on the action, the select can -//contain different values. If wanting to proceed, the action is -//executed for each of the checked elements of the table, with the -//selected item of the box as extra parameter. -function confirmWithSelectListener(){ - //add this dialog to the dialogs. - if (!($('div#confirm_with_select_dialog').length)){ - $('div#dialogs').append('
    '); - }; - - $('div#confirm_with_select_dialog').html( - '
    \ -
    \ - \ -
    \ - \ - \ -
    \ - '); - - //prepare the jquery dialog - $('div#confirm_with_select_dialog').dialog({ - resizable:false, - modal:true, - width:300, - heigth:300, - autoOpen:false - }); - - $('div#confirm_with_select_dialog button').button(); - - $( '.confirm_with_select_button').live("click",function(){ - val=$(this).val(); - tip=""; - dataTable=null; - select_helper=null; - callback=null; - //supported cases - switch (val) { - case "OpenNebula.Cluster.addhost": - tip="This will add the selected Hosts the the following cluster:"; - dataTable="dataTable_hosts"; - callback = function(req){ - OpenNebula.Host.show({data:{id:req.request.data}, success: updateHostElement, error: onError}); - }; - select_var = clusters_select; - break; - case "OpenNebula.Cluster.delete": - tip="Select the cluster you want to delete"; - dataTable="null"; - select_var = clusters_select; - callback = function (){ - OpenNebula.Cluster.list({success: updateClustersView,error: onError}); - } - break; - case "OpenNebula.VM.deploy": - tip="This will deploy the selected VMs. Please select a host for the deployment:"; - dataTable = "dataTable_vMachines"; - callback = function(req){ - OpenNebula.VM.show({data:{id:req.request.data},success: updateVMachineElement,error: onError})}; - select_var = hosts_select; - break; - case "OpenNebula.VM.migrate": - tip="This will migrate the selected VMs. Please select a host as destination for the migration:"; - dataTable = "dataTable_vMachines"; - callback = function(req){ - OpenNebula.VM.show({data:{id:req.request.data},success: updateVMachineElement, error: onError})}; - select_var = hosts_select; - break; - case "OpenNebula.VM.livemigrate": - tip="This will live-migrate the selected VMs. Please select a host as destination for the migration:"; - dataTable = "dataTable_vMachines"; - callback = function(req){ - OpenNebula.VM.show({data:{id:req.request.data},success: updateVMachineElement,error: onError})}; - select_var = hosts_select; - break; - default: return false; - - } - - //insert options - $('select#confirm_select').html(select_var); - - $('div#confirm_with_select_tip').text(tip); - - $('button#confirm_with_select_proceed').val(val); - $('button#confirm_with_select_proceed').attr("dataTable",dataTable); - $('div#confirm_with_select_dialog').dialog("open"); - - return false; - }); - - $('button#confirm_with_select_proceed').click(function(){ - action=$(this).val(); - - selected_item_id = $('#confirm_select :selected').val(); - dataTable=eval($(this).attr("dataTable")); - - var data; - switch (action) { - case "OpenNebula.Cluster.addhost": - data = {cluster_id: selected_item_id}; - break; - case "OpenNebula.Cluster.delete": - data = {cluster_id: selected_item_id}; - break; - case "OpenNebula.VM.deploy": - data = {host_id: selected_item_id}; - break; - case "OpenNebula.VM.migrate": - data = {host_id: selected_item_id}; - break; - case "OpenNebula.VM.livemigrate": - data = {host_id: selected_item_id}; - break; - default: return false; - } - - if (dataTable != null && selected_item_id.length){ - nodes = $('input:checked',dataTable.fnGetNodes()); - //prepare array for notification - var nodes_id = new Array(); - $.each(nodes, function(){ - nodes_id.push($(this).val()); - data.id = $(this).val(); - (eval(action)({data: data, success: callback, error: onError })); - }); - notifySubmit(action,nodes_id,selected_item_id); - } - else { //we execute the action only on the selected item - (eval(action)({data:{id: selected_item_id},success: callback,error: onError})); - } - - $('div#confirm_with_select_dialog').dialog("close"); - return false; - }); - - $('button#confirm_with_select_cancel').click(function(){ - $('div#confirm_with_select_dialog').dialog("close"); - return false; - }); - -} - -//Listens to click on ".action_button" elements. According to the value -//of the element, it sends actions to OpenNebula.js. This function -//handles all the simple actions of the UI: delete, enables, disables, etc... -function actionButtonListener(){ - - //Listener - $('.action_button').live("click",function(){ - dataTable=null; //Which dataTable should be updated afterwards? - callback = null; //Which callback function should be used on success? - - //Actions have 1 fixed parametre (the element they primarly - //affect, fectched from the checkboxes of the list. - //Does our action need two params? (ex. add host to cluster) - extra_param = null; - - - action = $(this).val(); //Fetch the value of the action - - //Actions are grouped. For some of them no need to make a - //difference - switch (action){ - //Host list actions - //case "OpenNebula.Cluster.addhost": - case "OpenNebula.Cluster.removehost": - extra_param="0"; - case "OpenNebula.Host.enable": - case "OpenNebula.Host.disable": - dataTable = dataTable_hosts; - callback = function(req){ - OpenNebula.Host.show({data:{id:req.request.data[0]},success: updateHostElement,error: onError}); - }; - break; - - case "OpenNebula.Host.delete": - dataTable = dataTable_hosts; - callback = deleteHostElement; - break; - - //~ //Cluster list actions - now it is confirm with select - //~ case "OpenNebula.Cluster.delete": - //~ dataTable = dataTable_clusters; - //~ callback = deleteClusterElement; - //~ break; - - //VMachine list actions - case "OpenNebula.VM.deploy": - case "OpenNebula.VM.migrate": - case "OpenNebula.VM.livemigrate": - //Set an extra param if is a deploy, migrate or livemigrate - host = $('#vm_host :selected').val(); - //Making sure we selected a host - if (!host.length){ - break; - }; - extra_param = host; - - case "OpenNebula.VM.hold": - case "OpenNebula.VM.release": - case "OpenNebula.VM.suspend": - case "OpenNebula.VM.resume": - case "OpenNebula.VM.stop": - case "OpenNebula.VM.restart": - case "OpenNebula.VM.shutdown": - case "OpenNebula.VM.cancel": - dataTable = dataTable_vMachines; - callback = function(req){ - OpenNebula.VM.show({data:{id:req.request.data},success: updateVMachineElement,error: onError})}; - break; - case "OpenNebula.VM.delete": - dataTable = dataTable_vMachines; - callback = deleteVMachineElement; - break; - - //VNET list actions - case "OpenNebula.Network.publish": - case "OpenNebula.Network.unpublish": - dataTable = dataTable_vNetworks; - callback = function(req){ - OpenNebula.Network.show({data:{id:req.request.data},success: updateVNetworkElement, error: onError})}; - break; - break; - case "OpenNebula.Network.delete": - dataTable = dataTable_vNetworks; - callback = deleteVNetworkElement; - break; - case "OpenNebula.User.delete": - dataTable = dataTable_users; - callback = deleteUserElement; - break; - - //Images - case "OpenNebula.Image.delete": - dataTable = dataTable_images; - callback = deleteImageElement; - break; - case "OpenNebula.Image.enable": - case "OpenNebula.Image.disable": - case "OpenNebula.Image.persistent": - case "OpenNebula.Image.nonpersistent": - case "OpenNebula.Image.publish": - case "OpenNebula.Image.unpublish": - dataTable = dataTable_images; - callback = function(req){ - OpenNebula.Image.show({data:{id:req.request.data[0]},success: updateImageElement, error: onError}); - }; - break; - } - - $('div#confirm_dialog').dialog("close"); //in case we required it - - //If there is not a datatable set to fetch the elements affected, - //we assume the action was not recognised. - if (dataTable != null){ - - //Which rows of the datatable are checked? - nodes = $('input:checked',dataTable.fnGetNodes()); - - //For each we execute the action - var nodes_id = new Array(); - $.each(nodes, function(){ - //prepare array for notification - nodes_id.push($(this).val()); - //Calling action(id,callback,error_callback) - if (extra_param!=null){ //action with two parameters - var data_arg = {cluster_id: extra_param, id: $(this).val()}; - (eval(action)({data: data_arg, success: callback, error: onError})); - } else { //action with one parameter - (eval(action)({data:{id:$(this).val()},success: callback,error: onError})); - }; - }); - //Notify - if (extra_param!=null) { - notifySubmit(action,nodes_id,extra_param); - } else { - notifySubmit(action,nodes_id); - } - } - return false; - }); -} - -function preloadTables(){ - dataTable_hosts.fnClearTable(); - addElement([ - spinner, - '','','','','','',''],dataTable_hosts); - OpenNebula.Host.list({success: updateHostsView,error: onError}); - - //~ dataTable_clusters.fnClearTable(); - //~ addElement([ - //~ spinner, - //~ '',''],dataTable_clusters); - OpenNebula.Cluster.list({success: updateClustersView,error: onError}); - - dataTable_vNetworks.fnClearTable(); - addElement([ - spinner, - '','','','','','',''],dataTable_vNetworks); - OpenNebula.Network.list({success: updateVNetworksView, error: onError}); - - dataTable_vMachines.fnClearTable(); - addElement([ - spinner, - '','','','','','','',''],dataTable_vMachines); - OpenNebula.VM.list({success: updateVMachinesView, error: onError}); - - if (uid == 0){ - dataTable_users.fnClearTable(); - addElement([ - spinner, - '',''],dataTable_users); - OpenNebula.User.list({success: updateUsersView,error: onError}); - } - - dataTable_images.fnClearTable(); - addElement([ - spinner, - '','','','','','','','',''],dataTable_images); - OpenNebula.Image.list({success: updateImagesView, error: onError}); -} - - - -function setupImageAttributesDialogs(){ - $('div#dialogs').append('
    '); - - $('#image_attributes_dialog').html( - '
    \ -
    \ -
    \ -
    \ -
    \ - \ - \ - \ -
    \ -
    \ - \ - \ -
    \ -
    \ - \ - \ -
    \ -
    \ - '); - - $('#image_attributes_dialog').dialog({ - autoOpen:false, - width:400, - modal:true, - height:200, - resizable:false, - }); - - $('.image_attribute_button').click(function(){ - action = $(this).val(); - desc = ""; - switch (action){ - case "OpenNebula.Image.addattr": - case "OpenNebula.Image.update": - $('#img_attr_value').show(); - $('#img_attr_value').prev().show(); - desc = "Please write the name and value of the attribute. It will be added or updated in all selected images:"; - $('#img_attr_action').val("OpenNebula.Image.addattr"); - break; - case "OpenNebula.Image.rmattr": - $('#img_attr_value').hide(); - $('#img_attr_value').prev().hide(); - desc = "Please type the attribute you want to remove:"; - $('#img_attr_action').val("OpenNebula.Image.rmattr"); - break; - } - - $('#img_attr_action_desc').html(desc); - $('#image_attributes_dialog').dialog('open'); - return false; - }); - - $('#img_attr_name').keyup(function(){ - $(this).val($(this).val().toUpperCase()); - }); - - $('#image_attributes_dialog #img_attr_proceed').click(function(){ - action = $('#img_attr_action').val(); - nodes = $('input:checked',dataTable_images.fnGetNodes()); - name = $('#img_attr_name').val(); - value = $('#img_attr_value').val(); - switch (action) { - case "OpenNebula.Image.addattr": - case "OpenNebula.Image.update": - $.each(nodes,function(){ - OpenNebula.Image.addattr({data: { - id: $(this).val() - , name: name - , value: value - } - , success: 0 - , error: onError - }); - }); - break; - case "OpenNebula.Image.rmattr": - $.each(nodes,function(){ - OpenNebula.Image.rmattr({data: { - id: $(this).val() - , name: name - , value: value - } - , success: 0 - , error: onError - }); - }); - break; - } - $('#image_attributes_dialog').dialog('close'); - return false; - }); - - $('#image_attributes_dialog #img_attr_cancel').click(function(){ - $('#image_attributes_dialog').dialog('close'); - return false; - }); - -} - -//Sets refresh intevals for the tables. -function setupAutoRefresh(){ - interval=120000; //2 minutes - //hosts - setInterval(function(){ - nodes = $('input:checked',dataTable_hosts.fnGetNodes()); - filter = $("#datatable_hosts_filter input").attr("value"); - if (!nodes.length && !filter.length){ - OpenNebula.Host.list({timeout: true, success: updateHostsView,error: onError}); - } - },interval); - - - //clusters - //~ setInterval(function(){ - //~ nodes = $('input:checked',dataTable_clusters.fnGetNodes()); - //~ if (!nodes.length){ - //~ OpenNebula.Cluster.list(updateClustersView,onError); - //~ } - //~ },interval+4000); //so that not all refreshing is done at the same time - - //clusters - setInterval(function(){ - OpenNebula.Cluster.list({timeout: true, success: updateClustersView,error: onError}); - },interval+4000); //so that not all refreshing is done at the same time - - - //Networks - setInterval(function(){ - nodes = $('input:checked',dataTable_vNetworks.fnGetNodes()); - filter = $("#datatable_vnetworks_filter input").attr("value"); - if (!nodes.length && !filter.length){ - OpenNebula.Network.list({timeout: true, success: updateVNetworksView, error: onError}); - } - },interval+8000); //so that not all refreshing is done at the same time - - //VMs - setInterval(function(){ - nodes = $('input:checked',dataTable_vMachines.fnGetNodes()); - filter = $("#datatable_vmachines_filter input").attr("value"); - if (!nodes.length && !filter.length){ - OpenNebula.VM.list({timeout: true, success: updateVMachinesView,error: onError}); - } - },interval+12000); //so that not all refreshing is done at the same time - - - //Users - //do not update if user is not oneadmin - if (uid == 0) { - setInterval(function(){ - nodes = $('input:checked',dataTable_users.fnGetNodes()); - filter = $("#datatable_users_filter input").attr("value"); - if (!nodes.length && !filter.length){ - OpenNebula.User.list({timeout: true, success: updateUsersView, error: onError}); - } - },interval+14000); //so that not all refreshing is done at the same time - } - - //Images - setInterval(function(){ - nodes = $('input:checked',dataTable_images.fnGetNodes()); - filter = $("#datatable_images_filter input").attr("value"); - if (!nodes.length && !filter.length){ - OpenNebula.Image.list({timeout: true, success: updateImagesView, error: onError}); - } - },interval+16000); -} - -/*###################################################################### - * CREATE DIALOGS - * ###################################################################*/ - - /*## HOSTS ## */ - -function createHostDialog(){ - - //We put the template in place - $('#create_host_dialog').html(create_host_tmpl); - - //Enable the jquery dialog but we keep it hidden - $create_host_dialog = $('#create_host_dialog').dialog({ - autoOpen: false, - modal: true, - width: 500 - }); - - //$('#create_host_dialog div.radioset').buttonset(); - //not working properly: sometimes selected option comes as undefined - //$('#create_host_button').button(); - - //Listen to the + New Host button and open dialog when clicked - $('.create_host_button').click(function(){ - $create_host_dialog.dialog('open'); - return false; - }); - - //Handle the form submission - $('#create_host_form').submit(function(){ - if (!($('#name',this).val().length)){ - notifyError("Host name missing!"); - return false; - } - host_json = { "host": { "name": $('#name',this).val(), - "tm_mad": $('#tm_mad :selected',this).val(), - "vm_mad": $('#vmm_mad :selected',this).val(), - "im_mad": $('#im_mad :selected',this).val()}} - - //Create the OpenNebula.Host. - //If it's successfull we refresh the list. - OpenNebula.Host.create({data: host_json, success: addHostElement, error: onError}); - $create_host_dialog.dialog('close'); - return false; - }); -} - - /*## CLUSTERS ## */ - -function createClusterDialog(){ - //Insert HTML in place - $('#create_cluster_dialog').html(create_cluster_tmpl); - - //Prepare the JQUERY dialog. Set style options here. - $create_cluster_dialog = $('#create_cluster_dialog').dialog({ - autoOpen: false, - modal: true, - width: 400 - }); - - //$('#create_cluster_button').button(); - - //Listen to a click on the + New Cluster button - $('.create_cluster_button').click(function(){ - $create_cluster_dialog.dialog('open'); - return false; - }); - - //Handle the submission of the form - $('#create_cluster_form').submit(function(){ - name=$('#name',this).val(); - cluster_json = { "cluster" : { "name" : name }}; - //Create the Cluster. - //If it's successfull we refresh the list. - OpenNebula.Cluster.create({ data:cluster_json, - success: function(){ - OpenNebula.Cluster.list({success:updateClustersView,error:onError})}, - error: onError}); - $create_cluster_dialog.dialog('close'); - return false; - }); -} - - /*## VNETS ## */ - -function createVNetworkDialog(){ - - //Insert dialog HTML in place - $('#create_vn_dialog').html(create_vn_tmpl); - - //Prepare the jquery-ui dialog. Set style options here. - $create_vn_dialog = $('#create_vn_dialog').dialog({ - autoOpen: false, - modal: true, - width: 475, - height: 500 - }); - - //Make the tabs look nice for the creation mode - $('#vn_tabs').tabs(); - $('div#ranged').hide(); - $('#fixed_check').click(function(){ - $('div#fixed').show(); - $('div#ranged').hide(); - }); - $('#ranged_check').click(function(){ - $('div#fixed').hide(); - $('div#ranged').show(); - }); - //$('#create_vn_button').button(); - - //We listen to the + New Vnet button and open the dialog when clicked - $('.create_vn_button').click(function(){ - $create_vn_dialog.dialog('open'); - return false; - }); - - //When we hit the add lease button... - $('#add_lease').click(function(){ - create_form = $('#create_vn_form_easy'); //this is our scope - - //Fetch the interesting values - lease_ip = $('#leaseip',create_form).val(); - lease_mac = $('#leasemac',create_form).val(); - - //We don't add anything to the list if there is nothing to add - if (lease_ip == null) { - notifyError("Please provide a lease IP"); - return false; - }; - - - lease = ""; //contains the HTML to be included in the select box - if (lease_mac == "") { - lease=''; - } else { - lease=''; - }; - - //We append the HTML into the select box. - $('select#leases').append(lease); - return false; - }); - - $('#remove_lease').click(function(){ - $('select#leases :selected').remove(); - return false; - }); - - //Handle submission of the easy mode - $('#create_vn_form_easy').submit(function(){ - //Fetch values - name = $('#name',this).val(); - if (!name.length){ - notifyError("Virtual Network name missing!"); - return false; - } - bridge = $('#bridge',this).val(); - type = $('input:checked',this).val(); - - //TBD: Name and bridge provided?! - - network_json = null; - if (type == "fixed") { - leases = $('#leases option', this); - leases_obj=[]; - - //for each specified lease we prepare the JSON object - $.each(leases,function(){ - leases_obj.push({"ip": $(this).val() }); - }); - - //and construct the final data for the request - network_json = { - "vnet" : { - "type" : "FIXED", - "leases" : leases_obj, - "bridge" : bridge, - "name" : name }}; - } - else { //type ranged - - network_addr = $('#net_address',this).val(); - network_size = $('#net_size',this).val(); - if (!network_addr.length){ - notifyError("Please provide a network address"); - return false; - }; - - //we form the object for the request - network_json = { - "vnet" : { - "type" : "RANGED", - "bridge" : bridge, - "network_size" : network_size, - "network_address" : network_addr, - "name" : name } - }; - }; - - //Create the VNetwork. - //If it's successfull we refresh the list. - OpenNebula.Network.create({ - data: network_json, - success: addVNetworkElement, - error: onError}); - $create_vn_dialog.dialog('close'); - return false; - }); - - $('#create_vn_form_manual').submit(function(){ - template=$('#template',this).val(); - vnet_json = {vnet: {vnet_raw: template}}; - OpenNebula.Network.create({data: vnet_json, success: addVNetworkElement,error: onError}); - $create_vn_dialog.dialog('close'); - return false; - }); - -} - - /*## VMACHINES ## */ - -function createVMachineDialog(){ - - /* #### createVMachineDialog() helper functions #### */ - - vmTabChange = function(event,ui){ - // ui.tab // anchor element of the selected (clicked) tab - // ui.panel // element, that contains the selected/clicked tab contents - // ui.index // zero-based index of the selected (clicked) tab - switch(ui.index){ - case 0: - enable_kvm(); - break; - case 1: - enable_xen(); - break; - case 2: - break; - case 3: - break; - } - } - - update_dynamic_css = function(){ - //This function used to be useful to add specific - //css to elements that changed. - //Now its not needed anymore apparently - /* - if (templ_type=="kvm"){ - $(xen_man_items).css({"font-weight":"normal"}); - $(kvm_man_items).css({"background":"green","font-weight":"bold"}); - $(kvm_opt_items).css({"background":"yellow"}); - } else if (templ_type=="xen"){ - $(kvm_man_items).css({"font-weight":"normal"}); - $(xen_man_items).css({"background":"green","font-weight":"bold"}); - $(xen_opt_items).css({"background":"yellow"}); - };*/ - }; - - enable_kvm = function(){ - man_class="kvm"; - opt_class="kvm_opt"; - $(xen_items).attr("disabled","disabled"); - $(xen_items).css("background",""); - $(kvm_items).removeAttr("disabled"); - //$(items+':disabled').hide(); - - - //particularities - $('div#disks select#TYPE option:selected').removeAttr("selected"); - $('div#disks select#TYPE').prepend( - ''); - $('div#disks select#TYPE option#no_type').attr("selected","selected"); - - $('select#boot_method option').removeAttr("selected"); - $('select#boot_method option#no_boot').html("Driver default"); - $('select#boot_method option').removeAttr("selected"); - $('.kernel, .bootloader', $('div#os_boot_opts')).hide(); - - $('div#disks select#BUS').append( - ''); - - $('input#TYPE', section_raw).val("kvm"); - - $(section_inputs).show(); - - update_dynamic_css(); - }; - - enable_xen = function(){ - man_class="xen"; - opt_class="xen_opt"; - $(kvm_items).attr("disabled","disabled"); - $(kvm_items).css("background",""); - $(xen_items).removeAttr("disabled"); - //$(items+':disabled').hide(); - - - //particularities - $('div#disks select#TYPE option#no_type').remove(); - - $('select#boot_method option:selected').removeAttr("selected"); - $('select#boot_method option#no_boot').html("Please choose"); - $('.kernel, .bootloader', $('div#os_boot_opts')).hide(); - - $('div#disks select#BUS option#virtio').remove(); - - $('input#TYPE', section_raw).val("kvm"); - $(section_inputs).hide(); //not present for xen - update_dynamic_css(); - }; - - mandatory_filter = function(context){ - man_items = ""; - if (templ_type == "kvm") - { man_items = ".kvm"; } - else if (templ_type == "xen") - { man_items = ".xen"; } - else {return false;}; - - //find enabled mandatory items in this context - man_items = $(man_items+' input:visible',context); - r = true; - $.each(man_items,function(){ - if ($(this).parents(".vm_param").attr("disabled") || - !($(this).val().length)) { - r = false; - return false; - }; - }); - return r; - - }; - - box_add_element = function(context,box_tag,filter){ - value=""; - params= $('.vm_param',context); - inputs= $('input:enabled',params); - selects = $('select:enabled',params); - fields = $.merge(inputs,selects); - - //are fields correctly set? - result = filter(); - if (!result) { - notifyError("There are mandatory parameters missing in this section"); - return false; - } - - value={}; - $.each(fields,function(){ - if (!($(this).parents(".vm_param").attr("disabled")) && - $(this).val().length){ - id = $(this).attr('id').length ? $(this).attr('id') : $(this).parent().attr('id'); - value[id] = $(this).val(); - } - }); - string = JSON.stringify(value); - option= ''; - $('select'+box_tag,context).append(option); - return false; - }; - - box_remove_element = function(section_tag,box_tag){ - context = $(section_tag); - $('select'+box_tag+' :selected',context).remove(); - return false; - }; - - addSectionJSON = function(template_json,context){ - params= $('.vm_param',context); - inputs= $('input:enabled',params); - selects = $('select:enabled',params); - fields = $.merge(inputs,selects); - - fields.each(function(){ - if (!($(this).parents(".vm_param").attr("disabled"))){ //if ! disabled - if ($(this).val().length){ //if has a length - template_json[$(this).attr('id')]=$(this).val(); - } - } - }); - } - - addBoxJSON = function(array,context,box_tag){ - $('select'+box_tag+' option',context).each(function(){ - array.push( JSON.parse($(this).val()) ); - }); - } - - removeEmptyObjects = function(obj){ - for (elem in obj){ - remove = false; - value = obj[elem]; - if (value instanceof Array) - { - if (value.length == 0) - remove = true; - } - else if (value instanceof Object) - { - var obj_length = 0; - for (e in value) - obj_length += 1; - if (obj_length == 0) - remove = true; - } - else - { - value = String(value); - if (value.length == 0) - remove = true; - } - if (remove) - delete obj[elem]; - } - return obj; - } - - iconToggle = function(){ - $('.icon_right').toggle( - function(e){ - $('span',e.currentTarget).removeClass("ui-icon-plusthick"); - $('span',e.currentTarget).addClass("ui-icon-minusthick"); - },function(e){ - $('span',e.currentTarget).removeClass("ui-icon-minusthick"); - $('span',e.currentTarget).addClass("ui-icon-plusthick"); - }); - } - - capacity_setup = function(){ - - //$('fieldset',section_capacity).hide(); - - //~ $('#add_capacity',section_capacity).click(function(){ - //~ $('fieldset',section_capacity).toggle(); - //~ return false; - //~ }); - - } - - os_boot_setup = function(){ - $('fieldset',section_os_boot).hide(); - $('.bootloader, .kernel',section_os_boot).hide(); - - $('#add_os_boot_opts',section_os_boot).click(function(){ - $('fieldset',section_os_boot).toggle(); - return false; - }); - - - //Chrome workaround - $('#boot_method').change(function(){ - $(this).trigger("click"); - }); - - $('#boot_method',section_os_boot).click(function(){ - select = $(this).val(); - switch (select) - { - case "kernel": - $('.bootloader',section_os_boot).hide(); - $('.bootloader',section_os_boot).attr("disabled","disabled"); - $('.kernel',section_os_boot).show(); - $('.kernel',section_os_boot).removeAttr("disabled"); - break; - case "bootloader": - $('.kernel',section_os_boot).hide(); - $('.kernel',section_os_boot).attr("disabled","disabled"); - $('.bootloader',section_os_boot).show(); - $('.bootloader',section_os_boot).removeAttr("disabled"); - break; - default: - $('.kernel, .bootloader',section_os_boot).hide(); - $('.kernel, .bootloader',section_os_boot).attr("disabled","disabled"); - $('.kernel input, .bootloader input',section_os_boot).val(""); - }; - }); - }; - - disks_setup = function(){ - - $('fieldset',section_disks).hide(); - $('.vm_param', section_disks).hide(); - //$('#image_vs_disk',section_disks).show(); - - $('#add_disks', section_disks).click(function(){ - $('fieldset',section_disks).toggle(); - return false; - }); - - $('#image_vs_disk input',section_disks).click(function(){ - //$('fieldset',section_disks).show(); - $('.vm_param', section_disks).show(); - select = $('#image_vs_disk :checked',section_disks).val(); - switch (select) - { - case "disk": - $('.add_image',section_disks).hide(); - $('.add_image',section_disks).attr("disabled","disabled"); - $('.add_disk',section_disks).show(); - $('.add_disk',section_disks).removeAttr("disabled"); - $('#TARGET',section_disks).parent().removeClass(opt_class); - $('#TARGET',section_disks).parent().addClass(man_class); - break; - case "image": - $('.add_disk',section_disks).hide(); - $('.add_disk',section_disks).attr("disabled","disabled"); - $('.add_image',section_disks).show(); - $('.add_image',section_disks).removeAttr("disabled"); - $('#TARGET',section_disks).parent().removeClass(man_class); - $('#TARGET',section_disks).parent().addClass(opt_class); - break; - } - $('#SIZE',section_disks).parent().hide(); - $('#SIZE',section_disks).parent().attr("disabled","disabled"); - $('#FORMAT',section_disks).parent().hide(); - $('#SIZE',section_disks).parent().attr("disabled","disabled"); - $('#TYPE :selected',section_disks).removeAttr("selected"); - - update_dynamic_css(); - }); - - - - //activate correct mandatory attributes when - //selecting disk type - - //Chrome workaround - $('select#TYPE',section_disks).change(function(){ - $(this).trigger('click'); - }); - - $('select#TYPE',section_disks).click(function(){ - select = $(this).val(); - switch (select) { - //size,format,target - case "swap": - //size mandatory - $('#SIZE',section_disks).parent().show(); - $('#SIZE',section_disks).parent().removeAttr("disabled"); - $('#SIZE',section_disks).parent().removeClass(opt_class); - $('#SIZE',section_disks).parent().addClass(man_class); - - //target optional - $('#TARGET',section_disks).parent().removeClass(man_class); - $('#TARGET',section_disks).parent().addClass(opt_class); - - //format hidden - $('#FORMAT',section_disks).parent().hide(); - $('#FORMAT',section_disks).parent().attr("disabled","disabled"); - break; - case "fs": - //size mandatory - $('#SIZE',section_disks).parent().show(); - $('#SIZE',section_disks).parent().removeAttr("disabled"); - $('#SIZE',section_disks).parent().removeClass(opt_class); - $('#SIZE',section_disks).parent().addClass(man_class); - - //target mandatory - $('#TARGET',section_disks).parent().removeClass(opt_class); - $('#TARGET',section_disks).parent().addClass(man_class); - - //format mandatory - $('#FORMAT',section_disks).parent().show(); - $('#FORMAT',section_disks).parent().removeAttr("disabled"); - $('#FORMAT',section_disks).parent().removeClass(opt_class); - $('#FORMAT',section_disks).parent().addClass(man_class); - - break; - case "block": - //size shown and optional - $('#SIZE',section_disks).parent().show(); - $('#SIZE',section_disks).parent().removeAttr("disabled"); - $('#SIZE',section_disks).parent().removeClass(man_class); - $('#SIZE',section_disks).parent().addClass(opt_class); - - //target mandatory - $('#TARGET',section_disks).parent().removeClass(opt_class); - $('#TARGET',section_disks).parent().addClass(man_class); - - //format hidden - $('#FORMAT',section_disks).parent().hide(); - $('#FORMAT',section_disks).parent().attr("disabled","disabled"); - break; - case "floppy": - case "disk": - case "cdrom": - //size hidden - $('#SIZE',section_disks).parent().hide(); - $('#SIZE',section_disks).parent().attr("disabled","disabled"); - - //target mandatory - $('#TARGET',section_disks).parent().removeClass(opt_class); - $('#TARGET',section_disks).parent().addClass(man_class); - - //format optional - $('#FORMAT',section_disks).parent().hide(); - $('#FORMAT',section_disks).parent().attr("disabled","disabled"); - - } - update_dynamic_css(); - }); - - diskFilter = function(){ - return mandatory_filter(section_disks); - }; - - $('#add_disk_button',section_disks).click(function(){ - box_add_element(section_disks,'#disks_box',diskFilter); - return false; - }); - $('#remove_disk_button',section_disks).click(function(){ - box_remove_element(section_disks,'#disks_box'); - return false; - }); - }; - - networks_setup = function(){ - - $('.vm_param',section_networks).hide(); - $('fieldset',section_networks).hide(); - - $('#add_networks',section_networks).click(function(){ - $('fieldset',section_networks).toggle(); - return false; - }); - - $('#network_vs_niccfg input',section_networks).click(function(){ - - select = $('#network_vs_niccfg :checked',section_networks).val(); - switch (select) { - case "network": - $('.niccfg',section_networks).hide(); - $('.niccfg',section_networks).attr("disabled","disabled"); - $('.network',section_networks).show(); - $('.network',section_networks).removeAttr("disabled"); - break; - case "niccfg": - $('.network',section_networks).hide(); - $('.network',section_networks).attr("disabled","disabled"); - $('.niccfg',section_networks).show(); - $('.niccfg',section_networks).removeAttr("disabled"); - break; - } - }); - - nicFilter = function(){ - network = $('select#network :selected',section_networks).attr('id'); - ip = $('#IP',section_networks).val(); - mac = $('#MAC',section_networks).val(); - - return (network != "no_network" || ip.length || mac.length); - }; - - $('#add_nic_button',section_networks).click(function(){ - box_add_element(section_networks,'#nics_box',nicFilter); - return false; - }); - $('#remove_nic_button',section_networks).click(function(){ - box_remove_element(section_networks,'#nics_box'); - return false; - }); - - }; - - inputs_setup = function() { - $('fieldset',section_inputs).hide(); - - $('#add_inputs',section_inputs).click(function(){ - $('fieldset',section_inputs).toggle(); - return false; - }); - - $('#add_input_button',section_inputs).click(function(){ - //no filter - box_add_element(section_inputs,'#inputs_box',function(){return true;}); - return false; - }); - $('#remove_input_button',section_inputs).click(function(){ - box_remove_element(section_inputs,'#inputs_box'); - return false; - }); - }; - - graphics_setup = function(){ - $('fieldset',section_graphics).hide(); - $('.vm_param',section_graphics).hide(); - $('select#TYPE',section_graphics).parent().show(); - - $('#add_graphics',section_graphics).click(function(){ - $('fieldset',section_graphics).toggle(); - return false; - }); - - //Chrome workaround - $('select#TYPE',section_graphics).change(function(){ - $(this).trigger("click"); - }); - $('select#TYPE',section_graphics).click(function(){ - g_type = $(this).val(); - switch (g_type) { - case "vnc": - $('#LISTEN',section_graphics).parent().show(); - $('#PORT',section_graphics).parent().show(); - $('#PASSWD',section_graphics).parent().show(); - $('#KEYMAP',section_graphics).parent().show(); - $('#PORT',section_graphics).parent().removeAttr("disabled"); - $('#PASSWD',section_graphics).parent().removeAttr("disabled"); - $('#KEYMAP',section_graphics).parent().removeAttr("disabled"); - break; - case "sdl": - $('#LISTEN',section_graphics).parent().show(); - $('#PORT',section_graphics).parent().hide(); - $('#PASSWD',section_graphics).parent().hide(); - $('#KEYMAP',section_graphics).parent().hide(); - $('#PORT',section_graphics).parent().attr("disabled","disabled"); - $('#PASSWD',section_graphics).parent().attr("disabled","disabled"); - $('#KEYMAP',section_graphics).parent().attr("disabled","disabled"); - break; - default: - $('#LISTEN',section_graphics).parent().hide(); - $('#PORT',section_graphics).parent().hide(); - $('#PASSWD',section_graphics).parent().hide(); - $('#KEYMAP',section_graphics).parent().hide(); - - } - }); - - } - - context_setup = function(){ - $('fieldset',section_context).hide(); - - $('#add_context',section_context).click(function(){ - $('fieldset',section_context).toggle(); - return false; - }); - - }; - - placement_setup = function(){ - $('fieldset',section_placement).hide(); - - $('#add_placement',section_placement).click(function(){ - $('fieldset',section_placement).toggle(); - return false; - }); - - }; - - raw_setup = function(){ - $('fieldset',section_raw).hide(); - - $('#add_raw',section_raw).click(function(){ - $('fieldset',section_raw).toggle(); - return false; - }); - }; - - /* #### createVMachineDialog() main body #### */ - - //Insert HTML in place - $('#create_vm_dialog').html(create_vm_tmpl); - $('#vm_create_tabs').tabs({ - select:vmTabChange - }); - - //Prepare jquery dialog - var height = Math.floor($(window).height()*0.8); //set height to a percentage of the window - $create_vm_dialog = $('#create_vm_dialog').dialog({ - autoOpen: false, - modal: true, - width: 700, - height: height - }); - - //Listen to the + New VM button and open dialog - $('.create_vm_button').click(function(){ - $create_vm_dialog.dialog('open'); - return false; - }); - - iconToggle(); //toogle +/- buttons - - //Sections, used to stay within their scope - section_capacity = $('#capacity'); - section_os_boot = $('#os_boot_opts'); - section_disks = $('#disks'); - section_networks = $('#networks'); - section_inputs = $('#inputs'); - section_graphics = $('#graphics'); - section_context = $('#context'); - section_placement = $('#placement'); - section_raw = $('#raw'); - - //Different selector for items of kvm and xen (mandatory and optional) - items = '.vm_section input,.vm_section select'; - kvm_man_items = '.kvm input,.kvm select'; - kvm_opt_items = '.kvm_opt input, .kvm_opt select'; - kvm_items = kvm_man_items +','+kvm_opt_items; - xen_man_items = '.xen input,.xen select'; - xen_opt_items = '.xen_opt input, .xen_opt select'; - xen_items = xen_man_items +','+ xen_opt_items; - - //Starting template type, optional items class and mandatory items class - templ_type = "kvm"; - opt_class=".kvm_opt"; - man_class=".kvm"; - - $('#template_type #kvm').attr("checked","checked"); //check KVM - enable_kvm(); //enable all kvm options - - //handle change between templates. - $("#template_type input").click(function(){ - templ_type = $("#template_type :checked").val(); - switch (templ_type) - { - case "kvm": - enable_kvm(); - break; - case "xen": - enable_xen(); - break; - } - }); - - $('#fold_unfold_vm_params').toggle( - function(){ - $('.vm_section fieldset').show(); - return false; - }, - function(){ - $('.vm_section fieldset').hide(); - $('.vm_section fieldset').first().show(); - return false; - }); - - capacity_setup(); - os_boot_setup(); - disks_setup(); - networks_setup(); - inputs_setup(); - graphics_setup(); - context_setup(); - placement_setup(); - raw_setup(); - - $('button#create_vm_form_easy').click(function(){ - //validate form - - vm_json = {}; - - //process capacity options - scope = section_capacity; - - if (!mandatory_filter(scope)){ - notifyError("There are mandatory fields missing in the capacity section"); - return false; - }; - addSectionJSON(vm_json,scope); - - //process os_boot_opts - scope= section_os_boot; - switch (templ_type){ - case "xen": - boot_method = $('#boot_method option:selected',scope).val(); - if (!boot_method.length){ - notifyError("Xen templates must specify a boot method"); - return false;} - }; - - if (!mandatory_filter(scope)){ - notifyError("There are mandatory fields missing in the OS Boot options section"); - return false; - }; - vm_json["OS"] = {}; - addSectionJSON(vm_json["OS"],scope); - - //process disks - scope = section_disks; - vm_json["DISK"] = []; - addBoxJSON(vm_json["DISK"],scope,'#disks_box'); - - //process nics -> fetch from box - scope = section_networks; - vm_json["NIC"] = []; - addBoxJSON(vm_json["NIC"],scope,'#nics_box'); - - //process inputs -> fetch from box - scope = section_inputs; - vm_json["INPUT"] = []; - addBoxJSON(vm_json["INPUT"],scope,'#inputs_box'); - - //process graphics -> fetch fields with value - scope = section_graphics; - vm_json["GRAPHICS"] = {}; - addSectionJSON(vm_json["GRAPHICS"],scope); - - //context -> include - scope = section_context; - var context = $('#CONTEXT',scope).val(); - if (context) - vm_json["CONTEXT"] = context; - - //placement -> fetch with value - scope = section_placement; - addSectionJSON(vm_json,scope); - - //raw -> if value set type to driver and fetch - scope = section_raw; - vm_json["RAW"] = {}; - addSectionJSON(vm_json["RAW"],scope); - - // remove empty elements - vm_json = removeEmptyObjects(vm_json); - - //wrap it in the "vm" object - vm_json = {vm: vm_json} - OpenNebula.VM.create({data: vm_json, - success: addVMachineElement, - error: onError}); - - $create_vm_dialog.dialog('close'); - return false; - }); - - $('button#create_vm_form_manual').click(function(){ - template = $('#textarea_vm_template').val(); - - //wrap it in the "vm" object - template = {"vm": {"vm_raw": template}}; - - OpenNebula.VM.create({data: template, - success: addVMachineElement, - error: onError}); - $create_vm_dialog.dialog('close'); - return false; - }); - - $('button#reset').click(function(){ - $('select#disks_box option',section_disks).remove(); - $('select#nics_box option',section_networks).remove(); - $('select#inputs_box option',section_inputs).remove(); - return true; - }); - - } - - /*## USERS ## */ - -function createUserDialog(){ - - //Insert HTML in place - $('#create_user_dialog').html(create_user_tmpl); - - //Prepare jquery dialog - $create_user_dialog = $('#create_user_dialog').dialog({ - autoOpen: false, - modal:true, - width: 400 - }); - - //$('#create_user_button').button(); - - //Listen to the + New User button and open dialog - $('.create_user_button').click(function(){ - $create_user_dialog.dialog('open'); - return false; - }); - - //Handle form submission - $('#create_user_form').submit(function(){ - user_name=$('#username',this).val(); - user_password=$('#pass',this).val(); - user_json = { "user" : - { "name" : user_name, - "password" : user_password } - }; - OpenNebula.User.create({data: user_json, - success: addUserElement, - error: onError}); - $create_user_dialog.dialog('close'); - return false; - }); -} - -function createImageDialog(){ - //Insert HTML in place - $('#create_image_dialog').html(create_image_tmpl); - - //Prepare jquery dialog - $create_image_dialog = $('#create_image_dialog').dialog({ - autoOpen: false, - modal:true, - width: 520 - }); - - //Listen to the Register image button and open dialog - $('.create_image_button').click(function(){ - $create_image_dialog.dialog('open'); - return false; - }); - - //Effects - $('#img_tabs').tabs(); - $('#img_type option').first().attr("selected","selected"); - $('#datablock_img').attr("disabled","disabled"); - - //Chrome workaround - $('select#img_type').change(function(){ - $(this).trigger("click"); - }); - - $('select#img_type').click(function(){ - value = $(this).val(); - switch (value){ - case "DATABLOCK": - $('#datablock_img').removeAttr("disabled"); - break; - default: - $('#datablock_img').attr("disabled","disabled"); - $('#path_img').attr("checked","checked"); - $('#img_source,#img_fstype,#img_size').parent().hide(); - $('#img_path').parent().show(); - } - }); - - $('#img_source,#img_fstype,#img_size').parent().hide(); - $('#path_img').attr("checked","checked"); - $('#img_path').parent().addClass("img_man"); - - $('#img_public').click(function(){ - $('#img_persistent').removeAttr("checked"); - }); - - $('#img_persistent').click(function(){ - $('#img_public').removeAttr("checked"); - }); - - - - $('#src_path_select input').click(function(){ - value = $(this).val(); - switch (value){ - case "path": - $('#img_source,#img_fstype,#img_size').parent().hide(); - $('#img_source,#img_fstype,#img_size').parent().removeClass("img_man"); - $('#img_path').parent().show(); - $('#img_path').parent().addClass("img_man"); - break; - case "source": - $('#img_path,#img_fstype,#img_size').parent().hide(); - $('#img_path,#img_fstype,#img_size').parent().removeClass("img_man"); - $('#img_source').parent().show(); - $('#img_source').parent().addClass("img_man"); - break; - case "datablock": - $('#img_source,#img_path').parent().hide(); - $('#img_source,#img_path').parent().removeClass("img_man"); - $('#img_fstype,#img_size').parent().show(); - $('#img_fstype,#img_size').parent().addClass("img_man"); - break; - } - }); - - - $('#create_image_form_easy').submit(function(){ - exit = false; - $('.img_man',this).each(function(){ - if (!$('input',this).val().length){ - notifyError("There are mandatory missing parameters"); - exit = true; - return false; - } - }); - if (exit) { return false; } - img_json = {}; - - name = $('#img_name').val(); - img_json["NAME"] = name; - - desc = $('#img_desc').val(); - if (desc.length){ - img_json["DESCRIPTION"] = desc; - } - - type = $('#img_type').val(); - img_json["TYPE"]= type; - - img_json["PUBLIC"] = $('#img_public:checked').length ? "YES" : "NO"; - - img_json["PERSISTENT"] = $('#img_persistent:checked').length ? "YES" : "NO"; - - dev_prefix = $('#img_dev_prefix').val(); - if (dev_prefix.length){ - img_json["DEV_PREFIX"] = dev_prefix; - } - - bus = $('#img_bus').val(); - img_json["BUS"] = bus; - - switch ($('#src_path_select input:checked').val()){ - case "path": - path = $('#img_path').val(); - img_json["PATH"] = path; - break; - case "source": - source = $('#img_source').val(); - img_json["SOURCE"] = source; - break; - case "datablock": - size = $('#img_size').val(); - fstype = $('#img_fstype').val(); - img_json["SIZE"] = size; - img_json["FSTYPE"] = fstype; - break; - } - obj = { "image" : img_json }; - OpenNebula.Image.register({data: obj,success: addImageElement,error: onError}); - - $create_image_dialog.dialog('close'); - return false; - }); - - $('#create_image_form_manual').submit(function(){ - template=$('#template',this).val(); - OpenNebula.Image.register({data: template,success: addImageElement,error: onError}); - $create_image_dialog.dialog('close'); - return false; - }); - - -} - -/*###################################################################### - * UTIL FUNCTIONS - * ###################################################################*/ - -//Notifications -function notifySubmit(action, args, extra_param){ - var action_text = action.replace(/OpenNebula\./,'').replace(/\./,' '); - - var msg = "

    Submitted

    "; - msg += action_text + ": " + args; - if (extra_param != null) - msg += " >> " + extra_param; - - $.jGrowl(msg, {theme: "jGrowl-notify-submit"}); -} - -function notifyError(msg){ - msg = "

    Error

    " + msg; - - $.jGrowl(msg, {theme: "jGrowl-notify-error", sticky: true }); -} - -// Returns an HTML string with the json keys and values in the form -// key: value
    -// It recursively explores objects, and flattens their contents in -// the result. -function prettyPrintJSON(template_json){ - str = "" - for (field in template_json) { - if (typeof template_json[field] == 'object'){ - str += prettyPrintJSON(template_json[field]) + '
    '; - } else { - str += ''; - }; - }; - return str; -} - -//Replaces all class"tip" divs with an information icon that -//displays the tip information on mouseover. -function setupTips(){ - $('div.tip').each(function(){ - tip = $(this).html(); - $(this).html(''); - $(this).append(''); - - $(this).append(''); - - - $('span.tipspan',this).html(tip); - $(this).parent().append('
    '); - $('span.tipspan',this).hide(); - $('span.info_icon',this).hover(function(e){ - var top, left; - top = e.pageY - 15;// - $(this).parents('#create_vm_dialog').offset().top - 15; - left = e.pageX + 15;// - $(this).parents('#create_vm_dialog').offset().left; - $(this).next().css( - {"top":top+"px", - "left":left+"px"}); - $(this).next().fadeIn(); - },function(){ - $(this).next().fadeOut(); - }); - }); -} - -//Returns the username of a user providing the uid. -//Crawls the user dataTable for that. If such user is not found, -//we return the uid. -function getUserName(uid){ - user = "uid "+uid; - if (dataTable_users != null){ - nodes = dataTable_users.fnGetData(); - $.each(nodes,function(){ - if (uid == this[1]) { - user = this[2]; - return false; - } - }); - }; - - return user; - -} - -// Returns an string in the form key=value key=value ... -// Does not explore objects in depth. -function stringJSON(json){ - str = "" - for (field in json) { - str+= field + '=' + json[field] + ' '; - } - return str; -} - -// Returns the running time data -function str_start_time(vm){ - return pretty_time(vm.STIME); -} - -// Updates a data_table, with a 2D array containing -// Does a partial redraw, so the filter and pagination are kept -function updateView(item_list,data_table){ - if (data_table!=null) { - data_table.fnClearTable(); - data_table.fnAddData(item_list); - data_table.fnDraw(false); - }; -} - -function updateSingleElement(element,data_table,tag){ - tr = $(tag).parents('tr')[0]; - position = data_table.fnGetPosition(tr); - data_table.fnUpdate(element,position,0); - $('input',data_table).trigger("change"); - -} - -function tableCheckboxesListener(dataTable){ - - context = dataTable.parents('form'); - last_action_b = $('.last_action_button',context); - $('.top_button, .list_button',context).button("disable"); - if (last_action_b.length && last_action_b.val().length){ - last_action_b.button("disable"); - }; - $('.new_button',context).button("enable"); - - //listen to changes - $('input',dataTable).live("change",function(){ - dataTable = $(this).parents('table').dataTable(); - context = dataTable.parents('form'); - last_action_b = $('.last_action_button',context); - nodes = dataTable.fnGetNodes(); - total_length = nodes.length; - checked_length = $('input:checked',nodes).length; - - if (total_length == checked_length){ - $('.check_all',dataTable).attr("checked","checked"); - } else { - $('.check_all',dataTable).removeAttr("checked"); - } - - if (checked_length){ - $('.top_button, .list_button',context).button("enable"); - if (last_action_b.length && last_action_b.val().length){ - last_action_b.button("enable"); - }; - $('.new_button',context).button("enable"); - } else { - $('.top_button, .list_button',context).button("disable"); - last_action_b.button("disable"); - $('.new_button',context).button("enable"); - } - }); - -} - -function deleteElement(data_table,tag){ - tr = $(tag).parents('tr')[0]; - data_table.fnDeleteRow(tr); - $('input',data_table).trigger("change"); -} - -function addElement(element,data_table){ - data_table.fnAddData(element); -} - -function hostElementArray(host_json){ - host = host_json.HOST; - acpu = parseInt(host.HOST_SHARE.MAX_CPU); - if (!acpu) {acpu=100}; - acpu = acpu - parseInt(host.HOST_SHARE.CPU_USAGE); - - total_mem = parseInt(host.HOST_SHARE.MAX_MEM); - free_mem = parseInt(host.HOST_SHARE.FREE_MEM); - - if (total_mem == 0) { - ratio_mem = 0; - } else { - ratio_mem = Math.round(((total_mem - free_mem) / total_mem) * 100); - } - - - total_cpu = parseInt(host.HOST_SHARE.MAX_CPU); - used_cpu = Math.max(total_cpu - parseInt(host.HOST_SHARE.USED_CPU),acpu); - - if (total_cpu == 0) { - ratio_cpu = 0; - } else { - ratio_cpu = Math.round(((total_cpu - used_cpu) / total_cpu) * 100); - } - - pb_mem = -'
    \ -
    \ - '+ratio_mem+'%\ -
    \ -
    '; - - pb_cpu = -'
    \ -
    \ - '+ratio_cpu+'%\ -
    \ -
    '; - - - return [ '', - host.ID, - host.NAME, - host.CLUSTER, - host.HOST_SHARE.RUNNING_VMS, //rvm - pb_cpu, - pb_mem, - OpenNebula.Helper.resource_state("host",host.STATE) ]; - - - //~ return [ '', - //~ host.ID, - //~ host.NAME, - //~ host.CLUSTER, - //~ host.HOST_SHARE.RUNNING_VMS, //rvm - //~ host.HOST_SHARE.MAX_CPU, //tcpu - //~ parseInt(host.HOST_SHARE.MAX_CPU) - parseInt(host.HOST_SHARE.USED_CPU), //fcpu - //~ acpu, - //~ humanize_size(host.HOST_SHARE.MAX_MEM), - //~ humanize_size(host.HOST_SHARE.FREE_MEM), - //~ OpenNebula.Helper.resource_state("host",host.STATE) ]; -} - -//Adds a listener to show the extended info when clicking on a row -function hostInfoListener(){ - $('#tbodyhosts tr').live("click",function(e){ - - //do nothing if we are clicking a checkbox! - if ($(e.target).is('input')) {return true;} - - popDialogLoading(); - aData = dataTable_hosts.fnGetData(this); - id = $(aData[0]).val(); - OpenNebula.Host.show({data:{id:id},success: updateHostInfo,error: onError}); - return false; - }); -} - -//~ function clusterElementArray(cluster_json){ - //~ cluster = cluster_json.CLUSTER; - //~ return ['', - //~ cluster.ID, - //~ cluster.NAME - //~ ] -//~ } - -function vMachineElementArray(vm_json){ - var vm = vm_json.VM; - var state = OpenNebula.Helper.resource_state("vm",vm.STATE); - if (state == "ACTIVE") { - state = OpenNebula.Helper.resource_state("vm_lcm",vm.LCM_STATE); - } - return [ - '', - vm.ID, - vm.USERNAME ? vm.USERNAME : getUserName(vm.UID), - vm.NAME, - state, - vm.CPU, - humanize_size(vm.MEMORY), - vm.HISTORY ? vm.HISTORY.HOSTNAME : "--", - str_start_time(vm) - ] -} - -//Adds a listener to show the extended info when clicking on a row -function vMachineInfoListener(){ - - $('#tbodyvmachines tr').live("click", function(e){ - if ($(e.target).is('input')) {return true;} - aData = dataTable_vMachines.fnGetData(this); - id = $(aData[0]).val(); - OpenNebula.VM.show({data: {id:id},success: updateVMInfo,error: onError}); - return false; - }); -} - -function vNetworkElementArray(vn_json){ - network = vn_json.VNET; - if (network.TOTAL_LEASES){ - total_leases = network.TOTAL_LEASES; - }else if (network.LEASES && network.LEASES.LEASE){ - total_leases = network.LEASES.LEASE.length ? network.LEASES.LEASE.length : "1"; - } else{ - total_leases = "0"; - } - username = network.USERNAME? network.USERNAME : getUserName(network.UID) - return ['', - network.ID, - username, - network.NAME, - parseInt(network.TYPE) ? "FIXED" : "RANGED", - network.BRIDGE, - parseInt(network.PUBLIC) ? "yes" : "no", - total_leases ]; -} -//Adds a listener to show the extended info when clicking on a row -function vNetworkInfoListener(){ - - $('#tbodyvnetworks tr').live("click", function(e){ - if ($(e.target).is('input')) {return true;} - aData = dataTable_vNetworks.fnGetData(this); - id = $(aData[0]).val(); - OpenNebula.Network.show({data:{id: id},success: updateVNetworkInfo,error: onError}); - return false; - }); -} - -function userElementArray(user_json){ - user = user_json.USER; - if (!user.NAME || user.NAME == {}){ - name = ""; - } else { - name = user.NAME; - } - - return [ - '', - user.ID, - name - ] -} - -function imageElementArray(image_json){ - image = image_json.IMAGE; - return [ - '', - image.ID, - image.USERNAME ? image.USERNAME : getUserName(image.UID), - image.NAME, - OpenNebula.Helper.image_type(image.TYPE), - pretty_time(image.REGTIME), - parseInt(image.PUBLIC) ? "yes" : "no", - parseInt(image.PERSISTENT) ? "yes" : "no", - OpenNebula.Helper.resource_state("image",image.STATE), - image.RUNNING_VMS - ]; -} - -function imageInfoListener(target){ - - $('#tbodyimages tr').live("click",function(e){ - if ($(e.target).is('input')) {return true;} - aData = dataTable_images.fnGetData(this); - id = $(aData[0]).val(); - OpenNebula.Image.show({data: {id: id},success: updateImageInfo,error: onError}); - return false; - }); -} - -function updateHostSelect(host_list){ - - //update select helper - hosts_select=""; - hosts_select += ""; - $.each(host_list, function(){ - hosts_select += ""; - }); - - //update static selectors - $('#vm_host').html(hosts_select); -} - -function updateClusterSelect(cluster_list){ - - //update select helper - clusters_select= ""; - clusters_select+=""; - $.each(cluster_list, function(){ - clusters_select += ""; - }); - - //update static selectors - //$('#host_cluster').html(clusters_select); - -} - -function updateNetworkSelect(network_list){ - //update select helper - vnetworks_select=""; - vnetworks_select += ""; - $.each(network_list, function(){ - vnetworks_select += ""; - - }); - - //update static selectors - $('div.vm_section#networks select#NETWORK').html(vnetworks_select); -} - -function updateImageSelect(image_list){ - images_select=""; - images_select += ""; - $.each(image_list, function(){ - if ((this.IMAGE.STATE < 3) && (this.IMAGE.STATE > 0)){ - images_select += ''; - } - }); - - //update static selectors - $('div.vm_section#disks select#IMAGE').html(images_select); -} - - -// New layout -//~ function tabSelect(event,ui){ - //~ // ui.tab // anchor element of the selected (clicked) tab - //~ // ui.panel // element, that contains the selected/clicked tab contents - //~ // ui.index // zero-based index of the selected (clicked) tab - //~ switch(ui.index) - //~ { - //~ case 0: - //~ emptyDashboard(); - //~ preloadTables(); - //~ break; - //~ case 1: // Hosts - //~ OpenNebula.Host.list(updateHostsView,onError); - //~ break; - //~ case 2: // Clusters - //~ OpenNebula.Cluster.list(updateClustersView,onError); - //~ break; - //~ case 3: //VMs - //~ OpenNebula.VM.list(updateVMachinesView,onError); - //~ break; - //~ case 4: //VNs - //~ OpenNebula.Network.list(updateVNetworksView,onError); - //~ break; - //~ case 5: //Users - //~ OpenNebula.User.list(updateUsersView,onError); - //~ break; - //~ } -//~ } - -//puts the dashboard values into "retrieving" -function emptyDashboard(){ - $("#dashboard .value_td span").html(spinner); -} - -function updateDashboard(what){ - db = $('#dashboard'); - switch (what){ - case "hosts": - total_hosts=host_list_json.length; - active_hosts=0; - $.each(host_list_json,function(){ - if (parseInt(this.HOST.STATE) < 3){ - active_hosts++;} - }); - $('#total_hosts',db).html(total_hosts); - $('#active_hosts',db).html(active_hosts); - break; - case "clusters": - total_clusters=cluster_list_json.length; - $('#total_clusters',db).html(total_clusters); - break; - case "vms": - total_vms=vmachine_list_json.length; - running_vms=0; - failed_vms=0; - $.each(vmachine_list_json,function(){ - vm_state = parseInt(this.VM.STATE); - if (vm_state == 3){ - running_vms++; - } - else if (vm_state == 7) { - failed_vms++; - } - }); - $('#total_vms',db).html(total_vms); - $('#running_vms',db).html(running_vms); - $('#failed_vms',db).html(failed_vms); - break; - case "vnets": - public_vnets=0; - total_vnets=network_list_json.length; - $.each(network_list_json,function(){ - if (parseInt(this.VNET.PUBLIC)){ - public_vnets++;} - }); - $('#total_vnets',db).html(total_vnets); - $('#public_vnets',db).html(public_vnets); - break; - case "users": - total_users=user_list_json.length; - $('#total_users',db).html(total_users); - break; - case "images": - total_images=image_list_json.length; - public_images=0; - $.each(image_list_json,function(){ - if (parseInt(this.IMAGE.PUBLIC)){ - public_images++;} - }); - $('#total_images',db).html(total_images); - $('#public_images',db).html(public_images); - break; - } -} - -/*###################################################################### - * UPDATE VIEWS - CALLBACKS - * ##################################################################*/ -function onError(request,error_json) { - var method; - var action; - var object; - var id; - var reason; - var m; - var message = error_json.error.message; - - //redirect to login if unauthenticated - if (error_json.error.http_status=="401") { - window.location.href = "/login"; - }; - - //Parse known errors: - var action_error = /^\[(\w+)\] Error trying to (\w+) (\w+) \[(\w+)\].*Reason: (.*)\.$/; - var action_error_noid = /^\[(\w+)\] Error trying to (\w+) (\w+) (.*)\.$/; - var get_error = /^\[(\w+)\] Error getting (\w+) \[(\w+)\]\.$/; - var auth_error = /^\[(\w+)\] User \[.\] not authorized to perform (\w+) on (\w+) \[?(\w+)\]?\.?$/; - - if (m = message.match(action_error)) { - method = m[1]; - action = m[2]; - object = m[3]; - id = m[4]; - reason = m[5]; - } else if (m = message.match(action_error_noid)) { - method = m[1]; - action = m[2]; - object = m[3]; - reason = m[4]; - } else if (m = message.match(get_error)) { - method = m[1]; - action = "SHOW"; - object = m[2]; - id = m[3]; - } else if (m = message.match(auth_error)) { - method = m[1]; - action = m[2]; - object = m[3]; - id = m[4]; - } - - if (m) { - var rows; - var i; - var value; - rows = ["method","action","object","id","reason"]; - message = ""; - for (i in rows){ - key = rows[i]; - value = eval(key); - if (value) - message += "
    "; - } - message = "
    '+field+''+template_json[field]+'
    "+key+""+value+"
    " + message + "
    "; - } - - notifyError(message); - return true; -} - -/* All the following functions follow a similar function: - * 'update*View' functions clear and fully repopulate the tables. - * 'update*Element' functions find and update a single element with new - * info. - * 'delete*Element' functions find and remove an element from the list. - * 'add*Element' functions add a new element to the list. - * */ - -function updateHostElement(request, host_json){ - id = host_json.HOST.ID; - element = hostElementArray(host_json); - updateSingleElement(element,dataTable_hosts,'#host_'+id); -} - -function deleteHostElement(req){ - deleteElement(dataTable_hosts,'#host_'+req.request.data); -} - -function addHostElement(request,host_json){ - id = host_json.HOST.ID; - element = hostElementArray(host_json); - addElement(element,dataTable_hosts); -} - -function updateHostsView (request,host_list){ - host_list_json = host_list; - host_list_array = [] - - $.each(host_list,function(){ - //Grab table data from the host_list - host_list_array.push(hostElementArray(this)); - }); - - updateView(host_list_array,dataTable_hosts); - updateHostSelect(host_list); - updateDashboard("hosts"); -} - - -//~ function updateClusterElement(request, cluster_json){ - //~ id = cluster_json.CLUSTER.ID; - //~ element = clusterElementArray(cluster_json); - //~ updateSingleElement(element,dataTable_clusters,'#cluster_'+id) -//~ } -//~ -//~ function deleteClusterElement(req){ - //~ deleteElement(dataTable_clusters,'#cluster_'+req.request.data); -//~ } -//~ -//~ function addClusterElement(request,cluster_json){ - //~ element = clusterElementArray(cluster_json); - //~ addElement(element,dataTable_clusters); -//~ } - -function updateClustersView(request, cluster_list){ - cluster_list_json = cluster_list; - //~ cluster_list_array = []; - - //~ $.each(cluster_list, function(){ - //~ cluster_list_array.push(clusterElementArray(this)); - //~ }); - //~ updateView(cluster_list_array,dataTable_clusters); - updateClusterSelect(cluster_list); - updateDashboard("clusters"); -} - - -function updateVMachineElement(request, vm_json){ - id = vm_json.VM.ID; - element = vMachineElementArray(vm_json); - updateSingleElement(element,dataTable_vMachines,'#vm_'+id) -} - -function deleteVMachineElement(req){ - deleteElement(dataTable_vMachines,'#vm_'+req.request.data); -} - -function addVMachineElement(request,vm_json){ - id = vm_json.VM.ID; - notifySubmit('OpenNebula.VM.create',id); - element = vMachineElementArray(vm_json); - addElement(element,dataTable_vMachines); - updateVMInfo(null,vm_json); -} - -function updateVMachinesView(request, vmachine_list){ - vmachine_list_json = vmachine_list; - vmachine_list_array = []; - - $.each(vmachine_list,function(){ - vmachine_list_array.push( vMachineElementArray(this)); - }); - - updateView(vmachine_list_array,dataTable_vMachines); - updateDashboard("vms"); -} - - -function updateVNetworkElement(request, vn_json){ - id = vn_json.VNET.ID; - element = vNetworkElementArray(vn_json); - updateSingleElement(element,dataTable_vNetworks,'#vnetwork_'+id); -} - -function deleteVNetworkElement(req){ - deleteElement(dataTable_vNetworks,'#vnetwork_'+req.request.data); - //How to delete vNetwork select option here? -} - -function addVNetworkElement(request,vn_json){ - element = vNetworkElementArray(vn_json); - addElement(element,dataTable_vNetworks); - vnetworks_select += ""; - $('div.vm_section#networks select#NETWORK').html(vnetworks_select); -} - -function updateVNetworksView(request, network_list){ - network_list_json = network_list; - network_list_array = []; - - $.each(network_list,function(){ - network_list_array.push(vNetworkElementArray(this)); - }); - - updateView(network_list_array,dataTable_vNetworks); - updateNetworkSelect(network_list); - updateDashboard("vnets"); - -} - -function updateUserElement(request, user_json){ - id = user_json.USER.ID; - element = userElementArray(user_json); - updateSingleElement(element,dataTable_users,'#user_'+id); -} - -function deleteUserElement(req){ - deleteElement(dataTable_users,'#user_'+req.request.data); -} - -function addUserElement(request,user_json){ - element = userElementArray(user_json); - addElement(element,dataTable_users); -} - -function updateUsersView(request,users_list){ - user_list_json = users_list; - user_list_array = []; - - $.each(user_list_json,function(){ - user_list_array.push(userElementArray(this)); - }); - updateView(user_list_array,dataTable_users); - updateDashboard("users"); -} - - -function updateImageElement(request, image_json){ - id = image_json.IMAGE.ID; - element = imageElementArray(image_json); - updateSingleElement(element,dataTable_images,'#image_'+id); - if ((image_json.IMAGE.STATE < 3) && - (image_json.IMAGE.STATE > 0) && - ($('#img_sel_'+id,images_select).length == 0)){ - images_select += ''; - } - else { - tag = 'option#img_sel_'+id; - select = $(''); - $(tag,select).remove(); - images_select = $(select).html(); - } - $('div.vm_section#disks select#IMAGE').html(images_select); -} - -function deleteImageElement(req){ - deleteElement(dataTable_images,'#image_'+req.request.data); - tag = 'option#img_sel_'+req.request.data; - select = $(''); - $(tag,select).remove(); - images_select = $(select).html(); - $('div.vm_section#disks select#IMAGE').html(images_select); -} - -function addImageElement(request, image_json){ - element = imageElementArray(image_json); - addElement(element,dataTable_images); -} - -function updateImagesView(request, images_list){ - image_list_json = images_list; - image_list_array = []; - $.each(image_list_json,function(){ - image_list_array.push(imageElementArray(this)); - }); - - updateView(image_list_array,dataTable_images); - updateImageSelect(images_list); - updateDashboard("images"); - - -} - - -/*###################################################################### - * UPDATE INFO DIALOGS FUNCTIONS - CALLBACKS - * ###################################################################*/ -//All functions in this section are callbacks for the "show" -//action. They receive the element JSON, format it and add it to the -//shown dialog. - - -function updateHostInfo(request,host){ - host_info = host.HOST - rendered_info = -'
    \ - \ -
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Host information - '+host_info.NAME+'
    ID'+host_info.ID+'
    State'+OpenNebula.Helper.resource_state("host",host_info.STATE)+'
    Cluster'+host_info.CLUSTER+'
    IM MAD'+host_info.IM_MAD+'
    VM MAD'+host_info.VM_MAD+'
    TM MAD'+host_info.TM_MAD+'
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Host shares
    Max Mem'+humanize_size(host_info.HOST_SHARE.MAX_MEM)+'
    Used Mem (real)'+humanize_size(host_info.HOST_SHARE.USED_MEM)+'
    Used Mem (allocated)'+humanize_size(host_info.HOST_SHARE.MAX_USAGE)+'
    Used CPU (real)'+host_info.HOST_SHARE.USED_CPU+'
    Used CPU(allocated)'+host_info.HOST_SHARE.CPU_USAGE+'
    Running VMs'+host_info.HOST_SHARE.RUNNING_VMS+'
    \ -
    \ -
    \ - \ - '+ - prettyPrintJSON(host_info.TEMPLATE)+ - '
    Host template
    \ -
    \ -
    '; - popDialog(rendered_info); - $('#host_informations').tabs(); - - $('.host_info_action_button').button(); - //listen to buttons - $('.host_info_action_button').click(function(){ - id = host_info.ID; - action=$(this).val(); - - switch (action){ - case "OpenNebula.Host.delete": - $('#host_info_dialog').dialog("close"); - (eval(action)({data: {id: id}, - success: deleteHostElement, - error: onError})); - break; - case "OpenNebula.Host.enable": - case "OpenNebula.Host.disable": - (eval(action)({ data:{id:id}, - success: function(){ - updateBoth = function(req,res){ - updateHostElement(req,res); - updateHostInfo(req,res); - }; - OpenNebula.Host.show({data:{id: id},success: updateBoth, error: onError}); - - }, - error: onError})); - } - return false; - }); - - -} - -// Used as an event method to the VM info tabs. -function fetch_log(event, ui) { - if (ui.index == 2) //tab - { - var vm_id = $("#vm_log pre").attr('id').substr(10); - OpenNebula.VM.log({ data: {id: vm_id}, - success: function(req, res){ - log_lines = res.split("\n"); - var colored_log = ''; - for (line in log_lines){ - line = log_lines[line]; - if (line.match(/\[E\]/)){ - line = ''+line+'' - } - colored_log += line + "\n"; - } - $("#vm_log pre").html(colored_log); - }, - error: function(request,error_json){ - $("#vm_log pre").html(''); - onError(request,error_json); - } - }); - } -} - -function updateVMInfo(request,vm){ - vm_info = vm.VM; - id = vm_info.ID; - rendered_info = -'
    \ - \ -
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Virtual Machine information - '+vm_info.NAME+'
    ID'+vm_info.ID+'
    Name'+vm_info.NAME+'
    State'+OpenNebula.Helper.resource_state("vm",vm_info.STATE)+'
    LCM State'+OpenNebula.Helper.resource_state("vm_lcm",vm_info.LCM_STATE)+'
    Start time'+pretty_time(vm_info.STIME)+'
    Deploy ID'+(typeof(vm_info.DEPLOY_ID) == "object" ? "-" : vm_info.DEPLOY_ID)+'
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Monitoring information
    Net_TX'+vm_info.NET_TX+'
    Net_RX'+vm_info.NET_RX+'
    Used Memory'+humanize_size(vm_info.MEMORY)+'
    Used CPU'+vm_info.CPU+'
    \ -
    \ -
    \ - \ - '+ - prettyPrintJSON(vm_info.TEMPLATE)+ - '
    VM template
    \ -
    \ -

    Virtual Machine Log - '+vm_info.NAME+'

    \ -
    '+spinner+'
    \ -
    \ -
    '; - - $('#vm_info_error',rendered_info).hide(); - popDialog(rendered_info); - $('#vm_informations').tabs({select: fetch_log}); - - /* Not used - $('#vm_info_simple_action').button(); - - - $('#vm_info_simple_action').click(function(){ - action = $('#vm_info_opt_actions').val(); - if (!action.length) { return false; }; - (eval(action)(id, - function(){OpenNebula.VM.show(id,updateVMInfo,onError)}, - function(request,error_json){ - $('#vm_info_error').html( - 'The request failed with the following error: '+ - error_json.error.message + - '. Resource: '+ request.request.resource + - '. Method: '+ request.request.method + '.'); - $('#vm_info_error').addClass("ui-state-error"); - $('#vm_info_error').show(); - - })); - });*/ -} - -function updateVNetworkInfo(request,vn){ - vn_info = vn.VNET; - rendered_info = -'
    \ - \ -
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Virtual Network '+vn_info.ID+' information
    ID'+vn_info.ID+'
    UID'+vn_info.UID+'
    Public'+(parseInt(vn_info.PUBLIC) ? "yes" : "no" )+'
    '; - if (vn_info.TEMPLATE.TYPE == "FIXED"){ - rendered_info += '\ - \ - \ - '+ - prettyPrintJSON(vn_info.LEASES)+ - '
    Leases information
    '; - } - rendered_info += '
    \ -
    \ - \ - '+ - prettyPrintJSON(vn_info.TEMPLATE)+ - '
    Virtual Network template
    \ -
    \ -
    '; - - popDialog(rendered_info); - $('#vn_informations').tabs(); -} - -function updateImageInfo(request,img){ - img_info = img.IMAGE; - rendered_info = -'
    \ - \ -
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Image "'+img_info.NAME+'" information
    ID'+img_info.ID+'
    Name'+img_info.NAME+'
    Type'+OpenNebula.Helper.image_type(img_info.TYPE)+'
    Register time'+pretty_time(img_info.REGTIME)+'
    Public'+(parseInt(img_info.PUBLIC) ? "yes" : "no")+'
    Persistent'+(parseInt(img_info.PERSISTENT) ? "yes" : "no")+'
    Source'+img_info.SOURCE+'
    State'+OpenNebula.Helper.resource_state("image",img_info.STATE)+'
    \ -
    \ -
    \ - \ - '+ - prettyPrintJSON(img_info.TEMPLATE)+ - '
    Image template
    \ -
    \ -
    '; - popDialog(rendered_info); - $('#image_informations').tabs(); -} - -// Auxiliary functions -function pad(number,length) { - var str = '' + number; - while (str.length < length) - str = '0' + str; - return str; -} - -function pretty_time(time_seconds) -{ - var d = new Date(); - d.setTime(time_seconds*1000); - - var secs = pad(d.getSeconds(),2); - var hour = pad(d.getHours(),2); - var mins = pad(d.getMinutes(),2); - var day = pad(d.getDate(),2); - var month = pad(d.getMonth(),2); - var year = d.getFullYear(); - - return hour + ":" + mins +":" + secs + " " + month + "/" + day + "/" + year; -} - -function humanize_size(value) { - if (typeof(value) === "undefined") { - value = 0; - } - var binarySufix = ["K", "M", "G", "T" ]; - var i=0; - while (value > 1024 && i < 3){ - value = value / 1024; - i++; - } - value = Math.round(value * 10) / 10; - - if (value - Math.round(value) == 0) { - value = Math.round(value); - } - - var st = value + binarySufix[i]; - return st; -} diff --git a/src/sunstone/public/js/one-ui_views.templates.js b/src/sunstone/public/js/one-ui_views.templates.js deleted file mode 100644 index 10f2c09d51..0000000000 --- a/src/sunstone/public/js/one-ui_views.templates.js +++ /dev/null @@ -1,1099 +0,0 @@ -/* -------------------------------------------------------------------------- */ -/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ -/* -------------------------------------------------------------------------- */ - -var dashboard_tmpl = -'\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    \ -
    \ -

    Hosts\ -
    \ - +\ -
    \ -

    \ -
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Total
    Active
    \ -
    \ -
    \ -
    \ -
    \ -

    Clusters\ -
    \ - +\ -
    \ -

    \ -
    \ - \ - \ - \ - \ - \ -
    Total
    \ -
    \ -
    \ -
    \ -
    \ -

    Virtual Machines\ -
    \ - +\ -
    \ -

    \ -
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Total
    Running
    Failed
    \ -
    \ -
    \ -
    \ -
    \ -

    Virtual Networks\ -
    \ - +\ -
    \ -

    \ -
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Total
    Public
    \ -
    \ -
    \ - \ -
    \ -
    \ -

    \ - Images\ -
    \ - +\ -
    \ -

    \ -
    \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    Total
    Public
    \ -
    \ -
    \ -
    \ -
    \ -

    Users\ -
    \ - +\ -
    \ -

    \ -
    \ - \ - \ - \ - \ - \ -
    Total
    \ -
    \ -
    \ -
    '; - - - - - - -var hostlist_tmpl = -'
    \ -
    \ -
    \ - OpenNebula.Host.list\ -
    \ -
    \ - \ -
    \ -
    \ - \ - \ -
    \ -
    \ - \ - \ - \ -
    \ -
    \ - \ -
    \ -
    \ -\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    AllIDNameClusterRunning VMsCPU UseMemory useStatus
    \ -
    '; - -var create_host_tmpl = -'
    \ -
    \ - Host parameters\ - \ -
    \ -

    Drivers

    \ -
    \ -
    \ - \ - \ -
    \ -
    \ - \ - \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    '; - -//~ var clusterlist_tmpl = -//~ '
    \ - //~
    \ - //~
    \ - //~ OpenNebula.Cluster.list\ - //~
    \ - //~
    \ - //~ \ - //~
    \ - //~
    \ - //~ \ - //~
    \ - //~
    \ -//~ \ - //~ \ - //~ \ - //~ \ - //~ \ - //~ \ - //~ \ - //~ \ - //~ \ - //~ \ -//~
    AllIDName
    \ -//~
    '; - -var create_cluster_tmpl = -'
    \ -
    \ -
    \ - \ -
    \ -
    \ -
    \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    '; - -var vmachinelist_tmpl = -'
    \ -
    \ -
    \ - OpenNebula.VM.list\ -
    \ -
    \ - \ -
    \ -
    \ - \ -
    \ -
    \ - \ -
    \ -
    \ - \ -
    \ -
    \ -\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    AllIDUserNameStatusCPUMemoryHostnameStart Time
    \ -
    '; - -var create_vm_tmpl = -'
    \ - \ -
    \ -
    \ -
    \ - \ -

    Fields marked with are mandatory
    \ - Fold / Unfold all sections

    \ -
    \ -\ - \ -
    \ -
    \ -

    Capacity options

    \ -
    \ -
    Capacity\ -
    \ - \ - \ -
    Name that the VM will get for description purposes. If NAME is not supplied a name generated by one will be in the form of one-<VID>.
    \ -
    \ -
    \ - \ - \ -
    Amount of RAM required for the VM, in Megabytes.
    \ -
    \ -
    \ - \ - \ -
    Percentage of CPU divided by 100 required for the Virtual Machine. Half a processor is written 0.5.
    \ -
    \ -
    \ - \ - \ -
    Number of virtual cpus. This value is optional, the default hypervisor behavior is used, usually one virtual CPU.
    \ -
    \ -
    \ -
    \ - \ -
    \ -
    \ -

    Boot/OS options

    \ -
    \ -
    OS and Boot options\ -
    \ - \ - \ -
    CPU architecture to virtualization
    \ -
    \ - \ -
    \ - \ - \ -
    Select boot method
    \ -
    \ -
    \ - \ - \ -
    Path to the OS kernel to boot the image
    \ -
    \ -
    \ - \ - \ -
    Path to the initrd image
    \ -
    \ -
    \ - \ - \ -
    Device to be mounted as root
    \ -
    \ -
    \ - \ - \ -
    Arguments for the booting kernel
    \ -
    \ -
    \ - \ - \ -
    Path to the bootloader executable
    \ -
    \ -
    \ - \ - \ -
    Boot device type
    \ -
    \ -
    \ -
    \ -\ -\ - \ -
    \ -
    \ -

    Add disks/images

    \ -
    \ -
    Disks\ -
    \ - \ - Disk\ - \ - Image\ - \ -
    \ -
    \ -
    \ - \ - \ -
    Name of the image to use
    \ -
    \ -
    \ - \ - \ -
    Type of disk device to emulate: ide, scsi
    \ -
    \ -
    \ - \ - \ -
    Device to map image disk. If set, it will overwrite the default device mapping
    \ -
    \ -
    \ - \ - \ -
    Specific image mapping driver. KVM: raw, qcow2. Xen:tap:aio:, file:. VMware unsupported
    \ -
    \ -
    \ - \ - \ -
    Disk type
    \ -
    \ -
    \ - \ - \ -
    Disk file location path or URL
    \ -
    \ -
    \ - \ - \ - \ -
    Disk file location path or URL. Mandatory for swap, fs and block images
    \ -
    \ -
    \ - \ - \ - \ -
    Filesystem type for the fs images
    \ -
    \ -
    \ - \ - \ -
    Clone this image
    \ -
    \ -
    \ - \ - \ -
    Save this image after shutting down the VM
    \ -
    \ -
    \ - \ - \ -
    Mount image as read-only
    \ -
    \ -
    \ - \ - \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ -\ - \ -
    \ -
    \ -

    Setup Networks

    \ -
    \ -
    Network\ -
    \ - \ - Predefined\ - \ - Manual\ - \ - \ -
    \ -
    \ -
    \ - \ - \ -
    Name of the network to attach this device
    \ -
    \ -
    \ - \ - \ -
    Request an specific IP from the Network
    \ -
    \ -
    \ - \ - \ -
    HW address associated with the network interface
    \ -
    \ -
    \ - \ - \ -
    Name of the bridge the network device is going to be attached to
    \ -
    \ -
    \ - \ - \ -
    Name for the tun device created for the VM
    \ -
    \ -
    \ - \ - \ -
    Name of a shell script to be executed after creating the tun device for the VM
    \ -
    \ -
    \ - \ - \ -
    Hardware that will emulate this network interface. With Xen this is the type attribute of the vif.
    \ -
    \ -
    \ - \ - \ -
    \ - \ - \ -
    \ -
    \ -
    \ -\ -\ - \ -
    \ -
    \ -

    Add inputs

    \ -
    \ -
    Inputs\ -
    \ - \ - \ -
    \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    \ - \ - \ -
    \ - \ - \ -
    \ -
    \ -
    \ -\ -\ - \ -
    \ -
    \ -

    Add Graphics

    \ -
    \ -
    Graphics\ -
    \ - \ - \ -
    \ -
    \ -
    \ - \ - \ -
    IP to listen on
    \ -
    \ -
    \ - \ - \ -
    Port for the VNC server
    \ -
    \ -
    \ - \ - \ -
    Password for the VNC server
    \ -
    \ -
    \ - \ - \ -
    Keyboard configuration locale to use in the VNC display
    \ -
    \ -
    \ -
    \ -\ -\ - \ -
    \ -
    \ -

    Add context

    \ -
    \ -
    Context\ -
    \ - \ - \ - \ -
    \ -
    \ -
    \ -\ -\ - \ -
    \ -
    \ -

    Add placement options

    \ -
    \ -
    Placement\ -
    \ - \ - \ -
    Boolean expression that rules out provisioning hosts from list of machines suitable to run this VM
    \ -
    \ -
    \ - \ - \ -
    This field sets which attribute will be used to sort the suitable hosts for this VM. Basically, it defines which hosts are more suitable than others
    \ -
    \ -
    \ -
    \ -\ -\ - \ -
    \ -
    \ -

    Add Hypervisor raw options

    \ -
    \ -
    Raw\ - \ -
    \ - \ - \ - \ -
    Raw data to be passed directly to the hypervisor
    \ -
    \ -
    \ -
    \ -\ -\ - \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -

    Write the Virtual Machine template here

    \ -
    \ - \ -
    \ -
    \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ -
    '; - - -var vnetworklist_tmpl = -'
    \ -
    \ -
    \ - OpenNebula.Network.list\ -
    \ -
    \ - \ -
    \ -
    \ - \ - \ -
    \ -
    \ - \ -
    \ -
    \ -\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    AllIDUserNameTypeBridgePublic?Total Leases
    \ -
    '; - -var create_vn_tmpl = -'
    \ - \ -
    \ -
    \ -
    \ - \ -
    \ -
    \ -
    \ - \ -
    \ -
    \ -
    \ - \ - Fixed network
    \ - Ranged network
    \ -
    \ -
    \ -
    \ -
    \ -
    \ - \ -
    \ - \ - \ -
    \ - \ - \ - \ -
    \ -
    \ -
    \ -
    \ -
    \ - \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ - \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -

    Write the Virtual Network template here

    \ -
    \ - \ -
    \ -
    \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ -
    '; - -var userlist_tmpl = -'
    \ -
    \ -
    \ - OpenNebula.User.list\ -
    \ -
    \ - \ -
    \ -
    \ - \ -
    \ -
    \ -\ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    AllIDName
    \ -
    '; - -var create_user_tmpl = -'
    \ -
    \ -
    \ - \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    '; - - -var imagelist_tmpl = -'
    \ -
    \ -
    \ - OpenNebula.Image.list\ -
    \ -
    \ - \ -
    \ -
    \ - \ - \ - \ -
    \ -
    \ - \ -
    \ -
    \ - \ -
    \ -
    \ -\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -
    AllIDUserNameTypeRegistration timePublicPersistentState#VMS
    \ -
    '; - -var create_image_tmpl = -'
    \ - \ -
    \ -
    \ -

    Fields marked with are mandatory
    \ -

    \ -
    \ - \ - \ -
    Name that the Image will get. Every image must have a unique name.
    \ -
    \ -
    \ - \ - \ -
    Human readable description of the image for other users.
    \ -
    \ -
    \ -
    \ -
    \ - \ - \ -
    Type of the image, explained in detail in the following section. If omitted, the default value is the one defined in oned.conf (install default is OS).
    \ -
    \ -
    \ - \ - \ -
    Public scope of the image
    \ -
    \ -
    \ - \ - \ -
    Persistence of the image
    \ -
    \ -
    \ - \ - \ -
    Prefix for the emulated device this image will be mounted at. For instance, “hd”, “sd”. If omitted, the default value is the one defined in oned.conf (installation default is “hd”).
    \ -
    \ -
    \ - \ - \ -
    Type of disk device to emulate.
    \ -
    \ -
    \ -
    \ -
    \ - \ - \ -
    \ - \ -
    \ - \ - \ -
    Please choose path if you have a file-based image. Choose source otherwise or create an empty datablock disk.

    \ -
    \ -
    \ - \ - \ -
    Path to the original file that will be copied to the image repository. If not specified for a DATABLOCK type image, an empty image will be created.
    \ -
    \ -
    \ - \ - \ -
    Source to be used in the DISK attribute. Useful for not file-based images.
    \ -
    \ -
    \ - \ - \ -
    Size of the datablock in MB.
    \ -
    \ -
    \ - \ - \ -
    Type of file system to be built. This can be any value understood by mkfs unix command.
    \ -
    \ -
    \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -
    \ -

    Write the image template here

    \ - \ -
    \ -
    \ -
    \ - \ - \ -
    \ -
    \ -
    \ -
    \ -
    '; diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index d47c582ca8..ce40c52746 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -182,8 +182,8 @@ var OpenNebula = { var password = params.data.password; var remember = params.remember; - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"login"); + var resource = OpenNebula.Auth.resource; + var request = OpenNebula.Helper.request(resource,"login"); $.ajax({ url: "/login", @@ -216,8 +216,8 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"logout"); + var resource = OpenNebula.Auth.resource; + var request = OpenNebula.Helper.request(resource,"logout"); $.ajax({ url: "/logout", @@ -248,8 +248,8 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"list"); + var resource = OpenNebula.Config.resource; + var request = OpenNebula.Helper.request(resource,"list"); $.ajax({ url: "/config", @@ -281,8 +281,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var data = params.data; + var resource = OpenNebula.Host.resource; - var request = OpenNebula.Helper.request(this.resource,"create", data); + var request = OpenNebula.Helper.request(resource,"create", data); $.ajax({ url: "/host", @@ -311,9 +312,10 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Host.resource; - var request = OpenNebula.Helper.request(this.resource,"delete", id); + var request = OpenNebula.Helper.request(resource,"delete", id); $.ajax({ url: "/host/" + id, @@ -341,8 +343,8 @@ var OpenNebula = { var callback_error = params.error; var timeout = params.timeout || false; - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"list"); + var resource = OpenNebula.Host.resource; + var request = OpenNebula.Helper.request(resource,"list"); $.ajax({ url: "/host", @@ -374,8 +376,8 @@ var OpenNebula = { var callback_error = params.error; var id = params.data.id; - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"show", id); + var resource = OpenNebula.Host.resource; + var request = OpenNebula.Helper.request(resource,"show", id); $.ajax({ url: "/host/" + id, @@ -403,10 +405,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Host.resource; var method = "enable"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/host/" + id + "/action", @@ -434,10 +437,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Host.resource; var method = "disable"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/host/" + id + "/action", @@ -469,8 +473,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var data = params.data; + var resource = OpenNebula.Network.resource; - var request = OpenNebula.Helper.request(this.resource,"create",data); + var request = OpenNebula.Helper.request(resource,"create",data); $.ajax({ url: "/vnet", @@ -499,8 +504,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Network.resource; - var request = OpenNebula.Helper.request(this.resource,"delete", id); + var request = OpenNebula.Helper.request(resource,"delete", id); $.ajax({ url: "/vnet/" + id, @@ -527,9 +533,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var timeout = params.timeout || false; - - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"list"); + var resource = OpenNebula.Network.resource; + + var request = OpenNebula.Helper.request(resource,"list"); $.ajax({ url: "/vnet", @@ -559,8 +565,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Network.resource; - var request = OpenNebula.Helper.request(this.resource,"show", id); + var request = OpenNebula.Helper.request(resource,"show", id); $.ajax({ url: "/vnet/" + id, @@ -588,10 +595,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Network.resource; var method = "publish"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vnet/" + id + "/action", @@ -619,10 +627,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Network.resource; var method = "unpublish"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vnet/" + id + "/action", @@ -654,8 +663,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var data = params.data; + var resource = OpenNebula.VM.resource; - var request = OpenNebula.Helper.request(this.resource,"create",data); + var request = OpenNebula.Helper.request(resource,"create",data); $.ajax({ url: "/vm", @@ -684,8 +694,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Network.resource; - var request = OpenNebula.Helper.request(this.resource,"delete", id); + var request = OpenNebula.Helper.request(resource,"delete", id); $.ajax({ url: "/vm/" + id, @@ -713,8 +724,8 @@ var OpenNebula = { var callback_error = params.error; var timeout = params.timeout || false; - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"list"); + var resource = OpenNebula.VM.resource; + var request = OpenNebula.Helper.request(resource,"list"); $.ajax({ url: "/vm", @@ -744,8 +755,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.VM.resource; - var request = OpenNebula.Helper.request(this.resource,"log", id); + var request = OpenNebula.Helper.request(resource,"log", id); $.ajax({ url: "/vm/" + id + "/log", @@ -772,8 +784,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.VM.resource; - var request = OpenNebula.Helper.request(this.resource,"show", id); + var request = OpenNebula.Helper.request(resource,"show", id); $.ajax({ url: "/vm/" + id, @@ -801,11 +814,12 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; - var host = params.data.host_id; + var host = params.data.extra_param; + var resource = OpenNebula.VM.resource; var method = "deploy"; var action = OpenNebula.Helper.action(method, {"host_id": host}); - var request = OpenNebula.Helper.request(this.resource,method, [id, host]); + var request = OpenNebula.Helper.request(resource,method, [id, host]); $.ajax({ url: "/vm/" + id + "/action", @@ -833,10 +847,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.VM.resource; var method = "shutdown"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vm/" + id + "/action", @@ -864,11 +879,12 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; - var host = params.data.host_id; + var host = params.data.extra_param; + var resource = OpenNebula.VM.resource; var method = "livemigrate"; var action = OpenNebula.Helper.action(method,{"host_id": host}); - var request = OpenNebula.Helper.request(this.resource,method, [id, host]); + var request = OpenNebula.Helper.request(resource,method, [id, host]); $.ajax({ url: "/vm/" + id + "/action", @@ -896,11 +912,12 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; - var host = params.data.host_id; + var host = params.data.extra_param; + var resource = OpenNebula.VM.resource; var method = "migrate"; var action = OpenNebula.Helper.action(method,{"host_id": host}); - var request = OpenNebula.Helper.request(this.resource,method, [id, host]); + var request = OpenNebula.Helper.request(resource,method, [id, host]); $.ajax({ url: "/vm/" + id + "/action", @@ -928,10 +945,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.VM.resource; var method = "hold"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vm/" + id + "/action", @@ -959,10 +977,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.VM.resource; var method = "release"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vm/" + id + "/action", @@ -990,10 +1009,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.VM.resource; var method = "stop"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vm/" + id + "/action", @@ -1021,10 +1041,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.VM.resource; var method = "cancel"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vm/" + id + "/action", @@ -1052,10 +1073,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; - + var resource = OpenNebula.VM.resource; + var method = "suspend"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vm/" + id + "/action", @@ -1083,10 +1105,11 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.VM.resource; var method = "resume"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vm/" + id + "/action", @@ -1113,20 +1136,21 @@ var OpenNebula = { { var callback = params.success; var callback_error = params.error; - var vm_id = params.data.vm_id; + var id = params.data.vm_id; var disk_id = params.data.disk_id; var image_name = params.data.image_name; var type = params.data.type; var method = "saveas"; var saveas_params = { - "vm_id" : vm_id, "disk_id" : disk_id, "image_name": image_name, "type" : type } + var resource = OpenNebula.VM.resource; + var action = OpenNebula.Helper.action(method,saveas_params) - var request = OpenNebula.Helper.request(this.resource,method, [vm_id, disk_id, image_name, type]); + var request = OpenNebula.Helper.request(resource,method, [id,disk_id, image_name, type]); $.ajax({ url: "/vm/" + id + "/action", @@ -1154,10 +1178,43 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.VM.resource; var method = "restart"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var request = OpenNebula.Helper.request(resource,method, id); + + $.ajax({ + url: "/vm/" + id + "/action", + type: "POST", + data: JSON.stringify(action), + success: function() + { + if (callback) + { + callback(request); + } + }, + error: function(response) + { + if (callback_error) + { + callback_error(request, OpenNebula.Error(response)); + } + } + }); + }, + + "resubmit": function(params) + { + var callback = params.success; + var callback_error = params.error; + var id = params.data.id; + var resource = OpenNebula.VM.resource; + + var method = "resubmit"; + var action = OpenNebula.Helper.action(method); + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/vm/" + id + "/action", @@ -1189,8 +1246,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var data = params.data; + var resource = OpenNebula.Cluster.resource; - var request = OpenNebula.Helper.request(this.resource,"create", name); + var request = OpenNebula.Helper.request(resource,"create", name); $.ajax({ url: "/cluster", @@ -1219,8 +1277,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Cluster.resource; - var request = OpenNebula.Helper.request(this.resource,"delete", id); + var request = OpenNebula.Helper.request(resource,"delete", id); $.ajax({ url: "/cluster/" + id, @@ -1248,8 +1307,8 @@ var OpenNebula = { var callback_error = params.error; var timeout = params.timeout || false; - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"list"); + var resource = OpenNebula.Cluster.resource; + var request = OpenNebula.Helper.request(resource,"list"); $.ajax({ url: "/cluster", @@ -1279,13 +1338,14 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var host_id = params.data.id; - var cluster_id = params.data.cluster_id; + var cluster_id = params.data.extra_param; + var resource = OpenNebula.Cluster.resource; var method = "add_host"; var action = OpenNebula.Helper.action(method, { "host_id" : host_id }); - var request = OpenNebula.Helper.request(this.resource,method, [host_id, cluster_id]); + var request = OpenNebula.Helper.request(resource,method, [host_id, cluster_id]); $.ajax({ url: "/cluster/" + cluster_id + "/action", @@ -1313,13 +1373,15 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var host_id = params.data.id; - var cluster_id = params.data.cluster_id; + var cluster_id = params.data.extra_param; var method = "remove_host"; var action = OpenNebula.Helper.action(method, { "host_id" : host_id }); - var request = OpenNebula.Helper.request(this.resource,method, [host_id, cluster_id]); + var resource = OpenNebula.Cluster.resource; + + var request = OpenNebula.Helper.request(resource,method, [host_id, cluster_id]); $.ajax({ url: "/cluster/" + cluster_id + "/action", @@ -1351,8 +1413,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var data = params.data; + var resource = OpenNebula.User.resource; - var request = OpenNebula.Helper.request(this.resource,"create",data); + var request = OpenNebula.Helper.request(resource,"create",data); $.ajax({ url: "/user", @@ -1381,8 +1444,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.User.resource; - var request = OpenNebula.Helper.request(this.resource,"delete", id); + var request = OpenNebula.Helper.request(resource,"delete", id); $.ajax({ url: "/user/" + id, @@ -1410,8 +1474,8 @@ var OpenNebula = { var callback_error = params.error; var timeout = params.timeout || false; - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"list"); + var resource = OpenNebula.User.resource; + var request = OpenNebula.Helper.request(resource,"list"); $.ajax({ url: "/user", @@ -1447,7 +1511,9 @@ var OpenNebula = { var action = OpenNebula.Helper.action(method, { "password" : passwd }); - var request = OpenNebula.Helper.request(this.resource,method, passwd); + + var resource = OpenNebula.User.resource; + var request = OpenNebula.Helper.request(resource,method, passwd); $.ajax({ url: "/user/" + id + "/action", @@ -1479,8 +1545,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var data = params.data; + var resource = OpenNebula.Image.resource; - var request = OpenNebula.Helper.request(this.resource,"register",data); + var request = OpenNebula.Helper.request(resource,"register",data); $.ajax({ url: "/image", @@ -1509,8 +1576,9 @@ var OpenNebula = { var callback = params.success; var callback_error = params.error; var id = params.data.id; + var resource = OpenNebula.Image.resource; - var request = OpenNebula.Helper.request(this.resource,"delete", id); + var request = OpenNebula.Helper.request(resource,"delete", id); $.ajax({ url: "/image/" + id, @@ -1538,8 +1606,8 @@ var OpenNebula = { var callback_error = params.error; var timeout = params.timeout || false; - var resource = this.resource; - var request = OpenNebula.Helper.request(this.resource,"list"); + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,"list"); $.ajax({ url: "/image", @@ -1570,7 +1638,8 @@ var OpenNebula = { var callback_error = params.error; var id = params.data.id; - var request = OpenNebula.Helper.request(this.resource,"show", id); + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,"show", id); $.ajax({ url: "/image/" + id, @@ -1606,7 +1675,9 @@ var OpenNebula = { "name" : name, "value" : value }); - var request = OpenNebula.Helper.request(this.resource,method, [id, name, value]); + + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,method, [id, name, value]); $.ajax({ url: "/image/" + id + "/action", @@ -1641,7 +1712,9 @@ var OpenNebula = { var action = OpenNebula.Helper.action(method, { "name" : name }); - var request = OpenNebula.Helper.request(this.resource,method, [id, name]); + + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,method, [id, name]); $.ajax({ url: "/image/" + id + "/action", @@ -1672,7 +1745,9 @@ var OpenNebula = { var method = "enable"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/image/" + id + "/action", @@ -1703,7 +1778,8 @@ var OpenNebula = { var method = "disable"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/image/" + id + "/action", @@ -1734,7 +1810,8 @@ var OpenNebula = { var method = "publish"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/image/" + id + "/action", @@ -1765,7 +1842,8 @@ var OpenNebula = { var method = "unpublish"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/image/" + id + "/action", @@ -1796,7 +1874,9 @@ var OpenNebula = { var method = "persistent"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/image/" + id + "/action", @@ -1827,7 +1907,9 @@ var OpenNebula = { var method = "nonpersistent"; var action = OpenNebula.Helper.action(method); - var request = OpenNebula.Helper.request(this.resource,method, id); + + var resource = OpenNebula.Image.resource; + var request = OpenNebula.Helper.request(resource,method, id); $.ajax({ url: "/image/" + id + "/action", diff --git a/src/sunstone/public/js/plugins/dashboard-tab.js b/src/sunstone/public/js/plugins/dashboard-tab.js new file mode 100644 index 0000000000..b6bc6fb2ac --- /dev/null +++ b/src/sunstone/public/js/plugins/dashboard-tab.js @@ -0,0 +1,241 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ +/* -------------------------------------------------------------------------- */ + +var dashboard_tab_content = +'\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    \ +
    \ +

    Hosts\ +
    \ + +\ +
    \ +

    \ +
    \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    Total
    Active
    \ +
    \ +
    \ +
    \ +
    \ +

    Clusters\ +
    \ + +\ +
    \ +

    \ +
    \ + \ + \ + \ + \ + \ +
    Total
    \ +
    \ +
    \ +
    \ +
    \ +

    Virtual Machines\ +
    \ + +\ +
    \ +

    \ +
    \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    Total
    Running
    Failed
    \ +
    \ +
    \ +
    \ +
    \ +

    Virtual Networks\ +
    \ + +\ +
    \ +

    \ +
    \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    Total
    Public
    \ +
    \ +
    \ + \ +
    \ +
    \ +

    \ + Images\ +
    \ + +\ +
    \ +

    \ +
    \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    Total
    Public
    \ +
    \ +
    \ +
    \ +
    \ +

    Users\ +
    \ + +\ +
    \ +

    \ +
    \ + \ + \ + \ + \ + \ +
    Total
    \ +
    \ +
    \ +
    '; + + +var dashboard_tab = { + title: 'Dashboard', + content: dashboard_tab_content, + condition : True +} + +Sunstone.addMainTab('dashboard_tab',dashboard_tab); + +$(document).ready(function(){ + //Dashboard link listener + $("#dashboard_table h3 a").live("click", function (){ + var tab = $(this).attr('href'); + showTab(tab); + return false; + }); + + emptyDashboard(); + if (uid!=0) { + $("td.oneadmin").hide(); + } + + +}); + +//puts the dashboard values into "retrieving" +function emptyDashboard(){ + $("#dashboard_tab .value_td span").html(spinner); +} + + +function updateDashboard(what,json_info){ + db = $('#dashboard_tab'); + switch (what){ + case "hosts": + total_hosts=json_info.length; + active_hosts=0; + $.each(json_info,function(){ + if (parseInt(this.HOST.STATE) < 3){ + active_hosts++;} + }); + $('#total_hosts',db).html(total_hosts); + $('#active_hosts',db).html(active_hosts); + break; + case "clusters": + total_clusters=json_info.length; + $('#total_clusters',db).html(total_clusters); + break; + case "vms": + total_vms=json_info.length; + running_vms=0; + failed_vms=0; + $.each(json_info,function(){ + vm_state = parseInt(this.VM.STATE); + if (vm_state == 3){ + running_vms++; + } + else if (vm_state == 7) { + failed_vms++; + } + }); + $('#total_vms',db).html(total_vms); + $('#running_vms',db).html(running_vms); + $('#failed_vms',db).html(failed_vms); + break; + case "vnets": + public_vnets=0; + total_vnets=json_info.length; + $.each(json_info,function(){ + if (parseInt(this.VNET.PUBLIC)){ + public_vnets++;} + }); + $('#total_vnets',db).html(total_vnets); + $('#public_vnets',db).html(public_vnets); + break; + case "users": + total_users=json_info.length; + $('#total_users',db).html(total_users); + break; + case "images": + total_images=json_info.length; + public_images=0; + $.each(json_info,function(){ + if (parseInt(this.IMAGE.PUBLIC)){ + public_images++;} + }); + $('#total_images',db).html(total_images); + $('#public_images',db).html(public_images); + break; + } +} diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js new file mode 100644 index 0000000000..fe3d087900 --- /dev/null +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -0,0 +1,686 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ +/* -------------------------------------------------------------------------- */ + +/*Host tab plugin*/ + +var hosts_tab_content = +'
    \ +
    \ +
    \ +\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    AllIDNameClusterRunning VMsCPU UseMemory useStatus
    \ +
    '; + +var create_host_tmpl = +'
    \ +
    \ + Host parameters\ + \ +
    \ +

    Drivers

    \ +
    \ +
    \ + \ + \ +
    \ +
    \ + \ + \ +
    \ +
    \ + \ + \ +
    \ +
    \ +
    \ +
    \ +
    \ +
    \ +
    \ +
    \ +
    '; + +var create_cluster_tmpl = +'
    \ +
    \ +
    \ + \ +
    \ +
    \ +
    \ +
    \ +
    \ + \ + \ +
    \ +
    \ +
    '; + +var hosts_select=""; +var clusters_select=""; +var host_list_json = {}; +var cluster_list_json = {}; +var dataTable_hosts; + +//Setup actions +var host_actions = { + + "Host.create" : { + type: "create", + call : OpenNebula.Host.create, + callback : addHostElement, + error : onError, + notify: true + }, + + "Host.create_dialog" : { + type: "custom", + call: popUpCreateHostDialog + }, + + //Custom below + //~ "Host.list" : { + //~ type: "list", + //~ call: OpenNebula.Host.list, + //~ callback: updateHostsView, + //~ error: onError, + //~ notify:False + //~ }, + + "Host.show" : { + type: "single", + call: OpenNebula.Host.show, + callback: updateHostElement, + error: onError + }, + + "Host.showinfo" : { + type: "single", + call: OpenNebula.Host.show, + callback: updateHostInfo, + error: onError + }, + + "Host.refresh" : { + type: "custom", + call: function(){ + waitingNodes(dataTable_hosts); + Sunstone.runAction("Host.list"); + }, + callback: function(){}, + error: onError, + notify:false + }, + + "Host.autorefresh" : { + type: "custom", + call : function() { + OpenNebula.Host.list({timeout: true, success: updateHostsView,error: onError}); + } + }, + + "Host.enable" : { + type: "multiple", + call : OpenNebula.Host.enable, + callback : function (req) { + Sunstone.runAction("Host.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_hosts); }, + error : onError, + notify: true + }, + + "Host.disable" : { + type: "multiple", + call : OpenNebula.Host.disable, + callback : function (req) { + Sunstone.runAction("Host.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_hosts); }, + error : onError, + notify:true + }, + + "Host.delete" : { + type: "multiple", + call : OpenNebula.Host.delete, + callback : deleteHostElement, + elements: function() { return getSelectedNodes(dataTable_hosts); }, + error : onError, + notify:true + }, + + "Host.list" : { + type: "custom", + call : function() { + OpenNebula.Host.list({success: updateHostsView, error: onError}); + OpenNebula.Cluster.list({success: updateClustersView, error: onError}); + } + }, + + "Cluster.create" : { + type: "create", + call : OpenNebula.Cluster.create, + callback : function(){ + Sunstone.runAction("Cluster.list"); + }, + error : onError, + notify: true + }, + + "Cluster.create_dialog" : { + type: "custom", + call: popUpCreateClusterDialog + }, + + "Cluster.list" : { + type: "list", + call: OpenNebula.Cluster.list, + callback: updateClustersView, + error: onError, + }, + + "Cluster.autorefresh" : { + type: "custom", + call: function () { + OpenNebula.Cluster.list({timeout: true, success: updateClustersView,error: onError}); + } + }, + + "Cluster.delete" : { + type: "single", + call : OpenNebula.Cluster.delete, + callback : function(){ + //OpenNebula.Cluster.list({success: updateClustersView, error: onError}); + Sunstone.runAction("Cluster.list"); + }, + error : onError, + notify:true + }, + + "Cluster.addhost" : { + type: "multiple", + call : OpenNebula.Cluster.addhost, + callback : function(req){ + Sunstone.runAction("Host.show",req.request.data); + }, + elements: function() { return getSelectedNodes(dataTable_hosts); }, + error : onError, + notify:true + }, + + "Cluster.removehost" : { + type: "multiple", + call : OpenNebula.Cluster.removehost, + callback : deleteHostElement, + elements: function() { return getSelectedNodes(dataTable_hosts); }, + error : onError, + notify:true + } + }; + +var host_buttons = { + "Host.refresh" : { + type: "image", + text: "Refresh list", + img: "/images/Refresh-icon.png", + condition: True + }, + "Host.create_dialog" : { + type: "create_dialog", + text: "+ New", + condition :True + }, + "Host.enable" : { + type: "action", + text: "Enable", + condition : True + }, + "Host.disable" : { + type: "action", + text: "Disable", + condition : True + }, + "Cluster.create_dialog" : { + type: "create_dialog", + text: "+ New Cluster", + condition : True + }, + "Cluster.delete" : { + type: "confirm_with_select", + text: "Delete cluster", + select: function(){return clusters_select}, + tip: "Select the cluster you want to remove", + condition : True + }, + + "action_list" : { //Special button + type: "select", + actions: { "Cluster.addhost": { + type: "confirm_with_select", + text: "Add host to cluster", + select: function(){return clusters_select;}, + tip: "Select the cluster in which you would like to place the hosts", + condition: True + }, + "Cluster.removehost" : { + type: "action", + text: "Remove host from cluster", + condition: True + }}, + condition : True + }, + "Host.delete" : { + type: "action", + text: "Delete host", + condition : True + } + }; + +var host_info_panel = { + "host_info_tab" : { + title: "Host information", + content:"" + }, + + "host_template_tab" : { + title: "Host template", + content: "" + } +}; + + +var hosts_tab = { + title: 'Hosts & Clusters', + content: hosts_tab_content, + buttons: host_buttons, + condition: True +} + +Sunstone.addActions(host_actions); +Sunstone.addMainTab('hosts_tab',hosts_tab); +Sunstone.addInfoPanel("host_info_panel",host_info_panel); + + + +//Creates an array to be added to the dataTable from the JSON of a host. +function hostElementArray(host_json){ + + var host = host_json.HOST; + + //Calculate some values + var acpu = parseInt(host.HOST_SHARE.MAX_CPU); + if (!acpu) {acpu=100}; + acpu = acpu - parseInt(host.HOST_SHARE.CPU_USAGE); + + var total_mem = parseInt(host.HOST_SHARE.MAX_MEM); + var free_mem = parseInt(host.HOST_SHARE.FREE_MEM); + + var ratio_mem = 0; + if (total_mem) { + ratio_mem = Math.round(((total_mem - free_mem) / total_mem) * 100); + } + + + var total_cpu = parseInt(host.HOST_SHARE.MAX_CPU); + var used_cpu = Math.max(total_cpu - parseInt(host.HOST_SHARE.USED_CPU),acpu); + + var ratio_cpu = 0; + if (total_cpu){ + ratio_cpu = Math.round(((total_cpu - used_cpu) / total_cpu) * 100); + } + + + //progressbars html code - hardcoded jquery html result + var pb_mem = +'
    \ +
    \ + '+ratio_mem+'%\ +
    \ +
    '; + + var pb_cpu = +'
    \ +
    \ + '+ratio_cpu+'%\ +
    \ +
    '; + + + return [ '', + host.ID, + host.NAME, + host.CLUSTER, + host.HOST_SHARE.RUNNING_VMS, //rvm + pb_cpu, + pb_mem, + OpenNebula.Helper.resource_state("host",host.STATE) ]; + +} + +//Listen to clicks on the tds of the tables and shows the info dialogs. +function hostInfoListener(){ + $('#tbodyhosts tr').live("click",function(e){ + + //do nothing if we are clicking a checkbox! + if ($(e.target).is('input')) {return true;} + popDialogLoading(); + var aData = dataTable_hosts.fnGetData(this); + var id = $(aData[0]).val(); + Sunstone.runAction("Host.showinfo",id); + return false; + }); +} + +//updates the host select by refreshing the options in it +function updateHostSelect(){ + + hosts_select = makeSelectOptions(dataTable_hosts,1,2,7,"DISABLED"); + +} + +//updates the cluster select by refreshing the options in it +function updateClusterSelect(cluster_list){ + + //manual, as there is not dataTable for it + clusters_select=""; + $.each(cluster_list, function(){ + clusters_select += ""; + }); +} + +//callback for an action affecting a host element +function updateHostElement(request, host_json){ + var id = host_json.HOST.ID; + var element = hostElementArray(host_json); + updateSingleElement(element,dataTable_hosts,'#host_'+id); + updateHostSelect(); +} + +//callback for actions deleting a host element +function deleteHostElement(req){ + deleteElement(dataTable_hosts,'#host_'+req.request.data); + updateHostSelect(); +} + +//call back for actions creating a host element +function addHostElement(request,host_json){ + var id = host_json.HOST.ID; + var element = hostElementArray(host_json); + addElement(element,dataTable_hosts); + updateHostSelect(); +} + +//callback to update the list of hosts. +function updateHostsView (request,host_list){ + host_list_json = host_list; + var host_list_array = [] + + $.each(host_list,function(){ + //Grab table data from the host_list + host_list_array.push(hostElementArray(this)); + }); + + updateView(host_list_array,dataTable_hosts); + updateHostSelect(); + //dependency with the dashboard plugin + updateDashboard("hosts",host_list_json); +} + +//updates the list of clusters +function updateClustersView(request, cluster_list){ + cluster_list_json = cluster_list; + updateClusterSelect(cluster_list); + updateDashboard("clusters",cluster_list); +} + +//Updates the host info panel tab's content and pops it up +function updateHostInfo(request,host){ + var host_info = host.HOST; + + //Information tab + var info_tab = { + title : "Host information", + content : + '\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    Host information - '+host_info.NAME+'
    ID'+host_info.ID+'
    State'+OpenNebula.Helper.resource_state("host",host_info.STATE)+'
    Cluster'+host_info.CLUSTER+'
    IM MAD'+host_info.IM_MAD+'
    VM MAD'+host_info.VM_MAD+'
    TM MAD'+host_info.TM_MAD+'
    \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    Host shares
    Max Mem'+humanize_size(host_info.HOST_SHARE.MAX_MEM)+'
    Used Mem (real)'+humanize_size(host_info.HOST_SHARE.USED_MEM)+'
    Used Mem (allocated)'+humanize_size(host_info.HOST_SHARE.MAX_USAGE)+'
    Used CPU (real)'+host_info.HOST_SHARE.USED_CPU+'
    Used CPU(allocated)'+host_info.HOST_SHARE.CPU_USAGE+'
    Running VMs'+host_info.HOST_SHARE.RUNNING_VMS+'
    ' + } + + //Template tab + var template_tab = { + title : "Host template", + content : + '\ + '+ + prettyPrintJSON(host_info.TEMPLATE)+ + '
    Host template
    ' + } + + //Sunstone.updateInfoPanelTab(info_panel_name,tab_name, new tab object); + Sunstone.updateInfoPanelTab("host_info_panel","host_info_tab",info_tab); + Sunstone.updateInfoPanelTab("host_info_panel","host_template_tab",template_tab); + Sunstone.popUpInfoPanel("host_info_panel"); + +} + +//Prepares the host creation dialog +function setupCreateHostDialog(){ + $('div#dialogs').append('
    '); + $('div#create_host_dialog').html(create_host_tmpl); + $('#create_host_dialog').dialog({ + autoOpen: false, + modal: true, + width: 500 + }); + + $('#create_host_dialog button').button(); + + //Handle the form submission + $('#create_host_form').submit(function(){ + if (!($('#name',this).val().length)){ + notifyError("Host name missing!"); + return false; + } + var host_json = { "host": { "name": $('#name',this).val(), + "tm_mad": $('#tm_mad :selected',this).val(), + "vm_mad": $('#vmm_mad :selected',this).val(), + "im_mad": $('#im_mad :selected',this).val()}} + + //Create the OpenNebula.Host. + //If it's successfull we refresh the list. + Sunstone.runAction("Host.create",host_json); + //OpenNebula.Host.create({data: host_json, success: addHostElement, error: onError}); + $('#create_host_dialog').dialog('close'); + return false; + }); + +} + +//Prepares the dialog to create a cluster +function setupCreateClusterDialog(){ + $('div#dialogs').append('
    '); + $('#create_cluster_dialog').html(create_cluster_tmpl); + + $('#create_cluster_dialog').dialog({ + autoOpen: false, + modal: true, + width: 400 + }); + + $('#create_cluster_dialog button').button(); + + $('#create_cluster_form').submit(function(){ + var name=$('#name',this).val(); + var cluster_json = { "cluster" : { "name" : name }}; + Sunstone.runAction("Cluster.create",cluster_json); + $('#create_cluster_dialog').dialog('close'); + return false; + }); + +} + + +//Open creation dialogs +function popUpCreateHostDialog(){ + $('#create_host_dialog').dialog('open'); + return false; +} + +function popUpCreateClusterDialog(){ + $('#create_cluster_dialog').dialog('open'); + return false; +} + +//Prepares the autorefresh for hosts +function setHostAutorefresh() { + setInterval(function(){ + var checked = $('input:checked',dataTable_hosts.fnGetNodes()); + var filter = $("#datatable_hosts_filter input").attr("value"); + if (!checked.length && !filter.length){ + Sunstone.runAction("Host.autorefresh"); + } + },INTERVAL+someTime()); +} + +//Prepares the autorefresh for clusters +function setClusterAutorefresh(){ + setInterval(function(){ + Sunstone.runAction("Cluster.autorefresh"); + },INTERVAL+someTime()); +} + +//This is executed after the sunstone.js ready() is run. +//Here we can basicly init the host datatable, preload it +//and add specific listeners +$(document).ready(function(){ + + //prepare host datatable + dataTable_hosts = $("#datatable_hosts").dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "bAutoWidth":false, + "sPaginationType": "full_numbers", + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0,4] }, + { "sWidth": "35px", "aTargets": [1] }, + { "sWidth": "120px", "aTargets": [5,6] } + ] + }); + + //preload it + dataTable_hosts.fnClearTable(); + addElement([ + spinner, + '','','','','','',''],dataTable_hosts); + Sunstone.runAction("Host.list"); + Sunstone.runAction("Cluster.list"); + + setupCreateHostDialog(); + setupCreateClusterDialog(); + + setHostAutorefresh(); + setClusterAutorefresh(); + + initCheckAllBoxes(dataTable_hosts); + tableCheckboxesListener(dataTable_hosts); + hostInfoListener(); + +}); diff --git a/src/sunstone/public/js/plugins/images-tab.js b/src/sunstone/public/js/plugins/images-tab.js new file mode 100644 index 0000000000..5009cb90b3 --- /dev/null +++ b/src/sunstone/public/js/plugins/images-tab.js @@ -0,0 +1,851 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ +/* -------------------------------------------------------------------------- */ + +/*Images tab plugin*/ + +var images_tab_content = +'
    \ +
    \ +
    \ +\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    AllIDUserNameTypeRegistration timePublicPersistentState#VMS
    \ +
    '; + +var create_image_tmpl = +'
    \ + \ +
    \ +
    \ +

    Fields marked with are mandatory
    \ +

    \ +
    \ + \ + \ +
    Name that the Image will get. Every image must have a unique name.
    \ +
    \ +
    \ + \ + \ +
    Human readable description of the image for other users.
    \ +
    \ +
    \ +
    \ +
    \ + \ + \ +
    Type of the image, explained in detail in the following section. If omitted, the default value is the one defined in oned.conf (install default is OS).
    \ +
    \ +
    \ + \ + \ +
    Public scope of the image
    \ +
    \ +
    \ + \ + \ +
    Persistence of the image
    \ +
    \ +
    \ + \ + \ +
    Prefix for the emulated device this image will be mounted at. For instance, “hd”, “sd”. If omitted, the default value is the one defined in oned.conf (installation default is “hd”).
    \ +
    \ +
    \ + \ + \ +
    Type of disk device to emulate.
    \ +
    \ +
    \ +
    \ +
    \ + \ + \ +
    \ + \ +
    \ + \ + \ +
    Please choose path if you have a file-based image. Choose source otherwise or create an empty datablock disk.

    \ +
    \ +
    \ + \ + \ +
    Path to the original file that will be copied to the image repository. If not specified for a DATABLOCK type image, an empty image will be created.
    \ +
    \ +
    \ + \ + \ +
    Source to be used in the DISK attribute. Useful for not file-based images.
    \ +
    \ +
    \ + \ + \ +
    Size of the datablock in MB.
    \ +
    \ +
    \ + \ + \ +
    Type of file system to be built. This can be any value understood by mkfs unix command.
    \ +
    \ +
    \ +
    \ +
    \ + \ + \ +
    \ +
    \ +
    \ +
    \ +
    \ +
    \ +
    \ +

    Write the image template here

    \ + \ +
    \ +
    \ +
    \ + \ + \ +
    \ +
    \ +
    \ +
    \ +
    '; + +var images_select = ""; +var image_list_json = {}; +var dataTable_images; + +var image_actions = { + + "Image.register" : { + type: "create", + call: OpenNebula.Image.register, + callback: addImageElement, + error: onError, + notify:true + }, + + "Image.create_dialog" : { + type: "custom", + call: popUpCreateImageDialog + }, + + "Image.list" : { + type: "list", + call: OpenNebula.Image.list, + callback: updateImagesView, + error: onError + }, + + "Image.show" : { + type : "single", + call: OpenNebula.Image.show, + callback: updateImageElement, + error: onError + }, + + "Image.showinfo" : { + type: "single", + call: OpenNebula.Image.show, + callback: updateImageInfo, + error: onError + }, + + "Image.refresh" : { + type: "custom", + call: function () { + waitingNodes(dataTable_images); + Sunstone.runAction("Image.list"); + }, + }, + + "Image.autorefresh" : { + type: "custom", + call: function() { + OpenNebula.Image.list({timeout: true, success: updateImagesView, error: onError}); + } + }, + + "Image.addattr" : { + type: "multiple", + call: function(obj){ + var id_attr = obj.data.id; + var name = $('#img_attr_name').val(); + var value = $('#img_attr_value').val(); + OpenNebula.Image.addattr( + {data: { + id: id_attr, + name: name, + value: value + }, + success: obj.success, + error: obj.error + }); + }, + callback : function (req) { + Sunstone.runAction("Image.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_images); }, + error: onError, + notify: true + }, + + "Image.addattr_dialog" : { + type: "custom", + call: popUpImageAddattrDialog + }, + + "Image.updateattr_dialog" : { + type: "custom", + call: popUpImageAddattrDialog + }, + + "Image.rmattr" : { + type: "multiple", + call: function(obj){ + var id_attr = obj.data.id; + var name = $('#img_attr_name').val(); + OpenNebula.Image.rmattr( + {data: { + id: id_attr, + name: name + }, + success: obj.success, + error: obj.error + }); + }, + callback: function (req) { + Sunstone.runAction("Image.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_images); }, + error: onError, + notify: true + }, + + "Image.rmattr_dialog" : { + type: "custom", + call: popUpImageRmattrDialog, + }, + + "Image.enable" : { + type: "multiple", + call: OpenNebula.Image.enable, + callback: function (req) { + Sunstone.runAction("Image.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_images); }, + error: onError, + notify: true + }, + + "Image.disable" : { + type: "multiple", + call: OpenNebula.Image.disable, + callback: function (req) { + Sunstone.runAction("Image.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_images); }, + error: onError, + notify: true + }, + + "Image.persistent" : { + type: "multiple", + call: OpenNebula.Image.persistent, + callback: function (req) { + Sunstone.runAction("Image.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_images); }, + error: onError, + notify: true + }, + + "Image.nonpersistent" : { + type: "multiple", + call: OpenNebula.Image.nonpersistent, + callback: function (req) { + Sunstone.runAction("Image.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_images); }, + error: onError, + notify: true + }, + + "Image.publish" : { + type: "multiple", + call: OpenNebula.Image.publish, + callback: function (req) { + Sunstone.runAction("Image.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_images); }, + error: onError, + notify: true + }, + + "Image.unpublish" : { + type: "multiple", + call: OpenNebula.Image.unpublish, + callback: function (req) { + Sunstone.runAction("Image.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_images); }, + error: onError, + notify: true + }, + + "Image.delete" : { + type: "multiple", + call: OpenNebula.Image.delete, + callback: function (req) { + Sunstone.runAction("Image.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_images); }, + error: onError, + notify: true + } +} + + +var image_buttons = { + "Image.refresh" : { + type: "image", + text: "Refresh list", + img: "/images/Refresh-icon.png", + condition: True + }, + "Image.create_dialog" : { + type: "create_dialog", + text: "+ New", + condition: True + }, + "Image.addattr_dialog" : { + type: "action", + text: "Add attribute", + condition: True + }, + "Image.updateattr_dialog" : { + type: "action", + text: "Update attribute", + condition: True + }, + "Image.rmattr_dialog" : { + type: "action", + text: "Remove attribute", + condition: True + }, + "action_list" : { + type: "select", + condition: True, + actions: { + "Image.enable" : { + type: "action", + text: "Enable", + condition: True + }, + "Image.disable" : { + type: "action", + text: "Disable", + condition: True + }, + "Image.publish" : { + type: "action", + text: "Publish", + condition: True + }, + "Image.unpublish" : { + type: "action", + text: "Unpublish", + condition: True + }, + "Image.persistent" : { + type: "action", + text: "Make persistent", + condition: True + }, + "Image.nonpersistent" : { + type: "action", + text: "Make non persistent", + condition: True + } + } + }, + "Image.delete" : { + type: "action", + text: "Delete", + condition: True + } +} + +var image_info_panel = { + "image_info_tab" : { + title: "Image information", + content: "" + }, + + "image_template_tab" : { + title: "Image template", + content: "" + } + +} + +var images_tab = { + title: "Images", + content: images_tab_content, + buttons: image_buttons, + condition: True +} + +Sunstone.addActions(image_actions); +Sunstone.addMainTab('images_tab',images_tab); +Sunstone.addInfoPanel('image_info_panel',image_info_panel); + +// Returns an array containing the values of the image_json and ready +// to be inserted in the dataTable +function imageElementArray(image_json){ + var image = image_json.IMAGE; + return [ + '', + image.ID, + image.USERNAME ? image.USERNAME : getUserName(image.UID), + image.NAME, + OpenNebula.Helper.image_type(image.TYPE), + pretty_time(image.REGTIME), + parseInt(image.PUBLIC) ? "yes" : "no", + parseInt(image.PERSISTENT) ? "yes" : "no", + OpenNebula.Helper.resource_state("image",image.STATE), + image.RUNNING_VMS + ]; +} + +// Set up the listener on the table TDs to show the info panel +function imageInfoListener(){ + + $('#tbodyimages tr').live("click",function(e){ + if ($(e.target).is('input')) {return true;} + popDialogLoading(); + var aData = dataTable_images.fnGetData(this); + var id = $(aData[0]).val(); + Sunstone.runAction("Image.showinfo",id); + return false; + }); +} + +//Updates the select input field with an option for each image +function updateImageSelect(){ + images_select = makeSelectOptions(dataTable_images,1,3,8,"DISABLED"); + + //update static selectors: + //in the VM section + $('div.vm_section#disks select#IMAGE_ID').html(images_select); +} + +// Callback to update an element in the dataTable +function updateImageElement(request, image_json){ + var id = image_json.IMAGE.ID; + var element = imageElementArray(image_json); + updateSingleElement(element,dataTable_images,'#image_'+id); + updateImageSelect(); +} + +// Callback to remove an element from the dataTable +function deleteImageElement(req){ + deleteElement(dataTable_images,'#image_'+req.request.data); + updateImageSelect(); +} + +// Callback to add an image element +function addImageElement(request, image_json){ + var element = imageElementArray(image_json); + addElement(element,dataTable_images); + //NOTE that the select is not updated because newly added images + //are disabled by default +} + +// Callback to refresh the list of images +function updateImagesView(request, images_list){ + image_list_json = images_list; + var image_list_array = []; + $.each(image_list_json,function(){ + image_list_array.push(imageElementArray(this)); + }); + + updateView(image_list_array,dataTable_images); + updateImageSelect(); + updateDashboard("images",image_list_json); + +} + +// Prepare the dialog to add/remove/update image attributes +function setupImageAttributesDialogs(){ + + //Append to DOM + $('div#dialogs').append('
    '); + + //Put HTML in place + $('#image_attributes_dialog').html( + '
    \ +
    \ +
    \ +
    \ +
    \ + \ + \ +
    \ +
    \ + \ + \ +
    \ +
    \ + \ + \ +
    \ +
    \ +
    '); + + $('#image_attributes_dialog').dialog({ + autoOpen:false, + width:400, + modal:true, + height:220, + resizable:false, + }); + + $('#image_attributes_dialog button').button(); + + //Upcase variable names + $('#img_attr_name').keyup(function(){ + $(this).val($(this).val().toUpperCase()); + }); + + $('#image_attributes_dialog #img_attr_proceed').click(function(){ + $('#image_attributes_dialog').dialog('close'); + }); + + $('#image_attributes_dialog #img_attr_cancel').click(function(){ + $('#image_attributes_dialog').dialog('close'); + return false; + }); + +} + +// Popup a dialog to add/update an attribute +function popUpImageAddattrDialog(){ + + //Show value field and label + $('#img_attr_value').show(); + $('#img_attr_value').prev().show(); + var desc = "Please write the name and value of the attribute. It will be added or updated in all selected images:"; + $('#img_attr_proceed').val("Image.addattr"); + $('#img_attr_action_desc').html(desc); + $('#image_attributes_dialog').dialog('open'); + return false; +} + +// Popup a dialog to remove an attribute +function popUpImageRmattrDialog(){ + + //Hide value field and label + $('#img_attr_value').hide(); + $('#img_attr_value').prev().hide(); + var desc = "Please type the attribute you want to remove:"; + $('#img_attr_proceed').val("Image.rmattr"); + $('#img_attr_action_desc').html(desc); + $('#image_attributes_dialog').dialog('open'); + return false; +} + +// Callback to update the information panel tabs and pop it up +function updateImageInfo(request,img){ + var img_info = img.IMAGE; + var info_tab = { + title: "Image information", + content: + '\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    Image "'+img_info.NAME+'" information
    ID'+img_info.ID+'
    Name'+img_info.NAME+'
    Type'+OpenNebula.Helper.image_type(img_info.TYPE)+'
    Register time'+pretty_time(img_info.REGTIME)+'
    Public'+(parseInt(img_info.PUBLIC) ? "yes" : "no")+'
    Persistent'+(parseInt(img_info.PERSISTENT) ? "yes" : "no")+'
    Source'+img_info.SOURCE+'
    State'+OpenNebula.Helper.resource_state("image",img_info.STATE)+'
    ' + } + + var template_tab = { + title: "Image template", + content: '\ + '+ + prettyPrintJSON(img_info.TEMPLATE)+ + '
    Image template
    ' + } + + Sunstone.updateInfoPanelTab("image_info_panel","image_info_tab",info_tab); + Sunstone.updateInfoPanelTab("image_info_panel","image_template_tab",template_tab); + + Sunstone.popUpInfoPanel("image_info_panel"); + +} + +// Prepare the image creation dialog +function setupCreateImageDialog(){ + $('div#dialogs').append('
    '); + + //Insert HTML in place + $('#create_image_dialog').html(create_image_tmpl); + + //Prepare jquery dialog + $('#create_image_dialog').dialog({ + autoOpen: false, + modal:true, + width: 520 + }); + + $('#img_tabs').tabs(); + $('#create_image_dialog button').button(); + $('#img_type option').first().attr("selected","selected"); + $('#datablock_img').attr("disabled","disabled"); + + //Chrome workaround + $('select#img_type').change(function(){ + $(this).trigger("click"); + }); + + $('select#img_type').click(function(){ + var value = $(this).val(); + switch (value){ + case "DATABLOCK": + $('#datablock_img').removeAttr("disabled"); + break; + default: + $('#datablock_img').attr("disabled","disabled"); + $('#path_img').attr("checked","checked"); + $('#img_source,#img_fstype,#img_size').parent().hide(); + $('#img_path').parent().show(); + } + }); + + $('#img_source,#img_fstype,#img_size').parent().hide(); + $('#path_img').attr("checked","checked"); + $('#img_path').parent().addClass("img_man"); + + $('#img_public').click(function(){ + $('#img_persistent').removeAttr("checked"); + }); + + $('#img_persistent').click(function(){ + $('#img_public').removeAttr("checked"); + }); + + + + $('#src_path_select input').click(function(){ + var value = $(this).val(); + switch (value){ + case "path": + $('#img_source,#img_fstype,#img_size').parent().hide(); + $('#img_source,#img_fstype,#img_size').parent().removeClass("img_man"); + $('#img_path').parent().show(); + $('#img_path').parent().addClass("img_man"); + break; + case "source": + $('#img_path,#img_fstype,#img_size').parent().hide(); + $('#img_path,#img_fstype,#img_size').parent().removeClass("img_man"); + $('#img_source').parent().show(); + $('#img_source').parent().addClass("img_man"); + break; + case "datablock": + $('#img_source,#img_path').parent().hide(); + $('#img_source,#img_path').parent().removeClass("img_man"); + $('#img_fstype,#img_size').parent().show(); + $('#img_fstype,#img_size').parent().addClass("img_man"); + break; + } + }); + + + $('#create_image_form_easy').submit(function(){ + var exit = false; + $('.img_man',this).each(function(){ + if (!$('input',this).val().length){ + notifyError("There are mandatory parameters missing"); + exit = true; + return false; + } + }); + if (exit) { return false; } + var img_json = {}; + + var name = $('#img_name').val(); + img_json["NAME"] = name; + + var desc = $('#img_desc').val(); + if (desc.length){ + img_json["DESCRIPTION"] = desc; + } + + var type = $('#img_type').val(); + img_json["TYPE"]= type; + + img_json["PUBLIC"] = $('#img_public:checked').length ? "YES" : "NO"; + + img_json["PERSISTENT"] = $('#img_persistent:checked').length ? "YES" : "NO"; + + var dev_prefix = $('#img_dev_prefix').val(); + if (dev_prefix.length){ + img_json["DEV_PREFIX"] = dev_prefix; + } + + var bus = $('#img_bus').val(); + img_json["BUS"] = bus; + + switch ($('#src_path_select input:checked').val()){ + case "path": + path = $('#img_path').val(); + img_json["PATH"] = path; + break; + case "source": + source = $('#img_source').val(); + img_json["SOURCE"] = source; + break; + case "datablock": + size = $('#img_size').val(); + fstype = $('#img_fstype').val(); + img_json["SIZE"] = size; + img_json["FSTYPE"] = fstype; + break; + } + var obj = { "image" : img_json }; + Sunstone.runAction("Image.register", obj); + + $('#create_image_dialog').dialog('close'); + return false; + }); + + $('#create_image_form_manual').submit(function(){ + var template=$('#template',this).val(); + Sunstone.runAction("Image.register",template); + $('#create_image_dialog').dialog('close'); + return false; + }); + +} + +function popUpCreateImageDialog(){ + $('#create_image_dialog').dialog('open'); +} + +// Set the autorefresh interval for the datatable +function setImageAutorefresh() { + setInterval(function(){ + var checked = $('input:checked',dataTable_images.fnGetNodes()); + var filter = $("#datatable_images_filter input").attr("value"); + if (!checked.length && !filter.length){ + Sunstone.runAction("Image.autorefresh"); + } + },INTERVAL+someTime()); +} + +//The DOM is ready at this point +$(document).ready(function(){ + + dataTable_images = $("#datatable_images").dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "bAutoWidth":false, + "sPaginationType": "full_numbers", + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0,3] }, + { "sWidth": "35px", "aTargets": [1] }, + { "sWidth": "100px", "aTargets": [2,3] } + ] + }); + + dataTable_images.fnClearTable(); + addElement([ + spinner, + '','','','','','','','',''],dataTable_images); + Sunstone.runAction("Image.list"); + + setupCreateImageDialog(); + setupImageAttributesDialogs(); + setupTips($('#create_image_dialog')); + setImageAutorefresh(); + + initCheckAllBoxes(dataTable_images); + tableCheckboxesListener(dataTable_images); + imageInfoListener(); + +}) diff --git a/src/sunstone/public/js/plugins/users-tab.js b/src/sunstone/public/js/plugins/users-tab.js new file mode 100644 index 0000000000..f5470aaed8 --- /dev/null +++ b/src/sunstone/public/js/plugins/users-tab.js @@ -0,0 +1,257 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ +/* -------------------------------------------------------------------------- */ + +/*Users tab plugin*/ + +var users_tab_content = +'
    \ +
    \ +
    \ +\ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    AllIDName
    \ +
    '; + +var create_user_tmpl = +'
    \ +
    \ +
    \ + \ +
    \ + \ + \ +
    \ +
    \ +
    \ +
    \ + \ + \ +
    \ +
    \ +
    '; + +var user_list_json = {}; +var dataTable_users; + +var user_actions = { + "User.create" : { + type: "create", + call: OpenNebula.User.create, + callback: addUserElement, + error: onError, + notify: true + }, + + "User.create_dialog" : { + type: "custom", + call: popUpCreateUserDialog + }, + + "User.list" : { + type: "list", + call: OpenNebula.User.list, + callback: updateUsersView, + error: onError + }, + + "User.refresh" : { + type: "custom", + call: function () { + waitingNodes(dataTable_users); + Sunstone.runAction("User.list"); + }, + }, + + "User.autorefresh" : { + type: "custom", + call: function(){ + OpenNebula.User.list({timeout: true, success: updateUsersView, error: onError}); + }, + condition: function(){ uid == 0 }, + notify: false + }, + + "User.delete" : { + type: "multiple", + call: OpenNebula.User.delete, + callback: deleteUserElement, + elements: function() { return getSelectedNodes(dataTable_users); }, + error: onError, + notify: true + }, +} + +var user_buttons = { + "User.refresh" : { + type: "image", + text: "Refresh list", + img: "/images/Refresh-icon.png", + condition: True + }, + "User.create_dialog" : { + type: "create_dialog", + text: "+ New", + condition: True + }, + "User.delete" : { + type: "action", + text: "Delete", + condition: True + } +} + +var users_tab = { + title: "Users", + content: users_tab_content, + buttons: user_buttons, + condition: function(){ return uid == 0; } +} + +Sunstone.addActions(user_actions); +Sunstone.addMainTab('users_tab',users_tab); + +// Returns an array with the values from the user_json ready to be +// added to the dataTable +function userElementArray(user_json){ + var user = user_json.USER; + if (!user.NAME || user.NAME == {}){ + name = ""; + } else { + name = user.NAME; + } + + return [ + '', + user.ID, + name + ] +} + + +// Callback to refresh a single element from the dataTable +function updateUserElement(request, user_json){ + var id = user_json.USER.ID; + var element = userElementArray(user_json); + updateSingleElement(element,dataTable_users,'#user_'+id); +} + +// Callback to delete a single element from the dataTable +function deleteUserElement(req){ + deleteElement(dataTable_users,'#user_'+req.request.data); +} + +// Callback to add a single user element +function addUserElement(request,user_json){ + var element = userElementArray(user_json); + addElement(element,dataTable_users); +} + +// Callback to update the list of users +function updateUsersView(request,users_list){ + user_list_json = users_list; + var user_list_array = []; + + $.each(user_list_json,function(){ + user_list_array.push(userElementArray(this)); + }); + updateView(user_list_array,dataTable_users); + updateDashboard("users",user_list_json); +} + +// Prepare the user creation dialog +function setupCreateUserDialog(){ + $('div#dialogs').append('
    '); + $('#create_user_dialog').html(create_user_tmpl); + + //Prepare jquery dialog + $('#create_user_dialog').dialog({ + autoOpen: false, + modal:true, + width: 400 + }); + + $('#create_user_dialog button').button(); + + $('#create_user_form').submit(function(){ + var user_name=$('#username',this).val(); + var user_password=$('#pass',this).val(); + if (!user_name.length && !user_password.length){ + notifyError("User name and password must be filled in"); + return false; + } + + var user_json = { "user" : + { "name" : user_name, + "password" : user_password } + }; + Sunstone.runAction("User.create",user_json); + $('#create_user_dialog').dialog('close'); + return false; + }); +} + +function popUpCreateUserDialog(){ + $('#create_user_dialog').dialog('open'); +} + +// Prepare the autorefresh of the list +function setUserAutorefresh(){ + setInterval(function(){ + var checked = $('input:checked',dataTable_users.fnGetNodes()); + var filter = $("#datatable_users_filter input").attr("value"); + if (!checked.length && !filter.length){ + Sunstone.runAction("User.autorefresh"); + } + },INTERVAL+someTime()); +} + +$(document).ready(function(){ + + //if we are not oneadmin, our tab will not even be in the DOM. + if (uid==0) { + dataTable_users = $("#datatable_users").dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "sPaginationType": "full_numbers", + "bAutoWidth":false, + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0] }, + { "sWidth": "35px", "aTargets": [1] } + ] + }); + dataTable_users.fnClearTable(); + addElement([ + spinner, + '',''],dataTable_users); + + Sunstone.runAction("User.list"); + + setupCreateUserDialog(); + setUserAutorefresh(); + + initCheckAllBoxes(dataTable_users); + tableCheckboxesListener(dataTable_users); + } +}) diff --git a/src/sunstone/public/js/plugins/vms-tab.js b/src/sunstone/public/js/plugins/vms-tab.js new file mode 100644 index 0000000000..9fbbb65bc5 --- /dev/null +++ b/src/sunstone/public/js/plugins/vms-tab.js @@ -0,0 +1,1969 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ +/* -------------------------------------------------------------------------- */ + +/*Virtual Machines tab plugin*/ + +var vms_tab_content = +'
    \ +
    \ +
    \ +\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    AllIDUserNameStatusCPUMemoryHostnameStart Time
    \ +
    '; + +var create_vm_tmpl = +'
    \ + \ +
    \ +
    \ +
    \ + \ +

    Fields marked with are mandatory
    \ + Fold / Unfold all sections

    \ +
    \ +\ + \ +
    \ +
    \ +

    Capacity options

    \ +
    \ +
    Capacity\ +
    \ + \ + \ +
    Name that the VM will get for description purposes. If NAME is not supplied a name generated by one will be in the form of one-<VID>.
    \ +
    \ +
    \ + \ + \ +
    Amount of RAM required for the VM, in Megabytes.
    \ +
    \ +
    \ + \ + \ +
    Percentage of CPU divided by 100 required for the Virtual Machine. Half a processor is written 0.5.
    \ +
    \ +
    \ + \ + \ +
    Number of virtual cpus. This value is optional, the default hypervisor behavior is used, usually one virtual CPU.
    \ +
    \ +
    \ +
    \ + \ +
    \ +
    \ +

    Boot/OS options

    \ +
    \ +
    OS and Boot options\ +
    \ + \ + \ +
    CPU architecture to virtualization
    \ +
    \ + \ +
    \ + \ + \ +
    Select boot method
    \ +
    \ +
    \ + \ + \ +
    Path to the OS kernel to boot the image
    \ +
    \ +
    \ + \ + \ +
    Path to the initrd image
    \ +
    \ +
    \ + \ + \ +
    Device to be mounted as root
    \ +
    \ +
    \ + \ + \ +
    Arguments for the booting kernel
    \ +
    \ +
    \ + \ + \ +
    Path to the bootloader executable
    \ +
    \ +
    \ + \ + \ +
    Boot device type
    \ +
    \ +
    \ +
    \ +\ +\ + \ +
    \ +
    \ +

    Add disks/images

    \ +
    \ +
    Disks\ +
    \ + \ + Disk\ + \ + Image\ + \ +
    \ +
    \ +
    \ + \ + \ +
    Name of the image to use
    \ +
    \ +
    \ + \ + \ +
    Type of disk device to emulate: ide, scsi
    \ +
    \ +
    \ + \ + \ +
    Device to map image disk. If set, it will overwrite the default device mapping
    \ +
    \ +
    \ + \ + \ +
    Specific image mapping driver. KVM: raw, qcow2. Xen:tap:aio:, file:. VMware unsupported
    \ +
    \ +
    \ + \ + \ +
    Disk type
    \ +
    \ +
    \ + \ + \ +
    Disk file location path or URL
    \ +
    \ +
    \ + \ + \ + \ +
    Disk file location path or URL. Mandatory for swap, fs and block images
    \ +
    \ +
    \ + \ + \ + \ +
    Filesystem type for the fs images
    \ +
    \ +
    \ + \ + \ +
    Clone this image
    \ +
    \ +
    \ + \ + \ +
    Save this image after shutting down the VM
    \ +
    \ +
    \ + \ + \ +
    Mount image as read-only
    \ +
    \ +
    \ + \ + \ +
    \ + \ + \ +
    \ +
    \ +
    \ +
    \ +\ + \ +
    \ +
    \ +

    Setup Networks

    \ +
    \ +
    Network\ +
    \ + \ + Predefined\ + \ + Manual\ + \ + \ +
    \ +
    \ +
    \ + \ + \ +
    Name of the network to attach this device
    \ +
    \ +
    \ + \ + \ +
    Request an specific IP from the Network
    \ +
    \ +
    \ + \ + \ +
    HW address associated with the network interface
    \ +
    \ +
    \ + \ + \ +
    Name of the bridge the network device is going to be attached to
    \ +
    \ +
    \ + \ + \ +
    Name for the tun device created for the VM
    \ +
    \ +
    \ + \ + \ +
    Name of a shell script to be executed after creating the tun device for the VM
    \ +
    \ +
    \ + \ + \ +
    Hardware that will emulate this network interface. With Xen this is the type attribute of the vif.
    \ +
    \ +
    \ + \ + \ +
    \ + \ + \ +
    \ +
    \ +
    \ +\ +\ + \ +
    \ +
    \ +

    Add inputs

    \ +
    \ +
    Inputs\ +
    \ + \ + \ +
    \ +
    \ +
    \ + \ + \ +
    \ +
    \ +
    \ + \ + \ +
    \ + \ + \ +
    \ +
    \ +
    \ +\ +\ + \ +
    \ +
    \ +

    Add Graphics

    \ +
    \ +
    Graphics\ +
    \ + \ + \ +
    \ +
    \ +
    \ + \ + \ +
    IP to listen on
    \ +
    \ +
    \ + \ + \ +
    Port for the VNC server
    \ +
    \ +
    \ + \ + \ +
    Password for the VNC server
    \ +
    \ +
    \ + \ + \ +
    Keyboard configuration locale to use in the VNC display
    \ +
    \ +
    \ +
    \ +\ +\ + \ +
    \ +
    \ +

    Add context variables

    \ +
    \ +
    Context\ +
    \ + \ + \ +
    Name for the context variable
    \ +
    \ +
    \ + \ + \ +
    Value of the context variable
    \ +
    \ +
    \ + \ + \ +
    \ + \ + \ +
    \ +
    \ +
    \ +\ +\ + \ +
    \ +
    \ +

    Add placement options

    \ +
    \ +
    Placement\ +
    \ + \ + \ +
    Boolean expression that rules out provisioning hosts from list of machines suitable to run this VM
    \ +
    \ +
    \ + \ + \ +
    This field sets which attribute will be used to sort the suitable hosts for this VM. Basically, it defines which hosts are more suitable than others
    \ +
    \ +
    \ +
    \ +\ +\ + \ +
    \ +
    \ +

    Add Hypervisor raw options

    \ +
    \ +
    Raw\ + \ +
    \ + \ + \ + \ +
    Raw data to be passed directly to the hypervisor
    \ +
    \ +
    \ +
    \ +\ +\ + \ +
    \ +
    \ + \ + \ +
    \ +
    \ +
    \ +
    \ +
    \ +
    \ +

    Write the Virtual Machine template here

    \ +
    \ + \ +
    \ +
    \ +
    \ +
    \ + \ + \ +
    \ +
    \ +
    \ +
    \ +
    '; + +var vmachine_list_json = {}; +var dataTable_vMachines; + +var vm_actions = { + "VM.create" : { + type: "create", + call: OpenNebula.VM.create, + callback: addVMachineElement, + error: onError, + notify: true + }, + + "VM.create_dialog" : { + type: "custom", + call: popUpCreateVMDialog, + }, + + "VM.list" : { + type: "list", + call: OpenNebula.VM.list, + callback: updateVMachinesView, + error: onError + }, + + "VM.show" : { + type: "single", + call: OpenNebula.VM.show, + callback: updateVMachineElement, + error: onError + }, + + "VM.showinfo" : { + type: "single", + call: OpenNebula.VM.show, + callback: updateVMInfo, + error: onError + }, + + "VM.refresh" : { + type: "custom", + call : function (){ + waitingNodes(dataTable_vMachines); + Sunstone.runAction("VM.list"); + }, + }, + + "VM.autorefresh" : { + type: "custom", + call : function() { + OpenNebula.VM.list({timeout: true, success: updateVMachinesView,error: onError}); + }, + }, + + "VM.deploy" : { + type: "multiple", + call: OpenNebula.VM.deploy, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.migrate" : { + type: "multiple", + call: OpenNebula.VM.migrate, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.livemigrate" : { + type: "multiple", + call: OpenNebula.VM.livemigrate, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.hold" : { + type: "multiple", + call: OpenNebula.VM.hold, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.release" : { + type: "multiple", + call: OpenNebula.VM.release, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.suspend" : { + type: "multiple", + call: OpenNebula.VM.suspend, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.resume" : { + type: "multiple", + call: OpenNebula.VM.resume, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.stop" : { + type: "multiple", + call: OpenNebula.VM.stop, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.restart" : { + type: "multiple", + call: OpenNebula.VM.restart, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.resubmit" : { + type: "multiple", + call: OpenNebula.VM.resubmit, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.saveasmultiple" : { + type: "custom", + call: function(){ + var elems = vm_actions["VM.saveasmultiple"].elements(); + popUpSaveasDialog(elems); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); } + }, + + "VM.saveas" : { + type: "custom", + call: function(obj) { + OpenNebula.VM.saveas( + {data:obj, + success: function (req) { + Sunstone.runAction("VM.show", + req.request.data[0]); + }, + error: onError }); + } + }, + + "VM.shutdown" : { + type: "multiple", + call: OpenNebula.VM.shutdown, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.cancel" : { + type: "multiple", + call: OpenNebula.VM.cancel, + callback: function (req) { + Sunstone.runAction("VM.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.delete" : { + type: "multiple", + call: OpenNebula.VM.delete, + callback: deleteVMachineElement, + elements: function() { return getSelectedNodes(dataTable_vMachines); }, + error: onError, + notify: true + }, + + "VM.log" : { + type: "single", + call: OpenNebula.VM.log, + callback: function(req,res) { + //after calling VM.log we process the answer + //update the tab and pop it up again + var log_lines = res.split("\n"); + var colored_log = ''; + for (line in log_lines){ + line = log_lines[line]; + if (line.match(/\[E\]/)){ + line = ''+line+'' + } + colored_log += line + "\n"; + } + var log_tab = { + title: "VM log", + content: '
    '+colored_log+'
    ' + } + Sunstone.updateInfoPanelTab("vm_info_panel","vm_log_tab",log_tab); + Sunstone.popUpInfoPanel("vm_info_panel",0); + + }, + error: function(request,error_json){ + $("#vm_log pre").html(''); + onError(request,error_json); + } + } +} + + + +var vm_buttons = { + "VM.refresh" : { + type: "image", + text: "Refresh list", + img: "/images/Refresh-icon.png", + condition: True + }, + + "VM.create_dialog" : { + type: "create_dialog", + text: "+ New", + condition: True + }, + + "VM.shutdown" : { + type: "confirm", + text: "Shutdown", + tip: "This will initiate the shutdown process in the selected VMs", + condition: True + }, + + "action_list" : { + type: "select", + actions: { + "VM.deploy" : { + type: "confirm_with_select", + text: "Deploy", + tip: "This will deploy the selected VMs on the chosen host", + select: function(){ + if (hosts_select){return hosts_select} + else {return ""} + }, + condition: True + }, + "VM.migrate" : { + type: "confirm_with_select", + text: "Migrate", + tip: "This will migrate the selected VMs to the chosen host", + select: function(){ + if (hosts_select){return hosts_select} + else {return ""} + }, + condition: True + + }, + "VM.livemigrate" : { + type: "confirm_with_select", + text: "Live migrate", + tip: "This will live-migrate the selected VMs to the chosen host", + select: function(){ + if (hosts_select){return hosts_select} + else {return ""} + }, + condition: True + }, + "VM.hold" : { + type: "confirm", + text: "Hold", + tip: "This will hold selected pending VMs from being deployed", + condition: True + }, + "VM.release" : { + type: "confirm", + text: "Release", + tip: "This will release held machines", + condition: True + }, + "VM.suspend" : { + type: "confirm", + text: "Suspend", + tip: "This will suspend selected machines", + condition: True + }, + "VM.resume" : { + type: "confirm", + text: "Resume", + tip: "This will resume selected stopped or suspended VMs", + condition: True + }, + "VM.stop" : { + type: "confirm", + text: "Stop", + tip: "This will stop selected VMs", + condition: True + }, + "VM.restart" : { + type: "confirm", + text: "Restart", + tip: "This will redeploy selected VMs (in UNKNOWN or BOOT state)", + condition: True + }, + "VM.resubmit" : { + type: "confirm", + text: "Resubmit", + tip: "This will resubmits VMs to PENDING state", + condition: True + }, + "VM.saveasmultiple" : { + type: "action", + text: "Save as", + condition: True + }, + "VM.cancel" : { + type: "confirm", + text: "Cancel", + tip: "This will cancel selected VMs", + condition: True + } + }, + condition: True + }, + + "VM.delete" : { + type: "confirm", + text: "Delete", + tip: "This will delete the selected VMs from the database", + condition: True + } +} + +var vm_info_panel = { + "vm_info_tab" : { + title: "Virtual Machine information", + content: "" + }, + "vm_template_tab" : { + title: "VM template", + content: "" + }, + "vm_log_tab" : { + title: "VM log", + content: "" + } +} + +var vms_tab = { + title: "Virtual Machines", + content: vms_tab_content, + buttons: vm_buttons, + condition: True +} + +Sunstone.addActions(vm_actions); +Sunstone.addMainTab('vms_tab',vms_tab); +Sunstone.addInfoPanel('vm_info_panel',vm_info_panel); + + +// Returns a human readable running time for a VM +function str_start_time(vm){ + return pretty_time(vm.STIME); +} + +// Returns an array formed by the information contained in the vm_json +// and ready to be introduced in a dataTable +function vMachineElementArray(vm_json){ + var vm = vm_json.VM; + var state = OpenNebula.Helper.resource_state("vm",vm.STATE); + if (state == "ACTIVE") { + state = OpenNebula.Helper.resource_state("vm_lcm",vm.LCM_STATE); + } + return [ + '', + vm.ID, + vm.USERNAME ? vm.USERNAME : getUserName(vm.UID), + vm.NAME, + state, + vm.CPU, + humanize_size(vm.MEMORY), + vm.HISTORY ? vm.HISTORY.HOSTNAME : "--", + str_start_time(vm) + ] +} + + +//Creates a listener for the TDs of the VM table +function vMachineInfoListener(){ + + $('#tbodyvmachines tr').live("click", function(e){ + if ($(e.target).is('input')) {return true;} + popDialogLoading(); + var aData = dataTable_vMachines.fnGetData(this); + var id = $(aData[0]).val(); + Sunstone.runAction("VM.showinfo",id); + return false; + }); +} + +// Callback to refresh a single element from the list +function updateVMachineElement(request, vm_json){ + var id = vm_json.VM.ID; + var element = vMachineElementArray(vm_json); + updateSingleElement(element,dataTable_vMachines,'#vm_'+id) +} + +// Callback to delete a single element from the list +function deleteVMachineElement(req){ + deleteElement(dataTable_vMachines,'#vm_'+req.request.data); +} + +// Callback to add an element to the list +function addVMachineElement(request,vm_json){ + var id = vm_json.VM.ID; + var element = vMachineElementArray(vm_json); + addElement(element,dataTable_vMachines); + //Popup info panel after creation. + updateVMInfo(null,vm_json); +} + + +// Callback to refresh the list of Virtual Machines +function updateVMachinesView(request, vmachine_list){ + vmachine_list_json = vmachine_list; + var vmachine_list_array = []; + + $.each(vmachine_list,function(){ + vmachine_list_array.push( vMachineElementArray(this)); + }); + + updateView(vmachine_list_array,dataTable_vMachines); + updateDashboard("vms",vmachine_list_json); +} + + +// Refreshes the information panel for a VM +function updateVMInfo(request,vm){ + var vm_info = vm.VM; + var info_tab = { + title : "VM information", + content: '\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    Virtual Machine information - '+vm_info.NAME+'
    ID'+vm_info.ID+'
    Name'+vm_info.NAME+'
    State'+OpenNebula.Helper.resource_state("vm",vm_info.STATE)+'
    LCM State'+OpenNebula.Helper.resource_state("vm_lcm",vm_info.LCM_STATE)+'
    Start time'+pretty_time(vm_info.STIME)+'
    Deploy ID'+(typeof(vm_info.DEPLOY_ID) == "object" ? "-" : vm_info.DEPLOY_ID)+'
    \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
    Monitoring information
    Net_TX'+vm_info.NET_TX+'
    Net_RX'+vm_info.NET_RX+'
    Used Memory'+humanize_size(vm_info.MEMORY)+'
    Used CPU'+vm_info.CPU+'
    ' + } + + var template_tab = { + title: "VM Template", + content: '\ + '+ + prettyPrintJSON(vm_info.TEMPLATE)+ + '
    VM template
    ' + } + + var log_tab = { + title: "VM log", + content: '
    '+spinner+'
    ' + } + + Sunstone.updateInfoPanelTab("vm_info_panel","vm_info_tab",info_tab); + Sunstone.updateInfoPanelTab("vm_info_panel","vm_template_tab",template_tab); + Sunstone.updateInfoPanelTab("vm_info_panel","vm_log_tab",log_tab); + + + //Here it is special, as we will let the callback from the VM.log + //action popUp the info panel again when the info is received. + Sunstone.popUpInfoPanel("vm_info_panel"); + Sunstone.runAction("VM.log",vm_info.ID); + +} + +// Sets up the create-VM dialog and all the processing associated to it, +// which is a lot. +function setupCreateVMDialog(){ + + //Helper functions for the dialog operations + + // Called when changing tabs. Since we use the same form for both + // KVM, XEN and others we need to do some operation to update it + var vmTabChange = function(event,ui){ + // ui.tab // anchor element of the selected (clicked) tab + // ui.panel // element, that contains the selected/clicked tab contents + // ui.index // zero-based index of the selected (clicked) tab + switch(ui.index){ + case 0: + enable_kvm(); + break; + case 1: + enable_xen(); + break; + case 2: + break; + case 3: + break; + } + } + + //Using kvm wizard. Updates mandatory tag, optional tags, disable + //XEN-only (and others) items, enables KVM items + var enable_kvm = function(){ + man_class="kvm"; + opt_class="kvm_opt"; + $(xen_items).attr("disabled","disabled"); + $(kvm_items).removeAttr("disabled"); + //$(items+':disabled').hide(); + + + //KVM particularities: + // * Add no_type option for disks + // * Add driver default option for boot and select it - hide some fields + // * Set the raw type to kvm + // * Show the inputs section + $('div#disks select#TYPE option:selected').removeAttr("selected"); + $('div#disks select#TYPE').prepend( + ''); + $('div#disks select#TYPE option#no_type').attr("selected","selected"); + + $('select#boot_method option').removeAttr("selected"); + $('select#boot_method option#no_boot').html("Driver default"); + $('select#boot_method option').removeAttr("selected"); + $('.kernel, .bootloader', $('div#os_boot_opts')).hide(); + + $('div#disks select#BUS').append( + ''); + + + + $('input#TYPE', section_raw).val("kvm"); + + $(section_inputs).show(); + }; + + // Using XEN wizard. Update mandatory and optional classes, disable + // KVM-only (and other) items, enable XEN fields... + enable_xen = function(){ + man_class="xen"; + opt_class="xen_opt"; + $(kvm_items).attr("disabled","disabled"); + $(kvm_items).css("background",""); + $(xen_items).removeAttr("disabled"); + //$(items+':disabled').hide(); + + + // XEN particularities: + // * Remove no_type option from disks + // * Remove driver default boot method + // * Set the raw section to XEN + // * Hide the inputs section + $('div#disks select#TYPE option#no_type').remove(); + + $('select#boot_method option:selected').removeAttr("selected"); + $('select#boot_method option#no_boot').html("Please choose"); + $('.kernel, .bootloader', $('div#os_boot_opts')).hide(); + + $('div#disks select#BUS option#virtio').remove(); + + $('input#TYPE', section_raw).val("xen"); + $(section_inputs).hide(); //not present for xen + }; + + //This function checks that all mandatory items within a section + //have some value. Returns true if so, false if not. + var mandatory_filter = function(context){ + var man_items = "."+man_class; + + //find enabled mandatory items in this context + man_items = $(man_items+' input:visible, '+man_items+' select:visible',context); + var r = true; + + //we fail it the item is enabled and has no value + $.each(man_items,function(){ + if ($(this).parents(".vm_param").attr("disabled") || + !($(this).val().length)) { + r = false; + return false; + }; + }); + return r; + + }; + + //Adds an option element to a multiple select box. Before doing so, + //it checks that the desired filter is passed + var box_add_element = function(context,box_tag,filter){ + var value=""; + var params= $('.vm_param',context); + var inputs= $('input:enabled',params); + var selects = $('select:enabled',params); + var fields = $.merge(inputs,selects); + + //are fields passing the filter? + var result = filter(); + if (!result) { + notifyError("There are mandatory parameters missing in this section"); + return false; + } + + value={}; + + //With each enabled field we form a JSON object + var id = null; + $.each(fields,function(){ + if (!($(this).parents(".vm_param").attr("disabled")) && + $(this).val().length){ + //Pick up parent's ID if we do not have one + id = $(this).attr('id').length ? $(this).attr('id') : $(this).parent().attr('id'); + value[id] = $(this).val(); + } + }); + var value_string = JSON.stringify(value); + var option= ''; + $('select'+box_tag,context).append(option); + return false; + }; + + //Removes selected elements from a multiple select box + var box_remove_element = function(section_tag,box_tag){ + var context = $(section_tag); + $('select'+box_tag+' :selected',context).remove(); + return false; + }; + + //Given the JSON of a VM template (or of a section of it), it crawls + //the fields of certain section (context) and add their name and + //values to the template JSON. + var addSectionJSON = function(template_json,context){ + var params= $('.vm_param',context); + var inputs= $('input:enabled',params); + var selects = $('select:enabled',params); + var fields = $.merge(inputs,selects); + + fields.each(function(){ + if (!($(this).parents(".vm_param").attr("disabled"))){ //if ! disabled + if ($(this).val().length){ //if has a length + template_json[$(this).attr('id')]=$(this).val(); + } + } + }); + } + + // Given an array (usually empty), a section (context) and a tag for + // a multiple select in that section, it adds the contents of the + // box as objects in the array. + // TODO: Make it return a new array? + var addBoxJSON = function(array,context,box_tag){ + $('select'+box_tag+' option',context).each(function(){ + array.push( JSON.parse($(this).val()) ); + }); + } + + //Given an object, removes those elements which are empty + //Used to clean up a template JSON before submitting + //it to opennebula.js + var removeEmptyObjects = function(obj){ + for (elem in obj){ + var remove = false; + var value = obj[elem]; + if (value instanceof Array) + { + if (value.length == 0) + remove = true; + } + else if (value instanceof Object) + { + var obj_length = 0; + for (e in value) + obj_length += 1; + if (obj_length == 0) + remove = true; + } + else + { + value = String(value); + if (value.length == 0) + remove = true; + } + if (remove) + delete obj[elem]; + } + return obj; + } + + //Toggles the icon when a section is folded/unfolded + var iconToggle = function(){ + $('.icon_right').toggle( + function(e){ + $('span',e.currentTarget).removeClass("ui-icon-plusthick"); + $('span',e.currentTarget).addClass("ui-icon-minusthick"); + },function(e){ + $('span',e.currentTarget).removeClass("ui-icon-minusthick"); + $('span',e.currentTarget).addClass("ui-icon-plusthick"); + }); + } + + // Set ups the capacity section + var capacity_setup = function(){ + //Actually there is nothing to set up, but it used to be + //possible to hide it like others + /* + $('fieldset',section_capacity).hide(); + $('#add_capacity',section_capacity).click(function(){ + $('fieldset',section_capacity).toggle(); + return false; + }); + */ + + } + + //Sets up the OS_BOOT section + var os_boot_setup = function(){ + $('fieldset',section_os_boot).hide(); + $('.bootloader, .kernel',section_os_boot).hide(); + + $('#add_os_boot_opts',section_os_boot).click(function(){ + $('fieldset',section_os_boot).toggle(); + return false; + }); + + + //Chrome workaround + $('#boot_method').change(function(){ + $(this).trigger("click"); + }); + + //Depending on the boot method we enable/disable some options + $('#boot_method',section_os_boot).click(function(){ + select = $(this).val(); + switch (select) + { + case "kernel": + $('.bootloader',section_os_boot).hide(); + $('.bootloader',section_os_boot).attr("disabled","disabled"); + $('.kernel',section_os_boot).show(); + $('.kernel',section_os_boot).removeAttr("disabled"); + break; + case "bootloader": + $('.kernel',section_os_boot).hide(); + $('.kernel',section_os_boot).attr("disabled","disabled"); + $('.bootloader',section_os_boot).show(); + $('.bootloader',section_os_boot).removeAttr("disabled"); + break; + default: + $('.kernel, .bootloader',section_os_boot).hide(); + $('.kernel, .bootloader',section_os_boot).attr("disabled","disabled"); + $('.kernel input, .bootloader input',section_os_boot).val(""); + }; + }); + }; + + // Sets up the disk section + var disks_setup = function(){ + + $('fieldset',section_disks).hide(); + $('.vm_param', section_disks).hide(); + //$('#image_vs_disk',section_disks).show(); + + $('#add_disks', section_disks).click(function(){ + $('fieldset',section_disks).toggle(); + return false; + }); + + //Depending on adding a disk or a image we need to show/hide + //different options and make then mandatory or not + $('#image_vs_disk input',section_disks).click(function(){ + //$('fieldset',section_disks).show(); + $('.vm_param', section_disks).show(); + var select = $('#image_vs_disk :checked',section_disks).val(); + switch (select) + { + case "disk": + $('.add_image',section_disks).hide(); + $('.add_image',section_disks).attr("disabled","disabled"); + $('.add_disk',section_disks).show(); + $('.add_disk',section_disks).removeAttr("disabled"); + $('#TARGET',section_disks).parent().removeClass(opt_class); + $('#TARGET',section_disks).parent().addClass(man_class); + break; + case "image": + $('.add_disk',section_disks).hide(); + $('.add_disk',section_disks).attr("disabled","disabled"); + $('.add_image',section_disks).show(); + $('.add_image',section_disks).removeAttr("disabled"); + $('#TARGET',section_disks).parent().removeClass(man_class); + $('#TARGET',section_disks).parent().addClass(opt_class); + break; + } + $('#SIZE',section_disks).parent().hide(); + $('#SIZE',section_disks).parent().attr("disabled","disabled"); + $('#FORMAT',section_disks).parent().hide(); + $('#SIZE',section_disks).parent().attr("disabled","disabled"); + $('#TYPE :selected',section_disks).removeAttr("selected"); + }); + + //Chrome workaround + $('select#TYPE',section_disks).change(function(){ + $(this).trigger('click'); + }); + + //Depending on the type of disk we need to show/hide + //different options and make then mandatory or not + $('select#TYPE',section_disks).click(function(){ + var select = $(this).val(); + switch (select) { + //size,format,target + case "swap": + //size mandatory + $('#SIZE',section_disks).parent().show(); + $('#SIZE',section_disks).parent().removeAttr("disabled"); + $('#SIZE',section_disks).parent().removeClass(opt_class); + $('#SIZE',section_disks).parent().addClass(man_class); + + //target optional + $('#TARGET',section_disks).parent().removeClass(man_class); + $('#TARGET',section_disks).parent().addClass(opt_class); + + //format hidden + $('#FORMAT',section_disks).parent().hide(); + $('#FORMAT',section_disks).parent().attr("disabled","disabled"); + break; + case "fs": + //size mandatory + $('#SIZE',section_disks).parent().show(); + $('#SIZE',section_disks).parent().removeAttr("disabled"); + $('#SIZE',section_disks).parent().removeClass(opt_class); + $('#SIZE',section_disks).parent().addClass(man_class); + + //target mandatory + $('#TARGET',section_disks).parent().removeClass(opt_class); + $('#TARGET',section_disks).parent().addClass(man_class); + + //format mandatory + $('#FORMAT',section_disks).parent().show(); + $('#FORMAT',section_disks).parent().removeAttr("disabled"); + $('#FORMAT',section_disks).parent().removeClass(opt_class); + $('#FORMAT',section_disks).parent().addClass(man_class); + + break; + case "block": + //size shown and optional + $('#SIZE',section_disks).parent().show(); + $('#SIZE',section_disks).parent().removeAttr("disabled"); + $('#SIZE',section_disks).parent().removeClass(man_class); + $('#SIZE',section_disks).parent().addClass(opt_class); + + //target mandatory + $('#TARGET',section_disks).parent().removeClass(opt_class); + $('#TARGET',section_disks).parent().addClass(man_class); + + //format hidden + $('#FORMAT',section_disks).parent().hide(); + $('#FORMAT',section_disks).parent().attr("disabled","disabled"); + break; + case "floppy": + case "disk": + case "cdrom": + default: + //size hidden + $('#SIZE',section_disks).parent().hide(); + $('#SIZE',section_disks).parent().attr("disabled","disabled"); + + //target mandatory + $('#TARGET',section_disks).parent().removeClass(opt_class); + $('#TARGET',section_disks).parent().addClass(man_class); + + //format optional + $('#FORMAT',section_disks).parent().hide(); + $('#FORMAT',section_disks).parent().attr("disabled","disabled"); + } + }); + + //Our filter for the disks section fields is the mandatory + //filter for this section + var diskFilter = function(){ + return mandatory_filter(section_disks); + }; + + $('#add_disk_button',section_disks).click(function(){ + box_add_element(section_disks,'#disks_box',diskFilter); + return false; + }); + $('#remove_disk_button',section_disks).click(function(){ + box_remove_element(section_disks,'#disks_box'); + return false; + }); + }; + + // Sets up the network section + var networks_setup = function(){ + + $('.vm_param',section_networks).hide(); + $('fieldset',section_networks).hide(); + + $('#add_networks',section_networks).click(function(){ + $('fieldset',section_networks).toggle(); + return false; + }); + + //Depending on adding predefined network or not we show/hide + //some fields + $('#network_vs_niccfg input',section_networks).click(function(){ + + select = $('#network_vs_niccfg :checked',section_networks).val(); + switch (select) { + case "network": + $('.niccfg',section_networks).hide(); + $('.niccfg',section_networks).attr("disabled","disabled"); + $('.network',section_networks).show(); + $('.network',section_networks).removeAttr("disabled"); + break; + case "niccfg": + $('.network',section_networks).hide(); + $('.network',section_networks).attr("disabled","disabled"); + $('.niccfg',section_networks).show(); + $('.niccfg',section_networks).removeAttr("disabled"); + break; + } + }); + + //The filter to add a new network checks that we have selected a + //network, or that the ip or mac are set + //TODO: Improve this check + var nicFilter = function(){ + return mandatory_filter(section_networks); + }; + + $('#add_nic_button',section_networks).click(function(){ + box_add_element(section_networks,'#nics_box',nicFilter); + return false; + }); + $('#remove_nic_button',section_networks).click(function(){ + box_remove_element(section_networks,'#nics_box'); + return false; + }); + + }; + + //Sets up the input section - basicly enabling adding and removing from box + var inputs_setup = function() { + $('fieldset',section_inputs).hide(); + + $('#add_inputs',section_inputs).click(function(){ + $('fieldset',section_inputs).toggle(); + return false; + }); + + $('#add_input_button',section_inputs).click(function(){ + //no filter + box_add_element(section_inputs,'#inputs_box',True); + return false; + }); + $('#remove_input_button',section_inputs).click(function(){ + box_remove_element(section_inputs,'#inputs_box'); + return false; + }); + }; + + //Set up the graphics section + var graphics_setup = function(){ + $('fieldset',section_graphics).hide(); + $('.vm_param',section_graphics).hide(); + $('select#TYPE',section_graphics).parent().show(); + + $('#add_graphics',section_graphics).click(function(){ + $('fieldset',section_graphics).toggle(); + return false; + }); + + //Chrome workaround + $('select#TYPE',section_graphics).change(function(){ + $(this).trigger("click"); + }); + $('select#TYPE',section_graphics).click(function(){ + g_type = $(this).val(); + switch (g_type) { + case "vnc": + $('#LISTEN',section_graphics).parent().show(); + $('#PORT',section_graphics).parent().show(); + $('#PASSWD',section_graphics).parent().show(); + $('#KEYMAP',section_graphics).parent().show(); + $('#PORT',section_graphics).parent().removeAttr("disabled"); + $('#PASSWD',section_graphics).parent().removeAttr("disabled"); + $('#KEYMAP',section_graphics).parent().removeAttr("disabled"); + break; + case "sdl": + $('#LISTEN',section_graphics).parent().show(); + $('#PORT',section_graphics).parent().hide(); + $('#PASSWD',section_graphics).parent().hide(); + $('#KEYMAP',section_graphics).parent().hide(); + $('#PORT',section_graphics).parent().attr("disabled","disabled"); + $('#PASSWD',section_graphics).parent().attr("disabled","disabled"); + $('#KEYMAP',section_graphics).parent().attr("disabled","disabled"); + break; + default: + $('#LISTEN',section_graphics).parent().hide(); + $('#PORT',section_graphics).parent().hide(); + $('#PASSWD',section_graphics).parent().hide(); + $('#KEYMAP',section_graphics).parent().hide(); + + } + }); + + } + + //Set up the context section - TODO: Apply improvements here... + var context_setup = function(){ + $('fieldset',section_context).hide(); + + $('#add_context',section_context).click(function(){ + $('fieldset',section_context).toggle(); + return false; + }); + + $('#add_context_button', section_context).click(function(){ + var name = $('#var_name',section_context).val(); + var value = $('#var_value',section_context).val(); + if (!name.length || !value.length) { + notifyError("Context variable name and value must be filled in"); + return false; + } + option= ''; + $('select#context_box',section_context).append(option); + return false; + }); + + $('#remove_context_button', section_context).click(function(){ + box_remove_element(section_context,'#context_box'); + return false; + }); + + + }; + + // Set up the placement section + var placement_setup = function(){ + $('fieldset',section_placement).hide(); + + $('#add_placement',section_placement).click(function(){ + $('fieldset',section_placement).toggle(); + return false; + }); + + }; + + // Set up the raw section + var raw_setup = function(){ + $('fieldset',section_raw).hide(); + + $('#add_raw',section_raw).click(function(){ + $('fieldset',section_raw).toggle(); + return false; + }); + }; + + //***CREATE VM DIALOG MAIN BODY*** + + $('div#dialogs').append('
    '); + //Insert HTML in place + $('#create_vm_dialog').html(create_vm_tmpl); + //Enable tabs + $('#vm_create_tabs').tabs({ + select:vmTabChange + }); + + //Prepare jquery dialog + var height = Math.floor($(window).height()*0.8); //set height to a percentage of the window + $('#create_vm_dialog').dialog({ + autoOpen: false, + modal: true, + width: 700, + height: height + }); + + // Enhace buttons + $('#create_vm_dialog button').button(); + + //Enable different icon for folded/unfolded categories + iconToggle(); //toogle +/- buttons + + //Sections, used to stay within their scope + var section_capacity = $('#capacity'); + var section_os_boot = $('#os_boot_opts'); + var section_disks = $('#disks'); + var section_networks = $('#networks'); + var section_inputs = $('#inputs'); + var section_graphics = $('#graphics'); + var section_context = $('#context'); + var section_placement = $('#placement'); + var section_raw = $('#raw'); + + //Different selector for items of kvm and xen (mandatory and optional) + var items = '.vm_section input,.vm_section select'; + var kvm_man_items = '.kvm input,.kvm select'; + var kvm_opt_items = '.kvm_opt input, .kvm_opt select'; + var kvm_items = kvm_man_items +','+kvm_opt_items; + var xen_man_items = '.xen input,.xen select'; + var xen_opt_items = '.xen_opt input, .xen_opt select'; + var xen_items = xen_man_items +','+ xen_opt_items; + + //Starting template type, optional items class and mandatory items class + var templ_type = "kvm"; + var opt_class=".kvm_opt"; + var man_class=".kvm"; + + enable_kvm(); //enable all kvm options + + //Fold/unfold all sections button + $('#fold_unfold_vm_params').toggle( + function(){ + $('.vm_section fieldset').show(); + return false; + }, + function(){ + $('.vm_section fieldset').hide(); + $('.vm_section fieldset').first().show(); //Show capacity opts + return false; + }); + + //initialise all sections + capacity_setup(); + os_boot_setup(); + disks_setup(); + networks_setup(); + inputs_setup(); + graphics_setup(); + context_setup(); + placement_setup(); + raw_setup(); + + //Process form + $('button#create_vm_form_easy').click(function(){ + //validate form + + var vm_json = {}; + + //process capacity options + var scope = section_capacity; + + if (!mandatory_filter(scope)){ + notifyError("There are mandatory fields missing in the capacity section"); + return false; + }; + addSectionJSON(vm_json,scope); + + //process os_boot_opts + scope= section_os_boot; + switch (templ_type){ + case "xen": + boot_method = $('#boot_method option:selected',scope).val(); + if (!boot_method.length){ + notifyError("Xen templates must specify a boot method"); + return false;} + }; + + if (!mandatory_filter(scope)){ + notifyError("There are mandatory fields missing in the OS Boot options section"); + return false; + }; + vm_json["OS"] = {}; + addSectionJSON(vm_json["OS"],scope); + + //process disks -> fetch from box + scope = section_disks; + vm_json["DISK"] = []; + addBoxJSON(vm_json["DISK"],scope,'#disks_box'); + + //process nics -> fetch from box + scope = section_networks; + vm_json["NIC"] = []; + addBoxJSON(vm_json["NIC"],scope,'#nics_box'); + + //process inputs -> fetch from box + scope = section_inputs; + vm_json["INPUT"] = []; + addBoxJSON(vm_json["INPUT"],scope,'#inputs_box'); + + //process graphics -> fetch fields with value + scope = section_graphics; + vm_json["GRAPHICS"] = {}; + addSectionJSON(vm_json["GRAPHICS"],scope); + + //context + scope = section_context; + var context = $('#CONTEXT',scope).val(); + vm_json["CONTEXT"] = {}; + $('#context_box option',scope).each(function(){ + name = $(this).attr("name"); + value = $(this).val(); + vm_json["CONTEXT"][name]=value; + }); + + //placement -> fetch with value + scope = section_placement; + addSectionJSON(vm_json,scope); + + //raw -> if value set type to driver and fetch + scope = section_raw; + vm_json["RAW"] = {}; + addSectionJSON(vm_json["RAW"],scope); + + // remove empty elements + vm_json = removeEmptyObjects(vm_json); + + //wrap it in the "vm" object + vm_json = {vm: vm_json}; + + + Sunstone.runAction("VM.create",vm_json); + + $('#create_vm_dialog').dialog('close'); + return false; + }); + + //Handle manual forms + $('button#create_vm_form_manual').click(function(){ + var template = $('#textarea_vm_template').val(); + + //wrap it in the "vm" object + template = {"vm": {"vm_raw": template}}; + + Sunstone.runAction("VM.create",template); + $('#create_vm_dialog').dialog('close'); + return false; + }); + + //Reset form - empty boxes + $('button#reset_vm_form').click(function(){ + $('select#disks_box option',section_disks).remove(); + $('select#nics_box option',section_networks).remove(); + $('select#inputs_box option',section_inputs).remove(); + return true; + }); + + +} + +// Open creation dialog +function popUpCreateVMDialog(){ + $('#create_vm_dialog').dialog('open'); +} + +//Prepares a dialog to saveas a VM +function setupSaveasDialog(){ + //Append to DOM + $('div#dialogs').append('
    '); + + //Put HTML in place + $('#saveas_vm_dialog').html('\ +
    \ +
    \ +
    \ +
    \ + \ + \ +
    \ + \ +
    '); + + $('#saveas_vm_dialog').dialog({ + autoOpen:false, + width:600, + modal:true, + height:350, + resizable:true, + }); + + $('#saveas_vm_dialog #vm_saveas_proceed').click(function(){ + var elems = $('#saveas_vm_dialog #saveas_tabs div.saveas_tab'); + var args = []; + $.each(elems,function(){ + var id = $('#vm_id',this).text(); + var disk_id = $('#vm_disk_id',this).val(); + var image_name = $('#image_name',this).val(); + var type = $('#image_type',this).val(); + + if (!id.length || !disk_id.length || !image_name.length) { + notifyError("Skipping VM "+id+ + ". No disk id or image name specified"); + } + else { + var obj = { + vm_id: id, + disk_id : disk_id, + image_name : image_name, + type: type + }; + args.push(id); + Sunstone.runAction("VM.saveas",obj); + } + }); + if (args.length > 0){ + notifySubmit("VM.saveas",args); + } + + $('#saveas_vm_dialog').dialog('close'); + return false; + }); + + $('#saveas_vm_dialog #vm_saveas_cancel').click(function(){ + $('#saveas_vm_dialog').dialog('close'); + return false; + }); + +} + +function popUpSaveasDialog(elems){ + $('#saveas_vm_dialog #saveas_tabs').tabs('destroy'); + $('#saveas_vm_dialog #saveas_tabs').empty(); + $('#saveas_vm_dialog #saveas_tabs').html('
      '); + + $.each(elems,function(){ + var li = '
    • VM '+this+'
    • ' + $('#saveas_vm_dialog #saveas_tabs ul').append(li); + var tab = '
      \ +
      Saveas for VM with ID '+this+'
      \ +
      \ +
      \ + \ + \ +
      \ +
      \ + \ + \ +
      \ +
      \ + \ + \ +
      \ +
      \ +
      '; + $('#saveas_vm_dialog #saveas_tabs').append(tab); + }); + $('#saveas_vm_dialog #saveas_tabs').tabs(); + $('#saveas_vm_dialog button').button(); + + $('#saveas_vm_dialog').dialog('open'); +} + +//Prepares autorefresh +function setVMAutorefresh(){ + setInterval(function(){ + var checked = $('input:checked',dataTable_vMachines.fnGetNodes()); + var filter = $("#datatable_vmachines_filter input").attr("value"); + if (!checked.length && !filter.length){ + Sunstone.runAction("VM.autorefresh"); + } + },INTERVAL+someTime()); //so that not all refreshing is done at the same time +} + +// At this point the DOM is ready and the sunstone.js ready() has been run. +$(document).ready(function(){ + + dataTable_vMachines = $("#datatable_vmachines").dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "sPaginationType": "full_numbers", + "bAutoWidth":false, + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0] }, + { "sWidth": "35px", "aTargets": [1] }, + { "sWidth": "100px", "aTargets": [2] } + ] + }); + + dataTable_vMachines.fnClearTable(); + addElement([ + spinner, + '','','','','','','',''],dataTable_vMachines); + Sunstone.runAction("VM.list"); + + setupCreateVMDialog(); + setupSaveasDialog(); + setVMAutorefresh(); + + initCheckAllBoxes(dataTable_vMachines); + tableCheckboxesListener(dataTable_vMachines); + vMachineInfoListener(); + setupTips($('#create_vm_dialog')); +}) diff --git a/src/sunstone/public/js/plugins/vnets-tab.js b/src/sunstone/public/js/plugins/vnets-tab.js new file mode 100644 index 0000000000..da05b8a849 --- /dev/null +++ b/src/sunstone/public/js/plugins/vnets-tab.js @@ -0,0 +1,587 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ +/* -------------------------------------------------------------------------- */ + +/*Virtual networks tab plugin*/ + +var vnets_tab_content = +'
      \ +
      \ +
      \ +\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
      AllIDUserNameTypeBridgePublic?Total Leases
      \ +
      '; + +var create_vn_tmpl = +'
      \ + \ +
      \ +
      \ +
      \ + \ +
      \ +
      \ +
      \ + \ +
      \ +
      \ +
      \ + \ + Fixed network
      \ + Ranged network
      \ +
      \ +
      \ +
      \ +
      \ +
      \ + \ +
      \ + \ + \ +
      \ + \ + \ + \ +
      \ +
      \ +
      \ +
      \ +
      \ + \ +
      \ + \ + \ +
      \ +
      \ +
      \ +
      \ + \ +
      \ +
      \ + \ + \ +
      \ +
      \ +
      \ +
      \ +
      \ +
      \ +

      Write the Virtual Network template here

      \ +
      \ + \ +
      \ +
      \ +
      \ +
      \ + \ + \ +
      \ +
      \ +
      \ +
      \ +
      '; + +var vnetworks_select=""; +var network_list_json = {}; +var dataTable_vNetworks; + +//Setup actions + +var vnet_actions = { + "Network.create" : { + type: "create", + call: OpenNebula.Network.create, + callback: addVNetworkElement, + error: onError, + notify: true + }, + + "Network.create_dialog" : { + type: "custom", + call: popUpCreateVnetDialog + }, + + "Network.list" : { + type: "list", + call: OpenNebula.Network.list, + callback: updateVNetworksView, + error: onError + }, + + "Network.show" : { + type: "single", + call: OpenNebula.Network.show, + callback: updateVNetworkElement, + error: onError + }, + + "Network.showinfo" : { + type: "single", + call: OpenNebula.Network.show, + callback: updateVNetworkInfo, + error: onError + + }, + + "Network.refresh" : { + type: "custom", + call: function(){ + waitingNodes(dataTable_vNetworks); + Sunstone.runAction("Network.list"); + } + }, + + "Network.autorefresh" : { + type: "custom", + call: function() { + OpenNebula.Network.list({timeout: true, success: updateVNetworksView, error: onError}); + } + }, + + "Network.publish" : { + type: "multiple", + call: OpenNebula.Network.publish, + callback: function (req) { + Sunstone.runAction("Network.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vNetworks); }, + error: onError, + notify: true + }, + + "Network.unpublish" : { + type: "multiple", + call: OpenNebula.Network.unpublish, + callback: function (req) { + Sunstone.runAction("Network.show",req.request.data[0]); + }, + elements: function() { return getSelectedNodes(dataTable_vNetworks); }, + error: onError, + notify: true + }, + + "Network.delete" : { + type: "multiple", + call: OpenNebula.Network.delete, + callback: deleteVNetworkElement, + elements: function() { return getSelectedNodes(dataTable_vNetworks); }, + error: onError, + notify: true + } + +} + + +var vnet_buttons = { + "Network.refresh" : { + type: "image", + text: "Refresh list", + img: "/images/Refresh-icon.png", + condition: True + }, + + "Network.create_dialog" : { + type: "create_dialog", + text: "+ New", + condition: True + }, + + "Network.publish" : { + type: "action", + text: "Publish", + condition: True + }, + + "Network.unpublish" : { + type: "action", + text: "Unpublish", + condition: True + }, + + "Network.delete" : { + type: "action", + text: "Delete", + condition: True + } +} + +var vnet_info_panel = { + "vnet_info_tab" : { + title: "Virtual network information", + content: "" + }, + "vnet_template_tab" : { + title: "Virtual network template", + content: "" + } +} + +var vnets_tab = { + title: "Virtual Networks", + content: vnets_tab_content, + buttons: vnet_buttons, + condition: True +} + +Sunstone.addActions(vnet_actions); +Sunstone.addMainTab('vnets_tab',vnets_tab); +Sunstone.addInfoPanel('vnet_info_panel',vnet_info_panel); + +//returns an array with the VNET information fetched from the JSON object +function vNetworkElementArray(vn_json){ + var network = vn_json.VNET; + var total_leases = "0"; + + if (network.TOTAL_LEASES){ + total_leases = network.TOTAL_LEASES; + } else if (network.LEASES && network.LEASES.LEASE){ + total_leases = network.LEASES.LEASE.length ? network.LEASES.LEASE.length : "1"; + } + + //Does the JSON bring a username field? Otherwise try + //to get it from the users dataTable + var username = network.USERNAME? network.USERNAME : getUserName(network.UID) + + + return ['', + network.ID, + username, + network.NAME, + parseInt(network.TYPE) ? "FIXED" : "RANGED", + network.BRIDGE, + parseInt(network.PUBLIC) ? "yes" : "no", + total_leases ]; +} + + +//Adds a listener to show the extended info when clicking on a row +function vNetworkInfoListener(){ + + $('#tbodyvnetworks tr').live("click", function(e){ + if ($(e.target).is('input')) {return true;} + popDialogLoading(); + var aData = dataTable_vNetworks.fnGetData(this); + var id = $(aData[0]).val(); + Sunstone.runAction("Network.showinfo",id); + return false; + }); +} + +//updates the vnet select different options +function updateNetworkSelect(){ + vnetworks_select= makeSelectOptions(dataTable_vNetworks,1,3,6,"no") + + //update static selectors: + //in the VM creation dialog + $('div.vm_section#networks select#NETWORK_ID').html(vnetworks_select); +} + +//Callback to update a vnet element after an action on it +function updateVNetworkElement(request, vn_json){ + id = vn_json.VNET.ID; + element = vNetworkElementArray(vn_json); + updateSingleElement(element,dataTable_vNetworks,'#vnetwork_'+id); + updateNetworkSelect(); +} + +//Callback to delete a vnet element from the table +function deleteVNetworkElement(req){ + deleteElement(dataTable_vNetworks,'#vnetwork_'+req.request.data); + updateNetworkSelect(); +} + +//Callback to add a new element +function addVNetworkElement(request,vn_json){ + var element = vNetworkElementArray(vn_json); + addElement(element,dataTable_vNetworks); + updateNetworkSelect(); +} + +//updates the list of virtual networks +function updateVNetworksView(request, network_list){ + network_list_json = network_list; + var network_list_array = []; + + $.each(network_list,function(){ + network_list_array.push(vNetworkElementArray(this)); + }); + + updateView(network_list_array,dataTable_vNetworks); + updateNetworkSelect(); + //dependency with dashboard + updateDashboard("vnets",network_list_json); + +} + +//updates the information panel tabs and pops the panel up +function updateVNetworkInfo(request,vn){ + var vn_info = vn.VNET; + var info_tab_content = + '\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
      Virtual Network '+vn_info.ID+' information
      ID'+vn_info.ID+'
      UID'+vn_info.UID+'
      Public'+(parseInt(vn_info.PUBLIC) ? "yes" : "no" )+'
      '; + + //if it is a fixed VNET we can add leases information + if (vn_info.TEMPLATE.TYPE == "FIXED"){ + info_tab_content += '\ + \ + \ + '+ + prettyPrintJSON(vn_info.LEASES)+ + '
      Leases information
      '; + } + + + var info_tab = { + title: "Virtual Network information", + content: info_tab_content + } + + var template_tab = { + title: "Virtual Network template", + content: '\ + '+ + prettyPrintJSON(vn_info.TEMPLATE)+ + '
      Virtual Network template
      ' + } + + Sunstone.updateInfoPanelTab("vnet_info_panel","vnet_info_tab",info_tab); + Sunstone.updateInfoPanelTab("vnet_info_panel","vnet_template_tab",template_tab); + + Sunstone.popUpInfoPanel("vnet_info_panel"); + +} + + +//Prepares the vnet creation dialog +function setupCreateVNetDialog() { + + $('div#dialogs').append('
      '); + $('#create_vn_dialog').html(create_vn_tmpl); + + + //Prepare the jquery-ui dialog. Set style options here. + $('#create_vn_dialog').dialog({ + autoOpen: false, + modal: true, + width: 475, + height: 500 + }); + + //Make the tabs look nice for the creation mode + $('#vn_tabs').tabs(); + $('div#ranged').hide(); + $('#fixed_check').click(function(){ + $('div#fixed').show(); + $('div#ranged').hide(); + }); + $('#ranged_check').click(function(){ + $('div#fixed').hide(); + $('div#ranged').show(); + }); + $('#create_vn_dialog button').button(); + + + //When we hit the add lease button... + $('#add_lease').click(function(){ + var create_form = $('#create_vn_form_easy'); //this is our scope + + //Fetch the interesting values + var lease_ip = $('#leaseip',create_form).val(); + var lease_mac = $('#leasemac',create_form).val(); + + //We don't add anything to the list if there is nothing to add + if (lease_ip == null) { + notifyError("Please provide a lease IP"); + return false; + }; + + + var lease = ""; //contains the HTML to be included in the select box + if (lease_mac == "") { + lease=''; + } else { + lease=''; + }; + + //We append the HTML into the select box. + $('select#leases').append(lease); + return false; + }); + + $('#remove_lease').click(function(){ + $('select#leases :selected').remove(); + return false; + }); + + //Handle submission of the easy mode + $('#create_vn_form_easy').submit(function(){ + //Fetch values + var name = $('#name',this).val(); + if (!name.length){ + notifyError("Virtual Network name missing!"); + return false; + } + var bridge = $('#bridge',this).val(); + var type = $('input:checked',this).val(); + + //TODO: Name and bridge provided?! + + var network_json = null; + if (type == "fixed") { + var leases = $('#leases option', this); + var leases_obj=[]; + + //for each specified lease we prepare the JSON object + $.each(leases,function(){ + leases_obj.push({"ip": $(this).val() }); + }); + + //and construct the final data for the request + network_json = { + "vnet" : { + "type" : "FIXED", + "leases" : leases_obj, + "bridge" : bridge, + "name" : name }}; + } + else { //type ranged + + var network_addr = $('#net_address',this).val(); + var network_size = $('#net_size',this).val(); + if (!network_addr.length){ + notifyError("Please provide a network address"); + return false; + }; + + //we form the object for the request + network_json = { + "vnet" : { + "type" : "RANGED", + "bridge" : bridge, + "network_size" : network_size, + "network_address" : network_addr, + "name" : name } + }; + }; + + //Create the VNetwork. + + Sunstone.runAction("Network.create",network_json); + $('#create_vn_dialog').dialog('close'); + return false; + }); + + $('#create_vn_form_manual').submit(function(){ + var template=$('#template',this).val(); + var vnet_json = {vnet: {vnet_raw: template}}; + Sunstone.runAction("Network.create",vnet_json); + $('#create_vn_dialog').dialog('close'); + return false; + }); +} + +function popUpCreateVnetDialog() { + $('#create_vn_dialog').dialog('open'); +} + +function setVNetAutorefresh() { + setInterval(function(){ + var checked = $('input:checked',dataTable_vNetworks.fnGetNodes()); + var filter = $("#datatable_vnetworks_filter input").attr("value"); + if (!checked.length && !filter.length){ + Sunstone.runAction("Network.autorefresh"); + } + },INTERVAL+someTime()); +} + +//The DOM is ready and the ready() from sunstone.js +//has been executed at this point. +$(document).ready(function(){ + + dataTable_vNetworks = $("#datatable_vnetworks").dataTable({ + "bJQueryUI": true, + "bSortClasses": false, + "bAutoWidth":false, + "sPaginationType": "full_numbers", + "aoColumnDefs": [ + { "bSortable": false, "aTargets": ["check"] }, + { "sWidth": "60px", "aTargets": [0,4,5,6,7] }, + { "sWidth": "35px", "aTargets": [1] }, + { "sWidth": "100px", "aTargets": [2] } + ] + }); + + dataTable_vNetworks.fnClearTable(); + addElement([ + spinner, + '','','','','','',''],dataTable_vNetworks); + Sunstone.runAction("Network.list"); + + + setupCreateVNetDialog(); + setVNetAutorefresh(); + + initCheckAllBoxes(dataTable_vNetworks); + tableCheckboxesListener(dataTable_vNetworks); + vNetworkInfoListener(); + + +}); diff --git a/src/sunstone/public/js/sunstone-util.js b/src/sunstone/public/js/sunstone-util.js new file mode 100644 index 0000000000..59a2c54434 --- /dev/null +++ b/src/sunstone/public/js/sunstone-util.js @@ -0,0 +1,404 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ +/* -------------------------------------------------------------------------- */ + + +/* Some useful functions for Sunstone default plugins */ +var INTERVAL=60000; + +function someTime(){ + return Math.floor(Math.random()*30000); +} + +//introduces 0s before a number until in reaches 'length'. +function pad(number,length) { + var str = '' + number; + while (str.length < length) + str = '0' + str; + return str; +} + +//turns a Unix-formatted time into a human readable string +function pretty_time(time_seconds) +{ + var d = new Date(); + d.setTime(time_seconds*1000); + + var secs = pad(d.getSeconds(),2); + var hour = pad(d.getHours(),2); + var mins = pad(d.getMinutes(),2); + var day = pad(d.getDate(),2); + var month = pad(d.getMonth(),2); + var year = d.getFullYear(); + + return hour + ":" + mins +":" + secs + " " + month + "/" + day + "/" + year; +} + +//returns a human readable size in Kilo, Mega, Giga or Tera bytes +function humanize_size(value) { + if (typeof(value) === "undefined") { + value = 0; + } + var binarySufix = ["K", "M", "G", "T" ]; + var i=0; + while (value > 1024 && i < 3){ + value = value / 1024; + i++; + } + value = Math.round(value * 10) / 10; + + if (value - Math.round(value) == 0) { + value = Math.round(value); + } + + var st = value + binarySufix[i]; + return st; +} + +//Wrapper to add an element to a dataTable +function addElement(element,data_table){ + data_table.fnAddData(element); +} + +//deletes an element with id 'tag' from a dataTable +function deleteElement(data_table,tag){ + var tr = $(tag).parents('tr')[0]; + data_table.fnDeleteRow(tr); + $('input',data_table).trigger("change"); +} + +//Listens to the checkboxes of the datatable. This function is used +//by standard sunstone plugins to enable/disable certain action buttons +//according to the number of elements checked in the dataTables. +//It also checks the "check-all" box when all elements are checked +function tableCheckboxesListener(dataTable){ + + //Initialization - disable all buttons + var context = dataTable.parents('form'); + var last_action_b = $('.last_action_button',context); + $('.top_button, .list_button',context).button("disable"); + if (last_action_b.length && last_action_b.val().length){ + last_action_b.button("disable"); + }; + $('.create_dialog_button',context).button("enable"); + + //listen to changes in the visible inputs + $('tbody input',dataTable).live("change",function(){ + var table = $(this).parents('tbody'); + var context = table.parents('form'); + var nodes = $('tr',table); + var total_length = nodes.length; + var checked_length = $('input:checked',nodes).length; + + var last_action_b = $('.last_action_button',context); + + + //if all elements are checked we check the check-all box + if (total_length == checked_length && total_length != 0){ + $('.check_all',dataTable).attr("checked","checked"); + } else { + $('.check_all',dataTable).removeAttr("checked"); + } + + //if some element is checked, we enable buttons, otherwise + //we disable them. + if (checked_length){ + $('.top_button, .list_button',context).button("enable"); + //check if the last_action_button should be enabled + if (last_action_b.length && last_action_b.val().length){ + last_action_b.button("enable"); + }; + } else { + $('.top_button, .list_button',context).button("disable"); + last_action_b.button("disable"); + } + + //any case the create dialog buttons should always be enabled. + $('.create_dialog_button',context).button("enable"); + }); + +} + +// Updates a data_table, with a 2D array containing the new values +// Does a partial redraw, so the filter and pagination are kept +function updateView(item_list,data_table){ + if (data_table!=null) { + data_table.fnClearTable(); + data_table.fnAddData(item_list); + data_table.fnDraw(false); + }; +} + +//replaces an element with id 'tag' in a dataTable with a new one +function updateSingleElement(element,data_table,tag){ + var nodes = data_table.fnGetNodes(); + var tr = $(tag,nodes).parents('tr')[0]; + var position = data_table.fnGetPosition(tr); + data_table.fnUpdate(element,position,0,false); + $('input',data_table).trigger("change"); + +} + +// Returns an string in the form key=value key=value ... +// Does not explore objects in depth. +function stringJSON(json){ + var str = "" + for (field in json) { + str+= field + '=' + json[field] + ' '; + } + return str; +} + +//Notifications +//Notification of submission of action +function notifySubmit(action, args, extra_param){ + var action_text = action.replace(/OpenNebula\./,'').replace(/\./,' '); + + var msg = "

      Submitted

      "; + if (!args || (typeof args == 'object' && args.constructor != Array)){ + msg += action_text; + } else { + msg += action_text + ": " + args; + } + if (extra_param != null) + msg += " >> " + extra_param; + + $.jGrowl(msg, {theme: "jGrowl-notify-submit"}); +} + +//Notification on error +function notifyError(msg){ + msg = "

      Error

      " + msg; + + $.jGrowl(msg, {theme: "jGrowl-notify-error", sticky: true }); +} + +// Returns an HTML string with the json keys and values in the form +// key: value
      +// It recursively explores objects, and flattens their contents in +// the result. +function prettyPrintJSON(template_json){ + var str = "" + for (field in template_json) { + if (typeof template_json[field] == 'object'){ + str += prettyPrintJSON(template_json[field]) + ''; + } else { + str += ''+field+''+template_json[field]+''; + }; + }; + return str; +} + +//Add a listener to the check-all box of a datatable, enabling it to +//check and uncheck all the checkboxes of its elements. +function initCheckAllBoxes(datatable){ + //not showing nice in that position + //$('.check_all').button({ icons: {primary : "ui-icon-check" }, + // text : true}); + + //small css hack + $('.check_all',datatable).css({"border":"2px"}); + $('.check_all',datatable).click(function(){ + if ($(this).attr("checked")) { + $('tbody input:checkbox', + $(this).parents("table")).each(function(){ + $(this).attr("checked","checked"); + }); + + } else { + $('tbody input:checkbox', + $(this).parents("table")).each(function(){ + $(this).removeAttr("checked"); + }); + } + $('tbody input:checkbox',$(this).parents("table")).trigger("change"); + }); +} + +//standard handling for the server errors on ajax requests. +//Pops up a message with the information. +function onError(request,error_json) { + var method; + var action; + var object; + var id; + var reason; + var m; + var message = error_json.error.message; + + //redirect to login if unauthenticated + if (error_json.error.http_status=="401") { + window.location.href = "/login"; + }; + + if (!message){ + notifyError("Cannot contact server: is Sunstone server running and reachable?"); + return false; + } + + //Parse known errors: + var action_error = /^\[(\w+)\] Error trying to (\w+) (\w+) \[(\w+)\].*Reason: (.*)\.$/; + var action_error_noid = /^\[(\w+)\] Error trying to (\w+) (\w+) (.*)\.$/; + var get_error = /^\[(\w+)\] Error getting (\w+) \[(\w+)\]\.$/; + var auth_error = /^\[(\w+)\] User \[.\] not authorized to perform (\w+) on (\w+) \[?(\w+)\]?\.?$/; + + if (m = message.match(action_error)) { + method = m[1]; + action = m[2]; + object = m[3]; + id = m[4]; + reason = m[5]; + } else if (m = message.match(action_error_noid)) { + method = m[1]; + action = m[2]; + object = m[3]; + reason = m[4]; + } else if (m = message.match(get_error)) { + method = m[1]; + action = "SHOW"; + object = m[2]; + id = m[3]; + } else if (m = message.match(auth_error)) { + method = m[1]; + action = m[2]; + object = m[3]; + id = m[4]; + } + + if (m) { + var rows; + var i; + var value; + rows = ["method","action","object","id","reason"]; + message = ""; + for (i in rows){ + key = rows[i]; + value = eval(key); + if (value) + message += ""+key+""+value+""; + } + message = "" + message + "
      "; + } + + notifyError(message); + return true; +} + +//Replaces the checkboxes of a datatable with a ajax-loading spinner. +//Used when refreshing elements of a datatable. +function waitingNodes(dataTable){ + var nodes = dataTable.fnGetData(); + for (var i=0;i'); + $(this).append(''); + + $(this).append(''); + + //add the text to .tipspan + $('span.tipspan',this).html(tip); + //make sure it is not floating in the wrong place + $(this).parent().append('
      '); + //hide the text + $('span.tipspan',this).hide(); + + //When the mouse is hovering on the icon we fadein/out + //the tip text + $('span.info_icon',this).hover(function(e){ + var top, left; + top = e.pageY - 15;// - $(this).parents('#create_vm_dialog').offset().top - 15; + left = e.pageX + 15;// - $(this).parents('#create_vm_dialog').offset().left; + $(this).next().css( + {"top":top+"px", + "left":left+"px"}); + $(this).next().fadeIn(); + },function(){ + $(this).next().fadeOut(); + }); + }); +} + +//returns an array of ids of selected elements in a dataTable +function getSelectedNodes(dataTable){ + var selected_nodes = []; + if (dataTable != null){ + //Which rows of the datatable are checked? + var nodes = $('input:checked',$('tbody',dataTable)); + $.each(nodes,function(){ + selected_nodes.push($(this).val()); + }); + } + return selected_nodes; +} + +//returns a HTML string with a select input code generated from +//a dataTable +function makeSelectOptions(dataTable,id_col,name_col,status_col,status_bad){ + var nodes = dataTable.fnGetData(); + var select = ""; + var array; + $.each(nodes,function(){ + var id = this[id_col]; + var name = this[name_col]; + var status = this[status_col]; + if (status != status_bad){ + select +=''; + } + }); + return select; +} + +//functions that used as true and false conditions for testing mainly +function True(){ + return true; +} +function False(){ + return false; +} diff --git a/src/sunstone/public/js/sunstone.js b/src/sunstone/public/js/sunstone.js new file mode 100644 index 0000000000..dad3ae4cb6 --- /dev/null +++ b/src/sunstone/public/js/sunstone.js @@ -0,0 +1,654 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.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. */ +/* -------------------------------------------------------------------------- */ + +var cookie = {}; +var username = ''; +var uid = ''; +var spinner = 'retrieving'; + + +//Sunstone configuration is formed by predifined "actions", main tabs +//and "info_panels". Each tab has "content" and "buttons". Each +//"info_panel" has "tabs" with "content". +var SunstoneCfg = { + "actions" : {}, + "tabs" : {}, + "info_panels" : {} +}; + +/* Public plugin interface */ + +var Sunstone = { + + //Adds a predifined action + "addAction" : function (action_name,action_obj) { + SunstoneCfg["actions"][action_name] = action_obj; + }, + + //Replaces a predefined action + "updateAction" : function(action_name,action_obj) { + SunstoneCfg["actions"][action_name] = action_obj; + }, + + //Deletes a predefined action. + "removeAction" : function(action_name) { + delete SunstoneCfg["actions"][action_name]; + }, + + //Adds several actions encapsulated in an js object. + "addActions" : function(actions) { + for (action in actions){ + Sunstone.addAction(action,actions[action]); + } + }, + + //Adds a new main tab. Refreshes the dom if wanted. + "addMainTab" : function(tab_id,tab_obj,refresh) { + SunstoneCfg["tabs"][tab_id] = tab_obj; + if (refresh){ + insertTab(tab_id); + } + }, + + //Updates the content of an info tab and refreshes the DOM if wanted. + "updateMainTabContent" : function(tab_id,content_arg,refresh){ + SunstoneCfg["tabs"][tab_id]["content"]=content_arg; + if (refresh){ //if not present it won't be updated + $('div#'+tab_id).html(content_arg); + } + }, + + //Replaces the buttons of an info tab and regenerates them if wanted. + "updateMainTabButtons" : function(tab_id,buttons_arg,refresh){ + SunstoneCfg["tabs"][tab_id]["buttons"]=buttons_arg; + if (refresh){ + $('div#'+tab_id+' .action_blocks').empty(); + insertButtonsInTab(tab_id); + } + }, + + //Removes a tab and refreshes the DOM + "removeMainTab" : function(tab_id,refresh) { + delete SunstoneCfg["tabs"][tab_id]; + if (refresh) { + $('div#'+tab_id).remove(); + $('ul#navigation li#li_'+tab_id).remove(); + } + }, + + //Adds a new info panel + "addInfoPanel" : function(panel_name, panel_obj){ + SunstoneCfg["info_panels"][panel_name]=panel_obj; + }, + + //Replaces an existing info panel + "updateInfoPanel" : function(panel_name,panel_obj){ + SunstoneCfg["info_panels"][panel_name]=panel_obj; + }, + + //Removes an info panel + "removeInfoPanel" : function(panel_name){ + delete SunstoneCfg["info_panels"][panel_name]; + }, + + //Makes an info panel content pop up in the screen. + "popUpInfoPanel" : function(panel_name, selected_tab){ + popDialog(Sunstone.getInfoPanelHTML(panel_name, selected_tab)); + }, + + //Generates and returns the HTML div element for an info panel, with + //Jquery tabs. + "getInfoPanelHTML" : function(panel_name,selected_tab){ + var info_panel = $('
        '); + var tabs = SunstoneCfg["info_panels"][panel_name]; + var tab=null; + for (tab_name in tabs){ + tab=tabs[tab_name]; + $('ul',info_panel).append('
      • '+tab.title+'
      • '); + info_panel.append('
        '+tab.content+'
        '); + } + if (selected_tab){ + return info_panel.tabs({selected: selected_tab}); + } + return info_panel.tabs({selected: 0}); + + }, + + //adds a tab to an info panel. + "addInfoPanelTab" : function(panel_name, panel_tab_id, panel_tab_obj){ + SunstoneCfg["info_panels"][panel_name][panel_tab_id] = panel_tab_obj; + }, + + //Replaces a tab from an info panel. Refreshes the DOM if wanted. + "updateInfoPanelTab" : function(panel_name, panel_tab_id, + panel_tab_obj, refresh){ + SunstoneCfg["info_panels"][panel_name][panel_tab_id] = panel_tab_obj; + if (refresh){ + var tab_content = panel_tab_obj.content; + $('div#'+panel_name+' div#'+panel_tab_id).html(tab_content); + } + }, + + //Removes a tab from an info panel configuration. + "removeInfoPanelTab" : function(panel_name,panel_tab_id){ + delete SunstoneCfg["info_panels"][panel_name][panel_tab_id]; + }, + + //Runs a predefined action. Wraps the calls to opennebula.js and + //can be use to run action depending on conditions and notify them + //if desired. + "runAction" : function(action, data_arg, extra_param){ + + var actions = SunstoneCfg["actions"]; + if (!actions[action]){ + notifyError("Action "+action+" not defined"); + return; + } + + var action_cfg = actions[action]; + var notify = action_cfg.notify; + + var condition = action_cfg["condition"]; + + //Is the condition to run the action met? + //Should we inform if it is not met? + if (condition && !condition()){ + if (notify) { + notifyError("This action cannot be run"); + } + return; + } + + var call = action_cfg["call"]; + var callback = action_cfg["callback"]; + var err = action_cfg["error"]; + + + //Time to close any confirmation dialogs, as the execution may have + //come from them. + $('div#confirm_with_select_dialog').dialog("close"); + $('div#confirm_dialog').dialog("close"); + + + //We ease the use of: + // * "create" calls to opennebula.js + // * "single" element calls to opennebula.js + // * "list" (get the pool of elements) calls to opennebula.js + // * "multiple" - actions to be run on a given list of elements + // (with maybe an extra parameter). + // * The default actions. Simple call the the pre-defined "call" + // function with an extraparam if defined. + switch (action_cfg.type){ + + case "create": + case "register": + call({data:data_arg, success: callback, error:err}); + break; + case "single": + call({data:{id:data_arg}, success: callback,error:err}); + break; + case "list": + call({success: callback, error:err}); + break; + case "multiple": + //run on the list of nodes that come on the data + $.each(data_arg,function(){ + if (extra_param){ + call({data:{id:this,extra_param:extra_param}, success: callback, error: err}); + } else { + call({data:{id:this}, success: callback, error:err}); + } + }); + break; + default: + //This action is complemente handled by the "call" function. + //we pass any data if present. + if (data_arg && extra_param) {call(data_arg,extra_param);} + else if (data_arg) {call(data_arg);} + else {call();} + } + //notify submission + if (notify) { + notifySubmit(action,data_arg,extra_param); + } + + + }, + + //Runs a predefined action on the selected nodes of a datatable. + //Optionally they are run with an extra_parameter. + //If no datatable is provided, it simply runs the action. + //~ "runActionOnDatatableNodes": function(action,dataTable,extra_param){ + //~ if (dataTable != null){ + //~ + //~ //Which rows of the datatable are checked? + //~ var nodes = $('input:checked',dataTable.fnGetNodes()); + //~ var data = []; + //~ $.each(nodes,function(){ + //~ data.push($(this).val()); + //~ }); + //~ Sunstone.runAction(action,data,extra_param); + //~ + //~ } else { + //~ Sunstone.runAction(action,extra_param); + //~ }; + //~ }, + //~ + //returns a button object from the desired tab + "getButton" : function(tab_id,button_name){ + var button = null; + var buttons = SunstoneCfg["tabs"][tab_id]["buttons"]; + button = buttons[button_name]; + //not found, is it in the list then? + if (!button && buttons["action_list"]) + { + button = buttons["action_list"]["actions"][button_name]; + } + return button; + } //end sunstone methods + +}; + + + + + +//Plugins have done their pre-ready jobs when we execute this. That means +//all startup configuration is in place regarding tabs, info panels etc. +$(document).ready(function(){ + readCookie(); + setLogin(); + + //Insert the tabs in the DOM and their buttons. + insertTabs(); + insertButtons(); + + //Enhace the look of select buttons + initListButtons(); + + //Prepare the standard confirmation dialogs + setupConfirmDialogs(); + + //Listen for .action_buttons + //An action buttons runs a predefined action. If it has type + //"multiple" it runs that action on the elements of a datatable. + $('.action_button').live("click",function(){ + + var table = null; + var value = $(this).attr("value"); + var action = SunstoneCfg["actions"][value]; + if (!action) { notifyError("Action "+value+" not defined."); return false;}; + switch (action.type){ + case "multiple": //find the datatable + var nodes = action.elements(); + Sunstone.runAction(value,nodes); + break; + default: + Sunstone.runAction(value); + } + return false; + }); + + + //Listen .confirm_buttons. These buttons show a confirmation dialog + //before running the action. + $('.confirm_button').live("click",function(){ + popUpConfirmDialog(this); + return false; + }); + + //Listen .confirm_buttons. These buttons show a confirmation dialog + //with a select box before running the action. + $('.confirm_with_select_button').live("click",function(){ + popUpConfirmWithSelectDialog(this); + return false; + }); + + //Jquery-enhace the buttons in the DOM + $('button').button(); + + //Close overlay dialogs when clicking outside of them. + $(".ui-widget-overlay").live("click", function (){ + $("div:ui-dialog:visible").dialog("close"); + }); + + //Close select lists when clicking somewhere else. + $('*:not(.action_list,.list_button)').click(function(){ + $('.action_list:visible').hide(); + }); + + //Start with the dashboard (supposing we have one). + showTab('#dashboard_tab'); + +}); + + + + +//reads the cookie and places its info in the 'cookie' var +function readCookie(){ + $.each(document.cookie.split("; "), function(i,e){ + var e_split = e.split("="); + var key = e_split[0]; + var value = e_split[1]; + cookie[key] = value; + }); +} + +//sets the user info in the top bar and creates a listner in the +//signout button +function setLogin(){ + //This two variables can be used anywhere + username = cookie["one-user"]; + uid = cookie["one-user_id"]; + + $("#user").html(username); + $("#logout").click(function(){ + OpenNebula.Auth.logout({success:function(){ + window.location.href = "/login"; + } + }); + return false; + }); +} + +//Inserts all main tabs in the DOM +function insertTabs(){ + var tab_info; + for (tab in SunstoneCfg["tabs"]){ + insertTab(tab); + } +} + + +//Inserts a main tab in the DOM. This is done by +//adding the content to the proper div and by adding a list item +//link to the navigation menu +function insertTab(tab_name){ + var tab_info = SunstoneCfg["tabs"][tab_name]; + var condition = tab_info["condition"]; + //skip this tab if we do not meet the condition + if (condition && !condition()) {return;} + $("div.inner-center").append('
        '); + $('div#'+tab_name).html(tab_info.content); + + $('ul#navigation').append('
      • '+tab_info.title+'
      • '); +} + + +//Inserts the buttons of all tabs. +function insertButtons(){ + for (tab in SunstoneCfg["tabs"]){ + insertButtonsInTab(tab) + } +} + +//If we have defined a block of action buttons in a tab, +//this function takes care of inserting them in the DOM. +function insertButtonsInTab(tab_name){ + var buttons = SunstoneCfg["tabs"][tab_name]["buttons"]; + var button_code=""; + var sel_obj=null; + var condition=null; + + //Check if we have included an appropiate space our tab to + //insert them (an .action_blocks div) + if ($('div#'+tab_name+' div.action_blocks').length){ + + //for every button defined for this tab... + for (button_name in buttons){ + button_code = ""; + button = buttons[button_name]; + condition = button.condition; + //if we meet the condition we proceed. Otherwise we skip it. + if (condition && !condition()) { continue; } + + //depending on the type of button we generate different + //code. There are 4 possible types: + /* + * select: We need to create a select element with actions inside. + * image: a button consisting of a link with an image inside. + * create: we make sure they have the "action_button" class. + * default: generally buttons have the "_button" class. + */ + switch (button.type) { + case "select": + button_code = ''; + break; + case "image": + button_code = ''+button.text+''; + break; + case "create_dialog": + button_code = ''; + break; + default: + button_code = ''; + + } + + $('div#'+tab_name+' .action_blocks').append(button_code); + + }//for each button in tab + $('.top_button').button(); + }//if tab exists +} + +//Converts selects into buttons which show a list of actions when +//clicked. This lists have two parts, one for the last action run, and +//another containing a list of actions that can be folded/unfolded. +function initListButtons(){ + + //for each multi_action select + $('.multi_action_slct').each(function(){ + //prepare replacement buttons + var buttonset = $('
        Previous action').button(); + button1.attr("disabled","disabled"); + var button2 = $('').button({ + text:false, + icons: { primary: "ui-icon-triangle-1-s" } + }); + buttonset.append(button1); + buttonset.append(button2); + buttonset.buttonset(); + + //prepare list + var options = $('option', $(this)); + var list = $('
          '); + $.each(options,function(){ + var classes = $(this).attr("class"); + var item = $('
        • '); + var a = $(''+$(this).text()+''); + a.val($(this).val()); + item.html(a); + list.append(item); + }); + list.css({ + "display":"none" + }); + + + //replace the select and insert the buttons + $(this).before(buttonset); + $(this).parents('.action_blocks').append(list); + $(this).remove(); + //$(this).replaceWith(list); + + }); + + + //below the listeners for events on these buttons and list + + //enable run the last action button + $('.action_list li a').click(function(){ + //enable run last action button + var prev_action_button = $('.last_action_button',$(this).parents('.action_blocks')); + prev_action_button.val($(this).val()); + prev_action_button.removeClass("confirm_with_select_button"); + prev_action_button.removeClass("confirm_button"); + prev_action_button.removeClass("action_button"); + prev_action_button.addClass($(this).attr("class")); + prev_action_button.button("option","label",$(this).text()); + prev_action_button.button("enable"); + $(this).parents('ul').hide("blind",100); + //return false; + }); + + + //Show the list of actions in place + $('.list_button').click(function(){ + $('.action_list',$(this).parents('.action_blocks')).css({ + "left": $(this).prev().position().left, + "top": $(this).prev().position().top+13, + "width": $(this).parent().outerWidth()-11 + }); + $('.action_list',$(this).parents('.action_blocks')).toggle("blind",100); + return false; + }); +} + +//Prepares the standard confirm dialogs +function setupConfirmDialogs(){ + + //add div to the main body if it isn't present. + if (!($('div#confirm_dialog').length)){ + $('div#dialogs').append('
          '); + }; + + //add the HTML with the standard question and buttons. + $('div#confirm_dialog').html( + '
          \ +
          You have to confirm this action.
          \ +
          \ +
          Do you want to proceed?
          \ +
          \ +
          \ + \ + \ +
          \ +
          '); + + //prepare the jquery dialog + $('div#confirm_dialog').dialog({ + resizable:false, + modal:true, + width:300, + heigth:200, + autoOpen:false + }); + + //enhace the button look + $('div#confirm_dialog button').button(); + + //same for the confirm with select dialog. + if (!($('div#confirm_with_select_dialog').length)){ + $('div#dialogs').append('
          '); + }; + + $('div#confirm_with_select_dialog').html( + '
          \ +
          You need to select something.
          \ + \ +
          \ + \ + \ +
          \ +
          '); + + + //prepare the jquery dialog + $('div#confirm_with_select_dialog').dialog({ + resizable:false, + modal:true, + width:300, + heigth:300, + autoOpen:false + }); + + $('div#confirm_with_select_dialog button').button(); + + //if a cancel button is pressed, we close the dialog. + $('button.confirm_cancel').click(function(){ + $('div#confirm_with_select_dialog').dialog("close"); + $('div#confirm_dialog').dialog("close"); + return false; + }); + + //when we proceed with a "confirm with select" we need to + //find out if we are running an action with a parametre on a datatable + //items or if its just an action + $('button#confirm_with_select_proceed').click(function(){ + var value = $(this).val(); + var action = SunstoneCfg["actions"][value]; + var param = $('select#confirm_select').val(); + if (!action) { notifyError("Action "+value+" not defined."); return false;}; + switch (action.type){ + case "multiple": //find the datatable + var nodes = action.elements(); + Sunstone.runAction(value,nodes,param); + break; + default: + Sunstone.runAction(value,param); + break; + } + return false; + + }); + +} + +//Popup a confirmation dialog. +//In order to find out the dialog action and +//tip for the user we need to access the clicked button +//configuration. We do this by discovering the name of the parent tab +//and with the value of the clicked element. +function popUpConfirmDialog(target_elem){ + var value = $(target_elem).val(); + var tab_id = $(target_elem).parents('.tab').attr('id'); + var button = Sunstone.getButton(tab_id,value); + var tip = button.tip; + $('button#confirm_proceed').val(value); + $('div#confirm_tip').text(tip); + $('div#confirm_dialog').dialog("open"); +} + +//Same as previous. This time we need as well to access the updated +//select list, which is done through the pointer of found in the +//config of the button (a function returning the select options). +function popUpConfirmWithSelectDialog(target_elem){ + var value = $(target_elem).val(); + var tab_id = $(target_elem).parents('.tab').attr('id'); + var button = Sunstone.getButton(tab_id,value); + var tip = button.tip; + var select_var = button.select(); + $('select#confirm_select').html(select_var); + $('div#confirm_with_select_tip').text(tip); + + $('button#confirm_with_select_proceed').val(value); + $('div#confirm_with_select_dialog').dialog("open"); +} + + diff --git a/src/sunstone/templates/index.html b/src/sunstone/templates/index.html index 37abef4e23..aa451a553f 100644 --- a/src/sunstone/templates/index.html +++ b/src/sunstone/templates/index.html @@ -20,31 +20,28 @@ - - + + + + + + + + + + +
          -
          -
          -
          -
          -
          -
          @@ -67,32 +64,8 @@
          -
          -
          -
          -
          - -
          -
          - -
          -
          - -
          -
          - -
          -
          - -
          -
          - -
          -
          - -
          -
          +
          diff --git a/src/template/Template.cc b/src/template/Template.cc index b1dd8b5ad9..75a2b9f712 100644 --- a/src/template/Template.cc +++ b/src/template/Template.cc @@ -445,12 +445,7 @@ Attribute * Template::vector_xml_att(const xmlNode * node) int Template::from_xml(const string &xml_str) { xmlDocPtr xml_doc = 0; - xmlNode * root_element; - xmlNode * cur_node = 0; - - Attribute * attr; - // Parse xml string as libxml document xml_doc = xmlParseMemory (xml_str.c_str(),xml_str.length()); @@ -460,6 +455,44 @@ int Template::from_xml(const string &xml_str) return -1; } + // Get the