diff --git a/include/Datastore.h b/include/Datastore.h index 781dfce738..8d145c9d02 100644 --- a/include/Datastore.h +++ b/include/Datastore.h @@ -223,6 +223,12 @@ public: return shared; }; + /** + * Returns true if the DS_MAD_CONF has PERSISTENT_ONLY = "YES" flag + * @return true if persistent only + */ + bool is_persistent_only(); + /** * Enable or disable the DS. Only for System DS. * @param enable true to enable @@ -373,6 +379,17 @@ private: return new DatastoreTemplate; } + /** + * Verify the proper definition of the DS_MAD by checking the attributes + * related to the DS defined in DS_MAD_CONF specified in the Datastore + * template + */ + int set_ds_mad(string &ds_mad, string &error_str); + + /** + * Verify the proper definition of the TM_MAD by checking the attributes + * related to the TM defined in TM_MAD_CONF + */ int set_tm_mad(string &tm_mad, string &error_str); /** diff --git a/include/Image.h b/include/Image.h index 3424e70fc3..05f25fbdbf 100644 --- a/include/Image.h +++ b/include/Image.h @@ -76,16 +76,17 @@ public: */ enum DiskType { - FILE = 0, /** < File-based disk */ - CD_ROM = 1, /** < An ISO9660 disk */ - BLOCK = 2, /** < Block-device disk */ - RBD = 3, /** < CEPH RBD disk */ - RBD_CDROM = 4, /** < CEPH RBD CDROM disk */ - GLUSTER = 5, /** < Gluster Block Device */ - GLUSTER_CDROM = 6, /** < Gluster CDROM Device Device */ - SHEEPDOG = 7, /** < Sheepdog Block Device */ + FILE = 0, /** < File-based disk */ + CD_ROM = 1, /** < An ISO9660 disk */ + BLOCK = 2, /** < Block-device disk */ + RBD = 3, /** < CEPH RBD disk */ + RBD_CDROM = 4, /** < CEPH RBD CDROM disk */ + GLUSTER = 5, /** < Gluster Block Device */ + GLUSTER_CDROM = 6, /** < Gluster CDROM Device Device */ + SHEEPDOG = 7, /** < Sheepdog Block Device */ SHEEPDOG_CDROM = 8, /** < Sheepdog CDROM Device Device */ - NONE = 255 /** < No disk type, error situation */ + ISCSI = 9, /** < iSCSI Volume (Devices Datastore) */ + NONE = 255 /** < No disk type, error situation */ }; /** @@ -106,6 +107,7 @@ public: case GLUSTER_CDROM: return "GLUSTER_CDROM" ; break; case SHEEPDOG: return "SHEEPDOG" ; break; case SHEEPDOG_CDROM: return "SHEEPDOG_CDROM" ; break; + case ISCSI: return "ISCSI" ; break; default: return ""; } }; diff --git a/include/LibVirtDriver.h b/include/LibVirtDriver.h index 9ee2073801..3b480dd59f 100644 --- a/include/LibVirtDriver.h +++ b/include/LibVirtDriver.h @@ -48,6 +48,8 @@ private: static const int GLUSTER_DEFAULT_PORT; + static const int ISCSI_DEFAULT_PORT; + int deployment_description( const VirtualMachine * vm, const string& file_name) const diff --git a/include/Nebula.h b/include/Nebula.h index cf3fd14741..ec13bb4aa5 100644 --- a/include/Nebula.h +++ b/include/Nebula.h @@ -193,57 +193,13 @@ public: * Returns the value of LOG->DEBUG_LEVEL in oned.conf file * @return the debug level, to instantiate Log'ers */ - Log::MessageType get_debug_level() const - { - Log::MessageType clevel = Log::ERROR; - vector logs; - int rc; - int log_level_int; - - rc = nebula_configuration->get("LOG", logs); - - if ( rc != 0 ) - { - string value; - const VectorAttribute * log = static_cast - (logs[0]); - value = log->vector_value("DEBUG_LEVEL"); - - log_level_int = atoi(value.c_str()); - - if ( Log::ERROR <= log_level_int && log_level_int <= Log::DDDEBUG ) - { - clevel = static_cast(log_level_int); - } - } - - return clevel; - } + Log::MessageType get_debug_level() const; /** * Returns the value of LOG->SYSTEM in oned.conf file * @return the logging system CERR, FILE_TS or SYSLOG */ - NebulaLog::LogType get_log_system() const - { - vector logs; - int rc; - NebulaLog::LogType log_system = NebulaLog::UNDEFINED; - - rc = nebula_configuration->get("LOG", logs); - - if ( rc != 0 ) - { - string value; - const VectorAttribute * log = static_cast - (logs[0]); - - value = log->vector_value("SYSTEM"); - log_system = NebulaLog::str_to_type(value); - } - - return log_system; - }; + NebulaLog::LogType get_log_system() const; /** * Returns the value of ONE_LOCATION env variable. When this variable is @@ -301,28 +257,7 @@ public: * * */ - int get_ds_location(int cluster_id, string& dsloc) - { - if ( cluster_id != -1 ) - { - Cluster * cluster = clpool->get(cluster_id, true); - - if ( cluster == 0 ) - { - return -1; - } - - cluster->get_ds_location(dsloc); - - cluster->unlock(); - } - else - { - get_configuration_attribute("DATASTORE_LOCATION", dsloc); - } - - return 0; - } + int get_ds_location(int cluster_id, string& dsloc); /** * Returns the default vms location. When ONE_LOCATION is defined this path @@ -344,21 +279,7 @@ public: * /var/log/one/$VM_ID.log * @return the log location for the VM. */ - string get_vm_log_filename(int oid) - { - ostringstream oss; - - if (nebula_location == "/") - { - oss << log_location << oid << ".log"; - } - else - { - oss << vms_location << oid << "/vm.log"; - } - - return oss.str(); - }; + string get_vm_log_filename(int oid); /** * Returns the name of the host running oned @@ -413,7 +334,10 @@ public: /** * Initialize the database */ - void bootstrap_db(); + void bootstrap_db() + { + start(true); + } // -------------------------------------------------------------- // Federation @@ -497,36 +421,19 @@ public: nebula_configuration->Template::get(_name, value); }; + /** + * Gets a DS configuration attribute + */ + int get_ds_conf_attribute( + const std::string& ds_name, + const VectorAttribute* &value) const; + /** * Gets a TM configuration attribute */ int get_tm_conf_attribute( const string& tm_name, - const VectorAttribute* &value) const - { - vector::const_iterator it; - vector values; - - nebula_configuration->Template::get("TM_MAD_CONF", values); - - for (it = values.begin(); it != values.end(); it ++) - { - value = dynamic_cast(*it); - - if (value == 0) - { - continue; - } - - if (value->vector_value("NAME") == tm_name) - { - return 0; - } - } - - value = 0; - return -1; - }; + const VectorAttribute* &value) const; /** * Gets an XML document with all of the configuration attributes diff --git a/include/NebulaTemplate.h b/include/NebulaTemplate.h index 714fa965b6..62dcef7a7e 100644 --- a/include/NebulaTemplate.h +++ b/include/NebulaTemplate.h @@ -133,12 +133,17 @@ protected: /** * Defaults for the configuration file */ - map conf_default; + multimap conf_default; /** * Sets the defaults value for the template */ virtual void set_conf_default() = 0; + + /** + * Sets the defaults value for multiple attributes + */ + virtual void set_multiple_conf_default() = 0; }; // ----------------------------------------------------------------------------- @@ -176,6 +181,39 @@ private: * Sets the defaults value for the template */ void set_conf_default(); + + /** + * Sets the defaults value for multiple attributes + */ + void set_multiple_conf_default(); + + /** + * register the multiple configuration attributes and clean the + * conf_default hash + */ + void register_multiple_conf_default(const std::string& conf_section); + + /** + * Sets a default single attribute value + */ + void set_conf_single(const std::string& attr, const std::string& value); + + /** + * Sets a the defaults for a DS + */ + void set_conf_ds(const std::string& name, + const std::string& required_attrs, + const std::string& persistent_only); + + /** + * Sets a the defaults for a TM + */ + void set_conf_tm(const std::string& name, + const std::string& ln_target, + const std::string& clone_target, + const std::string& shared, + const std::string& ds_migrate); + }; diff --git a/include/ObjectXML.h b/include/ObjectXML.h index 9b9de48965..dfbb3aabac 100644 --- a/include/ObjectXML.h +++ b/include/ObjectXML.h @@ -20,14 +20,13 @@ #include #include +#include #include #include #include #include -using namespace std; - /** * This class represents a generic Object supported by a xml document. * The class provides basic methods to query attributes, and get xml nodes @@ -43,7 +42,7 @@ public: /** * Constructs an object using a XML document */ - ObjectXML(const string &xml_doc); + ObjectXML(const std::string &xml_doc); /** * Constructs an object using a XML Node. The node is copied to the new @@ -54,11 +53,25 @@ public: virtual ~ObjectXML(); /** - * Access Object elements using Xpath + * Gets elements using Xpath expression. * @param xpath_expr the Xpath of the element * @return a vector with the elements */ - vector operator[] (const char * xpath_expr); + void xpaths(std::vector& values, const char * xpath_expr); + + /* ---------------------------------------------------------------------- */ + /* Gets elements, type wrappers. See __xpaths definition for full */ + /* description of these methods. */ + /* ---------------------------------------------------------------------- */ + inline void xpaths(std::vector& values, const char * xpath_expr) + { + __xpaths(values, xpath_expr); + }; + + inline void xpaths(std::vector& values, const char * xpath_expr) + { + __xpaths(values, xpath_expr); + }; /** * Gets and sets a xpath attribute, if the attribute is not found a default @@ -69,76 +82,41 @@ public: * * @return -1 if default was set */ - int xpath(string& value, const char * xpath_expr, const char * def); + int xpath(std::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 xpath attribute, type wrappers. See __xpath definition for full */ + /* description of these methods. */ + /* ---------------------------------------------------------------------- */ + inline int xpath(int& v, const char * x, const int& d) + { + return __xpath(v, x, d); + } - /** - * 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(float& value, const char * xpath_expr, const float& def); + inline int xpath(float& v, const char * x, const float& d) + { + return __xpath(v, x, d); + } - /** - * 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); + inline int xpath(unsigned int& v, const char * x, const unsigned int& d) + { + return __xpath(v, x, d); + } - /** - * 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(long long& value, const char * xpath_expr, - const long long& def); + inline int xpath(long long& v, const char * x, const long long& d) + { + return __xpath(v, x, d); + } - /** - * 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 long long& value, const char * xpath_expr, - const unsigned long long& def); + inline int xpath(unsigned long long& v, const char * x, const unsigned long long& d) + { + return __xpath(v, x, d); + } - /** - * 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); + inline int xpath(time_t& v, const char * x, const time_t& d) + { + return __xpath(v, x, d); + } /** * Gets the value of an element from an xml string @@ -148,7 +126,7 @@ public: * * @return -1 if the element was not found */ - static int xpath_value(string& value, const char *xml, const char *xpath); + static int xpath_value(std::string& value, const char *xml, const char *xpath); /** * Search the Object for a given attribute in a set of object specific @@ -158,7 +136,7 @@ public: * * @return -1 if the element was not found */ - virtual int search(const char *name, string& value); + virtual int search(const char *name, std::string& value); /** * Search the Object for a given attribute in a set of object specific @@ -179,7 +157,7 @@ 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, std::vector& content); /** * Adds a copy of the node as a child of the node in the xpath expression. @@ -197,9 +175,9 @@ public: * Frees a vector of XMLNodes, as returned by the get_nodes function * @param content the vector of xmlNodePtr */ - void free_nodes(vector& content) + void free_nodes(std::vector& content) { - vector::iterator it; + std::vector::iterator it; for (it = content.begin(); it < content.end(); it++) { @@ -212,7 +190,7 @@ public: * XML resources are freed * @param xml_doc the new xml document */ - int update_from_str(const string &xml_doc); + int update_from_str(const std::string &xml_doc); /** * Updates the object representation with a new XML document. Previous @@ -227,7 +205,7 @@ public: * @param xml_doc string to parse * @return 0 if the xml validates */ - static int validate_xml(const string &xml_doc); + static int validate_xml(const std::string &xml_doc); /** * Renames the nodes given in the xpath expression @@ -250,7 +228,7 @@ public: * calling function * @return 0 on success */ - int eval_bool(const string& expr, bool& result, char **errmsg); + int eval_bool(const std::string& expr, bool& result, char **errmsg); /** * Evaluates a rank expression on the given host. @@ -260,19 +238,19 @@ public: * calling function * @return 0 on success */ - int eval_arith(const string& expr, int& result, char **errmsg); + int eval_arith(const std::string& expr, int& result, char **errmsg); /** * Function to write the Object in an output stream */ - friend ostream& operator<<(ostream& os, ObjectXML& oxml) + friend std::ostream& operator<<(std::ostream& os, ObjectXML& oxml) { xmlChar * mem; int size; xmlDocDumpMemory(oxml.xml,&mem,&size); - string str(reinterpret_cast(mem)); + std::string str(reinterpret_cast(mem)); os << str; xmlFree(mem); @@ -305,7 +283,7 @@ private: /** * Parse a XML documents and initializes XPath contexts */ - void xml_parse(const string &xml_doc); + void xml_parse(const std::string &xml_doc); /** * Search the Object for a given attribute in a set of object specific @@ -313,7 +291,105 @@ private: * @param name of the attribute * @results vector of attributes that matches the query */ - void search(const char* name, vector& results); + void search(const char* name, std::vector& results); + + /** + * Gets a xpath attribute, if the attribute is not found a default is used. + * This function only returns the first element + * @param value of the element + * @param xpath_expr of the xml element + * @param def default value if the element is not found + * + * @return -1 if default was set + */ + template + int __xpath(T& value, const char * xpath_expr, const T& def) + { + std::vector values; + + xpaths(values, xpath_expr); + + if (values.empty() == true) + { + value = def; + return -1; + } + + std::istringstream iss(values[0]); + + iss >> std::dec >> value; + + if (iss.fail() == true) + { + value = def; + return -1; + } + + return 0; + } + + /** + * Gets elements by xpath. + * @param values vector with the element values. + * @param expr of the xml element + */ + template + void __xpaths(std::vector& values, const char * expr) + { + xmlXPathObjectPtr obj; + + xmlNodePtr cur; + xmlChar * str_ptr; + + obj=xmlXPathEvalExpression(reinterpret_cast(expr),ctx); + + if (obj == 0) + { + return; + } + + switch (obj->type) + { + case XPATH_NUMBER: + values.push_back(static_cast(obj->floatval)); + break; + + case XPATH_NODESET: + for(int i = 0; i < obj->nodesetval->nodeNr ; ++i) + { + cur = obj->nodesetval->nodeTab[i]; + + if ( cur == 0 || cur->type != XML_ELEMENT_NODE ) + { + continue; + } + + str_ptr = xmlNodeGetContent(cur); + + if (str_ptr != 0) + { + std::istringstream iss(reinterpret_cast(str_ptr)); + T val; + + iss >> std::dec >> val; + + if (!iss.fail()) + { + values.push_back(val); + } + + xmlFree(str_ptr); + } + } + break; + + default: + break; + + } + + xmlXPathFreeObject(obj); + }; }; #endif /*OBJECT_XML_H_*/ diff --git a/install.sh b/install.sh index e8bcfb843a..db71c6f756 100755 --- a/install.sh +++ b/install.sh @@ -286,6 +286,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/tm/ceph \ $VAR_LOCATION/remotes/tm/dev \ $VAR_LOCATION/remotes/tm/vcenter \ + $VAR_LOCATION/remotes/tm/iscsi \ $VAR_LOCATION/remotes/hooks \ $VAR_LOCATION/remotes/hooks/ft \ $VAR_LOCATION/remotes/datastore \ @@ -296,6 +297,7 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/datastore/ceph \ $VAR_LOCATION/remotes/datastore/dev \ $VAR_LOCATION/remotes/datastore/vcenter \ + $VAR_LOCATION/remotes/datastore/iscsi \ $VAR_LOCATION/remotes/auth \ $VAR_LOCATION/remotes/auth/plain \ $VAR_LOCATION/remotes/auth/ssh \ @@ -421,6 +423,7 @@ INSTALL_FILES=( TM_LVM_FILES:$VAR_LOCATION/remotes/tm/lvm TM_CEPH_FILES:$VAR_LOCATION/remotes/tm/ceph TM_DEV_FILES:$VAR_LOCATION/remotes/tm/dev + TM_ISCSI_FILES:$VAR_LOCATION/remotes/tm/iscsi TM_DUMMY_FILES:$VAR_LOCATION/remotes/tm/dummy TM_VCENTER_FILES:$VAR_LOCATION/remotes/tm/vcenter DATASTORE_DRIVER_COMMON_SCRIPTS:$VAR_LOCATION/remotes/datastore/ @@ -431,6 +434,7 @@ INSTALL_FILES=( DATASTORE_DRIVER_CEPH_SCRIPTS:$VAR_LOCATION/remotes/datastore/ceph DATASTORE_DRIVER_DEV_SCRIPTS:$VAR_LOCATION/remotes/datastore/dev DATASTORE_DRIVER_VCENTER_SCRIPTS:$VAR_LOCATION/remotes/datastore/vcenter + DATASTORE_DRIVER_ISCSI_SCRIPTS:$VAR_LOCATION/remotes/datastore/iscsi NETWORK_FILES:$VAR_LOCATION/remotes/vnm NETWORK_8021Q_FILES:$VAR_LOCATION/remotes/vnm/802.1Q NETWORK_VXLAN_FILES:$VAR_LOCATION/remotes/vnm/vxlan @@ -979,6 +983,7 @@ NETWORK_VMWARE_FILES="src/vnm_mad/remotes/vmware/clean \ # - LVM TM, $VAR_LOCATION/tm/lvm # - CEPH TM, $VAR_LOCATION/tm/ceph # - DEV TM, $VAR_LOCATION/tm/dev +# - ISCSI TM, $VAR_LOCATION/tm/iscsi #------------------------------------------------------------------------------- TM_FILES="src/tm_mad/tm_common.sh" @@ -1144,6 +1149,21 @@ TM_VCENTER_FILES="src/tm_mad/vcenter/clone \ src/tm_mad/vcenter/failmigrate \ src/tm_mad/vcenter/delete" +TM_ISCSI_FILES="src/tm_mad/iscsi/clone \ + src/tm_mad/iscsi/ln \ + src/tm_mad/iscsi/mv \ + src/tm_mad/iscsi/mvds \ + src/tm_mad/iscsi/cpds \ + src/tm_mad/iscsi/premigrate \ + src/tm_mad/iscsi/postmigrate \ + src/tm_mad/iscsi/snap_create \ + src/tm_mad/iscsi/snap_create_live \ + src/tm_mad/iscsi/snap_delete \ + src/tm_mad/iscsi/snap_revert \ + src/tm_mad/iscsi/failmigrate \ + src/tm_mad/iscsi/delete" +>>>>>>> master + #------------------------------------------------------------------------------- # Datastore drivers, to be installed under $REMOTES_LOCATION/datastore # - Dummy Image Repository, $REMOTES_LOCATION/datastore/dummy @@ -1230,6 +1250,16 @@ DATASTORE_DRIVER_VCENTER_SCRIPTS="src/datastore_mad/remotes/vcenter/cp \ src/datastore_mad/remotes/vcenter/snap_flatten \ src/datastore_mad/remotes/vcenter/clone" +DATASTORE_DRIVER_ISCSI_SCRIPTS="src/datastore_mad/remotes/iscsi/cp \ + src/datastore_mad/remotes/iscsi/mkfs \ + src/datastore_mad/remotes/iscsi/stat \ + src/datastore_mad/remotes/iscsi/rm \ + src/datastore_mad/remotes/iscsi/monitor \ + src/datastore_mad/remotes/iscsi/snap_delete \ + src/datastore_mad/remotes/iscsi/snap_revert \ + src/datastore_mad/remotes/iscsi/snap_flatten \ + src/datastore_mad/remotes/iscsi/clone" + #------------------------------------------------------------------------------- # Migration scripts for onedb command, to be installed under $LIB_LOCATION #------------------------------------------------------------------------------- diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 168ecb46a0..5bd4661bc5 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -57,7 +57,7 @@ LOG = [ debug_level = 3 ] -#MANAGER_TIMER = 30 +#MANAGER_TIMER = 15 MONITORING_INTERVAL = 60 MONITORING_THREADS = 50 @@ -547,8 +547,8 @@ VM_MAD = [ # default = "vmm_exec/vmm_exec_vcenter.conf", # type = "xml", # imported_vms_actions = "shutdown, shutdown-hard, hold, release, suspend, -# resume, delete, reboot, reboot-hard, resched, unresched, poweroff, -# poweroff-hard, disk-attach, disk-detach, nic-attach, nic-detach, +# resume, delete, reboot, reboot-hard, resched, unresched, poweroff, +# poweroff-hard, disk-attach, disk-detach, nic-attach, nic-detach, # snap-create, snap-delete" #] #------------------------------------------------------------------------------- @@ -563,7 +563,7 @@ VM_MAD = [ # executable = "one_vmm_sh", # arguments = "-t 15 -r 0 ec2", # type = "xml", -# imported_vms_actions = "shutdown, shutdown-hard, hold, release, suspend, +# imported_vms_actions = "shutdown, shutdown-hard, hold, release, suspend, # resume, delete, reboot, reboot-hard, resched, unresched, poweroff, # poweroff-hard, disk-attach, disk-detach, nic-attach, nic-detach, # snap-create, snap-delete" @@ -580,7 +580,7 @@ VM_MAD = [ # executable = "one_vmm_sh", # arguments = "-t 15 -r 0 sl", # type = "xml", -# imported_vms_actions = "shutdown, shutdown-hard, hold, release, suspend, +# imported_vms_actions = "shutdown, shutdown-hard, hold, release, suspend, # resume, delete, reboot, reboot-hard, resched, unresched, poweroff, # poweroff-hard, disk-attach, disk-detach, nic-attach, nic-detach, # snap-create, snap-delete" @@ -597,7 +597,7 @@ VM_MAD = [ # executable = "one_vmm_sh", # arguments = "-t 15 -r 0 az", # type = "xml", -# imported_vms_actions = "shutdown, shutdown-hard, hold, release, suspend, +# imported_vms_actions = "shutdown, shutdown-hard, hold, release, suspend, # resume, delete, reboot, reboot-hard, resched, unresched, poweroff, # poweroff-hard, disk-attach, disk-detach, nic-attach, nic-detach, # snap-create, snap-delete" @@ -628,7 +628,7 @@ VM_MAD = [ TM_MAD = [ executable = "one_tm", - arguments = "-t 15 -d dummy,lvm,shared,fs_lvm,qcow2,ssh,vmfs,ceph,dev,vcenter" + arguments = "-t 15 -d dummy,lvm,shared,fs_lvm,qcow2,ssh,vmfs,ceph,dev,vcenter,iscsi" ] #******************************************************************************* @@ -647,7 +647,7 @@ TM_MAD = [ DATASTORE_MAD = [ executable = "one_datastore", - arguments = "-t 15 -d dummy,fs,vmfs,lvm,ceph,dev -s shared,ssh,ceph,vcenter" + arguments = "-t 15 -d dummy,fs,vmfs,lvm,ceph,dev,iscsi -s shared,ssh,ceph,vcenter" ] #******************************************************************************* @@ -909,6 +909,15 @@ INHERIT_DATASTORE_ATTR = "CEPH_USER" INHERIT_DATASTORE_ATTR = "CEPH_CONF" INHERIT_DATASTORE_ATTR = "POOL_NAME" +INHERIT_DATASTORE_ATTR = "ISCSI_USER" +INHERIT_DATASTORE_ATTR = "ISCSI_USAGE" +INHERIT_DATASTORE_ATTR = "ISCSI_HOST" + +INHERIT_IMAGE_ATTR = "ISCSI_USER" +INHERIT_IMAGE_ATTR = "ISCSI_USAGE" +INHERIT_IMAGE_ATTR = "ISCSI_HOST" +INHERIT_IMAGE_ATTR = "ISCSI_IQN" + INHERIT_DATASTORE_ATTR = "GLUSTER_HOST" INHERIT_DATASTORE_ATTR = "GLUSTER_VOLUME" @@ -941,51 +950,110 @@ INHERIT_VNET_ATTR = "MTU" # SYSTEM: The image will be cloned in the System datastore # shared : determines if the storage holding the system datastore is shared # among the different hosts or not. Valid values: "yes" or "no" -# ds_migrate : The driver allows migrations across datastores. Valid values: +# ds_migrate : The driver allows migrations across datastores. Valid values: # "yes" or "no". Note: THIS ONLY APPLIES TO SYSTEM DS. #******************************************************************************* TM_MAD_CONF = [ - name = "dummy", ln_target = "NONE", clone_target = "SYSTEM", shared = "yes", - ds_migrate = "yes" + NAME = "dummy", LN_TARGET = "NONE", CLONE_TARGET = "SYSTEM", SHARED = "YES", + DS_MIGRATE = "YES" ] TM_MAD_CONF = [ - name = "lvm", ln_target = "NONE", clone_target = "SELF", shared = "yes" + NAME = "lvm", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES" ] TM_MAD_CONF = [ - name = "shared", ln_target = "NONE", clone_target = "SYSTEM", shared = "yes", - ds_migrate = "yes" + NAME = "shared", LN_TARGET = "NONE", CLONE_TARGET = "SYSTEM", SHARED = "YES", + DS_MIGRATE = "YES" ] TM_MAD_CONF = [ - name = "fs_lvm", ln_target = "SYSTEM", clone_target = "SYSTEM", shared="yes" + NAME = "fs_lvm", LN_TARGET = "SYSTEM", CLONE_TARGET = "SYSTEM", SHARED="YES" ] TM_MAD_CONF = [ - name = "qcow2", ln_target = "NONE", clone_target = "SYSTEM", shared = "yes" + NAME = "qcow2", LN_TARGET = "NONE", CLONE_TARGET = "SYSTEM", SHARED = "YES" ] TM_MAD_CONF = [ - name = "ssh", ln_target = "SYSTEM", clone_target = "SYSTEM", shared = "no", - ds_migrate = "yes" + NAME = "ssh", LN_TARGET = "SYSTEM", CLONE_TARGET = "SYSTEM", SHARED = "NO", + DS_MIGRATE = "YES" ] TM_MAD_CONF = [ - name = "vmfs", ln_target = "NONE", clone_target= "SYSTEM", shared = "yes" + NAME = "vmfs", LN_TARGET = "NONE", CLONE_TARGET= "SYSTEM", SHARED = "YES" ] TM_MAD_CONF = [ - name = "ceph", ln_target = "NONE", clone_target = "SELF", shared = "yes", - ds_migrate = "no" + NAME = "ceph", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES", + DS_MIGRATE = "NO" ] TM_MAD_CONF = [ - name = "dev", ln_target = "NONE", clone_target = "NONE", shared = "yes" + NAME = "iscsi", LN_TARGET = "NONE", CLONE_TARGET = "SELF", SHARED = "YES", + DS_MIGRATE = "NO" +] + +TM_MAD_CONF = [ + NAME = "dev", LN_TARGET = "NONE", CLONE_TARGET = "NONE", SHARED = "YES" +] + +#******************************************************************************* +# Datastore Manager Driver Behavior Configuration +#******************************************************************************* +# The configuration for each driver is defined in DS_MAD_CONF. These +# values are used when creating a new datastore and should not be modified +# since they define the datastore behavior. +# name : name of the transfer driver, listed in the -d option of the +# DS_MAD section +# required_attrs : comma separated list of required attributes in the DS +# template +# persistent_only: specifies whether the datastore can only manage persistent +# images +#******************************************************************************* + +DS_MAD_CONF = [ + NAME = "ceph", + REQUIRED_ATTRS = "DISK_TYPE,BRIDGE_LIST,CEPH_HOST,CEPH_USER,CEPH_SECRET", + PERSISTENT_ONLY = "NO" ] TM_MAD_CONF = [ name = "vcenter", ln_target = "NONE", clone_target = "NONE", shared = "yes" ] +DS_MAD_CONF = [ + NAME = "dev", REQUIRED_ATTRS = "DISK_TYPE", PERSISTENT_ONLY = "YES" +] + +DS_MAD_CONF = [ + NAME = "iscsi", REQUIRED_ATTRS = "DISK_TYPE,ISCSI_HOST", + PERSISTENT_ONLY = "YES" +] + +DS_MAD_CONF = [ + NAME = "dummy", REQUIRED_ATTRS = "", PERSISTENT_ONLY = "NO" +] + +DS_MAD_CONF = [ + NAME = "fs", REQUIRED_ATTRS = "", PERSISTENT_ONLY = "NO" +] + +DS_MAD_CONF = [ + NAME = "lvm", REQUIRED_ATTRS = "DISK_TYPE,BRIDGE_LIST", + PERSISTENT_ONLY = "NO" +] + +DS_MAD_CONF = [ + NAME = "shared", REQUIRED_ATTRS = "", PERSISTENT_ONLY = "NO" +] + +DS_MAD_CONF = [ + NAME = "ssh", REQUIRED_ATTRS = "", PERSISTENT_ONLY = "NO" +] + +DS_MAD_CONF = [ + NAME = "vmfs", REQUIRED_ATTRS = "BRIDGE_LIST", PERSISTENT_ONLY = "NO" +] +>>>>>>> master diff --git a/src/datastore/Datastore.cc b/src/datastore/Datastore.cc index 9ca71c0e0a..ec3bf80203 100644 --- a/src/datastore/Datastore.cc +++ b/src/datastore/Datastore.cc @@ -109,6 +109,7 @@ void Datastore::disk_attribute( ostringstream oss; string st; string inherit_val; + string current_val; vector::const_iterator it; @@ -142,9 +143,10 @@ void Datastore::disk_attribute( for (it = inherit_attrs.begin(); it != inherit_attrs.end(); it++) { + current_val = disk->vector_value((*it).c_str()); get_template_attribute((*it).c_str(), inherit_val); - if (!inherit_val.empty()) + if ( current_val.empty() && !inherit_val.empty() ) { disk->replace(*it, inherit_val); } @@ -209,24 +211,81 @@ static int check_tm_target_type(string& tm_tt) /* -------------------------------------------------------------------------- */ +int Datastore::set_ds_mad(std::string &mad, std::string &error_str) +{ + const VectorAttribute* vatt; + std::vector vrequired_attrs; + + int rc; + std::string required_attrs, required_attr, value; + + std::ostringstream oss; + + if ( type == SYSTEM_DS ) //No ds_mad for SYSTEM_DS + { + return 0; + } + + rc = Nebula::instance().get_ds_conf_attribute(mad, vatt); + + if ( rc != 0 ) + { + goto error_conf; + } + + rc = vatt->vector_value("REQUIRED_ATTRS", required_attrs); + + if ( rc == -1 ) //No required attributes + { + return 0; + } + + vrequired_attrs = one_util::split(required_attrs, ','); + + for ( std::vector::const_iterator it = vrequired_attrs.begin(); + it != vrequired_attrs.end(); it++ ) + { + required_attr = *it; + + required_attr = one_util::trim(required_attr); + one_util::toupper(required_attr); + + get_template_attribute(required_attr.c_str(), value); + + if ( value.empty() ) + { + goto error_required; + } + } + + return 0; + +error_conf: + oss << "DS_MAD named \"" << mad << "\" is not defined in oned.conf"; + goto error_common; + +error_required: + oss << "Datastore template is missing the \"" << required_attr + << "\" attribute or it's empty."; + +error_common: + error_str = oss.str(); + return -1; +} + +/* -------------------------------------------------------------------------- */ + int Datastore::set_tm_mad(string &tm_mad, string &error_str) { const VectorAttribute* vatt; - int rc; string st; ostringstream oss; - rc = Nebula::instance().get_tm_conf_attribute(tm_mad, vatt); - - if (rc != 0) + if ( Nebula::instance().get_tm_conf_attribute(tm_mad, vatt) != 0 ) { - oss << "TM_MAD named \"" << tm_mad << "\" is not defined in oned.conf"; - - error_str = oss.str(); - - return -1; + goto error_conf; } if (type == SYSTEM_DS) @@ -290,12 +349,16 @@ int Datastore::set_tm_mad(string &tm_mad, string &error_str) return 0; +error_conf: + oss << "TM_MAD named \"" << tm_mad << "\" is not defined in oned.conf"; + goto error_common; + error: oss << "Attribute shared, ln_target or clone_target in TM_MAD_CONF for " << tm_mad << " is missing or has wrong value in oned.conf"; +error_common: error_str = oss.str(); - return -1; } @@ -321,6 +384,7 @@ int Datastore::set_ds_disk_type(string& s_dt, string& error) //Valid disk types for Image DS case Image::FILE: case Image::BLOCK: + case Image::ISCSI: case Image::RBD: case Image::GLUSTER: case Image::SHEEPDOG: @@ -350,6 +414,7 @@ int Datastore::set_ds_disk_type(string& s_dt, string& error) case Image::GLUSTER: case Image::SHEEPDOG: case Image::BLOCK: + case Image::ISCSI: case Image::CD_ROM: case Image::RBD_CDROM: case Image::SHEEPDOG_CDROM: @@ -416,6 +481,11 @@ int Datastore::insert(SqlDB *db, string& error_str) goto error_ds; } + if (set_ds_mad(ds_mad, error_str) != 0) + { + goto error_common; + } + get_template_attribute("TM_MAD", tm_mad); if ( tm_mad.empty() == true ) @@ -701,13 +771,13 @@ int Datastore::post_update_template(string& error_str) DatastoreType old_ds_type = type; Image::DiskType old_disk_type = disk_type; + string old_tm_mad = tm_mad; + string old_ds_mad = ds_mad; /* ---------------------------------------------------------------------- */ /* Set the TYPE of the Datastore (class & template) */ /* ---------------------------------------------------------------------- */ - old_ds_type = type; - get_template_attribute("TYPE", s_ds_type); if (!s_ds_type.empty()) @@ -808,6 +878,20 @@ int Datastore::post_update_template(string& error_str) } } + /* ---------------------------------------------------------------------- */ + /* Verify that the template has the required attributees */ + /* ---------------------------------------------------------------------- */ + + if ( set_ds_mad(ds_mad, error_str) != 0 ) + { + type = old_ds_type; + disk_type = old_disk_type; + tm_mad = old_tm_mad; + ds_mad = old_ds_mad; + + return -1; + } + /* ---------------------------------------------------------------------- */ /* Set the BASE_PATH of the Datastore (class & template) */ /* ---------------------------------------------------------------------- */ @@ -868,3 +952,27 @@ bool Datastore::get_avail_mb(long long &avail) return check; } + +/* ------------------------------------------------------------------------ */ +/* ------------------------------------------------------------------------ */ + +bool Datastore::is_persistent_only() +{ + int rc; + bool persistent_only = false; + + const VectorAttribute* vatt; + + rc = Nebula::instance().get_ds_conf_attribute(ds_mad, vatt); + + if ( rc != 0 ) + { + // No DS_MAD_CONF is available for this DS_MAD. + // Assuming this DS is not PERSISTENT_ONLY + return false; + } + + vatt->vector_value("PERSISTENT_ONLY", persistent_only); + + return persistent_only; +}; diff --git a/src/datastore_mad/remotes/iscsi/clone b/src/datastore_mad/remotes/iscsi/clone new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/iscsi/clone @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/iscsi/cp b/src/datastore_mad/remotes/iscsi/cp new file mode 120000 index 0000000000..4457ca04a1 --- /dev/null +++ b/src/datastore_mad/remotes/iscsi/cp @@ -0,0 +1 @@ +../dev/cp \ No newline at end of file diff --git a/src/datastore_mad/remotes/iscsi/mkfs b/src/datastore_mad/remotes/iscsi/mkfs new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/iscsi/mkfs @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/iscsi/monitor b/src/datastore_mad/remotes/iscsi/monitor new file mode 120000 index 0000000000..59d1033b39 --- /dev/null +++ b/src/datastore_mad/remotes/iscsi/monitor @@ -0,0 +1 @@ +../dev/monitor \ No newline at end of file diff --git a/src/datastore_mad/remotes/iscsi/rm b/src/datastore_mad/remotes/iscsi/rm new file mode 120000 index 0000000000..a1ce6491e6 --- /dev/null +++ b/src/datastore_mad/remotes/iscsi/rm @@ -0,0 +1 @@ +../dev/rm \ No newline at end of file diff --git a/src/datastore_mad/remotes/iscsi/snap_delete b/src/datastore_mad/remotes/iscsi/snap_delete new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/iscsi/snap_delete @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/iscsi/snap_flatten b/src/datastore_mad/remotes/iscsi/snap_flatten new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/iscsi/snap_flatten @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/iscsi/snap_revert b/src/datastore_mad/remotes/iscsi/snap_revert new file mode 120000 index 0000000000..9c454e8cd4 --- /dev/null +++ b/src/datastore_mad/remotes/iscsi/snap_revert @@ -0,0 +1 @@ +../common/not_supported.sh \ No newline at end of file diff --git a/src/datastore_mad/remotes/iscsi/stat b/src/datastore_mad/remotes/iscsi/stat new file mode 120000 index 0000000000..898330e74c --- /dev/null +++ b/src/datastore_mad/remotes/iscsi/stat @@ -0,0 +1 @@ +../dev/stat \ No newline at end of file diff --git a/src/flow/oneflow-server.rb b/src/flow/oneflow-server.rb index 22b6fb2b9d..debd322e1f 100644 --- a/src/flow/oneflow-server.rb +++ b/src/flow/oneflow-server.rb @@ -245,6 +245,8 @@ post '/service/:id/action' do OpenNebula::Error.new("Action #{action['perform']}: " << "You have to specify an OCTET") end + when 'rename' + service.rename(opts['name']) else OpenNebula::Error.new("Action #{action['perform']} not supported") end @@ -472,24 +474,24 @@ post '/service_template/:id/action' do args << opts['owner_id'].to_i args << (opts['group_id'].to_i || -1) - service_template.chown(*args) status 204 + service_template.chown(*args) else OpenNebula::Error.new("Action #{action['perform']}: " << "You have to specify a UID") end when 'chgrp' if opts && opts['group_id'] - service_template.chown(-1, opts['group_id'].to_i) status 204 + service_template.chown(-1, opts['group_id'].to_i) else OpenNebula::Error.new("Action #{action['perform']}: " << "You have to specify a GID") end when 'chmod' if opts && opts['octet'] - service_template.chmod_octet(opts['octet']) status 204 + service_template.chmod_octet(opts['octet']) else OpenNebula::Error.new("Action #{action['perform']}: " << "You have to specify an OCTET") @@ -506,6 +508,9 @@ post '/service_template/:id/action' do OpenNebula::Error.new("Action #{action['perform']}: " << "You have to provide a template") end + when 'rename' + status 204 + service_template.rename(opts['name']) else OpenNebula::Error.new("Action #{action['perform']} not supported") end diff --git a/src/image/Image.cc b/src/image/Image.cc index 41388fe7dc..a7b5fdd7f9 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -811,6 +811,10 @@ Image::DiskType Image::str_to_disk_type(string& s_disk_type) { type = Image::BLOCK; } + else if (s_disk_type == "ISCSI") + { + type = Image::ISCSI; + } else if (s_disk_type == "CDROM") { type = Image::CD_ROM; diff --git a/src/mad/sh/scripts_common.sh b/src/mad/sh/scripts_common.sh index 023fe63a1d..52a342a38b 100644 --- a/src/mad/sh/scripts_common.sh +++ b/src/mad/sh/scripts_common.sh @@ -453,7 +453,7 @@ fi EOF` SSH_EXEC_RC=$? - if [ $? -ne 0 ]; then + if [ $SSH_EXEC_RC -ne 0 ]; then error_message "Error creating directory $2 at $1: $SSH_EXEC_ERR" exit $SSH_EXEC_RC @@ -593,3 +593,36 @@ function iqn_get_host { VG_NAME=$(iqn_get_vg_name "$IQN") echo ${TARGET%%.$VG_NAME.$LV_NAME} } + +# ------------------------------------------------------------------------------ +# VMM helpers +# ------------------------------------------------------------------------------ + +# This function builds the XML necessary for attach-disk operations +# that require declaration of host sources +# @param $1 - Space separated list of hosts +# @return The XML via STDOUT +function get_source_xml { + for host in $1 ; do + BCK_IFS=$IFS + IFS=':' + + unset k HOST_PARTS SOURCE_HOST + + for part in $host ; do + HOST_PARTS[k++]="$part" + done + + SOURCE_HOST="$SOURCE_HOST logs; + int rc; + int log_level_int; + + rc = nebula_configuration->get("LOG", logs); + + if ( rc != 0 ) + { + string value; + const VectorAttribute * log = static_cast + (logs[0]); + value = log->vector_value("DEBUG_LEVEL"); + + log_level_int = atoi(value.c_str()); + + if ( Log::ERROR <= log_level_int && log_level_int <= Log::DDDEBUG ) + { + clevel = static_cast(log_level_int); + } + } + + return clevel; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +NebulaLog::LogType Nebula::get_log_system() const +{ + vector logs; + int rc; + NebulaLog::LogType log_system = NebulaLog::UNDEFINED; + + rc = nebula_configuration->get("LOG", logs); + + if ( rc != 0 ) + { + string value; + const VectorAttribute * log = static_cast + (logs[0]); + + value = log->vector_value("SYSTEM"); + log_system = NebulaLog::str_to_type(value); + } + + return log_system; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int Nebula::get_ds_location(int cluster_id, string& dsloc) +{ + if ( cluster_id != -1 ) + { + Cluster * cluster = clpool->get(cluster_id, true); + + if ( cluster == 0 ) + { + return -1; + } + + cluster->get_ds_location(dsloc); + + cluster->unlock(); + } + else + { + get_configuration_attribute("DATASTORE_LOCATION", dsloc); + } + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string Nebula::get_vm_log_filename(int oid) +{ + ostringstream oss; + + if (nebula_location == "/") + { + oss << log_location << oid << ".log"; + } + else + { + oss << vms_location << oid << "/vm.log"; + } + + return oss.str(); +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int Nebula::get_ds_conf_attribute( + const std::string& ds_name, + const VectorAttribute* &value) const +{ + std::vector::const_iterator it; + std::vector values; + std::string template_ds_name; + std::string ds_name_upper; + + nebula_configuration->Template::get("DS_MAD_CONF", values); + + for (it = values.begin(); it != values.end(); it ++) + { + value = dynamic_cast(*it); + + if (value == 0) + { + continue; + } + + template_ds_name = value->vector_value("NAME"); + ds_name_upper = ds_name; + + one_util::toupper(ds_name_upper); + one_util::toupper(template_ds_name); + + if ( template_ds_name == ds_name_upper) + { + return 0; + } + } + + value = 0; + return -1; +}; + +int Nebula::get_tm_conf_attribute( + const string& tm_name, + const VectorAttribute* &value) const +{ + vector::const_iterator it; + vector values; + std::string template_tm_name; + std::string tm_name_upper; + + nebula_configuration->Template::get("TM_MAD_CONF", values); + + for (it = values.begin(); it != values.end(); it ++) + { + value = dynamic_cast(*it); + + if (value == 0) + { + continue; + } + + template_tm_name = value->vector_value("NAME"); + tm_name_upper = tm_name; + + one_util::toupper(tm_name_upper); + one_util::toupper(template_tm_name); + + if ( tm_name_upper == template_tm_name) + { + return 0; + } + } + + value = 0; + return -1; +}; + diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index 86e3676394..8bdc54a285 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -72,8 +72,11 @@ int NebulaTemplate::load_configuration() } } + set_multiple_conf_default(); + return 0; } + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -82,22 +85,210 @@ const char * OpenNebulaTemplate::conf_name="oned.conf"; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void OpenNebulaTemplate::set_conf_default() +void OpenNebulaTemplate::set_multiple_conf_default() +{ + +/* +#******************************************************************************* +# Transfer Manager Configuration +#******************************************************************************* +# dummy +# lvm +# shared +# fs_lvm +# qcow2 +# ssh +# vmfs +# ceph +# dev +#******************************************************************************* +*/ + + set_conf_tm("dummy", "NONE", "SYSTEM", "YES", "YES"); + set_conf_tm("lvm", "NONE", "SELF", "YES", "NO"); + set_conf_tm("shared", "NONE", "SYSTEM", "YES", "YES"); + set_conf_tm("fs_lvm", "SYSTEM", "SYSTEM", "YES", "NO"); + set_conf_tm("qcow2", "NONE", "SYSTEM", "YES", "NO"); + set_conf_tm("ssh", "SYSTEM", "SYSTEM", "NO", "YES"); + set_conf_tm("vmfs", "NONE", "SYSTEM", "YES", "NO"); + set_conf_tm("ceph", "NONE", "SELF", "YES", "NO"); + set_conf_tm("dev", "NONE", "NONE", "YES", "NO"); + + register_multiple_conf_default("TM_MAD_CONF"); + + +/* +#******************************************************************************* +# Datastore Manager Configuration +#******************************************************************************* +# ceph +# dev +# dummy +# fs +# lvm +# shared +# ssh +# vmfs +#****** +*/ + + set_conf_ds("dev", "DISK_TYPE", "YES"); + set_conf_ds("iscsi", "DISK_TYPE,ISCSI_HOST", "YES"); + set_conf_ds("dummy", "", "NO"); + set_conf_ds("fs", "", "NO"); + set_conf_ds("lvm", "DISK_TYPE", "NO"); + set_conf_ds("shared", "", "NO"); + set_conf_ds("ssh", "", "NO"); + set_conf_ds("vmfs", "BRIDGE_LIST", "NO"); + set_conf_ds("ceph", + "DISK_TYPE,BRIDGE_LIST,CEPH_HOST,CEPH_USER,CEPH_SECRET", + "NO"); + + register_multiple_conf_default("DS_MAD_CONF"); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void OpenNebulaTemplate::register_multiple_conf_default( + const std::string& conf_section) +{ + std::string defaults_name, attributes_name; + + Attribute * defaults_value; + + bool found; + + const VectorAttribute* defaults_attr; + const VectorAttribute* attributes_attr; + + std::map::iterator iter_defaults, prev; + + std::vector::const_iterator iter_attributes; + std::vector attributes_values; + + get(conf_section.c_str(), attributes_values); + + for( iter_defaults = conf_default.begin(); + iter_defaults != conf_default.end(); ) + { + if ( iter_defaults->first == conf_section ) + { + found = false; + + defaults_value = iter_defaults->second; + + defaults_attr = dynamic_cast + (defaults_value); + + defaults_name = defaults_attr->vector_value("NAME"); + + for (iter_attributes = attributes_values.begin(); + iter_attributes != attributes_values.end(); iter_attributes++) + { + attributes_attr = dynamic_cast + (*iter_attributes); + + if (attributes_attr == 0) + { + continue; + } + + attributes_name = attributes_attr->vector_value("NAME"); + + if ( attributes_name == defaults_name ) + { + found = true; + break; + } + } + + if ( !found ) + { + // insert into attributes + attributes.insert(make_pair(conf_section, defaults_value)); + iter_defaults++; + } + else + { + // remove from conf_defaults + delete iter_defaults->second; + prev = iter_defaults++; + conf_default.erase(prev); + } + } + else + { + iter_defaults++; + } + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void OpenNebulaTemplate::set_conf_single(const std::string& attr, + const std::string& value) { SingleAttribute * attribute; + + attribute = new SingleAttribute(attr, value); + conf_default.insert(make_pair(attribute->name(),attribute)); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void OpenNebulaTemplate::set_conf_ds(const std::string& name, + const std::string& required_attrs, + const std::string& persistent_only) +{ + VectorAttribute * vattribute; + std::map vvalue; + + vvalue.insert(make_pair("NAME", name)); + vvalue.insert(make_pair("REQUIRED_ATTRS", required_attrs)); + vvalue.insert(make_pair("PERSISTENT_ONLY", persistent_only)); + + vattribute = new VectorAttribute("DS_MAD_CONF", vvalue); + conf_default.insert(make_pair(vattribute->name(), vattribute)); +} +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void OpenNebulaTemplate::set_conf_tm(const std::string& name, + const std::string& ln_target, + const std::string& clone_target, + const std::string& shared, + const std::string& ds_migrate) +{ + VectorAttribute * vattribute; + std::map vvalue; + + vvalue.insert(make_pair("NAME", name)); + vvalue.insert(make_pair("LN_TARGET", ln_target)); + vvalue.insert(make_pair("CLONE_TARGET", clone_target)); + vvalue.insert(make_pair("SHARED", shared)); + vvalue.insert(make_pair("DS_MIGRATE", ds_migrate)); + + vattribute = new VectorAttribute("TM_MAD_CONF", vvalue); + conf_default.insert(make_pair(vattribute->name(), vattribute)); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void OpenNebulaTemplate::set_conf_default() +{ VectorAttribute * vattribute; string value; map vvalue; - // MANAGER_TIMER - value = "15"; - - attribute = new SingleAttribute("MANAGER_TIMER",value); - conf_default.insert(make_pair(attribute->name(),attribute)); /* #******************************************************************************* # Daemon configuration attributes #------------------------------------------------------------------------------- +# MANAGER_TIMER # MONITORING_INTERVAL # MONITORING_THREADS # HOST_PER_INTERVAL @@ -113,59 +304,19 @@ void OpenNebulaTemplate::set_conf_default() # VM_SUBMIT_ON_HOLD #******************************************************************************* */ - // MONITORING_INTERVAL - value = "60"; - - attribute = new SingleAttribute("MONITORING_INTERVAL",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // MONITORING_THREADS - value = "50"; - - attribute = new SingleAttribute("MONITORING_THREADS",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // HOST_PER_INTERVAL - value = "15"; - - attribute = new SingleAttribute("HOST_PER_INTERVAL",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // HOST_MONITORING_EXPIRATION_TIME - value = "43200"; - - attribute = new SingleAttribute("HOST_MONITORING_EXPIRATION_TIME",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // VM_INDIVIDUAL_MONITORING - value = "no"; - - attribute = new SingleAttribute("VM_INDIVIDUAL_MONITORING",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // VM_PER_INTERVAL - value = "5"; - - attribute = new SingleAttribute("VM_PER_INTERVAL",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // VM_MONITORING_EXPIRATION_TIME - value = "14400"; - - attribute = new SingleAttribute("VM_MONITORING_EXPIRATION_TIME",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //XML-RPC Server PORT - value = "2633"; - - attribute = new SingleAttribute("PORT",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //XML-RPC Server listen address - value = "0.0.0.0"; - - attribute = new SingleAttribute("LISTEN_ADDRESS",value); - conf_default.insert(make_pair(attribute->name(),attribute)); + set_conf_single("MANAGER_TIMER", "15"); + set_conf_single("MONITORING_INTERVAL", "60"); + set_conf_single("MONITORING_THREADS", "50"); + set_conf_single("HOST_PER_INTERVAL", "15"); + set_conf_single("HOST_MONITORING_EXPIRATION_TIME", "43200"); + set_conf_single("VM_INDIVIDUAL_MONITORING", "no"); + set_conf_single("VM_PER_INTERVAL", "5"); + set_conf_single("VM_MONITORING_EXPIRATION_TIME", "14400"); + set_conf_single("PORT", "2633"); + set_conf_single("LISTEN_ADDRESS", "0.0.0.0"); + set_conf_single("VNC_BASE_PORT", "5900"); + set_conf_single("SCRIPTS_REMOTE_DIR", "/var/tmp/one"); + set_conf_single("VM_SUBMIT_ON_HOLD", "NO"); //DB CONFIGURATION vvalue.insert(make_pair("BACKEND","sqlite")); @@ -173,24 +324,6 @@ void OpenNebulaTemplate::set_conf_default() vattribute = new VectorAttribute("DB",vvalue); conf_default.insert(make_pair(vattribute->name(),vattribute)); - //VNC_BASE_PORT - value = "5900"; - - attribute = new SingleAttribute("VNC_BASE_PORT",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //SCRIPTS_REMOTE_DIR - value = "/var/tmp/one"; - - attribute = new SingleAttribute("SCRIPTS_REMOTE_DIR",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // VM_SUBMIT_ON_HOLD - value = "NO"; - - attribute = new SingleAttribute("VM_SUBMIT_ON_HOLD",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - // LOG CONFIGURATION vvalue.clear(); vvalue.insert(make_pair("SYSTEM","file")); @@ -244,53 +377,15 @@ void OpenNebulaTemplate::set_conf_default() # LOG_CALL_FORMAT #******************************************************************************* */ - // MAX_CONN - value = "15"; + set_conf_single("MAX_CONN", "15"); + set_conf_single("MAX_CONN_BACKLOG", "15"); + set_conf_single("KEEPALIVE_TIMEOUT", "15"); + set_conf_single("KEEPALIVE_MAX_CONN", "30"); + set_conf_single("TIMEOUT", "15"); + set_conf_single("RPC_LOG", "NO"); + set_conf_single("MESSAGE_SIZE", "1073741824"); + set_conf_single("LOG_CALL_FORMAT", "Req:%i UID:%u %m invoked %l"); - attribute = new SingleAttribute("MAX_CONN",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // MAX_CONN_BACKLOG - value = "15"; - - attribute = new SingleAttribute("MAX_CONN_BACKLOG",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // KEEPALIVE_TIMEOUT - value = "15"; - - attribute = new SingleAttribute("KEEPALIVE_TIMEOUT",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // KEEPALIVE_MAX_CONN - value = "30"; - - attribute = new SingleAttribute("KEEPALIVE_MAX_CONN",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // TIMEOUT - value = "15"; - - attribute = new SingleAttribute("TIMEOUT",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // RPC_LOG - value = "NO"; - - attribute = new SingleAttribute("RPC_LOG",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //MESSAGE_SIZE - value = "1073741824"; - - attribute = new SingleAttribute("MESSAGE_SIZE",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //LOG_CALL_FORMAT - value = "Req:%i UID:%u %m invoked %l"; - - attribute = new SingleAttribute("LOG_CALL_FORMAT",value); - conf_default.insert(make_pair(attribute->name(),attribute)); /* #******************************************************************************* # Physical Networks configuration @@ -299,17 +394,9 @@ void OpenNebulaTemplate::set_conf_default() # MAC_PREFIX #******************************************************************************* */ - //MAC_PREFIX - value = "02:00"; - attribute = new SingleAttribute("MAC_PREFIX",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //NETWORK_SIZE - value = "254"; - - attribute = new SingleAttribute("NETWORK_SIZE",value); - conf_default.insert(make_pair(attribute->name(),attribute)); + set_conf_single("MAC_PREFIX", "02:00"); + set_conf_single("NETWORK_SIZE", "254"); /* #******************************************************************************* @@ -323,37 +410,13 @@ void OpenNebulaTemplate::set_conf_default() # DEFAULT_CDROM_DEVICE_PREFIX #******************************************************************************* */ - //DATASTORE_LOCATION - attribute = new SingleAttribute("DATASTORE_LOCATION", - var_location + "/datastores"); - conf_default.insert(make_pair(attribute->name(),attribute)); + set_conf_single("DATASTORE_LOCATION", var_location + "/datastores"); + set_conf_single("DATASTORE_BASE_PATH", var_location + "/datastores"); + set_conf_single("DATASTORE_CAPACITY_CHECK", "YES"); + set_conf_single("DEFAULT_IMAGE_TYPE", "OS"); + set_conf_single("DEFAULT_DEVICE_PREFIX", "hd"); + set_conf_single("DEFAULT_CDROM_DEVICE_PREFIX", "hd"); - //DATASTORE_BASE_PATH - attribute = new SingleAttribute("DATASTORE_BASE_PATH", - var_location + "/datastores"); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //DATASTORE_CAPACITY_CHECK - value = "YES"; - - attribute = new SingleAttribute("DATASTORE_CAPACITY_CHECK",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //DEFAULT_IMAGE_TYPE - value = "OS"; - - attribute = new SingleAttribute("DEFAULT_IMAGE_TYPE",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //DEFAULT_DEVICE_PREFIX - value = "hd"; - - attribute = new SingleAttribute("DEFAULT_DEVICE_PREFIX",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - //DEFAULT_CDROM_DEVICE_PREFIX - attribute = new SingleAttribute("DEFAULT_CDROM_DEVICE_PREFIX",value); - conf_default.insert(make_pair(attribute->name(),attribute)); /* #******************************************************************************* # Auth Manager Configuration @@ -364,29 +427,10 @@ void OpenNebulaTemplate::set_conf_default() # DEFAULT_UMASK #******************************************************************************* */ - // DEFAULT_AUTH - value = "default"; - - attribute = new SingleAttribute("DEFAULT_AUTH",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // SESSION_EXPIRATION_TIME - value = "0"; - - attribute = new SingleAttribute("SESSION_EXPIRATION_TIME",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // ENABLE_OTHER_PERMISSIONS - value = "YES"; - - attribute = new SingleAttribute("ENABLE_OTHER_PERMISSIONS",value); - conf_default.insert(make_pair(attribute->name(),attribute)); - - // DEFAULT_UMASK - value = "177"; - - attribute = new SingleAttribute("DEFAULT_UMASK",value); - conf_default.insert(make_pair(attribute->name(),attribute)); + set_conf_single("DEFAULT_AUTH", "default"); + set_conf_single("SESSION_EXPIRATION_TIME", "0"); + set_conf_single("ENABLE_OTHER_PERMISSIONS", "YES"); + set_conf_single("DEFAULT_UMASK", "177"); } /* -------------------------------------------------------------------------- */ diff --git a/src/onegate/etc/onegate-server.conf b/src/onegate/etc/onegate-server.conf index 3e7255952a..9ceaabd0be 100644 --- a/src/onegate/etc/onegate-server.conf +++ b/src/onegate/etc/onegate-server.conf @@ -77,4 +77,42 @@ :show: true :change_cardinality: true +# Attrs that cannot be modified when updating a VM template +:restricted_attrs: + - SCHED_REQUIREMENTS + - SERVICE_ID + - ROLE_NAME + +# Actions that cannot be performed on a VM +:restricted_actions: + #- deploy + #- delete + #- hold + #- livemigrate + #- migrate + #- resume + #- release + #- stop + #- suspend + #- saveas + #- snapshot_create + #- snapshot_revert + #- snapshot_delete + #- shutdown + #- reboot + #- poweroff + #- resubmit + #- chown + #- chmod + #- resize + #- attachdisk + #- detachdisk + #- attachnic + #- detachnic + #- rename + #- undeploy + #- resched + #- unresched + #- recover + diff --git a/src/onegate/onegate-server.rb b/src/onegate/onegate-server.rb index f1738715eb..f97296e02e 100644 --- a/src/onegate/onegate-server.rb +++ b/src/onegate/onegate-server.rb @@ -52,6 +52,22 @@ require 'opennebula/oneflow_client' USER_AGENT = 'GATE' +# Attrs that cannot be modified when updating a VM template +# If this parameter is not defined in onegate-server.conf +# this constant will be used +RESTRICTED_ATTRS = [ + 'SCHED_REQUIREMENTS', + 'SERVICE_ID', + 'ROLE_NAME' +] + +# Actions that cannot be triggered on a VM +# If this parameter is not defined in onegate-server.conf +# this constant will be used +RESTRICTED_ACTIONS = [ + 'reboot' +] + include OpenNebula begin @@ -98,7 +114,13 @@ helpers do logger.info { "Unauthorized login attempt" } halt 401, "Not authorized" else - return $cloud_auth.client(result) + client = $cloud_auth.client(result) + if client.nil? + logger.info { "Unauthorized login attempt" } + halt 401, "Not authorized" + end + + return client end end @@ -124,6 +146,75 @@ helpers do vm end + # Retrieve the VM id from the header of the request and return + # an OpenNebula VirtualMachine object + def get_source_vm(request_env, client) + vm_id = request_env['HTTP_X_ONEGATE_VMID'].to_i + get_vm(vm_id, client) + end + + def get_requested_vm(requested_vm_id, request_env, client) + source_vm = get_source_vm(request_env, client) + if source_vm['ID'] != requested_vm_id + service_id = source_vm['USER_TEMPLATE/SERVICE_ID'] + check_vm_in_service(requested_vm_id, service_id, client) + + requested_vm = get_vm(requested_vm_id, client) + else + requested_vm = source_vm + end + end + + # Perform the action provided in the body of the request on the + # given VM. If error trigger a halt + def perform_action(vm, body) + action_hash = parse_json(body, 'action') + if OpenNebula.is_error?(action_hash) + halt 400, rc.message + end + + check_restricted_actions(action_hash['perform']) + rc = case action_hash['perform'] + when "deploy" then vm.deploy(action_hash['params']) + when "delete" then vm.finalize + when "hold" then vm.hold + when "livemigrate" then vm.migrate(action_hash['params'], true) + when "migrate" then vm.migrate(action_hash['params'], false) + when "resume" then vm.resume + when "release" then vm.release + when "stop" then vm.stop + when "suspend" then vm.suspend + when "saveas" then vm.save_as(action_hash['params']) + when "snapshot_create" then vm.snapshot_create(action_hash['params']) + when "snapshot_revert" then vm.snapshot_revert(action_hash['params']) + when "snapshot_delete" then vm.snapshot_delete(action_hash['params']) + when "shutdown" then vm.shutdown(action_hash['params']) + when "reboot" then vm.reboot(action_hash['params']) + when "poweroff" then vm.poweroff(action_hash['params']) + when "resubmit" then vm.resubmit + when "chown" then vm.chown(action_hash['params']) + when "chmod" then vm.chmod_octet(action_hash['params']) + when "resize" then vm.resize(action_hash['params']) + when "attachdisk" then vm.disk_attach(action_hash['params']) + when "detachdisk" then vm.disk_detach(action_hash['params']) + when "attachnic" then vm.nic_attach(action_hash['params']) + when "detachnic" then vm.nic_detach(action_hash['params']) + when "rename" then vm.rename(action_hash['params']) + when "undeploy" then vm.undeploy(action_hash['params']) + when "resched" then vm.resched + when "unresched" then vm.unresched + when "recover" then vm.recover(action_hash['params']) + else + error_msg = "#{action_hash['perform']} action not " << + " available for this resource" + OpenNebula::Error.new(error_msg) + end + + if OpenNebula.is_error?(rc) + halt 500, rc.message + end + end + def get_service(service_id, client) if service_id.nil? || !service_id.match(/^\d+$/) error_msg = "Empty or invalid SERVICE_ID" @@ -156,6 +247,38 @@ helpers do end end + # Attrs that cannot be modified when updating a VM template + def check_restricted_attrs(request) + body = request.body.read + + body.split("\n").each{ |key_value| + parts = key_value.split('=') + if parts[0] && get_restricted_attrs.include?(parts[0].upcase) + error_msg = "Attribute (#{parts[0]}) cannot be modified" + logger.error {error_msg} + halt 403, error_msg + end + } + request.body.rewind + end + + def get_restricted_attrs + $conf[':restricted_attrs'] || RESTRICTED_ATTRS + end + + # Actions that cannot be performed on a VM + def check_restricted_actions(action) + if action && get_restricted_actions.include?(action.downcase) + error_msg = "Action (#{action}) is not allowed on this resource" + logger.error {error_msg} + halt 403, error_msg + end + end + + def get_restricted_actions + $conf[':restricted_actions'] || RESTRICTED_ACTIONS + end + def check_permissions(resource, action) permissions = settings.config[:permissions] unless permissions && permissions[resource] && permissions[resource][action] @@ -164,6 +287,38 @@ helpers do halt 403, error_msg end end + + # Check if the source VM is part of a service and if the requested + # VM is part of the same Service as the source VM. + # + # If true the service hash is returned + # If false a halt is triggered + # + def check_vm_in_service(requested_vm_id, service_id, client) + service = get_service(service_id, client) + + service_hash = JSON.parse(service) + + response = build_service_hash(service_hash) rescue nil + if response.nil? + error_msg = "Service #{service_id} is empty." + logger.error {error_msg} + halt 400, error_msg + end + + # Check that the user has not spoofed the Service_ID + service_vm_ids = response["SERVICE"]["roles"].collect do |r| + r["nodes"].collect{|n| n["deploy_id"]} + end.flatten rescue [] + + if service_vm_ids.empty? || !service_vm_ids.include?(requested_vm_id.to_i) + error_msg = "Service #{service_id} does not contain VM #{requested_vm_id}." + logger.error {error_msg} + halt 400, error_msg + end + + return response + end end NIC_VALID_KEYS = %w(IP IP6_LINK IP6_SITE IP6_GLOBAL NETWORK MAC) @@ -248,7 +403,6 @@ end get '/' do client = authenticate(request.env, params) - halt 401, "Not authorized" if client.nil? if $conf[:ssl_server] base_uri = $conf[:ssl_server] @@ -268,19 +422,14 @@ end put '/vm' do check_permissions(:vm, :update) - client = authenticate(request.env, params) - halt 401, "Not authorized" if client.nil? - - vm_id = request.env['HTTP_X_ONEGATE_VMID'].to_i - - vm = get_vm(vm_id, client) - - rc = vm.update(request.body.read, true) + source_vm = get_source_vm(request.env, client) + check_restricted_attrs(request) + rc = source_vm.update(request.body.read, true) if OpenNebula.is_error?(rc) - logger.error {"VMID:#{vm_id} vm.update error: #{rc.message}"} + logger.error {"VMID:#{source_vm['ID']} vm.update error: #{rc.message}"} halt 500, rc.message end @@ -289,222 +438,52 @@ end get '/vm' do check_permissions(:vm, :show) - client = authenticate(request.env, params) - halt 401, "Not authorized" if client.nil? - - vm_id = request.env['HTTP_X_ONEGATE_VMID'].to_i - - vm = get_vm(vm_id, client) - - response = build_vm_hash(vm.to_hash["VM"]) + source_vm = get_source_vm(request.env, client) + response = build_vm_hash(source_vm.to_hash["VM"]) [200, response.to_json] end get '/service' do check_permissions(:service, :show) - client = authenticate(request.env, params) - halt 401, "Not authorized" if client.nil? - - vm_id = request.env['HTTP_X_ONEGATE_VMID'].to_i - - vm = get_vm(vm_id, client) - - service_id = vm['USER_TEMPLATE/SERVICE_ID'] - service = get_service(service_id, client) - - service_hash = JSON.parse(service) - - response = build_service_hash(service_hash) rescue nil - - if response.nil? - error_msg = "VMID:#{vm_id} Service #{service_id} is empty." - logger.error {error_msg} - halt 400, error_msg - end - - # Check that the user has not spoofed the Service_ID - service_vm_ids = response["SERVICE"]["roles"].collect do |r| - r["nodes"].collect{|n| n["deploy_id"]} - end.flatten rescue [] - - if service_vm_ids.empty? || !service_vm_ids.include?(vm_id) - error_msg = "VMID:#{vm_id} Service #{service_id} does not contain VM." - logger.error {error_msg} - halt 400, error_msg - end + source_vm = get_source_vm(request.env, client) + service_id = source_vm['USER_TEMPLATE/SERVICE_ID'] + response = check_vm_in_service(source_vm['ID'], service_id, client) [200, response.to_json] end get '/vms/:id' do check_permissions(:vm, :show_by_id) - client = authenticate(request.env, params) - halt 401, "Not authorized" if client.nil? + requested_vm = get_requested_vm(params[:id].to_i, request.env, client) - source_vm_id = request.env['HTTP_X_ONEGATE_VMID'].to_i - requested_vm_id = params[:id].to_i - - vm = get_vm(source_vm_id, client) - - service_id = vm['USER_TEMPLATE/SERVICE_ID'] - service = get_service(service_id, client) - - service_hash = JSON.parse(service) - - response = build_service_hash(service_hash) rescue nil - - if response.nil? - error_msg = "VMID:#{source_vm_id} Service #{service_id} is empty." - logger.error {error_msg} - halt 400, error_msg - end - - # Check that the user has not spoofed the Service_ID - service_vm_ids = response["SERVICE"]["roles"].collect do |r| - r["nodes"].collect{|n| n["deploy_id"]} - end.flatten rescue [] - - if service_vm_ids.empty? || !service_vm_ids.include?(requested_vm_id) - error_msg = "VMID:#{requested_vm_id} Service #{service_id} does not contain VM." - logger.error {error_msg} - halt 400, error_msg - end - - vm = get_vm(requested_vm_id, client) - - response = build_vm_hash(vm.to_hash["VM"]) - - [200, response.to_json] + [200, build_vm_hash(requested_vm.to_hash["VM"]).to_json] end post '/vms/:id/action' do check_permissions(:vm, :action_by_id) - client = authenticate(request.env, params) - halt 401, "Not authorized" if client.nil? + requested_vm = get_requested_vm(params[:id].to_i, request.env, client) - source_vm_id = request.env['HTTP_X_ONEGATE_VMID'].to_i - requested_vm_id = params[:id].to_i - - vm = get_vm(source_vm_id, client) - - service_id = vm['USER_TEMPLATE/SERVICE_ID'] - service = get_service(service_id, client) - - service_hash = JSON.parse(service) - - response = build_service_hash(service_hash) rescue nil - - if response.nil? - error_msg = "VMID:#{source_vm_id} Service #{service_id} is empty." - logger.error {error_msg} - halt 400, error_msg - end - - # Check that the user has not spoofed the Service_ID - service_vm_ids = response["SERVICE"]["roles"].collect do |r| - r["nodes"].collect{|n| n["deploy_id"]} - end.flatten rescue [] - - if service_vm_ids.empty? || !service_vm_ids.include?(requested_vm_id) - error_msg = "VMID:#{requested_vm_id} Service #{service_id} does not contain VM." - logger.error {error_msg} - halt 400, error_msg - end - - vm = get_vm(requested_vm_id, client) - - action_hash = parse_json(request.body.read, 'action') - if OpenNebula.is_error?(action_hash) - halt 400, rc.message - end - - rc = case action_hash['perform'] - when "deploy" then vm.deploy(action_hash['params']) - when "delete" then vm.finalize - when "hold" then vm.hold - when "livemigrate" then vm.migrate(action_hash['params'], true) - when "migrate" then vm.migrate(action_hash['params'], false) - when "resume" then vm.resume - when "release" then vm.release - when "stop" then vm.stop - when "suspend" then vm.suspend - when "saveas" then vm.save_as(action_hash['params']) - when "snapshot_create" then vm.snapshot_create(action_hash['params']) - when "snapshot_revert" then vm.snapshot_revert(action_hash['params']) - when "snapshot_delete" then vm.snapshot_delete(action_hash['params']) - when "shutdown" then vm.shutdown(action_hash['params']) - when "reboot" then vm.reboot(action_hash['params']) - when "poweroff" then vm.poweroff(action_hash['params']) - when "resubmit" then vm.resubmit - when "chown" then vm.chown(action_hash['params']) - when "chmod" then vm.chmod_octet(action_hash['params']) - when "resize" then vm.resize(action_hash['params']) - when "attachdisk" then vm.disk_attach(action_hash['params']) - when "detachdisk" then vm.disk_detach(action_hash['params']) - when "attachnic" then vm.nic_attach(action_hash['params']) - when "detachnic" then vm.nic_detach(action_hash['params']) - when "update" then vm.update(action_hash['params']) - when "rename" then vm.rename(action_hash['params']) - when "undeploy" then vm.undeploy(action_hash['params']) - when "resched" then vm.resched - when "unresched" then vm.unresched - when "recover" then vm.recover(action_hash['params']) - else - error_msg = "#{action_hash['perform']} action not " << - " available for this resource" - OpenNebula::Error.new(error_msg) - end - - if OpenNebula.is_error?(rc) - halt 500, rc.message - else - [204, vm.to_json] - end + perform_action(requested_vm, request.body.read) + [204, requested_vm.to_json] end put '/service/role/:role' do check_permissions(:service, :change_cardinality) - client = authenticate(request.env, params) - halt 401, "Not authorized" if client.nil? + source_vm = get_source_vm(request.env, client) + service_id = source_vm['USER_TEMPLATE/SERVICE_ID'] - vm_id = request.env['HTTP_X_ONEGATE_VMID'].to_i - - vm = get_vm(vm_id, client) - - service_id = vm['USER_TEMPLATE/SERVICE_ID'] - service = get_service(service_id, client) - - service_hash = JSON.parse(service) - - response = build_service_hash(service_hash) rescue nil - - if response.nil? - error_msg = "VMID:#{vm_id} Service #{service_id} is empty." - logger.error {error_msg} - halt 400, error_msg - end - - # Check that the user has not spoofed the Service_ID - service_vm_ids = response["SERVICE"]["roles"].collect do |r| - r["nodes"].collect{|n| n["deploy_id"]} - end.flatten rescue [] - - if service_vm_ids.empty? || !service_vm_ids.include?(vm_id) - error_msg = "VMID:#{vm_id} Service #{service_id} does not contain VM." - logger.error {error_msg} - halt 400, error_msg - end + check_vm_in_service(source_vm['ID'], service_id, client) action_response = flow_client(client).put( "/service/" + service_id + "/role/" + params[:role], @@ -522,21 +501,12 @@ end put '/vms/:id' do check_permissions(:vm, :update_by_id) - client = authenticate(request.env, params) - halt 401, "Not authorized" if client.nil? - - vm = VirtualMachine.new_with_id(params[:id], client) - rc = vm.info - - if OpenNebula.is_error?(rc) - logger.error {"VMID:#{params[:id]} vm.info error: #{rc.message}"} - halt 404, rc.message - end - - rc = vm.update(request.body.read, true) + requested_vm = get_requested_vm(params[:id].to_i, request.env, client) + check_restricted_attrs(request) + rc = requested_vm.update(request.body.read, true) if OpenNebula.is_error?(rc) logger.error {"VMID:#{params[:id]} vm.update error: #{rc.message}"} halt 500, rc.message diff --git a/src/pool/ObjectCollection.cc b/src/pool/ObjectCollection.cc index 48c84d758f..e5983ad680 100644 --- a/src/pool/ObjectCollection.cc +++ b/src/pool/ObjectCollection.cc @@ -27,11 +27,13 @@ int ObjectCollection::from_xml_node(const xmlNodePtr node) ostringstream oss; vector::iterator it; + vector ids; ObjectXML oxml(node); oss << "/" << collection_name << "/ID"; - vector ids = oxml[oss.str().c_str()]; + + oxml.xpaths(ids, oss.str().c_str()); for (it = ids.begin(); it != ids.end(); it++) { diff --git a/src/rm/RequestManagerAllocate.cc b/src/rm/RequestManagerAllocate.cc index e5719ba3a6..3790daf0fc 100644 --- a/src/rm/RequestManagerAllocate.cc +++ b/src/rm/RequestManagerAllocate.cc @@ -303,6 +303,8 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, string ds_name; string ds_data; + bool ds_persistent_only; + Datastore::DatastoreType ds_type; int rc, id; @@ -327,6 +329,7 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, long long avail; bool ds_check; + bool persistent_attr; // ------------------------- Parse image template -------------------------- @@ -372,9 +375,10 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, ds->get_permissions(ds_perms); - ds_name = ds->get_name(); - ds_disk_type = ds->get_disk_type(); - ds_check = ds->get_avail_mb(avail); + ds_name = ds->get_name(); + ds_disk_type = ds->get_disk_type(); + ds_check = ds->get_avail_mb(avail); + ds_persistent_only = ds->is_persistent_only(); ds->to_xml(ds_data); @@ -472,6 +476,23 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, } } + // ------------------------- Check persistent only ------------------------- + + tmpl->get("PERSISTENT", persistent_attr); + + if ( ds_persistent_only && persistent_attr == false ) + { + std::ostringstream oss; + oss << "This Datastore only accepts persistent images."; + + failure_response(INTERNAL, allocate_error(oss.str()), att); + + delete tmpl; + return; + } + + // ------------------------- Allocate -------------------------------------- + rc = ipool->allocate(att.uid, att.gid, att.uname, diff --git a/src/rm/RequestManagerImage.cc b/src/rm/RequestManagerImage.cc index 819f65cfed..8e2decd8f6 100644 --- a/src/rm/RequestManagerImage.cc +++ b/src/rm/RequestManagerImage.cc @@ -68,8 +68,15 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList, bool persistent_flag = xmlrpc_c::value_boolean(paramList.getBoolean(2)); int rc; + int ds_id; + int ds_persistent_only; + + Nebula& nd = Nebula::instance(); + DatastorePool * dspool = nd.get_dspool(); + + Datastore * ds; Image * image; - string err_msg; + std::string err_msg; if ( basic_authorization(id, att) == false ) { @@ -87,6 +94,36 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList, return; } + ds_id = image->get_ds_id(); + + image->unlock(); + + ds = dspool->get(ds_id, true); + + if ( ds == 0 ) + { + failure_response(INTERNAL, + request_error("Datastore no longer exists.", + ""), att); + + return; + } + + ds_persistent_only = ds->is_persistent_only(); + + ds->unlock(); + + image = static_cast(pool->get(id,true)); + + if ( image == 0 ) + { + failure_response(NO_EXISTS, + get_error(object_name(auth_object),id), + att); + + return; + } + switch (image->get_type()) { case Image::OS: @@ -104,6 +141,17 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList, return; } + /* Check if datastore allows the operation */ + if ( ds_persistent_only && persistent_flag == false ) + { + failure_response(INTERNAL, + request_error("This Datastore only accepts persistent images.",""), + att); + + image->unlock(); + return; + } + rc = image->persistent(persistent_flag, err_msg); if ( rc != 0 ) diff --git a/src/scheduler/include/Scheduler.h b/src/scheduler/include/Scheduler.h index a884ead7b0..287718a4e1 100644 --- a/src/scheduler/include/Scheduler.h +++ b/src/scheduler/include/Scheduler.h @@ -19,6 +19,7 @@ #include "Log.h" #include "HostPoolXML.h" +#include "UserPoolXML.h" #include "ClusterPoolXML.h" #include "DatastorePoolXML.h" #include "VirtualMachinePoolXML.h" @@ -54,6 +55,7 @@ protected: vmapool(0), dspool(0), img_dspool(0), + upool(0), acls(0), timer(0), url(""), @@ -76,6 +78,8 @@ protected: delete dspool; delete img_dspool; + delete upool; + delete acls; delete client; @@ -92,6 +96,7 @@ protected: VirtualMachineActionsPoolXML* vmapool; SystemDatastorePoolXML * dspool; ImageDatastorePoolXML * img_dspool; + UserPoolXML * upool; AclXML * acls; diff --git a/src/scheduler/include/SchedulerTemplate.h b/src/scheduler/include/SchedulerTemplate.h index abf89d0fa1..4175735542 100644 --- a/src/scheduler/include/SchedulerTemplate.h +++ b/src/scheduler/include/SchedulerTemplate.h @@ -44,6 +44,11 @@ private: * Sets the defaults value for the template */ void set_conf_default(); + + /** + * Sets the defaults value for multiple attributes + */ + void set_multiple_conf_default(){}; }; #endif /*SCHEDULER_TEMPLATE_H_*/ diff --git a/src/scheduler/include/UserPoolXML.h b/src/scheduler/include/UserPoolXML.h new file mode 100644 index 0000000000..2a36486a43 --- /dev/null +++ b/src/scheduler/include/UserPoolXML.h @@ -0,0 +1,57 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, 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 USER_POOL_XML_H_ +#define USER_POOL_XML_H_ + +#include + +#include "PoolXML.h" +#include "UserXML.h" + +class UserPoolXML : public PoolXML +{ +public: + + UserPoolXML(Client* client):PoolXML(client){}; + + ~UserPoolXML(){}; + + /** + * Gets an object from the pool + * @param oid the object unique identifier + * + * @return a pointer to the object, 0 in case of failure + */ + UserXML * get(int oid) const + { + return static_cast(PoolXML::get(oid)); + }; + +protected: + + int get_suitable_nodes(std::vector& content) + { + return get_nodes("/USER_POOL/USER", content); + }; + + void add_object(xmlNodePtr node); + + int load_info(xmlrpc_c::value &result); +}; + +#endif /* USER_POOL_XML_H_ */ diff --git a/src/scheduler/include/UserXML.h b/src/scheduler/include/UserXML.h new file mode 100644 index 0000000000..3678f6855f --- /dev/null +++ b/src/scheduler/include/UserXML.h @@ -0,0 +1,57 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, 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 USER_XML_H_ +#define USER_XML_H_ + +#include "ObjectXML.h" + +class UserXML : public ObjectXML +{ +public: + UserXML(const string &xml_doc):ObjectXML(xml_doc) + { + init_attributes(); + }; + + UserXML(const xmlNodePtr node):ObjectXML(node) + { + init_attributes(); + }; + + int get_oid() const + { + return oid; + }; + + const std::vector& get_gids() const + { + return gids; + }; + +private: + int oid; + + std::vector gids; + + void init_attributes() + { + xpath(oid, "/USER/ID", -1); + xpaths(gids,"/USER/GROUPS/ID"); + }; +}; + +#endif /* USER_XML_H_ */ diff --git a/src/scheduler/src/pool/HostXML.cc b/src/scheduler/src/pool/HostXML.cc index e8fe66688b..7130ad7c41 100644 --- a/src/scheduler/src/pool/HostXML.cc +++ b/src/scheduler/src/pool/HostXML.cc @@ -53,8 +53,11 @@ void HostXML::init_attributes() public_cloud = (one_util::toupper(public_cloud_st) == "YES"); //-------------------- HostShare Datastores ------------------------------ - vector ds_ids = (*this)["/HOST/HOST_SHARE/DATASTORES/DS/ID"]; - vector ds_free = (*this)["/HOST/HOST_SHARE/DATASTORES/DS/FREE_MB"]; + vector ds_ids; + vector ds_free; + + xpaths(ds_ids, "/HOST/HOST_SHARE/DATASTORES/DS/ID"); + xpaths(ds_free,"/HOST/HOST_SHARE/DATASTORES/DS/FREE_MB"); int id; long long disk; @@ -99,7 +102,9 @@ int HostXML::search(const char *name, int& value) istringstream iss; int id; - vector results = (*this)["/HOST/VMS/ID"]; + vector results; + + xpaths(results, "/HOST/VMS/ID"); for (it=results.begin(); it!=results.end(); it++) { diff --git a/src/scheduler/src/pool/SConstruct b/src/scheduler/src/pool/SConstruct index 8af8ba7072..0c9273251a 100644 --- a/src/scheduler/src/pool/SConstruct +++ b/src/scheduler/src/pool/SConstruct @@ -27,6 +27,7 @@ source_files=[ 'VirtualMachinePoolXML.cc', 'VirtualMachineXML.cc', 'ClusterPoolXML.cc', + 'UserPoolXML.cc', 'DatastorePoolXML.cc', 'DatastoreXML.cc'] diff --git a/src/scheduler/src/pool/UserPoolXML.cc b/src/scheduler/src/pool/UserPoolXML.cc new file mode 100644 index 0000000000..7897a648fe --- /dev/null +++ b/src/scheduler/src/pool/UserPoolXML.cc @@ -0,0 +1,62 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, 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 "UserPoolXML.h" + +void UserPoolXML::add_object(xmlNodePtr node) +{ + if ( node == 0 || node->children == 0 ) + { + NebulaLog::log("USER",Log::ERROR, + "XML Node does not represent a valid user"); + + return; + } + + UserXML* user = new UserXML( node ); + + objects.insert( pair(user->get_oid(), user) ); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int UserPoolXML::load_info(xmlrpc_c::value &result) +{ + try + { + client->call(client->get_endpoint(), // serverUrl + "one.userpool.info", // methodName + "s", // arguments format + &result, // resultP + client->get_oneauth().c_str() // argument + ); + return 0; + } + catch (exception const& e) + { + ostringstream oss; + oss << "Exception raised: " << e.what(); + + NebulaLog::log("USER", Log::ERROR, oss); + + return -1; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index 4db6f08ddb..e2f48748e5 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -321,6 +321,7 @@ void Scheduler::start() // ------------------------------------------------------------------------- hpool = new HostPoolXML(client); + upool = new UserPoolXML(client); clpool = new ClusterPoolXML(client); vmpool = new VirtualMachinePoolXML(client,machines_limit,(live_rescheds==1)); @@ -430,8 +431,6 @@ int Scheduler::set_up_pools() //Cleans the cache and get the datastores //-------------------------------------------------------------------------- - // TODO: Avoid two ds pool info calls to oned - rc = dspool->set_up(); if ( rc != 0 ) @@ -450,6 +449,17 @@ int Scheduler::set_up_pools() //Cleans the cache and get the hosts ids //-------------------------------------------------------------------------- + rc = upool->set_up(); + + if ( rc != 0 ) + { + return rc; + } + + //-------------------------------------------------------------------------- + //Cleans the cache and get the hosts ids + //-------------------------------------------------------------------------- + rc = hpool->set_up(); if ( rc != 0 ) @@ -499,6 +509,8 @@ int Scheduler::set_up_pools() * 2. Meets user/policy requirements * 3. Have enough capacity to host the VM * + * @param acl pool + * @param users the user pool * @param vm the virtual machine * @param vm_memory vm requirement * @param vm_cpu vm requirement @@ -511,9 +523,9 @@ int Scheduler::set_up_pools() * @param error, string describing why the host is not valid * @return true for a positive match */ -static bool match_host(AclXML * acls, VirtualMachineXML* vm, int vmem, int vcpu, - vector& vpci, HostXML * host, int &n_auth, int& n_error, - int &n_fits, int &n_matched, string &error) +static bool match_host(AclXML * acls, UserPoolXML * upool, VirtualMachineXML* vm, + int vmem, int vcpu, vector& vpci, HostXML * host, int &n_auth, + int& n_error, int &n_fits, int &n_matched, string &error) { // ------------------------------------------------------------------------- // Filter current Hosts for resched VMs @@ -544,10 +556,17 @@ static bool match_host(AclXML * acls, VirtualMachineXML* vm, int vmem, int vcpu, hperms.cid = host->get_cid(); hperms.obj_type = PoolObjectSQL::HOST; - // Only include the VM group ID + UserXML * user = upool->get(vm->get_uid()); - set gids; - gids.insert(vm->get_gid()); + if (user == 0) + { + error = "User does not exists."; + return false; + } + + const vector vgids = user->get_gids(); + + set gids(vgids.begin(), vgids.end()); if ( !acls->authorize(vm->get_uid(), gids, hperms, AuthRequest::MANAGE)) { @@ -614,6 +633,8 @@ static bool match_host(AclXML * acls, VirtualMachineXML* vm, int vmem, int vcpu, * 1. Meet user/policy requirements * 2. Have enough capacity to host the VM * + * @param acl pool + * @param users the user pool * @param vm the virtual machine * @param vdisk vm requirement * @param ds to evaluate vm assgiment @@ -624,9 +645,9 @@ static bool match_host(AclXML * acls, VirtualMachineXML* vm, int vmem, int vcpu, * @param error, string describing why the host is not valid * @return true for a positive match */ -static bool match_system_ds(AclXML * acls, VirtualMachineXML* vm, long long vdisk, - DatastoreXML * ds, int& n_auth, int& n_error, int& n_fits, int &n_matched, - string &error) +static bool match_system_ds(AclXML * acls, UserPoolXML * upool, + VirtualMachineXML* vm, long long vdisk, DatastoreXML * ds, int& n_auth, + int& n_error, int& n_fits, int &n_matched, string &error) { // ------------------------------------------------------------------------- // Check if user is authorized @@ -637,10 +658,17 @@ static bool match_system_ds(AclXML * acls, VirtualMachineXML* vm, long long vdis ds->get_permissions(dsperms); - // Only include the VM group ID + UserXML * user = upool->get(vm->get_uid()); - set gids; - gids.insert(vm->get_gid()); + if (user == 0) + { + error = "User does not exists."; + return false; + } + + const vector vgids = user->get_gids(); + + set gids(vgids.begin(), vgids.end()); if ( !acls->authorize(vm->get_uid(), gids, dsperms, AuthRequest::USE)) { @@ -740,6 +768,7 @@ void Scheduler::match_schedule() const map pending_vms = vmpool->get_objects(); const map hosts = hpool->get_objects(); const map datastores = dspool->get_objects(); + const map users = upool->get_objects(); double total_match_time = 0; double total_rank_time = 0; @@ -790,8 +819,8 @@ void Scheduler::match_schedule() { host = static_cast(h_it->second); - if (match_host(acls, vm, vm_memory, vm_cpu, vm_pci, host, n_auth, - n_error, n_fits, n_matched, m_error)) + if (match_host(acls, upool, vm, vm_memory, vm_cpu, vm_pci, host, + n_auth, n_error, n_fits, n_matched, m_error)) { vm->add_match_host(host->get_hid()); @@ -894,8 +923,8 @@ void Scheduler::match_schedule() { ds = static_cast(h_it->second); - if (match_system_ds(acls, vm, vm_disk, ds, n_auth, n_error, n_fits, - n_matched, m_error)) + if (match_system_ds(acls, upool, vm, vm_disk, ds, n_auth, n_error, + n_fits, n_matched, m_error)) { vm->add_match_datastore(ds->get_oid()); diff --git a/src/sunstone/etc/sunstone-views/admin.yaml b/src/sunstone/etc/sunstone-views/admin.yaml index a72ef24739..5c20f87e53 100644 --- a/src/sunstone/etc/sunstone-views/admin.yaml +++ b/src/sunstone/etc/sunstone-views/admin.yaml @@ -63,6 +63,7 @@ tabs: - 7 # CPU #- 8 # Group ID #- 9 # Hidden User Data + #- 10 # Labels actions: User.refresh: true User.create_dialog: true @@ -88,6 +89,7 @@ tabs: - 4 # VMs - 5 # Memory - 6 # CPU + #- 7 # Labels actions: Group.refresh: true Group.create_dialog: true @@ -108,6 +110,7 @@ tabs: - 5 # Hosts - 6 # VNets - 7 # Datastores + #- 8 # Labels actions: Vdc.refresh: true Vdc.create_dialog: true @@ -158,6 +161,7 @@ tabs: #- 10 # Start Time - 11 # VNC #- 12 # Hidden Template + #- 13 # Labels actions: VM.refresh: true VM.create_dialog: true @@ -209,6 +213,7 @@ tabs: - 3 # Group - 4 # Name - 5 # Registration time + #- 6 # Labels actions: Template.refresh: true Template.create_dialog: true @@ -251,6 +256,7 @@ tabs: - 10 # Status - 11 # #VMs #- 12 # Target + #- 13 # Labels actions: Image.refresh: true Image.create_dialog: true @@ -284,6 +290,7 @@ tabs: - 10 # Status #- 11 # #VMs #- 12 # Target + #- 13 # Labels actions: File.refresh: true File.create_dialog: true @@ -310,6 +317,7 @@ tabs: - 3 # Hosts - 4 # VNets - 5 # Datastores + #- 6 # Labels actions: Cluster.refresh: true Cluster.create_dialog: true @@ -338,6 +346,7 @@ tabs: #- 10 # IM MAD #- 11 # VM MAD #- 12 # Last monitored on + #- 13 # Labels actions: Host.refresh: true Host.create_dialog: true @@ -363,6 +372,7 @@ tabs: #- 9 # DS - 10 # Type - 11 # Status + #- 12 # Labels actions: Datastore.refresh: true Datastore.create_dialog: true @@ -391,6 +401,7 @@ tabs: #- 7 # Bridge - 8 # Leases #- 9 # VLAN ID + #- 10 # Labels actions: Network.refresh: true Network.create_dialog: true @@ -416,6 +427,7 @@ tabs: - 2 # Owner - 3 # Group - 4 # Name + #- 5 # Labels actions: SecurityGroup.refresh: true SecurityGroup.create_dialog: true @@ -496,6 +508,7 @@ tabs: Service.chown: true Service.chgrp: true Service.chmod: true + Service.rename: true Service.shutdown: true Service.recover: true Service.delete: true @@ -516,6 +529,7 @@ tabs: ServiceTemplate.chown: true ServiceTemplate.chgrp: true ServiceTemplate.chmod: true + ServiceTemplate.rename: true ServiceTemplate.delete: true zones-tab: panel_tabs: @@ -525,6 +539,7 @@ tabs: - 1 # ID - 2 # Name - 3 # Endpoint + #- 4 # Labels actions: Zone.refresh: true Zone.create_dialog: true diff --git a/src/sunstone/etc/sunstone-views/admin_vcenter.yaml b/src/sunstone/etc/sunstone-views/admin_vcenter.yaml index e198a6c33e..9bb7a8b8b4 100644 --- a/src/sunstone/etc/sunstone-views/admin_vcenter.yaml +++ b/src/sunstone/etc/sunstone-views/admin_vcenter.yaml @@ -63,6 +63,7 @@ tabs: - 7 # CPU #- 8 # Group ID #- 9 # Hidden User Data + #- 10 # Labels actions: User.refresh: true User.create_dialog: true @@ -88,6 +89,7 @@ tabs: - 4 # VMs - 5 # Memory - 6 # CPU + #- 7 # Labels actions: Group.refresh: true Group.create_dialog: true @@ -108,6 +110,7 @@ tabs: - 5 # Hosts - 6 # VNets - 7 # Datastores + #- 8 # Labels actions: Vdc.refresh: true Vdc.create_dialog: true @@ -158,6 +161,7 @@ tabs: #- 10 # Start Time - 11 # VNC #- 12 # Hidden Template + #- 13 # Labels actions: VM.refresh: true VM.create_dialog: true @@ -209,6 +213,7 @@ tabs: - 3 # Group - 4 # Name - 5 # Registration time + #- 6 # Labels actions: Template.refresh: true Template.create_dialog: true @@ -251,6 +256,7 @@ tabs: - 10 # Status - 11 # #VMs #- 12 # Target + #- 13 # Labels actions: Image.refresh: true Image.create_dialog: true @@ -284,6 +290,7 @@ tabs: - 10 # Status #- 11 # #VMs #- 12 # Target + #- 13 # Labels actions: File.refresh: true File.create_dialog: true @@ -310,6 +317,7 @@ tabs: - 3 # Hosts - 4 # VNets - 5 # Datastores + #- 6 # Labels actions: Cluster.refresh: true Cluster.create_dialog: true @@ -338,6 +346,7 @@ tabs: #- 10 # IM MAD #- 11 # VM MAD #- 12 # Last monitored on + #- 13 # Labels actions: Host.refresh: true Host.create_dialog: true @@ -363,6 +372,7 @@ tabs: #- 9 # DS - 10 # Type - 11 # Status + #- 12 # Labels actions: Datastore.refresh: true Datastore.create_dialog: true @@ -391,6 +401,7 @@ tabs: #- 7 # Bridge - 8 # Leases #- 9 # VLAN ID + #- 10 # Labels actions: Network.refresh: true Network.create_dialog: true @@ -416,6 +427,7 @@ tabs: - 2 # Owner - 3 # Group - 4 # Name + #- 5 # Labels actions: SecurityGroup.refresh: true SecurityGroup.create_dialog: true @@ -496,6 +508,7 @@ tabs: Service.chown: true Service.chgrp: true Service.chmod: true + Service.rename: true Service.shutdown: true Service.recover: true Service.delete: true @@ -516,6 +529,7 @@ tabs: ServiceTemplate.chown: true ServiceTemplate.chgrp: true ServiceTemplate.chmod: true + ServiceTemplate.rename: true ServiceTemplate.delete: true zones-tab: panel_tabs: @@ -525,6 +539,7 @@ tabs: - 1 # ID - 2 # Name - 3 # Endpoint + #- 4 # Labels actions: Zone.refresh: true Zone.create_dialog: true diff --git a/src/sunstone/etc/sunstone-views/user.yaml b/src/sunstone/etc/sunstone-views/user.yaml index 0a2f6b38c1..34b99b8da4 100644 --- a/src/sunstone/etc/sunstone-views/user.yaml +++ b/src/sunstone/etc/sunstone-views/user.yaml @@ -64,6 +64,7 @@ tabs: - 7 # CPU #- 8 # Group ID #- 9 # Hidden User Data + #- 10 # Labels actions: User.refresh: true User.create_dialog: true @@ -89,6 +90,7 @@ tabs: - 4 # VMs - 5 # Memory - 6 # CPU + #- 7 # Labels actions: Group.refresh: true Group.create_dialog: true @@ -109,6 +111,7 @@ tabs: - 5 # Hosts - 6 # VNets - 7 # Datastores + #- 8 # Labels actions: Vdc.refresh: true Vdc.create_dialog: true @@ -159,6 +162,7 @@ tabs: #- 10 # Start Time - 11 # VNC #- 12 # Hidden Template + #- 13 # Labels actions: VM.refresh: true VM.create_dialog: true @@ -210,6 +214,7 @@ tabs: - 3 # Group - 4 # Name - 5 # Registration time + #- 6 # Labels actions: Template.refresh: true Template.create_dialog: true @@ -252,6 +257,7 @@ tabs: - 10 # Status - 11 # #VMs #- 12 # Target + #- 13 # Labels actions: Image.refresh: true Image.create_dialog: true @@ -285,6 +291,7 @@ tabs: - 10 # Status #- 11 # #VMs #- 12 # Target + #- 13 # Labels actions: File.refresh: true File.create_dialog: true @@ -311,6 +318,7 @@ tabs: - 3 # Hosts - 4 # VNets - 5 # Datastores + #- 6 # Labels actions: Cluster.refresh: true Cluster.create_dialog: true @@ -339,6 +347,7 @@ tabs: #- 10 # IM MAD #- 11 # VM MAD #- 12 # Last monitored on + #- 13 # Labels actions: Host.refresh: true Host.create_dialog: true @@ -364,6 +373,7 @@ tabs: #- 9 # DS #- 10 # Type #- 11 # Status + #- 12 # Labels actions: Datastore.refresh: true Datastore.create_dialog: false @@ -392,6 +402,7 @@ tabs: #- 7 # Bridge - 8 # Leases #- 9 # VLAN ID + #- 10 # Labels actions: Network.refresh: true Network.create_dialog: false @@ -417,6 +428,7 @@ tabs: - 2 # Owner - 3 # Group - 4 # Name + #- 5 # Labels actions: SecurityGroup.refresh: true SecurityGroup.create_dialog: true @@ -497,6 +509,7 @@ tabs: Service.chown: false Service.chgrp: false Service.chmod: true + Service.rename: true Service.shutdown: true Service.recover: true Service.delete: true @@ -517,6 +530,7 @@ tabs: ServiceTemplate.chown: false ServiceTemplate.chgrp: false ServiceTemplate.chmod: true + ServiceTemplate.rename: true ServiceTemplate.delete: true zones-tab: panel_tabs: @@ -526,6 +540,7 @@ tabs: - 1 # ID - 2 # Name - 3 # Endpoint + #- 4 # Labels actions: Zone.refresh: true Zone.create_dialog: true diff --git a/src/sunstone/models/OpenNebulaJSON/ClusterJSON.rb b/src/sunstone/models/OpenNebulaJSON/ClusterJSON.rb index 1abf67d2a8..c06fc4123c 100644 --- a/src/sunstone/models/OpenNebulaJSON/ClusterJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/ClusterJSON.rb @@ -77,7 +77,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - super(params['template_raw']) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end end def rename(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/DatastoreJSON.rb b/src/sunstone/models/OpenNebulaJSON/DatastoreJSON.rb index fc8437247f..0f5d093171 100644 --- a/src/sunstone/models/OpenNebulaJSON/DatastoreJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/DatastoreJSON.rb @@ -61,7 +61,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - super(params['template_raw']) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end end def chown(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/GroupJSON.rb b/src/sunstone/models/OpenNebulaJSON/GroupJSON.rb index 7fe17fa38d..53939c6d90 100644 --- a/src/sunstone/models/OpenNebulaJSON/GroupJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/GroupJSON.rb @@ -53,7 +53,11 @@ module OpenNebulaJSON end def update_json(params=Hash.new) - update(params['template_raw']) + if !params['append'].nil? + update(params['template_raw'], params['append']) + else + update(params['template_raw']) + end end def set_quota(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/HostJSON.rb b/src/sunstone/models/OpenNebulaJSON/HostJSON.rb index e397cc6df7..99eb964aa9 100644 --- a/src/sunstone/models/OpenNebulaJSON/HostJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/HostJSON.rb @@ -60,7 +60,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - super(params['template_raw']) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end end def rename(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/ImageJSON.rb b/src/sunstone/models/OpenNebulaJSON/ImageJSON.rb index 8b83e1b461..fa399acf87 100644 --- a/src/sunstone/models/OpenNebulaJSON/ImageJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/ImageJSON.rb @@ -71,7 +71,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - super(params['template_raw']) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end end def remove_attr(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/SecurityGroupJSON.rb b/src/sunstone/models/OpenNebulaJSON/SecurityGroupJSON.rb index 18b392ffae..cfea214b9e 100644 --- a/src/sunstone/models/OpenNebulaJSON/SecurityGroupJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/SecurityGroupJSON.rb @@ -57,7 +57,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - super(params['template_raw']) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end end def chown(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb index d49b9f0f8b..fec8431a1d 100644 --- a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb @@ -70,14 +70,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - template_hash = parse_json(params, 'vmtemplate') - if template_hash['template_raw'] - template = template_hash['template_raw'] + if !params['append'].nil? + super(params['template_raw'], params['append']) else - template = template_to_str(template_hash) + super(params['template_raw']) end - - super(template) end def chown(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/VdcJSON.rb b/src/sunstone/models/OpenNebulaJSON/VdcJSON.rb index 816569cf96..122c9ae00d 100644 --- a/src/sunstone/models/OpenNebulaJSON/VdcJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VdcJSON.rb @@ -104,7 +104,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - super(params['template_raw']) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end end def rename(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb index 1cce24e2af..b76067e2a0 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb @@ -173,7 +173,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - super(params['template_raw']) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end end def rename(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb index adc65fb5c8..3626c29255 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb @@ -62,7 +62,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - super(params['template_raw']) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end end def chown(params=Hash.new) diff --git a/src/sunstone/models/OpenNebulaJSON/ZoneJSON.rb b/src/sunstone/models/OpenNebulaJSON/ZoneJSON.rb index 3008e7ba80..1a0f959f64 100644 --- a/src/sunstone/models/OpenNebulaJSON/ZoneJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/ZoneJSON.rb @@ -49,7 +49,11 @@ module OpenNebulaJSON end def update(params=Hash.new) - super(params['template_raw']) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end end def rename(params=Hash.new) diff --git a/src/sunstone/public/app/app.js b/src/sunstone/public/app/app.js index 8cb9ecae3f..7e2aec1a19 100644 --- a/src/sunstone/public/app/app.js +++ b/src/sunstone/public/app/app.js @@ -53,7 +53,7 @@ define(function(require) { _setupCloseDropdownsOnClick(); _insertUserAndZoneSelector(); - Config.initDefaultCost(); + Config.initOnedConf(); if (Config.isTabEnabled(PROVISION_TAB_ID)) { Sunstone.showTab(PROVISION_TAB_ID); diff --git a/src/sunstone/public/app/opennebula/cluster.js b/src/sunstone/public/app/opennebula/cluster.js index 727dc8b2e8..89962fb33a 100644 --- a/src/sunstone/public/app/opennebula/cluster.js +++ b/src/sunstone/public/app/opennebula/cluster.js @@ -64,6 +64,10 @@ define(function(require) { var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "rename" : function(params) { var action_obj = params.data.extra_param; OpenNebulaAction.simple_action(params, RESOURCE, "rename", action_obj); diff --git a/src/sunstone/public/app/opennebula/datastore.js b/src/sunstone/public/app/opennebula/datastore.js index 78c2121704..37353b581e 100644 --- a/src/sunstone/public/app/opennebula/datastore.js +++ b/src/sunstone/public/app/opennebula/datastore.js @@ -79,6 +79,10 @@ define(function(require) { var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "rename" : function(params) { var action_obj = params.data.extra_param; OpenNebulaAction.simple_action(params, RESOURCE, "rename", action_obj); diff --git a/src/sunstone/public/app/opennebula/group.js b/src/sunstone/public/app/opennebula/group.js index 5f50c865d2..ca9be524fd 100644 --- a/src/sunstone/public/app/opennebula/group.js +++ b/src/sunstone/public/app/opennebula/group.js @@ -60,6 +60,10 @@ define(function(require) { var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "set_quota" : function(params) { var action_obj = {quotas : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "set_quota", action_obj); diff --git a/src/sunstone/public/app/opennebula/host.js b/src/sunstone/public/app/opennebula/host.js index 1eb7ec04be..24527bf27a 100644 --- a/src/sunstone/public/app/opennebula/host.js +++ b/src/sunstone/public/app/opennebula/host.js @@ -99,6 +99,11 @@ define(function(require) { OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); _clearCache(); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + _clearCache(); + }, "enable": function(params) { OpenNebulaAction.simple_action(params, RESOURCE, "enable"); _clearCache(); diff --git a/src/sunstone/public/app/opennebula/image.js b/src/sunstone/public/app/opennebula/image.js index 77942faa1d..cb0665b248 100644 --- a/src/sunstone/public/app/opennebula/image.js +++ b/src/sunstone/public/app/opennebula/image.js @@ -93,6 +93,10 @@ define(function(require) { var action_obj = params.data.extra_param; OpenNebulaAction.simple_action(params, RESOURCE, "chmod", action_obj); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "update": function(params) { var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); diff --git a/src/sunstone/public/app/opennebula/network.js b/src/sunstone/public/app/opennebula/network.js index 130bff63e0..4922c8b51b 100644 --- a/src/sunstone/public/app/opennebula/network.js +++ b/src/sunstone/public/app/opennebula/network.js @@ -80,6 +80,10 @@ define(function(require) { var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "rename" : function(params) { var action_obj = params.data.extra_param; OpenNebulaAction.simple_action(params, RESOURCE, "rename", action_obj); diff --git a/src/sunstone/public/app/opennebula/securitygroup.js b/src/sunstone/public/app/opennebula/securitygroup.js index 6d40ac8639..2b75c5f6bb 100644 --- a/src/sunstone/public/app/opennebula/securitygroup.js +++ b/src/sunstone/public/app/opennebula/securitygroup.js @@ -48,6 +48,10 @@ define(function(require) { var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "clone" : function(params) { var name = params.data.extra_param ? params.data.extra_param : ""; var action_obj = {"name" : name}; diff --git a/src/sunstone/public/app/opennebula/service.js b/src/sunstone/public/app/opennebula/service.js index 38e8a5ade4..86cd0955b1 100644 --- a/src/sunstone/public/app/opennebula/service.js +++ b/src/sunstone/public/app/opennebula/service.js @@ -85,6 +85,10 @@ define(function(require) { params.cache_name = CACHE_NAME; OpenNebulaAction.simple_action(params, RESOURCE, "recover", null, PATH); }, + "rename" : function(params) { + var action_obj = params.data.extra_param; + OpenNebulaAction.simple_action(params, RESOURCE, "rename", action_obj, PATH); + }, "stateStr" : function(stateId) { return STATES_STR[stateId]; }, diff --git a/src/sunstone/public/app/opennebula/servicetemplate.js b/src/sunstone/public/app/opennebula/servicetemplate.js index 9c001834d4..462d0e8328 100644 --- a/src/sunstone/public/app/opennebula/servicetemplate.js +++ b/src/sunstone/public/app/opennebula/servicetemplate.js @@ -63,6 +63,10 @@ define(function(require) { var action_obj = params.data.extra_param; OpenNebulaAction.simple_action(params, RESOURCE, "chmod", action_obj, PATH); }, + "rename" : function(params) { + var action_obj = params.data.extra_param; + OpenNebulaAction.simple_action(params, RESOURCE, "rename", action_obj, PATH); + }, "getName": function(id){ return OpenNebulaAction.getName(id, CACHE_NAME); } diff --git a/src/sunstone/public/app/opennebula/template.js b/src/sunstone/public/app/opennebula/template.js index 9498d59652..b76bc6d65a 100644 --- a/src/sunstone/public/app/opennebula/template.js +++ b/src/sunstone/public/app/opennebula/template.js @@ -50,8 +50,12 @@ define(function(require) { var action_obj = params.data.extra_param; OpenNebulaAction.simple_action(params, RESOURCE, "chmod_from_provision", action_obj); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "update" : function(params) { - var action_obj = params.data.extra_param; + var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); }, "publish" : function(params) { diff --git a/src/sunstone/public/app/opennebula/vdc.js b/src/sunstone/public/app/opennebula/vdc.js index 332886f02c..66d4d5b595 100644 --- a/src/sunstone/public/app/opennebula/vdc.js +++ b/src/sunstone/public/app/opennebula/vdc.js @@ -37,6 +37,10 @@ define(function(require) { var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "rename" : function(params) { var action_obj = params.data.extra_param; OpenNebulaAction.simple_action(params, RESOURCE, "rename", action_obj); diff --git a/src/sunstone/public/app/opennebula/vm.js b/src/sunstone/public/app/opennebula/vm.js index 57b8533022..2a096f8fac 100644 --- a/src/sunstone/public/app/opennebula/vm.js +++ b/src/sunstone/public/app/opennebula/vm.js @@ -450,6 +450,10 @@ define(function(require) { } }); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "update": function(params) { var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); diff --git a/src/sunstone/public/app/opennebula/zone.js b/src/sunstone/public/app/opennebula/zone.js index b42b3a7f0a..b2e61cdefa 100644 --- a/src/sunstone/public/app/opennebula/zone.js +++ b/src/sunstone/public/app/opennebula/zone.js @@ -37,6 +37,10 @@ define(function(require) { var action_obj = {"template_raw" : params.data.extra_param}; OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); }, + "append": function(params) { + var action_obj = {"template_raw" : params.data.extra_param, append : true}; + OpenNebulaAction.simple_action(params, RESOURCE, "update", action_obj); + }, "rename" : function(params) { var action_obj = params.data.extra_param; OpenNebulaAction.simple_action(params, RESOURCE, "rename", action_obj); diff --git a/src/sunstone/public/app/sunstone-config.js b/src/sunstone/public/app/sunstone-config.js index 2901d367a3..d7c6c1e9da 100644 --- a/src/sunstone/public/app/sunstone-config.js +++ b/src/sunstone/public/app/sunstone-config.js @@ -27,6 +27,8 @@ define(function(require) { diskCost : 0 }; + var _dsMadConf = {}; + var Config = { 'isTabEnabled': function(tabName) { var enabled = _config['view']['enabled_tabs'].indexOf(tabName) != -1; @@ -62,7 +64,7 @@ define(function(require) { if (_config['view']['tabs'][tabName]['provision_tabs']) { return _config['view']['tabs'][tabName]['provision_tabs'][panelTabName]; } else { - // if provision_tabs is not defined use panel_tabs. + // if provision_tabs is not defined use panel_tabs. // This attribute was used in before 4.14, provision_tabs was include in 4.14.2 return _config['view']['tabs'][tabName]['panel_tabs'][panelTabName]; } @@ -152,7 +154,8 @@ define(function(require) { 'vmLogos': (_config['vm_logos']), 'enabledTabs': _config['view']['enabled_tabs'], "defaultCost" : _defaultCost, - "initDefaultCost" : function() { + 'dsMadConf' : _dsMadConf, + "initOnedConf" : function() { OpenNebulaSystem.onedconf({ data : {}, timeout: true, @@ -168,6 +171,10 @@ define(function(require) { _defaultCost.diskCost = parseInt(onedconf.DEFAULT_COST.DISK_COST); } } + + if (onedconf.DS_MAD_CONF != undefined){ + jQuery.extend(true, _dsMadConf, onedconf.DS_MAD_CONF); + } }, error: function(request, error_json){ console.error("There was an error requesting oned.conf: "+ diff --git a/src/sunstone/public/app/sunstone.js b/src/sunstone/public/app/sunstone.js index e5b8fd7f59..5291e5bb5e 100644 --- a/src/sunstone/public/app/sunstone.js +++ b/src/sunstone/public/app/sunstone.js @@ -131,8 +131,15 @@ define(function(require) { } var _setupDataTable = function(tabName) { - if (SunstoneCfg['tabs'][tabName].dataTable) { - SunstoneCfg['tabs'][tabName].dataTable.initialize(); + var dataTable = SunstoneCfg['tabs'][tabName].dataTable; + if (dataTable) { + dataTable.initialize(); + if (dataTable.labelsColumn) { + $('#' + tabName + 'labels_buttons').html( + '' + + '
    '); + } } } @@ -454,13 +461,13 @@ define(function(require) { var _setupTabs = function() { var topTabs = $(".left-content ul li.topTab"); - var subTabs = $(".left-content ul li.subTab"); + var subTabs = $(".left-content ul li.subTab > a"); subTabs.on("click", function() { - if ($(this).hasClass('topTab')) { + if ($(this).closest('li').hasClass('topTab')) { return false; } else { - var tabName = $(this).attr('id').substring(3); + var tabName = $(this).closest('li').attr('id').substring(3); _showTab(tabName); return false; } @@ -527,6 +534,7 @@ define(function(require) { //clean selected menu $("#navigation li").removeClass("navigation-active-li"); $("#navigation li#li_" + tabName).addClass("navigation-active-li"); + $('.tree', '#navigation').remove(); var tab = $('#' + tabName); //show tab @@ -534,6 +542,9 @@ define(function(require) { var dataTable = SunstoneCfg['tabs'][tabName]['dataTable']; if (dataTable) { + if (dataTable.clearLabelsFilter) { + dataTable.clearLabelsFilter(); + } dataTable.recountCheckboxes(); } @@ -971,6 +982,12 @@ define(function(require) { } } + var _getResource = function(tabName) { + if (SunstoneCfg['tabs'][tabName]) { + return SunstoneCfg['tabs'][tabName].resource; + } + } + var _getDialogInstance = function(dialogId) { var dialogInstance = SunstoneCfg['dialogInstances'][dialogId]; if (dialogInstance == undefined) { @@ -1011,6 +1028,7 @@ define(function(require) { "getAction": _getAction, "getButton": _getButton, "getDataTable": _getDataTable, + "getResource": _getResource, "getDialog": _getDialogInstance, "insertButtonsInTab": _insertButtonsInTab, diff --git a/src/sunstone/public/app/sunstone/buttons.hbs b/src/sunstone/public/app/sunstone/buttons.hbs index 825189e4c0..f02abe6c6b 100644 --- a/src/sunstone/public/app/sunstone/buttons.hbs +++ b/src/sunstone/public/app/sunstone/buttons.hbs @@ -29,6 +29,7 @@ +
      diff --git a/src/sunstone/public/app/tabs/clusters-tab/actions.js b/src/sunstone/public/app/tabs/clusters-tab/actions.js index e04e226f6e..cc7c4041f6 100644 --- a/src/sunstone/public/app/tabs/clusters-tab/actions.js +++ b/src/sunstone/public/app/tabs/clusters-tab/actions.js @@ -37,6 +37,7 @@ define(function(require) { "Cluster.refresh" : _commonActions.refresh(), "Cluster.delete" : _commonActions.del(), "Cluster.update_template" : _commonActions.updateTemplate(), + "Cluster.append_template" : _commonActions.appendTemplate(), "Cluster.update_dialog" : _commonActions.checkAndShowUpdate(), "Cluster.show_to_update" : _commonActions.showUpdate(CREATE_DIALOG_ID), "Cluster.rename": _commonActions.singleAction('rename'), diff --git a/src/sunstone/public/app/tabs/clusters-tab/datatable.js b/src/sunstone/public/app/tabs/clusters-tab/datatable.js index aec30cd390..ab8d188223 100644 --- a/src/sunstone/public/app/tabs/clusters-tab/datatable.js +++ b/src/sunstone/public/app/tabs/clusters-tab/datatable.js @@ -22,6 +22,7 @@ define(function(require) { var TabDataTable = require('utils/tab-datatable'); var SunstoneConfig = require('sunstone-config'); var Locale = require('utils/locale'); + var LabelsUtils = require('utils/labels/utils'); /* CONSTANTS @@ -30,6 +31,8 @@ define(function(require) { var RESOURCE = "Cluster"; var XML_ROOT = "CLUSTER"; var TAB_NAME = require('./tabId'); + var LABELS_COLUMN = 6; + var TEMPLATE_ATTR = 'TEMPLATE'; /* CONSTRUCTOR @@ -41,6 +44,7 @@ define(function(require) { this.dataTableId = dataTableId; this.resource = RESOURCE; this.xmlRoot = XML_ROOT; + this.labelsColumn = LABELS_COLUMN; this.dataTableOptions = { "bAutoWidth": false, @@ -59,7 +63,8 @@ define(function(require) { Locale.tr("Name"), Locale.tr("Hosts"), Locale.tr("VNets"), - Locale.tr("Datastores") + Locale.tr("Datastores"), + Locale.tr("Labels") ]; this.selectOptions = { @@ -95,7 +100,8 @@ define(function(require) { element.NAME, _lengthOf(element.HOSTS.ID), _lengthOf(element.VNETS.ID), - _lengthOf(element.DATASTORES.ID) + _lengthOf(element.DATASTORES.ID), + (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||'') ]; } diff --git a/src/sunstone/public/app/tabs/datastores-tab/actions.js b/src/sunstone/public/app/tabs/datastores-tab/actions.js index 1428c6c12d..da01b39d82 100644 --- a/src/sunstone/public/app/tabs/datastores-tab/actions.js +++ b/src/sunstone/public/app/tabs/datastores-tab/actions.js @@ -42,6 +42,7 @@ define(function(require) { "Datastore.chmod": _commonActions.singleAction('chmod'), "Datastore.update" : _commonActions.updateTemplate(), "Datastore.update_template" : _commonActions.updateTemplate(), + "Datastore.append_template" : _commonActions.appendTemplate(), "Datastore.rename": _commonActions.singleAction('rename'), "Datastore.enable": _commonActions.multipleAction('enable'), "Datastore.disable": _commonActions.multipleAction('disable'), diff --git a/src/sunstone/public/app/tabs/datastores-tab/datatable.js b/src/sunstone/public/app/tabs/datastores-tab/datatable.js index 762e4622a5..7f0ffd230a 100644 --- a/src/sunstone/public/app/tabs/datastores-tab/datatable.js +++ b/src/sunstone/public/app/tabs/datastores-tab/datatable.js @@ -24,6 +24,7 @@ define(function(require) { var Locale = require('utils/locale'); var OpenNebulaDatastore = require('opennebula/datastore'); var DatastoreCapacityBar = require('./utils/datastore-capacity-bar'); + var LabelsUtils = require('utils/labels/utils'); /* CONSTANTS @@ -32,6 +33,8 @@ define(function(require) { var RESOURCE = "Datastore"; var XML_ROOT = "DATASTORE"; var TAB_NAME = require('./tabId'); + var LABELS_COLUMN = 12; + var TEMPLATE_ATTR = 'TEMPLATE'; /* CONSTRUCTOR @@ -57,6 +60,7 @@ define(function(require) { this.dataTableId = dataTableId; this.resource = RESOURCE; this.xmlRoot = XML_ROOT; + this.labelsColumn = LABELS_COLUMN; this.dataTableOptions = { "bAutoWidth": false, @@ -83,6 +87,7 @@ define(function(require) { Locale.tr("DS MAD"), Locale.tr("Type"), Locale.tr("Status"), + Locale.tr("Labels") ] this.selectOptions = { @@ -125,7 +130,8 @@ define(function(require) { element.TM_MAD, element.DS_MAD, OpenNebulaDatastore.typeStr(element.TYPE), - OpenNebulaDatastore.stateStr(element.STATE) + OpenNebulaDatastore.stateStr(element.STATE), + (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||'') ]; } }); diff --git a/src/sunstone/public/app/tabs/datastores-tab/form-panels/create.js b/src/sunstone/public/app/tabs/datastores-tab/form-panels/create.js index b546e87597..97dac7da4f 100644 --- a/src/sunstone/public/app/tabs/datastores-tab/form-panels/create.js +++ b/src/sunstone/public/app/tabs/datastores-tab/form-panels/create.js @@ -26,6 +26,7 @@ define(function(require) { var Notifier = require('utils/notifier'); var Tips = require('utils/tips'); var ResourceSelect = require('utils/resource-select'); + var Config = require('sunstone-config'); /* TEMPLATES @@ -125,28 +126,45 @@ define(function(require) { $('#presets', dialog).change(function() { _hideAll(dialog); var choice_str = $(this).val(); + + // Disable all required attributes except for those that come in the + // template. + $('input[required_active]', dialog).removeAttr('required') + .removeAttr('required_active'); + switch (choice_str) { case 'fs': _selectFilesystem(dialog); + // _setRequiredFields(dialog, ''); break; case 'vmware_vmfs': _selectVmwareVmfs(dialog); + _setRequiredFields(dialog, 'vmfs'); break; case 'block_lvm': _selectBlockLvm(dialog); + _setRequiredFields(dialog, 'lvm'); break; case 'fs_lvm': _selectFsLvm(dialog); + // _setRequiredFields(dialog, ''); break; case 'ceph': _selectCeph(dialog); + _setRequiredFields(dialog, 'ceph'); break; case 'gluster': _selectGluster(dialog); + // _setRequiredFields(dialog, ''); break; case 'dev': _selectDevices(dialog); + _setRequiredFields(dialog, 'dev'); + break; + case 'iscsi': + _selectISCSI(dialog); + _setRequiredFields(dialog, 'iscsi'); break; case 'custom': _selectCustom(dialog); @@ -154,6 +172,8 @@ define(function(require) { } }); + $('#presets', dialog).change(); + // Hide disk_type $('select#disk_type', dialog).parent().hide(); @@ -192,6 +212,9 @@ define(function(require) { var rbd_format = $('#rbd_format', dialog).val(); var staging_dir = $('#staging_dir', dialog).val(); var ceph_conf = $('#ceph_conf', dialog).val(); + var iscsi_host = $('#iscsi_host', dialog).val(); + var iscsi_user = $('#iscsi_user', dialog).val(); + var iscsi_usage = $('#iscsi_usage', dialog).val(); var ds_obj = { "datastore" : { @@ -265,6 +288,15 @@ define(function(require) { if (ceph_conf) ds_obj.datastore.ceph_conf = ceph_conf; + if (iscsi_host) + ds_obj.datastore.iscsi_host = iscsi_host; + + if (iscsi_user) + ds_obj.datastore.iscsi_user = iscsi_user; + + if (iscsi_usage) + ds_obj.datastore.iscsi_usage = iscsi_usage; + Sunstone.runAction("Datastore.create", ds_obj); return false; } @@ -308,6 +340,9 @@ define(function(require) { $('label[for="rbd_format"],input#rbd_format', dialog).parent().hide(); $('label[for="staging_dir"],input#staging_dir', dialog).parent().hide(); $('label[for="ceph_conf"],input#ceph_conf', dialog).parent().hide(); + $('label[for="iscsi_host"],input#ceph_conf', dialog).parent().hide(); + $('label[for="iscsi_user"],input#ceph_conf', dialog).parent().hide(); + $('label[for="iscsi_usage"],input#ceph_conf', dialog).parent().hide(); $('label[for="limit_transfer_bw"],input#limit_transfer_bw', dialog).parent().hide(); $('label[for="no_decompress"],input#no_decompress', dialog).parent().hide(); $('select#ds_mad', dialog).removeAttr('disabled'); @@ -478,6 +513,27 @@ define(function(require) { $('input#restricted_dirs', dialog).attr('disabled', 'disabled'); } + function _selectISCSI(dialog) { + $('select#ds_mad', dialog).val('iscsi'); + $('select#ds_mad', dialog).attr('disabled', 'disabled'); + $('select#tm_mad', dialog).val('iscsi'); + $('select#tm_mad', dialog).attr('disabled', 'disabled'); + $('input#image_ds_type', dialog).click(); + $('input[name=ds_type]', dialog).attr('disabled', 'disabled'); + $('label[for="iscsi_host"],input#iscsi_host', dialog).parent().fadeIn(); + $('label[for="iscsi_user"],input#iscsi_user', dialog).parent().fadeIn(); + $('label[for="iscsi_usage"],input#iscsi_usage', dialog).parent().fadeIn(); + $('select#disk_type', dialog).val('iscsi'); + $('select#disk_type', dialog).attr('disabled', 'disabled'); + $('label[for="limit_transfer_bw"],input#limit_transfer_bw', dialog).parent().hide(); + $('label[for="no_decompress"],input#no_decompress', dialog).parent().hide(); + $('label[for="datastore_capacity_check"],input#datastore_capacity_check', dialog).parent().hide(); + $('input#safe_dirs', dialog).attr('disabled', 'disabled'); + $('input#base_path', dialog).attr('disabled', 'disabled'); + $('input#limit_mb', dialog).attr('disabled', 'disabled'); + $('input#restricted_dirs', dialog).attr('disabled', 'disabled'); + } + function _selectCustom(dialog) { _hideAll(dialog); $('select#ds_mad', dialog).val('fs'); @@ -491,4 +547,25 @@ define(function(require) { $('label[for="no_decompress"],input#no_decompress', dialog).parent().fadeIn(); $('label[for="datastore_capacity_check"],input#datastore_capacity_check', dialog).parent().fadeIn(); } + + function _setRequiredFields(dialog, mad) { + $.each(Config.dsMadConf,function(i,e){ + if (e["NAME"] == mad) { + if (!$.isEmptyObject(e["REQUIRED_ATTRS"])) { + var required_attrs = e["REQUIRED_ATTRS"].split(","); + + if (required_attrs != undefined){ + $.each(required_attrs, function(i,e){ + $('input#' + e.toLowerCase(), dialog).attr('required', true) + .attr('required_active', ''); + }); + } + + } + return false; + } + } + ); + } }); + diff --git a/src/sunstone/public/app/tabs/datastores-tab/form-panels/create/wizard.hbs b/src/sunstone/public/app/tabs/datastores-tab/form-panels/create/wizard.hbs index e55b8c5cec..cf469bd207 100644 --- a/src/sunstone/public/app/tabs/datastores-tab/form-panels/create/wizard.hbs +++ b/src/sunstone/public/app/tabs/datastores-tab/form-panels/create/wizard.hbs @@ -32,6 +32,7 @@ + @@ -68,6 +69,7 @@ +
      @@ -86,6 +88,7 @@ +
      @@ -104,6 +107,7 @@ +
      @@ -267,5 +271,32 @@ +
      + + +
      +
      + + +
      +
      + + +
      diff --git a/src/sunstone/public/app/tabs/files-tab/actions.js b/src/sunstone/public/app/tabs/files-tab/actions.js index d2f02b6948..f454795bf6 100644 --- a/src/sunstone/public/app/tabs/files-tab/actions.js +++ b/src/sunstone/public/app/tabs/files-tab/actions.js @@ -36,6 +36,7 @@ define(function(require) { "File.refresh" : _commonActions.refresh(), "File.delete" : _commonActions.del(), "File.update_template" : _commonActions.updateTemplate(), + "File.append_template" : _commonActions.appendTemplate(), "File.chown": _commonActions.multipleAction('chown'), "File.chgrp": _commonActions.multipleAction('chgrp'), "File.chmod": _commonActions.singleAction('chmod'), diff --git a/src/sunstone/public/app/tabs/files-tab/datatable.js b/src/sunstone/public/app/tabs/files-tab/datatable.js index 3fe6354e82..1ebe7f048d 100644 --- a/src/sunstone/public/app/tabs/files-tab/datatable.js +++ b/src/sunstone/public/app/tabs/files-tab/datatable.js @@ -25,6 +25,7 @@ define(function(require) { var Humanize = require('utils/humanize'); var Notifier = require('utils/notifier'); var OpenNebulaImage = require('opennebula/image'); + var LabelsUtils = require('utils/labels/utils'); /* CONSTANTS @@ -33,6 +34,8 @@ define(function(require) { var RESOURCE = "File"; var XML_ROOT = "IMAGE"; var TAB_NAME = require('./tabId'); + var LABELS_COLUMN = 13; + var TEMPLATE_ATTR = 'TEMPLATE'; /* CONSTRUCTOR @@ -44,6 +47,7 @@ define(function(require) { this.dataTableId = dataTableId; this.resource = RESOURCE; this.xmlRoot = XML_ROOT; + this.labelsColumn = LABELS_COLUMN; this.dataTableOptions = { "bAutoWidth": false, @@ -70,6 +74,7 @@ define(function(require) { Locale.tr("Status"), Locale.tr("#VMS"), Locale.tr("Target"), + Locale.tr("Labels") ]; this.selectOptions = { @@ -119,7 +124,8 @@ define(function(require) { parseInt(element.PERSISTENT) ? "yes" : "no", OpenNebulaImage.stateStr(element.STATE), element.RUNNING_VMS, - element.TEMPLATE.TARGET ? element.TEMPLATE.TARGET : '--' + element.TEMPLATE.TARGET ? element.TEMPLATE.TARGET : '--', + (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||'') ]; } }); diff --git a/src/sunstone/public/app/tabs/groups-tab/actions.js b/src/sunstone/public/app/tabs/groups-tab/actions.js index 9cd71c5c18..8a41a2e667 100644 --- a/src/sunstone/public/app/tabs/groups-tab/actions.js +++ b/src/sunstone/public/app/tabs/groups-tab/actions.js @@ -40,6 +40,7 @@ define(function(require) { "Group.delete" : _commonActions.del(), "Group.update" : _commonActions.update(), "Group.update_template" : _commonActions.updateTemplate(), + "Group.append_template" : _commonActions.appendTemplate(), "Group.update_dialog" : _commonActions.checkAndShowUpdate(), "Group.show_to_update" : _commonActions.showUpdate(CREATE_DIALOG_ID), diff --git a/src/sunstone/public/app/tabs/groups-tab/datatable.js b/src/sunstone/public/app/tabs/groups-tab/datatable.js index 8b7f8d785d..4669f50dcd 100644 --- a/src/sunstone/public/app/tabs/groups-tab/datatable.js +++ b/src/sunstone/public/app/tabs/groups-tab/datatable.js @@ -24,6 +24,7 @@ define(function(require) { var Locale = require('utils/locale'); var QuotaDefaults = require('utils/quotas/quota-defaults'); var QuotaWidgets = require('utils/quotas/quota-widgets'); + var LabelsUtils = require('utils/labels/utils'); /* CONSTANTS @@ -32,6 +33,8 @@ define(function(require) { var RESOURCE = "Group"; var XML_ROOT = "GROUP"; var TAB_NAME = require('./tabId'); + var LABELS_COLUMN = 7; + var TEMPLATE_ATTR = 'TEMPLATE'; /* CONSTRUCTOR @@ -43,6 +46,7 @@ define(function(require) { this.dataTableId = dataTableId; this.resource = RESOURCE; this.xmlRoot = XML_ROOT; + this.labelsColumn = LABELS_COLUMN; this.dataTableOptions = { "bAutoWidth": false, @@ -63,7 +67,8 @@ define(function(require) { Locale.tr("Users"), Locale.tr("VMs"), Locale.tr("Memory"), - Locale.tr("CPU") + Locale.tr("CPU"), + Locale.tr("Labels") ]; this.selectOptions = { @@ -141,7 +146,8 @@ define(function(require) { users_str, vms, memory, - cpu + cpu, + (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||'') ]; } diff --git a/src/sunstone/public/app/tabs/hosts-tab/actions.js b/src/sunstone/public/app/tabs/hosts-tab/actions.js index d6934377c6..80e6a18cc0 100644 --- a/src/sunstone/public/app/tabs/hosts-tab/actions.js +++ b/src/sunstone/public/app/tabs/hosts-tab/actions.js @@ -39,6 +39,7 @@ define(function(require) { "Host.refresh" : _commonActions.refresh(), "Host.delete" : _commonActions.del(), "Host.update_template" : _commonActions.updateTemplate(), + "Host.append_template" : _commonActions.appendTemplate(), "Host.enable": _commonActions.multipleAction('enable'), "Host.disable": _commonActions.multipleAction('disable'), "Host.rename": _commonActions.singleAction('rename'), diff --git a/src/sunstone/public/app/tabs/hosts-tab/datatable.js b/src/sunstone/public/app/tabs/hosts-tab/datatable.js index 9b575684fc..0c382437fa 100644 --- a/src/sunstone/public/app/tabs/hosts-tab/datatable.js +++ b/src/sunstone/public/app/tabs/hosts-tab/datatable.js @@ -25,7 +25,9 @@ define(function(require) { var Humanize = require('utils/humanize'); var CPUBars = require('./utils/cpu-bars'); var MemoryBars = require('./utils/memory-bars'); - var OpenNebulaHost = require('opennebula/host') + var OpenNebulaHost = require('opennebula/host'); + var LabelsUtils = require('utils/labels/utils'); + /* CONSTANTS @@ -34,6 +36,8 @@ define(function(require) { var RESOURCE = "Host"; var XML_ROOT = "HOST"; var TAB_NAME = require('./tabId'); + var LABELS_COLUMN = 13; + var TEMPLATE_ATTR = 'TEMPLATE'; /* CONSTRUCTOR @@ -45,6 +49,7 @@ define(function(require) { this.dataTableId = dataTableId; this.resource = RESOURCE; this.xmlRoot = XML_ROOT; + this.labelsColumn = LABELS_COLUMN; this.dataTableOptions = { "bAutoWidth": false, @@ -70,7 +75,8 @@ define(function(require) { Locale.tr("Status"), Locale.tr("IM MAD"), Locale.tr("VM MAD"), - Locale.tr("Last monitored on") + Locale.tr("Last monitored on"), + Locale.tr("Labels") ]; this.selectOptions = { @@ -157,7 +163,8 @@ define(function(require) { OpenNebulaHost.simpleStateStr(element.STATE), element.IM_MAD, element.VM_MAD, - Humanize.prettyTime(element.LAST_MON_TIME) + Humanize.prettyTime(element.LAST_MON_TIME), + (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||'') ]; } diff --git a/src/sunstone/public/app/tabs/images-tab/actions.js b/src/sunstone/public/app/tabs/images-tab/actions.js index c8b1117fa8..bc7fe8f977 100644 --- a/src/sunstone/public/app/tabs/images-tab/actions.js +++ b/src/sunstone/public/app/tabs/images-tab/actions.js @@ -36,6 +36,7 @@ define(function(require) { "Image.show" : _commonActions.show(), "Image.refresh" : _commonActions.refresh(), "Image.delete" : _commonActions.del(), + "Image.append_template" : _commonActions.appendTemplate(), "Image.update_template" : _commonActions.updateTemplate(), "Image.chown": _commonActions.multipleAction('chown'), "Image.chgrp": _commonActions.multipleAction('chgrp'), diff --git a/src/sunstone/public/app/tabs/images-tab/datatable.js b/src/sunstone/public/app/tabs/images-tab/datatable.js index e47882c872..b9f1aa80f3 100644 --- a/src/sunstone/public/app/tabs/images-tab/datatable.js +++ b/src/sunstone/public/app/tabs/images-tab/datatable.js @@ -25,6 +25,7 @@ define(function(require) { var Humanize = require('utils/humanize'); var Notifier = require('utils/notifier'); var OpenNebulaImage = require('opennebula/image'); + var LabelsUtils = require('utils/labels/utils'); /* CONSTANTS @@ -33,6 +34,8 @@ define(function(require) { var RESOURCE = "Image" var XML_ROOT = "IMAGE" var TAB_NAME = require('./tabId'); + var LABELS_COLUMN = 13; + var TEMPLATE_ATTR = 'TEMPLATE'; /* CONSTRUCTOR @@ -44,6 +47,7 @@ define(function(require) { this.dataTableId = dataTableId; this.resource = RESOURCE; this.xmlRoot = XML_ROOT; + this.labelsColumn = LABELS_COLUMN; this.dataTableOptions = { "bAutoWidth": false, @@ -70,6 +74,7 @@ define(function(require) { Locale.tr("Status"), Locale.tr("#VMS"), Locale.tr("Target"), + Locale.tr("Labels") ] this.selectOptions = { @@ -125,7 +130,8 @@ define(function(require) { parseInt(element.PERSISTENT) ? "yes" : "no", OpenNebulaImage.stateStr(element.STATE), element.RUNNING_VMS, - element.TEMPLATE.TARGET ? element.TEMPLATE.TARGET : '--' + element.TEMPLATE.TARGET ? element.TEMPLATE.TARGET : '--', + (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||'') ]; } diff --git a/src/sunstone/public/app/tabs/images-tab/form-panels/create.js b/src/sunstone/public/app/tabs/images-tab/form-panels/create.js index d744c82ee5..ad959ce415 100644 --- a/src/sunstone/public/app/tabs/images-tab/form-panels/create.js +++ b/src/sunstone/public/app/tabs/images-tab/form-panels/create.js @@ -26,9 +26,11 @@ define(function(require) { var Notifier = require('utils/notifier'); var Locale = require('utils/locale'); var Tips = require('utils/tips'); + var OpenNebulaDatastore = require('opennebula/datastore'); var ResourceSelect = require('utils/resource-select'); var CustomTagsTable = require('utils/custom-tags-table'); var BrowserInfo = require('utils/browser-info'); + var Config = require('sunstone-config'); var TemplateWizardHTML = require('hbs!./create/wizard'); var TemplateAdvancedHTML = require('hbs!./create/advanced'); @@ -97,10 +99,10 @@ define(function(require) { var filter_val = ["1", "2"]; ResourceSelect.insert('div#img_datastore', context, "Datastore", - ds_id, false, null, filter_att, filter_val); + ds_id, false, null, filter_att, filter_val, true); ResourceSelect.insert('div#img_datastore_raw', context, "Datastore", - ds_id_raw, false, null, filter_att, filter_val); + ds_id_raw, false, null, filter_att, filter_val, true); return false; } @@ -122,6 +124,43 @@ define(function(require) { } }); + $('#img_datastore', context).off('change', '.resource_list_select'); + $('#img_datastore', context).on('change', '.resource_list_select', function() { + var ds_id = $(this).val(); + OpenNebulaDatastore.show({ + data : { + id: ds_id + }, + timeout: true, + success: function(request, ds){ + var mad = ds["DATASTORE"]["DS_MAD"]; + var pers_forced = false; + + // Set the persistency + $.each(Config.dsMadConf,function(i,e){ + if (e["NAME"] == mad && !$.isEmptyObject(e["PERSISTENT_ONLY"])) { + if (e["PERSISTENT_ONLY"] != undefined && + e["PERSISTENT_ONLY"].toLowerCase() == "yes") { + $('#img_persistent', context).prop('disabled', true); + $('#img_persistent', context).prop('checked', true); + pers_forced = true; + return false; + } + } + } + ); + + if (!pers_forced) { + $('#img_persistent', context).prop('disabled', false); + } + + }, + error: function(request, error_json, container){ + Notifier.onError(request, error_json, container); + } + }); + }); + $('#img_path,#img_fstype,#img_size,#file-uploader', context).closest('.row').hide(); $("input[name='src_path']", context).change(function() { diff --git a/src/sunstone/public/app/tabs/oneflow-services-tab/actions.js b/src/sunstone/public/app/tabs/oneflow-services-tab/actions.js index 0e74f6e502..602e2b1679 100644 --- a/src/sunstone/public/app/tabs/oneflow-services-tab/actions.js +++ b/src/sunstone/public/app/tabs/oneflow-services-tab/actions.js @@ -67,6 +67,7 @@ define(function(require) { "Service.chown": _commonActions.multipleAction('chown'), "Service.chgrp": _commonActions.multipleAction('chgrp'), "Service.chmod": _commonActions.singleAction('chmod'), + "Service.rename": _commonActions.singleAction('rename'), "Service.shutdown": _commonActions.multipleAction('shutdown'), "Service.recover": _commonActions.multipleAction('recover'), diff --git a/src/sunstone/public/app/tabs/oneflow-services-tab/panels/info.js b/src/sunstone/public/app/tabs/oneflow-services-tab/panels/info.js index 26e40e1c6e..7eebf3385d 100644 --- a/src/sunstone/public/app/tabs/oneflow-services-tab/panels/info.js +++ b/src/sunstone/public/app/tabs/oneflow-services-tab/panels/info.js @@ -20,6 +20,7 @@ define(function(require) { */ var Locale = require('utils/locale'); + var RenameTr = require('utils/panel/rename-tr'); var PermissionsTable = require('utils/panel/permissions-table'); var OpenNebulaService = require('opennebula/service'); @@ -62,16 +63,19 @@ define(function(require) { */ function _html() { + var renameTrHTML = RenameTr.html(TAB_ID, RESOURCE, this.element.NAME); var permissionsTableHTML = PermissionsTable.html(TAB_ID, RESOURCE, this.element); return TemplateHTML({ 'element': this.element, + 'renameTrHTML': renameTrHTML, 'permissionsTableHTML': permissionsTableHTML, 'stateStr': OpenNebulaService.stateStr(this.element.TEMPLATE.BODY.state) }); } function _setup(context) { + RenameTr.setup(TAB_ID, RESOURCE, this.element.ID, context); PermissionsTable.setup(TAB_ID, RESOURCE, this.element, context); } }); diff --git a/src/sunstone/public/app/tabs/oneflow-services-tab/panels/info/html.hbs b/src/sunstone/public/app/tabs/oneflow-services-tab/panels/info/html.hbs index 1ca635c410..7ab1d294ec 100644 --- a/src/sunstone/public/app/tabs/oneflow-services-tab/panels/info/html.hbs +++ b/src/sunstone/public/app/tabs/oneflow-services-tab/panels/info/html.hbs @@ -27,10 +27,7 @@ {{tr "ID"}} {{element.ID}} - - {{tr "Name"}} - {{element.NAME}} - + {{{renameTrHTML}}} {{tr "Strategy"}} {{element.TEMPLATE.BODY.deployment}} diff --git a/src/sunstone/public/app/tabs/oneflow-templates-tab/actions.js b/src/sunstone/public/app/tabs/oneflow-templates-tab/actions.js index be51aa4bff..171189bc7e 100644 --- a/src/sunstone/public/app/tabs/oneflow-templates-tab/actions.js +++ b/src/sunstone/public/app/tabs/oneflow-templates-tab/actions.js @@ -39,6 +39,7 @@ define(function(require) { "ServiceTemplate.chown": _commonActions.multipleAction('chown'), "ServiceTemplate.chgrp": _commonActions.multipleAction('chgrp'), "ServiceTemplate.chmod": _commonActions.singleAction('chmod'), + "ServiceTemplate.rename": _commonActions.singleAction('rename'), "ServiceTemplate.update" : _commonActions.update(), "ServiceTemplate.update_dialog" : _commonActions.checkAndShowUpdate(), "ServiceTemplate.show_to_update" : _commonActions.showUpdate(CREATE_DIALOG_ID), diff --git a/src/sunstone/public/app/tabs/oneflow-templates-tab/panels/info.js b/src/sunstone/public/app/tabs/oneflow-templates-tab/panels/info.js index b1f604e0d0..dde0641025 100644 --- a/src/sunstone/public/app/tabs/oneflow-templates-tab/panels/info.js +++ b/src/sunstone/public/app/tabs/oneflow-templates-tab/panels/info.js @@ -20,6 +20,7 @@ define(function(require) { */ var Locale = require('utils/locale'); + var RenameTr = require('utils/panel/rename-tr'); var PermissionsTable = require('utils/panel/permissions-table'); var TemplateUtils = require('utils/template-utils'); @@ -64,6 +65,7 @@ define(function(require) { function _html() { var that = this; + var renameTrHTML = RenameTr.html(TAB_ID, RESOURCE, this.element.NAME); var permissionsTableHTML = PermissionsTable.html(TAB_ID, RESOURCE, this.element); var customAttrs = []; @@ -102,12 +104,14 @@ define(function(require) { return TemplateHTML({ 'element': this.element, + 'renameTrHTML': renameTrHTML, 'permissionsTableHTML': permissionsTableHTML, 'customAttrs': customAttrs }); } function _setup(context) { + RenameTr.setup(TAB_ID, RESOURCE, this.element.ID, context); PermissionsTable.setup(TAB_ID, RESOURCE, this.element, context); } }); diff --git a/src/sunstone/public/app/tabs/oneflow-templates-tab/panels/info/html.hbs b/src/sunstone/public/app/tabs/oneflow-templates-tab/panels/info/html.hbs index 50030fd7c4..b663938b5e 100644 --- a/src/sunstone/public/app/tabs/oneflow-templates-tab/panels/info/html.hbs +++ b/src/sunstone/public/app/tabs/oneflow-templates-tab/panels/info/html.hbs @@ -27,10 +27,7 @@ {{tr "ID"}} {{element.ID}} - - {{tr "Name"}} - {{element.NAME}} - + {{{renameTrHTML}}} {{tr "Description"}} {{element.TEMPLATE.BODY.description}} diff --git a/src/sunstone/public/app/tabs/provision-tab.js b/src/sunstone/public/app/tabs/provision-tab.js index 770416427b..4848c46c73 100644 --- a/src/sunstone/public/app/tabs/provision-tab.js +++ b/src/sunstone/public/app/tabs/provision-tab.js @@ -35,6 +35,7 @@ define(function(require) { var DisksResize = require('utils/disks-resize'); var NicsSection = require('utils/nics-section'); var TemplateUtils = require('utils/template-utils'); + var LabelsUtils = require('utils/labels/utils'); var ProvisionQuotaWidget = require('./provision-tab/users/quota-widget'); @@ -56,6 +57,7 @@ define(function(require) { var TemplateGroupInfo = require('hbs!./provision-tab/group/info'); var TAB_ID = require('./provision-tab/tabId'); + var TEMPLATE_LABELS_COLUMN = 4; var povision_actions = { "Provision.User.create" : { @@ -1206,7 +1208,9 @@ define(function(require) { "aoColumns": [ { "mDataProp": "VMTEMPLATE.ID" }, { "mDataProp": "VMTEMPLATE.NAME" }, - { "mDataProp": "VMTEMPLATE.TEMPLATE.SAVED_TEMPLATE_ID", "sDefaultContent" : "-" } + { "mDataProp": "VMTEMPLATE.TEMPLATE.SAVED_TEMPLATE_ID", "sDefaultContent" : "-" }, + { "mDataProp": "VMTEMPLATE.PERMISSIONS.GROUP_U" }, + { "mDataProp": "VMTEMPLATE.TEMPLATE.LABELS", "sDefaultContent" : "-" } ], "fnPreDrawCallback": function (oSettings) { initializeTemplateCards(this, "provision_system_templates") @@ -1214,6 +1218,8 @@ define(function(require) { "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) { appendTemplateCard(aData, "provision_system_templates"); return nRow; + }, + "fnDrawCallback": function(oSettings) { } }); @@ -1229,7 +1235,8 @@ define(function(require) { { "mDataProp": "VMTEMPLATE.ID" }, { "mDataProp": "VMTEMPLATE.NAME" }, { "mDataProp": "VMTEMPLATE.TEMPLATE.SAVED_TEMPLATE_ID", "sDefaultContent" : "-" }, - { "mDataProp": "VMTEMPLATE.PERMISSIONS.GROUP_U" } + { "mDataProp": "VMTEMPLATE.PERMISSIONS.GROUP_U" }, + { "mDataProp": "VMTEMPLATE.TEMPLATE.LABELS", "sDefaultContent" : "-" } ], "fnPreDrawCallback": function (oSettings) { initializeTemplateCards(this, "provision_vdc_templates") @@ -1252,7 +1259,8 @@ define(function(require) { { "mDataProp": "VMTEMPLATE.ID" }, { "mDataProp": "VMTEMPLATE.NAME" }, { "mDataProp": "VMTEMPLATE.TEMPLATE.SAVED_TEMPLATE_ID", "sDefaultContent" : "-" }, - { "mDataProp": "VMTEMPLATE.PERMISSIONS.GROUP_U" } + { "mDataProp": "VMTEMPLATE.PERMISSIONS.GROUP_U" }, + { "mDataProp": "VMTEMPLATE.TEMPLATE.LABELS", "sDefaultContent" : "-" } ], "fnPreDrawCallback": function (oSettings) { initializeTemplateCards(this, "provision_saved_templates") @@ -1264,12 +1272,30 @@ define(function(require) { }); - $('#provision_create_template_search').on('input',function(){ + $('#provision_create_system_template_search').on('input',function(){ provision_system_templates_datatable.fnFilter( $(this).val() ); - provision_saved_templates_datatable.fnFilter( $(this).val() ); + }) + + $('#provision_create_vdc_template_search').on('input',function(){ provision_vdc_templates_datatable.fnFilter( $(this).val() ); }) + $('#provision_create_saved_template_search').on('input',function(){ + provision_saved_templates_datatable.fnFilter( $(this).val() ); + }) + + $('[href="#provision_system_templates_selector"]').on('click', function() { + ProvisionTemplatesList.updateDatatable(provision_system_templates_datatable); + }) + + $('[href="#provision_saved_templates_selector"]').on('click', function() { + ProvisionTemplatesList.updateDatatable(provision_saved_templates_datatable); + }) + + $('[href="#provision_vdc_templates_selector"]').on('click', function() { + ProvisionTemplatesList.updateDatatable(provision_vdc_templates_datatable); + }) + $("#provision_create_template_refresh_button").click(function(){ OpenNebula.Action.clear_cache("VMTEMPLATE"); ProvisionTemplatesList.updateDatatable(provision_system_templates_datatable); diff --git a/src/sunstone/public/app/tabs/provision-tab/templates/list.js b/src/sunstone/public/app/tabs/provision-tab/templates/list.js index 81b863c051..96d0ae80a2 100644 --- a/src/sunstone/public/app/tabs/provision-tab/templates/list.js +++ b/src/sunstone/public/app/tabs/provision-tab/templates/list.js @@ -22,10 +22,12 @@ define(function(require) { var Notifier = require('utils/notifier'); var Humanize = require('utils/humanize'); var ResourceSelect = require('utils/resource-select'); + var LabelsUtils = require('utils/labels/utils'); var TemplateTemplatesList = require('hbs!./list'); var _accordionId = 0; + var TEMPLATE_LABELS_COLUMN = 4; return { 'generate': generate_provision_templates_list, @@ -90,6 +92,9 @@ define(function(require) { ''); } else { datatable.fnAddData(item_list); + LabelsUtils.clearLabelsFilter(datatable, TEMPLATE_LABELS_COLUMN); + var context = $('.labels-dropdown', datatable.closest('.content')); + LabelsUtils.insertLabelsMenu(context, datatable, TEMPLATE_LABELS_COLUMN, "VMTEMPLATE.TEMPLATE.LABELS"); } }, error: Notifier.onError diff --git a/src/sunstone/public/app/tabs/provision-tab/vms/create.hbs b/src/sunstone/public/app/tabs/provision-tab/vms/create.hbs index 3676762a15..c12b0e8a82 100644 --- a/src/sunstone/public/app/tabs/provision-tab/vms/create.hbs +++ b/src/sunstone/public/app/tabs/provision-tab/vms/create.hbs @@ -13,7 +13,6 @@ {{! See the License for the specific language governing permissions and }} {{! limitations under the License. }} {{! -------------------------------------------------------------------------- }} -