diff --git a/SConstruct b/SConstruct index a575fa3036..cd90d7f44c 100644 --- a/SConstruct +++ b/SConstruct @@ -84,6 +84,8 @@ main_env.Append(LIBPATH=[ cwd+'/src/client', cwd+'/src/secgroup', cwd+'/src/vdc', + cwd+'/src/vrouter', + cwd+'/src/market' ]) # Compile flags @@ -244,6 +246,8 @@ build_scripts=[ 'src/zone/SConstruct', 'src/secgroup/SConstruct', 'src/vdc/SConstruct', + 'src/vrouter/SConstruct', + 'src/market/SConstruct', 'share/man/SConstruct', 'src/sunstone/public/locale/languages/SConstruct', 'src/sunstone/public/SConstruct', diff --git a/include/ActionSet.h b/include/ActionSet.h new file mode 100644 index 0000000000..585f455aee --- /dev/null +++ b/include/ActionSet.h @@ -0,0 +1,62 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 ACTION_SET_H +#define ACTION_SET_H + +/** + * This class defines actions sets (for example the set of actions supported + * by the driver). Just the basic methods to initialize the set and check if a + * an action is included is provided (similar to FD_SET(3) or SIGSETOPS(3)) + * + * Types should be enums with uint values. + */ +template +class ActionSet +{ +public: + ActionSet():action_set(0){}; + ActionSet(const T * actions, int actions_len):action_set(0) + { + for (int i=0; i(action); + }; + + /** + * Check if action is included in the set + * @param action + * @return true if included + */ + bool is_set(T action) const + { + return (action_set & (1 << static_cast(action))) != 0; + }; + +private: + long long action_set; +}; + +#endif /*ACTION_SET_H*/ diff --git a/include/AddressRange.h b/include/AddressRange.h index c26b629827..c6ed40c311 100644 --- a/include/AddressRange.h +++ b/include/AddressRange.h @@ -121,9 +121,11 @@ public: * A vector containing just -1 means all VMs. * @param vnet_ids list of VNET the user can access reservation info from. * A vector containing just -1 means all VNETs. + * @param vrs list of VRouter the user can access VNET usage info from. + * A vector containing just -1 means all VRouters. */ void to_xml(ostringstream &oss, const vector& vms, - const vector& vnets) const; + const vector& vnets, const vector& vrs) const; // ************************************************************************* // Address allocation functions @@ -344,7 +346,7 @@ public: */ friend int AddressRangePool::add_ar(AddressRange * ar); - static void set_restricted_attributes(vector& rattrs); + static void set_restricted_attributes(vector& rattrs); private: /* ---------------------------------------------------------------------- */ diff --git a/include/AddressRangePool.h b/include/AddressRangePool.h index 91d66f656a..a2b5d93773 100644 --- a/include/AddressRangePool.h +++ b/include/AddressRangePool.h @@ -82,7 +82,7 @@ public: * the reason. * @return 0 on success */ - int update_ar(vector ars, bool keep_restricted, string& error_msg); + int update_ar(vector ars, bool keep_restricted, string& error_msg); /** * Allocates a new *empty* address range. It is not added to the pool as it @@ -341,10 +341,12 @@ public: * A vector containing just -1 means all VMs. * @param vnet_ids list of VNET the user can access reservation info from. * A vector containing just -1 means all VNETs. + * @param vrs list of VRouter the user can access VNET usage info from. + * A vector containing just -1 means all VRouters. * @return the string with the XML */ string& to_xml(string& sstream, bool extended, const vector& vms, - const vector& vnets) const; + const vector& vnets, const vector& vrs) const; private: /** diff --git a/include/Attribute.h b/include/Attribute.h index c80245dd63..20fb9eb2c5 100644 --- a/include/Attribute.h +++ b/include/Attribute.h @@ -247,84 +247,81 @@ public: string vector_value(const char *name) const; /** - * Returns the string value - * @param name of the attribute - * @param value of the value + * Returns the value of the given element of the VectorAttribute * - * @return 0 if the attribute was found, -1 otherwise + * @param name of the attribute + * @param value, not set if the element is not found of has invalid type + * + * @return 0 on success, -1 otherwise */ + template + int vector_value(const char *name, T& value) const + { + map::const_iterator it; + + it = attribute_value.find(name); + + if ( it == attribute_value.end() ) + { + return -1; + } + + if ( it->second.empty() ) + { + return -1; + } + + istringstream iss(it->second); + iss >> value; + + if (iss.fail() || !iss.eof()) + { + return -1; + } + + return 0; + } + int vector_value(const char *name, string& value) const; - /** - * Returns the boolean value - * @param name of the attribute - * @param value Bool value ("YES" is true) - * - * @return 0 on success, -1 otherwise - */ int vector_value(const char *name, bool& value) const; - /** - * Returns the integer value - * - * @param name Name of the attribute - * @param value Integer value - * - * @return 0 on success, -1 otherwise - */ - int vector_value(const char *name, int& value) const; - - /** - * Returns the unsigned integer value - * - * @param name Name of the attribute - * @param value Integer value - * - * @return 0 on success, -1 otherwise - */ - int vector_value(const char *name, unsigned int& value) const; - - /** - * Returns the long long value - * - * @param name Name of the attribute - * @param value Long long value - * - * @return 0 on success, -1 otherwise - */ - int vector_value(const char *name, long long& value) const; - - /** - * Returns the float value - * - * @param name Name of the attribute - * @param value Float value - * - * @return 0 on success, -1 otherwise - */ - int vector_value(const char *name, float& value) const; - /** * Returns the integer value * * @param name Name of the attribute * @param value Integer value, if an error occurred the string returned is - * empty and value set to -1; + * empty and value is not set * * @return the value in string form on success, "" otherwise */ - string vector_value_str(const char *name, int& value) const; + template + string vector_value_str(const char *name, T& value) const + { + map::const_iterator it; - /** - * Returns the float value - * - * @param name Name of the attribute - * @param value Float value, if an error occurred the string returned is - * empty and value set to -1; - * - * @return the value in string form on success, "" otherwise - */ - string vector_value_str(const char *name, float& value) const; + it = attribute_value.find(name); + + if ( it == attribute_value.end() ) + { + return ""; + } + + if ( it->second.empty() ) + { + return ""; + } + + istringstream iss(it->second); + iss >> value; + + if (iss.fail() || !iss.eof()) + { + return ""; + } + + return it->second; + } /** * Marshall the attribute in a single string. The string MUST be freed @@ -375,12 +372,8 @@ public: /** * Replace the value of the given vector attribute */ - void replace(const string& name, const string& value); - - /** - * Replace the value of the given vector attribute - */ - void replace(const string& name, int value) + template + void replace(const string& name, T value) { ostringstream oss; @@ -389,59 +382,20 @@ public: replace(name, oss.str()); } - /** - * Replace the value of the given vector attribute - */ - void replace(const string& name, unsigned int value) - { - ostringstream oss; - - oss << value; - - replace(name, oss.str()); - } - - /** - * Replace the value of the given vector attribute - */ - void replace(const string& name, long long value) - { - ostringstream oss; - - oss << value; - - replace(name, oss.str()); - } - - /** - * Replace the value of the given vector attribute - */ - void replace(const string& name, const char* value) - { - string svalue(value); - - replace(name, svalue); - } - - /** - * Replace the value of the given vector attribute - */ void replace(const string& name, bool value) { - string b_value; - if (value == true) { - b_value = "YES"; + replace(name, "YES"); } else { - b_value = "NO"; + replace(name, "NO"); } - - replace(name, b_value); } + void replace(const string& name, const string& value); + /** * Removes given the vector attribute * @param name of the vector attribute diff --git a/include/AuthManager.h b/include/AuthManager.h index d3d717912c..e9a570849e 100644 --- a/include/AuthManager.h +++ b/include/AuthManager.h @@ -41,7 +41,7 @@ public: AuthManager( time_t timer, - vector& _mads): + vector& _mads): MadManager(_mads), timer_period(timer) { am.addListener(this); diff --git a/include/ClusterPool.h b/include/ClusterPool.h index 049942bffc..0c15913dda 100644 --- a/include/ClusterPool.h +++ b/include/ClusterPool.h @@ -100,15 +100,6 @@ public: return name; }; - /** Update a particular Cluster - * @param user pointer to Cluster - * @return 0 on success - */ - int update(Cluster * cluster) - { - return cluster->update(db); - }; - /** * Drops the Cluster from the data base. The object mutex SHOULD be * locked. diff --git a/include/DatastorePool.h b/include/DatastorePool.h index 711236c37b..cd917c4e5f 100644 --- a/include/DatastorePool.h +++ b/include/DatastorePool.h @@ -26,7 +26,7 @@ using namespace std; class DatastorePool : public PoolSQL { public: - DatastorePool(SqlDB * db, const vector& _inherit_attrs); + DatastorePool(SqlDB * db, const vector& _inherit_attrs); ~DatastorePool(){}; @@ -135,15 +135,6 @@ public: return name; }; - /** Update a particular Datastore - * @param user pointer to Datastore - * @return 0 on success - */ - int update(Datastore * datastore) - { - return datastore->update(db); - }; - /** * Drops the Datastore data in the data base. The object mutex SHOULD be * locked. diff --git a/include/DocumentPool.h b/include/DocumentPool.h index faeb61ae40..ee5a5c223a 100644 --- a/include/DocumentPool.h +++ b/include/DocumentPool.h @@ -76,18 +76,6 @@ public: return static_cast(PoolSQL::get(oid,lock)); }; - /** - * Updates the object's data in the data base. The object mutex SHOULD be - * locked. - * @param objsql a pointer to the object - * - * @return 0 on success. - */ - int update(Document * document) - { - return document->update(db); - }; - /** * Dumps the pool in XML format. A filter can be also added to the * query diff --git a/include/GroupPool.h b/include/GroupPool.h index f2436a0912..cf88a5c81f 100644 --- a/include/GroupPool.h +++ b/include/GroupPool.h @@ -26,10 +26,8 @@ using namespace std; class GroupPool : public PoolSQL { public: - GroupPool(SqlDB * db, - vector hook_mads, - const string& remotes_location, - bool is_federation_slave); + GroupPool(SqlDB * db, vector hook_mads, + const string& remotes_location, bool is_federation_slave); ~GroupPool(){}; @@ -118,7 +116,7 @@ public: * @param user pointer to Group * @return 0 on success */ - int update(Group * group); + int update(PoolObjectSQL * objsql); /** * Update a particular Group's Quotas diff --git a/include/HookManager.h b/include/HookManager.h index 677228ef31..1896e8f84a 100644 --- a/include/HookManager.h +++ b/include/HookManager.h @@ -30,7 +30,7 @@ class HookManager : public MadManager, public ActionListener { public: - HookManager(vector& _mads, VirtualMachinePool * _vmpool) + HookManager(vector& _mads, VirtualMachinePool * _vmpool) :MadManager(_mads),vmpool(_vmpool) { am.addListener(this); diff --git a/include/Host.h b/include/Host.h index 9c10af777c..da15c503e0 100644 --- a/include/Host.h +++ b/include/Host.h @@ -383,7 +383,7 @@ public: * @return 0 on success */ void add_capacity(int vm_id, long long cpu, long long mem, long long disk, - vector pci) + vector pci) { if ( vm_collection.add_collection_id(vm_id) == 0 ) { @@ -410,7 +410,7 @@ public: * @return 0 on success */ void del_capacity(int vm_id, long long cpu, long long mem, long long disk, - vector pci) + vector pci) { if ( vm_collection.del_collection_id(vm_id) == 0 ) { @@ -449,7 +449,7 @@ public: * @return true if the share can host the VM */ bool test_capacity(long long cpu, long long mem, long long disk, - vector &pci, string& error) const + vector &pci, string& error) const { return host_share.test(cpu, mem, disk, pci, error); } @@ -461,7 +461,7 @@ public: * @param error Returns the error reason, if any * @return true if the share can host the VM */ - bool test_capacity(vector &pci, string& error) const + bool test_capacity(vector &pci, string& error) const { return host_share.test(pci, error); } diff --git a/include/HostPool.h b/include/HostPool.h index db1bceef9a..973a8acbb6 100644 --- a/include/HostPool.h +++ b/include/HostPool.h @@ -35,11 +35,9 @@ using namespace std; class HostPool : public PoolSQL { public: - HostPool(SqlDB * db, - vector hook_mads, - const string& hook_location, - const string& remotes_location, - time_t expire_time); + HostPool(SqlDB * db, vector hook_mads, + const string& hook_location, const string& remotes_location, + time_t expire_time); ~HostPool(){}; @@ -128,7 +126,7 @@ public: * @return 0 on success -1 in case of failure */ int add_capacity(int oid, int vm_id, int cpu, int mem, int disk, - vector pci) + vector pci) { int rc = 0; Host * host = get(oid, true); @@ -159,7 +157,7 @@ public: * @param pci devices requested by the VM */ void del_capacity(int oid, int vm_id, int cpu, int mem, int disk, - vector pci) + vector pci) { Host * host = get(oid, true); diff --git a/include/HostShare.h b/include/HostShare.h index b95c5cb779..3f98129761 100644 --- a/include/HostShare.h +++ b/include/HostShare.h @@ -79,7 +79,7 @@ public: * @param devs list of requested devices by the VM. * @return true if all the devices are available. */ - bool test(const vector &devs) const; + bool test(const vector &devs) const; /** * Assign the requested devices to the given VM. The assigned devices will @@ -89,18 +89,18 @@ public: * assigned devices. * @param vmid of the VM */ - void add(vector &devs, int vmid); + void add(vector &devs, int vmid); /** * Remove the VM assignment from the PCI device list */ - void del(const vector &devs); + void del(const vector &devs); /** * Updates the PCI list with monitor data, it will create or * remove PCIDevices as needed. */ - void set_monitorization(vector &pci_att); + void set_monitorization(vector &pci_att); /** * Prints the PCI device list to an output stream. This function is used @@ -122,7 +122,7 @@ private: /** * Sets the internal class structures from the template */ - int init(); + void init(); /** * Internal structure to represent PCI devices for fast look up and @@ -171,7 +171,7 @@ public: * @param pci_devs requested by the VM */ void add(int vmid, long long cpu, long long mem, long long disk, - vector pci_devs) + vector pci_devs) { cpu_usage += cpu; mem_usage += mem; @@ -202,7 +202,8 @@ public: * @param disk requested by the VM * @param pci_devs requested by the VM */ - void del(long long cpu, long long mem, long long disk, vector pci_devs) + void del(long long cpu, long long mem, long long disk, + vector pci_devs) { cpu_usage -= cpu; mem_usage -= mem; @@ -225,7 +226,7 @@ public: * configured */ bool test(long long cpu, long long mem, long long disk, - vector& pci_devs, string& error) const + vector& pci_devs, string& error) const { bool pci_fits = pci.test(pci_devs); @@ -257,7 +258,7 @@ public: * @return true if the share can host the VM or it is the only one * configured */ - bool test(vector& pci_devs, string& error) const + bool test(vector& pci_devs, string& error) const { bool fits = pci.test(pci_devs); @@ -282,9 +283,9 @@ public: */ string& to_xml(string& xml) const; - void set_ds_monitorization(const vector &ds_att); + void set_ds_monitorization(const vector &ds_att); - void set_pci_monitorization(vector &pci_att) + void set_pci_monitorization(vector &pci_att) { pci.set_monitorization(pci_att); } diff --git a/include/ImageManager.h b/include/ImageManager.h index 4f2e5020a5..0ac1f9c746 100644 --- a/include/ImageManager.h +++ b/include/ImageManager.h @@ -37,7 +37,7 @@ public: time_t _monitor_period, ImagePool * _ipool, DatastorePool * _dspool, - vector& _mads): + vector& _mads): MadManager(_mads), timer_period(_timer_period), monitor_period(_monitor_period), @@ -115,8 +115,8 @@ public: /** * Closes any cloning operation on the image, updating the state if needed - * @param iid image id of the image to be released - * @param clone_img_id image id of the image that was being cloned + * @param iid image id of the image to that was being cloned + * @param clone_img_id the cloned image (id > 0) or market app (id =< 0) */ void release_cloning_image(int iid, int clone_img_id); @@ -133,11 +133,15 @@ public: * Adds a new image to the repository copying or creating it as needed * @param img pointer to the image * @param ds_data data of the associated datastore in XML format + * @param extra_data data to be sent to the driver * @param error Error reason * * @return 0 on success */ - int register_image(int iid, const string& ds_data, string& error); + int register_image(int iid, + const string& ds_data, + const string& extra_data, + string& error); /** * Checks if an image is ready to be cloned @@ -147,22 +151,31 @@ public: * * @return 0 if the image can be cloned, -1 otherwise */ - int can_clone_image(int cloning_id, - ostringstream& oss_error); + int can_clone_image(int cloning_id, ostringstream& oss_error); + + /** + * Sets the state to CLONE for the given image + * @param new_id for the target image (new_id>0) or market app (new_id =<0) + * @param clonning_id the ID of the image to be cloned + * @param error if any + * @return 0 if siccess + */ + int set_clone_state(int new_id, int cloning_id, std::string& error); /** * Clone an existing image to the repository * @param new_id of the new image * @param cloning_id of the image to be cloned * @param ds_data data of the associated datastore in XML format + * @param extra_data data to be sent to the driver * @param error describing the error * @return 0 on success */ int clone_image(int new_id, int cloning_id, const string& ds_data, + const string& extra_data, string& error); - /** * Deletes an image from the repository and the DB. The Datastore image list * is also updated diff --git a/include/ImagePool.h b/include/ImagePool.h index 7e5b676342..4c7643bc11 100644 --- a/include/ImagePool.h +++ b/include/ImagePool.h @@ -41,14 +41,14 @@ class ImagePool : public PoolSQL public: ImagePool( - SqlDB * db, - const string& __default_type, - const string& __default_dev_prefix, - const string& __default_cdrom_dev_prefix, - vector& restricted_attrs, - vector hook_mads, - const string& remotes_location, - const vector& _inherit_image_attrs); + SqlDB * db, + const string& __default_type, + const string& __default_dev_prefix, + const string& __default_cdrom_dev_prefix, + vector& restricted_attrs, + vector& hook_mads, + const string& remotes_location, + const vector& _inherit_image_attrs); ~ImagePool(){}; @@ -65,6 +65,7 @@ public: * @param ds_type disk type for the image * @param ds_data the datastore data * @param ds_type the datastore type + * @param extra_data extra data that will be sent to the driver * @param source_img_id If the new Image is a clone, this must be the * source Image ID. Otherwise, it must be set to -1 * @param oid the id assigned to the Image @@ -85,6 +86,7 @@ public: Image::DiskType disk_type, const string& ds_data, Datastore::DatastoreType ds_type, + const string& extra_data, int source_img_id, int * oid, string& error_str); @@ -115,16 +117,6 @@ public: return static_cast(PoolSQL::get(name,uid,lock)); }; - /** - * Update a particular Image - * @param image pointer to Image - * @return 0 on success - */ - int update(Image * image) - { - return image->update(db); - }; - /** * Bootstraps the database table(s) associated to the Image pool * @return 0 on success diff --git a/include/ImageTemplate.h b/include/ImageTemplate.h index 8cda4f3b3f..f3685b52d7 100644 --- a/include/ImageTemplate.h +++ b/include/ImageTemplate.h @@ -88,7 +88,7 @@ private: * ImageTemplate::check * @param rattrs Attributes to restrict */ - static void set_restricted_attributes(vector& rattrs) + static void set_restricted_attributes(vector& rattrs) { Template::set_restricted_attributes(rattrs, restricted_attributes); }; diff --git a/include/InformationManager.h b/include/InformationManager.h index 67408e0508..bc30bccacb 100644 --- a/include/InformationManager.h +++ b/include/InformationManager.h @@ -41,7 +41,7 @@ public: int _host_limit, int _monitor_threads, const string& _remotes_location, - vector& _mads) + vector& _mads) :MadManager(_mads), hpool(_hpool), clpool(_clpool), diff --git a/include/MadManager.h b/include/MadManager.h index 0425c50a94..ba37ba837a 100644 --- a/include/MadManager.h +++ b/include/MadManager.h @@ -64,7 +64,7 @@ public: protected: - MadManager(vector& _mads); + MadManager(vector& _mads); virtual ~MadManager(); @@ -72,7 +72,7 @@ protected: * Vector containing Mad configuration for this Manager, as described in * the nebula location */ - vector mad_conf; + vector mad_conf; /** * This function initialize the communication pipes to register new MADs diff --git a/include/MarketPlace.h b/include/MarketPlace.h new file mode 100644 index 0000000000..fff1132f9f --- /dev/null +++ b/include/MarketPlace.h @@ -0,0 +1,218 @@ +/* ------------------------------------------------------------------------ */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 MARKETPLACE_H_ +#define MARKETPLACE_H_ + +#include "PoolSQL.h" +#include "ObjectCollection.h" +#include "MarketPlaceTemplate.h" +#include "MarketPlaceApp.h" +#include "ActionSet.h" + +/** + * The MarketPlace class. It represents an abstract container for OpenNebula + * objects (Image, VM Templates or Flows) + */ +class MarketPlace : public PoolObjectSQL, ObjectCollection +{ +public: + /** + * Function to print the MarketPlace object into a string in XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(string& xml) const; + + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + int from_xml(const string &xml_str); + + /** + * Adds this marketplace app's ID to the set. + * @param id of the app to be added to the MarketPlace + * @return 0 on success + */ + int add_marketapp(int id) + { + return add_collection_id(id); + }; + + /** + * Deletes this image's ID from the set. + * @param id of the image to be deleted from the MarketPlace + * @return 0 on success + */ + int del_marketapp(int id) + { + return del_collection_id(id); + }; + + /** + * Returns a copy of the Image IDs set + */ + set get_marketapp_ids() + { + return get_collection_copy(); + } + + /** + * Retrieves marketplace mad name + * @return string mp mad name + */ + const string& get_market_mad() const + { + return market_mad; + }; + + /** + * Set monitor information for the MarketPlace + * @param data template with monitor information + */ + void update_monitor(const Template& data); + + /** + * Check if action is supported for the apps + * @param action + * @return true if it is supported + */ + bool is_action_supported(MarketPlaceApp::Action action) const + { + return supported_actions.is_set(action); + } + +private: + + friend class MarketPlacePool; + + // ************************************************************************* + // MarketPlace Attributes + // ************************************************************************* + /** + * Name of the marketplace driver used to import apps + */ + string market_mad; + + /** + * Total capacity in MB + */ + long long total_mb; + + /** + * Available capacity in MB + */ + long long free_mb; + + /** + * Used capacity in MB + */ + long long used_mb; + + /** + * Supported actions on MarketPlaceApps + */ + ActionSet supported_actions; + + // ************************************************************************* + // Constructor + // ************************************************************************* + MarketPlace( + int uid, + int gid, + const string& uname, + const string& gname, + int umask, + MarketPlaceTemplate* mp_template); + + virtual ~MarketPlace(); + + // ************************************************************************* + // DataBase implementation (Private) + // ************************************************************************* + + static const char * db_names; + + static const char * db_bootstrap; + + static const char * table; + + /** + * Execute an INSERT or REPLACE Sql query. + * @param db The SQL DB + * @param replace Execute an INSERT or a REPLACE + * @param error_str Returns the error reason, if any + * @return 0 one success + */ + int insert_replace(SqlDB *db, bool replace, string& error_str); + + /** + * Bootstraps the database table(s) associated to the MarketPlace + * @return 0 on success + */ + static int bootstrap(SqlDB * db) + { + ostringstream oss(db_bootstrap); + + return db->exec(oss); + }; + + /** + * Writes the MarketPlace in the database. + * @param db pointer to the db + * @return 0 on success + */ + int insert(SqlDB *db, string& error_str); + + /** + * Writes/updates the MarketPlace's data fields in the database. + * @param db pointer to the db + * @return 0 on success + */ + int update(SqlDB *db) + { + string error_str; + return insert_replace(db, true, error_str); + } + + /** + * Factory method for marketplace templates + */ + Template * get_new_template() const + { + return new MarketPlaceTemplate; + } + + /** + * Verify the proper definition of the Market by checking the + * attributes of the MARKET_MAD_CONF parameter + */ + int set_market_mad(string &tm_mad, string &error_str); + + /** + * Child classes can process the new template set with replace_template or + * append_template with this method + * @param error string describing the error if any + * @return 0 on success + */ + int post_update_template(string& error); +}; + +#endif /*MARKETPLACE_H*/ + diff --git a/include/MarketPlaceApp.h b/include/MarketPlaceApp.h new file mode 100644 index 0000000000..a22721e8d5 --- /dev/null +++ b/include/MarketPlaceApp.h @@ -0,0 +1,417 @@ +/* ------------------------------------------------------------------------ */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 MARKETPLACEAPP_H_ +#define MARKETPLACEAPP_H_ + +#include "PoolSQL.h" +#include "ObjectCollection.h" +#include "MarketPlaceAppTemplate.h" + +/** + * The MarketPlaceApp class. It represents an abstract application for + * OpenNebula objects (Image, VM Templates or Flows) + */ +class MarketPlaceApp : public PoolObjectSQL +{ +public: + /** + * MarketPlaceApp actions + */ + enum Action + { + NONE = 0, + CREATE = 1, + DELETE = 2, + MONITOR = 3 + }; + + static int action_from_str(string& st, Action& action) + { + if (st == "create") + { + action = CREATE; + } + else if (st == "delete") + { + action = DELETE; + } + else if (st == "monitor") + { + action = MONITOR; + } + else + { + action = NONE; + return -1; + } + + return 0; + }; + + /** + * MarketPlaceApp states + */ + enum State + { + INIT = 0, /** < Initialization state */ + READY = 1, /** < Ready to use */ + LOCKED = 2, /** < Operation in process */ + ERROR = 3, /** < Error state the operation failed*/ + DISABLED = 4 + }; + + /** + * Returns the string representation of an MarketplaceApp State + * @param state The state + * @return the string representation + */ + static string state_to_str(State state) + { + switch(state) + { + case INIT: return "INIT"; break; + case READY: return "READY"; break; + case LOCKED: return "LOCKED"; break; + case ERROR: return "ERROR"; break; + case DISABLED: return "DISABLED"; break; + default: return ""; + } + }; + + /** + * MarketPlaceApp container types + */ + enum Type + { + UNKNOWN = 0, /** < Unknown types */ + IMAGE = 1, /** < Image MarketPlace App*/ + VMTEMPLATE = 2, /** < VM Template MarketPlace App*/ + SERVICE_TEMPLATE = 3 /** < Service Template MarketPlace App*/ + }; + + /** + * Return the string representation of a MarketPlaceType + * @param ob the type + * @return the string + */ + static string type_to_str(Type ob) + { + switch (ob) + { + case IMAGE: return "IMAGE"; break; + case VMTEMPLATE: return "VMTEMPLATE"; break; + case SERVICE_TEMPLATE: return "SERVICE_TEMPLATE"; break; + default: return ""; + } + }; + + /** + * Return the string representation of a MarketPlaceType, By default it will + * return IMAGE_MP. + * @param str_type string representing the type + * @return the MarketPlaceType + */ + static Type str_to_type(string& str_type); + + /** + * Function to print the MarketPlaceApp object into a string in XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(std::string& xml) const; + + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + int from_xml(const std::string &xml_str); + + /** + * Rebuilds the object from base64 encoded template representation + * @param str The template string, base64 encoded + * @param error_str Returns the error reason, if any + * + * @return 0 on success, -1 otherwise + */ + int from_template64(const std::string &xml_str, std::string& error_str); + + /** + * Copies the special attributes of the App to the template + * @param tmp The template object + * @param error_str Returns the error reason, if any + */ + void to_template(Template * tmpl) const; + + /** + * Enable or disable the app. A disabled app cannot be exported + * @param enable true to enable + * @param error_str Returns the error reason, if any + * + * @return 0 on success + */ + int enable(bool enable, std::string& error_str); + + /** + * Returns the marketplace ID + */ + int get_market_id() const + { + return market_id; + }; + + /** + * Returns the marketplace name + */ + const std::string& get_market_name() const + { + return market_name; + }; + + /** + * Updates the marketplace name + */ + void set_market_name(const std::string& name) + { + market_name = name; + }; + + /** + * Returns the marketplace app type + * @return marketplace app type + */ + Type get_type() const + { + return type; + }; + + /** + * Returns the ID of the object originating this app + * @return the image, vmtemplate or flow id + */ + int get_origin_id() const + { + return origin_id; + }; + + const string& get_source() const + { + return source; + } + + const string& get_md5() const + { + return md5; + } + + long long get_size() const + { + return size_mb; + } + + const string& get_format() const + { + return format; + } + + + State get_state() const + { + return state; + } + + //-------------------------------------------------------------------------- + // Set Marketplace app attributes + //-------------------------------------------------------------------------- + void set_state(State _state) + { + state = _state; + }; + + void set_source(const std::string& _source) + { + source = _source; + }; + + void set_md5(const std::string& _md5) + { + md5 = _md5; + }; + + void set_size(long long _size_mb) + { + size_mb = _size_mb; + }; + + void set_format(const std::string& _format) + { + format = _format; + }; + +private: + + friend class MarketPlaceAppPool; + + // ************************************************************************* + // MarketPlaceApp Attributes + // ************************************************************************* + /** + * Publishing date + */ + time_t regtime; + + /** + * Source URL for the marketplace app + */ + std::string source; + + /** + * Source URL for the marketplace app + */ + std::string md5; + + /** + * Size of this app + */ + long long size_mb; + + /** + * Description of the App + */ + std::string description; + + /** + * Version of the app + */ + std::string version; + + /** + * format of the disk images + */ + std::string format; + + /** + * App template to import it + */ + std::string apptemplate64; + + /** + * Marketplace ID that holds this app + */ + int market_id; + + /** + * Marketplace name + */ + std::string market_name; + + /** + * Marketplace App state + */ + State state; + + /** + * The marketplace type + */ + Type type; + + /** + * Origin of this App + */ + int origin_id; + + // ************************************************************************* + // Constructor + // ************************************************************************* + MarketPlaceApp( + int uid, + int gid, + const std::string& uname, + const std::string& gname, + int umask, + MarketPlaceAppTemplate* app_template); + + virtual ~MarketPlaceApp(); + + // ************************************************************************* + // DataBase implementation (Private) + // ************************************************************************* + + static const char * db_names; + + static const char * db_bootstrap; + + static const char * table; + + /** + * Execute an INSERT or REPLACE Sql query. + * @param db The SQL DB + * @param replace Execute an INSERT or a REPLACE + * @param error_str Returns the error reason, if any + * @return 0 one success + */ + int insert_replace(SqlDB *db, bool replace, std::string& error_str); + + /** + * Bootstraps the database table(s) associated to the MarketPlace + * @return 0 on success + */ + static int bootstrap(SqlDB * db) + { + ostringstream oss(db_bootstrap); + + return db->exec(oss); + }; + + /** + * Writes the MarketPlace in the database. + * @param db pointer to the db + * @return 0 on success + */ + int insert(SqlDB *db, std::string& error_str); + + /** + * Writes/updates the MarketPlace's data fields in the database. + * @param db pointer to the db + * @return 0 on success + */ + int update(SqlDB *db) + { + std::string error_str; + return insert_replace(db, true, error_str); + } + + /** + * Child classes can process the new template set with replace_template or + * append_template with this method + * @param error string describing the error if any + * @return 0 on success + */ + int post_update_template(std::string& error); + + /** + * Factory method for marketplace app templates + */ + Template * get_new_template() const + { + return new MarketPlaceAppTemplate; + } +}; + +#endif /*MARKETPLACEAPP_H*/ + diff --git a/include/MarketPlaceAppPool.h b/include/MarketPlaceAppPool.h new file mode 100644 index 0000000000..25ea7f36d5 --- /dev/null +++ b/include/MarketPlaceAppPool.h @@ -0,0 +1,144 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 MARKETPLACEAPP_POOL_H_ +#define MARKETPLACEAPP_POOL_H_ + +#include "MarketPlaceApp.h" + +class SqlDB; + +class MarketPlaceAppPool : public PoolSQL +{ +public: + MarketPlaceAppPool(SqlDB * db):PoolSQL(db,MarketPlaceApp::table,true,true){}; + + ~MarketPlaceAppPool(){}; + + /* ---------------------------------------------------------------------- */ + /* Methods for DB management */ + /* ---------------------------------------------------------------------- */ + + /** + * Allocates a new MarketPlaceApp, writing it in the pool database. + * @param uid the user id of the MarketPlace owner + * @param gid the id of the group this object is assigned to + * @param uname name of the user + * @param gname name of the group + * @param umask permissions umask + * @param apptemplate MarketPlaceApp definition template + * @param mp_id of the MarketPlace to store de App + * @param mp_name of the MarketPlace + * @param mp_data XML representation of the target MarketPlace + * @param oid the id assigned to the MarketPlace + * @param error_str Returns the error reason, if any + * + * @return the oid assigned to the object, -1 in case of failure + */ + int allocate( + int uid, + int gid, + const std::string& uname, + const std::string& gname, + int umask, + MarketPlaceAppTemplate * apptemplate, + int mp_id, + const std::string& mp_name, + const std::string& mp_data, + int * oid, + std::string& error_str); + /** + * Imports an app into the marketplace, as reported by the monitor driver + * @param template to generate app with the from_template64 function + * @param mp_id of the MarketPlace to store de App + * @param mp_name of the MarketPlace + * @param error_str Returns the error reason, if any + * + * @return the oid assigned to the object, -1 in case of failure, -2 + * already imported + */ + int import(const std::string& t64, int mp_id, const std::string& mp_name, + std::string& error_str); + + /** + * Function to get a MarketPlaceApp from the pool + * @param oid MarketPlaceApp unique id + * @param lock locks the MarketPlaceApp mutex + * @return a pointer to the MarketPlaceApp, 0 if not loaded + */ + MarketPlaceApp * get(int oid, bool lock) + { + return static_cast(PoolSQL::get(oid,lock)); + }; + + /** + * Gets an object from the pool (if needed the object is loaded from the + * database). + * @param name of the object + * @param uid id of owner + * @param lock locks the object if true + * + * @return a pointer to the object, 0 in case of failure + */ + MarketPlaceApp * get(const std::string& name, int uid, bool lock) + { + return static_cast(PoolSQL::get(name, uid, lock)); + }; + + /** + * Bootstraps the database table(s) associated to the MarketPlace pool + * @return 0 on success + */ + static int bootstrap(SqlDB * _db) + { + return MarketPlaceApp::bootstrap(_db); + }; + + /** + * Dumps the MarketPlace pool in XML format. A filter can be also added to + * the query + * @param oss the output stream to dump the pool contents + * @param where filter for the objects, defaults to all + * @param limit parameters used for pagination + * + * @return 0 on success + */ + int dump(std::ostringstream& oss, const std::string& where, + const std::string& limit) + { + return PoolSQL::dump(oss, "MARKETPLACEAPP_POOL", MarketPlaceApp::table, + where, limit); + }; + + /** Update a particular MarketPlaceApp + * @param zone pointer to Zone + * @return 0 on success + */ + int update(PoolObjectSQL * objsql); + +private: + + /** + * Factory method to produce objects + * @return a pointer to the new object + */ + PoolObjectSQL * create() + { + return new MarketPlaceApp(-1,-1,"","", 0, 0); + }; +}; + +#endif /*MARKETPLACE_POOL_H_*/ diff --git a/include/MarketPlaceAppTemplate.h b/include/MarketPlaceAppTemplate.h new file mode 100644 index 0000000000..a91d961785 --- /dev/null +++ b/include/MarketPlaceAppTemplate.h @@ -0,0 +1,37 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 MARKETPLACEAPP_TEMPLATE_H_ +#define MARKETPLACEAPP_TEMPLATE_H_ + +#include "Template.h" + +/** + * Datastore Template class + */ +class MarketPlaceAppTemplate : public Template +{ +public: + MarketPlaceAppTemplate(): + Template(false,'=',"TEMPLATE"){}; + + ~MarketPlaceAppTemplate(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +#endif /*MARKETPLACEAPP_TEMPLATE_H_*/ diff --git a/include/MarketPlaceManager.h b/include/MarketPlaceManager.h new file mode 100644 index 0000000000..42deafe9c9 --- /dev/null +++ b/include/MarketPlaceManager.h @@ -0,0 +1,227 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 MARKETPLACE_MANAGER_H_ +#define MARKETPLACE_MANAGER_H_ + +#include "MadManager.h" +#include "ActionManager.h" +#include "MarketPlaceManagerDriver.h" + +extern "C" void * marketplace_action_loop(void *arg); + +class MarketPlacePool; +class MarketPlaceAppPool; +class ImagePool; +class DatastorePool; + +class ImageManager; + +class MarketPlaceManager : public MadManager, public ActionListener +{ +public: + + /** + * Inititalizes the Marketplace manager: + * @param t, timer_period to wake up the manger to perform actions + * @param m, monitor_period to monitor marketplaces + * @param mad, list of drivers for the manager + */ + MarketPlaceManager(time_t t, time_t m, std::vector& mad); + + ~MarketPlaceManager(){}; + + /** + * Initializes internal pointers to other managers. Must be called when + * all the other managers exist in Nebula::instance + */ + void init_managers(); + + /** + * This functions starts the associated listener thread, and creates a + * new thread for the MarketPlace Manager. This thread will wait in + * an action loop till it receives ACTION_FINALIZE. + * @return 0 on success. + */ + int start(); + + /** + * Loads the MarketPlace Driver defined in configuration file + * @param uid of the user executing the driver. When uid is 0 the nebula + * identity will be used. Otherwise the Mad will be loaded through the + * sudo application. + */ + int load_mads(int uid=0); + + /** + * Gets the thread identification. + * @return pthread_t for the manager thread (that in the action loop). + */ + pthread_t get_thread_id() const + { + return marketm_thread; + }; + + /** + * Finalizes the Image Manager + */ + void finalize() + { + am.trigger(ACTION_FINALIZE,0); + }; + + /** + * Imports a new app into the marketplace. The marketplace app needs to + * include the ORIGIN_ID attribute so the driver can locate the app. An + * optional template maybe provided to export the app to a cloud. + * @param appid of the app + * @param market_data of the associated marketplace in XML format + * @param error descrition + * + * @return 0 on success + */ + int import_app(int appid, const std::string& market_data, std::string& err); + + /** + * Exports the app to this cloud. If an APPTEMPLATE64 is provided associated + * objects can also be created. + * @param appid of the app + * @param market_data of the associated marketplace in XML format + * @param error descrition + * + * @return 0 on success + */ + int export_app(int appid, const std::string& market_data, std::string& err); + + /** + * Deletes an app from the marketplace. + * @param appid of the app + * @param market_data of the associated marketplace in XML format + * @param error descrition + * + * @return 0 on success + */ + int delete_app(int appid, const std::string& market_data, std::string& err); + + /** + * Trigger a monitor action for the marketplace . + * @param ds_id id of the datastore to monitor + */ + void monitor_market(int ds_id); + + /** + * Relsease resources locked by this app during the import phase + * @param appid of the app + */ + void release_app_resources(int appid); + +private: + /** + * Generic name for the marketplace driver + */ + static const char * market_driver_name; + + /** + * Thread id for the MarketPlace Manager + */ + pthread_t marketm_thread; + + /** + * Timer period for the Image Manager. + */ + time_t timer_period; + + /** + * Marketplace monitor interval + */ + time_t monitor_period; + + /** + * Pointer to the marketplace pool + */ + MarketPlacePool * mppool; + + /** + * Pointer to the app pool + */ + MarketPlaceAppPool * apppool; + + /** + * Pointer to the image pool + */ + ImagePool * ipool; + + /** + * Pointer to the image pool + */ + DatastorePool * dspool; + + /** + * Pointer to the Image Manger + */ + ImageManager * imagem; + + /** + * Action engine for the Manager + */ + ActionManager am; + + /** + * Returns a pointer to the marketplace driver. + * @return the marketplace manager driver or 0 in not found + */ + const MarketPlaceManagerDriver * get() + { + std::string name("NAME"); + + return static_cast + (MadManager::get(0, name, market_driver_name)); + }; + + /** + * Function to execute the Manager action loop method within a new pthread + * (requires C linkage) + */ + friend void * marketplace_action_loop(void *arg); + + /** + * The action function executed when an action is triggered. + * @param action the name of the action + * @param arg arguments for the action function + */ + void do_action(const std::string& action, void * arg); + + /** + * Formats an XML message for the MAD + * + * @param app_data marketplace app XML representation + * @param market_data marketplace XML representation + * @param extra_data additional XML formatted data for the driver + * + * @return the XML message + */ + static std::string * format_message( + const std::string& app_data, + const std::string& market_data, + const std::string& extra_data); + /** + * This function is executed periodically to monitor marketplaces.. + */ + void timer_action(); +}; + +#endif /*MARKETPLACE_MANAGER_H*/ + diff --git a/include/MarketPlaceManagerDriver.h b/include/MarketPlaceManagerDriver.h new file mode 100644 index 0000000000..6c1108da16 --- /dev/null +++ b/include/MarketPlaceManagerDriver.h @@ -0,0 +1,98 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 MARKETPLACE_MANAGER_DRIVER_H_ +#define MARKETPLACE_MANAGER_DRIVER_H_ + +#include +#include +#include + +#include "Mad.h" + +class MarketPlacePool; +class MarketPlaceAppPool; +class MarketPlaceManager; + +/** + * ImageManagerDriver represents the basic abstraction for Image Repository + * drivers. It implements the protocol and recover functions from the Mad + * interface. + */ +class MarketPlaceManagerDriver : public Mad +{ +public: + MarketPlaceManagerDriver(int userid, + const std::map& attrs, + bool sudo, + MarketPlacePool * _marketpool, + MarketPlaceAppPool * _apppool, + MarketPlaceManager * _marketm + ):Mad(userid,attrs,sudo), marketpool(_marketpool), apppool(_apppool), + marketm(_marketm){}; + + virtual ~MarketPlaceManagerDriver(){}; + + /** + * Implements the Image Manager driver protocol. + * @param message the string read from the driver + */ + void protocol(const std::string& message) const; + + /** + * TODO: What do we need here? Check on-going xfr? + */ + void recover(); + +private: + friend class MarketPlaceManager; + + /** + * Reference to Marketplace related pools + */ + MarketPlacePool * marketpool; + + MarketPlaceAppPool * apppool; + + MarketPlaceManager * marketm; + + /** + * Imports a new object into the marketplace + * @param oid of the app + * @param drv_msg xml data for the mad operation. + */ + void importapp(int oid, const std::string& drv_msg) const; + + /** + * Deletes an app from the marketplace + * @param oid of the app + * @param drv_msg xml data for the mad operation. + */ + void deleteapp(int oid, const std::string& drv_msg) const; + + /** + * Monitors the marketplace + * @param oid of the operation + * @param drv_msg xml data for the mad operation. + */ + void monitor(int oid, const std::string& drv_msg) const; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +#endif /*MARKETPLACE_MANAGER_DRIVER_H_*/ + diff --git a/include/MarketPlacePool.h b/include/MarketPlacePool.h new file mode 100644 index 0000000000..bfe7c59a91 --- /dev/null +++ b/include/MarketPlacePool.h @@ -0,0 +1,162 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 MARKETPLACE_POOL_H_ +#define MARKETPLACE_POOL_H_ + +#include "MarketPlace.h" +#include "NebulaLog.h" +#include "SqlDB.h" + +class SqlDB; +class MarketPlaceApp; + +class MarketPlacePool : public PoolSQL +{ +public: + MarketPlacePool(SqlDB * db); + + ~MarketPlacePool(){}; + + /* ---------------------------------------------------------------------- */ + /* Methods for DB management */ + /* ---------------------------------------------------------------------- */ + + /** + * Allocates a new MarketPlace, writing it in the pool database. No memory is + * allocated for the object. + * @param uid the user id of the MarketPlace owner + * @param gid the id of the group this object is assigned to + * @param uname name of the user + * @param gname name of the group + * @param umask permissions umask + * @param mp_template MarketPlace definition template + * @param oid the id assigned to the MarketPlace + * @param error_str Returns the error reason, if any + * + * @return the oid assigned to the object, -1 in case of failure + */ + int allocate( + int uid, + int gid, + const std::string& uname, + const std::string& gname, + int umask, + MarketPlaceTemplate * mp_template, + int * oid, + std::string& error_str); + + /** + * Function to get a MarketPlace from the pool, the object is loaded if not + * in memory + * @param oid MarketPlace unique id + * @param lock locks the MarketPlace mutex + * @return a pointer to the MarketPlace, 0 if not loaded + */ + MarketPlace * get(int oid, bool lock) + { + return static_cast(PoolSQL::get(oid,lock)); + }; + + /** + * Gets an object from the pool (if needed the object is loaded from the + * database). + * @param name of the object + * @param lock locks the object if true + * + * @return a pointer to the object, 0 in case of failure + */ + MarketPlace * get(const std::string& name, bool lock) + { + return static_cast(PoolSQL::get(name,-1,lock)); + }; + + /** + * Generate an index key for the object + * @param name of the object + * @param uid owner of the object, only used if needed + * + * @return the key, a string + */ + string key(const std::string& name, int uid) + { + return name; + }; + + /** Update a particular MarketPlace + * @param objsql points to the market + * @return 0 on success + */ + int update(PoolObjectSQL * objsql); + + /** + * Drops the MarketPlace data in the data base. The object mutex SHOULD be + * locked. + * @param objsql a pointer to the MarketPlace object + * @param error_msg Error reason, if any + * @return 0 on success, -1 DB error -3 MarketPlace's App ID set not empty + */ + int drop(PoolObjectSQL * objsql, std::string& error_msg); + + /** + * Bootstraps the database table(s) associated to the MarketPlace pool + * @return 0 on success + */ + static int bootstrap(SqlDB * _db) + { + return MarketPlace::bootstrap(_db); + }; + + /** + * Dumps the MarketPlace pool in XML format. A filter can be also added to + * the query + * @param oss the output stream to dump the pool contents + * @param where filter for the objects, defaults to all + * @param limit parameters used for pagination + * + * @return 0 on success + */ + int dump(std::ostringstream& oss, const std::string& where, + const std::string& limit) + { + return PoolSQL::dump(oss, "MARKETPLACE_POOL", MarketPlace::table, where, + limit); + }; + + /** + * Lists the Datastore ids + * @param oids a vector with the oids of the objects. + * + * @return 0 on success + */ + int list(std::vector& oids) + { + return PoolSQL::list(oids, MarketPlace::table); + } + +private: + + /** + * Factory method to produce objects + * @return a pointer to the new object + */ + PoolObjectSQL * create() + { + return new MarketPlace(-1,-1,"","", 0, 0); + }; +}; + +#endif /*MARKETPLACE_POOL_H_*/ diff --git a/include/MarketPlaceTemplate.h b/include/MarketPlaceTemplate.h new file mode 100644 index 0000000000..9aef6cc91b --- /dev/null +++ b/include/MarketPlaceTemplate.h @@ -0,0 +1,37 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 MARKETPLACE_TEMPLATE_H_ +#define MARKETPLACE_TEMPLATE_H_ + +#include "Template.h" + +/** + * Datastore Template class + */ +class MarketPlaceTemplate : public Template +{ +public: + MarketPlaceTemplate(): + Template(false,'=',"TEMPLATE"){}; + + ~MarketPlaceTemplate(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +#endif /*MARKETPLACE_TEMPLATE_H_*/ diff --git a/include/Nebula.h b/include/Nebula.h index ec13bb4aa5..4790abb08c 100644 --- a/include/Nebula.h +++ b/include/Nebula.h @@ -34,6 +34,9 @@ #include "ZonePool.h" #include "SecurityGroupPool.h" #include "VdcPool.h" +#include "VirtualRouterPool.h" +#include "MarketPlacePool.h" +#include "MarketPlaceAppPool.h" #include "VirtualMachineManager.h" #include "LifeCycleManager.h" @@ -45,6 +48,7 @@ #include "AuthManager.h" #include "AclManager.h" #include "ImageManager.h" +#include "MarketPlaceManager.h" #include "DefaultQuotas.h" @@ -136,6 +140,21 @@ public: return vdcpool; }; + VirtualRouterPool * get_vrouterpool() + { + return vrouterpool; + }; + + MarketPlacePool * get_marketpool() + { + return marketpool; + }; + + MarketPlaceAppPool * get_apppool() + { + return apppool; + }; + // -------------------------------------------------------------- // Manager Accessors // -------------------------------------------------------------- @@ -185,6 +204,11 @@ public: return aclm; }; + MarketPlaceManager * get_marketm() + { + return marketm; + }; + // -------------------------------------------------------------- // Environment & Configuration // -------------------------------------------------------------- @@ -378,62 +402,41 @@ public: * @param name of the attribute * @param value of the attribute */ - void get_configuration_attribute( - const char * name, - string& value) const - { - string _name(name); - - nebula_configuration->Template::get(_name, value); - }; - - /** - * Gets a configuration attribute for oned (long long version) - */ - void get_configuration_attribute( - const char * name, - long long& value) const - { - string _name(name); - - nebula_configuration->Template::get(_name, value); - }; - - /** - * Gets a configuration attribute for oned (time_t version) - */ - void get_configuration_attribute( - const char * name, - time_t& value) const + template + void get_configuration_attribute(const string& name, T& value) const { nebula_configuration->get(name, value); }; - /** - * Gets a configuration attribute for oned, bool version - */ - void get_configuration_attribute( - const char * name, - bool& value) const - { - string _name(name); - - 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; + const VectorAttribute* &value) const + { + return get_conf_attribute("DS_MAD_CONF", ds_name, value); + }; /** * Gets a TM configuration attribute */ int get_tm_conf_attribute( const string& tm_name, - const VectorAttribute* &value) const; + const VectorAttribute* &value) const + { + return get_conf_attribute("TM_MAD_CONF", tm_name, value); + }; + + /** + * Gets a Market configuration attribute + */ + int get_market_conf_attribute( + const string& mk_name, + const VectorAttribute* &value) const + { + return get_conf_attribute("MARKET_MAD_CONF", mk_name, value); + }; /** * Gets an XML document with all of the configuration attributes @@ -564,9 +567,10 @@ private: "/DEFAULT_GROUP_QUOTAS/VM_QUOTA"), system_db(0), db(0), vmpool(0), hpool(0), vnpool(0), upool(0), ipool(0), gpool(0), tpool(0), - dspool(0), clpool(0), docpool(0), zonepool(0), secgrouppool(0), vdcpool(0), + dspool(0), clpool(0), docpool(0), zonepool(0), + secgrouppool(0), vdcpool(0), vrouterpool(0), marketpool(0), apppool(0), lcm(0), vmm(0), im(0), tm(0), dm(0), rm(0), hm(0), authm(0), - aclm(0), imagem(0) + aclm(0), imagem(0), marketm(0) { const char * nl = getenv("ONE_LOCATION"); @@ -614,6 +618,9 @@ private: delete zonepool; delete secgrouppool; delete vdcpool; + delete vrouterpool; + delete marketpool; + delete apppool; delete vmm; delete lcm; delete im; @@ -624,6 +631,7 @@ private: delete authm; delete aclm; delete imagem; + delete marketm; delete nebula_configuration; delete db; delete system_db; @@ -693,6 +701,9 @@ private: ZonePool * zonepool; SecurityGroupPool * secgrouppool; VdcPool * vdcpool; + VirtualRouterPool * vrouterpool; + MarketPlacePool * marketpool; + MarketPlaceAppPool * apppool; // --------------------------------------------------------------- // Nebula Managers @@ -708,12 +719,31 @@ private: AuthManager * authm; AclManager * aclm; ImageManager * imagem; + MarketPlaceManager * marketm; // --------------------------------------------------------------- // Implementation functions // --------------------------------------------------------------- friend void nebula_signal_handler (int sig); + + // --------------------------------------------------------------- + // Helper functions + // --------------------------------------------------------------- + + /** + * Gets a Generic configuration attribute + * @param key String that identifies the configuration parameter group name + * @param name Name of the specific configuration parameter + * @param value Value of the specific configuration parameter + * @return a reference to the generated string + */ + + int get_conf_attribute( + const std::string& key, + const std::string& name, + const VectorAttribute* &value) const; + }; #endif /*NEBULA_H_*/ diff --git a/include/NebulaTemplate.h b/include/NebulaTemplate.h index 62dcef7a7e..bfa4a16372 100644 --- a/include/NebulaTemplate.h +++ b/include/NebulaTemplate.h @@ -26,9 +26,6 @@ class NebulaTemplate : public Template { public: - // ----------------------------------------------------------------------- - // ----------------------------------------------------------------------- - NebulaTemplate(const string& etc_location, const char * _conf_name) { conf_file = etc_location + _conf_name; @@ -36,89 +33,6 @@ public: virtual ~NebulaTemplate(){}; - // ----------------------------------------------------------------------- - // ----------------------------------------------------------------------- - - int get(const char * name, vector& values) const - { - string _name(name); - - return Template::get(_name,values); - }; - - void get(const char * name, string& values) const - { - string _name(name); - - Template::get(_name,values); - }; - - void get(const char * name, int& values) const - { - string _name(name); - - Template::get(_name,values); - }; - - void get(const char *name, unsigned int& values) const - { - int ival; - - NebulaTemplate::get(name, ival); - - values = static_cast(ival); - }; - - void get(const char * name, time_t& values) const - { - const SingleAttribute * sattr; - vector attr; - - string _name(name); - - if ( Template::get(_name,attr) == 0 ) - { - values = 0; - return; - } - - sattr = dynamic_cast(attr[0]); - - if ( sattr != 0 ) - { - istringstream is; - - is.str(sattr->value()); - is >> values; - } - else - values = 0; - }; - - void get(const char *name, float& value) const - { - string _name(name); - - Template::get(_name,value); - }; - - void get(const char *name, bool& value) const - { - string _name(name); - - Template::get(_name,value); - }; - - void get(const char *name, long long& value) const - { - string _name(name); - - Template::get(_name,value); - } - - // ----------------------------------------------------------------------- - // ----------------------------------------------------------------------- - /** * Parse and loads the configuration in the template */ @@ -214,6 +128,11 @@ private: const std::string& shared, const std::string& ds_migrate); + /** + * Sets a the defaults for a Market + */ + void set_conf_market(const std::string& name, + const std::string& required_attrs); }; diff --git a/include/NebulaUtil.h b/include/NebulaUtil.h index 441e24df4a..38bf7b550c 100644 --- a/include/NebulaUtil.h +++ b/include/NebulaUtil.h @@ -159,6 +159,33 @@ namespace one_util */ std::string float_to_str(const float &num); + /** + * Returns a scaped version of a value in the from "" + * @param v the value to be escaped + * @param op the opening escape string + * @param cl the closing escape string + */ + template inline + std::string escape(const ValueType& v, const char * op, const char * cl) + { + std::ostringstream oss; + + oss << op << v << cl; + + return oss.str(); + } + + template inline + std::string escape_xml(const ValueType &v) + { + return escape(v, ""); + } + + template inline + std::string escape_xml_attr(const ValueType &v) + { + return escape(v, "'", "'"); + } /** * Checks if a strings matches a regular expression * @@ -174,6 +201,17 @@ namespace one_util * @return trimed string */ std::string trim(const std::string& str); + + /** + * Returns a copy of st with the all occurrences of "find" substituted + * for "replacement" + * @param st string input + * @param sfind string to search for + * @param replacement string to replace occurrences with + * @return a string copy + */ + std::string gsub(const std::string& st, const std::string& sfind, + const std::string& replacement); }; #endif /* _NEBULA_UTIL_H_ */ diff --git a/include/ObjectCollection.h b/include/ObjectCollection.h index 115563a912..03f304d78e 100644 --- a/include/ObjectCollection.h +++ b/include/ObjectCollection.h @@ -80,11 +80,19 @@ public: /** * Returns a copy of the IDs set */ - set get_collection_copy() + set get_collection_copy() const { return set (collection_set); }; + /** + * Returns a reference to the IDs set + */ + const set& get_collection() const + { + return collection_set; + }; + /** * Returns true if the collection contains the given id * @param id ID to search diff --git a/include/ObjectXML.h b/include/ObjectXML.h index dfbb3aabac..2ae12be37b 100644 --- a/include/ObjectXML.h +++ b/include/ObjectXML.h @@ -53,71 +53,107 @@ public: virtual ~ObjectXML(); /** - * Gets elements using Xpath expression. - * @param xpath_expr the Xpath of the element - * @return a vector with the elements + * 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); + }; + 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 - * is used - * @param value to set + * 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; + } + int xpath(std::string& value, const char * xpath_expr, const char * 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); - } - - inline int xpath(float& v, const char * x, const float& d) - { - return __xpath(v, x, d); - } - - inline int xpath(unsigned int& v, const char * x, const unsigned int& d) - { - return __xpath(v, x, d); - } - - inline int xpath(long long& v, const char * x, const long long& d) - { - return __xpath(v, x, d); - } - - inline int xpath(unsigned long long& v, const char * x, const unsigned long long& d) - { - return __xpath(v, x, d); - } - - 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 * @param value the value of the element @@ -293,103 +329,7 @@ private: */ 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/include/PoolObjectSQL.h b/include/PoolObjectSQL.h index dd24f93a9f..2b32e23fc2 100644 --- a/include/PoolObjectSQL.h +++ b/include/PoolObjectSQL.h @@ -49,41 +49,48 @@ public: */ enum ObjectType { - VM = 0x0000001000000000LL, - HOST = 0x0000002000000000LL, - NET = 0x0000004000000000LL, - IMAGE = 0x0000008000000000LL, - USER = 0x0000010000000000LL, - TEMPLATE = 0x0000020000000000LL, - GROUP = 0x0000040000000000LL, - ACL = 0x0000080000000000LL, - DATASTORE = 0x0000100000000000LL, - CLUSTER = 0x0000200000000000LL, - DOCUMENT = 0x0000400000000000LL, - ZONE = 0x0000800000000000LL, - SECGROUP = 0x0001000000000000LL, - VDC = 0x0002000000000000LL + NONE = 0x0000000000000000LL, + VM = 0x0000001000000000LL, + HOST = 0x0000002000000000LL, + NET = 0x0000004000000000LL, + IMAGE = 0x0000008000000000LL, + USER = 0x0000010000000000LL, + TEMPLATE = 0x0000020000000000LL, + GROUP = 0x0000040000000000LL, + ACL = 0x0000080000000000LL, + DATASTORE = 0x0000100000000000LL, + CLUSTER = 0x0000200000000000LL, + DOCUMENT = 0x0000400000000000LL, + ZONE = 0x0000800000000000LL, + SECGROUP = 0x0001000000000000LL, + VDC = 0x0002000000000000LL, + VROUTER = 0x0004000000000000LL, + MARKETPLACE = 0x0008000000000000LL, + MARKETPLACEAPP = 0x0010000000000000LL }; static string type_to_str(ObjectType ob) { switch (ob) { - case VM: return "VM" ; break; - case HOST: return "HOST" ; break; - case NET: return "NET" ; break; - case IMAGE: return "IMAGE" ; break; - case USER: return "USER" ; break; - case TEMPLATE: return "TEMPLATE" ; break; - case GROUP: return "GROUP" ; break; - case ACL: return "ACL" ; break; - case DATASTORE: return "DATASTORE" ; break; - case CLUSTER: return "CLUSTER" ; break; - case DOCUMENT: return "DOCUMENT" ; break; - case ZONE: return "ZONE" ; break; - case SECGROUP: return "SECGROUP" ; break; - case VDC: return "VDC" ; break; - default: return ""; + case VM: return "VM" ; break; + case HOST: return "HOST" ; break; + case NET: return "NET" ; break; + case IMAGE: return "IMAGE" ; break; + case USER: return "USER" ; break; + case TEMPLATE: return "TEMPLATE" ; break; + case GROUP: return "GROUP" ; break; + case ACL: return "ACL" ; break; + case DATASTORE: return "DATASTORE" ; break; + case CLUSTER: return "CLUSTER" ; break; + case DOCUMENT: return "DOCUMENT" ; break; + case ZONE: return "ZONE" ; break; + case SECGROUP: return "SECGROUP" ; break; + case VDC: return "VDC" ; break; + case VROUTER: return "VROUTER" ; break; + case MARKETPLACE: return "MARKETPLACE" ; break; + case MARKETPLACEAPP: return "MARKETPLACEAPP" ; break; + default: return ""; } }; @@ -320,152 +327,61 @@ public: // Template // ------------------------------------------------------------------------ /** - * Gets the values of a template attribute + * Gets the first VectorAttribute of the specified type with the given name. + * Const and non-const versions of this method is provided + * @param name the attribute name. + * @return true first attribute or 0 if not found or wrong type + */ + const VectorAttribute * get_template_attribute(const string& s) const + { + return obj_template->get(s); + } + + VectorAttribute * get_template_attribute(const string& s) + { + return obj_template->get(s); + } + + /** + * Gets the values of a template attribute, as a list of VectorAttributes * @param name of the attribute * @param values of the attribute * @return the number of values */ - int get_template_attribute( - const char * name, - vector& values) const + template + int get_template_attribute(const char * name, vector& values) const { return obj_template->get(name,values); }; /** - * Gets a string based attribute (single) + * These methods gets the value of a SingleAttribute and converts it to the + * target type * @param name of the attribute - * @param value of the attribute (a string), will be "" if not defined or + * @param value of the attribute, will be ""/0/false if not defined or * not a single attribute + * + * @return true if the attribute was found and is a valid type for the + * target value */ - void get_template_attribute( - const char * name, - string& value) const - { - obj_template->get(name,value); - } - - /** - * Gets and removes a string based attribute (single) - * @param name of the attribute - * @param value of the attribute (a string), will be "" if not defined or - * not a single attribute - * @return the number of attributes erased - */ - int erase_template_attribute( - const char * name, - string& value) - { - obj_template->get(name,value); - return obj_template->erase(name); - } - - /** - * Gets and removes a float based attribute (single) - * @param name of the attribute - * @param value of the attribute (a float), will be 0 if not defined or - * not a single attribute - * @return the number of attributes erased - */ - int erase_template_attribute( - const char * name, - float& value) - { - obj_template->get(name,value); - return obj_template->erase(name); - } - - /** - * Gets and removes a long long based attribute (single) - * @param name of the attribute - * @param value of the attribute (a long long), will be 0 if not defined or - * not a single attribute - * @return the number of attributes erased - */ - int erase_template_attribute( - const char * name, - long long& value) - { - obj_template->get(name,value); - return obj_template->erase(name); - } - - /** - * Gets and removes a boolean based attribute (single) - * @param name of the attribute - * @param value of the attribute (a boolean), will be false if not defined or - * not a single attribute - * @return the number of attributes erased - */ - int erase_template_attribute( - const char * name, - bool& value) - { - obj_template->get(name,value); - return obj_template->erase(name); - } - - /** - * Gets an int based attribute (single) - * @param name of the attribute - * @param value of the attribute (an int), will be 0 if not defined or - * not a single attribute - * - * @return True if the Single attribute was found and is a valid integer - * value - */ - bool get_template_attribute( - const char * name, - int& value) const + template + bool get_template_attribute(const char * name, T& value) const { return obj_template->get(name,value); } /** - * Gets a long long based attribute (single) + * These methods get and remove a string based attribute (single) * @param name of the attribute - * @param value of the attribute (long long), will be 0 if not defined or - * not a single attribute - * - * @return True if the Single attribute was found and is a valid integer - * value + * @param value of the attribute (a string), will be ""/0/false if not + * defined or not a single attribute, depending on the target value type + * @return the number of attributes erased */ - bool get_template_attribute( - const char * name, - long long& value) const + template + int erase_template_attribute(const char * name, T& value) { - return obj_template->get(name,value); - } - - /** - * Gets a float based attribute (single) - * @param name of the attribute - * @param value of the attribute (a float), will be 0 if not defined or - * not a single attribute - * - * @return True if the Single attribute was found and is a valid float - * value - */ - bool get_template_attribute( - const char * name, - float& value) const - { - return obj_template->get(name,value); - } - - /** - * Gets a boolean attribute (single) (YES = true) - * @param name of the attribute - * @param value of the attribute (True if "YES", false otherwise) - * - * @return True if the Single attribute was found and is a valid boolean - * value - */ - bool get_template_attribute( - const char * name, - bool& value) const - { - return obj_template->get(name,value); + obj_template->get(name,value); + return obj_template->erase(name); } /** @@ -475,9 +391,8 @@ public: * @param value of the new attribute * @return 0 on success */ - int replace_template_attribute( - const string& name, - const string& value) + template + int replace_template_attribute(const string& name, const T& value) { return obj_template->replace(name, value); } @@ -489,18 +404,17 @@ public: * @param values a vector containing a pointer to the attributes * @return the number of attributes removed */ - int remove_template_attribute( - const string& name, - vector& values) + template + int remove_template_attribute(const string& n, vector& v) { - return obj_template->remove(name, values); + return obj_template->remove(n, v); } /** * Generates a XML string for the template of the Object * @param xml the string to store the XML description. */ - string& template_to_xml(string &xml) const + string& template_to_xml(string &xml) const { return obj_template->to_xml(xml); } @@ -530,27 +444,8 @@ public: * @param att_name Name for the attribute * @param att_val Message string */ - void add_template_attribute(const string& name, const string& value) - { - obj_template->add(name, value); - } - - /** - * Adds an int attribute - * @param att_name Name for the attribute - * @param att_val integer - */ - void add_template_attribute(const string& name, int value) - { - obj_template->add(name, value); - } - - /** - * Adds a float attribute - * @param att_name Name for the attribute - * @param att_val integer - */ - void add_template_attribute(const string& name, float value) + template + void add_template_attribute(const string& name, const T& value) { obj_template->add(name, value); } diff --git a/include/PoolSQL.h b/include/PoolSQL.h index 8f7367154d..c1073c142d 100644 --- a/include/PoolSQL.h +++ b/include/PoolSQL.h @@ -248,8 +248,8 @@ protected: * @param remotes_location, path to remotes in the front-end where the * hooks are installed */ - void register_hooks(vector hook_mads, - const string& remotes_location); + void register_hooks(vector hook_mads, + const string& remotes_location); /** * Gets an object from the pool (if needed the object is loaded from the diff --git a/include/Quota.h b/include/Quota.h index e1b79e9c77..cd7b38b025 100644 --- a/include/Quota.h +++ b/include/Quota.h @@ -23,24 +23,11 @@ class Quotas; /** - * Base class for resource quotas, it provides basic storage and management of - * the quotas. Each resource MUST inherit from it to implement check and - * update methods. Quotas are stored in a template form, each class store the - * limits and usage in a resource specific format. + * This class defines the public interface (pure abstract) for Quota. */ -class Quota: public Template +class QuotaInterface { public: - - /** - * Set the quotas. If the quota previously exists its limit is updated. - * @param quota_str the quota template in ASCII or XML formats - * @param error describe the error in case of error - * - * @return 0 on success -1 otherwise - */ - int set(vector * quotas, string& error); - /** * Check if the resource allocation will exceed the quota limits. If not * the usage counters are updated @@ -51,6 +38,112 @@ public: */ virtual bool check(Template* tmpl, Quotas& default_quotas, string& error) = 0; + /** + * Decrement usage counters when deallocating image + * @param tmpl template for the resource + */ + virtual void del(Template* tmpl) = 0; + /** + * Set the quotas. If the quota previously exists its limit is updated. + * @param quota_str the quota template in ASCII or XML formats + * @param error describe the error in case of error + * + * @return 0 on success -1 otherwise + */ + virtual int set(vector * quotas, string& error) = 0; + + /** + * Check if a resource update in usage counters will exceed the + * quota limits. If not the usage counters are updated for that resource + * @param tmpl with increments in MEMORY and CPU + * @param default_quotas Quotas that contain the default limits + * @param error string + * @return true if the operation can be performed + */ + virtual bool update(Template * tmpl, Quotas& default_quotas, string& error) = 0; + + /** + * Returns the name that identifies the quota in a template + */ + virtual const char * get_quota_name() = 0; + + /** + * Gets a quota identified by its ID. + * @param id of the quota + * @param va The quota, if it is found + * @return 0 on success, -1 if not found + */ + virtual int get_quota(const string& id, VectorAttribute **va) = 0; + +protected: + QuotaInterface(){}; + + virtual ~QuotaInterface(){}; +}; + +/** + * The QuotaDecorator class decorates the quota interface with specific + * behavior over the same quota object and counters. Decorators must be derived + * from this class and pass in its constructor the decorated object. + */ +class QuotaDecorator : public QuotaInterface +{ + virtual bool check(Template* tmpl, Quotas& default_quotas, string& error) + { + return quota->check(tmpl, default_quotas, error); + } + + virtual void del(Template* tmpl) + { + return quota->del(tmpl); + } + + virtual int set(vector * quotas, string& error) + { + return quota->set(quotas, error); + } + + virtual bool update(Template * tmpl, Quotas& default_quotas, string& error) + { + return quota->update(tmpl, default_quotas, error); + } + + virtual const char * get_quota_name() + { + return quota->get_quota_name(); + } + + virtual int get_quota(const string& id, VectorAttribute **va) + { + return quota->get_quota(id, va); + } + +protected: + QuotaDecorator(QuotaInterface * _quota):quota(_quota){}; + + virtual ~QuotaDecorator(){}; + + QuotaInterface * quota; +}; + +/** + * Base class for resource quotas, it provides basic storage and management of + * the quotas. Each resource MUST inherit from it to implement check and + * update methods. Quotas are stored in a template form, each class store the + * limits and usage in a resource specific format. + */ +class Quota: public Template, public QuotaInterface +{ +public: + /** + * Set the quotas. If the quota previously exists its limit is updated. + * @param quota_str the quota template in ASCII or XML formats + * @param error describe the error in case of error + * + * @return 0 on success -1 otherwise + */ + int set(vector * quotas, string& error); + /** * Check if a resource update in usage counters will exceed the * quota limits. If not the usage counters are updated for that resource @@ -65,12 +158,6 @@ public: return false; }; - /** - * Decrement usage counters when deallocating image - * @param tmpl template for the resource - */ - virtual void del(Template* tmpl) = 0; - /** * Returns the name that identifies the quota in a template */ @@ -102,7 +189,6 @@ public: */ static const int UNLIMITED; - protected: Quota(const char * quota_name, diff --git a/include/QuotaNetwork.h b/include/QuotaNetwork.h index ff18a2bd83..13f6e0cd74 100644 --- a/include/QuotaNetwork.h +++ b/include/QuotaNetwork.h @@ -18,6 +18,7 @@ #define QUOTA_NETWORK_H_ #include "Quota.h" +#include "PoolObjectSQL.h" /** * DataStore Quotas, defined as: @@ -29,39 +30,38 @@ * * 0 = unlimited, default if missing */ - class QuotaNetwork : public Quota { public: + QuotaNetwork(bool is_default): Quota("NETWORK_QUOTA", "NETWORK", NET_METRICS, + NUM_NET_METRICS, is_default) {}; - QuotaNetwork(bool is_default): - Quota("NETWORK_QUOTA", - "NETWORK", - NET_METRICS, - NUM_NET_METRICS, - is_default) - {}; - - ~QuotaNetwork(){}; + virtual ~QuotaNetwork(){}; /** * Check if the resource allocation will exceed the quota limits. If not - * the usage counters are updated + * the usage counters are updated. Assumes calling object is a VM * @param tmpl template for the resource * @param default_quotas Quotas that contain the default limits * @param error string * @return true if the operation can be performed */ - bool check(Template* tmpl, Quotas& default_quotas, string& error); + bool check(Template* tmpl, Quotas& default_quotas, string& err) + { + return check(PoolObjectSQL::VM, tmpl, default_quotas, err); + } /** - * Decrement usage counters when deallocating image + * Decrement usage counters when freeing a lease. This method considers + * the object type to accounto for FLOATING IP addresses or not * @param tmpl template for the resource */ - void del(Template* tmpl); + void del(Template* tmpl) + { + del(PoolObjectSQL::VM, tmpl); + } protected: - /** * Gets the default quota identified by its ID. * @@ -78,6 +78,61 @@ protected: static const char * NET_METRICS[]; static const int NUM_NET_METRICS; + +private: + /** + * Friends are decorators for the QuotaNetwork. They can access specialized + * methods to operate over the same quota counters (base Template class) + */ + friend class QuotaNetworkVirtualRouter; + + /** + * Check if the resource allocation will exceed the quota limits. If not + * the usage counters are updated. This method considers the object type to + * accounto for FLOATING IP addresses or not + * @param otype object type, VM or VRouter + * @param tmpl template for the resource + * @param default_quotas Quotas that contain the default limits + * @param error string + * @return true if the operation can be performed + */ + bool check(PoolObjectSQL::ObjectType otype, Template* tmpl, + Quotas& default_quotas, string& error); + + /** + * Decrement usage counters when freeing a lease. This method considers + * the object type to accounto for FLOATING IP addresses or not + * @param otype object type, VM or VRouter + * @param tmpl template for the resource + */ + void del(PoolObjectSQL::ObjectType otype, Template* tmpl); +}; + +/** + * Decorates the QuotaNetwork object to consider the FLOATING_IP attribute + * of the NIC attributes. It must be instantiated using an exisiting QuotaNetwork + * object + */ +class QuotaNetworkVirtualRouter: public QuotaDecorator +{ +public: + QuotaNetworkVirtualRouter(QuotaNetwork *qn):QuotaDecorator(qn){}; + + virtual ~QuotaNetworkVirtualRouter(){}; + + bool check(Template* tmpl, Quotas& default_quotas, string& err) + { + QuotaNetwork * qn = static_cast(quota); + + return qn->check(PoolObjectSQL::VROUTER, tmpl, default_quotas, err); + } + + void del(Template* tmpl) + { + QuotaNetwork * qn = static_cast(quota); + + qn->del(PoolObjectSQL::VROUTER, tmpl); + } }; #endif /*QUOTA_NETWORK_H_*/ diff --git a/include/Quotas.h b/include/Quotas.h index bbcd348658..93261ae39b 100644 --- a/include/Quotas.h +++ b/include/Quotas.h @@ -35,7 +35,8 @@ public: VM, /**< Checks VM usage (MEMORY, CPU and VMS) */ NETWORK, /**< Checks Network usage (leases) */ IMAGE, /**< Checks Image usage (RVMs using it) */ - VIRTUALMACHINE /**< Checks all VM associated resources VM, NETWORK, IMAGE */ + VIRTUALMACHINE, /**< Checks all VM associated resources VM, NETWORK, IMAGE */ + VIRTUALROUTER /**< Checks the Virtual Router NETWORK usage (leases) */ }; /** @@ -69,17 +70,6 @@ public: return datastore_quota.get_quota(id, va); } - /** - * Delete VM related usage (network, image and compute) from quota counters. - * @param tmpl template for the image, with usage - */ - void vm_del(Template * tmpl) - { - network_quota.del(tmpl); - vm_quota.del(tmpl); - image_quota.del(tmpl); - } - /** * Gets a VM quota identified by its ID. * diff --git a/include/Request.h b/include/Request.h index f606def3c0..2263c7218c 100644 --- a/include/Request.h +++ b/include/Request.h @@ -27,6 +27,77 @@ using namespace std; +/** + * This class represents the dynamic attributes: specific for a request of the + * same method. + */ +struct RequestAttributes +{ +public: + int uid; /**< id of the user */ + int gid; /**< id of the user's group */ + + string uname; /**< name of the user */ + string gname; /**< name of the user's group */ + + string password; /**< password of the user */ + + set group_ids; /**< set of user's group ids */ + + string session; /**< Session from ONE XML-RPC API */ + int req_id; /**< Request ID for log messages */ + + int umask; /**< User umask for new objects */ + + xmlrpc_c::value * retval; /**< Return value from libxmlrpc-c */ + + PoolObjectSQL::ObjectType resp_obj; /**< object type */ + int resp_id; /**< Id of the object */ + string resp_msg; /**< Additional response message */ + + RequestAttributes(){}; + + RequestAttributes(const RequestAttributes& ra) + { + uid = ra.uid; + gid = ra.gid; + + uname = ra.uname; + gname = ra.gname; + + password = ra.password; + + session = ra.session; + retval = ra.retval; + + umask = ra.umask; + + resp_obj = ra.resp_obj; + resp_id = ra.resp_id; + resp_msg = ra.resp_msg; + }; + + RequestAttributes(int _uid, int _gid, const RequestAttributes& ra) + { + uid = _uid; + gid = _gid; + + password = ""; + + uname = ""; + gname = ""; + + umask = 0; + + session = ra.session; + retval = ra.retval; + + resp_obj = PoolObjectSQL::NONE; + resp_id = -1; + resp_msg = ""; + }; +}; + /** * The Request Class represents the basic abstraction for the OpenNebula * XML-RPC API. This interface must be implemented by any XML-RPC API call @@ -34,16 +105,6 @@ using namespace std; class Request: public xmlrpc_c::method { public: - /** - * Wraps the actual execution function by authorizing the user - * and calling the request_execute virtual function - * @param _paramlist list of XML parameters - * @param _retval value to be returned to the client - */ - virtual void execute( - xmlrpc_c::paramList const& _paramList, - xmlrpc_c::value * const _retval); - /** * Error codes for the XML-RPC API */ @@ -55,8 +116,17 @@ public: ACTION = 0x0800, XML_RPC_API = 0x1000, INTERNAL = 0x2000, + ALLOCATE = 0x4000 }; + /** + * Gets a string representation for the Auth object in the + * request. + * @param ob object for the auth operation + * @return string equivalent of the object + */ + static string object_name(PoolObjectSQL::ObjectType ob); + /** * Sets the format string to log xml-rpc method calls. The format string * interprets the following sequences: @@ -77,69 +147,9 @@ public: } protected: - - /* ---------------------------------------------------------------------*/ - /* Attributes of the Request */ - /* ---------------------------------------------------------------------*/ - - /* -------- Dynamic (specific for a request of the same method) -------- */ - - struct RequestAttributes - { - int uid; /**< id of the user */ - int gid; /**< id of the user's group */ - - string uname; /**< name of the user */ - string gname; /**< name of the user's group */ - - string password; /**< password of the user */ - - set group_ids; /**< set of user's group ids */ - - string session; /**< Session from ONE XML-RPC API */ - int req_id; /**< Request ID for log messages */ - - int umask; /**< User umask for new objects */ - - xmlrpc_c::value * retval; /**< Return value from libxmlrpc-c */ - - RequestAttributes(){}; - - RequestAttributes(const RequestAttributes& ra) - { - uid = ra.uid; - gid = ra.gid; - - uname = ra.uname; - gname = ra.gname; - - password = ra.password; - - session = ra.session; - retval = ra.retval; - - umask = ra.umask; - }; - - RequestAttributes(int _uid, int _gid, const RequestAttributes& ra) - { - uid = _uid; - gid = _gid; - - password = ""; - - uname = ""; - gname = ""; - - umask = 0; - - session = ra.session; - retval = ra.retval; - }; - }; - - /* -------- Static (shared among request of the same method) -------- */ - + /* ---------------------------------------------------------------------- */ + /* Static Request Attributes: shared among request of the same method */ + /* ---------------------------------------------------------------------- */ PoolSQL * pool; /**< Pool of objects */ string method_name; /**< The name of the XML-RPC method */ @@ -150,11 +160,11 @@ protected: static string format_str; - /* -------------------- Constructors ---------------------------------- */ - - Request(const string& mn, - const string& signature, - const string& help): pool(0),method_name(mn) + /* ---------------------------------------------------------------------- */ + /* Class Constructors */ + /* ---------------------------------------------------------------------- */ + Request(const string& mn, const string& signature, const string& help): + pool(0),method_name(mn) { _signature = signature; _help = help; @@ -164,9 +174,88 @@ protected: virtual ~Request(){}; - /* -------------------------------------------------------------------- */ - /* -------------------------------------------------------------------- */ + /* ---------------------------------------------------------------------- */ + /* Methods to execute the request when received at the server */ + /* ---------------------------------------------------------------------- */ + /** + * Wraps the actual execution function by authorizing the user + * and calling the request_execute virtual function + * @param _paramlist list of XML parameters + * @param _retval value to be returned to the client + */ + virtual void execute(xmlrpc_c::paramList const& _paramList, + xmlrpc_c::value * const _retval); + /** + * Actual Execution method for the request. Must be implemented by the + * XML-RPC requests + * @param _paramlist of the XML-RPC call (complete list) + * @param att the specific request attributes + */ + virtual void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att) = 0; + /** + * Locks the requested object, gets information, and unlocks it + * + * @param pool object pool + * @param id of the object + * @param type of the object + * @param att the specific request attributes + * + * @param perms returns the object's permissions + * @param name returns the object's name + * @param throw_error send error response to client if object not found + * + * @return 0 on success, -1 otherwise + */ + int get_info(PoolSQL * pool, + int id, + PoolObjectSQL::ObjectType type, + RequestAttributes& att, + PoolObjectAuth& perms, + string& name, + bool throw_error); + + /* ---------------------------------------------------------------------- */ + /* Methods to send response to xml-rpc client */ + /* ---------------------------------------------------------------------- */ + /** + * Builds an XML-RPC response updating retval. After calling this function + * the xml-rpc excute method should return + * @param val to be returned to the client + * @param att the specific request attributes + */ + void success_response(int val, RequestAttributes& att); + + /** + * Builds an XML-RPC response updating retval. After calling this function + * the xml-rpc excute method should return + * @param val string to be returned to the client + * @param att the specific request attributes + */ + void success_response(const string& val, RequestAttributes& att); + + /** + * Builds an XML-RPC response updating retval. After calling this function + * the xml-rpc execute method should return + * @param val to be returned to the client + * @param att the specific request attributes + */ + void success_response(bool val, RequestAttributes& att); + + /** + * Builds an XML-RPC response updating retval. After calling this function + * the xml-rpc excute method should return. A descriptive error message + * is constructed using att.resp_obj, att.resp_id and/or att.resp_msg and + * the ErrorCode + * @param ec error code for this call + * @param ra the specific request attributes + */ + void failure_response(ErrorCode ec, RequestAttributes& ra); + + /* ---------------------------------------------------------------------- */ + /* Authorization methods for requests */ + /* ---------------------------------------------------------------------- */ /** * Performs a basic authorization for this request using the uid/gid * from the request. The function gets the object from the pool to get @@ -196,7 +285,7 @@ protected: * @return true if the user is authorized. */ bool basic_authorization(int oid, AuthRequest::Operation op, - RequestAttributes& att); + RequestAttributes& att); /** * Performs a basic quota check for this request using the uid/gid @@ -209,10 +298,8 @@ protected: * * @return true if the user is authorized. */ - bool quota_authorization( - Template * tmpl, - Quotas::QuotaType qtype, - RequestAttributes& att); + bool quota_authorization(Template * tmpl, Quotas::QuotaType qtype, + RequestAttributes& att); /** * Performs a basic quota check for this request using the uid/gid @@ -227,11 +314,8 @@ protected: * @param error_str Error reason, if any * @return true if the user is authorized. */ - bool quota_authorization( - Template * tmpl, - Quotas::QuotaType qtype, - RequestAttributes& att, - string& error_str); + static bool quota_authorization(Template * tmpl, Quotas::QuotaType qtype, + RequestAttributes& att, string& error_str); /** * Performs rollback on usage counters for a previous quota check operation @@ -239,136 +323,53 @@ protected: * @param tmpl describing the object * @param att the specific request attributes */ - void quota_rollback(Template * tmpl, - Quotas::QuotaType qtype, - RequestAttributes& att); + static void quota_rollback(Template * tmpl, Quotas::QuotaType qtype, + RequestAttributes& att); - /** - * Actual Execution method for the request. Must be implemented by the - * XML-RPC requests - * @param _paramlist of the XML-RPC call (complete list) - * @param att the specific request attributes - */ - virtual void request_execute(xmlrpc_c::paramList const& _paramList, - RequestAttributes& att) = 0; +private: + /* ---------------------------------------------------------------------- */ + /* Functions to manage user and group quotas */ + /* ---------------------------------------------------------------------- */ + static bool user_quota_authorization(Template * tmpl, Quotas::QuotaType qtype, + RequestAttributes& att, string& error_str); - /** - * Builds an XML-RPC response updating retval. After calling this function - * the xml-rpc excute method should return - * @param val to be returned to the client - * @param att the specific request attributes - */ - void success_response(int val, RequestAttributes& att); + static bool group_quota_authorization(Template * tmpl, Quotas::QuotaType qtype, + RequestAttributes& att, string& error_str); - /** - * Builds an XML-RPC response updating retval. After calling this function - * the xml-rpc excute method should return - * @param val string to be returned to the client - * @param att the specific request attributes - */ - void success_response(const string& val, RequestAttributes& att); + static void user_quota_rollback(Template * tmpl, Quotas::QuotaType qtype, + RequestAttributes& att); - /** - * Builds an XML-RPC response updating retval. After calling this function - * the xml-rpc execute method should return - * @param val to be returned to the client - * @param att the specific request attributes - */ - void success_response(bool val, RequestAttributes& att); + static void group_quota_rollback(Template * tmpl, Quotas::QuotaType qtype, + RequestAttributes& att); /** * Builds an XML-RPC response updating retval. After calling this function * the xml-rpc excute method should return * @param ec error code for this call - * @param val string representation of the error - * @param att the specific request attributes + * @param va string representation of the error + * @param ra the specific request attributes */ - void failure_response(ErrorCode ec, - const string& val, - RequestAttributes& att); + void failure_response(ErrorCode ec, const string& va, RequestAttributes& ra); /** - * Gets a string representation for the Auth object in the - * request. - * @param ob object for the auth operation - * @return string equivalent of the object - */ - static string object_name(PoolObjectSQL::ObjectType ob); - - /** - * Logs authorization errors - * @param message with the authorization error details - * @return string for logging - * @param att the specific request attributes - */ - string authorization_error (const string &message, RequestAttributes& att); - - /** - * Logs authenticate errors - * @return string for logging - */ - string authenticate_error (); - - /** - * Logs get object errors - * @param object over which the get failed - * @param id of the object over which the get failed - * @return string for logging - */ - string get_error (const string &object, int id); - - /** - * Logs action errors - * @param err_desc brief description of the error - * @param err_detail additional error details from Managers & Pools - * @return string for logging - */ - string request_error (const string &err_desc, const string &err_detail); - - /** - * Logs allocate errors - * @param message with the allocate error details - * @return string for logging - */ - string allocate_error (const string& error); - - /** - * Logs allocate errors for a given resource - * @param obj the resource - * @param message with the allocate error details - * @return string for logging - */ - string allocate_error (PoolObjectSQL::ObjectType obj, const string& error); - - /** - * Locks the requested object, gets information, and unlocks it - * - * @param pool object pool - * @param id of the object - * @param type of the object + * Logs the method invocation, including the arguments * @param att the specific request attributes - * - * @param perms returns the object's permissions - * @param name returns the object's name - * @param throw_error send error response to client if object not found - * - * @return 0 on success, -1 otherwise + * @param paramList list of XML parameters + * @param format_str for the log + * @param hidden_params params not to be shown */ - int get_info (PoolSQL * pool, - int id, - PoolObjectSQL::ObjectType type, - RequestAttributes& att, - PoolObjectAuth& perms, - string& name, - bool throw_error); + static void log_method_invoked(const RequestAttributes& att, + const xmlrpc_c::paramList& paramList, const string& format_str, + const std::string& method_name, const std::set& hidden_params); /** * Logs the method result, including the output data or error message * * @param att the specific request attributes + * @param method_name that produced the error */ - virtual void log_result( - const RequestAttributes& att); + static void log_result(const RequestAttributes& att, + const std::string& method_name); /** * Formats and adds a xmlrpc_c::value to oss. @@ -376,41 +377,7 @@ protected: * @param v value to format * @param oss stream to write v */ - virtual void log_xmlrpc_value( - const xmlrpc_c::value& v, - ostringstream& oss); - -private: - - /** - * Logs the method invocation, including the arguments - * - * @param att the specific request attributes - * @param paramList list of XML parameters - */ - void log_method_invoked( - const RequestAttributes& att, - const xmlrpc_c::paramList& paramList); - - /* ------------- Functions to manage user and group quotas -------------- */ - - bool user_quota_authorization(Template * tmpl, - Quotas::QuotaType qtype, - RequestAttributes& att, - string& error_str); - - bool group_quota_authorization(Template * tmpl, - Quotas::QuotaType qtype, - RequestAttributes& att, - string& error_str); - - void user_quota_rollback(Template * tmpl, - Quotas::QuotaType qtype, - RequestAttributes& att); - - void group_quota_rollback(Template * tmpl, - Quotas::QuotaType qtype, - RequestAttributes& att); + static void log_xmlrpc_value(const xmlrpc_c::value& v, std::ostringstream& oss); }; /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerAllocate.h b/include/RequestManagerAllocate.h index 0076f2d7bc..d78d6ccd5d 100644 --- a/include/RequestManagerAllocate.h +++ b/include/RequestManagerAllocate.h @@ -64,7 +64,6 @@ protected: virtual int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { return -1; @@ -73,12 +72,11 @@ protected: virtual int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att, int cluster_id, const string& cluster_name) { - return pool_allocate(_paramList, tmpl, id, error_str, att); + return pool_allocate(_paramList, tmpl, id, att); }; virtual int get_cluster_id(xmlrpc_c::paramList const& paramList) @@ -138,7 +136,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att); bool allocate_authorization(Template * obj_template, @@ -175,7 +172,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att, int cluster_id, const string& cluster_name); @@ -249,7 +245,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att); bool allocate_authorization(Template * obj_template, @@ -281,7 +276,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att, int cluster_id, const string& cluster_name); @@ -325,7 +319,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att); }; @@ -353,7 +346,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att); private: @@ -389,7 +381,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att, int cluster_id, const string& cluster_name); @@ -445,7 +436,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att); }; @@ -478,7 +468,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att); }; @@ -514,7 +503,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att); }; @@ -547,7 +535,6 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att); }; @@ -580,10 +567,113 @@ public: int pool_allocate(xmlrpc_c::paramList const& _paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att); }; -/* -------------------------------------------------------------------------- */ + + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterAllocate : public RequestManagerAllocate +{ +public: + VirtualRouterAllocate(): + RequestManagerAllocate("VirtualRouterAllocate", + "Allocates a new virtual router", + "A:ss", + true) + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vrouterpool(); + auth_object = PoolObjectSQL::VROUTER; + }; + + ~VirtualRouterAllocate(){}; + + /* --------------------------------------------------------------------- */ + + Template * get_object_template() + { + return new Template; + }; + + int pool_allocate(xmlrpc_c::paramList const& _paramList, + Template * tmpl, + int& id, + RequestAttributes& att); + + bool allocate_authorization(Template * obj_template, + RequestAttributes& att, + PoolObjectAuth * cluster_perms); +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceAllocate : public RequestManagerAllocate +{ +public: + MarketPlaceAllocate(): + RequestManagerAllocate("MarketPlaceAllocate", + "Allocates a new marketplace", + "A:ss", + true) + { + Nebula& nd = Nebula::instance(); + pool = nd.get_marketpool(); + auth_object = PoolObjectSQL::MARKETPLACE; + }; + + ~MarketPlaceAllocate(){}; + + /* --------------------------------------------------------------------- */ + + Template * get_object_template() + { + return new MarketPlaceTemplate; + }; + + int pool_allocate(xmlrpc_c::paramList const& _paramList, + Template * tmpl, + int& id, + RequestAttributes& att); +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceAppAllocate : public RequestManagerAllocate +{ +public: + MarketPlaceAppAllocate(): + RequestManagerAllocate("MarketPlaceAppAllocate", + "Allocates a new marketplace app", + "A:ssi", + true) + { + Nebula& nd = Nebula::instance(); + pool = nd.get_apppool(); + mppool = nd.get_marketpool(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + }; + + ~MarketPlaceAppAllocate(){}; + + /* --------------------------------------------------------------------- */ + + Template * get_object_template() + { + return new MarketPlaceAppTemplate; + }; + + int pool_allocate(xmlrpc_c::paramList const& _paramList, + Template * tmpl, + int& id, + RequestAttributes& att); +private: + MarketPlacePool * mppool; +}; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerChmod.h b/include/RequestManagerChmod.h index 18520f3181..a48474a7da 100644 --- a/include/RequestManagerChmod.h +++ b/include/RequestManagerChmod.h @@ -171,7 +171,62 @@ public: }; -/* -------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterChmod: public RequestManagerChmod +{ +public: + VirtualRouterChmod(): + RequestManagerChmod("VirtualRouterChmod", + "Changes permission bits of a virtual router") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vrouterpool(); + auth_object = PoolObjectSQL::VROUTER; + }; + + ~VirtualRouterChmod(){}; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceChmod: public RequestManagerChmod +{ +public: + MarketPlaceChmod(): + RequestManagerChmod("MarketPlaceChmod", + "Changes permission bits of a marketplace") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_marketpool(); + auth_object = PoolObjectSQL::MARKETPLACE; + }; + + ~MarketPlaceChmod(){}; + +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceAppChmod: public RequestManagerChmod +{ +public: + MarketPlaceAppChmod(): + RequestManagerChmod("MarketPlaceAppChmod", + "Changes permission bits of a marketplace app") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_apppool(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + }; + + ~MarketPlaceAppChmod(){}; + +}; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerChown.h b/include/RequestManagerChown.h index df88d6e4a7..4f069cab93 100644 --- a/include/RequestManagerChown.h +++ b/include/RequestManagerChown.h @@ -268,7 +268,76 @@ public: return static_cast(pool)->get(name, uid, lock); }; }; -/* -------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterChown: public RequestManagerChown +{ +public: + VirtualRouterChown(): + RequestManagerChown("VirtualRouterChown", + "Changes ownership of a virtual router") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vrouterpool(); + auth_object = PoolObjectSQL::VROUTER; + }; + + ~VirtualRouterChown(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, uid, lock); + }; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceChown: public RequestManagerChown +{ +public: + MarketPlaceChown(): + RequestManagerChown("MarketPlaceChown", + "Changes ownership of a marketplace") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_marketpool(); + auth_object = PoolObjectSQL::MARKETPLACE; + }; + + ~MarketPlaceChown(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return 0; + }; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceAppChown: public RequestManagerChown +{ +public: + MarketPlaceAppChown(): + RequestManagerChown("MarketPlaceAppChown", + "Changes ownership of a marketplace app") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_apppool(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + }; + + ~MarketPlaceAppChown(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, uid, lock); + }; +}; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerClone.h b/include/RequestManagerClone.h index 807df66dde..7ead78db9d 100644 --- a/include/RequestManagerClone.h +++ b/include/RequestManagerClone.h @@ -48,7 +48,6 @@ protected: int source_id, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) = 0; }; @@ -82,7 +81,6 @@ public: int source_id, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { VMTemplatePool * tpool = static_cast(pool); @@ -91,7 +89,7 @@ public: static_cast(tmpl); return tpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, - ttmpl, &id, error_str); + ttmpl, &id, att.resp_msg); }; }; @@ -126,17 +124,15 @@ public: int source_id, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { DocumentPool * docpool = static_cast(pool); Document * doc = docpool->get(source_id, true); - int document_type = doc->get_document_type(); doc->unlock(); return docpool->allocate(att.uid, att.gid, att.uname, att.gname, - att.umask, document_type, tmpl, &id, error_str); + att.umask, doc->get_document_type(), tmpl, &id, att.resp_msg); }; }; @@ -170,13 +166,12 @@ public: int source_id, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { SecurityGroupPool * secgrouppool = static_cast(pool); return secgrouppool->allocate(att.uid, att.gid, att.uname, att.gname, - att.umask, tmpl, &id, error_str); + att.umask, tmpl, &id, att.resp_msg); }; }; /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerDelete.h b/include/RequestManagerDelete.h index 25f23adeb7..38f7617c18 100644 --- a/include/RequestManagerDelete.h +++ b/include/RequestManagerDelete.h @@ -137,9 +137,6 @@ public: ~ImageDelete(){}; - - /* -------------------------------------------------------------------- */ - int drop(int oid, PoolObjectSQL * object, string& error_msg); }; @@ -354,7 +351,61 @@ public: ~VdcDelete(){}; }; -/* -------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterDelete : public RequestManagerDelete +{ +public: + VirtualRouterDelete(): + RequestManagerDelete("VirtualRouterDelete", + "Deletes a virtual router") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vrouterpool(); + auth_object = PoolObjectSQL::VROUTER; + }; + + ~VirtualRouterDelete(){}; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceDelete : public RequestManagerDelete +{ +public: + MarketPlaceDelete(): + RequestManagerDelete("MarketPlaceDelete", + "Deletes a marketplace") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_marketpool(); + auth_object = PoolObjectSQL::MARKETPLACE; + }; + + ~MarketPlaceDelete(){}; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceAppDelete : public RequestManagerDelete +{ +public: + MarketPlaceAppDelete(): + RequestManagerDelete("MarketPlaceAppDelete", + "Deletes a marketplace app") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_apppool(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + }; + + ~MarketPlaceAppDelete(){}; + + int drop(int oid, PoolObjectSQL * object, string& error_msg); +}; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerInfo.h b/include/RequestManagerInfo.h index c978be23d9..d50b5cf7b7 100644 --- a/include/RequestManagerInfo.h +++ b/include/RequestManagerInfo.h @@ -318,7 +318,59 @@ public: ~VdcInfo(){}; }; -/* -------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterInfo : public RequestManagerInfo +{ +public: + VirtualRouterInfo(): + RequestManagerInfo("VirtualRouterInfo", + "Returns virtual router information") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vrouterpool(); + auth_object = PoolObjectSQL::VROUTER; + }; + + ~VirtualRouterInfo(){}; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceInfo : public RequestManagerInfo +{ +public: + MarketPlaceInfo(): + RequestManagerInfo("MarketPlaceInfo", + "Returns marketplace information") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_marketpool(); + auth_object = PoolObjectSQL::MARKETPLACE; + }; + + ~MarketPlaceInfo(){}; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceAppInfo : public RequestManagerInfo +{ +public: + MarketPlaceAppInfo(): + RequestManagerInfo("MarketPlaceAppInfo", + "Returns marketplace app information") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_apppool(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + }; + + ~MarketPlaceAppInfo(){}; +}; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerMarketPlaceApp.h b/include/RequestManagerMarketPlaceApp.h new file mode 100644 index 0000000000..d0b8cb4015 --- /dev/null +++ b/include/RequestManagerMarketPlaceApp.h @@ -0,0 +1,66 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 REQUEST_MANAGER_MARKETPLACEAPP_H +#define REQUEST_MANAGER_MARKETPLACEAPP_H + +#include "Request.h" +#include "Nebula.h" + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class RequestManagerMarketPlaceApp: public Request +{ +protected: + RequestManagerMarketPlaceApp(const std::string& method_name, + const std::string& help, const std::string& params) : + Request(method_name, params, help) + { + Nebula& nd = Nebula::instance(); + pool = nd.get_apppool(); + + auth_object = PoolObjectSQL::MARKETPLACEAPP; + auth_op = AuthRequest::MANAGE; + }; + + ~RequestManagerMarketPlaceApp(){}; + + /* --------------------------------------------------------------------- */ + + virtual void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att) = 0; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceAppEnable : public RequestManagerMarketPlaceApp +{ +public: + MarketPlaceAppEnable(): RequestManagerMarketPlaceApp("MarketPlaceAppEnable", + "Enables or disables a marketplace app", "A:sib"){}; + + ~MarketPlaceAppEnable(){}; + + void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att); +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +#endif diff --git a/include/RequestManagerPoolInfoFilter.h b/include/RequestManagerPoolInfoFilter.h index 1708e39346..c0ac51a9f5 100644 --- a/include/RequestManagerPoolInfoFilter.h +++ b/include/RequestManagerPoolInfoFilter.h @@ -488,14 +488,66 @@ public: ~VdcPoolInfo(){}; - /* -------------------------------------------------------------------- */ + void request_execute(xmlrpc_c::paramList const& pl, RequestAttributes& att); +}; - void request_execute( - xmlrpc_c::paramList const& paramList, RequestAttributes& att); +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterPoolInfo : public RequestManagerPoolInfoFilter +{ +public: + VirtualRouterPoolInfo(): + RequestManagerPoolInfoFilter("VirtualRouterPoolInfo", + "Returns the virtual router pool", + "A:siii") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vrouterpool(); + auth_object = PoolObjectSQL::VROUTER; + }; + + ~VirtualRouterPoolInfo(){}; }; /* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class MarketPlacePoolInfo : public RequestManagerPoolInfoFilter +{ +public: + MarketPlacePoolInfo(): + RequestManagerPoolInfoFilter("MarketPlacePoolInfo", + "Returns the marketplace pool", + "A:s") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_marketpool(); + auth_object = PoolObjectSQL::MARKETPLACE; + }; + + ~MarketPlacePoolInfo(){}; + + void request_execute(xmlrpc_c::paramList const& pl, RequestAttributes& att); +}; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +class MarketPlaceAppPoolInfo : public RequestManagerPoolInfoFilter +{ +public: + MarketPlaceAppPoolInfo(): + RequestManagerPoolInfoFilter("MarketPlacePoolInfo", + "Returns the market place pool", + "A:siii") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_apppool(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + }; + + ~MarketPlaceAppPoolInfo(){}; +}; + #endif diff --git a/include/RequestManagerRename.h b/include/RequestManagerRename.h index 539c2f7c5b..e726589d73 100644 --- a/include/RequestManagerRename.h +++ b/include/RequestManagerRename.h @@ -334,7 +334,74 @@ public: ~VdcRename(){}; }; -/* -------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterRename: public RequestManagerRename +{ +public: + VirtualRouterRename(): + RequestManagerRename("VirtualRouterRename", "Renames a virtual router") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vrouterpool(); + auth_object = PoolObjectSQL::VROUTER; + }; + + ~VirtualRouterRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, uid, lock); + }; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceRename: public RequestManagerRename +{ +public: + MarketPlaceRename(): + RequestManagerRename("MarketPlaceRename", "Renames a marketplace") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_marketpool(); + auth_object = PoolObjectSQL::MARKETPLACE; + }; + + ~MarketPlaceRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, lock); + }; + + void batch_rename(int oid); +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceAppRename: public RequestManagerRename +{ +public: + MarketPlaceAppRename(): + RequestManagerRename("MarketPlaceRename", "Renames a marketplace app") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_apppool(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + }; + + ~MarketPlaceAppRename(){}; + + PoolObjectSQL * get(const string& name, int uid, bool lock) + { + return static_cast(pool)->get(name, uid, lock); + }; +}; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerUpdateTemplate.h b/include/RequestManagerUpdateTemplate.h index abffc3aa48..c3f0bf9085 100644 --- a/include/RequestManagerUpdateTemplate.h +++ b/include/RequestManagerUpdateTemplate.h @@ -286,7 +286,60 @@ public: ~VdcUpdateTemplate(){}; }; -/* -------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterUpdateTemplate : public RequestManagerUpdateTemplate +{ +public: + VirtualRouterUpdateTemplate(): + RequestManagerUpdateTemplate("VirtualRouterUpdateTemplate", + "Updates a virtual router template") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vrouterpool(); + auth_object = PoolObjectSQL::VROUTER; + }; + + ~VirtualRouterUpdateTemplate(){}; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceUpdateTemplate : public RequestManagerUpdateTemplate +{ +public: + MarketPlaceUpdateTemplate(): + RequestManagerUpdateTemplate("MarketPlaceUpdateTemplate", + "Updates a marketplace template") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_marketpool(); + auth_object = PoolObjectSQL::MARKETPLACE; + }; + + ~MarketPlaceUpdateTemplate(){}; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class MarketPlaceAppUpdateTemplate : public RequestManagerUpdateTemplate +{ +public: + MarketPlaceAppUpdateTemplate(): + RequestManagerUpdateTemplate("MarketPlaceUpdateTemplate", + "Updates a marketplace app template") + { + Nebula& nd = Nebula::instance(); + pool = nd.get_apppool(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + }; + + ~MarketPlaceAppUpdateTemplate(){}; +}; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerVMTemplate.h b/include/RequestManagerVMTemplate.h index e495eb45bf..f53f4808bb 100644 --- a/include/RequestManagerVMTemplate.h +++ b/include/RequestManagerVMTemplate.h @@ -66,6 +66,24 @@ public: void request_execute(xmlrpc_c::paramList const& _paramList, RequestAttributes& att); + + /** + * Instantiates the VM Template, checking permissions, quotas, etc + * @param id VM Template ID + * @param name Name for the new VM. Can be empty + * @param on_hold True to start the VM on HOLD state + * @param str_uattrs Template supplied by user to merge with the original + * contents. Can be empty + * @param extra_attrs Template to be merged. It should contain internal + * configuration, and it won't be authenticated or checked for restricted + * attributes. Can be 0 + * @param vmid on success of the new VM + * @param att the specific request attributes + * + * @return ErroCode for the request. + */ + static ErrorCode instantiate(int id, string name, bool on_hold, + string str_uattrs, Template* extra_attrs, int& vid, RequestAttributes& att); }; /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerVirtualMachine.h b/include/RequestManagerVirtualMachine.h index 88bd255120..5c3bbc3872 100644 --- a/include/RequestManagerVirtualMachine.h +++ b/include/RequestManagerVirtualMachine.h @@ -253,8 +253,16 @@ public: ~VirtualMachineAttachNic(){}; - void request_execute(xmlrpc_c::paramList const& _paramList, - RequestAttributes& att); + void request_execute(xmlrpc_c::paramList const& pl, RequestAttributes& ra); + + /** + * Process a NIC attahment request to a Virtual Machine + * @param id of the VirtualMachine + * @param tmpl with the new NIC description + * @param att attributes of this request + * @return ErroCode as defined in Request + */ + static ErrorCode attach(int id, VirtualMachineTemplate& tmpl, RequestAttributes& att); }; /* -------------------------------------------------------------------------- */ @@ -272,6 +280,15 @@ public: void request_execute(xmlrpc_c::paramList const& _paramList, RequestAttributes& att); + + /** + * Process a NIC detach request to a Virtual Machine + * @param id of the VirtualMachine + * @param nic_id id of the NIC + * @param att attributes of this request + * @return ErroCode as defined in Request + */ + static ErrorCode detach(int id, int nic_id, RequestAttributes& att); }; /* -------------------------------------------------------------------------- */ diff --git a/include/RequestManagerVirtualRouter.h b/include/RequestManagerVirtualRouter.h new file mode 100644 index 0000000000..a48f942398 --- /dev/null +++ b/include/RequestManagerVirtualRouter.h @@ -0,0 +1,118 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 REQUEST_MANAGER_VIRTUAL_ROUTER_H +#define REQUEST_MANAGER_VIRTUAL_ROUTER_H + +#include "Request.h" +#include "Nebula.h" + +using namespace std; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class RequestManagerVirtualRouter: public Request +{ +protected: + RequestManagerVirtualRouter(const string& method_name, + const string& help, + const string& params) + :Request(method_name,params,help) + { + Nebula& nd = Nebula::instance(); + pool = nd.get_vrouterpool(); + + auth_object = PoolObjectSQL::VROUTER; + }; + + ~RequestManagerVirtualRouter(){}; + + /* -------------------------------------------------------------------- */ + + virtual void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att) = 0; +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterInstantiate : public RequestManagerVirtualRouter +{ +public: + VirtualRouterInstantiate(): + RequestManagerVirtualRouter("VirtualRouterInstantiate", + "Instantiates a new virtual machine associated to a virtual router", + "A:siiisbs") + { + auth_op = AuthRequest::MANAGE; + }; + + ~VirtualRouterInstantiate(){}; + + void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att); + +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterAttachNic : public RequestManagerVirtualRouter +{ +public: + VirtualRouterAttachNic(): + RequestManagerVirtualRouter("VirtualRouterAttachNic", + "Attaches a new NIC to the virtual router, and its virtual machines", + "A:sis") + { + auth_op = AuthRequest::MANAGE; + }; + + ~VirtualRouterAttachNic(){}; + + void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att); + +}; + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +class VirtualRouterDetachNic : public RequestManagerVirtualRouter +{ +public: + VirtualRouterDetachNic(): + RequestManagerVirtualRouter("VirtualRouterDetachNic", + "Detaches a NIC from a virtual router, and its virtual machines", + "A:sii") + { + auth_op = AuthRequest::MANAGE; + }; + + ~VirtualRouterDetachNic(){}; + + void request_execute(xmlrpc_c::paramList const& _paramList, + RequestAttributes& att); + +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +#endif diff --git a/include/SecurityGroupPool.h b/include/SecurityGroupPool.h index a4e96e34bc..2b6847b631 100644 --- a/include/SecurityGroupPool.h +++ b/include/SecurityGroupPool.h @@ -86,12 +86,6 @@ public: return static_cast(PoolSQL::get(name,uid,lock)); }; - /** Update a particular SecurityGroup - * @param securitygroup pointer to SecurityGroup - * @return 0 on success - */ - int update(SecurityGroup * securitygroup); - /** * Bootstraps the database table(s) associated to the SecurityGroup pool * @return 0 on success diff --git a/include/SqliteDB.h b/include/SqliteDB.h index 2f1244a457..ceb34ea02d 100644 --- a/include/SqliteDB.h +++ b/include/SqliteDB.h @@ -45,7 +45,7 @@ class SqliteDB : public SqlDB { public: - SqliteDB(string& db_name); + SqliteDB(const string& db_name); ~SqliteDB(); diff --git a/include/Template.h b/include/Template.h index 18ef02d38b..ffde7a42cc 100644 --- a/include/Template.h +++ b/include/Template.h @@ -89,6 +89,9 @@ public: */ virtual ~Template(); + /* ---------------------------------------------------------------------- */ + /* Functions to create a Template parsing a file, stream in txt or XML */ + /* ---------------------------------------------------------------------- */ /** * Parse a string representing the template, each attribute is inserted * in the template class. @@ -119,6 +122,30 @@ public: */ int parse_str_or_xml(const string &parse_str, string& error_msg); + /** + * Rebuilds the template from a xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + int from_xml(const string &xml_str); + + /** + * Rebuilds the object from an xml node + * @param node The xml node pointer + * + * @return 0 on success, -1 otherwise + */ + int from_xml_node(const xmlNodePtr node); + + /** + * Writes the Template into a output stream in txt format + */ + friend ostream& operator<<(ostream& os, const Template& t); + + /* ---------------------------------------------------------------------- */ + /* Functions to render a Template in a str, or xml */ + /* ---------------------------------------------------------------------- */ /** * Marshall a template. This function generates a single string with the * template attributes ("VAR=VAL..."). @@ -150,6 +177,9 @@ public: */ string& to_str(string& str) const; + /* ---------------------------------------------------------------------- */ + /* Functions to add, remove and change attributes from a Template */ + /* ---------------------------------------------------------------------- */ /** * Clears all the attributes from the template */ @@ -163,98 +193,43 @@ public: virtual void set(Attribute * attr); /** - * Adds a new attribute to the template (replacing it if - * already defined) + * Adds a new attribute to the template (replacing it if already defined) * @param name of the new attribute * @param value of the new attribute * @return 0 on success */ + template + int replace(const string& name, const T& value) + { + std::ostringstream oss; + + oss << value; + + return replace(name, oss.str()); + } + int replace(const string& name, const string& value); /** - * Adds a new attribute to the template (replacing it if - * already defined) - * @param name of the new attribute - * @param value of the new attribute - * @return 0 on success - */ - int replace(const string& name, int value) - { - ostringstream oss; - - oss << value; - - return replace(name, oss.str()); - } - - /** - * Adds a new attribute to the template (replacing it if - * already defined) - * @param name of the new attribute - * @param value of the new attribute - * @return 0 on success - */ - int replace(const string& name, long long value) - { - ostringstream oss; - - oss << value; - - return replace(name, oss.str()); - } - - /* * Adds a new single attribute to the template. It will replace an existing * one if replace_mode was set to true * @param name of the attribute * @param value of the attribute */ - void add(const string& name, const string& value) - { - set(new SingleAttribute(name, value)); - } - - /** - * Adds a new single attribute to the template. - * @param name of the attribute - * @param value of the attribute - */ - void add(const string& name, int value) - { - ostringstream oss; + template + void add(const string& name, const T& value) + { + std::ostringstream oss; oss << value; set(new SingleAttribute(name, oss.str())); - } + } - /** - * Adds a new single attribute to the template. - * @param name of the attribute - * @param value of the attribute - */ - void add(const string& name, long long value) - { - ostringstream oss; - - oss << value; - - set(new SingleAttribute(name, oss.str())); - } - - /** - * Adds a new single attribute to the template. - * @param name of the attribute - * @param value of the attribute - */ - void add(const string& name, float value) - { - ostringstream oss; - - oss << value; - - set(new SingleAttribute(name, oss.str())); - } + void add(const string& name, const string& value) + { + set(new SingleAttribute(name, value)); + } /** * Removes an attribute from the template. The attributes are returned. The @@ -263,9 +238,27 @@ public: * @param values a vector containing a pointer to the attributes * @return the number of attributes removed */ - virtual int remove( - const string& name, - vector& values); + template + int remove(const string& name, vector& values) + { + pair::iterator, + multimap::iterator> index; + + multimap::iterator i; + + int j; + + index = attributes.equal_range(name); + + for ( i = index.first,j=0 ; i != index.second ; i++,j++ ) + { + values.push_back(static_cast(i->second)); + } + + attributes.erase(index.first, index.second); + + return j; + } /** * Removes an attribute from the template, but it DOES NOT free the @@ -283,94 +276,90 @@ public: */ virtual int erase(const string& name); + /* ---------------------------------------------------------------------- */ + /* Functions get attributes from a template */ + /* ---------------------------------------------------------------------- */ /** - * Gets all the attributes with the given name. + * Gets the all the attributes of the given name and stores a reference + * to them in a vector. If the selected attribute does not match the + * requested type it will not be included * @param name the attribute name. + * @param values vector with the values + * * @return the number of elements in the vector */ - virtual int get( - const string& name, - vector& values) const; - - /** - * Gets all the attributes with the given name, non-const version - * @param name the attribute name. - * @return the number of elements in the vector - */ - virtual int get( - const string& name, - vector& values); - - /** - * Gets the value of a Single attributes (string) with the given name. - * @param name the attribute name. - * @param value the attribute value, a string, "" if the attribute is not - * defined or not Single - */ - virtual void get( - const string& name, - string& value) const; - - /** - * Gets the value of a Single attributes (int) with the given name. - * @param name the attribute name. - * @param value the attribute value, an int, 0 if the attribute is not - * defined or not Single - * - * @return True if the Single attribute was found and is a valid integer - * value - */ - virtual bool get( - const string& name, - int& value) const; - - /** - * Gets the value of a Single attributes (long long) with the given name. - * @param name the attribute name. - * @param value the attribute value, a long long, 0 if the attribute is not - * defined or not Single - * - * @return True if the Single attribute was found and is a valid integer - * value - */ - virtual bool get( - const string& name, - long long& value) const; - - /** - * Gets the value of a Single attributes (float) with the given name. - * @param name the attribute name. - * @param value the attribute value, an int, 0 if the attribute is not - * defined or not Single - * - * @return True if the Single attribute was found and is a valid float - * value - */ - virtual bool get( - const string& name, - float& value) const; - - /** - * Gets the value of a Single attributes (bool) with the given name. - * @param name the attribute name. - * @param value the attribute value, a bool, false if the attribute is not - * defined or not Single - * - * @return True if the Single attribute was found and is a valid bool - * value - */ - virtual bool get( - const string& name, - bool& value) const; - - /** - * Trims the trailing spaces in the NAME attribute - * @return True if the attribute was found and trimmed - */ - virtual bool trim_name() + inline virtual int get(const string& n, vector& v) const { - return trim("NAME"); - }; + return __get(n, v); + } + + inline virtual int get( const string& n, vector& v) + { + return __get(n, v); + } + + inline virtual int get(const string& n, vector& s) const + { + return __get(n, s); + } + + inline virtual int get( const string& n, vector& s) + { + return __get(n, s); + } + + /** + * Gets the first Attribute of the specified type with the given name. + * Const and non-const versions of this method is provided + * @param name the attribute name. + * @return true first attribute or 0 if not found or wrong type + */ + inline const VectorAttribute * get(const string& name) const + { + return __get(name); + } + + inline VectorAttribute * get(const string& name) + { + return __get(name); + } + + /** + * Gets the value of a SingleAttribute with the given name and converts + * it to the target value format + * @param name the attribute name. + * @param value the attribute value + * + * @return true if a SingleAttribute was found and it stores a valid + * value, false otherwise. + */ + template + bool get(const string& name, T& value) const + { + const SingleAttribute * s = __get(name); + + value = 0; + + if ( s == 0 ) + { + return false; + } + + istringstream iss(s->value()); + + iss >> value; + + if (iss.fail() || !iss.eof()) + { + return false; + } + + return true; + } + + virtual bool get(const string& name, bool& value) const; + + virtual bool get(const string& name, string& value) const; /** * Trims the trailing spaces in the attribute @@ -379,23 +368,14 @@ public: */ virtual bool trim(const string& name); - friend ostream& operator<<(ostream& os, const Template& t); - /** - * Rebuilds the template from a xml formatted string - * @param xml_str The xml-formatted string - * - * @return 0 on success, -1 otherwise + * Trims the trailing spaces in the NAME attribute + * @return True if the attribute was found and trimmed */ - int from_xml(const string &xml_str); - - /** - * Rebuilds the object from an xml node - * @param node The xml node pointer - * - * @return 0 on success, -1 otherwise - */ - int from_xml_node(const xmlNodePtr node); + inline virtual bool trim_name() + { + return trim("NAME"); + }; /** * Merges another Template, adding the new attributes and @@ -452,7 +432,7 @@ protected: * @param restricted_attributes The attributes will be stored here */ static void set_restricted_attributes( - vector& rattrs, + vector& rattrs, vector& restricted_attributes); /** @@ -505,6 +485,96 @@ private: * @param root_element The xml element to build the template from. */ void rebuild_attributes(const xmlNode * root_element); + + /** + * Gets the all the attributes of the given name and stores a reference + * to them in a vector. If the selected attribute does not match the + * requested type it will not be included + * @param name the attribute name. + * @param values vector with the values + * + * @return the number of elements in the vector + */ + template + int __get(const string& name, vector& values) const + { + pair::const_iterator, + multimap::const_iterator> index; + + multimap::const_iterator i; + + int j; + + index = attributes.equal_range(name); + + for (i = index.first, j = 0 ; i != index.second ; i++, j++) + { + const T * vatt = dynamic_cast(i->second); + + if ( vatt == 0 ) + { + continue; + } + + values.push_back(vatt); + } + + return j; + } + + /* Non-const version of get for all attributes */ + template + int __get(const string& name, vector& values) + { + pair::iterator, + multimap::iterator> index; + + multimap::iterator i; + + int j; + + index = attributes.equal_range(name); + + for (i = index.first, j = 0 ; i != index.second ; i++, j++) + { + T * vatt = dynamic_cast(i->second); + + if ( vatt == 0 ) + { + continue; + } + + values.push_back(vatt); + } + + return j; + } + + /** + * Gets the first Attribute of the specified type with the given name. + * Const and non-const versions of this method is provided + * @param name the attribute name. + * @return true first attribute or 0 if not found or wrong type + */ + template + const T * __get(const string& s) const + { + vector atts; + + if (__get(s, atts) < 1) + { + return 0; + } + + return atts[0]; + } + + template + T * __get(const string& s) + { + return const_cast( + static_cast(*this).__get(s)); + } }; /* -------------------------------------------------------------------------- */ diff --git a/include/TransferManager.h b/include/TransferManager.h index 530d4bdd9b..6dd76432f1 100644 --- a/include/TransferManager.h +++ b/include/TransferManager.h @@ -32,9 +32,9 @@ class TransferManager : public MadManager, public ActionListener public: TransferManager( - VirtualMachinePool * _vmpool, - HostPool * _hpool, - vector& _mads): + VirtualMachinePool * _vmpool, + HostPool * _hpool, + vector& _mads): MadManager(_mads), vmpool(_vmpool), hpool(_hpool) @@ -123,6 +123,22 @@ public: ostream& xfr, ostringstream& error); + /** + * Inserts a context command in the xfs stream + * + * @param vm The VM + * @param token_password Owner user's token password + * @param system_tm_mad The Transfer Manager for the system datastore + * @param xfr Stream where the transfer command will be written + * + * @return 0 on success + */ + int prolog_context_command( + VirtualMachine * vm, + const string& token_password, + string& system_tm_mad, + ostream& xfr); + /** * Inserts a transfer command in the xfs stream * diff --git a/include/UserPool.h b/include/UserPool.h index b8ed1961c8..44b1797200 100644 --- a/include/UserPool.h +++ b/include/UserPool.h @@ -41,7 +41,7 @@ public: UserPool(SqlDB * db, time_t __session_expiration_time, - vector hook_mads, + vector hook_mads, const string& remotes_location, bool is_federation_slave); @@ -114,7 +114,7 @@ public: * @param user pointer to User * @return 0 on success */ - int update(User * user); + int update(PoolObjectSQL * objsql); /** * Update a particular User's Quotas diff --git a/include/VMTemplate.h b/include/VMTemplate.h index 7a1b611e05..d9bd27f288 100644 --- a/include/VMTemplate.h +++ b/include/VMTemplate.h @@ -70,6 +70,16 @@ public: *(static_cast(obj_template))); }; + // ------------------------------------------------------------------------ + // Virtual Router + // ------------------------------------------------------------------------ + + /** + * Returns true if this Template is a Virtual Router Template + * @return true if this Template is a Virtual Router Template + */ + bool is_vrouter(); + private: // ------------------------------------------------------------------------- // Friends diff --git a/include/VMTemplatePool.h b/include/VMTemplatePool.h index dc8bda90f8..cc43f94a04 100644 --- a/include/VMTemplatePool.h +++ b/include/VMTemplatePool.h @@ -81,18 +81,6 @@ public: return static_cast(PoolSQL::get(name,uid,lock)); }; - /** - * Updates the object's data in the data base. The object mutex SHOULD be - * locked. - * @param objsql a pointer to the object - * - * @return 0 on success. - */ - int update(VMTemplate * vm_template) - { - return vm_template->update(db); - }; - /** * Dumps the pool in XML format. A filter can be also added to the * query diff --git a/include/VdcPool.h b/include/VdcPool.h index 164f54c7d2..b16bbea558 100644 --- a/include/VdcPool.h +++ b/include/VdcPool.h @@ -90,7 +90,7 @@ public: * @param vdc pointer to Vdc * @return 0 on success */ - int update(Vdc * vdc); + int update(PoolObjectSQL * objsql); /** * Drops the Vdc from the data base. The object mutex SHOULD be diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index 0b6fe56480..c02e4192d4 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -463,18 +463,13 @@ public: */ void set_kernel(const string& kernel) { - vector os_attr; - VectorAttribute * os; + VectorAttribute * os = obj_template->get("OS"); - int num = obj_template->get("OS", os_attr); - - if ( num == 0 ) + if ( os == 0 ) { return; } - os = dynamic_cast(os_attr[0]); - os->replace("KERNEL", kernel); }; @@ -485,18 +480,13 @@ public: */ void set_initrd(const string& initrd) { - vector os_attr; - VectorAttribute * os; + VectorAttribute * os = obj_template->get("OS"); - int num = obj_template->get("OS", os_attr); - - if ( num == 0 ) + if ( os == 0 ) { return; } - os = dynamic_cast(os_attr[0]); - os->replace("INITRD", initrd); }; @@ -1225,7 +1215,7 @@ public: * @param pci_dev */ void get_requirements (int& cpu, int& memory, int& disk, - vector& pci_dev); + vector& pci_dev); /** * Checks if the resize parameters are valid @@ -1265,7 +1255,8 @@ public: * * @return 0 on success, -1 otherwise */ - static int release_network_leases(VectorAttribute const * nic, int vmid); + static int release_network_leases( + VectorAttribute const * nic, int vmid); /** * Releases all disk images taken by this Virtual Machine @@ -1317,6 +1308,25 @@ public: */ const VectorAttribute* get_disk(int disk_id) const; + const VectorAttribute* get_nic(int nic_id) const; + + // ------------------------------------------------------------------------ + // Virtual Router related functions + // ------------------------------------------------------------------------ + + /** + * Returns the Virtual Router ID if this VM is a VR, or -1 + * @return VR ID or -1 + */ + int get_vrouter_id(); + + /** + * Returns true if this VM is a Virtual Router + * @return true if this VM is a Virtual Router + */ + bool is_vrouter(); + + // ------------------------------------------------------------------------ // Context related functions // ------------------------------------------------------------------------ @@ -1328,7 +1338,18 @@ public: * @param token_password Password to encrypt the token, if it is set * @return -1 in case of error, 0 if the VM has no context, 1 on success */ - int generate_context(string &files, int &disk_id, string& token_password); + int generate_context(string &files, int &disk_id, const string& token_password); + + const VectorAttribute* get_context() const + { + return obj_template->get("CONTEXT"); + } + + /** + * Returns the CREATED_BY template attribute, or the uid if it does not exist + * @return uid + */ + int get_created_by_uid() const; // ------------------------------------------------------------------------- // "Save as" Disk related functions (save_as hot) @@ -1550,18 +1571,6 @@ public: int uid, string& error_str); - /** - * Cleans the ATTACH = YES attribute from the NICs - */ - void clear_attach_nic(); - - /** - * Deletes the NIC that was in the process of being attached - * - * @return the deleted NIC or 0 if none was deleted - */ - VectorAttribute * delete_attach_nic(); - /** * Adds a new NIC to the virtual machine template. The NIC should be * generated by the build_attach_nic @@ -1570,12 +1579,37 @@ public: */ void set_attach_nic(VectorAttribute * new_nic, vector &rules); + /** + * Cleans the ATTACH = YES attribute from the NICs + */ + void attach_nic_success(); + + /** + * Deletes the NIC that was in the process of being attached + * + * @return the deleted NIC or 0 if none was deleted + */ + VectorAttribute * attach_nic_failure(); + /** * Sets the attach attribute to the given NIC * @param nic_id of the NIC * @return 0 if the nic_id was found, -1 otherwise */ - int set_attach_nic(int nic_id); + int set_detach_nic(int nic_id); + + /** + * Deletes the NIC that was in the process of being detached + * + * @return the deleted NIC or 0 if none was deleted + */ + VectorAttribute * detach_nic_success(); + + /** + * Cleans the ATTACH = YES attribute from the NIC, restores the NIC context + * variables + */ + void detach_nic_failure(); // ------------------------------------------------------------------------ // Snapshot related functions @@ -1694,7 +1728,6 @@ public: */ void delete_snapshots(); - private: // ------------------------------------------------------------------------- @@ -1954,6 +1987,20 @@ private: */ int parse_defaults(string& error_str); + /** + * Parse virtual router related attributes + * @param error_str Returns the error reason, if any + * @return 0 on success + */ + int parse_vrouter(string& error_str); + + /** + * Known Virtual Router attributes, to be moved from the user template + * to the template + */ + static const char* VROUTER_ATTRIBUTES[]; + static const int NUM_VROUTER_ATTRIBUTES; + /** * Known attributes for network contextualization rendered as: * ETH__ = $NETWORK[context[1], vnet_name] @@ -1997,6 +2044,17 @@ private: */ int parse_context(string& error_str); + /** + * Parses the current contents of the context vector attribute, without + * adding any attributes. Substitutes $VARIABLE, $VARIABLE[ATTR] and + * $VARIABLE[ATTR, ATTR = VALUE] + * @param pointer to the context attribute. It will be updated to point + * to the new parsed CONTEXT + * @param error_str description in case of error + * @return 0 on success + */ + int parse_context_variables(VectorAttribute ** context, string& error_str); + /** * Parse the "SCHED_REQUIREMENTS" attribute of the template by substituting * $VARIABLE, $VARIABLE[ATTR] and $VARIABLE[ATTR, ATTR = VALUE] @@ -2099,6 +2157,13 @@ private: static_cast(*this).get_disk(disk_id)); }; + /** + * Returns the NIC that is waiting for an attachment action + * + * @return the NIC waiting for an attachment action, or 0 + */ + VectorAttribute* get_attach_nic(); + // ------------------------------------------------------------------------ // Public cloud templates related functions // ------------------------------------------------------------------------ diff --git a/include/VirtualMachineManager.h b/include/VirtualMachineManager.h index b527265d76..d13e2203fb 100644 --- a/include/VirtualMachineManager.h +++ b/include/VirtualMachineManager.h @@ -38,7 +38,7 @@ public: time_t _poll_period, bool _do_vm_poll, int _vm_limit, - vector& _mads); + vector& _mads); ~VirtualMachineManager(){}; diff --git a/include/VirtualMachineManagerDriver.h b/include/VirtualMachineManagerDriver.h index 50bb69ce99..6a3ef1ef3c 100644 --- a/include/VirtualMachineManagerDriver.h +++ b/include/VirtualMachineManagerDriver.h @@ -22,6 +22,7 @@ #include #include "Mad.h" +#include "ActionSet.h" #include "VirtualMachinePool.h" #include "History.h" @@ -91,7 +92,7 @@ public: */ bool is_imported_action_supported(History::VMAction action) const { - return (imported_vm_actions && (1 << static_cast(action))) != 0; + return imported_actions.is_set(action); } protected: @@ -101,13 +102,10 @@ protected: * @param name of config attribute * @param value of the attribute */ - void get_default( - const char * name, - string& value) const + template + void get_default(const string& name, T& value) const { - string sn = name; - - driver_conf.get(sn,value); + driver_conf.get(name, value); } /** @@ -117,26 +115,25 @@ protected: * @param vname of the attribute * @param value of the attribute */ - void get_default( - const char * name, - const char * vname, - string& value) const; + template + int get_default(const char* name, const char* vname, T& value) const + { + const VectorAttribute * vattr = driver_conf.get(name); - /** - * Gets a configuration attr from driver configuration file (vector - * version) - * @param name of config vector attribute for the domain - * @param vname of the attribute - * @param value of the attribute - * - * @return true if the attribute was found - */ - bool get_default( - const char * name, - const char * vname, - bool& value) const; + if (vattr != 0) + { + return -1; + } + + return vattr->vector_value(vname, value); + } private: + friend class VirtualMachineManager; + + static const string imported_actions_default; + static const string imported_actions_default_public; + /** * Configuration file for the driver */ @@ -146,15 +143,13 @@ private: * List of available actions for imported VMs. Each bit is an action * as defined in History.h, 1=supported and 0=not supported */ - long long imported_vm_actions; + ActionSet imported_actions; /** * Pointer to the Virtual Machine Pool, to access VMs */ VirtualMachinePool * vmpool; - friend class VirtualMachineManager; - /** * Sends a deploy request to the MAD: "DEPLOY ID XML_DRV_MSG" * @param oid the virtual machine id. @@ -287,7 +282,6 @@ private: const string& drv_msg) const { write_drv("POLL", oid, drv_msg); - } /** diff --git a/include/VirtualMachinePool.h b/include/VirtualMachinePool.h index 1551e8054f..f4f2274429 100644 --- a/include/VirtualMachinePool.h +++ b/include/VirtualMachinePool.h @@ -33,10 +33,10 @@ class VirtualMachinePool : public PoolSQL public: VirtualMachinePool(SqlDB * db, - vector hook_mads, + vector hook_mads, const string& hook_location, const string& remotes_location, - vector& restricted_attrs, + vector& restricted_attrs, time_t expire_time, bool on_hold, float default_cpu_cost, @@ -112,14 +112,20 @@ public: * * @return 0 on success. */ - virtual int update( - VirtualMachine * objsql) + virtual int update(PoolObjectSQL * objsql) { + VirtualMachine * vm = dynamic_cast(objsql); + + if ( vm == 0 ) + { + return -1; + } + do_hooks(objsql, Hook::UPDATE); - objsql->set_prev_state(); + vm->set_prev_state(); - return objsql->update(db); + return vm->update(db); }; /** @@ -353,7 +359,20 @@ public: * * @param vid VM id */ - void delete_attach_nic(int vid); + void attach_nic_failure(int vid) + { + delete_hotplug_nic(vid, true); + } + + /** + * Deletes the NIC that was in the process of being detached + * + * @param vid VM id + */ + void detach_nic_success(int vid) + { + delete_hotplug_nic(vid, false); + } /** * Deletes an entry in the HV-2-vmid mapping table for imported VMs @@ -411,6 +430,15 @@ private: * @return 0 on success */ int insert_index(const string& deploy_id, int vm_id, bool replace); + + // ------------------------------------------------------------------------- + + /** + * Helper method for delete attach/detach + * @param vid VM id + * @param attach true for an attach action, false for detach + */ + void delete_hotplug_nic(int vid, bool attach); }; #endif /*VIRTUAL_MACHINE_POOL_H_*/ diff --git a/include/VirtualMachineTemplate.h b/include/VirtualMachineTemplate.h index fa5f3aa72b..9515aafb71 100644 --- a/include/VirtualMachineTemplate.h +++ b/include/VirtualMachineTemplate.h @@ -101,7 +101,7 @@ private: * VirtualMachineTemplate::check * @param rattrs Attributes to restrict */ - static void set_restricted_attributes(vector& rattrs) + static void set_restricted_attributes(vector& rattrs) { Template::set_restricted_attributes(rattrs, restricted_attributes); }; diff --git a/include/VirtualNetwork.h b/include/VirtualNetwork.h index 424c35563a..e9463d8ec3 100644 --- a/include/VirtualNetwork.h +++ b/include/VirtualNetwork.h @@ -22,6 +22,7 @@ #include "VirtualNetworkTemplate.h" #include "Clusterable.h" #include "AddressRangePool.h" +#include "ObjectCollection.h" #include #include @@ -82,7 +83,7 @@ public: * @param error_msg If the action fails, this message contains the reason. * @return 0 on success */ - int add_var(vector &var, string& error_msg); + int add_var(vector &var, string& error_msg); /** * Removes an address range from the VNET @@ -156,64 +157,80 @@ public: /** * Gets a new address lease for a specific VM - * @param vid VM identifier + * @param ot the type of the object requesting the address + * @param oid the id of the object requesting the address * @param nic the VM NIC attribute to be filled with the lease info. * @param inherit attributes from the address range to include in the NIC * @return 0 if success */ - int allocate_addr(int vid, VectorAttribute * nic, - const vector& inherit) + int allocate_addr(PoolObjectSQL::ObjectType ot, int oid, + VectorAttribute * nic, const vector& inherit) { - return ar_pool.allocate_addr(PoolObjectSQL::VM, vid, nic, inherit); + return ar_pool.allocate_addr(ot, oid, nic, inherit); } /** * Gets a new address lease for a specific VM by MAC - * @param vid VM identifier + * @param ot the type of the object requesting the address + * @param oid the id of the object requesting the address * @param mac the MAC address requested * @param nic the VM NIC attribute to be filled with the lease info. * @param inherit attributes from the address range to include in the NIC * @return 0 if success */ - int allocate_by_mac(int vid, const string& mac, VectorAttribute * nic, - const vector& inherit) + int allocate_by_mac(PoolObjectSQL::ObjectType ot, int oid, const string& mac, + VectorAttribute * nic, const vector& inherit) { - return ar_pool.allocate_by_mac(mac, PoolObjectSQL::VM, vid, nic, inherit); + return ar_pool.allocate_by_mac(mac, ot, oid, nic, inherit); } /** * Gets a new address lease for a specific VM by IP - * @param vid VM identifier + * @param ot the type of the object requesting the address + * @param oid the id of the object requesting the address * @param ip the IP address requested * @param nic the VM NIC attribute to be filled with the lease info. * @param inherit attributes from the address range to include in the NIC * @return 0 if success */ - int allocate_by_ip(int vid, const string& ip, VectorAttribute * nic, - const vector& inherit) + int allocate_by_ip(PoolObjectSQL::ObjectType ot, int oid, const string& ip, + VectorAttribute * nic, const vector& inherit) { - return ar_pool.allocate_by_ip(ip, PoolObjectSQL::VM, vid, nic, inherit); + return ar_pool.allocate_by_ip(ip, ot, oid, nic, inherit); } /** * Release previously given address lease * @param arid of the address range where the address was leased from - * @param vid the ID of the VM + * @param ot the type of the object requesting the address + * @param oid the id of the object requesting the address * @param mac MAC address identifying the lease */ - void free_addr(unsigned int arid, int vid, const string& mac) + void free_addr(unsigned int arid, PoolObjectSQL::ObjectType ot, int oid, + const string& mac) { - ar_pool.free_addr(arid, PoolObjectSQL::VM, vid, mac); + ar_pool.free_addr(arid, ot, oid, mac); + + if (ot == PoolObjectSQL::VROUTER) + { + vrouters.del_collection_id(oid); + } } /** * Release previously given address lease - * @param vid the ID of the VM + * @param ot the type of the object requesting the address + * @param oid the id of the object requesting the address * @param mac MAC address identifying the lease */ - void free_addr(int vid, const string& mac) + void free_addr(PoolObjectSQL::ObjectType ot, int oid, const string& mac) { - ar_pool.free_addr(PoolObjectSQL::VM, vid, mac); + ar_pool.free_addr(ot, oid, mac); + + if (ot == PoolObjectSQL::VROUTER) + { + vrouters.del_collection_id(oid); + } } /** @@ -255,6 +272,21 @@ public: int vid, const vector& inherit_attrs); + /** + * Modifies the given nic attribute adding the following attributes: + * * IP: leased from network + * * MAC: leased from network + * @param nic attribute for the VRouter template + * @param vrid of the VRouter getting the lease + * @param inherit_attrs Attributes to be inherited from the vnet template + * into the nic + * @return 0 on success + */ + int vrouter_nic_attribute( + VectorAttribute * nic, + int vrid, + const vector& inherit_attrs); + /** * From a Security Group rule that uses this vnet, creates a new rule * copy for each AR. @@ -377,10 +409,12 @@ public: * A vector containing just -1 means all VMs. * @param vnet_ids list of VNET the user can access reservation info from. * A vector containing just -1 means all VNETs. + * @param vrs list of VRouter the user can access reservation info from. + * A vector containing just -1 means all VRouters. * @return a reference to the generated string */ string& to_xml_extended(string& xml, const vector& vms, - const vector& vnets) const; + const vector& vnets, const vector& vrs) const; /** * Gets a string based attribute (single) from an address range. If the @@ -458,6 +492,11 @@ private: */ AddressRangePool ar_pool; + /** + * Set of Virtual Router IDs + */ + ObjectCollection vrouters; + // ************************************************************************* // DataBase implementation (Private) // ************************************************************************* @@ -490,7 +529,8 @@ private: * @return a reference to the generated string */ string& to_xml_extended(string& xml, bool extended, - const vector& vm_ids, const vector& vnet_oids) const; + const vector& vm_ids, const vector& vnet_oids, + const vector& vr_ids) const; /** * Rebuilds the object from an xml formatted string diff --git a/include/VirtualNetworkPool.h b/include/VirtualNetworkPool.h index e175f41742..f8079a40d3 100644 --- a/include/VirtualNetworkPool.h +++ b/include/VirtualNetworkPool.h @@ -33,13 +33,10 @@ class VirtualNetworkPool : public PoolSQL { public: - VirtualNetworkPool(SqlDB * db, - const string& str_mac_prefix, - int default_size, - vector& restricted_attrs, - vector hook_mads, - const string& remotes_location, - const vector& _inherit_attrs); + VirtualNetworkPool(SqlDB * db, const string& str_mac_prefix, int default_size, + vector& restricted_attrs, + vector& hook_mads, const string& remotes_location, + const vector& _inherit_attrs); ~VirtualNetworkPool(){}; @@ -113,18 +110,23 @@ public: * -2 not using the pool */ int nic_attribute( - VectorAttribute* nic, - int nic_id, - int uid, - int vid, - string& error_str); + PoolObjectSQL::ObjectType ot, + VectorAttribute* nic, + int nic_id, + int uid, + int vid, + string& error_str); /** * Generates an Authorization token for a NIC attribute * @param nic the nic to be authorized * @param ar the AuthRequest */ - void authorize_nic(VectorAttribute * nic, int uid, AuthRequest * ar); + void authorize_nic( + PoolObjectSQL::ObjectType ot, + VectorAttribute * nic, + int uid, + AuthRequest * ar); /** * Bootstraps the database table(s) associated to the VirtualNetwork pool diff --git a/include/VirtualNetworkTemplate.h b/include/VirtualNetworkTemplate.h index ba9d34f798..84d879bc4b 100644 --- a/include/VirtualNetworkTemplate.h +++ b/include/VirtualNetworkTemplate.h @@ -74,7 +74,7 @@ private: * VirtualMachineTemplate::check * @param rattrs Attributes to restrict */ - static void set_restricted_attributes(vector& rattrs) + static void set_restricted_attributes(vector& rattrs) { Template::set_restricted_attributes(rattrs, restricted_attributes); }; diff --git a/include/VirtualRouter.h b/include/VirtualRouter.h new file mode 100644 index 0000000000..377f3465ca --- /dev/null +++ b/include/VirtualRouter.h @@ -0,0 +1,283 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 VIRTUAL_ROUTER_H_ +#define VIRTUAL_ROUTER_H_ + +#include "PoolObjectSQL.h" +#include "Template.h" +#include "ObjectCollection.h" +#include "VirtualMachineTemplate.h" +#include "AuthRequest.h" +#include "History.h" +#include "ActionSet.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +/** + * The VirtualRouter class. + */ +class VirtualRouter : public PoolObjectSQL +{ +public: + + /** + * Function to print the VirtualRouter object into a string in XML format + * @param xml the resulting XML string + * @return a reference to the generated string + */ + string& to_xml(string& xml) const; + + int add_vmid(int vmid); + + bool has_vmids() const; + + /** + * Returns a copy of the VM IDs set + */ + set get_vms() const; + + // ------------------------------------------------------------------------ + // Template Contents + // ------------------------------------------------------------------------ + + /** + * Factory method for VirtualRouter templates + */ + Template * get_new_template() const + { + return new Template; + } + + /** + * Returns a copy of the Template + * @return A copy of the VirtualMachineTemplate + */ + Template * clone_template() const + { + return new Template(obj_template); + }; + + Template * get_vm_template() const; + + /** + * Replace template for this object. Object should be updated + * after calling this method + * @param tmpl_str new contents + * @param keep_restricted If true, the restricted attributes of the + * current template will override the new template + * @param error string describing the error if any + * @return 0 on success + */ + int replace_template(const string& tmpl_str, bool keep_restricted, string& error); + + /** + * Append new attributes to this object's template. Object should be updated + * after calling this method + * @param tmpl_str new contents + * @param keep_restricted If true, the restricted attributes of the + * current template will override the new template + * @param error string describing the error if any + * @return 0 on success + */ + int append_template(const string& tmpl_str, bool keep_restricted, string& error); + + // ------------------------------------------------------------------------ + // Attach and detach NIC + // ------------------------------------------------------------------------ + + /** + * Adds a new NIC to the virtual router template. + * @param tmpl Template, should contain only one NIC + * @param error_str error reason, if any + * + * @return 0 on failure, the NIC to attach to each VM on success + */ + VectorAttribute * attach_nic( + VirtualMachineTemplate * tmpl, string& error_str); + + /** + * Deletes the NIC from the virtual router template. + * + * @param nic_id of the NIC + * @return 0 if the nic_id was found, -1 otherwise + */ + int detach_nic(int nic_id); + + // ------------------------------------------------------------------------ + // Authorization related functions + // ------------------------------------------------------------------------ + + /** + * Sets an authorization request for a Virtual Router template based on + * the networks used + * @param uid for template owner + * @param ar the AuthRequest object + * @param tmpl the virtual router template + */ + static void set_auth_request(int uid, + AuthRequest& ar, + Template *tmpl); + + /** + * Checks if the given action is supported for Virtual Router VMs + * @param action VM action to check + * @return true if the action is supported for Virtual Router VMs + */ + static bool is_action_supported(History::VMAction action) + { + return SUPPORTED_ACTIONS.is_set(action); + } + +private: + // ------------------------------------------------------------------------- + // Friends + // ------------------------------------------------------------------------- + friend class VirtualRouterPool; + + static const ActionSet SUPPORTED_ACTIONS; + + // ************************************************************************* + // Attributes + // ************************************************************************* + ObjectCollection vms; + + // ************************************************************************* + // DataBase implementation (Private) + // ************************************************************************* + + /** + * Execute an INSERT or REPLACE Sql query. + * @param db The SQL DB + * @param replace Execute an INSERT or a REPLACE + * @param error_str Returns the error reason, if any + * @return 0 one success + */ + int insert_replace(SqlDB *db, bool replace, string& error_str); + + /** + * Bootstraps the database table(s) associated to the VirtualRouter + * @return 0 on success + */ + static int bootstrap(SqlDB * db) + { + ostringstream oss(VirtualRouter::db_bootstrap); + + return db->exec(oss); + }; + + /** + * Rebuilds the object from an xml formatted string + * @param xml_str The xml-formatted string + * + * @return 0 on success, -1 otherwise + */ + int from_xml(const string &xml_str); + + // ************************************************************************* + // Constructor + // ************************************************************************* + VirtualRouter( int id, + int uid, + int gid, + const string& uname, + const string& gname, + int umask, + Template * _template_contents); + + ~VirtualRouter(); + + // ************************************************************************* + // DataBase implementation + // ************************************************************************* + + static const char * db_names; + + static const char * db_bootstrap; + + static const char * table; + + /** + * Writes the VirtualRouter in the database. + * @param db pointer to the db + * @param error_str Returns the error reason, if any + * @return 0 on success + */ + int insert(SqlDB *db, string& error_str); + + /** + * Drops object from the database + * @param db pointer to the db + * @return 0 on success + */ + virtual int drop(SqlDB *db); + + /** + * Writes/updates the VirtualRouter data fields in the database. + * @param db pointer to the db + * @return 0 on success + */ + int update(SqlDB *db) + { + string err; + return insert_replace(db, true, err); + }; + + // ------------------------------------------------------------------------- + // NIC Management + // ------------------------------------------------------------------------- + + /** + * Get all network leases for this Virtual Router + * @return 0 onsuccess + */ + int get_network_leases(string& estr); + + /** + * Releases all network leases taken by this Virtual Router + */ + void release_network_leases(); + + /** + * Releases the network lease taken by this NIC + * + * @param nic NIC to be released + * + * @return 0 on success, -1 otherwise + */ + int release_network_leases(const VectorAttribute * nic); + + /** + * Returns the nic with the giver nic_id, or 0 + * @param nic_id + * @return nic if found, 0 if not found + */ + VectorAttribute* get_nic(int nic_id) const; + + // ------------------------------------------------------------------------- + // VM Management + // ------------------------------------------------------------------------- + + /** + * Tries to shutdown, or delete, all this Virtual Router's VMs + * + * @return 0 on success, -1 otherwise + */ + int shutdown_vms(); +}; + +#endif /*VIRTUAL_ROUTER_H_*/ diff --git a/include/VirtualRouterPool.h b/include/VirtualRouterPool.h new file mode 100644 index 0000000000..38f1b1b822 --- /dev/null +++ b/include/VirtualRouterPool.h @@ -0,0 +1,141 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 VIRTUAL_ROUTER_POOL_H_ +#define VIRTUAL_ROUTER_POOL_H_ + +#include "PoolSQL.h" +#include "VirtualRouter.h" + +/** + * The VirtualRouter Pool class. + */ +class VirtualRouterPool : public PoolSQL +{ +public: + + VirtualRouterPool(SqlDB * db, vector hook_mads, + const string& remotes_location) : PoolSQL(db, VirtualRouter::table, true, true) + { + register_hooks(hook_mads, remotes_location); + }; + + ~VirtualRouterPool(){}; + + /** + * Allocates a new object, writing it in the pool database. No memory is + * allocated for the object. + * @param uid user id (the owner of the VirtualRouter) + * @param gid the id of the group this object is assigned to + * @param uname name of the owner user + * @param gname name of the group + * @param umask permissions umask + * @param template_contents a Template object + * @param oid the id assigned to the VirtualRouter + * @param error_str Returns the error reason, if any + * + * @return the oid assigned to the object, -1 in case of failure + */ + int allocate(int uid, + int gid, + const string& uname, + const string& gname, + int umask, + Template * template_contents, + int * oid, + string& error_str) + { + *oid = PoolSQL::allocate( + new VirtualRouter(-1, uid, gid, uname, gname, umask, template_contents), + error_str); + + return *oid; + } + + /** + * Gets an object from the pool (if needed the object is loaded from the + * database). + * @param oid the object unique identifier + * @param lock locks the object if true + * + * @return a pointer to the object, 0 in case of failure + */ + VirtualRouter * get(int oid, bool lock) + { + return static_cast(PoolSQL::get(oid,lock)); + }; + + /** + * Gets an object from the pool (if needed the object is loaded from the + * database). + * @param name of the object + * @param uid id of owner + * @param lock locks the object if true + * + * @return a pointer to the object, 0 in case of failure + */ + VirtualRouter * get(const string& name, int uid, bool lock) + { + return static_cast(PoolSQL::get(name,uid,lock)); + }; + + /** + * Dumps the pool in XML format. A filter can be also added to the + * query + * @param oss the output stream to dump the pool contents + * @param where filter for the objects, defaults to all + * @param limit parameters used for pagination + * + * @return 0 on success + */ + int dump(ostringstream& oss, const string& where, const string& limit) + { + return PoolSQL::dump(oss, "VROUTER_POOL", VirtualRouter::table, where, + limit); + }; + + /** + * Bootstraps the database table(s) associated to the pool + * @return 0 on success + */ + static int bootstrap(SqlDB *_db) + { + return VirtualRouter::bootstrap(_db); + }; + + /** + * Gets the IDs of objects matching the given SQL where string. + * @param oids a vector that contains the IDs + * @param where SQL clause + * @return 0 on success + */ + int search(vector& oids, const string& where) + { + return PoolSQL::search(oids, VirtualRouter::table, where); + }; + +private: + /** + * Factory method to produce objects + * @return a pointer to the new object + */ + PoolObjectSQL * create() + { + return new VirtualRouter(-1,-1,-1,"","",0,0); + }; +}; + +#endif /*VIRTUAL_ROUTER_POOL_H_*/ diff --git a/include/ZonePool.h b/include/ZonePool.h index 825242b3c5..512d6c9121 100644 --- a/include/ZonePool.h +++ b/include/ZonePool.h @@ -91,7 +91,7 @@ public: * @param zone pointer to Zone * @return 0 on success */ - int update(Zone * zone); + int update(PoolObjectSQL * objsql); /** * Drops the Zone from the data base. The object mutex SHOULD be diff --git a/install.sh b/install.sh index caf4bea7a5..c22ca6a34f 100755 --- a/install.sh +++ b/install.sh @@ -227,7 +227,6 @@ LIB_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/ruby/cloud/ \ $LIB_LOCATION/ruby/cloud/econe \ $LIB_LOCATION/ruby/cloud/econe/views \ - $LIB_LOCATION/ruby/cloud/marketplace \ $LIB_LOCATION/ruby/cloud/CloudAuth \ $LIB_LOCATION/ruby/onedb \ $LIB_LOCATION/ruby/onedb/shared \ @@ -295,6 +294,10 @@ VAR_DIRS="$VAR_LOCATION/remotes \ $VAR_LOCATION/remotes/datastore/lvm \ $VAR_LOCATION/remotes/datastore/ceph \ $VAR_LOCATION/remotes/datastore/dev \ + $VAR_LOCATION/remotes/market \ + $VAR_LOCATION/remotes/market/http \ + $VAR_LOCATION/remotes/market/one \ + $VAR_LOCATION/remotes/market/s3 \ $VAR_LOCATION/remotes/datastore/iscsi \ $VAR_LOCATION/remotes/auth \ $VAR_LOCATION/remotes/auth/plain \ @@ -329,10 +332,6 @@ LIB_ECO_CLIENT_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/ruby/cloud/ \ $LIB_LOCATION/ruby/cloud/econe" -LIB_MARKET_CLIENT_DIRS="$LIB_LOCATION/ruby \ - $LIB_LOCATION/ruby/opennebula \ - $LIB_LOCATION/ruby/cloud/marketplace" - LIB_OCA_CLIENT_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/ruby/opennebula" @@ -342,7 +341,7 @@ LIB_CLI_CLIENT_DIRS="$LIB_LOCATION/ruby/cli \ CONF_CLI_DIRS="$ETC_LOCATION/cli" if [ "$CLIENT" = "yes" ]; then - MAKE_DIRS="$MAKE_DIRS $LIB_ECO_CLIENT_DIRS $LIB_MARKET_CLIENT_DIRS \ + MAKE_DIRS="$MAKE_DIRS $LIB_ECO_CLIENT_DIRS \ $LIB_OCA_CLIENT_DIRS $LIB_CLI_CLIENT_DIRS $CONF_CLI_DIRS \ $ETC_LOCATION" elif [ "$ONEGATE" = "yes" ]; then @@ -431,6 +430,9 @@ INSTALL_FILES=( DATASTORE_DRIVER_CEPH_SCRIPTS:$VAR_LOCATION/remotes/datastore/ceph DATASTORE_DRIVER_DEV_SCRIPTS:$VAR_LOCATION/remotes/datastore/dev DATASTORE_DRIVER_ISCSI_SCRIPTS:$VAR_LOCATION/remotes/datastore/iscsi + MARKETPLACE_DRIVER_HTTP_SCRIPTS:$VAR_LOCATION/remotes/market/http + MARKETPLACE_DRIVER_ONE_SCRIPTS:$VAR_LOCATION/remotes/market/one + MARKETPLACE_DRIVER_S3_SCRIPTS:$VAR_LOCATION/remotes/market/s3 NETWORK_FILES:$VAR_LOCATION/remotes/vnm NETWORK_8021Q_FILES:$VAR_LOCATION/remotes/vnm/802.1Q NETWORK_VXLAN_FILES:$VAR_LOCATION/remotes/vnm/vxlan @@ -449,8 +451,6 @@ INSTALL_FILES=( ECO_LIB_FILES:$LIB_LOCATION/ruby/cloud/econe ECO_LIB_VIEW_FILES:$LIB_LOCATION/ruby/cloud/econe/views ECO_BIN_FILES:$BIN_LOCATION - MARKET_LIB_FILES:$LIB_LOCATION/ruby/cloud/marketplace - MARKET_BIN_FILES:$BIN_LOCATION MAN_FILES:$MAN_LOCATION DOCS_FILES:$DOCS_LOCATION CLI_LIB_FILES:$LIB_LOCATION/ruby/cli @@ -467,8 +467,6 @@ INSTALL_CLIENT_FILES=( ECO_LIB_CLIENT_FILES:$LIB_LOCATION/ruby/cloud/econe ECO_BIN_CLIENT_FILES:$BIN_LOCATION COMMON_CLOUD_CLIENT_LIB_FILES:$LIB_LOCATION/ruby/cloud - MARKET_LIB_CLIENT_FILES:$LIB_LOCATION/ruby/cloud/marketplace - MARKET_BIN_CLIENT_FILES:$BIN_LOCATION CLI_BIN_FILES:$BIN_LOCATION CLI_LIB_FILES:$LIB_LOCATION/ruby/cli ONE_CLI_LIB_FILES:$LIB_LOCATION/ruby/cli/one_helper @@ -588,6 +586,9 @@ BIN_FILES="src/nebula/oned \ src/cli/oneflow-template \ src/cli/onesecgroup \ src/cli/onevdc \ + src/cli/onevrouter \ + src/cli/onemarket \ + src/cli/onemarketapp \ src/cli/onevcenter \ src/onedb/onedb \ src/mad/utils/tty_expect \ @@ -664,7 +665,9 @@ MADS_LIB_FILES="src/mad/sh/madcommon.sh \ src/authm_mad/one_auth_mad.rb \ src/authm_mad/one_auth_mad \ src/datastore_mad/one_datastore.rb \ - src/datastore_mad/one_datastore" + src/datastore_mad/one_datastore \ + src/market_mad/one_market.rb \ + src/market_mad/one_market" #------------------------------------------------------------------------------- # VMM SH Driver KVM scripts, to be installed under $REMOTES_LOCATION/vmm/kvm @@ -689,7 +692,9 @@ VMM_EXEC_KVM_SCRIPTS="src/vmm_mad/remotes/kvm/cancel \ src/vmm_mad/remotes/kvm/snapshot_create \ src/vmm_mad/remotes/kvm/snapshot_revert \ src/vmm_mad/remotes/kvm/snapshot_delete \ - src/vmm_mad/remotes/kvm/shutdown" + src/vmm_mad/remotes/kvm/shutdown \ + src/vmm_mad/remotes/kvm/reconfigure \ + src/vmm_mad/remotes/kvm/prereconfigure" #------------------------------------------------------------------------------- # VMM SH Driver Xen scripts, to be installed under $REMOTES_LOCATION/vmm/xen @@ -1155,6 +1160,7 @@ TM_ISCSI_FILES="src/tm_mad/iscsi/clone \ DATASTORE_DRIVER_COMMON_SCRIPTS="src/datastore_mad/remotes/xpath.rb \ src/datastore_mad/remotes/downloader.sh \ + src/datastore_mad/remotes/url.rb \ src/datastore_mad/remotes/libfs.sh" DATASTORE_DRIVER_DUMMY_SCRIPTS="src/datastore_mad/remotes/dummy/cp \ @@ -1165,7 +1171,8 @@ DATASTORE_DRIVER_DUMMY_SCRIPTS="src/datastore_mad/remotes/dummy/cp \ src/datastore_mad/remotes/dummy/snap_delete \ src/datastore_mad/remotes/dummy/snap_revert \ src/datastore_mad/remotes/dummy/snap_flatten \ - src/datastore_mad/remotes/dummy/rm" + src/datastore_mad/remotes/dummy/rm \ + src/datastore_mad/remotes/dummy/export" DATASTORE_DRIVER_FS_SCRIPTS="src/datastore_mad/remotes/fs/cp \ src/datastore_mad/remotes/fs/mkfs \ @@ -1175,7 +1182,8 @@ DATASTORE_DRIVER_FS_SCRIPTS="src/datastore_mad/remotes/fs/cp \ src/datastore_mad/remotes/fs/snap_delete \ src/datastore_mad/remotes/fs/snap_revert \ src/datastore_mad/remotes/fs/snap_flatten \ - src/datastore_mad/remotes/fs/rm" + src/datastore_mad/remotes/fs/rm \ + src/datastore_mad/remotes/fs/export" DATASTORE_DRIVER_VMFS_SCRIPTS="src/datastore_mad/remotes/vmfs/cp \ src/datastore_mad/remotes/vmfs/mkfs \ @@ -1209,7 +1217,8 @@ DATASTORE_DRIVER_CEPH_SCRIPTS="src/datastore_mad/remotes/ceph/cp \ src/datastore_mad/remotes/ceph/snap_revert \ src/datastore_mad/remotes/ceph/snap_flatten \ src/datastore_mad/remotes/ceph/ceph.conf \ - src/datastore_mad/remotes/ceph/ceph_utils.sh" + src/datastore_mad/remotes/ceph/ceph_utils.sh \ + src/datastore_mad/remotes/ceph/export" DATASTORE_DRIVER_DEV_SCRIPTS="src/datastore_mad/remotes/dev/cp \ src/datastore_mad/remotes/dev/mkfs \ @@ -1232,9 +1241,28 @@ DATASTORE_DRIVER_ISCSI_SCRIPTS="src/datastore_mad/remotes/iscsi/cp \ src/datastore_mad/remotes/iscsi/clone" #------------------------------------------------------------------------------- -# Migration scripts for onedb command, to be installed under $LIB_LOCATION +# Marketplace drivers, to be installed under $REMOTES_LOCATION/market +# - HTTP based marketplace, $REMOTES_LOCATION/market/http +# - OpenNebula public marketplace, $REMOTES_LOCATION/market/one +# - S3-obeject based marketplace, $REMOTES_LOCATION/market/s3 #------------------------------------------------------------------------------- +MARKETPLACE_DRIVER_HTTP_SCRIPTS="src/market_mad/remotes/http/import \ + src/market_mad/remotes/http/delete \ + src/market_mad/remotes/http/monitor" + +MARKETPLACE_DRIVER_ONE_SCRIPTS="src/market_mad/remotes/one/import \ + src/market_mad/remotes/one/delete \ + src/market_mad/remotes/one/monitor" + +MARKETPLACE_DRIVER_S3_SCRIPTS="src/market_mad/remotes/s3/import \ + src/market_mad/remotes/s3/delete \ + src/market_mad/remotes/s3/monitor \ + src/market_mad/remotes/s3/S3.rb" + +#------------------------------------------------------------------------------- +# Migration scripts for onedb command, to be installed under $LIB_LOCATION +#------------------------------------------------------------------------------- ONEDB_FILES="src/onedb/fsck.rb \ src/onedb/import_slave.rb \ @@ -1283,7 +1311,8 @@ ONEDB_LOCAL_MIGRATOR_FILES="src/onedb/local/4.5.80_to_4.7.80.rb \ src/onedb/local/4.9.80_to_4.10.3.rb \ src/onedb/local/4.10.3_to_4.11.80.rb \ src/onedb/local/4.11.80_to_4.13.80.rb \ - src/onedb/local/4.13.80_to_4.13.85.rb" + src/onedb/local/4.13.80_to_4.13.85.rb \ + src/onedb/local/4.13.85_to_4.90.0.rb" ONEDB_PATCH_FILES="src/onedb/patches/4.14_monitoring.rb \ src/onedb/patches/history_times.rb" @@ -1406,7 +1435,13 @@ RUBY_OPENNEBULA_LIB_FILES="src/oca/ruby/opennebula/acl_pool.rb \ src/oca/ruby/opennebula/xml_pool.rb \ src/oca/ruby/opennebula/xml_utils.rb \ src/oca/ruby/opennebula/zone_pool.rb \ - src/oca/ruby/opennebula/zone.rb" + src/oca/ruby/opennebula/zone.rb \ + src/oca/ruby/opennebula/virtual_router_pool.rb \ + src/oca/ruby/opennebula/virtual_router.rb \ + src/oca/ruby/opennebula/marketplace_pool.rb \ + src/oca/ruby/opennebula/marketplace.rb \ + src/oca/ruby/opennebula/marketplaceapp_pool.rb \ + src/oca/ruby/opennebula/marketplaceapp.rb" #------------------------------------------------------------------------------- # Common Cloud Files @@ -1521,19 +1556,6 @@ ECO_ETC_FILES="src/cloud/ec2/etc/econe.conf" ECO_ETC_TEMPLATE_FILES="src/cloud/ec2/etc/templates/m1.small.erb" -#------------------------------------------------------------------------------- -# Marketplace Client -#------------------------------------------------------------------------------- - -MARKET_LIB_FILES="src/cloud/marketplace/lib/marketplace_client.rb" - -MARKET_LIB_CLIENT_FILES="src/cloud/marketplace/lib/marketplace_client.rb" - -MARKET_BIN_FILES="src/cloud/marketplace/bin/onemarket" - -MARKET_BIN_CLIENT_FILES="src/cloud/marketplace/bin/onemarket" - - #----------------------------------------------------------------------------- # CLI files #----------------------------------------------------------------------------- @@ -1556,7 +1578,10 @@ ONE_CLI_LIB_FILES="src/cli/one_helper/onegroup_helper.rb \ src/cli/one_helper/onezone_helper.rb \ src/cli/one_helper/onevdc_helper.rb \ src/cli/one_helper/oneacct_helper.rb \ - src/cli/one_helper/onesecgroup_helper.rb" + src/cli/one_helper/onesecgroup_helper.rb \ + src/cli/one_helper/onevrouter_helper.rb \ + src/cli/one_helper/onemarketapp_helper.rb \ + src/cli/one_helper/onemarket_helper.rb" CLI_BIN_FILES="src/cli/onevm \ src/cli/onehost \ @@ -1574,7 +1599,10 @@ CLI_BIN_FILES="src/cli/onevm \ src/cli/oneacct \ src/cli/onesecgroup \ src/cli/oneshowback \ - src/cli/onevdc" + src/cli/onevdc \ + src/cli/onevrouter \ + src/cli/onemarketapp \ + src/cli/onemarket" CLI_CONF_FILES="src/cli/etc/onegroup.yaml \ src/cli/etc/onehost.yaml \ @@ -1590,7 +1618,10 @@ CLI_CONF_FILES="src/cli/etc/onegroup.yaml \ src/cli/etc/oneacct.yaml \ src/cli/etc/onesecgroup.yaml \ src/cli/etc/oneshowback.yaml \ - src/cli/etc/onevdc.yaml" + src/cli/etc/onevdc.yaml \ + src/cli/etc/onevrouter.yaml \ + src/cli/etc/onemarketapp.yaml \ + src/cli/etc/onemarket.yaml" #----------------------------------------------------------------------------- # Sunstone files @@ -1616,7 +1647,6 @@ SUNSTONE_ETC_VIEW_FILES="src/sunstone/etc/sunstone-views/admin.yaml \ SUNSTONE_MODELS_FILES="src/sunstone/models/OpenNebulaJSON.rb \ src/sunstone/models/SunstoneServer.rb \ - src/sunstone/models/SunstoneMarketplace.rb \ src/sunstone/models/SunstoneViews.rb" SUNSTONE_MODELS_JSON_FILES="src/sunstone/models/OpenNebulaJSON/HostJSON.rb \ @@ -1633,7 +1663,10 @@ SUNSTONE_MODELS_JSON_FILES="src/sunstone/models/OpenNebulaJSON/HostJSON.rb \ src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb \ src/sunstone/models/OpenNebulaJSON/ZoneJSON.rb \ src/sunstone/models/OpenNebulaJSON/SecurityGroupJSON.rb \ - src/sunstone/models/OpenNebulaJSON/VdcJSON.rb" + src/sunstone/models/OpenNebulaJSON/VdcJSON.rb \ + src/sunstone/models/OpenNebulaJSON/VirtualRouterJSON.rb \ + src/sunstone/models/OpenNebulaJSON/MarketPlaceJSON.rb \ + src/sunstone/models/OpenNebulaJSON/MarketPlaceAppJSON.rb" SUNSTONE_VIEWS_FILES="src/sunstone/views/index.erb \ src/sunstone/views/login.erb \ @@ -1861,6 +1894,9 @@ MAN_FILES="share/man/oneacct.1.gz \ share/man/oneflow-template.1.gz \ share/man/onesecgroup.1.gz \ share/man/onevdc.1.gz \ + share/man/onevrouter.1.gz \ + share/man/onemarket.1.gz \ + share/man/onemarketapp.1.gz \ share/man/econe-allocate-address.1.gz \ share/man/econe-associate-address.1.gz \ share/man/econe-attach-volume.1.gz \ diff --git a/share/etc/oned.conf b/share/etc/oned.conf index 485af459f5..23729b5b18 100644 --- a/share/etc/oned.conf +++ b/share/etc/oned.conf @@ -650,6 +650,24 @@ DATASTORE_MAD = [ arguments = "-t 15 -d dummy,fs,vmfs,lvm,ceph,dev,iscsi -s shared,ssh,ceph" ] +#******************************************************************************* +# Marketplace Driver Configuration +#******************************************************************************* +# Drivers to manage different marketplaces, specialized for the storage backend +# executable: path of the transfer driver executable, can be an +# absolute path or relative to $ONE_LOCATION/lib/mads (or +# /usr/lib/one/mads/ if OpenNebula was installed in /) +# +# arguments : for the driver executable +# -t number of threads, i.e. number of repo operations at the same time +# -m marketplace mads separated by commas +#******************************************************************************* + +MARKET_MAD = [ + executable = "one_market", + arguments = "-t 15 -m http,s3,one" +] + #******************************************************************************* # Hook Manager Configuration #******************************************************************************* @@ -728,6 +746,7 @@ DATASTORE_MAD = [ # - NO, The hook is executed in the OpenNebula server (default) # # Virtual Network (VNET_HOOK) +# Virtual Router (VROUTER_HOOK) # User (USER_HOOK) # Group (GROUP_HOOK) # Image (IMAGE_HOOK) @@ -1049,3 +1068,36 @@ DS_MAD_CONF = [ DS_MAD_CONF = [ NAME = "vmfs", REQUIRED_ATTRS = "BRIDGE_LIST", PERSISTENT_ONLY = "NO" ] + +#******************************************************************************* +# MarketPlace Driver Behavior Configuration +#******************************************************************************* +# The configuration for each driver is defined in MARKET_MAD_CONF. These +# values are used when creating a new marketplaces and should not be modified +# since they define the marketplace behavior. +# name : name of the market driver +# required_attrs : comma separated list of required attributes in the Market +# template +# app_actions: List of actions allowed for a MarketPlaceApp +# - monitor The apps of the marketplace will be monitored +# - create, the app in the marketplace +# - delete, the app from the marketplace +#******************************************************************************* + +MARKET_MAD_CONF = [ + NAME = "one", + REQUIRED_ATTRS = "", + APP_ACTIONS = "create, monitor" +] + +MARKET_MAD_CONF = [ + NAME = "http", + REQUIRED_ATTRS = "BASE_URL,PUBLIC_DIR", + APP_ACTIONS = "create, delete, monitor" +] + +MARKET_MAD_CONF = [ + NAME = "s3", + REQUIRED_ATTRS = "ACCESS_KEY_ID,SECRET_ACCESS_KEY,REGION,BUCKET", + APP_ACTIONS = "create, delete, monitor" +] diff --git a/share/man/SConstruct b/share/man/SConstruct index c81a2e6558..eaae4e13ad 100644 --- a/share/man/SConstruct +++ b/share/man/SConstruct @@ -64,6 +64,9 @@ env.Man('onezone') env.Man('onevcenter') env.Man('onesecgroup') env.Man('onevdc') +env.Man('onevrouter') +env.Man('onemarket') +env.Man('onemarketapp') env.Man('oneflow') env.Man('oneflow-template') diff --git a/share/man/onemarket.1 b/share/man/onemarket.1 new file mode 100644 index 0000000000..9e8d6d3158 --- /dev/null +++ b/share/man/onemarket.1 @@ -0,0 +1,94 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "ONEMARKET" "1" "December 2015" "" "onemarket(1) -- manages OpenNebula marketplaces" +. +.SH "NAME" +\fBonemarket\fR \- manages OpenNebula marketplaces +. +.SH "SYNOPSIS" +\fBonemarket\fR \fIcommand\fR [\fIargs\fR] [\fIoptions\fR] +. +.SH "OPTIONS" +. +.nf + + \-l, \-\-list x,y,z Selects columns to display with list command + \-d, \-\-delay x Sets the delay in seconds for top command + \-f, \-\-filter x,y,z Filter data\. An array is specified with + column=value pairs\. + \-\-csv Write table in csv format + \-x, \-\-xml Show the resource in xml format + \-n, \-\-numeric Do not translate user and group IDs + \-\-describe Describe list columns + \-a, \-\-append Append new attributes to the current template + \-v, \-\-verbose Verbose mode + \-h, \-\-help Show this message + \-V, \-\-version Show version and copyright information + \-\-user name User name used to connect to OpenNebula + \-\-password password Password to authenticate with OpenNebula + \-\-endpoint endpoint URL of OpenNebula xmlrpc frontend +. +.fi +. +.SH "COMMANDS" +. +.IP "\(bu" 4 +create \fIfile\fR Creates a new Marketplace from the given template file +. +.IP "\(bu" 4 +delete \fIrange|marketplaceid_list\fR Deletes the given Marketplace +. +.IP "\(bu" 4 +chgrp \fIrange|marketplaceid_list\fR \fIgroupid\fR Changes the Marketplace group +. +.IP "\(bu" 4 +chown \fIrange|marketplaceid_list\fR \fIuserid\fR [\fIgroupid\fR] Changes the Marketplace owner and group +. +.IP "\(bu" 4 +chmod \fIrange|marketplaceid_list\fR \fIoctet\fR Changes the Marketplace permissions +. +.IP "\(bu" 4 +list Lists Marketplaces valid options: list, delay, filter, csv, xml, numeric, describe +. +.IP "\(bu" 4 +show \fImarketplaceid\fR Shows Marketplace information valid options: xml +. +.IP "\(bu" 4 +update \fImarketplaceid\fR [\fIfile\fR] Update the template contents\. If a path is not provided the editor will be launched to modify the current content\. valid options: append +. +.IP "\(bu" 4 +rename \fImarketplaceid\fR \fIname\fR Renames the Marketplace +. +.IP "" 0 +. +.SH "ARGUMENT FORMATS" +. +.IP "\(bu" 4 +file Path to a file +. +.IP "\(bu" 4 +range List of id\'s in the form 1,8\.\.15 +. +.IP "\(bu" 4 +text String +. +.IP "\(bu" 4 +marketplaceid OpenNebula MARKETPLACE name or id +. +.IP "\(bu" 4 +marketplaceid_list Comma\-separated list of OpenNebula MARKETPLACE names or ids +. +.IP "\(bu" 4 +groupid OpenNebula GROUP name or id +. +.IP "\(bu" 4 +userid OpenNebula USER name or id +. +.IP "" 0 +. +.SH "LICENSE" +OpenNebula 4\.14\.1 Copyright 2002\-2015, OpenNebula Project, OpenNebula Systems +. +.P +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 diff --git a/share/man/onemarketapp.1 b/share/man/onemarketapp.1 new file mode 100644 index 0000000000..243a5864f8 --- /dev/null +++ b/share/man/onemarketapp.1 @@ -0,0 +1,98 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "ONEMARKETAPP" "1" "December 2015" "" "onemarketapp(1) -- manages OpenNebula marketplace apps" +. +.SH "NAME" +\fBonemarketapp\fR \- manages OpenNebula marketplace apps +. +.SH "SYNOPSIS" +\fBonemarket\fR \fIcommand\fR [\fIargs\fR] [\fIoptions\fR] +. +.SH "OPTIONS" +. +.nf + + \-m, \-\-marketplace id|name Selects the marketplace + \-a, \-\-append Append new attributes to the current template + \-l, \-\-list x,y,z Selects columns to display with list command + \-d, \-\-delay x Sets the delay in seconds for top command + \-f, \-\-filter x,y,z Filter data\. An array is specified with + column=value pairs\. + \-\-csv Write table in csv format + \-x, \-\-xml Show the resource in xml format + \-n, \-\-numeric Do not translate user and group IDs + \-\-describe Describe list columns + \-v, \-\-verbose Verbose mode + \-h, \-\-help Show this message + \-V, \-\-version Show version and copyright information + \-\-user name User name used to connect to OpenNebula + \-\-password password Password to authenticate with OpenNebula + \-\-endpoint endpoint URL of OpenNebula xmlrpc frontend +. +.fi +. +.SH "COMMANDS" +. +.IP "\(bu" 4 +create \fIfile\fR Creates a new marketplace app in the given marketplace valid options: marketplace +. +.IP "\(bu" 4 +delete \fIrange|appid_list\fR Deletes the given marketplace app +. +.IP "\(bu" 4 +update \fIappid\fR [\fIfile\fR] Update the template contents for the app\. If a path is not provided the editor will be launched to modify the current content\. valid options: append +. +.IP "\(bu" 4 +chgrp \fIrange|appid_list\fR \fIgroupid\fR Changes the marketplace app group +. +.IP "\(bu" 4 +chown \fIrange|appid_list\fR \fIuserid\fR [\fIgroupid\fR] Changes the marketplace app owner and group +. +.IP "\(bu" 4 +chmod \fIrange|appid_list\fR \fIoctet\fR Changes the marketplace app permissions +. +.IP "\(bu" 4 +rename \fIappid\fR \fIname\fR Renames the marketplace app +. +.IP "\(bu" 4 +list [\fIfilterflag\fR] Lists marketplace apps valid options: list, delay, filter, csv, xml, numeric, describe +. +.IP "\(bu" 4 +show \fIappid\fR Shows information for the given marketplace app valid options: xml +. +.IP "" 0 +. +.SH "ARGUMENT FORMATS" +. +.IP "\(bu" 4 +file Path to a file +. +.IP "\(bu" 4 +range List of id\'s in the form 1,8\.\.15 +. +.IP "\(bu" 4 +text String +. +.IP "\(bu" 4 +groupid OpenNebula GROUP name or id +. +.IP "\(bu" 4 +userid OpenNebula USER name or id +. +.IP "\(bu" 4 +appid OpenNebula MARKETPLACEAPP name or id +. +.IP "\(bu" 4 +appid_list Comma\-separated list of OpenNebula MARKETPLACEAPP names or ids +. +.IP "\(bu" 4 +filterflag a, all all the known MARKETPLACEAPPs m, mine the MARKETPLACEAPP belonging to the user in ONE_AUTH g, group \'mine\' plus the MARKETPLACEAPP belonging to the groups the user is member of uid MARKETPLACEAPP of the user identified by this uid user MARKETPLACEAPP of the user identified by the username +. +.IP "" 0 +. +.SH "LICENSE" +OpenNebula 4\.14\.1 Copyright 2002\-2015, OpenNebula Project, OpenNebula Systems +. +.P +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 diff --git a/share/man/onevrouter.1 b/share/man/onevrouter.1 new file mode 100644 index 0000000000..a0e64f9351 --- /dev/null +++ b/share/man/onevrouter.1 @@ -0,0 +1,100 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "ONEVROUTER" "1" "January 2016" "" "onevrouter(1) -- manages OpenNebula Virtual Routers" +. +.SH "NAME" +\fBonevrouter\fR \- manages OpenNebula Virtual Routers +. +.SH "SYNOPSIS" +\fBonevrouter\fR \fIcommand\fR [\fIargs\fR] [\fIoptions\fR] +. +.SH "OPTIONS" +. +.nf + + \-a, \-\-append Append new attributes to the current template + \-l, \-\-list x,y,z Selects columns to display with list command + \-d, \-\-delay x Sets the delay in seconds for top command + \-f, \-\-filter x,y,z Filter data\. An array is specified with + column=value pairs\. + \-\-csv Write table in csv format + \-x, \-\-xml Show the resource in xml format + \-n, \-\-numeric Do not translate user and group IDs + \-\-describe Describe list columns + \-v, \-\-verbose Verbose mode + \-h, \-\-help Show this message + \-V, \-\-version Show version and copyright information + \-\-user name User name used to connect to OpenNebula + \-\-password password Password to authenticate with OpenNebula + \-\-endpoint endpoint URL of OpenNebula xmlrpc frontend +. +.fi +. +.SH "COMMANDS" +. +.IP "\(bu" 4 +create \fIfile\fR Creates a new Virtual Router from the given description +. +.IP "\(bu" 4 +delete \fIrange|vrouterid_list\fR Deletes the given Virtual Router +. +.IP "\(bu" 4 +chgrp \fIrange|vrouterid_list\fR \fIgroupid\fR Changes the Virtual Router group +. +.IP "\(bu" 4 +chown \fIrange|vrouterid_list\fR \fIuserid\fR [\fIgroupid\fR] Changes the Virtual Router owner and group +. +.IP "\(bu" 4 +chmod \fIrange|vrouterid_list\fR \fIoctet\fR Changes the Virtual Router permissions +. +.IP "\(bu" 4 +update \fIvrouterid\fR [\fIfile\fR] Update the Virtual Router contents\. If a path is not provided the editor will be launched to modify the current content\. valid options: append +. +.IP "\(bu" 4 +rename \fIvrouterid\fR \fIname\fR Renames the Virtual Router +. +.IP "\(bu" 4 +list [\fIfilterflag\fR] Lists the Virtual Routers in the pool valid options: list, delay, filter, csv, xml, numeric, describe +. +.IP "\(bu" 4 +show \fIsecgroupid\fR Shows information for the given Virtual Router valid options: xml +. +.IP "\(bu" 4 +top [\fIfilterflag\fR] Lists Virtual Routers continuously valid options: list, delay, filter, csv, xml, numeric, describe +. +.IP "" 0 +. +.SH "ARGUMENT FORMATS" +. +.IP "\(bu" 4 +file Path to a file +. +.IP "\(bu" 4 +range List of id\'s in the form 1,8\.\.15 +. +.IP "\(bu" 4 +text String +. +.IP "\(bu" 4 +groupid OpenNebula GROUP name or id +. +.IP "\(bu" 4 +userid OpenNebula USER name or id +. +.IP "\(bu" 4 +vrouterid OpenNebula VROUTER name or id +. +.IP "\(bu" 4 +vrouterid_list Comma\-separated list of OpenNebula VROUTER names or ids +. +.IP "\(bu" 4 +filterflag a, all all the known VROUTERs m, mine the VROUTER belonging to the user in ONE_AUTH g, group \'mine\' plus the VROUTER belonging to the groups the user is member of uid VROUTER of the user identified by this uid user VROUTER of the user identified by the username +. +.IP "" 0 +. +.SH "LICENSE" +OpenNebula 4\.14\.1 Copyright 2002\-2015, OpenNebula Project, OpenNebula Systems +. +.P +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 diff --git a/src/acl/AclManager.cc b/src/acl/AclManager.cc index 2f89a0b5b5..1670f20378 100644 --- a/src/acl/AclManager.cc +++ b/src/acl/AclManager.cc @@ -103,6 +103,15 @@ AclManager::AclManager( AuthRequest::USE, AclRule::ALL_ID, error_str); + + // * MARKETPLACE+MARKETPLACEAPP/* USE * + add_rule(AclRule::ALL_ID, + AclRule::ALL_ID | + PoolObjectSQL::MARKETPLACE | + PoolObjectSQL::MARKETPLACEAPP, + AuthRequest::USE, + AclRule::ALL_ID, + error_str); } } diff --git a/src/acl/AclRule.cc b/src/acl/AclRule.cc index e6e49fa686..67a1b9cae1 100644 --- a/src/acl/AclRule.cc +++ b/src/acl/AclRule.cc @@ -28,7 +28,7 @@ const long long AclRule::CLUSTER_ID = 0x0000000800000000LL; const long long AclRule::NONE_ID = 0x1000000000000000LL; -const int AclRule::num_pool_objects = 13; +const int AclRule::num_pool_objects = 16; const PoolObjectSQL::ObjectType AclRule::pool_objects[] = { PoolObjectSQL::VM, PoolObjectSQL::HOST, @@ -42,7 +42,10 @@ const PoolObjectSQL::ObjectType AclRule::pool_objects[] = { PoolObjectSQL::DOCUMENT, PoolObjectSQL::ZONE, PoolObjectSQL::SECGROUP, - PoolObjectSQL::VDC + PoolObjectSQL::VDC, + PoolObjectSQL::VROUTER, + PoolObjectSQL::MARKETPLACE, + PoolObjectSQL::MARKETPLACEAPP }; const int AclRule::num_auth_operations = 4; @@ -57,7 +60,8 @@ const long long AclRule::INVALID_CLUSTER_OBJECTS = PoolObjectSQL::VM | PoolObjectSQL::IMAGE | PoolObjectSQL::USER | PoolObjectSQL::TEMPLATE | PoolObjectSQL::GROUP | PoolObjectSQL::ACL | PoolObjectSQL::CLUSTER | PoolObjectSQL::DOCUMENT | PoolObjectSQL::ZONE | - PoolObjectSQL::SECGROUP | PoolObjectSQL::VDC; + PoolObjectSQL::SECGROUP | PoolObjectSQL::VDC | PoolObjectSQL::VROUTER | + PoolObjectSQL::MARKETPLACE | PoolObjectSQL::MARKETPLACEAPP; const long long AclRule::INVALID_GROUP_OBJECTS = PoolObjectSQL::HOST | PoolObjectSQL::GROUP | PoolObjectSQL::CLUSTER | @@ -222,7 +226,7 @@ bool AclRule::malformed(string& error_str) const oss << "when using the ALL bit, [resource] ID must be 0"; } - if ( (resource & 0xFFFF000000000LL) == 0 ) + if ( (resource & 0xFFFFFFF000000000LL) == 0 ) { if ( error ) { @@ -233,7 +237,7 @@ bool AclRule::malformed(string& error_str) const oss << "[resource] type is missing"; } - if ( (resource & 0xFFFC000000000000LL) != 0 ) + if ( (resource & 0xFFE0000000000000LL) != 0 ) { if ( error ) { diff --git a/src/cli/etc/oneacl.yaml b/src/cli/etc/oneacl.yaml index 0a1e3a5d35..f08817d68b 100644 --- a/src/cli/etc/oneacl.yaml +++ b/src/cli/etc/oneacl.yaml @@ -9,9 +9,9 @@ :size: 8 :right: true -:RES_VHNIUTGDCOZSv: +:RES_VHNIUTGDCOZSvRMA: :desc: Which resource the rule applies to - :size: 17 + :size: 20 :RID: :desc: Resource ID @@ -31,7 +31,7 @@ :default: - :ID - :USER -- :RES_VHNIUTGDCOZSv +- :RES_VHNIUTGDCOZSvRMA - :RID - :OPE_UMAC - :ZONE diff --git a/src/cli/etc/onemarket.yaml b/src/cli/etc/onemarket.yaml new file mode 100644 index 0000000000..9a651248e0 --- /dev/null +++ b/src/cli/etc/onemarket.yaml @@ -0,0 +1,35 @@ +--- +:ID: + :desc: ONE identifier for the Marketplace + :size: 4 + +:NAME: + :desc: Name of the Marketplace + :size: 20 + :left: true + +:SIZE: + :desc: Marketplace total size (M) + :size: 10 + +:AVAIL: + :desc: MarketPlace free size (%) + :size: 10 + :left: true + +:APPS: + :desc: Number of Marketplace Apps + :size: 6 + +:MAD: + :desc: Marketplace driver + :size: 7 + :left: true + +:default: +- :ID +- :NAME +- :SIZE +- :AVAIL +- :APPS +- :MAD diff --git a/src/cli/etc/onemarketapp.yaml b/src/cli/etc/onemarketapp.yaml new file mode 100644 index 0000000000..1f9346cb1f --- /dev/null +++ b/src/cli/etc/onemarketapp.yaml @@ -0,0 +1,43 @@ +--- +:ID: + :desc: ONE identifier for the MarketPlaceApp + :size: 4 + +:NAME: + :desc: Name of the MarketPlaceApp + :size: 25 + :left: true + +:VERSION: + :desc: Version of the MarketPlaceApp + :size: 10 + +:SIZE: + :desc: MarketPlaceApp size (M) + :size: 5 + +:STAT: + :desc: State of the app + :size: 4 + +:TYPE: + :desc: MarketPlaceApp type + :size: 4 + +:REGTIME: + :desc: Registration time of the MarketplaceApp + :size: 8 + +:MARKET: + :desc: Name of the MarketPlace + :size: 20 + +:default: +- :ID +- :NAME +- :VERSION +- :SIZE +- :STAT +- :TYPE +- :REGTIME +- :MARKET diff --git a/src/cli/etc/onevrouter.yaml b/src/cli/etc/onevrouter.yaml new file mode 100644 index 0000000000..4ccb9028dc --- /dev/null +++ b/src/cli/etc/onevrouter.yaml @@ -0,0 +1,25 @@ +--- +:ID: + :desc: ONE identifier for the Virtual Router + :size: 4 + +:NAME: + :desc: Name of the Virtual Router + :size: 27 + :left: true + +:USER: + :desc: Username of the Virtual Router owner + :size: 15 + :left: true + +:GROUP: + :desc: Group of the Virtual Router + :size: 15 + :left: true + +:default: +- :ID +- :USER +- :GROUP +- :NAME diff --git a/src/cli/one_helper.rb b/src/cli/one_helper.rb index eb24e950a9..a6d0cf8896 100644 --- a/src/cli/one_helper.rb +++ b/src/cli/one_helper.rb @@ -714,16 +714,17 @@ EOT client=OneHelper.client pool = case poolname - when "HOST" then OpenNebula::HostPool.new(client) - when "GROUP" then OpenNebula::GroupPool.new(client) - when "USER" then OpenNebula::UserPool.new(client) - when "DATASTORE" then OpenNebula::DatastorePool.new(client) - when "CLUSTER" then OpenNebula::ClusterPool.new(client) - when "VNET" then OpenNebula::VirtualNetworkPool.new(client) - when "IMAGE" then OpenNebula::ImagePool.new(client) - when "VMTEMPLATE" then OpenNebula::TemplatePool.new(client) - when "VM" then OpenNebula::VirtualMachinePool.new(client) - when "ZONE" then OpenNebula::ZonePool.new(client) + when "HOST" then OpenNebula::HostPool.new(client) + when "GROUP" then OpenNebula::GroupPool.new(client) + when "USER" then OpenNebula::UserPool.new(client) + when "DATASTORE" then OpenNebula::DatastorePool.new(client) + when "CLUSTER" then OpenNebula::ClusterPool.new(client) + when "VNET" then OpenNebula::VirtualNetworkPool.new(client) + when "IMAGE" then OpenNebula::ImagePool.new(client) + when "VMTEMPLATE" then OpenNebula::TemplatePool.new(client) + when "VM" then OpenNebula::VirtualMachinePool.new(client) + when "ZONE" then OpenNebula::ZonePool.new(client) + when "MARKETPLACE" then OpenNebula::MarketPlacePool.new(client) end rc = pool.info @@ -963,7 +964,7 @@ EOT end end - def self.create_template(options) + def self.create_template(options, template_obj=nil) template='' template<<"NAME=\"#{options[:name]}\"\n" if options[:name] @@ -1020,6 +1021,17 @@ EOT context=create_context(options) template< options[:userdata]) + + template << template_obj.template_like_str( + 'TEMPLATE', false, 'EC2') + end + end + [0, template] end diff --git a/src/cli/one_helper/oneacl_helper.rb b/src/cli/one_helper/oneacl_helper.rb index e9b2e1da3a..c552c83628 100644 --- a/src/cli/one_helper/oneacl_helper.rb +++ b/src/cli/one_helper/oneacl_helper.rb @@ -44,7 +44,7 @@ private def self.resource_mask(str) resource_type=str.split("/")[0] - mask = "-------------" + mask = "----------------" resource_type.split("+").each{|type| case type @@ -74,6 +74,12 @@ private mask[11] = "S" when "VDC" mask[12] = "v" + when "VROUTER" + mask[13] = "R" + when "MARKETPLACE" + mask[14] = "M" + when "MARKETPLACEAPP" + mask[15] = "A" end } mask @@ -113,8 +119,8 @@ private d['STRING'].split(" ")[0] end - column :RES_VHNIUTGDCOZSv, "Resource to which the rule applies", - :size => 17 do |d| + column :RES_VHNIUTGDCOZSvRMA, "Resource to which the rule applies", + :size => 20 do |d| OneAclHelper::resource_mask d['STRING'].split(" ")[1] end @@ -131,7 +137,7 @@ private OneAclHelper::right_mask d['STRING'].split(" ")[2] end - default :ID, :USER, :RES_VHNIUTGDCOZSv, :RID, :OPE_UMAC, :ZONE + default :ID, :USER, :RES_VHNIUTGDCOZSvRMA, :RID, :OPE_UMAC, :ZONE end table diff --git a/src/cli/one_helper/onemarket_helper.rb b/src/cli/one_helper/onemarket_helper.rb new file mode 100644 index 0000000000..eac7711929 --- /dev/null +++ b/src/cli/one_helper/onemarket_helper.rb @@ -0,0 +1,138 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'one_helper' + +class OneMarketPlaceHelper < OpenNebulaHelper::OneHelper + MARKETPLACE = { + :name => "marketplace", + :short => "-m id|name", + :large => "--marketplace id|name" , + :description => "Selects the marketplace", + :format => String, + :proc => lambda { |o, options| + OpenNebulaHelper.rname_to_id(o, "MARKETPLACE") + } + } + + def self.rname + "MARKETPLACE" + end + + def self.conf_file + "onemarket.yaml" + end + + def format_pool(options) + config_file = self.class.table_conf + + table = CLIHelper::ShowTable.new(config_file, self) do + column :ID, "ONE identifier for the Marketplace", :size=>4 do |d| + d["ID"] + end + + column :NAME, "Name of the Marketplace", :left, :size=>30 do |d| + d["NAME"] + end + + column :SIZE, "Marketplace total size", :size =>10 do |d| + OpenNebulaHelper.unit_to_str(d['TOTAL_MB'].to_i, {}, 'M') + end + + column :AVAIL, "Marketplace free size", :left, :size =>10 do |d| + if d['TOTAL_MB'].to_i == 0 + "-" + else + "#{((d['FREE_MB'].to_f/d['TOTAL_MB'].to_f) * 100).round()}%" + end + end + + column :APPS, "Number of marketplace apps", :size=>6 do |d| + if d["MARKETPLACEAPPS"]["ID"].nil? + "0" + else + d["MARKETPLACEAPPS"]["ID"].size + end + end + + column :MAD, "Marketplace driver", :left, :size=>7 do |d| + d["MARKET_MAD"] + end + + default :ID, :SIZE, :AVAIL, :APPS, :TYPE, :MAD, :NAME + end + + table + end + + private + + def factory(id=nil) + if id + OpenNebula::MarketPlace.new_with_id(id, @client) + else + xml=OpenNebula::MarketPlace.build_xml + OpenNebula::MarketPlace.new(xml, @client) + end + end + + def factory_pool(user_flag=-2) + OpenNebula::MarketPlacePool.new(@client) + end + + def format_resource(market, options = {}) + str="%-15s: %-20s" + str_h1="%-80s" + + CLIHelper.print_header(str_h1 % "MARKETPLACE #{market['ID']} INFORMATION") + puts str % ["ID", market.id.to_s] + puts str % ["NAME", market.name] + puts str % ["USER", market['UNAME']] + puts str % ["GROUP", market['GNAME']] + + puts str % ["MARKET_MAD", market['MARKET_MAD']] + puts + + CLIHelper.print_header(str_h1 % "MARKETPLACE CAPACITY", false) + + puts str % ["TOTAL:", OpenNebulaHelper.unit_to_str(market['TOTAL_MB'].to_i,{},'M')] + puts str % ["FREE:", OpenNebulaHelper.unit_to_str(market['FREE_MB'].to_i, {},'M')] + puts str % ["USED: ", OpenNebulaHelper.unit_to_str(market['USED_MB'].to_i, {},'M')] + puts + + CLIHelper.print_header(str_h1 % "PERMISSIONS",false) + + ["OWNER", "GROUP", "OTHER"].each { |e| + mask = "---" + mask[0] = "u" if market["PERMISSIONS/#{e}_U"] == "1" + mask[1] = "m" if market["PERMISSIONS/#{e}_M"] == "1" + mask[2] = "a" if market["PERMISSIONS/#{e}_A"] == "1" + + puts str % [e, mask] + } + puts + + CLIHelper.print_header(str_h1 % "MARKETPLACE TEMPLATE", false) + puts market.template_str + + puts + + CLIHelper.print_header("%-15s" % "MARKETAPPS") + market.marketapp_ids.each do |id| + puts "%-15s" % [id] + end + end +end diff --git a/src/cli/one_helper/onemarketapp_helper.rb b/src/cli/one_helper/onemarketapp_helper.rb new file mode 100644 index 0000000000..b971e3c1b5 --- /dev/null +++ b/src/cli/one_helper/onemarketapp_helper.rb @@ -0,0 +1,144 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'one_helper' + +class OneMarketPlaceAppHelper < OpenNebulaHelper::OneHelper + def self.rname + "MARKETPLACEAPP" + end + + def self.conf_file + "onemarketapp.yaml" + end + + def self.state_to_str(id) + id = id.to_i + state_str = MarketPlaceApp::MARKETPLACEAPP_STATES[id] + return MarketPlaceApp::SHORT_MARKETPLACEAPP_STATES[state_str] + end + + def format_pool(options) + config_file = self.class.table_conf + + table = CLIHelper::ShowTable.new(config_file, self) do + column :ID, "ONE identifier for the marketplace app", :size=>4 do |d| + d["ID"] + end + + column :NAME, "Name of the marketplace app", :left, :size=>15 do |d| + d["NAME"] + end + + column :VERSION, "Version of the app", :size=>7 do |d| + d["VERSION"] + end + + column :SIZE, "App size", :size =>5 do |d| + OpenNebulaHelper.unit_to_str(d['SIZE'].to_i, {}, 'M') + end + + column :STAT, "State of the app", :size=>4 do |d| + OneMarketPlaceAppHelper.state_to_str(d["STATE"]) + end + + column :REGTIME, "Registration time of the app", :size=>8 do |d| + Time.at(d['REGTIME'].to_i).strftime("%D") + end + + column :TYPE, "Marketplace app type", :size=>4 do |d| + type = MarketPlaceApp::MARKETPLACEAPP_TYPES[d["TYPE"].to_i] + MarketPlaceApp::SHORT_MARKETPLACEAPP_TYPES[type] + end + + column :MARKET, "Name of the MarketPlace", :size=>6 do |d| + d["MARKETPLACE"] + end + + default :ID,:NAME,:VERSION,:SIZE,:STAT,:TYPE,:REGTIME,:MARKET + end + + table + end + + private + + def factory(id=nil) + if id + OpenNebula::MarketPlaceApp.new_with_id(id, @client) + else + xml=OpenNebula::MarketPlaceApp.build_xml + OpenNebula::MarketPlaceApp.new(xml, @client) + end + end + + def factory_pool(user_flag=-2) + OpenNebula::MarketPlaceAppPool.new(@client, user_flag) + end + + def format_resource(app, options = {}) + str="%-15s: %-20s" + str_h1="%-80s" + + CLIHelper.print_header(str_h1 % "MARKETPLACE APP #{app['ID']} INFORMATION") + puts str % ["ID", app.id.to_s] + puts str % ["NAME", app.name] + puts str % ["TYPE", app.type_str] + puts str % ["USER", app['UNAME']] + puts str % ["GROUP", app['GNAME']] + puts str % ["MARKETPLACE", app['MARKETPLACE']] + puts str % ["STATE", OneMarketPlaceAppHelper.state_to_str(app["STATE"])] + + puts + + CLIHelper.print_header(str_h1 % "PERMISSIONS",false) + + ["OWNER", "GROUP", "OTHER"].each { |e| + mask = "---" + mask[0] = "u" if app["PERMISSIONS/#{e}_U"] == "1" + mask[1] = "m" if app["PERMISSIONS/#{e}_M"] == "1" + mask[2] = "a" if app["PERMISSIONS/#{e}_A"] == "1" + + puts str % [e, mask] + } + puts + + CLIHelper.print_header(str_h1 % "DETAILS", false) + + puts str % ["SOURCE", app['SOURCE']] + puts str % ["MD5", app['MD5']] + puts str % ["PUBLISHER", app['PUBLISHER']] + puts str % ["REGISTER TIME", Time.at(app['REGTIME'].to_i).strftime("%c") ] + puts str % ["VERSION", app['VERSION']] + puts str % ["DESCRIPTION", app['DESCRIPTION']] + puts str % ["SIZE", OpenNebulaHelper.unit_to_str(app['SIZE'].to_i,{},'M')] + puts str % ["ORIGIN_ID", app['ORIGIN_ID']] + puts str % ["FORMAT", app['FORMAT']] + + puts + + CLIHelper.print_header(str_h1 % "IMPORT TEMPLATE", false) + + puts Base64.decode64(app['APPTEMPLATE64']) + + puts + + CLIHelper.print_header(str_h1 % "MARKETPLACE APP TEMPLATE", false) + puts app.template_str + + puts + end +end diff --git a/src/cli/one_helper/onetemplate_helper.rb b/src/cli/one_helper/onetemplate_helper.rb index 80e3672aa2..30f0b385d6 100644 --- a/src/cli/one_helper/onetemplate_helper.rb +++ b/src/cli/one_helper/onetemplate_helper.rb @@ -111,7 +111,7 @@ EOT table end - def get_user_inputs(template) + def self.get_user_inputs(template) user_inputs = template['VMTEMPLATE']['TEMPLATE']['USER_INPUTS'] return "" if !user_inputs diff --git a/src/cli/one_helper/onevm_helper.rb b/src/cli/one_helper/onevm_helper.rb index 6e4de11eb5..8d062efb5f 100644 --- a/src/cli/one_helper/onevm_helper.rb +++ b/src/cli/one_helper/onevm_helper.rb @@ -84,6 +84,14 @@ class OneVMHelper < OpenNebulaHelper::OneHelper } } + IP={ + :name => "ip", + :short => "-i ip", + :large => "--ip ip", + :format => String, + :description => "IP address for the new NIC" + } + FILE = { :name => "file", :short => "-f file", @@ -170,16 +178,11 @@ class OneVMHelper < OpenNebulaHelper::OneHelper end vm_nics.each do |nic| - if nic.has_key?("IP") - ips.push(nic["IP"]) - end - - if nic.has_key?("IP6_GLOBAL") - ips.push(nic["IP6_GLOBAL"]) - end - - if nic.has_key?("IP6_ULA") - ips.push(nic["IP6_ULA"]) + ["IP", "IP6_GLOBAL", "IP6_ULA", + "VROUTER_IP", "VROUTER_IP6_GLOBAL", "VROUTER_IP6_ULA"].each do |attr| + if nic.has_key?(attr) + ips.push(nic[attr]) + end end end @@ -517,6 +520,8 @@ in the frontend machine. OpenNebulaHelper.time_to_str(vm['/VM/ETIME'])] value=vm['DEPLOY_ID'] puts str % ["DEPLOY ID", value=="" ? "-" : value] + value=vm['TEMPLATE/VROUTER_ID'] + puts str % ["VIRTUAL ROUTER ID", value] if value puts @@ -735,37 +740,31 @@ in the frontend machine. next if nic.has_key?("CLI_DONE") - if nic.has_key?("IP6_LINK") - shown_ips << nic["IP6_LINK"] + ["IP6_LINK", "IP6_ULA", "IP6_GLOBAL"].each do |attr| + if nic.has_key?(attr) + shown_ips << nic[attr] - ip6_link = {"IP" => nic.delete("IP6_LINK"), - "CLI_DONE" => true, - "DOUBLE_ENTRY" => true} - vm_nics.insert(array_id+1,ip6_link) + ipstr = {"IP" => nic.delete(attr), + "CLI_DONE" => true, + "DOUBLE_ENTRY" => true} + vm_nics.insert(array_id+1,ipstr) - array_id += 1 + array_id += 1 + end end - if nic.has_key?("IP6_ULA") - shown_ips << nic["IP6_ULA"] + ["VROUTER_IP", "VROUTER_IP6_LINK", + "VROUTER_IP6_ULA", "VROUTER_IP6_GLOBAL"].each do |attr| + if nic.has_key?(attr) + shown_ips << nic[attr] - ip6_link = {"IP" => nic.delete("IP6_ULA"), - "CLI_DONE" => true, - "DOUBLE_ENTRY" => true} - vm_nics.insert(array_id+1,ip6_link) + ipstr = {"IP" => nic.delete(attr) + " (VRouter)", + "CLI_DONE" => true, + "DOUBLE_ENTRY" => true} + vm_nics.insert(array_id+1,ipstr) - array_id += 1 - end - - if nic.has_key?("IP6_GLOBAL") - shown_ips << nic["IP6_GLOBAL"] - - ip6_link = {"IP" => nic.delete("IP6_GLOBAL"), - "CLI_DONE" => true, - "DOUBLE_ENTRY" => true} - vm_nics.insert(array_id+1,ip6_link) - - array_id += 1 + array_id += 1 + end end shown_ips << nic["IP"] if nic.has_key?("IP") diff --git a/src/cli/one_helper/onevnet_helper.rb b/src/cli/one_helper/onevnet_helper.rb index e422527517..8510c2d5ec 100644 --- a/src/cli/one_helper/onevnet_helper.rb +++ b/src/cli/one_helper/onevnet_helper.rb @@ -308,6 +308,8 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper "V:#{d['VM']}" elsif d['VNET'] "N:#{d['VNET']}" + elsif d['VROUTER'] + "R:#{d['VROUTER']}" end end @@ -324,6 +326,13 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper end end.show(leases, {}) + puts + + CLIHelper.print_header("%-15s" % "VIRTUAL ROUTERS") + vn.vrouter_ids.each do |id| + puts "%-15s" % [id] + end + if options[:show_ar] ar_list.each do |ar_id| puts diff --git a/src/cli/one_helper/onevrouter_helper.rb b/src/cli/one_helper/onevrouter_helper.rb new file mode 100644 index 0000000000..b0ed03a548 --- /dev/null +++ b/src/cli/one_helper/onevrouter_helper.rb @@ -0,0 +1,225 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'one_helper' + +class OneVirtualRouterHelper < OpenNebulaHelper::OneHelper + + ALL_TEMPLATE = { + :name => "all", + :large => "--all", + :description => "Show all template data" + } + + def self.rname + "VROUTER" + end + + def self.conf_file + "onevrouter.yaml" + end + + def show_resource(id, options) + resource = retrieve_resource(id) + + if !options[:extended].nil? + rc = resource.info(options[:extended]) + else + rc = resource.info + end + + return -1, rc.message if OpenNebula.is_error?(rc) + + if options[:xml] + return 0, resource.to_xml(true) + else + format_resource(resource, options) + return 0 + end + end + + def format_pool(options) + config_file = self.class.table_conf + + table = CLIHelper::ShowTable.new(config_file, self) do + column :ID, "ONE identifier for the Virtual Router", :size=>4 do |d| + d["ID"] + end + + column :NAME, "Name of the Virtual Router", :left, :size=>27 do |d| + d["NAME"] + end + + column :USER, "Username of the Virtual Router owner", :left, + :size=>15 do |d| + helper.user_name(d, options) + end + + column :GROUP, "Group of the Virtual Router", :left, :size=>15 do |d| + helper.group_name(d, options) + end + + default :ID, :USER, :GROUP, :NAME + end + + table + end + + private + + def factory(id=nil) + if id + OpenNebula::VirtualRouter.new_with_id(id, @client) + else + xml=OpenNebula::VirtualRouter.build_xml + OpenNebula::VirtualRouter.new(xml, @client) + end + end + + def factory_pool(user_flag=-2) + OpenNebula::VirtualRouterPool.new(@client, user_flag) + end + + def format_resource(obj, options = {}) + str="%-15s: %-20s" + str_h1="%-80s" + + CLIHelper.print_header( + str_h1 % "VIRTUAL ROUTER #{obj['ID']} INFORMATION") + puts str % ["ID", obj.id.to_s] + puts str % ["NAME", obj.name] + puts str % ["USER", obj['UNAME']] + puts str % ["GROUP", obj['GNAME']] + puts + + CLIHelper.print_header(str_h1 % "PERMISSIONS",false) + + ["OWNER", "GROUP", "OTHER"].each { |e| + mask = "---" + mask[0] = "u" if obj["PERMISSIONS/#{e}_U"] == "1" + mask[1] = "m" if obj["PERMISSIONS/#{e}_M"] == "1" + mask[2] = "a" if obj["PERMISSIONS/#{e}_A"] == "1" + + puts str % [e, mask] + } + + if obj.has_elements?("/VROUTER/TEMPLATE/NIC") + puts + CLIHelper.print_header(str_h1 % "VIRTUAL ROUTER NICS",false) + + nic_default = {"NETWORK" => "-", + "IP" => "-"} + + shown_ips = [] + + array_id = 0 + vm_nics = [obj.to_hash['VROUTER']['TEMPLATE']['NIC']].flatten.compact + vm_nics.each {|nic| + + next if nic.has_key?("CLI_DONE") + + if nic.has_key?("IP6_LINK") + shown_ips << nic["IP6_LINK"] + + ip6_link = {"IP" => nic.delete("IP6_LINK"), + "CLI_DONE" => true, + "DOUBLE_ENTRY" => true} + vm_nics.insert(array_id+1,ip6_link) + + array_id += 1 + end + + if nic.has_key?("IP6_ULA") + shown_ips << nic["IP6_ULA"] + + ip6_link = {"IP" => nic.delete("IP6_ULA"), + "CLI_DONE" => true, + "DOUBLE_ENTRY" => true} + vm_nics.insert(array_id+1,ip6_link) + + array_id += 1 + end + + if nic.has_key?("IP6_GLOBAL") + shown_ips << nic["IP6_GLOBAL"] + + ip6_link = {"IP" => nic.delete("IP6_GLOBAL"), + "CLI_DONE" => true, + "DOUBLE_ENTRY" => true} + vm_nics.insert(array_id+1,ip6_link) + + array_id += 1 + end + + shown_ips << nic["IP"] if nic.has_key?("IP") + + nic.merge!(nic_default) {|k,v1,v2| v1} + array_id += 1 + } + + CLIHelper::ShowTable.new(nil, self) do + column :ID, "", :size=>3 do |d| + if d["DOUBLE_ENTRY"] + "" + else + d["NIC_ID"] + end + end + + column :NETWORK, "", :left, :size=>20 do |d| + if d["DOUBLE_ENTRY"] + "" + else + d["NETWORK"] + end + end + + column :MANAGEMENT, "", :left, :size=>10 do |d| + if d["DOUBLE_ENTRY"] + "" + else + if !d["VROUTER_MANAGEMENT"].nil? + d["VROUTER_MANAGEMENT"] + else + "NO" + end + end + end + + + column :IP, "",:left, :donottruncate, :size=>15 do |d| + d["IP"] + end + end.show(vm_nics,{}) + end + + while obj.has_elements?("/VROUTER/TEMPLATE/NIC") + obj.delete_element("/VROUTER/TEMPLATE/NIC") + end if !options[:all] + + puts + + CLIHelper.print_header(str_h1 % "TEMPLATE CONTENTS",false) + puts obj.template_str + + puts + + CLIHelper.print_header("%-15s" % "VIRTUAL MACHINES") + obj.vm_ids.each do |id| + puts "%-15s" % [id] + end + end +end diff --git a/src/cli/onemarket b/src/cli/onemarket new file mode 100755 index 0000000000..2bd506e3e4 --- /dev/null +++ b/src/cli/onemarket @@ -0,0 +1,178 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +ONE_LOCATION=ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" +end + +$: << RUBY_LIB_LOCATION +$: << RUBY_LIB_LOCATION+"/cli" + +require 'command_parser' +require 'one_helper/onemarket_helper' + +cmd=CommandParser::CmdParser.new(ARGV) do + usage "`onemarket` [] []" + version OpenNebulaHelper::ONE_VERSION + + helper = OneMarketPlaceHelper.new + + before_proc do + helper.set_client(options) + end + + ######################################################################## + # Global Options + ######################################################################## + set :option, CommandParser::OPTIONS+OpenNebulaHelper::CLIENT_OPTIONS + + list_options = CLIHelper::OPTIONS + list_options << OpenNebulaHelper::XML + list_options << OpenNebulaHelper::NUMERIC + list_options << OpenNebulaHelper::DESCRIBE + + ######################################################################## + # Formatters for arguments + ######################################################################## + set :format, :marketplaceid, OneMarketPlaceHelper.to_id_desc do |arg| + helper.to_id(arg) + end + + set :format, :marketplaceid_list, OneMarketPlaceHelper.list_to_id_desc do |arg| + helper.list_to_id(arg) + end + + set :format, :groupid, OpenNebulaHelper.rname_to_id_desc("GROUP") do |arg| + OpenNebulaHelper.rname_to_id(arg, "GROUP") + end + + set :format, :userid, OpenNebulaHelper.rname_to_id_desc("USER") do |arg| + OpenNebulaHelper.rname_to_id(arg, "USER") + end + + ######################################################################## + # Commands + ######################################################################## + + create_desc = <<-EOT.unindent + Creates a new Marketplace from the given template file + EOT + + command :create, create_desc, :file do + + helper.create_resource(options) do |marketplace| + begin + template = File.read(args[0]) + marketplace.allocate(template) + rescue =>e + STDERR.puts e.message + exit -1 + end + end + end + + delete_desc = <<-EOT.unindent + Deletes the given Marketplace + EOT + + command :delete, delete_desc, [:range, :marketplaceid_list] do + helper.perform_actions(args[0],options,"deleted") do |obj| + obj.delete + end + end + + chgrp_desc = <<-EOT.unindent + Changes the Marketplace group + EOT + + command :chgrp, chgrp_desc,[:range, :marketplaceid_list], :groupid do + helper.perform_actions(args[0],options,"Group changed") do |obj| + obj.chown(-1, args[1].to_i) + end + end + + chown_desc = <<-EOT.unindent + Changes the Marketplace owner and group + EOT + + command :chown, chown_desc, [:range, :marketplaceid_list], :userid, + [:groupid,nil] do + gid = args[2].nil? ? -1 : args[2].to_i + helper.perform_actions(args[0],options,"Owner/Group changed") do |obj| + obj.chown(args[1].to_i, gid) + end + end + + chmod_desc = <<-EOT.unindent + Changes the Marketplace permissions + EOT + + command :chmod, chmod_desc, [:range, :marketplaceid_list], :octet do + helper.perform_actions(args[0],options, "Permissions changed") do |obj| + obj.chmod_octet(args[1]) + end + end + + list_desc = <<-EOT.unindent + Lists Marketplaces + EOT + + command :list, list_desc, :options=>list_options do + helper.list_pool(options) + end + + show_desc = <<-EOT.unindent + Shows Marketplace information + EOT + + command :show, show_desc, :marketplaceid, :options=>OpenNebulaHelper::XML do + helper.show_resource(args[0],options) + end + + update_desc = <<-EOT.unindent + Update the template contents. If a path is not provided the editor will + be launched to modify the current content. + EOT + + command :update, update_desc, :marketplaceid, [:file, nil], + :options=>OpenNebulaHelper::APPEND do + helper.perform_action(args[0],options,"modified") do |obj| + if options[:append] + str = OpenNebulaHelper.append_template(args[0], obj, args[1]) + else + str = OpenNebulaHelper.update_template(args[0], obj, args[1]) + end + + obj.update(str, options[:append]) + end + end + + rename_desc = <<-EOT.unindent + Renames the Marketplace + EOT + + command :rename, rename_desc, :marketplaceid, :name do + helper.perform_action(args[0],options,"renamed") do |o| + o.rename(args[1]) + end + end +end diff --git a/src/cli/onemarketapp b/src/cli/onemarketapp new file mode 100755 index 0000000000..d803e3417e --- /dev/null +++ b/src/cli/onemarketapp @@ -0,0 +1,236 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +ONE_LOCATION=ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" +end + +$: << RUBY_LIB_LOCATION +$: << RUBY_LIB_LOCATION+"/cli" + +require 'command_parser' +require 'one_helper/onemarketapp_helper' +require 'one_helper/onemarket_helper' +require 'one_helper/onedatastore_helper' + +CommandParser::CmdParser.new(ARGV) do + usage "`onemarket` [] []" + version OpenNebulaHelper::ONE_VERSION + + helper = OneMarketPlaceAppHelper.new + + before_proc do + helper.set_client(options) + end + + ######################################################################## + # Global Options + ######################################################################## + set :option, CommandParser::OPTIONS+OpenNebulaHelper::CLIENT_OPTIONS + + list_options = CLIHelper::OPTIONS + list_options << OpenNebulaHelper::XML + list_options << OpenNebulaHelper::NUMERIC + list_options << OpenNebulaHelper::DESCRIBE + + CREATE_OPTIONS = [OneMarketPlaceHelper::MARKETPLACE] + EXPORT_OPTIONS = [OneDatastoreHelper::DATASTORE] + + ######################################################################## + # Formatters for arguments + ######################################################################## + set :format, :groupid, OpenNebulaHelper.rname_to_id_desc("GROUP") do |arg| + OpenNebulaHelper.rname_to_id(arg, "GROUP") + end + + set :format, :userid, OpenNebulaHelper.rname_to_id_desc("USER") do |arg| + OpenNebulaHelper.rname_to_id(arg, "USER") + end + + set :format, :appid, OneMarketPlaceAppHelper.to_id_desc do |arg| + helper.to_id(arg) + end + + set :format, :appid_list, OneMarketPlaceAppHelper.list_to_id_desc do |arg| + helper.list_to_id(arg) + end + + set :format, :filterflag, OneMarketPlaceAppHelper.filterflag_to_i_desc do |arg| + helper.filterflag_to_i(arg) + end + + ######################################################################## + # Commands + ######################################################################## + + create_desc = <<-EOT.unindent + Creates a new marketplace app in the given marketplace + EOT + + command :create, create_desc, :file, :options=>CREATE_OPTIONS do + + if options[:marketplace].nil? + STDERR.puts "Marketplace to save the app is mandatory: " + STDERR.puts "\t -m marketplace_id" + exit(-1) + end + + helper.create_resource(options) do |app| + begin + template=File.read(args[0]) + app.allocate(template, options[:marketplace]) + rescue => e + STDERR.puts e.messsage + exit(-1) + end + end + end + + export_desc = <<-EOT.unindent + Exports the marketplace app to the OpenNebula cloud + EOT + + command :export, export_desc, :appid, :name, :options=>EXPORT_OPTIONS do + helper.perform_action(args[0], options, "exported") do |obj| + + rc = obj.export(:dsid=>options[:datastore], :name=>args[1]) + + next rc if OpenNebula.is_error?(rc) + + rc.each { |key, value| + puts "#{key.to_s.upcase}" + value.each{ |id| + puts " ID: #{id}" + } + } + end + end + + delete_desc = <<-EOT.unindent + Deletes the given marketplace app + EOT + + command :delete, delete_desc, [:range, :appid_list] do + helper.perform_actions(args[0], options, "deleted") do |app| + app.delete + end + end + + update_desc = <<-EOT.unindent + Update the template contents for the app. If a path is not provided the + editor will be launched to modify the current content. + EOT + + command :update, update_desc, :appid, [:file, nil], + :options=>OpenNebulaHelper::APPEND do + + helper.perform_action(args[0],options,"modified") do |obj| + if options[:append] + str = OpenNebulaHelper.append_template(args[0], obj, args[1]) + else + str = OpenNebulaHelper.update_template(args[0], obj, args[1]) + end + + obj.update(str, options[:append]) + end + end + + chgrp_desc = <<-EOT.unindent + Changes the marketplace app group + EOT + + command :chgrp, chgrp_desc,[:range, :appid_list], :groupid do + helper.perform_actions(args[0], options, "Group changed") do |app| + app.chown(-1, args[1].to_i) + end + end + + chown_desc = <<-EOT.unindent + Changes the marketplace app owner and group + EOT + + command :chown, chown_desc, [:range, :appid_list], :userid, + [:groupid, nil] do + gid = args[2].nil? ? -1 : args[2].to_i + + helper.perform_actions(args[0], options, "Owner/Group changed") do |app| + app.chown(args[1].to_i, gid) + end + end + + chmod_desc = <<-EOT.unindent + Changes the marketplace app permissions + EOT + + command :chmod, chmod_desc, [:range, :appid_list], :octet do + helper.perform_actions(args[0], options, "Permissions changed") do |app| + app.chmod_octet(args[1]) + end + end + + rename_desc = <<-EOT.unindent + Renames the marketplace app + EOT + + command :rename, rename_desc, :appid, :name do + helper.perform_action(args[0], options, "renamed") do |o| + o.rename(args[1]) + end + end + + list_desc = <<-EOT.unindent + Lists marketplace apps + EOT + + command :list, list_desc, [:filterflag, nil], :options=>list_options do + helper.list_pool(options, false, args[0]) + end + + show_desc = <<-EOT.unindent + Shows information for the given marketplace app + EOT + + command :show, show_desc, :appid, :options=>OpenNebulaHelper::XML do + helper.show_resource(args[0], options) + end + + enable_desc = <<-EOT.unindent + Enables the marketplace app + EOT + + command :enable, enable_desc, [:range, :appid_list] do + helper.perform_actions(args[0], options, "enabled") do |obj| + obj.enable + end + end + + disable_desc = <<-EOT.unindent + Disables the marketplace app. A disabled marketplace app cannot be + exported to a cloud + EOT + + command :disable, disable_desc, [:range, :appid_list] do + helper.perform_actions(args[0], options, "disabled") do |obj| + obj.disable + end + end +end diff --git a/src/cli/onetemplate b/src/cli/onetemplate index 2728f0fa5d..f8efea7f33 100755 --- a/src/cli/onetemplate +++ b/src/cli/onetemplate @@ -160,7 +160,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do end delete_desc = <<-EOT.unindent - Deletes the given Image + Deletes the given Template EOT command :delete, delete_desc, [:range, :templateid_list] do @@ -208,17 +208,8 @@ cmd=CommandParser::CmdParser.new(ARGV) do if args[1] extra_template = File.read(args[1]) - elsif options[:userdata] - if t.has_elements?('TEMPLATE/EC2') - t.add_element( - 'TEMPLATE/EC2', - 'USERDATA' => options[:userdata]) - - extra_template = t.template_like_str( - 'TEMPLATE', false, 'EC2') - end else - res = OpenNebulaHelper.create_template(options) + res = OpenNebulaHelper.create_template(options, t) if res.first != 0 STDERR.puts res.last @@ -228,7 +219,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do extra_template = res.last end - user_inputs = helper.get_user_inputs(t.to_hash) unless user_inputs + user_inputs = OneTemplateHelper.get_user_inputs(t.to_hash) unless user_inputs extra_template << "\n" << user_inputs diff --git a/src/cli/onevm b/src/cli/onevm index 35cc28e988..814f826da9 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -63,14 +63,6 @@ cmd=CommandParser::CmdParser.new(ARGV) do :description => "Overrides the DEV_PREFIX of the image" } - IP={ - :name => "ip", - :short => "-i ip", - :large => "--ip ip", - :format => String, - :description => "IP address for the new NIC" - } - CACHE={ :name => "cache", :large => "--cache cache_mode", @@ -669,7 +661,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do EOT command :"nic-attach", nic_attach_desc, :vmid, - :options => [OneVMHelper::FILE, OneVMHelper::NETWORK, IP] do + :options => [OneVMHelper::FILE, OneVMHelper::NETWORK, OneVMHelper::IP] do if options[:file].nil? and options[:network].nil? STDERR.puts "Provide a template file or a network:" diff --git a/src/cli/onevrouter b/src/cli/onevrouter new file mode 100755 index 0000000000..1d91daaaad --- /dev/null +++ b/src/cli/onevrouter @@ -0,0 +1,305 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +ONE_LOCATION=ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION="/usr/lib/one/ruby" +else + RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" +end + +$: << RUBY_LIB_LOCATION +$: << RUBY_LIB_LOCATION+"/cli" + +require 'command_parser' +require 'one_helper/onevrouter_helper' +require 'one_helper/onetemplate_helper' +require 'one_helper/onevm_helper' + +cmd=CommandParser::CmdParser.new(ARGV) do + usage "`onevrouter` [] []" + version OpenNebulaHelper::ONE_VERSION + + helper = OneVirtualRouterHelper.new + + before_proc do + helper.set_client(options) + end + + ######################################################################## + # Global Options + ######################################################################## + set :option, CommandParser::OPTIONS+OpenNebulaHelper::CLIENT_OPTIONS + + list_options = CLIHelper::OPTIONS + list_options << OpenNebulaHelper::XML + list_options << OpenNebulaHelper::NUMERIC + list_options << OpenNebulaHelper::DESCRIBE + + ######################################################################## + # Formatters for arguments + ######################################################################## + set :format, :groupid, OpenNebulaHelper.rname_to_id_desc("GROUP") do |arg| + OpenNebulaHelper.rname_to_id(arg, "GROUP") + end + + set :format, :userid, OpenNebulaHelper.rname_to_id_desc("USER") do |arg| + OpenNebulaHelper.rname_to_id(arg, "USER") + end + + set :format, :vrouterid, OneVirtualRouterHelper.to_id_desc do |arg| + helper.to_id(arg) + end + + set :format, :vrouterid_list, OneVirtualRouterHelper.list_to_id_desc do |arg| + helper.list_to_id(arg) + end + + set :format, :filterflag, OneVirtualRouterHelper.filterflag_to_i_desc do |arg| + helper.filterflag_to_i(arg) + end + + set :format, :templateid, OpenNebulaHelper.rname_to_id_desc("VMTEMPLATE") do |arg| + OpenNebulaHelper.rname_to_id(arg, "VMTEMPLATE") + end + + ######################################################################## + # Commands + ######################################################################## + + create_desc = <<-EOT.unindent + Creates a new Virtual Router from the given description + EOT + + command :create, create_desc, :file do + helper.create_resource(options) do |obj| + begin + template = File.read(args[0]) + + obj.allocate(template) + rescue => e + STDERR.puts e.messsage + exit -1 + end + end + end + + instantiate_desc = <<-EOT.unindent + Creates a new VM instance from the given Template. This VM can be + managed with the 'onevm' command. + + The NIC elements defined in the Virtual Router will be used. The + source Template can be modified adding or replacing attributes with + the optional file argument, or with the options. + EOT + + instantiate_options = [ + OneTemplateHelper::VM_NAME, + OneTemplateHelper::MULTIPLE, + OneVMHelper::HOLD + ] + + command :instantiate, instantiate_desc, :vrouterid, :templateid, [:file, nil], + :options=>instantiate_options+OpenNebulaHelper::TEMPLATE_OPTIONS do + exit_code=0 + + if args[1] && OpenNebulaHelper.create_template_options_used?(options) + STDERR.puts "You cannot use both template file and template"<< + " creation options." + next -1 + end + + number = options[:multiple] || 1 + user_inputs = nil + + helper.perform_action(args[0], options, "instantiated") do |vr| + name = options[:name] || "" + + t = OpenNebula::Template.new_with_id(args[1], helper.client) + + on_hold = options[:hold] != nil + + extra_template = "" + rc = t.info + + if OpenNebula.is_error?(rc) + STDERR.puts rc.message + exit(-1) + end + + if args[2] + extra_template = File.read(args[2]) + else + res = OpenNebulaHelper.create_template(options, t) + + if res.first != 0 + STDERR.puts res.last + next -1 + end + + extra_template = res.last + end + + user_inputs = OneTemplateHelper.get_user_inputs(t.to_hash) unless user_inputs + + extra_template << "\n" << user_inputs + + vr.instantiate(number, args[1], name, on_hold, extra_template) + end + end + + delete_desc = <<-EOT.unindent + Deletes the given Virtual Router + EOT + + command :delete, delete_desc, [:range, :vrouterid_list] do + helper.perform_actions(args[0],options,"deleted") do |obj| + obj.delete + end + end + + chgrp_desc = <<-EOT.unindent + Changes the Virtual Router group + EOT + + command :chgrp, chgrp_desc,[:range, :vrouterid_list], :groupid do + helper.perform_actions(args[0],options,"Group changed") do |obj| + obj.chown(-1, args[1].to_i) + end + end + + chown_desc = <<-EOT.unindent + Changes the Virtual Router owner and group + EOT + + command :chown, chown_desc, [:range, :vrouterid_list], :userid, + [:groupid,nil] do + gid = args[2].nil? ? -1 : args[2].to_i + helper.perform_actions(args[0],options,"Owner/Group changed") do |obj| + obj.chown(args[1].to_i, gid) + end + end + + chmod_desc = <<-EOT.unindent + Changes the Virtual Router permissions + EOT + + command :chmod, chmod_desc, [:range, :vrouterid_list], :octet do + helper.perform_actions(args[0],options, "Permissions changed") do |obj| + obj.chmod_octet(args[1]) + end + end + + update_desc = <<-EOT.unindent + Update the Virtual Router contents. If a path is not provided the editor + will be launched to modify the current content. + EOT + + command :update, update_desc, :vrouterid, [:file, nil], + :options=>OpenNebulaHelper::APPEND do + helper.perform_action(args[0],options,"modified") do |obj| + if options[:append] + str = OpenNebulaHelper.append_template(args[0], obj, args[1]) + else + str = OpenNebulaHelper.update_template(args[0], obj, args[1]) + end + + obj.update(str, options[:append]) + end + end + + rename_desc = <<-EOT.unindent + Renames the Virtual Router + EOT + + command :rename, rename_desc, :vrouterid, :name do + helper.perform_action(args[0],options,"renamed") do |obj| + obj.rename(args[1]) + end + end + + nic_attach_desc = <<-EOT.unindent + Attaches a NIC to a VirtualRouter, and each one of its VMs. When using + --file add only one NIC instance. + EOT + + command :"nic-attach", nic_attach_desc, :vrouterid, + :options => [OneVMHelper::FILE, OneVMHelper::NETWORK, OneVMHelper::IP] do + + if options[:file].nil? and options[:network].nil? + STDERR.puts "Provide a template file or a network:" + STDERR.puts "\t--file " + STDERR.puts "\t--network " + exit -1 + end + + if options[:file] + template = File.read(options[:file]) + else + network_id = options[:network] + ip = options[:ip] + if ip + template = "NIC = [ NETWORK_ID = #{network_id}, IP = #{ip} ]" + else + template = "NIC = [ NETWORK_ID = #{network_id} ]" + end + end + + helper.perform_action(args[0],options,"Attach NIC") do |vr| + vr.nic_attach(template) + end + end + + nic_detach_desc = <<-EOT.unindent + Detaches a NIC from a VirtualRouter, and each one of its VMs + EOT + + command :"nic-detach", nic_detach_desc, :vrouterid, :nicid do + nicid = args[1].to_i + + helper.perform_action(args[0],options,"Detach NIC") do |vr| + vr.nic_detach(nicid) + end + end + + list_desc = <<-EOT.unindent + Lists the Virtual Routers in the pool + EOT + + command :list, list_desc, [:filterflag, nil], :options=>list_options do + helper.list_pool(options, false, args[0]) + end + + show_desc = <<-EOT.unindent + Shows information for the given Virtual Router + EOT + + command :show, show_desc, :vrouterid, + :options=>[OpenNebulaHelper::XML, OneVMHelper::ALL_TEMPLATE] do + helper.show_resource(args[0],options) + end + + top_desc = <<-EOT.unindent + Lists Virtual Routers continuously + EOT + + command :top, top_desc, [:filterflag, nil], :options=>list_options do + helper.list_pool(options, true, args[0]) + end +end diff --git a/src/cloud/marketplace/bin/onemarket b/src/cloud/marketplace/bin/onemarket deleted file mode 100755 index 9d940c7adb..0000000000 --- a/src/cloud/marketplace/bin/onemarket +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env ruby - -# ---------------------------------------------------------------------------- # -# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); you may # -# not use this file except in compliance with the License. You may obtain # -# a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -# ---------------------------------------------------------------------------- # - -ONE_LOCATION=ENV["ONE_LOCATION"] - -if !ONE_LOCATION - RUBY_LIB_LOCATION="/usr/lib/one/ruby" -else - RUBY_LIB_LOCATION=ONE_LOCATION+"/lib/ruby" - TEMPLATES_LOCATION=ONE_LOCATION+"/etc/occi_templates" - CONF_LOCATION=ONE_LOCATION+"/etc" -end - -$: << RUBY_LIB_LOCATION -$: << RUBY_LIB_LOCATION+"/cloud" - -require 'marketplace/marketplace_client' - -require 'cli/command_parser' -require 'cli/cli_helper' - -require 'rubygems' -require 'json' - -USER_AGENT = "CLI" - -# -# Options -# - -DEFAULT_OPTIONS = [ - ENDPOINT = { - :name => "server", - :short => "-s url", - :large => "--server url", - :format => String, - :description => "Marketplace endpoint" - }, - USERNAME={ - :name => "username", - :short => "-u name", - :large => "--username name", - :format => String, - :description => "User name" - }, - PASSWORD={ - :name => "password", - :short => "-p pass", - :large => "--password pass", - :format => String, - :description => "User password" - } -] - -JSON_FORMAT={ - :name => "json", - :short => "-j", - :large => "--json", - :description => "Show in JSON format" -} - -# -# Table -# - -TABLE = CLIHelper::ShowTable.new(nil, self) do - column :ID, "Appliance", :size=>25 do |d| - d["_id"]["$oid"] - end - - column :NAME, "Name", :size=>50 do |d| - d["name"] - end - - column :PUBLISHER, "Publisher", :size=>15 do |d| - d["publisher"] - end - - default :ID, :NAME, :PUBLISHER -end - -# -# Commands -# - -cmd=CommandParser::CmdParser.new(ARGV) do - usage "`onemarket` [] []" - - set :option, DEFAULT_OPTIONS - - # - # List - # - - list_desc = <<-EOT.unindent - List the available appliances in the Marketplace - EOT - - command :list, list_desc, :options => JSON_FORMAT do - client = Market::ApplianceClient.new( - options[:username], - options[:password], - options[:server], - USER_AGENT) - - response = client.list - - if CloudClient::is_error?(response) - [response.code.to_i, response.to_s] - else - if options[:json] - [0,response.body] - else - array_list = JSON.parse(response.body) - TABLE.show(array_list['appliances']) - 0 - end - end - end - - # - # Create - # - - create_desc = <<-EOT.unindent - Create a new appliance in the Marketplace - EOT - - command :create, create_desc, :file do - client = Market::ApplianceClient.new( - options[:username], - options[:password], - options[:server], - USER_AGENT) - - response = client.create(File.read(args[0])) - - if CloudClient::is_error?(response) - [response.code.to_i, response.to_s] - else - [0, response.body] - end - end - - # - # Show - # - - show_desc = <<-EOT.unindent - Show detailed information of a given appliance - EOT - - command :show, show_desc, :id, :options => JSON_FORMAT do - client = Market::ApplianceClient.new( - options[:username], - options[:password], - options[:server], - USER_AGENT) - - response = client.show(args[0]) - - if CloudClient::is_error?(response) - [response.code.to_i, response.to_s] - else - [0,response.body] - end - end -end diff --git a/src/cloud/marketplace/lib/marketplace_client.rb b/src/cloud/marketplace/lib/marketplace_client.rb deleted file mode 100644 index 32724e64fa..0000000000 --- a/src/cloud/marketplace/lib/marketplace_client.rb +++ /dev/null @@ -1,90 +0,0 @@ -# ---------------------------------------------------------------------------- # -# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # -# # -# 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. # -# ---------------------------------------------------------------------------- # - -require 'uri' -require 'cloud/CloudClient' - -require 'ostruct' - -module Market - class Client - def initialize(username, password, url, user_agent="Ruby") - @username = username - @password = password - - url ||= 'http://marketplace.opennebula.systems/' - @uri = URI.parse(url) - - @user_agent = "OpenNebula #{CloudClient::VERSION} (#{user_agent})" - - @host = nil - @port = nil - - if ENV['http_proxy'] - uri_proxy = URI.parse(ENV['http_proxy']) - @host = uri_proxy.host - @port = uri_proxy.port - end - end - - def get(path) - req = Net::HTTP::Proxy(@host, @port)::Get.new(@uri.path + path) - do_request(req) - end - - def post(path, body) - req = Net::HTTP::Proxy(@host, @port)::Post.new(@uri.path + path) - req.body = body - - do_request(req) - end - - private - - def do_request(req) - if @username && @password - req.basic_auth @username, @password - end - - req['User-Agent'] = @user_agent - - res = CloudClient::http_start(@uri, @timeout) do |http| - http.request(req) - end - - res - end - end - - - class ApplianceClient < Client - def initialize(user, password, url, agent) - super(user, password, url, agent) - end - - def list - get("/appliance") - end - - def create(body) - post("/appliance", body) - end - - def show(id) - get("/appliance/#{id}") - end - end -end diff --git a/src/common/Attribute.cc b/src/common/Attribute.cc index 1849c5966f..11f731d44f 100644 --- a/src/common/Attribute.cc +++ b/src/common/Attribute.cc @@ -307,188 +307,3 @@ int VectorAttribute::vector_value(const char *name, bool& value) const /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VectorAttribute::vector_value(const char *name, int & value) const -{ - map::const_iterator it; - - it = attribute_value.find(name); - - if ( it == attribute_value.end() ) - { - return -1; - } - - if ( it->second.empty() ) - { - return -1; - } - - istringstream iss(it->second); - iss >> value; - - if (iss.fail() || !iss.eof()) - { - return -1; - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VectorAttribute::vector_value(const char *name, unsigned int & value) const -{ - map::const_iterator it; - - it = attribute_value.find(name); - - if ( it == attribute_value.end() ) - { - return -1; - } - - if ( it->second.empty() ) - { - return -1; - } - - istringstream iss(it->second); - iss >> value; - - if (iss.fail() || !iss.eof()) - { - return -1; - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VectorAttribute::vector_value(const char *name, long long& value) const -{ - map::const_iterator it; - - it = attribute_value.find(name); - - if ( it == attribute_value.end() ) - { - return -1; - } - - if ( it->second.empty() ) - { - return -1; - } - - istringstream iss(it->second); - iss >> value; - - if (iss.fail() || !iss.eof()) - { - return -1; - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -int VectorAttribute::vector_value(const char *name, float & value) const -{ - map::const_iterator it; - - it = attribute_value.find(name); - - if ( it == attribute_value.end() ) - { - return -1; - } - - if ( it->second.empty() ) - { - return -1; - } - - istringstream iss(it->second); - iss >> value; - - if (iss.fail() || !iss.eof()) - { - return -1; - } - - return 0; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -string VectorAttribute::vector_value_str(const char *name, int& value) const -{ - map::const_iterator it; - - it = attribute_value.find(name); - - if ( it == attribute_value.end() ) - { - value = -1; - return ""; - } - - if ( it->second.empty() ) - { - value = -1; - return ""; - } - - istringstream iss(it->second); - iss >> value; - - if (iss.fail() || !iss.eof()) - { - value = -1; - return ""; - } - - return it->second; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -string VectorAttribute::vector_value_str(const char *name, float& value) const -{ - map::const_iterator it; - - it = attribute_value.find(name); - - if ( it == attribute_value.end() ) - { - value = -1; - return ""; - } - - if ( it->second.empty() ) - { - value = -1; - return ""; - } - - istringstream iss(it->second); - iss >> value; - - if (iss.fail() || !iss.eof()) - { - value = -1; - return ""; - } - - return it->second; -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ diff --git a/src/common/NebulaUtil.cc b/src/common/NebulaUtil.cc index b172da2b51..cc9976710c 100644 --- a/src/common/NebulaUtil.cc +++ b/src/common/NebulaUtil.cc @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -306,3 +307,29 @@ std::string one_util::trim(const std::string& str) return tstr; } + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +std::string one_util::gsub(const std::string& st, const std::string& sfind, + const std::string& srepl) +{ + std::string result = st; + + std::string::size_type pos = 0; + + size_t srepl_len = srepl.length(); + size_t sfind_len = sfind.length(); + + pos = result.find(sfind, pos); + + while(pos != std::string::npos) + { + result.replace(pos, sfind_len , srepl); + pos += srepl_len; + + pos = result.find(sfind, pos); + } + + return result; +} diff --git a/src/datastore/Datastore.cc b/src/datastore/Datastore.cc index ec3bf80203..9c67cde324 100644 --- a/src/datastore/Datastore.cc +++ b/src/datastore/Datastore.cc @@ -711,9 +711,9 @@ int Datastore::from_xml(const string& xml) rc += xpath(cluster_id, "/DATASTORE/CLUSTER_ID", -1); rc += xpath(cluster, "/DATASTORE/CLUSTER", "not_found"); - rc += xpath(total_mb, "/DATASTORE/TOTAL_MB", 0); - rc += xpath(free_mb, "/DATASTORE/FREE_MB", 0); - rc += xpath(used_mb, "/DATASTORE/USED_MB", 0); + rc += xpath(total_mb,"/DATASTORE/TOTAL_MB",0); + rc += xpath(free_mb, "/DATASTORE/FREE_MB", 0); + rc += xpath(used_mb, "/DATASTORE/USED_MB", 0); // Permissions rc += perms_from_xml(); diff --git a/src/datastore/DatastorePool.cc b/src/datastore/DatastorePool.cc index f1382ad658..a6f96456b3 100644 --- a/src/datastore/DatastorePool.cc +++ b/src/datastore/DatastorePool.cc @@ -40,20 +40,18 @@ const int DatastorePool::FILE_DS_ID = 2; DatastorePool::DatastorePool( SqlDB * db, - const vector& _inherit_attrs) : + const vector& _inherit_attrs) : PoolSQL(db, Datastore::table, true, true) { ostringstream oss; string error_str; - vector::const_iterator it; + vector::const_iterator it; for (it = _inherit_attrs.begin(); it != _inherit_attrs.end(); it++) { - const SingleAttribute* sattr = static_cast(*it); - - inherit_attrs.push_back(sattr->value()); + inherit_attrs.push_back((*it)->value()); } if (get_lastOID() == -1) //lastOID is set in PoolSQL::init_cb diff --git a/src/datastore_mad/remotes/ceph/cp b/src/datastore_mad/remotes/ceph/cp index 4918e88dc1..b1bb0e14ca 100755 --- a/src/datastore_mad/remotes/ceph/cp +++ b/src/datastore_mad/remotes/ceph/cp @@ -40,6 +40,8 @@ source ${DRIVER_PATH}/ceph.conf DRV_ACTION=$1 ID=$2 +export DRV_ACTION + UTILS_PATH="${DRIVER_PATH}/.." XPATH="$UTILS_PATH/xpath.rb -b $DRV_ACTION" @@ -139,7 +141,7 @@ fi REGISTER_CMD=$(cat <\$CHECKSUM +$SIZE +${FORMAT} +EOT +EOF +) + +INFO=$(ssh_monitor_and_log "$DST_HOST" "$INFO_SCRIPT" "Image info script" 2>&1) +INFO_STATUS=$? + +if [ "$INFO_STATUS" != "0" ]; then + echo "$INFO" + exit $INFO_STATUS +fi + +cat < + $IMPORT_SOURCE + $INFO + NO +" +EOF + diff --git a/src/datastore_mad/remotes/dev/cp b/src/datastore_mad/remotes/dev/cp index 7e133e18ad..f48310f39d 100755 --- a/src/datastore_mad/remotes/dev/cp +++ b/src/datastore_mad/remotes/dev/cp @@ -39,6 +39,8 @@ source ${DRIVER_PATH}/../libfs.sh DRV_ACTION=$1 ID=$2 +export DRV_ACTION + UTILS_PATH="${DRIVER_PATH}/.." XPATH="$UTILS_PATH/xpath.rb -b $DRV_ACTION" diff --git a/src/datastore_mad/remotes/downloader.sh b/src/datastore_mad/remotes/downloader.sh index 79bad38ec5..33a52e50ff 100755 --- a/src/datastore_mad/remotes/downloader.sh +++ b/src/datastore_mad/remotes/downloader.sh @@ -16,6 +16,16 @@ # limitations under the License. # #--------------------------------------------------------------------------- # +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +DRIVER_PATH=$(dirname $0) + # Execute a command (first parameter) and use the first kb of stdout # to determine the file type function get_type @@ -117,6 +127,86 @@ function unarchive fi } +function s3_env +{ + XPATH="$DRIVER_PATH/xpath.rb -b $DRV_ACTION" + + unset i j XPATH_ELEMENTS + + while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" + done < <($XPATH /DS_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/ACCESS_KEY_ID \ + /DS_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/SECRET_ACCESS_KEY \ + /DS_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/ENDPOINT) + + S3_ACCESS_KEY_ID="${XPATH_ELEMENTS[j++]}" + S3_SECRET_ACCESS_KEY="${XPATH_ELEMENTS[j++]}" + S3_ENDPOINT="${XPATH_ELEMENTS[j++]}" +} + +function s3_curl_args +{ + FROM="$1" + + ENDPOINT=${S3_ENDPOINT:-https://s3.amazonaws.com} + OBJECT=$(basename $FROM) + BUCKET=$(basename $(dirname $FROM)) + + DATE="`date -u +'%a, %d %b %Y %H:%M:%S GMT'`" + AUTH_STRING="GET\n\n\n${DATE}\n/${BUCKET}/${OBJECT}" + + SIGNED_AUTH_STRING=`echo -en "$AUTH_STRING" | \ + openssl sha1 -hmac ${S3_SECRET_ACCESS_KEY} -binary | \ + base64` + + echo " -H \"Date: ${DATE}\"" \ + " -H \"Authorization: AWS ${S3_ACCESS_KEY_ID}:${SIGNED_AUTH_STRING}\"" \ + " ${ENDPOINT}/${BUCKET}/${OBJECT}" +} + +function get_rbd_cmd +{ + local i j URL_ELEMENTS + + FROM="$1" + + URL_RB="$DRIVER_PATH/url.rb" + + while IFS= read -r -d '' element; do + URL_ELEMENTS[i++]="$element" + done < <($URL_RB $FROM \ + USER \ + HOST \ + SOURCE \ + PARAM_DS \ + PARAM_CEPH_USER \ + PARAM_CEPH_CONF) + + USER="${URL_ELEMENTS[j++]}" + DST_HOST="${URL_ELEMENTS[j++]}" + SOURCE="${URL_ELEMENTS[j++]}" + DS="${URL_ELEMENTS[j++]}" + CEPH_USER="${URL_ELEMENTS[j++]}" + CEPH_CONF="${URL_ELEMENTS[j++]}" + + # Remove leading '/' + SOURCE="${SOURCE#/}" + + if [ -n "$USER" ]; then + DST_HOST="$USER@$DST_HOST" + fi + + if [ -n "$CEPH_USER" ]; then + RBD="$RBD --id ${CEPH_USER}" + fi + + if [ -n "$CEPH_CONF" ]; then + RBD="$RBD --conf ${CEPH_CONF}" + fi + + echo "ssh $DST_HOST $RBD export $SOURCE -" +} + TEMP=`getopt -o m:s:l:n -l md5:,sha1:,limit:,nodecomp -- "$@"` if [ $? != 0 ] ; then @@ -162,13 +252,15 @@ TO="$2" # File used by the hasher function to store the resulting hash export HASH_FILE="/tmp/downloader.hash.$$" +GLOBAL_CURL_ARGS="--fail -sS -k -L" + case "$FROM" in http://*|https://*) # -k so it does not check the certificate # -L to follow redirects # -sS to hide output except on failure # --limit_rate to limit the bw - curl_args="-sS -k -L $FROM" + curl_args="$GLOBAL_CURL_ARGS $FROM" if [ -n "$LIMIT_RATE" ]; then curl_args="--limit-rate $LIMIT_RATE $curl_args" @@ -176,6 +268,33 @@ http://*|https://*) command="curl $curl_args" ;; +ssh://*) + # pseudo-url for ssh transfers ssh://user@host:path + # -l to limit the bw + ssh_src=${FROM#ssh://} + ssh_arg=(${ssh_src/:/ }) + + rmt_cmd="'cat ${ssh_arg[1]}'" + + command="ssh ${ssh_arg[0]} $rmt_cmd" + ;; +s3://*) + + # Read s3 environment + s3_env + + if [ -z "$S3_ACCESS_KEY_ID" -o -z "$S3_SECRET_ACCESS_KEY" ]; then + echo "S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY are required" >&2 + exit -1 + fi + + curl_args="$(s3_curl_args $FROM)" + + command="curl $GLOBAL_CURL_ARGS $curl_args" + ;; +rbd://*) + command="$(get_rbd_cmd $FROM)" + ;; *) if [ ! -r $FROM ]; then echo "Cannot read from $FROM" >&2 @@ -188,9 +307,9 @@ esac file_type=$(get_type "$command") decompressor=$(get_decompressor "$file_type") -$command | tee >( hasher $HASH_TYPE) | decompress "$decompressor" "$TO" +eval "$command" | tee >( hasher $HASH_TYPE) | decompress "$decompressor" "$TO" -if [ "$?" != "0" ]; then +if [ "$?" != "0" -o "$PIPESTATUS" != "0" ]; then echo "Error copying" >&2 exit -1 fi diff --git a/src/datastore_mad/remotes/dummy/export b/src/datastore_mad/remotes/dummy/export new file mode 100755 index 0000000000..d701831e7a --- /dev/null +++ b/src/datastore_mad/remotes/dummy/export @@ -0,0 +1,19 @@ +#!/bin/sh + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +echo "dummy_path" diff --git a/src/datastore_mad/remotes/fs/cp b/src/datastore_mad/remotes/fs/cp index d5d0acf8a9..258cfa97f7 100755 --- a/src/datastore_mad/remotes/fs/cp +++ b/src/datastore_mad/remotes/fs/cp @@ -39,6 +39,8 @@ source ${DRIVER_PATH}/../libfs.sh DRV_ACTION=$1 ID=$2 +export DRV_ACTION + UTILS_PATH="${DRIVER_PATH}/.." XPATH="$UTILS_PATH/xpath.rb -b $DRV_ACTION" diff --git a/src/datastore_mad/remotes/fs/export b/src/datastore_mad/remotes/fs/export new file mode 100755 index 0000000000..4660f33311 --- /dev/null +++ b/src/datastore_mad/remotes/fs/export @@ -0,0 +1,89 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +############################################################################### +# This script is used to export an image to qcow2 file +############################################################################### + +# ------------ Set up the environment to source common tools ------------ + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +DRIVER_PATH=$(dirname $0) +source ${DRIVER_PATH}/../libfs.sh + +# -------- Get rm and datastore arguments from OpenNebula core ------------ + +DRV_ACTION=$1 +ID=$2 + +XPATH="${DRIVER_PATH}/../xpath.rb -b $DRV_ACTION" + +unset i XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <($XPATH /DS_DRIVER_ACTION_DATA/IMAGE/SOURCE \ + /DS_DRIVER_ACTION_DATA/DATASTORE/TEMPLATE/BRIDGE_LIST) +unset i + +SRC="${XPATH_ELEMENTS[i++]}" +BRIDGE_LIST="${XPATH_ELEMENTS[i++]}" + +#------------------------------------------------------------------------------- +# Output image source and format +#------------------------------------------------------------------------------- + +INFO_SCRIPT=$(cat </dev/null | grep -Po '(?<=file format: )\w+') + +echo "\$CHECKSUM" +echo "\$SIZE" +echo "\${FORMAT-"unknown"}" + +EOF +) + +if [ -n "$BRIDGE_LIST" ]; then + HOST=`get_destination_host $ID` + INFO=$(ssh_monitor_and_log "$HOST" "$INFO_SCRIPT" "Image info script" 2>&1) + SRC="ssh://$HOST:$SRC" +else + INFO=$(monitor_and_log "$INFO_SCRIPT" "Image info script" 2>&1) +fi + +INFO_STATUS=$? + +if [ "$INFO_STATUS" != "0" ]; then + echo "$INFO" + exit $INFO_STATUS +fi + +echo "$SRC \ + $INFO \ + NO" + diff --git a/src/datastore_mad/remotes/libfs.sh b/src/datastore_mad/remotes/libfs.sh index 24fb95dbca..f130dd81ea 100644 --- a/src/datastore_mad/remotes/libfs.sh +++ b/src/datastore_mad/remotes/libfs.sh @@ -53,7 +53,15 @@ function set_up_datastore { } #------------------------------------------------------------------------------- -# Generates an unique image hash. Requires BASE_PATH to be set +# Get file format using qemu-img +# @return string representation of the format, empty if error +#------------------------------------------------------------------------------- +function image_format { + echo "$($QEMU_IMG info $1 2>/dev/null | grep -Po '(?<=file format: )\w+')" +} + +#------------------------------------------------------------------------------- +# Generates an unique image hash. Requires ID to be set # @return hash for the image (empty if error) #------------------------------------------------------------------------------- function generate_image_hash { @@ -64,11 +72,10 @@ function generate_image_hash { $CANONICAL_STR EOF ) - IMAGE_HASH=$(echo $CANONICAL_MD5 | cut -d ' ' -f1) - IMAGE_HASH=$(basename "$IMAGE_HASH") + IMAGE_HASH="$(echo $CANONICAL_MD5 | cut -d ' ' -f1)" - if [ -z "$IMAGE_HASH" -o -z "$BASE_PATH" ]; then - log_error "Error generating the path in generate_image_path." + if [ -z "$IMAGE_HASH" ]; then + log_error "Error generating the path in generate_image_hash." exit 1 fi @@ -81,6 +88,12 @@ EOF #------------------------------------------------------------------------------- function generate_image_path { IMAGE_HASH=`generate_image_hash` + + if [ -z "$BASE_PATH" ]; then + log_error "Error generating the path in generate_image_path." + exit 1 + fi + echo "${BASE_PATH}/${IMAGE_HASH}" } diff --git a/src/datastore_mad/remotes/lvm/cp b/src/datastore_mad/remotes/lvm/cp index c7d02d086b..a1c8a5c4d7 100755 --- a/src/datastore_mad/remotes/lvm/cp +++ b/src/datastore_mad/remotes/lvm/cp @@ -40,6 +40,8 @@ source ${DRIVER_PATH}/lvm.conf DRV_ACTION=$1 ID=$2 +export DRV_ACTION + UTILS_PATH="${DRIVER_PATH}/.." XPATH="$UTILS_PATH/xpath.rb -b $DRV_ACTION" diff --git a/src/datastore_mad/remotes/url.rb b/src/datastore_mad/remotes/url.rb new file mode 100755 index 0000000000..dc193aa564 --- /dev/null +++ b/src/datastore_mad/remotes/url.rb @@ -0,0 +1,58 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- */ +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# 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. */ +# -------------------------------------------------------------------------- */ + +# +# Simple command to parse an URLs more elements (refer by keywords or params) +# + +require 'uri' +require 'cgi' +require 'pp' + +url = ARGV.shift + +u = URI.parse(url) + +SPECIAL_KEYS = { + "PROTOCOL" => u.scheme, + "USER" => u.user, + "PASSWORD" => u.password, + "HOST" => u.host, + "PORT" => u.port, + "SOURCE" => u.path +} + +PARAMS = CGI.parse(u.query) + +values = "" +ARGV.each do |key| + key = key.to_s + if key.downcase.start_with?("param_") + param = key.gsub(/^param_/i,"") + value = PARAMS[param] + value = [value].flatten.first || "" + values << value + else + value = SPECIAL_KEYS[key] || "" + values << value + end + values << "\0" +end + +puts values + +exit 0 diff --git a/src/datastore_mad/remotes/vmfs/cp b/src/datastore_mad/remotes/vmfs/cp index 384319548e..1aed20504f 100755 --- a/src/datastore_mad/remotes/vmfs/cp +++ b/src/datastore_mad/remotes/vmfs/cp @@ -43,6 +43,8 @@ source ${DRIVER_PATH}/vmfs.conf DRV_ACTION=$1 ID=$2 +export DRV_ACTION + UTILS_PATH="${DRIVER_PATH}/.." XPATH="$UTILS_PATH/xpath.rb -b $DRV_ACTION" diff --git a/src/dm/DispatchManagerActions.cc b/src/dm/DispatchManagerActions.cc index 66a5aac144..d31c03750f 100644 --- a/src/dm/DispatchManagerActions.cc +++ b/src/dm/DispatchManagerActions.cc @@ -92,7 +92,7 @@ int DispatchManager::import ( time_t the_time = time(0); int cpu, mem, disk; - vector pci; + vector pci; vm->get_requirements(cpu, mem, disk, pci); @@ -772,7 +772,7 @@ int DispatchManager::finalize( Host * host; ostringstream oss; - vector pci; + vector pci; VirtualMachine::VmState state; bool is_public_host = false; @@ -1443,6 +1443,7 @@ int DispatchManager::attach_nic( int uid; int oid; int rc; + string tmp_error; set vm_sgs; @@ -1496,8 +1497,8 @@ int DispatchManager::attach_nic( vm->set_resched(false); - uid = vm->get_uid(); - oid = vm->get_oid(); + uid = vm->get_uid(); + oid = vm->get_oid(); vmpool->update(vm); @@ -1514,8 +1515,6 @@ int DispatchManager::attach_nic( if ( vm == 0 ) { - delete nic; - if ( rc == 0 ) { VirtualMachine::release_network_leases(nic, vid); @@ -1527,6 +1526,8 @@ int DispatchManager::attach_nic( } } + delete nic; + oss << "Could not attach a new NIC to VM " << vid << ", VM does not exist after setting its state to HOTPLUG." ; error_str = oss.str(); @@ -1599,7 +1600,7 @@ int DispatchManager::attach_nic( { vm->log("DiM", Log::INFO, "VM NIC Successfully attached."); - vm->clear_attach_nic(); + vm->attach_nic_success(); } vmpool->update(vm); @@ -1618,6 +1619,7 @@ int DispatchManager::detach_nic( string& error_str) { ostringstream oss; + string tmp_error; VirtualMachine * vm = vmpool->get(vid, true); @@ -1644,7 +1646,7 @@ int DispatchManager::detach_nic( return -1; } - if ( vm->set_attach_nic(nic_id) == -1 ) + if ( vm->set_detach_nic(nic_id) == -1 ) { oss << "Could not detach NIC with NIC_ID " << nic_id << ", it does not exist."; @@ -1698,9 +1700,11 @@ int DispatchManager::detach_nic( } else { + vmpool->update(vm); + vm->unlock(); - vmpool->delete_attach_nic(vid); + vmpool->detach_nic_success(vid); vm->log("DiM", Log::INFO, "VM NIC Successfully detached."); } diff --git a/src/group/Group.cc b/src/group/Group.cc index c2c6f9e117..354b14726d 100644 --- a/src/group/Group.cc +++ b/src/group/Group.cc @@ -380,7 +380,7 @@ void Group::add_admin_rules(int user_id) NebulaLog::log("GROUP",Log::ERROR,error_msg); } - // # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP/@ USE+MANAGE * + // # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER/@ USE+MANAGE * rc = aclm->add_rule( AclRule::INDIVIDUAL_ID | user_id, @@ -391,6 +391,7 @@ void Group::add_admin_rules(int user_id) PoolObjectSQL::TEMPLATE | PoolObjectSQL::DOCUMENT | PoolObjectSQL::SECGROUP | + PoolObjectSQL::VROUTER | AclRule::GROUP_ID | oid, @@ -463,7 +464,7 @@ void Group::del_admin_rules(int user_id) NebulaLog::log("GROUP",Log::ERROR,error_msg); } - // # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP/@ USE+MANAGE * + // # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER/@ USE+MANAGE * rc = aclm->del_rule( AclRule::INDIVIDUAL_ID | user_id, @@ -474,6 +475,7 @@ void Group::del_admin_rules(int user_id) PoolObjectSQL::TEMPLATE | PoolObjectSQL::DOCUMENT | PoolObjectSQL::SECGROUP | + PoolObjectSQL::VROUTER | AclRule::GROUP_ID | oid, diff --git a/src/group/GroupPool.cc b/src/group/GroupPool.cc index 53c451a607..97d467a993 100644 --- a/src/group/GroupPool.cc +++ b/src/group/GroupPool.cc @@ -37,11 +37,9 @@ const int GroupPool::USERS_ID = 1; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -GroupPool::GroupPool(SqlDB * db, - vector hook_mads, - const string& remotes_location, - bool is_federation_slave) - :PoolSQL(db, Group::table, !is_federation_slave, true) +GroupPool::GroupPool(SqlDB * db, vector hook_mads, + const string& remotes_location, bool is_federation_slave) : + PoolSQL(db, Group::table, !is_federation_slave, true) { ostringstream oss; string error_str; @@ -144,7 +142,7 @@ error_name: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int GroupPool::update(Group * group) +int GroupPool::update(PoolObjectSQL * objsql) { if (Nebula::instance().is_federation_slave()) { @@ -155,7 +153,7 @@ int GroupPool::update(Group * group) return -1; } - return group->update(db); + return PoolSQL::update(objsql); } /* -------------------------------------------------------------------------- */ diff --git a/src/host/Host.cc b/src/host/Host.cc index dd1197004f..4be82146e0 100644 --- a/src/host/Host.cc +++ b/src/host/Host.cc @@ -182,13 +182,11 @@ int Host::extract_ds_info( Template &tmpl, map &ds) { - char * error_msg; - int rc; + char * error_msg; + int rc; - const VectorAttribute * vatt; - vector ds_att; - - vector::const_iterator it; + vector ds_att; + vector::const_iterator it; // ------------------------------------------------------------------------- // Parse Template @@ -223,18 +221,11 @@ int Host::extract_ds_info( { int dsid; - vatt = dynamic_cast(*it); - - if (vatt == 0) - { - continue; - } - - rc = vatt->vector_value("ID", dsid); + rc = (*it)->vector_value("ID", dsid); if (rc == 0 && dsid != -1) { - ds.insert(make_pair(dsid, vatt)); + ds.insert(make_pair(dsid, *it)); } } @@ -256,8 +247,8 @@ int Host::update_info(Template &tmpl, vector::iterator it; vector vm_att; vector ds_att; - vector pci_att; - vector local_ds_att; + vector pci_att; + vector local_ds_att; int rc; int vmid; @@ -639,7 +630,7 @@ int Host::from_xml(const string& xml) rc += xpath(vmm_mad_name, "/HOST/VM_MAD", "not_found"); rc += xpath(vnm_mad_name, "/HOST/VN_MAD", "not_found"); - rc += xpath(last_monitored, "/HOST/LAST_MON_TIME", 0); + rc += xpath(last_monitored, "/HOST/LAST_MON_TIME", 0); rc += xpath(cluster_id, "/HOST/CLUSTER_ID", -1); rc += xpath(cluster, "/HOST/CLUSTER", "not_found"); diff --git a/src/host/HostPool.cc b/src/host/HostPool.cc index 434df31640..c42c4a494f 100644 --- a/src/host/HostPool.cc +++ b/src/host/HostPool.cc @@ -37,7 +37,7 @@ time_t HostPool::_monitor_expiration; /* -------------------------------------------------------------------------- */ HostPool::HostPool(SqlDB* db, - vector hook_mads, + vector hook_mads, const string& hook_location, const string& remotes_location, time_t expire_time) @@ -52,9 +52,6 @@ HostPool::HostPool(SqlDB* db, } // ------------------ Initialize Hooks for the pool ---------------------- - - const VectorAttribute * vattr; - string name; string on; string cmd; @@ -65,15 +62,13 @@ HostPool::HostPool(SqlDB* db, for (unsigned int i = 0 ; i < hook_mads.size() ; i++ ) { - vattr = static_cast(hook_mads[i]); + name = hook_mads[i]->vector_value("NAME"); + on = hook_mads[i]->vector_value("ON"); + cmd = hook_mads[i]->vector_value("COMMAND"); + arg = hook_mads[i]->vector_value("ARGUMENTS"); + hook_mads[i]->vector_value("REMOTE", remote); - name = vattr->vector_value("NAME"); - on = vattr->vector_value("ON"); - cmd = vattr->vector_value("COMMAND"); - arg = vattr->vector_value("ARGUMENTS"); - vattr->vector_value("REMOTE", remote); - - transform (on.begin(),on.end(),on.begin(),(int(*)(int))toupper); + one_util::toupper(on); if ( on.empty() || cmd.empty() ) { diff --git a/src/host/HostShare.cc b/src/host/HostShare.cc index 6a0fa68cc3..d9e411ce1f 100644 --- a/src/host/HostShare.cc +++ b/src/host/HostShare.cc @@ -38,40 +38,33 @@ int HostSharePCI::from_xml_node(const xmlNodePtr node) return -1; } - return init(); -} - -/* ------------------------------------------------------------------------*/ - -int HostSharePCI::init() -{ - vector devices; - - int num_devs = get("PCI", devices); - - for (int i=0; i < num_devs; i++) - { - VectorAttribute * pci = dynamic_cast(devices[i]); - - if (pci == 0) - { - return -1; - } - - PCIDevice * pcidev = new PCIDevice(pci); - - pci_devices.insert(make_pair(pcidev->address, pcidev)); - } + init(); return 0; } +/* ------------------------------------------------------------------------*/ + +void HostSharePCI::init() +{ + vector devices; + + int num_devs = get("PCI", devices); + + for (int i=0; i < num_devs; i++) + { + PCIDevice * pcidev = new PCIDevice(devices[i]); + + pci_devices.insert(make_pair(pcidev->address, pcidev)); + } +} + /* ------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------*/ -bool HostSharePCI::test(const vector &devs) const +bool HostSharePCI::test(const vector &devs) const { - vector::const_iterator it; + vector::const_iterator it; map::const_iterator jt; std::set assigned; @@ -82,20 +75,11 @@ bool HostSharePCI::test(const vector &devs) const for ( it=devs.begin(); it!= devs.end(); it++) { - const VectorAttribute* pci = dynamic_cast(*it); + vendor_rc = get_pci_value("VENDOR", *it, vendor_id); + device_rc = get_pci_value("DEVICE", *it, device_id); + class_rc = get_pci_value("CLASS" , *it, class_id); - if ( pci == 0 ) - { - return false; - } - - vendor_rc = get_pci_value("VENDOR", pci, vendor_id); - device_rc = get_pci_value("DEVICE", pci, device_id); - class_rc = get_pci_value("CLASS" , pci, class_id); - - if (vendor_rc <= 0 && - device_rc <= 0 && - class_rc <= 0) + if (vendor_rc <= 0 && device_rc <= 0 && class_rc <= 0) { return false; } @@ -130,9 +114,9 @@ bool HostSharePCI::test(const vector &devs) const /* ------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------*/ -void HostSharePCI::add(vector &devs, int vmid) +void HostSharePCI::add(vector &devs, int vmid) { - vector::iterator it; + vector::iterator it; map::const_iterator jt; unsigned int vendor_id, device_id, class_id; @@ -140,16 +124,9 @@ void HostSharePCI::add(vector &devs, int vmid) for ( it=devs.begin(); it!= devs.end(); it++) { - VectorAttribute * pci = dynamic_cast(*it); - - if ( pci == 0 ) - { - return; - } - - vendor_rc = get_pci_value("VENDOR", pci, vendor_id); - device_rc = get_pci_value("DEVICE", pci, device_id); - class_rc = get_pci_value("CLASS" , pci, class_id); + vendor_rc = get_pci_value("VENDOR", *it, vendor_id); + device_rc = get_pci_value("DEVICE", *it, device_id); + class_rc = get_pci_value("CLASS" , *it, class_id); for (jt=pci_devices.begin(); jt!=pci_devices.end(); jt++) { @@ -163,12 +140,12 @@ void HostSharePCI::add(vector &devs, int vmid) dev->vmid = vmid; dev->attrs->replace("VMID", vmid); - pci->replace("DOMAIN",dev->attrs->vector_value("DOMAIN")); - pci->replace("BUS",dev->attrs->vector_value("BUS")); - pci->replace("SLOT",dev->attrs->vector_value("SLOT")); - pci->replace("FUNCTION",dev->attrs->vector_value("FUNCTION")); + (*it)->replace("DOMAIN",dev->attrs->vector_value("DOMAIN")); + (*it)->replace("BUS",dev->attrs->vector_value("BUS")); + (*it)->replace("SLOT",dev->attrs->vector_value("SLOT")); + (*it)->replace("FUNCTION",dev->attrs->vector_value("FUNCTION")); - pci->replace("ADDRESS",dev->attrs->vector_value("ADDRESS")); + (*it)->replace("ADDRESS",dev->attrs->vector_value("ADDRESS")); break; } @@ -179,21 +156,14 @@ void HostSharePCI::add(vector &devs, int vmid) /* ------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------*/ -void HostSharePCI::del(const vector &devs) +void HostSharePCI::del(const vector &devs) { - vector::const_iterator it; + vector::const_iterator it; map::iterator pci_it; for ( it=devs.begin(); it!= devs.end(); it++) { - const VectorAttribute * pci = dynamic_cast(*it); - - if ( pci == 0 ) - { - continue; - } - - pci_it = pci_devices.find(pci->vector_value("ADDRESS")); + pci_it = pci_devices.find((*it)->vector_value("ADDRESS")); if (pci_it != pci_devices.end()) { @@ -206,9 +176,9 @@ void HostSharePCI::del(const vector &devs) /* ------------------------------------------------------------------------*/ /* ------------------------------------------------------------------------*/ -void HostSharePCI::set_monitorization(vector &pci_att) +void HostSharePCI::set_monitorization(vector &pci_att) { - vector::iterator it; + vector::iterator it; map::iterator pci_it; string address; @@ -223,12 +193,7 @@ void HostSharePCI::set_monitorization(vector &pci_att) for (it = pci_att.begin(); it != pci_att.end(); it++) { - VectorAttribute * pci = dynamic_cast(*it); - - if ( pci == 0 ) - { - continue; - } + VectorAttribute * pci = *it; address = pci->vector_value("ADDRESS"); @@ -422,23 +387,23 @@ int HostShare::from_xml_node(const xmlNodePtr node) // Initialize the internal XML object ObjectXML::update_from_node(node); - rc += xpath(disk_usage, "/HOST_SHARE/DISK_USAGE", -1); - rc += xpath(mem_usage, "/HOST_SHARE/MEM_USAGE", -1); - rc += xpath(cpu_usage, "/HOST_SHARE/CPU_USAGE", -1); + rc += xpath(disk_usage, "/HOST_SHARE/DISK_USAGE", -1); + rc += xpath(mem_usage, "/HOST_SHARE/MEM_USAGE", -1); + rc += xpath(cpu_usage, "/HOST_SHARE/CPU_USAGE", -1); - rc += xpath(max_disk, "/HOST_SHARE/MAX_DISK", -1); - rc += xpath(max_mem , "/HOST_SHARE/MAX_MEM", -1); - rc += xpath(max_cpu , "/HOST_SHARE/MAX_CPU", -1); + rc += xpath(max_disk, "/HOST_SHARE/MAX_DISK", -1); + rc += xpath(max_mem , "/HOST_SHARE/MAX_MEM", -1); + rc += xpath(max_cpu , "/HOST_SHARE/MAX_CPU", -1); - rc += xpath(free_disk, "/HOST_SHARE/FREE_DISK", -1); - rc += xpath(free_mem , "/HOST_SHARE/FREE_MEM", -1); - rc += xpath(free_cpu , "/HOST_SHARE/FREE_CPU", -1); + rc += xpath(free_disk, "/HOST_SHARE/FREE_DISK", -1); + rc += xpath(free_mem , "/HOST_SHARE/FREE_MEM", -1); + rc += xpath(free_cpu , "/HOST_SHARE/FREE_CPU", -1); - rc += xpath(used_disk, "/HOST_SHARE/USED_DISK", -1); - rc += xpath(used_mem , "/HOST_SHARE/USED_MEM", -1); - rc += xpath(used_cpu , "/HOST_SHARE/USED_CPU", -1); + rc += xpath(used_disk, "/HOST_SHARE/USED_DISK", -1); + rc += xpath(used_mem , "/HOST_SHARE/USED_MEM", -1); + rc += xpath(used_cpu , "/HOST_SHARE/USED_CPU", -1); - rc += xpath(running_vms,"/HOST_SHARE/RUNNING_VMS",-1); + rc += xpath(running_vms,"/HOST_SHARE/RUNNING_VMS",-1); // ------------ Datastores --------------- @@ -487,9 +452,9 @@ int HostShare::from_xml_node(const xmlNodePtr node) /* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */ -void HostShare::set_ds_monitorization(const vector &ds_att) +void HostShare::set_ds_monitorization(const vector &ds_att) { - vector::const_iterator it; + vector::const_iterator it; ds.erase("DS"); diff --git a/src/image/Image.cc b/src/image/Image.cc index a7b5fdd7f9..100f347e3b 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -402,14 +402,15 @@ int Image::from_xml(const string& xml) rc += xpath(int_type, "/IMAGE/TYPE", 0); rc += xpath(int_disk_type, "/IMAGE/DISK_TYPE", 0); rc += xpath(persistent_img, "/IMAGE/PERSISTENT",0); - rc += xpath(regtime, "/IMAGE/REGTIME", 0); + rc += xpath(regtime,"/IMAGE/REGTIME", 0); - rc += xpath(source, "/IMAGE/SOURCE", "not_found"); - rc += xpath(size_mb, "/IMAGE/SIZE", 0); - rc += xpath(int_state, "/IMAGE/STATE", 0); - rc += xpath(running_vms, "/IMAGE/RUNNING_VMS", -1); - rc += xpath(cloning_ops, "/IMAGE/CLONING_OPS", -1); - rc += xpath(cloning_id, "/IMAGE/CLONING_ID", -1); + rc += xpath(size_mb, "/IMAGE/SIZE", 0); + + rc += xpath(source, "/IMAGE/SOURCE", "not_found"); + rc += xpath(int_state, "/IMAGE/STATE", 0); + rc += xpath(running_vms,"/IMAGE/RUNNING_VMS",-1); + rc += xpath(cloning_ops,"/IMAGE/CLONING_OPS",-1); + rc += xpath(cloning_id, "/IMAGE/CLONING_ID", -1); rc += xpath(target_snapshot, "/IMAGE/TARGET_SNAPSHOT", -1); diff --git a/src/image/ImageManagerActions.cc b/src/image/ImageManagerActions.cc index 66ab6e4a8a..25bf7d2c30 100644 --- a/src/image/ImageManagerActions.cc +++ b/src/image/ImageManagerActions.cc @@ -287,12 +287,8 @@ void ImageManager::release_cloning_image(int iid, int clone_img_id) case Image::ERROR: case Image::USED_PERS: case Image::LOCKED: - ostringstream oss; - - oss << "Releasing image in wrong state: " - << Image::state_to_str(img->get_state()); - - NebulaLog::log("ImM", Log::ERROR, oss.str()); + NebulaLog::log("ImM", Log::ERROR, "Release cloning image" + " in wrong state"); break; } @@ -564,8 +560,7 @@ int ImageManager::delete_image(int iid, string& error_str) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int ImageManager::can_clone_image( int cloning_id, - ostringstream& oss_error) +int ImageManager::can_clone_image(int cloning_id, ostringstream& oss_error) { Image * img; @@ -607,29 +602,10 @@ int ImageManager::can_clone_image( int cloning_id, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int ImageManager::clone_image(int new_id, - int cloning_id, - const string& ds_data, - string& error) +int ImageManager::set_clone_state(int new_id, int cloning_id, std::string& error) { - const ImageManagerDriver* imd = get(); - - ostringstream oss; - Image * img; - - string path; - string img_tmpl; - string* drv_msg; - - if ( imd == 0 ) - { - error = "Could not get datastore driver"; - - NebulaLog::log("ImM", Log::ERROR, error); - return -1; - } - - img = ipool->get(cloning_id, true); + int rc = 0; + Image * img = ipool->get(cloning_id, true); if (img == 0) { @@ -652,18 +628,13 @@ int ImageManager::clone_image(int new_id, } ipool->update(img); - - img->unlock(); - break; + break; case Image::USED: case Image::CLONE: img->inc_cloning(new_id); - ipool->update(img); - - img->unlock(); - break; + break; case Image::USED_PERS: case Image::INIT: @@ -671,24 +642,58 @@ int ImageManager::clone_image(int new_id, case Image::ERROR: case Image::DELETE: case Image::LOCKED: - oss << "Cannot clone image in state: " - << Image::state_to_str(img->get_state()); + error = "Cannot clone image in current state"; + rc = -1; + break; + } - error = oss.str(); - img->unlock(); - return -1; - break; + img->unlock(); + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int ImageManager::clone_image(int new_id, + int cloning_id, + const string& ds_data, + const string& extra_data, + string& error) +{ + const ImageManagerDriver* imd = get(); + + ostringstream oss; + Image * img; + + string path; + string img_tmpl; + string* drv_msg; + + if ( imd == 0 ) + { + error = "Could not get datastore driver"; + + NebulaLog::log("ImM", Log::ERROR, error); + return -1; + } + + if ( set_clone_state(new_id, cloning_id, error) == -1 ) + { + return -1; } img = ipool->get(new_id,true); - if (img == 0) //TODO: Rollback cloning counter + if (img == 0) { + release_cloning_image(cloning_id, new_id); + error = "Target image deleted during cloning operation"; return -1; } - drv_msg = format_message(img->to_xml(img_tmpl), ds_data, ""); + drv_msg = format_message(img->to_xml(img_tmpl), ds_data, extra_data); imd->clone(img->get_oid(), *drv_msg); @@ -707,7 +712,10 @@ int ImageManager::clone_image(int new_id, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int ImageManager::register_image(int iid, const string& ds_data, string& error) +int ImageManager::register_image(int iid, + const string& ds_data, + const string& extra_data, + string& error) { const ImageManagerDriver* imd = get(); @@ -734,7 +742,7 @@ int ImageManager::register_image(int iid, const string& ds_data, string& error) return -1; } - drv_msg = format_message(img->to_xml(img_tmpl), ds_data, ""); + drv_msg = format_message(img->to_xml(img_tmpl), ds_data, extra_data); path = img->get_path(); if ( path.empty() == true ) //NO PATH diff --git a/src/image/ImagePool.cc b/src/image/ImagePool.cc index 12b64c9c8e..3cf7d1b58b 100644 --- a/src/image/ImagePool.cc +++ b/src/image/ImagePool.cc @@ -34,14 +34,14 @@ string ImagePool::_default_cdrom_dev_prefix; /* -------------------------------------------------------------------------- */ ImagePool::ImagePool( - SqlDB * db, - const string& __default_type, - const string& __default_dev_prefix, - const string& __default_cdrom_dev_prefix, - vector& restricted_attrs, - vector hook_mads, - const string& remotes_location, - const vector& _inherit_attrs) + SqlDB * db, + const string& __default_type, + const string& __default_dev_prefix, + const string& __default_cdrom_dev_prefix, + vector& restricted_attrs, + vector& hook_mads, + const string& remotes_location, + const vector& _inherit_attrs) :PoolSQL(db, Image::table, true, true) { // Init static defaults @@ -51,13 +51,11 @@ ImagePool::ImagePool( _default_cdrom_dev_prefix = __default_cdrom_dev_prefix; // Init inherit attributes - vector::const_iterator it; + vector::const_iterator it; for (it = _inherit_attrs.begin(); it != _inherit_attrs.end(); it++) { - const SingleAttribute* sattr = static_cast(*it); - - inherit_attrs.push_back(sattr->value()); + inherit_attrs.push_back((*it)->value()); } // Set default type @@ -89,6 +87,7 @@ int ImagePool::allocate ( Image::DiskType disk_type, const string& ds_data, Datastore::DatastoreType ds_type, + const string& extra_data, int cloning_id, int * oid, string& error_str) @@ -102,6 +101,8 @@ int ImagePool::allocate ( string type; ostringstream oss; + int rc; + img = new Image(uid, gid, uname, gname, umask, img_template); // ------------------------------------------------------------------------- @@ -168,7 +169,9 @@ int ImagePool::allocate ( { if (cloning_id == -1) { - if ( imagem->register_image(*oid, ds_data, error_str) == -1 ) + rc = imagem->register_image(*oid, ds_data, extra_data, error_str); + + if ( rc == -1 ) { img = get(*oid, true); @@ -187,7 +190,13 @@ int ImagePool::allocate ( } else { - if (imagem->clone_image(*oid, cloning_id, ds_data, error_str) == -1) + rc = imagem->clone_image(*oid, + cloning_id, + ds_data, + extra_data, + error_str); + + if (rc == -1) { img = get(*oid, true); @@ -322,7 +331,24 @@ int ImagePool::acquire_disk(int vm_id, *snap = 0; - if (!(source = disk->vector_value("IMAGE")).empty()) + if (!(source = disk->vector_value("IMAGE_ID")).empty()) + { + iid = get_disk_id(source); + + if ( iid == -1) + { + error_str = "Wrong ID set in IMAGE_ID"; + return -1; + } + + img = imagem->acquire_image(vm_id, iid, error_str); + + if ( img == 0 ) + { + return -1; + } + } + else if (!(source = disk->vector_value("IMAGE")).empty()) { int uiid = get_disk_uid(disk,uid); @@ -346,23 +372,6 @@ int ImagePool::acquire_disk(int vm_id, iid = img->get_oid(); } - else if (!(source = disk->vector_value("IMAGE_ID")).empty()) - { - iid = get_disk_id(source); - - if ( iid == -1) - { - error_str = "Wrong ID set in IMAGE_ID"; - return -1; - } - - img = imagem->acquire_image(vm_id, iid, error_str); - - if ( img == 0 ) - { - return -1; - } - } else //Not using the image repository (volatile DISK) { string type = disk->vector_value("TYPE"); @@ -494,16 +503,7 @@ void ImagePool::disk_attribute( Nebula& nd = Nebula::instance(); DatastorePool * ds_pool = nd.get_dspool(); - if (!(source = disk->vector_value("IMAGE")).empty()) - { - int uiid = get_disk_uid(disk,uid); - - if ( uiid != -1) - { - img = get(source, uiid, true); - } - } - else if (!(source = disk->vector_value("IMAGE_ID")).empty()) + if (!(source = disk->vector_value("IMAGE_ID")).empty()) { int iid = get_disk_id(source); @@ -512,6 +512,15 @@ void ImagePool::disk_attribute( img = get(iid, true); } } + else if (!(source = disk->vector_value("IMAGE")).empty()) + { + int uiid = get_disk_uid(disk,uid); + + if ( uiid != -1) + { + img = get(source, uiid, true); + } + } if ( img != 0 ) { diff --git a/src/lcm/LifeCycleActions.cc b/src/lcm/LifeCycleActions.cc index 20e7230d7e..cef57faded 100644 --- a/src/lcm/LifeCycleActions.cc +++ b/src/lcm/LifeCycleActions.cc @@ -35,7 +35,7 @@ void LifeCycleManager::deploy_action(int vid) { time_t thetime = time(0); int cpu,mem,disk; - vector pci; + vector pci; VirtualMachine::LcmState vm_state; TransferManager::Actions tm_action; @@ -212,7 +212,7 @@ void LifeCycleManager::migrate_action(int vid) VirtualMachine * vm; int cpu, mem, disk; - vector pci; + vector pci; time_t the_time = time(0); @@ -365,7 +365,7 @@ void LifeCycleManager::live_migrate_action(int vid) vm->get_lcm_state() == VirtualMachine::RUNNING) { int cpu, mem, disk; - vector pci; + vector pci; //---------------------------------------------------- // MIGRATE STATE @@ -873,7 +873,7 @@ void LifeCycleManager::clean_action(int vid) void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& image_id) { int cpu, mem, disk; - vector pci; + vector pci; time_t the_time = time(0); VirtualMachine::LcmState state = vm->get_lcm_state(); @@ -956,7 +956,7 @@ void LifeCycleManager::clean_up_vm(VirtualMachine * vm, bool dispose, int& imag break; case VirtualMachine::HOTPLUG_NIC: - vm->clear_attach_nic(); + vm->attach_nic_success(); vmpool->update(vm); vm->set_running_etime(the_time); diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index 73e0a99c05..fe2dc68401 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -38,7 +38,7 @@ void LifeCycleManager::save_success_action(int vid) if ( vm->get_lcm_state() == VirtualMachine::SAVE_MIGRATE ) { int cpu, mem, disk; - vector pci; + vector pci; time_t the_time = time(0); @@ -157,7 +157,7 @@ void LifeCycleManager::save_failure_action(int vid) if ( vm->get_lcm_state() == VirtualMachine::SAVE_MIGRATE ) { int cpu, mem, disk; - vector pci; + vector pci; time_t the_time = time(0); @@ -261,7 +261,7 @@ void LifeCycleManager::deploy_success_action(int vid) if ( vm->get_lcm_state() == VirtualMachine::MIGRATE ) { int cpu,mem,disk; - vector pci; + vector pci; time_t the_time = time(0); @@ -335,7 +335,7 @@ void LifeCycleManager::deploy_failure_action(int vid) if ( vm->get_lcm_state() == VirtualMachine::MIGRATE ) { int cpu, mem, disk; - vector pci; + vector pci; time_t the_time = time(0); @@ -797,7 +797,7 @@ void LifeCycleManager::prolog_failure_action(int vid) void LifeCycleManager::epilog_success_action(int vid) { VirtualMachine * vm; - vector pci; + vector pci; time_t the_time = time(0); int cpu,mem,disk; @@ -1542,7 +1542,7 @@ void LifeCycleManager::attach_nic_success_action(int vid) if ( vm->get_lcm_state() == VirtualMachine::HOTPLUG_NIC ) { - vm->clear_attach_nic(); + vm->attach_nic_success(); vm->set_state(VirtualMachine::RUNNING); @@ -1574,7 +1574,7 @@ void LifeCycleManager::attach_nic_failure_action(int vid) { vm->unlock(); - vmpool->delete_attach_nic(vid); + vmpool->attach_nic_failure(vid); vm = vmpool->get(vid,true); @@ -1601,7 +1601,39 @@ void LifeCycleManager::attach_nic_failure_action(int vid) void LifeCycleManager::detach_nic_success_action(int vid) { - attach_nic_failure_action(vid); + VirtualMachine * vm; + + vm = vmpool->get(vid,true); + + if ( vm == 0 ) + { + return; + } + + if ( vm->get_lcm_state() == VirtualMachine::HOTPLUG_NIC ) + { + vm->unlock(); + + vmpool->detach_nic_success(vid); + + vm = vmpool->get(vid,true); + + if ( vm == 0 ) + { + return; + } + + vm->set_state(VirtualMachine::RUNNING); + + vmpool->update(vm); + + vm->unlock(); + } + else + { + vm->log("LCM",Log::ERROR,"detach_nic_success_action, VM in a wrong state"); + vm->unlock(); + } } /* -------------------------------------------------------------------------- */ @@ -1609,7 +1641,29 @@ void LifeCycleManager::detach_nic_success_action(int vid) void LifeCycleManager::detach_nic_failure_action(int vid) { - attach_nic_success_action(vid); + VirtualMachine * vm; + + vm = vmpool->get(vid,true); + + if ( vm == 0 ) + { + return; + } + + if ( vm->get_lcm_state() == VirtualMachine::HOTPLUG_NIC ) + { + vm->detach_nic_failure(); + + vm->set_state(VirtualMachine::RUNNING); + + vmpool->update(vm); + } + else + { + vm->log("LCM",Log::ERROR,"detach_nic_failure_action, VM in a wrong state"); + } + + vm->unlock(); } /* -------------------------------------------------------------------------- */ diff --git a/src/mad/MadManager.cc b/src/mad/MadManager.cc index a9975361ed..811510e0e6 100644 --- a/src/mad/MadManager.cc +++ b/src/mad/MadManager.cc @@ -27,7 +27,7 @@ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -MadManager::MadManager(vector& _mads):mad_conf(_mads) +MadManager::MadManager(vector& _mads):mad_conf(_mads) { pthread_mutex_init(&mutex,0); } diff --git a/src/mad/sh/scripts_common.sh b/src/mad/sh/scripts_common.sh index 52a342a38b..1ac9b6dfd4 100644 --- a/src/mad/sh/scripts_common.sh +++ b/src/mad/sh/scripts_common.sh @@ -42,6 +42,7 @@ RADOS=${RADOS:-rados} RBD=${RBD:-rbd} READLINK=${READLINK:-readlink} RM=${RM:-rm} +CP=${CP:-cp} SCP=${SCP:-scp} SED=${SED:-sed} SSH=${SSH:-ssh} diff --git a/src/market/MarketPlace.cc b/src/market/MarketPlace.cc new file mode 100644 index 0000000000..a62513dd95 --- /dev/null +++ b/src/market/MarketPlace.cc @@ -0,0 +1,434 @@ +/* ------------------------------------------------------------------------ */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------*/ + +#include +#include "MarketPlace.h" +#include "NebulaLog.h" +#include "NebulaUtil.h" +#include "Nebula.h" + +/* ************************************************************************ */ +/* MarketPlace:: Database Definition */ +/* ************************************************************************ */ + +const char * MarketPlace::table = "marketplace_pool"; + +const char * MarketPlace::db_names = + "oid, name, body, uid, gid, owner_u, group_u, other_u"; + +const char * MarketPlace::db_bootstrap = + "CREATE TABLE IF NOT EXISTS marketplace_pool (oid INTEGER PRIMARY KEY, " + "name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, gid INTEGER, " + "owner_u INTEGER, group_u INTEGER, other_u INTEGER)"; + +/* ************************************************************************ */ +/* MarketPlace:: Constructor / Destructor */ +/* ************************************************************************ */ + +MarketPlace::MarketPlace( + int uid, + int gid, + const std::string& uname, + const std::string& gname, + int umask, + MarketPlaceTemplate * mp_template): + PoolObjectSQL(-1, MARKETPLACE, "", uid, gid, uname, gname, table), + ObjectCollection("MARKETPLACEAPPS"), + market_mad(""), + total_mb(0), + free_mb(0), + used_mb(0) +{ + if (mp_template != 0) + { + obj_template = mp_template; + } + else + { + obj_template = new MarketPlaceTemplate; + } + + set_umask(umask); +}; + +MarketPlace::~MarketPlace() +{ + delete obj_template; +}; + +/* *************************************************************************** */ +/* MartketPlace :: Database Access Functions */ +/* *************************************************************************** */ + +/* -------------------------------------------------------------------------- */ + +int MarketPlace::set_market_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; + + rc = Nebula::instance().get_market_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 << "MARKET_MAD_CONF named \"" << mad << "\" is not defined in oned.conf"; + goto error_common; + +error_required: + oss << "MarketPlace template is missing the \"" << required_attr + << "\" attribute or it's empty."; + +error_common: + error_str = oss.str(); + return -1; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +int MarketPlace::insert(SqlDB *db, string& error_str) +{ + std::ostringstream oss; + + // ------------------------------------------------------------------------- + // Check default marketplace attributes + // ------------------------------------------------------------------------- + + //MarketPlacePool::allocate checks NAME + erase_template_attribute("NAME", name); + + get_template_attribute("MARKET_MAD", market_mad); + + if ( market_mad.empty() == true ) + { + goto error_mad; + } + + if (set_market_mad(market_mad, error_str) != 0) + { + goto error_common; + } + + //-------------------------------------------------------------------------- + + return insert_replace(db, false, error_str); + +error_mad: + error_str = "No marketplace driver (MARKET_MAD) in template."; + goto error_common; + +error_common: + NebulaLog::log("MKP", Log::ERROR, error_str); + return -1; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +int MarketPlace::insert_replace(SqlDB *db, bool replace, string& error_str) +{ + std::ostringstream oss; + + int rc; + std::string xml_body; + + char * sql_name; + char * sql_xml; + + sql_name = db->escape_str(name.c_str()); + + if ( sql_name == 0 ) + { + goto error_name; + } + + sql_xml = db->escape_str(to_xml(xml_body).c_str()); + + if ( sql_xml == 0 ) + { + goto error_body; + } + + if ( validate_xml(sql_xml) != 0 ) + { + goto error_xml; + } + + if ( replace ) + { + oss << "REPLACE"; + } + else + { + oss << "INSERT"; + } + + // Construct the SQL statement to Insert or Replace + oss <<" INTO "<exec(oss); + + db->free_str(sql_name); + db->free_str(sql_xml); + + return rc; + +error_xml: + db->free_str(sql_name); + db->free_str(sql_xml); + + error_str = "Error transforming the marketplace to XML."; + + goto error_common; + +error_body: + db->free_str(sql_name); + goto error_generic; + +error_name: + goto error_generic; + +error_generic: + error_str = "Error inserting marketplace in DB."; +error_common: + return -1; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +/* *************************************************************************** */ +/* MartketPlace :: Template Functions */ +/* *************************************************************************** */ +std::string& MarketPlace::to_xml(std::string& xml) const +{ + std::ostringstream oss; + std::string template_xml; + std::string collection_xml; + std::string perm_str; + + ObjectCollection::to_xml(collection_xml); + + oss << "" + "" << oid << "" << + "" << uid << "" << + "" << gid << "" << + "" << uname << "" << + "" << gname << "" << + "" << name << "" << + ""<"<< + "" << total_mb << "" << + "" << free_mb << "" << + "" << used_mb << "" << + collection_xml << + perms_to_xml(perm_str) << + obj_template->to_xml(template_xml) << + ""; + + xml = oss.str(); + + return xml; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +static void set_supported_actions(ActionSet& as, + const string& astr) +{ + std::vector actions; + std::vector::iterator vit; + + std::string action; + MarketPlaceApp::Action id; + + actions = one_util::split(astr, ','); + + for (vit = actions.begin() ; vit != actions.end() ; ++vit) + { + action = one_util::trim(*vit); + + if ( MarketPlaceApp::action_from_str(action, id) != 0 ) + { + NebulaLog::log("MKP", Log::ERROR, "Wrong action: " + action); + continue; + } + + as.set(id); + } +} + +int MarketPlace::from_xml(const std::string &xml_str) +{ + int rc = 0; + std::vector content; + + // Initialize the internal XML object + update_from_str(xml_str); + + // ----- MARKETPLACE base attributes ----- + rc += xpath(oid, "/MARKETPLACE/ID", -1); + rc += xpath(uid, "/MARKETPLACE/UID", -1); + rc += xpath(gid, "/MARKETPLACE/GID", -1); + rc += xpath(uname, "/MARKETPLACE/UNAME", "not_found"); + rc += xpath(gname, "/MARKETPLACE/GNAME", "not_found"); + rc += xpath(name, "/MARKETPLACE/NAME", "not_found"); + + rc += xpath(market_mad, "/MARKETPLACE/MARKET_MAD", "not_found"); + + rc += xpath(total_mb, "/MARKETPLACE/TOTAL_MB", 0); + rc += xpath(free_mb, "/MARKETPLACE/FREE_MB", 0); + rc += xpath(used_mb, "/MARKETPLACE/USED_MB", 0); + + // ----- Permissions ----- + rc += perms_from_xml(); + + // ----- MARKETPLACEAPP Collection ----- + ObjectXML::get_nodes("/MARKETPLACE/MARKETPLACEAPPS", content); + + if (content.empty()) + { + return -1; + } + + rc += ObjectCollection::from_xml_node(content[0]); + + ObjectXML::free_nodes(content); + + content.clear(); + + // ----- TEMPLATE ----- + ObjectXML::get_nodes("/MARKETPLACE/TEMPLATE", content); + + if (content.empty()) + { + return -1; + } + + rc += obj_template->from_xml_node(content[0]); + + ObjectXML::free_nodes(content); + + if (rc != 0) + { + return -1; + } + + // ------ SUPPORTED ACTIONS, regenerated from oned.conf ------ + const VectorAttribute* vatt; + string actions; + + if (Nebula::instance().get_market_conf_attribute(market_mad, vatt) == 0) + { + actions = vatt->vector_value("APP_ACTIONS"); + } + + if (actions.empty()) + { + if (market_mad == "http" || market_mad == "s3") + { + actions = "create, monitor, delete"; + } + else if ( market_mad == "one" ) + { + actions = "create, monitor"; + } + } + + set_supported_actions(supported_actions, actions); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlace::post_update_template(std::string& error) +{ + std::string new_market_mad; + + erase_template_attribute("MARKET_MAD", new_market_mad); + + if (!new_market_mad.empty()) + { + if (set_market_mad(new_market_mad, error) != 0) + { + add_template_attribute("MARKET_MAD", market_mad); + return -1; + } + + market_mad = new_market_mad; + } + + add_template_attribute("MARKET_MAD", market_mad); + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void MarketPlace::update_monitor(const Template& data) +{ + data.get("TOTAL_MB", total_mb); + data.get("FREE_MB", free_mb); + data.get("USED_MB", used_mb); +} + diff --git a/src/market/MarketPlaceApp.cc b/src/market/MarketPlaceApp.cc new file mode 100644 index 0000000000..00f7510c75 --- /dev/null +++ b/src/market/MarketPlaceApp.cc @@ -0,0 +1,464 @@ +/* ------------------------------------------------------------------------ */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------*/ + +#include +#include "MarketPlaceApp.h" +#include "NebulaLog.h" +#include "NebulaUtil.h" + +/* ************************************************************************ */ +/* MarketPlaceApp:: Database Definition */ +/* ************************************************************************ */ + +const char * MarketPlaceApp::table = "marketplaceapp_pool"; + +const char * MarketPlaceApp::db_names = + "oid, name, body, uid, gid, owner_u, group_u, other_u"; + +const char * MarketPlaceApp::db_bootstrap = + "CREATE TABLE IF NOT EXISTS marketplaceapp_pool (oid INTEGER PRIMARY KEY, " + "name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, gid INTEGER, " + "owner_u INTEGER, group_u INTEGER, other_u INTEGER, UNIQUE(name,uid))"; + +/* ************************************************************************ */ +/* MarketPlaceApp:: Constructor / Destructor */ +/* ************************************************************************ */ + +MarketPlaceApp::MarketPlaceApp( + int uid, + int gid, + const std::string& uname, + const std::string& gname, + int umask, + MarketPlaceAppTemplate * app_template): + PoolObjectSQL(-1, MARKETPLACEAPP, "", uid, gid, uname, gname, table), + source(""), + md5(""), + size_mb(0), + description(""), + version(""), + apptemplate64(""), + market_id(-1), + market_name(""), + state(INIT), + type(IMAGE) +{ + if (app_template != 0) + { + obj_template = app_template; + } + else + { + obj_template = new MarketPlaceAppTemplate; + } + + set_umask(umask); +}; + +MarketPlaceApp::~MarketPlaceApp() +{ + delete obj_template; +}; + +/* ************************************************************************ */ +/* MartketPlaceApp:: Database Access Functions */ +/* ************************************************************************ */ + +int MarketPlaceApp::insert(SqlDB *db, string& error_str) +{ + std::ostringstream oss; + bool imported; + + if (get_template_attribute("IMPORTED", imported) && imported) + { + return insert_replace(db, false, error_str); + } + + // ------------------------------------------------------------------------- + // Check default marketplace app attributes + // ------------------------------------------------------------------------- + + //MarketPlaceAppPool::allocate checks NAME + erase_template_attribute("NAME", name); + + //Atrributes updated after export + remove_template_attribute("SOURCE"); + remove_template_attribute("SIZE"); + remove_template_attribute("MD5"); + remove_template_attribute("FORMAT"); + remove_template_attribute("REGTIME"); + + regtime = time(NULL); + + type = IMAGE; + + //Known attributes + //ORIGIN_ID + //DESCRIPTION + //APPTEMPLATE64 + //VERSION + if (!get_template_attribute("ORIGIN_ID", origin_id)) + { + goto error_origin; + } + + remove_template_attribute("ORIGIN_ID"); + + get_template_attribute("DESCRIPTION", description); + + get_template_attribute("APPTEMPLATE64", apptemplate64); + + get_template_attribute("VERSION", version); + + if (version.empty()) + { + version = "0.0"; + } + + state = LOCKED; + + //-------------------------------------------------------------------------- + + return insert_replace(db, false, error_str); + +error_origin: + error_str = "Missing ORIGIN_ID for the MARKETPLACEAPP"; + NebulaLog::log("MKP", Log::ERROR, error_str); + return -1; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +int MarketPlaceApp::insert_replace(SqlDB *db, bool replace, string& error_str) +{ + std::ostringstream oss; + + int rc; + std::string xml_body; + + char * sql_name; + char * sql_xml; + + sql_name = db->escape_str(name.c_str()); + + if ( sql_name == 0 ) + { + goto error_name; + } + + sql_xml = db->escape_str(to_xml(xml_body).c_str()); + + if ( sql_xml == 0 ) + { + goto error_body; + } + + if ( validate_xml(sql_xml) != 0 ) + { + goto error_xml; + } + + if ( replace ) + { + oss << "REPLACE"; + } + else + { + oss << "INSERT"; + } + + // Construct the SQL statement to Insert or Replace + oss <<" INTO "<
exec(oss); + + db->free_str(sql_name); + db->free_str(sql_xml); + + return rc; + +error_xml: + db->free_str(sql_name); + db->free_str(sql_xml); + + error_str = "Error transforming the marketplace app to XML."; + + goto error_common; + +error_body: + db->free_str(sql_name); + goto error_generic; + +error_name: + goto error_generic; + +error_generic: + error_str = "Error inserting marketplace app in DB."; +error_common: + return -1; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +/* *************************************************************************** */ +/* MartketPlaceApp :: Template Functions */ +/* *************************************************************************** */ +std::string& MarketPlaceApp::to_xml(std::string& xml) const +{ + std::ostringstream oss; + std::string template_xml; + std::string perm_str; + + oss << "" + "" << oid << "" << + "" << uid << "" << + "" << gid << "" << + "" << uname << "" << + "" << gname << "" << + "" << regtime << "" << + "" << name << "" << + "" << origin_id << "" << + "" << source << "" << + "" << md5 << "" << + "" << size_mb << "" << + "" << description << "" << + "" << version << "" << + "" << format << "" << + "" << apptemplate64 << "" << + "" << market_id << "" << + "" << market_name << "" << + "" << state << "" << + "" << type << "" << + perms_to_xml(perm_str) << + obj_template->to_xml(template_xml) << + ""; + + xml = oss.str(); + + return xml; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +int MarketPlaceApp::from_xml(const std::string &xml_str) +{ + int rc = 0; + int istate; + int itype; + std::vector content; + + // Initialize the internal XML object + update_from_str(xml_str); + + // ----- MARKETPLACEAPP base attributes ----- + rc += xpath(oid, "/MARKETPLACEAPP/ID", -1); + rc += xpath(uid, "/MARKETPLACEAPP/UID", -1); + rc += xpath(gid, "/MARKETPLACEAPP/GID", -1); + rc += xpath(uname, "/MARKETPLACEAPP/UNAME", "not_found"); + rc += xpath(gname, "/MARKETPLACEAPP/GNAME", "not_found"); + rc += xpath(name, "/MARKETPLACEAPP/NAME", "not_found"); + rc += xpath(regtime,"/MARKETPLACEAPP/REGTIME", -1); + rc += xpath(source, "/MARKETPLACEAPP/SOURCE", "not_found"); + rc += xpath(origin_id, "/MARKETPLACEAPP/ORIGIN_ID", -1); + rc += xpath(istate, "/MARKETPLACEAPP/STATE", -1); + rc += xpath(itype, "/MARKETPLACEAPP/TYPE", -1); + rc += xpath(description, "/MARKETPLACEAPP/DESCRIPTION", "not_found"); + rc += xpath(size_mb, "/MARKETPLACEAPP/SIZE", -1); + rc += xpath(version, "/MARKETPLACEAPP/VERSION", "not_found"); + rc += xpath(md5, "/MARKETPLACEAPP/MD5", "not_found"); + rc += xpath(format, "/MARKETPLACEAPP/FORMAT", "not_found"); + rc += xpath(apptemplate64,"/MARKETPLACEAPP/APPTEMPLATE64", "not_found"); + rc += xpath(market_name, "/MARKETPLACEAPP/MARKETPLACE", "not_found"); + rc += xpath(market_id, "/MARKETPLACEAPP/MARKETPLACE_ID", -1); + + state = static_cast(istate); + type = static_cast(itype); + + // ----- Permissions ----- + rc += perms_from_xml(); + + // ----- TEMPLATE ----- + ObjectXML::get_nodes("/MARKETPLACEAPP/TEMPLATE", content); + + if (content.empty()) + { + return -1; + } + + rc += obj_template->from_xml_node(content[0]); + + ObjectXML::free_nodes(content); + + if (rc != 0) + { + return -1; + } + + return 0; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +int MarketPlaceApp::post_update_template(string& error) +{ + std::string n_description; + std::string n_apptemplate64; + std::string n_version; + + // ------------------------------------------------------------------------- + // Update well known attributes + // ------------------------------------------------------------------------- + get_template_attribute("DESCRIPTION", description); + get_template_attribute("APPTEMPLATE64", apptemplate64); + get_template_attribute("VERSION", version); + + // ------------------------------------------------------------------------- + // Remove non-update attributes + // ------------------------------------------------------------------------- + remove_template_attribute("SOURCE"); + remove_template_attribute("SIZE"); + remove_template_attribute("MD5"); + remove_template_attribute("FORMAT"); + remove_template_attribute("REGTIME"); + remove_template_attribute("ORIGIN_ID"); + + return 0; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +MarketPlaceApp::Type MarketPlaceApp::str_to_type(string& str_type) +{ + one_util::toupper(str_type); + + if ( str_type == "IMAGE" ) + { + return IMAGE; + } + else if ( str_type == "VMTEMPLATE" ) + { + return VMTEMPLATE; + } + else if ( str_type == "SERVICE_TEMPLATE" ) + { + return SERVICE_TEMPLATE; + } + + return UNKNOWN; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +int MarketPlaceApp::enable(bool enable, string& error_str) +{ + switch(state) + { + case INIT: + case LOCKED: + case ERROR: + break; + + case READY: + case DISABLED: + if (enable) + { + state = READY; + } + else + { + state = DISABLED; + } + break; + } + + return 0; +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +void MarketPlaceApp::to_template(Template * tmpl) const +{ + tmpl->replace("FROM_APP_NAME", get_name()); + tmpl->replace("PATH", get_source()); + tmpl->replace("FORMAT", get_format()); + tmpl->replace("MD5", get_md5()); +} + +/* --------------------------------------------------------------------------- */ +/* --------------------------------------------------------------------------- */ + +int MarketPlaceApp::from_template64(const std::string &info64, std::string& err) +{ + std::string * info = one_util::base64_decode(info64); + + if (info == 0) + { + err = "Error decoding driver message"; + return -1; + } + + char * error_msg; + + int rc = obj_template->parse(*info, &error_msg); + + delete info; + + if ( rc != 0 ) + { + err = error_msg; + + free(error_msg); + return -1; + } + + state = READY; + + type = IMAGE; + origin_id = -1; + remove_template_attribute("TYPE"); + remove_template_attribute("ORIGIN_ID"); + + erase_template_attribute("NAME", name); + erase_template_attribute("SOURCE", source); + erase_template_attribute("SIZE", size_mb); + erase_template_attribute("MD5", md5); + erase_template_attribute("FORMAT", format); + erase_template_attribute("REGTIME", regtime); + + get_template_attribute("DESCRIPTION", description); + get_template_attribute("VERSION", version); + get_template_attribute("APPTEMPLATE64", apptemplate64); + + replace_template_attribute("IMPORTED", "YES"); + + return 0; +} + diff --git a/src/market/MarketPlaceAppPool.cc b/src/market/MarketPlaceAppPool.cc new file mode 100644 index 0000000000..772c07ba9f --- /dev/null +++ b/src/market/MarketPlaceAppPool.cc @@ -0,0 +1,172 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 "MarketPlaceAppPool.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlaceAppPool:: allocate( + int uid, + int gid, + const std::string& uname, + const std::string& gname, + int umask, + MarketPlaceAppTemplate * apptemplate, + int mp_id, + const std::string& mp_name, + const std::string& mp_data, + int * oid, + std::string& error_str) +{ + MarketPlaceApp * mp; + MarketPlaceApp * mp_aux = 0; + + Nebula& nd = Nebula::instance(); + MarketPlaceManager * marketm = nd.get_marketm(); + + std::string name; + + std::ostringstream oss; + + mp = new MarketPlaceApp(uid, gid, uname, gname, umask, apptemplate); + + mp->market_id = mp_id; + mp->market_name = mp_name; + + mp->state = MarketPlaceApp::INIT; + + mp->remove_template_attribute("IMPORTED"); + + // ------------------------------------------------------------------------- + // Check name & duplicates + // ------------------------------------------------------------------------- + mp->get_template_attribute("NAME", name); + + if ( !PoolObjectSQL::name_is_valid(name, error_str) ) + { + goto error_name; + } + + mp_aux = get(name, uid, false); + + if( mp_aux != 0 ) + { + goto error_duplicated; + } + + *oid = PoolSQL::allocate(mp, error_str); + + if ( *oid != -1 ) + { + if (marketm->import_app(*oid, mp_data, error_str) == -1) + { + MarketPlaceApp * app = get(*oid, true); + + if ( app != 0 ) + { + string aux_str; + + drop(app, aux_str); + + app->unlock(); + } + + *oid = -1; + } + } + + return *oid; + +error_duplicated: + oss << "NAME is already taken by MARKETPLACEAPP " << mp_aux->get_oid(); + error_str = oss.str(); + +error_name: + delete mp; + *oid = -1; + + return *oid; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlaceAppPool::import(const std::string& t64, int mp_id, + const std::string& mp_name, std::string& error_str) +{ + MarketPlaceApp * app = new MarketPlaceApp(UserPool::ONEADMIN_ID, + GroupPool::ONEADMIN_ID, UserPool::oneadmin_name, + GroupPool::ONEADMIN_NAME, 0133, 0); + + int rc = app->from_template64(t64, error_str); + + if ( rc != 0 ) + { + delete app; + return -1; + } + + app->market_id = mp_id; + app->market_name = mp_name; + + if ( !PoolObjectSQL::name_is_valid(app->name, error_str) ) + { + std::ostringstream oss; + + oss << "imported-" << app->get_origin_id(); + app->name = oss.str(); + + if ( !PoolObjectSQL::name_is_valid(app->name, error_str) ) + { + error_str = "Cannot generate a valida name for app"; + return -1; + } + } + + MarketPlaceApp * mp_aux = get(app->name, 0, false); + + if( mp_aux != 0 ) + { + //Marketplace app already imported + delete app; + return -2; + } + + return PoolSQL::allocate(app, error_str); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlaceAppPool::update(PoolObjectSQL * objsql) +{ + if (Nebula::instance().is_federation_slave()) + { + NebulaLog::log("ONE",Log::ERROR, + "MarketPlaceAppPool::update called, but this " + "OpenNebula is a federation slave"); + + return -1; + } + + return PoolSQL::update(objsql); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + diff --git a/src/market/MarketPlaceManager.cc b/src/market/MarketPlaceManager.cc new file mode 100644 index 0000000000..4655fbd5ac --- /dev/null +++ b/src/market/MarketPlaceManager.cc @@ -0,0 +1,291 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 "MarketPlaceManager.h" +#include "MarketPlacePool.h" +#include "MarketPlaceAppPool.h" +#include "MarketPlaceManagerDriver.h" + +#include "NebulaLog.h" +#include "Nebula.h" + +const char * MarketPlaceManager::market_driver_name = "market_exe"; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +extern "C" void * marketplace_action_loop(void *arg) +{ + MarketPlaceManager * mpm; + + if ( arg == 0 ) + { + return 0; + } + + NebulaLog::log("MKP", Log::INFO, "Marketplace Manager started."); + + mpm = static_cast(arg); + + mpm->am.loop(mpm->timer_period, 0); + + NebulaLog::log("MKP", Log::INFO, "Marketplace Manager stopped."); + + return 0; +} +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +MarketPlaceManager::MarketPlaceManager( + time_t _timer_period, + time_t _monitor_period, + std::vector& _mads): + MadManager(_mads), + timer_period(_timer_period), + monitor_period(_monitor_period), + imagem(0) +{ + Nebula& nd = Nebula::instance(); + + mppool = nd.get_marketpool(); + apppool = nd.get_apppool(); + dspool = nd.get_dspool(); + ipool = nd.get_ipool(); + + am.addListener(this); +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlaceManager::load_mads(int uid) +{ + MarketPlaceManagerDriver * marketm_mad; + + std::ostringstream oss; + const VectorAttribute * vattr = 0; + + int rc; + + NebulaLog::log("MKP", Log::INFO,"Loading Marketplace Manager driver."); + + if ( mad_conf.size() > 0 ) + { + vattr = static_cast(mad_conf[0]); + } + + if ( vattr == 0 ) + { + NebulaLog::log("MKP", Log::INFO,"Failed to load Marketplace Manager driver."); + return -1; + } + + VectorAttribute market_conf("MARKET_MAD", vattr->value()); + + market_conf.replace("NAME", market_driver_name); + + marketm_mad= new MarketPlaceManagerDriver(0, market_conf.value(), false, + mppool, apppool, this); + + rc = add(marketm_mad); + + if ( rc == 0 ) + { + oss.str(""); + oss << "\tMarketplace Manager loaded"; + + NebulaLog::log("MKP", Log::INFO, oss); + } + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void MarketPlaceManager::init_managers() +{ + Nebula& nd = Nebula::instance(); + + imagem = nd.get_imagem(); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlaceManager::start() +{ + int rc; + pthread_attr_t pattr; + + rc = MadManager::start(); + + if ( rc != 0 ) + { + return -1; + } + + NebulaLog::log("ImM",Log::INFO,"Starting Marketplace Manager..."); + + pthread_attr_init (&pattr); + pthread_attr_setdetachstate (&pattr, PTHREAD_CREATE_JOINABLE); + + rc = pthread_create(&marketm_thread, &pattr, marketplace_action_loop, + (void *) this); + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void MarketPlaceManager::do_action(const string &action, void * arg) +{ + if (action == ACTION_TIMER) + { + timer_action(); + } + else if (action == ACTION_FINALIZE) + { + NebulaLog::log("MKP", Log::INFO, "Stopping Marketplace Manager..."); + MadManager::stop(); + } + else + { + std::ostringstream oss; + oss << "Unknown action name: " << action; + + NebulaLog::log("MKP", Log::ERROR, oss); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string * MarketPlaceManager::format_message( + const string& app_data, + const string& market_data, + const string& extra_data) +{ + ostringstream oss; + + oss << "" + << app_data + << market_data + << extra_data + << ""; + + return one_util::base64_encode(oss.str()); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void MarketPlaceManager::timer_action() +{ + static int mark = 0; + static int tics = monitor_period; + + mark += timer_period; + tics += timer_period; + + if ( mark >= 600 ) + { + NebulaLog::log("MKP",Log::INFO,"--Mark--"); + mark = 0; + } + + if ( tics < monitor_period ) + { + return; + } + + tics = 0; + + int rc; + + std::vector markets; + std::vector::iterator it; + + rc = mppool->list(markets); + + if ( rc != 0 ) + { + return; + } + + for(it = markets.begin() ; it != markets.end(); it++) + { + monitor_market(*it); + } + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void MarketPlaceManager::monitor_market(int mp_id) +{ + std::string mp_data; + std::string mp_name; + std::string* drv_msg; + + std::ostringstream oss; + + const MarketPlaceManagerDriver* mpmd = get(); + + if ( mpmd == 0 ) + { + oss << "Error getting MarketPlaceManagerDriver"; + + NebulaLog::log("MKP", Log::ERROR, oss); + return; + } + + MarketPlace * mp = mppool->get(mp_id, true); + + if ( mp == 0 ) + { + return; + } + + mp_name = mp->get_name(); + + if ( !mp->is_action_supported(MarketPlaceApp::MONITOR) ) + { + NebulaLog::log("MKP", Log::DEBUG, "Monitoring disabled for market: " + + mp_name); + + mp->unlock(); + + return; + } + + mp->to_xml(mp_data); + + mp->unlock(); + + drv_msg = MarketPlaceManager::format_message("", mp_data, ""); + + oss << "Monitoring marketplace " << mp_name << " (" << mp_id << ")"; + + NebulaLog::log("MKP", Log::DEBUG, oss); + + mpmd->monitor(mp_id, *drv_msg); + + delete drv_msg; +} diff --git a/src/market/MarketPlaceManagerActions.cc b/src/market/MarketPlaceManagerActions.cc new file mode 100644 index 0000000000..25e6714803 --- /dev/null +++ b/src/market/MarketPlaceManagerActions.cc @@ -0,0 +1,230 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 "MarketPlaceManager.h" +#include "MarketPlacePool.h" +#include "MarketPlaceAppPool.h" +#include "MarketPlaceManagerDriver.h" + +#include "Image.h" +#include "Datastore.h" +#include "ImageManager.h" + +#include "NebulaLog.h" +#include "Nebula.h" + + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlaceManager::import_app( + int appid, + const std::string& market_data, + std::string& err) +{ + std::string app_data, image_data, ds_data; + std::string * msg; + + Image * image; + Datastore * ds; + + int ds_id; + + const MarketPlaceManagerDriver* mpmd = get(); + + if ( mpmd == 0 ) + { + err = "Error getting MarketPlaceManagerDriver"; + return -1; + } + + MarketPlaceApp * app = apppool->get(appid, true); + + if ( app == 0 ) + { + err = "Marketplace app no longer exists"; + return -1; + } + + app->to_xml(app_data); + + MarketPlaceApp::Type type = app->get_type(); + + int app_id = app->get_oid(); + int origin_id = app->get_origin_id(); + + app->unlock(); + + switch (type) + { + case MarketPlaceApp::IMAGE: + image = ipool->get(origin_id, true); + + if ( image == 0 ) + { + err = "Image does not exist."; + return -1; + } + + image->to_xml(image_data); + + ds_id = image->get_ds_id(); + + image->unlock(); + + ds = dspool->get(ds_id, true); + + if ( ds == 0 ) + { + err = "Image datastore no longer exists."; + return -1; + } + + ds->to_xml(ds_data); + + ds->unlock(); + + if (imagem->set_clone_state(-app_id, origin_id, err) != 0) + { + return -1; + } + break; + + case MarketPlaceApp::VMTEMPLATE: + case MarketPlaceApp::SERVICE_TEMPLATE: + case MarketPlaceApp::UNKNOWN: + err = "Marketplace app type not supported."; + return -1; + } + + msg = format_message(app_data, market_data, image_data + ds_data); + + mpmd->importapp(appid, *msg); + + delete msg; + + return 0; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void MarketPlaceManager::release_app_resources(int appid) +{ + MarketPlaceApp * app = apppool->get(appid, true); + + if (app == 0) + { + return; + } + + MarketPlaceApp::Type type = app->get_type(); + + int iid = app->get_origin_id(); + + app->unlock(); + + switch (type) + { + case MarketPlaceApp::IMAGE: + imagem->release_cloning_image(iid, -appid); + return; + + case MarketPlaceApp::VMTEMPLATE: + case MarketPlaceApp::SERVICE_TEMPLATE: + case MarketPlaceApp::UNKNOWN: + return; + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlaceManager::delete_app(int appid, const std::string& market_data, + std::string& error_str) +{ + MarketPlaceApp * app; + MarketPlace * mp; + + std::string app_data; + std::string * msg; + + const MarketPlaceManagerDriver* mpmd = get(); + + if ( mpmd == 0 ) + { + error_str = "Error getting MarketPlaceManagerDriver"; + return -1; + } + + app = apppool->get(appid, true); + + if (app == 0) + { + error_str = "Marketplace app no longer exists"; + return -1; + } + + app->to_xml(app_data); + + MarketPlaceApp::Type type = app->get_type(); + MarketPlaceApp::State state = app->get_state(); + + int market_id = app->get_market_id(); + + app->unlock(); + + switch (type) + { + case MarketPlaceApp::IMAGE: + switch (state) + { + case MarketPlaceApp::LOCKED: + release_app_resources(appid); + break; + case MarketPlaceApp::INIT: + case MarketPlaceApp::READY : + case MarketPlaceApp::ERROR: + case MarketPlaceApp::DISABLED: + break; + } + break; + + case MarketPlaceApp::VMTEMPLATE: + case MarketPlaceApp::SERVICE_TEMPLATE: + case MarketPlaceApp::UNKNOWN: + return -1; + } + + mp = mppool->get(market_id, true); + + if ( mp != 0 ) + { + mp->del_marketapp(appid); + + mppool->update(mp); + + mp->unlock(); + } + + msg = format_message(app_data, market_data, ""); + + mpmd->deleteapp(appid, *msg); + + delete msg; + + return 0; +} diff --git a/src/market/MarketPlaceManagerDriver.cc b/src/market/MarketPlaceManagerDriver.cc new file mode 100644 index 0000000000..60dd9e9509 --- /dev/null +++ b/src/market/MarketPlaceManagerDriver.cc @@ -0,0 +1,484 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 "MarketPlaceManagerDriver.h" +#include "Nebula.h" +#include + +/* ************************************************************************** */ +/* Driver ASCII Protocol Implementation */ +/* ************************************************************************** */ + +void MarketPlaceManagerDriver::importapp(int oid, const std::string& msg) const +{ + std::ostringstream os; + + os << "IMPORT " << oid << " " << msg << endl; + + write(os); +} + +/* -------------------------------------------------------------------------- */ + +void MarketPlaceManagerDriver::deleteapp(int oid, const std::string& msg) const +{ + std::ostringstream os; + + os << "DELETE " << oid << " " << msg << endl; + + write(os); +} + +/* -------------------------------------------------------------------------- */ + +void MarketPlaceManagerDriver::monitor(int oid, const std::string& msg) const +{ + std::ostringstream os; + + os << "MONITOR " << oid << " " << msg << endl; + + write(os); +} + +/* ************************************************************************** */ +/* MAD Interface */ +/* ************************************************************************** */ + +static void monitor_action( + std::istringstream& is, + MarketPlacePool * marketpool, + MarketPlaceAppPool * apppool, + MarketPlaceManager * marketm, + int id, + const std::string& result) +{ + std::string info64; + std::string* info = 0; + + std::ostringstream oss; + + getline (is, info64); + + if (is.fail()) + { + oss << "Error monitoring marketplace " << id << ". Bad monitor data: " + << info64; + + NebulaLog::log("MKP", Log::ERROR, oss); + return; + } + + if (result != "SUCCESS") + { + oss << "Error monitoring datastore " << id << ": " << info64; + NebulaLog::log("MKP", Log::ERROR, oss); + + delete info; + return; + } + + info = one_util::base64_decode(info64); + + if (info == 0) + { + oss << "Error monitoring marketplace " << id << ". Bad monitor data: " + << info64; + + NebulaLog::log("MKP", Log::ERROR, oss); + return; + } + + + Template monitor_data; + + char * error_msg; + int rc = monitor_data.parse(*info, &error_msg); + + delete info; + + if ( rc != 0 ) + { + oss << "Error parsing marketplace information: " << error_msg + << ". Monitoring information: " << endl << *info; + + NebulaLog::log("MKP", Log::ERROR, oss); + + free(error_msg); + return; + } + + std::string name; + MarketPlace * market = marketpool->get(id, true); + + if (market == 0 ) + { + return; + } + + name = market->get_name(); + + market->update_monitor(monitor_data); + + marketpool->update(market); + + market->unlock(); + + std::vector apps; + std::string err; + + int num = monitor_data.get("APP", apps); + + for (int i=0; i< num ; i++) + { + int rc = apppool->import(apps[i]->value(), id, name, err); + + if ( rc == -1 ) + { + NebulaLog::log("MKP", Log::ERROR, "Error importing app: " + err); + } + else if ( rc >= 0 ) //-2 means app already imported + { + MarketPlace * market = marketpool->get(id, true); + + market->add_marketapp(rc); + + marketpool->update(market); + + market->unlock(); + } + } + + oss << "Marketplace " << name << " (" << id << ") successfully monitored."; + + NebulaLog::log("MKP", Log::DEBUG, oss); + + return; +} + +/* -------------------------------------------------------------------------- */ +/* Helper functions for failure and error conditions */ +/* -------------------------------------------------------------------------- */ + +static void set_failure_response( + std::istringstream * is, + PoolObjectSQL * obj, + const std::string& msg) +{ + std::ostringstream oss; + std::string info; + + oss << msg; + + getline(*is, info); + + if (!info.empty() && (info[0] != '-')) + { + oss << ": " << info; + } + + if (obj != 0) + { + obj->set_template_error_message(oss.str()); + } + + NebulaLog::log("MKP", Log::ERROR, oss); +} + +static void app_failure_action( + std::istringstream * is, + MarketPlaceAppPool * apppool, + int id, + const std::string& msg) +{ + MarketPlaceApp * app = apppool->get(id, true); + + if (app == 0) + { + return; + } + + if ( is == 0) + { + app->set_template_error_message(msg); + + NebulaLog::log("MKP", Log::ERROR, msg); + } + else + { + set_failure_response(is, app, msg); + } + + app->set_state(MarketPlaceApp::ERROR); + + apppool->update(app); + + app->unlock(); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +static int import_action( + std::istringstream& is, + MarketPlaceAppPool * apppool, + MarketPlaceManager * marketm, + int id, + const std::string& result) +{ + bool rc; + int rci; + + std::string error; + std::string info64; + std::string * info; + + MarketPlaceApp * app; + MarketPlaceAppTemplate tmpl; + + std::string source; + std::string checksum; + std::string format; + long long size_mb; + + marketm->release_app_resources(id); + + if ( result == "FAILURE" ) + { + app_failure_action(&is, apppool, id, "Error importing app into marketplace"); + return -1; + } + + getline(is, info64); + + if (is.fail()) + { + goto error_parse; + } + + info = one_util::base64_decode(info64); + + if ( info == 0 ) + { + goto error_decode64; + } + + rci = tmpl.parse_str_or_xml(*info, error); + + delete info; + + if ( rci != 0 ) + { + goto error_parse_template; + } + + tmpl.get("SOURCE", source); + tmpl.get("MD5", checksum); + tmpl.get("FORMAT", format); + rc = tmpl.get("SIZE", size_mb); + + if ( source.empty() || checksum.empty() || format.empty() || rc == false ) + { + goto error_attributes; + } + + app = apppool->get(id, true); + + if (app == 0) + { + goto error_app; + } + + app->set_source(source); + app->set_md5(checksum); + app->set_size(size_mb); + app->set_format(format); + + app->set_state(MarketPlaceApp::READY); + + apppool->update(app); + + app->unlock(); + + NebulaLog::log("MKP", Log::INFO, "Marketplace app successfully imported"); + + return 0; + +error_parse: + app_failure_action(0, apppool, id, + "Error importing app into marketplace. Wrong message from driver."); + return -1; + +error_decode64: + app_failure_action(0, apppool, id, + "Error importing app into marketplace. Bad base64 encoding."); + return -1; + +error_parse_template: + app_failure_action(0, apppool, id, + "Error importing app into marketplace. Parse error: " + error); + return -1; + +error_attributes: + app_failure_action(0, apppool, id, + "Error importing app into marketplace. Missing app atributes."); + return -1; + +error_app: + NebulaLog::log("MKP", Log::ERROR, "Marketplace app successfully imported " + "but it no longer exists. You may need to manually remove: " + source); + return -1; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +static int delete_action( + std::istringstream& is, + MarketPlaceAppPool * apppool, + MarketPlaceManager * marketm, + int id, + const std::string& result) +{ + int rc; + + std::string source; + std::string error; + + std::ostringstream eoss("Error removing app from marketplace"); + + MarketPlaceApp * app = apppool->get(id, true); + + if ( app == 0 ) + { + return -1; + } + + source = app->get_source(); + + rc = apppool->drop(app, error); + + app->unlock(); + + if ( result == "FAILURE" ) + { + std::string info; + + getline(is, info); + + if (!info.empty() && (info[0] != '-')) + { + eoss << ": " << info; + } + + eoss << "."; + } + + if ( rc < 0 ) + { + eoss << " Error removing app from DB: " << error + << ". Remove app manually, source is: " << source; + } + + if ( rc < 0 || result == "FAILURE" ) + { + NebulaLog::log("MKP", Log::ERROR, eoss.str()); + } + else + { + NebulaLog::log("MKP",Log::INFO,"Marketplace app successfully removed."); + } + + return rc; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void MarketPlaceManagerDriver::protocol(const string& message) const +{ + std::istringstream is(message); + std::ostringstream oss; + + std::string action; + std::string result; + std::string info; + + int id; + + oss << "Message received: " << message; + NebulaLog::log("MKP", Log::DDEBUG, oss); + + // --------------------- Parse the driver message -------------------------- + + if ( is.good() ) + is >> action >> ws; + else + return; + + if ( is.good() ) + is >> result >> ws; + else + return; + + if ( is.good() ) + { + is >> id >> ws; + + if ( is.fail() ) + { + if ( action == "LOG" ) + { + is.clear(); + getline(is,info); + + NebulaLog::log("MKP",log_type(result[0]), info.c_str()); + } + + return; + } + } + else + return; + + if (action == "IMPORT") + { + import_action(is, apppool, marketm, id, result); + } + else if (action == "DELETE") + { + delete_action(is, apppool, marketm, id, result); + } + else if (action == "MONITOR") + { + monitor_action(is, marketpool, apppool, marketm, id, result); + } + else if (action == "LOG") + { + getline(is,info); + NebulaLog::log("MKP", log_type(result[0]), info.c_str()); + } + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void MarketPlaceManagerDriver::recover() +{ + NebulaLog::log("MKP",Log::INFO,"Recovering MarketPlace drivers"); +} + diff --git a/src/market/MarketPlacePool.cc b/src/market/MarketPlacePool.cc new file mode 100644 index 0000000000..470fdcfb06 --- /dev/null +++ b/src/market/MarketPlacePool.cc @@ -0,0 +1,171 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 "MarketPlacePool.h" +#include "User.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ + +MarketPlacePool::MarketPlacePool(SqlDB * db) + :PoolSQL(db, MarketPlace::table, true, true) +{ + //lastOID is set in PoolSQL::init_cb + if (get_lastOID() == -1) + { + // Build the default default security group + string default_market = + "NAME=\"OpenNebula Public\"\n" + "MARKET_MAD=one\n" + "DESCRIPTION=\"OpenNebula Systems MarketPlace\""; + + Nebula& nd = Nebula::instance(); + UserPool * upool = nd.get_upool(); + User * oneadmin = upool->get(0, false); + + string error; + + MarketPlaceTemplate * default_tmpl = new MarketPlaceTemplate; + char * error_parse; + + default_tmpl->parse(default_market, &error_parse); + + MarketPlace * marketplace = new MarketPlace( + oneadmin->get_uid(), + oneadmin->get_gid(), + oneadmin->get_uname(), + oneadmin->get_gname(), + oneadmin->get_umask(), + default_tmpl); + + marketplace->set_permissions(1,1,1, 1,0,0, 1,0,0, error); + + if (PoolSQL::allocate(marketplace, error) < 0) + { + ostringstream oss; + oss << "Error trying to create default " + << "OpenNebula Systems MarketPlace: " << error; + NebulaLog::log("MKP", Log::ERROR, oss); + + throw runtime_error(oss.str()); + } + + // The first 100 IDs are reserved for system MarketPlaces. + // Regular ones start from ID 100 + + set_update_lastOID(99); + } + + return; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlacePool::allocate( + int uid, + int gid, + const std::string& uname, + const std::string& gname, + int umask, + MarketPlaceTemplate * mp_template, + int * oid, + std::string& error_str) +{ + MarketPlace * mp; + MarketPlace * mp_aux = 0; + + std::string name; + + ostringstream oss; + + mp = new MarketPlace(uid, gid, uname, gname, umask, mp_template); + + // ------------------------------------------------------------------------- + // Check name & duplicates + // ------------------------------------------------------------------------- + + mp->get_template_attribute("NAME", name); + + if ( !PoolObjectSQL::name_is_valid(name, error_str) ) + { + goto error_name; + } + + mp_aux = get(name, false); + + if( mp_aux != 0 ) + { + goto error_duplicated; + } + + *oid = PoolSQL::allocate(mp, error_str); + + return *oid; + +error_duplicated: + oss << "NAME is already taken by MARKETPLACE " << mp_aux->get_oid(); + error_str = oss.str(); + +error_name: + delete mp; + *oid = -1; + + return *oid; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlacePool::drop(PoolObjectSQL * objsql, std::string& error_msg) +{ + MarketPlace *mp = static_cast(objsql); + + if( mp->get_collection_size() > 0 ) + { + std::ostringstream oss; + + oss << "MarketPlace " << mp->get_oid() << " is not empty."; + error_msg = oss.str(); + + NebulaLog::log("MARKETPLACE", Log::ERROR, error_msg); + + return -3; + } + + return PoolSQL::drop(objsql, error_msg); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlacePool::update(PoolObjectSQL * objsql) +{ + if (Nebula::instance().is_federation_slave()) + { + NebulaLog::log("ONE",Log::ERROR, + "MarketPlacePool::update called, but this " + "OpenNebula is a federation slave"); + + return -1; + } + + return PoolSQL::update(objsql); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + diff --git a/src/market/SConstruct b/src/market/SConstruct new file mode 100644 index 0000000000..2690a2a4ea --- /dev/null +++ b/src/market/SConstruct @@ -0,0 +1,35 @@ +# SConstruct for src/datastore + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#--------------------------------------------------------------------------- # + +Import('env') + +lib_name='nebula_marketplace' + +# Sources to generate the library +source_files=[ + 'MarketPlace.cc', + 'MarketPlacePool.cc', + 'MarketPlaceApp.cc', + 'MarketPlaceAppPool.cc', + 'MarketPlaceManager.cc', + 'MarketPlaceManagerDriver.cc', + 'MarketPlaceManagerActions.cc' +] + +# Build library +env.StaticLibrary(lib_name, source_files) diff --git a/src/market_mad/one_market b/src/market_mad/one_market new file mode 100755 index 0000000000..43f334f60f --- /dev/null +++ b/src/market_mad/one_market @@ -0,0 +1,38 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +#Setup driver variables +DRIVER_NAME=`basename $0 | cut -d. -f1` + +if [ -z "${ONE_LOCATION}" ]; then + MADCOMMON=/usr/lib/one/mads/madcommon.sh + VAR_LOCATION=/var/lib/one +else + MADCOMMON=$ONE_LOCATION/lib/mads/madcommon.sh + VAR_LOCATION=$ONE_LOCATION/var +fi + +. $MADCOMMON + +# Go to var directory ONE_LOCATION/var or /var/lib/one +cd $VAR_LOCATION + +LOG_FILE=$DRIVER_NAME + +# Execute the actual MAD +execute_mad $* diff --git a/src/market_mad/one_market.rb b/src/market_mad/one_market.rb new file mode 100755 index 0000000000..4186d16141 --- /dev/null +++ b/src/market_mad/one_market.rb @@ -0,0 +1,305 @@ +#!/usr/bin/env ruby + +# ---------------------------------------------------------------------------- +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Set up the environment for the driver +# ---------------------------------------------------------------------------- + +ONE_LOCATION = ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION = "/usr/lib/one/ruby" + VAR_LOCATION = "/var/lib/one" +else + RUBY_LIB_LOCATION = ONE_LOCATION + "/lib/ruby" + VAR_LOCATION = ONE_LOCATION + "/var" +end + +$: << RUBY_LIB_LOCATION + +require "OpenNebulaDriver" +require 'getoptlong' +require 'base64' +require 'rexml/document' +require 'opennebula' + +# This class provides basic messaging and logging functionality to implement +# Marketplace Drivers. A marketplace driver specialize the OpenNebula behavior +# to interface with different object or file stores. +class MarketPlaceDriver < OpenNebulaDriver + + # Market Driver Protocol constants + ACTION = { + :import => "IMPORT", + :delete => "DELETE", + :log => "LOG", + :monitor => "MONITOR", + :export => "EXPORT" #For Datastore export action + } + + # XPATHs for driver messages + MARKETPLACE_XPATH = '/MARKET_DRIVER_ACTION_DATA/MARKETPLACE' + MARKETPLACEAPP_XPATH = '/MARKET_DRIVER_ACTION_DATA/MARKETPLACEAPP' + + # Register default actions for the protocol + def initialize(market_type, options={}) + @options={ + :concurrency => 10, + :threaded => true, + :retries => 0, + :local_actions => { + ACTION[:import] => nil, + ACTION[:delete] => nil, + ACTION[:log] => nil, + ACTION[:monitor] => nil + } + }.merge!(options) + + super("market/", @options) + + if market_type == nil + @types = Dir["#{@local_scripts_path}/*/"].map do |d| + d.split('/')[-1] + end + elsif market_type.class == String + @types = [marke_type] + else + @types = market_type + end + + @local_ds_scripts_path = File.join(@local_scripts_base_path, 'datastore/') + + @one = OpenNebula::Client.new() + + register_action(ACTION[:import].to_sym, method("import")) + register_action(ACTION[:delete].to_sym, method("delete")) + register_action(ACTION[:monitor].to_sym,method("monitor")) + end + + ############################################################################ + # Import a marketplace app into the marketplace. This is a two step process: + # 1- The associated datastore_mad/export script is invoked to generate + # a file representation of the app. + # 2- The resulting file path is used to import it into the marketplace + # invoking marketplace_mad/import. + ############################################################################ + def import(id, drv_message) + xml = decode(drv_message) + + if xml.nil? + failure(:import, id, "Cannot decode driver message") + return + end + + type = xml['MARKETPLACEAPP/TYPE'] + origin = xml['MARKETPLACEAPP/ORIGIN_ID'] + mp_mad = xml['MARKETPLACE/MARKET_MAD'] + + if type.nil? || origin.nil? || mp_mad.nil? + failure(:import, id, "Wrong driver message format") + return + end + + case OpenNebula::MarketPlaceApp::MARKETPLACEAPP_TYPES[type.to_i] + #----------------------------------------------------------------------- + # Export marketplace origin to a file path, IMAGE + #----------------------------------------------------------------------- + when "IMAGE" then + # ------------ Execute export action from Datastore ---------------- + ds_mad = xml['DATASTORE/DS_MAD'] + + if ds_mad.nil? + failure(:import, id, "Wrong driver message format") + return + end + + ds_msg = ""\ + "#{xml.element_xml('IMAGE')}"\ + "#{xml.element_xml('DATASTORE')}"\ + "" + + ds_msg64 = Base64::strict_encode64(ds_msg) + + result, info = do_action(id, nil, ds_mad, :export, + "#{ds_msg64} #{id}", false) + + if ( result == RESULT[:failure] ) + failure(:import, id, "Error exporting image to file: #{info}") + return + end + + info_doc = OpenNebula::XMLElement.new + info_doc.initialize_xml(info, 'IMPORT_INFO') + #----------------------------------------------------------------------- + # Only IMAGE type is supported + # when "VMTEMPLATE" + # when "SERVICE_TEMPLATE" + #----------------------------------------------------------------------- + else + failure(:import, id, "Type #{apptype} not supported") + return + end + + # --------------- Import image app into the marketplace ---------------- + xml.add_element('/MARKET_DRIVER_ACTION_DATA', + 'IMPORT_SOURCE' => "#{info_doc['IMPORT_SOURCE']}", + 'MD5' => "#{info_doc['MD5']}", + 'SIZE' => "#{info_doc['SIZE']}", + 'FORMAT' => "#{info_doc['FORMAT']}", + 'DISPOSE' => "#{info_doc['DISPOSE']}") + + mp_msg64 = Base64::strict_encode64(xml.to_xml) + + rc, info = do_action(id, mp_mad, nil, :import, "#{mp_msg64} #{id}",true) + + send_message(ACTION[:import], rc, id, info) + end + + ############################################################################ + # Deletes an app from the marketplace + ############################################################################ + def delete(id, drv_message) + xml = decode(drv_message) + + if xml.nil? + failure(:import, id, "Cannot decode driver message") + return + end + + mp_mad = xml['MARKETPLACE/MARKET_MAD'] + + if mp_mad.nil? + failure(:delete, id, "Wrong driver message format") + return + end + + rc, info = do_action(id,mp_mad,nil,:delete,"#{drv_message} #{id}",false) + + send_message(ACTION[:delete], rc, id, info) + end + + ############################################################################ + # Monitor the marketplace. It gathers information about usage and app status + ############################################################################ + def monitor(id, drv_message) + xml = decode(drv_message) + + if xml.nil? + failure(:monitor, id, "Cannot decode driver message") + return + end + + mp_mad = xml['MARKETPLACE/MARKET_MAD'] + + if mp_mad.nil? + failure(:monitor, id, "Wrong driver message format") + return + end + + rc, info = do_action(id,mp_mad,nil,:monitor,"#{drv_message} #{id}",true) + + send_message(ACTION[:monitor], rc, id, info) + end + + private + + # Check if the selected marketplace driver is enabled in the configuration + def is_available?(market, id, action) + if @types.include?(market) + return true + else + send_message(ACTION[action], RESULT[:failure], id, + "Marketplace driver '#{market}' not available") + return false + end + end + + #Execute marketplace or datastore actions for + # @param id of the app + # @param market driver to use + # @param datastore driver to use + # @param action to invoke from the driver + # @param arguments for the action + # @return result and info of the action + def do_action(id, market, datastore, action, arguments, encode) + + if !datastore.nil? + path = File.join(@local_ds_scripts_path, datastore) + else + return if not is_available?(market, id, action) + path = File.join(@local_scripts_path, market) + end + + cmd = File.join(path, ACTION[action].downcase) + cmd << " " << arguments + + rc = LocalCommand.run(cmd, log_method(id)) + + result, info = get_info_from_execution(rc) + + info = Base64::strict_encode64(info) if encode && result != RESULT[:failure] + + return result, info + end + + # Decodes the core message and returns the app and market information as + # xml documents + def decode(drv_message) + msg = Base64.decode64(drv_message) + doc = OpenNebula::XMLElement.new + doc.initialize_xml(msg, 'MARKET_DRIVER_ACTION_DATA') + + doc = nil if doc.xml_nil? + + return doc + end + + def failure(asym, id, message) + send_message(ACTION[asym], RESULT[:failure], id, message) + end +end + +################################################################################ +################################################################################ +# DatastoreDriver Main program +################################################################################ +################################################################################ + +opts = GetoptLong.new( + [ '--threads', '-t', GetoptLong::OPTIONAL_ARGUMENT ], + [ '--market-types', '-m', GetoptLong::OPTIONAL_ARGUMENT ] +) + +mp_type = nil +threads = 15 + +begin + opts.each do |opt, arg| + case opt + when '--threads' + threads = arg.to_i + when '--market-types' + mp_type = arg.split(',').map {|a| a.strip } + end + end +rescue Exception => e + exit(-1) +end + +mp_driver = MarketPlaceDriver.new(mp_type, :concurrency => threads) +mp_driver.start_driver + diff --git a/src/market_mad/remotes/http/delete b/src/market_mad/remotes/http/delete new file mode 100755 index 0000000000..c651bab702 --- /dev/null +++ b/src/market_mad/remotes/http/delete @@ -0,0 +1,81 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +# -------------------------------------------------------------------------- # + +############################################################################### +# This script is used to import a file into the marketplace. The source file +# is an opaque representation of an OpenNebula object, like a image file or a +# tar.gz with several vm template or flow disk images +############################################################################### + +# -------- Set up the environment to source common tools & conf ------------ + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +DRIVER_PATH=$(dirname $0) +source ${DRIVER_PATH}/../../datastore/libfs.sh + +UTILS_PATH="${DRIVER_PATH}/../../datastore" + +# -------- Get arguments from OpenNebula core ------------ + +DRV_ACTION=$1 +ID=$2 + +XPATH="$UTILS_PATH/xpath.rb -b $DRV_ACTION" + +unset i XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <($XPATH /MARKET_DRIVER_ACTION_DATA/MARKETPLACEAPP/SOURCE \ + /MARKET_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/BASE_URL \ + /MARKET_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/BRIDGE_LIST \ + /MARKET_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/PUBLIC_DIR) +unset i + +SOURCE="${XPATH_ELEMENTS[i++]}" +BASE_URL="${XPATH_ELEMENTS[i++]}" +BRIDGE_LIST="${XPATH_ELEMENTS[i++]}" +PUBLIC_DIR="${XPATH_ELEMENTS[i++]}" + +# ----------------- Delete the app source from public folder ------------------- +APPNAME=${SOURCE##${BASE_URL}} +DST_PATH="${PUBLIC_DIR}/${APPNAME}" + +if [ -n "$BRIDGE_LIST" ]; then + DST_HOST=`get_destination_host $ID` + + ssh_exec_and_log "${DST_HOST}" "[ -f ${DST_PATH} ] && rm -rf ${DST_PATH}" \ + "Error deleting ${DST_PATH} in ${DST_HOST}" +else + if [ -f ${DST_PATH} ] + then + log "Removing ${DST_PATH} from the marketplace" + + exec_and_log "rm -rf ${DST_PATH}" "Error deleting ${DST_PATH}" + else + log_error "Bad formed or unavailable app source: ${DST_PATH}" + exit 1 + fi +fi diff --git a/src/market_mad/remotes/http/import b/src/market_mad/remotes/http/import new file mode 100755 index 0000000000..baf140ea63 --- /dev/null +++ b/src/market_mad/remotes/http/import @@ -0,0 +1,101 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +# -------------------------------------------------------------------------- # + +############################################################################### +# This script is used to import a file into the marketplace. The source file +# is an opaque representation of an OpenNebula object, like a image file or a +# tar.gz with several vm template or flow disk images +############################################################################### + +# -------- Set up the environment to source common tools & conf ------------ + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +DRIVER_PATH=$(dirname $0) +source ${DRIVER_PATH}/../../datastore/libfs.sh + +UTILS_PATH="${DRIVER_PATH}/../../datastore" + +# -------- Get arguments from OpenNebula core ------------ + +DRV_ACTION=$1 +ID=$2 + +XPATH="$UTILS_PATH/xpath.rb -b $DRV_ACTION" + +unset i XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <($XPATH /MARKET_DRIVER_ACTION_DATA/IMPORT_SOURCE \ + /MARKET_DRIVER_ACTION_DATA/FORMAT \ + /MARKET_DRIVER_ACTION_DATA/DISPOSE \ + /MARKET_DRIVER_ACTION_DATA/SIZE \ + /MARKET_DRIVER_ACTION_DATA/MD5 \ + /MARKET_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/BASE_URL \ + /MARKET_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/BRIDGE_LIST \ + /MARKET_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/PUBLIC_DIR) +unset i + +IMPORT_SOURCE="${XPATH_ELEMENTS[i++]}" +FORMAT="${XPATH_ELEMENTS[i++]}" +DISPOSE="${XPATH_ELEMENTS[i++]}" +SIZE="${XPATH_ELEMENTS[i++]}" +MD5="${XPATH_ELEMENTS[i++]}" +BASE_URL="${XPATH_ELEMENTS[i++]}" +BRIDGE_LIST="${XPATH_ELEMENTS[i++]}" +PUBLIC_DIR="${XPATH_ELEMENTS[i++]}" + +# -------- Copy source to public folder an generarte App data ------------ + +APPNAME=`generate_image_hash` +DST_PATH="${PUBLIC_DIR%/}/${APPNAME}" +SOURCE="${BASE_URL%/}/${APPNAME}" + +if [ -n "$BRIDGE_LIST" ]; then + DST_HOST=`get_destination_host $ID` + CP_CMD="$UTILS_PATH/downloader.sh ${IMPORT_SOURCE} -" + + exec_and_log "eval $CP_CMD | $SSH ${DST_HOST} $DD of=${DST_PATH} bs=64k" \ + "Error dumping ${IMPORT_SOURCE} to ${DST_HOST}:${DST_PATH}" + + #if [ "${DISPOSE}" = "YES" ]; then + #TODO This should call a ds operation + #fi +else + CP_CMD="$UTILS_PATH/downloader.sh ${IMPORT_SOURCE} ${DST_PATH}" + exec_and_log "$CP_CMD" "Error copying ${IMPORT_SOURCE} to ${DST_PATH}" + + if [ "${DISPOSE}" = "YES" ]; then + #TODO This should call a ds operation + exec_and_log "$RM ${IMPORT_SOURCE}" "Error removing ${IMPORT_SOURCE}" + fi +fi + +cat << EOF +SOURCE="$SOURCE" +MD5="$MD5" +SIZE="$SIZE" +FORMAT="$FORMAT" +EOF diff --git a/src/market_mad/remotes/http/monitor b/src/market_mad/remotes/http/monitor new file mode 100755 index 0000000000..0a9ef8bdaf --- /dev/null +++ b/src/market_mad/remotes/http/monitor @@ -0,0 +1,90 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +############################################################################### +# This script is used to monitor the free and used space of a marketplace +############################################################################### + +# -------- Set up the environment to source common tools & conf ------------ + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +DRIVER_PATH=$(dirname $0) +source ${DRIVER_PATH}/../../datastore/libfs.sh + +UTILS_PATH="${DRIVER_PATH}/../../datastore" + +# -------- Get arguments from OpenNebula core ------------ + +DRV_ACTION=$1 +ID=$2 + +XPATH="$UTILS_PATH/xpath.rb -b $DRV_ACTION" + +unset i XPATH_ELEMENTS + +while IFS= read -r -d '' element; do + XPATH_ELEMENTS[i++]="$element" +done < <($XPATH /MARKET_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/BRIDGE_LIST \ + /MARKET_DRIVER_ACTION_DATA/MARKETPLACE/TEMPLATE/PUBLIC_DIR) +unset i + +BRIDGE_LIST="${XPATH_ELEMENTS[i++]}" +PUBLIC_DIR="${XPATH_ELEMENTS[i++]}" + +# ------------ Compute datastore usage ------------- + +MONITOR_SCRIPT=$(cat </dev/null | tail -n 1 | awk '{print \$3}') +TOTAL_MB=\$(df -B1M -P ${PUBLIC_DIR} 2>/dev/null | tail -n 1 | awk '{print \$2}') +FREE_MB=\$(expr \$TOTAL_MB - \$USED_MB) + +if [ -z "\$USED_MB" -o -z "\$TOTAL_MB" -o -z "\$FREE_MB" ]; then + msg="Empty value found" + echo "\$msg: USED_MB=\$USED_MB, TOTAL_MB=\$TOTAL_MB, FREE_MB=\$FREE_MB" + exit 1 +fi + +echo "USED_MB=\$USED_MB" +echo "FREE_MB=\$FREE_MB" +echo "TOTAL_MB=\$TOTAL_MB" +EOF +) + +if [ -n "$BRIDGE_LIST" ]; then + HOST=`get_destination_host` + MONITOR_DATA=$(ssh_monitor_and_log "$HOST" "$MONITOR_SCRIPT" "Remote monitor script" 2>&1) +else + MONITOR_DATA=$(monitor_and_log "$MONITOR_SCRIPT" "Monitor script" 2>&1) +fi + +MONITOR_STATUS=$? + +if [ "$MONITOR_STATUS" = "0" ]; then + echo "$MONITOR_DATA" | tr ' ' '\n' + exit 0 +else + echo "$MONITOR_DATA" + exit $MONITOR_STATUS +fi diff --git a/src/market_mad/remotes/one/delete b/src/market_mad/remotes/one/delete new file mode 100755 index 0000000000..4c8d775233 --- /dev/null +++ b/src/market_mad/remotes/one/delete @@ -0,0 +1,29 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +# -------------------------------------------------------------------------- # + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +error_message "Cannot delete app from OpenNebula marketplace" + +exit -1 diff --git a/src/market_mad/remotes/one/import b/src/market_mad/remotes/one/import new file mode 100755 index 0000000000..e436d9a627 --- /dev/null +++ b/src/market_mad/remotes/one/import @@ -0,0 +1,29 @@ +#!/bin/bash + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +# -------------------------------------------------------------------------- # + +if [ -z "${ONE_LOCATION}" ]; then + LIB_LOCATION=/usr/lib/one +else + LIB_LOCATION=$ONE_LOCATION/lib +fi + +. $LIB_LOCATION/sh/scripts_common.sh + +error_message "Cannot import app into OpenNebula marketplace" + +exit -1 diff --git a/src/market_mad/remotes/one/monitor b/src/market_mad/remotes/one/monitor new file mode 100755 index 0000000000..f05b183a53 --- /dev/null +++ b/src/market_mad/remotes/one/monitor @@ -0,0 +1,157 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +# -------------------------------------------------------------------------- # + +require 'net/http' +require 'uri' +require 'json' +require 'base64' +require 'rexml/document' + +class OneMarket + ONE_MARKET_URL = 'http://marketplace.opennebula.systems/' + AGENT = 'Market Driver' + VERSION = File.dirname(__FILE__) + '/../../VERSION' + + def initialize(url) + @url = url || ONE_MARKET_URL + @agent = "OpenNebula #{File.read(VERSION)} (#{AGENT})" + end + + def get(path) + uri = URI(@url + path) + req = Net::HTTP::Get.new(uri.request_uri) + + req['User-Agent'] = @agent + + response = Net::HTTP.start(uri.hostname, uri.port) {|http| + http.request(req) + } + + if response.is_a? Net::HTTPSuccess + return 0, response.body + else + return response.code.to_i, response.msg + end + end + + def get_appliances() + rc, body = get('/appliance') + + if rc != 0 + return rc, body + end + + applist = JSON.parse(body) + appstr = "" + + applist['appliances'].each { |app| + id = app["_id"]["$oid"] + source = "#{@url}/appliance/#{id}/download/0" + + tmpl = "" + + print_var(tmpl, "NAME", app["name"]) + print_var(tmpl, "SOURCE", source) + print_var(tmpl, "IMPORT_ID", id) + print_var(tmpl, "ORIGIN_ID", "-1") + print_var(tmpl, "TYPE", "IMAGE") + print_var(tmpl, "PUBLISHER", app["publisher"]) + print_var(tmpl, "FORMAT", app["format"]) + print_var(tmpl, "DESCRIPTION", app["short_description"]) + print_var(tmpl, "VERSION", app["version"]) + print_var(tmpl, "TAGS", app["tags"].join(', ')) + print_var(tmpl, "REGTIME", app["creation_time"]) + + if !app["files"].nil? && !app["files"][0].nil? + file = app["files"][0] + size = 0 + + if (file["size"].to_i != 0) + size = file["size"].to_i / (2**20) + end + + print_var(tmpl, "SIZE", size) + print_var(tmpl, "MD5", file["md5"]) + + tmpl64 = "" + print_var(tmpl64, "DEV_PREFIX", file["dev_prefix"]) + print_var(tmpl64, "DRIVER", file["driver"]) + print_var(tmpl64, "TYPE", file["type"]) + + if !tmpl64.empty? + print_var(tmpl64, "APPTEMPLATE64", Base64::strict_encode64(tmpl64)) + end + end + + if !app["opennebula_template"].nil? + vmtmpl64 = template_to_str(JSON.parse(app["opennebula_template"])) + print_var(tmpl, "VMTEMPLATE64", Base64::strict_encode64(vmtmpl64)) + end + + appstr << "APP=\"#{Base64::strict_encode64(tmpl)}\"\n" + } + + appstr + end + + private + + def print_var(str, name, val) + return if val.nil? + return if val.class == String && val.empty? + + val.gsub!('"','\"') if val.class == String + + str << "#{name}=\"#{val}\"\n" + end + + def template_to_str(thash) + thash.collect do |key, value| + next if value.nil? || value.empty? + + str = case value.class.name + when "Hash" + attr = "#{key.to_s.upcase} = [ " + + attr << value.collect do |k, v| + next if v.nil? || v.empty? + "#{k.to_s.upcase} =\"#{v.to_s}\"" + end.compact.join(",") + + attr << "]\n" + when "String" + "#{key.to_s.upcase} = \"#{value.to_s}\"" + end + end.compact.join("\n") + end +end + +################################################################################ +# Main Program. Outpust the list of marketplace appliances +################################################################################ + +begin + drv_message = Base64::decode64(ARGV[0]) + doc = REXML::Document.new(drv_message).root + url = doc.elements['MARKETPLACE/TEMPLATE/ENDPOINT'].text rescue nil +rescue Exception +end + +#TODO get marketplace URL from MARKETPLACE Templace for other markets +one_market = OneMarket.new(url) +puts one_market.get_appliances diff --git a/src/market_mad/remotes/s3/S3.rb b/src/market_mad/remotes/s3/S3.rb new file mode 100644 index 0000000000..59510898a8 --- /dev/null +++ b/src/market_mad/remotes/s3/S3.rb @@ -0,0 +1,129 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +# -------------------------------------------------------------------------- # + +require 'aws-sdk' + +# This class is a generic wrapper to the s3 gem. +# It can either handle simple or multipart uploads, but the logic to decide +# which uploader to use is not included in this class. +class S3 + attr_accessor :name, :client + + def initialize(h) + @client = Aws::S3::Client.new(h) + end + + def bucket=(bucket) + @bucket = bucket + + # Implicit creation of the bucket + begin + @client.head_bucket({ + :bucket => @bucket + }) + rescue Aws::S3::Errors::NotFound + puts "create" + @client.create_bucket({ + :bucket => @bucket + }) + end + end + + def create_multipart_upload + @parts = [] + @part_number = 1 + + resp = @client.create_multipart_upload({ + :bucket => @bucket, + :key => @name + }) + + @upload_id = resp.upload_id + end + + def complete_multipart_upload + @client.complete_multipart_upload({ + :bucket => @bucket, + :key => @name, + :upload_id => @upload_id, + :multipart_upload => {:parts => @parts} + }) + end + + def abort_multipart_upload + @client.abort_multipart_upload({ + :upload_id => @upload_id, + :key => @name, + :bucket => @bucket + }) + end + + def upload_part(body) + resp = @client.upload_part({ + :body => body, + :upload_id => @upload_id, + :part_number => @part_number, + :key => @name, + :bucket => @bucket + }) + + @parts << { + :etag => resp.etag, + :part_number => @part_number + } + + @part_number += 1 + end + + def put_object(body) + @client.put_object({ + :body => body, + :bucket => @bucket, + :key => @name + }) + end + + def delete_object + @client.delete_object({ + :bucket => @bucket, + :key => @name + }) + end + + def exists? + begin + !!@client.head_object({ + :bucket => @bucket, + :key => @name + }) + rescue Aws::S3::Errors::NotFound + false + end + end + + def get_bucket_size + resp = @client.list_objects({ + bucket: @bucket + }) + + size = 0 + resp.contents.each do |o| + size += o.size + end + + return size + end +end diff --git a/src/market_mad/remotes/s3/delete b/src/market_mad/remotes/s3/delete new file mode 100755 index 0000000000..844018f11f --- /dev/null +++ b/src/market_mad/remotes/s3/delete @@ -0,0 +1,92 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +# -------------------------------------------------------------------------- # + +############################################################################### +# This script is used to import a file into the marketplace. The source file +# is an opaque representation of an OpenNebula object, like a image file or a +# tar.gz with several vm template or flow disk images +############################################################################### + +ONE_LOCATION = ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION = "/usr/lib/one/ruby" +else + RUBY_LIB_LOCATION = ONE_LOCATION + "/lib/ruby" +end + +UTILS_PATH = File.join(File.dirname(__FILE__), '../../datastore') + +$: << RUBY_LIB_LOCATION +$: << RUBY_LIB_LOCATION+"/cli" +$: << File.dirname(__FILE__) + +require 'base64' +require 'rexml/document' +require 'getoptlong' +require 'pp' + +require 'S3' + +def xpath(xml, xpath) + xml.elements[xpath].text.to_s rescue nil +end + +xml = REXML::Document.new(Base64::decode64(ARGV[0])).root + +source = xpath(xml, 'MARKETPLACEAPP/SOURCE') + +# required +access_key_id = xpath(xml, 'MARKETPLACE/TEMPLATE/ACCESS_KEY_ID') +secret_access_key = xpath(xml, 'MARKETPLACE/TEMPLATE/SECRET_ACCESS_KEY') +bucket = xpath(xml, 'MARKETPLACE/TEMPLATE/BUCKET') +region = xpath(xml, 'MARKETPLACE/TEMPLATE/REGION') + +# optional +signature_version = xpath(xml, 'MARKETPLACE/TEMPLATE/SIGNATURE_VERSION') +endpoint = xpath(xml, 'MARKETPLACE/TEMPLATE/ENDPOINT') +force_path_style = xpath(xml, 'MARKETPLACE/TEMPLATE/FORCE_PATH_STYLE') + +name = File.basename(source) + +if name.empty? + STDERR.puts "Empty SOURCE." + exit 1 +end + +s3_config = { + :region => region, + :access_key_id => access_key_id, + :secret_access_key => secret_access_key +} + +s3_config[:signature_version] = signature_version if !signature_version.to_s.empty? +s3_config[:endpoint] = endpoint if !endpoint.to_s.empty? +s3_config[:force_path_style] = true if force_path_style.to_s.downcase == "yes" + +s3 = S3.new(s3_config) + +s3.name = name +s3.bucket = bucket + +if !s3.exists? + STDERR.puts "Object '#{name}' does not exist." + exit 1 +end + +s3.delete_object diff --git a/src/market_mad/remotes/s3/import b/src/market_mad/remotes/s3/import new file mode 100755 index 0000000000..2f1da80db5 --- /dev/null +++ b/src/market_mad/remotes/s3/import @@ -0,0 +1,143 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +# -------------------------------------------------------------------------- # + +############################################################################### +# This script is used to import a file into the marketplace. The source file +# is an opaque representation of an OpenNebula object, like a image file or a +# tar.gz with several vm template or flow disk images +############################################################################### + +ONE_LOCATION = ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION = "/usr/lib/one/ruby" +else + RUBY_LIB_LOCATION = ONE_LOCATION + "/lib/ruby" +end + +UTILS_PATH = File.join(File.dirname(__FILE__), '../../datastore') + +$: << RUBY_LIB_LOCATION +$: << RUBY_LIB_LOCATION+"/cli" +$: << File.dirname(__FILE__) + +require 'base64' +require 'rexml/document' +require 'getoptlong' +require 'open3' +require 'pp' + +require 'S3' + +def xpath(xml, xpath) + xml.elements[xpath].text.to_s rescue nil +end + +xml = REXML::Document.new(Base64::decode64(ARGV[0])).root + +import_source = xpath(xml, 'IMPORT_SOURCE') +format = xpath(xml, 'FORMAT') +dispose = xpath(xml, 'DISPOSE') +size = xpath(xml, 'SIZE') +md5 = xpath(xml, 'MD5') + +id = xpath(xml, 'MARKETPLACEAPP/ID') + +# required +access_key_id = xpath(xml, 'MARKETPLACE/TEMPLATE/ACCESS_KEY_ID') +secret_access_key = xpath(xml, 'MARKETPLACE/TEMPLATE/SECRET_ACCESS_KEY') +bucket = xpath(xml, 'MARKETPLACE/TEMPLATE/BUCKET') +region = xpath(xml, 'MARKETPLACE/TEMPLATE/REGION') + +# optional +signature_version = xpath(xml, 'MARKETPLACE/TEMPLATE/SIGNATURE_VERSION') +endpoint = xpath(xml, 'MARKETPLACE/TEMPLATE/ENDPOINT') +force_path_style = xpath(xml, 'MARKETPLACE/TEMPLATE/FORCE_PATH_STYLE') + +name = "marketapp-#{id}" +source = "s3://#{bucket}/#{name}" + +# Upload + +READ_LENGTH = 10*1024*1024 # Read in chunks of 10MB + +s3_config = { + :region => region, + :access_key_id => access_key_id, + :secret_access_key => secret_access_key +} + +s3_config[:signature_version] = signature_version if !signature_version.to_s.empty? +s3_config[:endpoint] = endpoint if !endpoint.to_s.empty? +s3_config[:force_path_style] = true if force_path_style.to_s.downcase == "yes" + +s3 = S3.new(s3_config) + +s3.name = name +s3.bucket = bucket + +if s3.exists? + STDERR.puts "Object '#{name}' already exists." + exit 1 +end + +cmd = "#{UTILS_PATH}/downloader.sh #{import_source} -" + +Open3.popen3(cmd) do |_, o, _, _| + body = o.read(READ_LENGTH) + + if o.eof? + s3.put_object(body) + else + s3.create_multipart_upload + + begin + s3.upload_part(body) + + until o.eof? + body = o.read(READ_LENGTH) + s3.upload_part(body) + end + + s3.complete_multipart_upload + rescue Exception => e + STDERR.puts(e.message) + STDERR.puts(e.backtrace) + + resp = s3.abort_multipart_upload + STDERR.puts(resp.inspect) + + exit 1 + end + end +end + +# Result + +marketplaceapp = { + :source => source, + :md5 => md5, + :size => size, + :format => format +} + +marketplaceapp.each do |k,v| + puts "#{k.upcase}=\"#{v}\"" +end + +exit 0 diff --git a/src/market_mad/remotes/s3/monitor b/src/market_mad/remotes/s3/monitor new file mode 100755 index 0000000000..181ffb950d --- /dev/null +++ b/src/market_mad/remotes/s3/monitor @@ -0,0 +1,87 @@ +#!/usr/bin/env ruby + +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +# -------------------------------------------------------------------------- # + +############################################################################### +# This script is used to import a file into the marketplace. The source file +# is an opaque representation of an OpenNebula object, like a image file or a +# tar.gz with several vm template or flow disk images +############################################################################### + +ONE_LOCATION = ENV["ONE_LOCATION"] + +if !ONE_LOCATION + RUBY_LIB_LOCATION = "/usr/lib/one/ruby" +else + RUBY_LIB_LOCATION = ONE_LOCATION + "/lib/ruby" +end + +UTILS_PATH = File.join(File.dirname(__FILE__), '../../datastore') + +$: << RUBY_LIB_LOCATION +$: << RUBY_LIB_LOCATION+"/cli" +$: << File.dirname(__FILE__) + +TOTAL_MB_DEFAULT = 1048576 # Default maximum 1TB + +require 'base64' +require 'rexml/document' +require 'getoptlong' +require 'pp' + +require 'S3' + +def xpath(xml, xpath) + xml.elements[xpath].text.to_s rescue nil +end + +xml = REXML::Document.new(Base64::decode64(ARGV[0])).root + +# required +access_key_id = xpath(xml, 'MARKETPLACE/TEMPLATE/ACCESS_KEY_ID') +secret_access_key = xpath(xml, 'MARKETPLACE/TEMPLATE/SECRET_ACCESS_KEY') +bucket = xpath(xml, 'MARKETPLACE/TEMPLATE/BUCKET') +region = xpath(xml, 'MARKETPLACE/TEMPLATE/REGION') +total_mb = xpath(xml, 'MARKETPLACE/TEMPLATE/TOTAL_MB') || TOTAL_MB_DEFAULT + +# optional +signature_version = xpath(xml, 'MARKETPLACE/TEMPLATE/SIGNATURE_VERSION') +endpoint = xpath(xml, 'MARKETPLACE/TEMPLATE/ENDPOINT') +force_path_style = xpath(xml, 'MARKETPLACE/TEMPLATE/FORCE_PATH_STYLE') + +s3_config = { + :region => region, + :access_key_id => access_key_id, + :secret_access_key => secret_access_key +} + +s3_config[:signature_version] = signature_version if !signature_version.to_s.empty? +s3_config[:endpoint] = endpoint if !endpoint.to_s.empty? +s3_config[:force_path_style] = true if force_path_style.to_s.downcase == "yes" + +s3 = S3.new(s3_config) + +s3.bucket = bucket + +used_mb = (s3.get_bucket_size.to_f/1024/1024).ceil +free_mb = total_mb - used_mb + +puts < atts; - federation_enabled = false; federation_master = false; zone_id = 0; master_oned = ""; - rc = nebula_configuration->get("FEDERATION", atts); + const VectorAttribute * vatt = nebula_configuration->get("FEDERATION"); - if (rc != 0) + if (vatt != 0) { - const VectorAttribute * vatt = static_cast - (atts[0]); - - string mode; - mode = vatt->vector_value("MODE"); + string mode = vatt->vector_value("MODE"); one_util::toupper(mode); if (mode == "STANDALONE") @@ -225,10 +218,7 @@ void Nebula::start(bool bootstrap_only) // ----------------------------------------------------------- try { - vector dbs; - int rc; - - bool db_is_sqlite = true; + bool db_is_sqlite = true; string server = "localhost"; string port_str; @@ -237,20 +227,17 @@ void Nebula::start(bool bootstrap_only) string passwd = "oneadmin"; string db_name = "opennebula"; - rc = nebula_configuration->get("DB", dbs); + const VectorAttribute * _db = nebula_configuration->get("DB"); - if ( rc != 0 ) + if ( _db != 0 ) { - string value; - const VectorAttribute * db = static_cast - (dbs[0]); - value = db->vector_value("BACKEND"); + string value = _db->vector_value("BACKEND"); if (value == "mysql") { db_is_sqlite = false; - value = db->vector_value("SERVER"); + value = _db->vector_value("SERVER"); if (!value.empty()) { server = value; @@ -258,7 +245,7 @@ void Nebula::start(bool bootstrap_only) istringstream is; - port_str = db->vector_value("PORT"); + port_str = _db->vector_value("PORT"); is.str(port_str); is >> port; @@ -268,19 +255,19 @@ void Nebula::start(bool bootstrap_only) port = 0; } - value = db->vector_value("USER"); + value = _db->vector_value("USER"); if (!value.empty()) { user = value; } - value = db->vector_value("PASSWD"); + value = _db->vector_value("PASSWD"); if (!value.empty()) { passwd = value; } - value = db->vector_value("DB_NAME"); + value = _db->vector_value("DB_NAME"); if (!value.empty()) { db_name = value; @@ -290,15 +277,11 @@ void Nebula::start(bool bootstrap_only) if ( db_is_sqlite ) { - string db_name = var_location + "one.db"; - - db = new SqliteDB(db_name); + db = new SqliteDB(var_location + "one.db"); } else { - ostringstream oss; - - db = new MySqlDB(server,port,user,passwd,db_name); + db = new MySqlDB(server, port, user, passwd, db_name); } // --------------------------------------------------------------------- @@ -338,6 +321,9 @@ void Nebula::start(bool bootstrap_only) rc += UserQuotas::bootstrap(db); rc += GroupQuotas::bootstrap(db); rc += SecurityGroupPool::bootstrap(db); + rc += VirtualRouterPool::bootstrap(db); + rc += MarketPlacePool::bootstrap(db); + rc += MarketPlaceAppPool::bootstrap(db); // Create the system tables only if bootstrap went well if (rc == 0) @@ -462,34 +448,36 @@ void Nebula::start(bool bootstrap_only) float mem_cost; float disk_cost; - vector vm_hooks; - vector host_hooks; - vector vnet_hooks; - vector user_hooks; - vector group_hooks; - vector image_hooks; + vector vm_hooks; + vector host_hooks; + vector vrouter_hooks; + vector vnet_hooks; + vector user_hooks; + vector group_hooks; + vector image_hooks; - vector vm_restricted_attrs; - vector img_restricted_attrs; - vector vnet_restricted_attrs; + vector vm_restricted_attrs; + vector img_restricted_attrs; + vector vnet_restricted_attrs; - vector inherit_image_attrs; - vector inherit_datastore_attrs; - vector inherit_vnet_attrs; + vector inherit_image_attrs; + vector inherit_datastore_attrs; + vector inherit_vnet_attrs; - vector default_cost; + vector default_cost; clpool = new ClusterPool(db); docpool = new DocumentPool(db); zonepool= new ZonePool(db, is_federation_slave()); vdcpool = new VdcPool(db, is_federation_slave()); - nebula_configuration->get("VM_HOOK", vm_hooks); - nebula_configuration->get("HOST_HOOK", host_hooks); - nebula_configuration->get("VNET_HOOK", vnet_hooks); - nebula_configuration->get("USER_HOOK", user_hooks); - nebula_configuration->get("GROUP_HOOK", group_hooks); - nebula_configuration->get("IMAGE_HOOK", image_hooks); + nebula_configuration->get("VM_HOOK", vm_hooks); + nebula_configuration->get("HOST_HOOK", host_hooks); + nebula_configuration->get("VROUTER_HOOK", vrouter_hooks); + nebula_configuration->get("VNET_HOOK", vnet_hooks); + nebula_configuration->get("USER_HOOK", user_hooks); + nebula_configuration->get("GROUP_HOOK", group_hooks); + nebula_configuration->get("IMAGE_HOOK", image_hooks); nebula_configuration->get("VM_RESTRICTED_ATTR", vm_restricted_attrs); nebula_configuration->get("IMAGE_RESTRICTED_ATTR", img_restricted_attrs); @@ -555,6 +543,10 @@ void Nebula::start(bool bootstrap_only) remotes_location, host_expiration); + vrouterpool = new VirtualRouterPool(db, + vrouter_hooks, + remotes_location); + nebula_configuration->get("MAC_PREFIX", mac_prefix); nebula_configuration->get("NETWORK_SIZE", size); @@ -596,6 +588,9 @@ void Nebula::start(bool bootstrap_only) default_group_quota.select(); secgrouppool = new SecurityGroupPool(db); + + marketpool = new MarketPlacePool(db); + apppool = new MarketPlaceAppPool(db); } catch (exception&) { @@ -606,7 +601,7 @@ void Nebula::start(bool bootstrap_only) // ---- Virtual Machine Manager ---- try { - vector vmm_mads; + vector vmm_mads; int vm_limit; bool do_poll; @@ -659,7 +654,7 @@ void Nebula::start(bool bootstrap_only) // ---- Information Manager ---- try { - vector im_mads; + vector im_mads; int host_limit; int monitor_threads; @@ -694,7 +689,7 @@ void Nebula::start(bool bootstrap_only) // ---- Transfer Manager ---- try { - vector tm_mads; + vector tm_mads; nebula_configuration->get("TM_MAD", tm_mads); @@ -732,7 +727,7 @@ void Nebula::start(bool bootstrap_only) // ---- Hook Manager ---- try { - vector hm_mads; + vector hm_mads; nebula_configuration->get("HM_MAD", hm_mads); @@ -753,7 +748,7 @@ void Nebula::start(bool bootstrap_only) // ---- Auth Manager ---- try { - vector auth_mads; + vector auth_mads; nebula_configuration->get("AUTH_MAD", auth_mads); @@ -784,7 +779,7 @@ void Nebula::start(bool bootstrap_only) // ---- Image Manager ---- try { - vector image_mads; + vector image_mads; nebula_configuration->get("DATASTORE_MAD", image_mads); @@ -806,6 +801,27 @@ void Nebula::start(bool bootstrap_only) throw runtime_error("Could not start the Image Manager"); } + // ---- Marketplace Manager ---- + try + { + vector mmads ; + + nebula_configuration->get("MARKET_MAD", mmads); + + marketm = new MarketPlaceManager(timer_period, monitor_period, mmads); + } + catch (bad_alloc&) + { + throw; + } + + rc = marketm->start(); + + if ( rc != 0 ) + { + throw runtime_error("Could not start the Marketplace Manager"); + } + // ----------------------------------------------------------- // Load mads // ----------------------------------------------------------- @@ -839,6 +855,11 @@ void Nebula::start(bool bootstrap_only) goto error_mad; } + if (marketm->load_mads(0) != 0) + { + goto error_mad; + } + if ( authm != 0 ) { if (authm->load_mads(0) != 0) @@ -895,6 +916,8 @@ void Nebula::start(bool bootstrap_only) lcm->init_managers(); + marketm->init_managers(); + // ---- Start the Request Manager ---- rc = rm->start(); @@ -929,6 +952,7 @@ void Nebula::start(bool bootstrap_only) rm->finalize(); hm->finalize(); imagem->finalize(); + marketm->finalize(); aclm->finalize(); //sleep to wait drivers??? @@ -966,19 +990,14 @@ error_mad: Log::MessageType Nebula::get_debug_level() const { - Log::MessageType clevel = Log::ERROR; - vector logs; - int rc; - int log_level_int; + Log::MessageType clevel = Log::ERROR; + int log_level_int; - rc = nebula_configuration->get("LOG", logs); + const VectorAttribute * log = nebula_configuration->get("LOG"); - if ( rc != 0 ) + if ( log != 0 ) { - string value; - const VectorAttribute * log = static_cast - (logs[0]); - value = log->vector_value("DEBUG_LEVEL"); + string value = log->vector_value("DEBUG_LEVEL"); log_level_int = atoi(value.c_str()); @@ -996,20 +1015,14 @@ Log::MessageType Nebula::get_debug_level() const NebulaLog::LogType Nebula::get_log_system() const { - vector logs; - int rc; - NebulaLog::LogType log_system = NebulaLog::UNDEFINED; + NebulaLog::LogType log_system = NebulaLog::UNDEFINED; - rc = nebula_configuration->get("LOG", logs); + const VectorAttribute * log = nebula_configuration->get("LOG"); - if ( rc != 0 ) + if ( log != 0 ) { - string value; - const VectorAttribute * log = static_cast - (logs[0]); - - value = log->vector_value("SYSTEM"); - log_system = NebulaLog::str_to_type(value); + string value = log->vector_value("SYSTEM"); + log_system = NebulaLog::str_to_type(value); } return log_system; @@ -1063,69 +1076,28 @@ string Nebula::get_vm_log_filename(int oid) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int Nebula::get_ds_conf_attribute( - const std::string& ds_name, +int Nebula::get_conf_attribute( + const std::string& key, + const std::string& name, const VectorAttribute* &value) const { - std::vector::const_iterator it; - std::vector values; - std::string template_ds_name; - std::string ds_name_upper; + std::vector::const_iterator it; + std::vector values; + std::string template_name; + std::string name_upper; - nebula_configuration->Template::get("DS_MAD_CONF", values); + nebula_configuration->get(key, values); for (it = values.begin(); it != values.end(); it ++) { - value = dynamic_cast(*it); + value = *it; + template_name = (*it)->vector_value("NAME"); + name_upper = name; - if (value == 0) - { - continue; - } + one_util::toupper(name_upper); + one_util::toupper(template_name); - 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) + if ( template_name == name_upper) { return 0; } diff --git a/src/nebula/NebulaTemplate.cc b/src/nebula/NebulaTemplate.cc index 8bdc54a285..31c529a6b5 100644 --- a/src/nebula/NebulaTemplate.cc +++ b/src/nebula/NebulaTemplate.cc @@ -87,7 +87,6 @@ const char * OpenNebulaTemplate::conf_name="oned.conf"; void OpenNebulaTemplate::set_multiple_conf_default() { - /* #******************************************************************************* # Transfer Manager Configuration @@ -103,7 +102,6 @@ void OpenNebulaTemplate::set_multiple_conf_default() # 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"); @@ -115,8 +113,6 @@ void OpenNebulaTemplate::set_multiple_conf_default() set_conf_tm("dev", "NONE", "NONE", "YES", "NO"); register_multiple_conf_default("TM_MAD_CONF"); - - /* #******************************************************************************* # Datastore Manager Configuration @@ -131,20 +127,32 @@ void OpenNebulaTemplate::set_multiple_conf_default() # 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"); - 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"); +/* +#******************************************************************************* +# Marketplace Manager Configuration +#******************************************************************************* +# http +# s3 +#****** +*/ + set_conf_market("one", ""); + set_conf_market("http", "BASE_URL,PUBLIC_DIR"); + set_conf_market("s3", "ACCESS_KEY_ID,SECRET_ACCESS_KEY,REGION,BUCKET"); - register_multiple_conf_default("DS_MAD_CONF"); + register_multiple_conf_default("MARKET_MAD_CONF"); } /* -------------------------------------------------------------------------- */ @@ -153,50 +161,37 @@ void OpenNebulaTemplate::set_multiple_conf_default() void OpenNebulaTemplate::register_multiple_conf_default( const std::string& conf_section) { - std::string defaults_name, attributes_name; - - Attribute * defaults_value; + std::string d_name; bool found; - const VectorAttribute* defaults_attr; - const VectorAttribute* attributes_attr; + VectorAttribute* d_attr; - std::map::iterator iter_defaults, prev; + std::map::iterator i, prev; - std::vector::const_iterator iter_attributes; - std::vector attributes_values; + std::vector::const_iterator j; + std::vector attrs; - get(conf_section.c_str(), attributes_values); + get(conf_section.c_str(), attrs); - for( iter_defaults = conf_default.begin(); - iter_defaults != conf_default.end(); ) + for(i = conf_default.begin(); i != conf_default.end(); ) { - if ( iter_defaults->first == conf_section ) + if ( i->first == conf_section ) { found = false; - defaults_value = iter_defaults->second; + d_attr = dynamic_cast(i->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++) + if (d_attr == 0) { - attributes_attr = dynamic_cast - (*iter_attributes); + continue; + } - if (attributes_attr == 0) - { - continue; - } + d_name = d_attr->vector_value("NAME"); - attributes_name = attributes_attr->vector_value("NAME"); - - if ( attributes_name == defaults_name ) + for (j = attrs.begin(); j != attrs.end(); j++) + { + if ( (*j)->vector_value("NAME") == d_name ) { found = true; break; @@ -206,20 +201,20 @@ void OpenNebulaTemplate::register_multiple_conf_default( if ( !found ) { // insert into attributes - attributes.insert(make_pair(conf_section, defaults_value)); - iter_defaults++; + attributes.insert(make_pair(conf_section, d_attr)); + i++; } else { // remove from conf_defaults - delete iter_defaults->second; - prev = iter_defaults++; + delete i->second; + prev = i++; conf_default.erase(prev); } } else { - iter_defaults++; + i++; } } } @@ -278,6 +273,22 @@ void OpenNebulaTemplate::set_conf_tm(const std::string& name, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +void OpenNebulaTemplate::set_conf_market(const std::string& name, + const std::string& required_attrs) +{ + VectorAttribute * vattribute; + std::map vvalue; + + vvalue.insert(make_pair("NAME", name)); + vvalue.insert(make_pair("REQUIRED_ATTRS", required_attrs)); + + vattribute = new VectorAttribute("MARKET_MAD_CONF", vvalue); + conf_default.insert(make_pair(vattribute->name(), vattribute)); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + void OpenNebulaTemplate::set_conf_default() { VectorAttribute * vattribute; diff --git a/src/nebula/SConstruct b/src/nebula/SConstruct index d970365ad9..91f44ef7e4 100644 --- a/src/nebula/SConstruct +++ b/src/nebula/SConstruct @@ -64,6 +64,8 @@ env.Prepend(LIBS=[ 'nebula_xml', 'nebula_secgroup', 'nebula_vdc', + 'nebula_vrouter', + 'nebula_marketplace', 'crypto', 'xml2' ]) diff --git a/src/oca/java/src/org/opennebula/client/acl/Acl.java b/src/oca/java/src/org/opennebula/client/acl/Acl.java index ddb15ba7a5..682b09fa3e 100644 --- a/src/oca/java/src/org/opennebula/client/acl/Acl.java +++ b/src/oca/java/src/org/opennebula/client/acl/Acl.java @@ -71,6 +71,9 @@ public class Acl extends PoolElement{ tmpResources.put("ZONE" , 0x0000800000000000L); tmpResources.put("SECGROUP" , 0x0001000000000000L); tmpResources.put("VDC" , 0x0002000000000000L); + tmpResources.put("VROUTER" , 0x0004000000000000L); + tmpResources.put("MARKETPLACE", 0x0008000000000000L); + tmpResources.put("MARKETPLACEAPP", 0x0010000000000000L); RESOURCES = Collections.unmodifiableMap(tmpResources); diff --git a/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouter.java b/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouter.java new file mode 100644 index 0000000000..5c61a65966 --- /dev/null +++ b/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouter.java @@ -0,0 +1,441 @@ +/******************************************************************************* + * Copyright 2002-2015, OpenNebula Project, OpenNebula Systems + * + * 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. + ******************************************************************************/ +package org.opennebula.client.vrouter; + +import org.opennebula.client.Client; +import org.opennebula.client.OneResponse; +import org.opennebula.client.PoolElement; +import org.w3c.dom.Node; + +/** + * This class represents an OpenNebula Virtual Router + * It also offers static XML-RPC call wrappers. + */ +public class VirtualRouter extends PoolElement +{ + + private static final String METHOD_PREFIX = "vrouter."; + private static final String ALLOCATE = METHOD_PREFIX + "allocate"; + private static final String INSTANTIATE = METHOD_PREFIX + "instantiate"; + private static final String INFO = METHOD_PREFIX + "info"; + private static final String UPDATE = METHOD_PREFIX + "update"; + private static final String DELETE = METHOD_PREFIX + "delete"; + private static final String CHOWN = METHOD_PREFIX + "chown"; + private static final String CHMOD = METHOD_PREFIX + "chmod"; + private static final String RENAME = METHOD_PREFIX + "rename"; + private static final String ATTACHNIC = METHOD_PREFIX + "attachnic"; + private static final String DETACHNIC = METHOD_PREFIX + "detachnic"; + + /** + * Creates a new VirtualRouter representation. + * @param id The VirtualRouter id. + * @param client XML-RPC Client. + */ + public VirtualRouter(int id, Client client) + { + super(id, client); + } + + /** + * @see PoolElement + */ + protected VirtualRouter(Node xmlElement, Client client) + { + super(xmlElement, client); + } + + // ================================= + // Static XML-RPC methods + // ================================= + + + /** + * Allocates a new VirtualRouter in OpenNebula. + * + * @param client XML-RPC Client. + * @param description A string containing the template of the VirtualRouter. + * @return If successful the message contains the associated + * id generated for this VirtualRouter. + */ + public static OneResponse allocate(Client client, String description) + { + return client.call(ALLOCATE, description); + } + + /** + * Retrieves the information of the given VirtualRouter. + * + * @param client XML-RPC Client. + * @param id The VirtualRouter id for the VirtualRouter to retrieve the information from + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public static OneResponse info(Client client, int id) + { + return client.call(INFO, id); + } + + /** + * Creates VM instances from a VM Template. New VMs will be associated + * to this Virtual Router, and its Virtual Networks + * + * @param client XML-RPC Client. + * @param id The id of the target VirtualRouter. + * @param nVMs Number of VMs to instantiate + * @param templateId VM Template id to instantiate + * @param name Name for the VM instances. If it is an empty string + * OpenNebula will set a default name. Wildcard %i can be used. + * @param onHold False to create this VM in pending state, true on hold + * @param template User provided Template to merge with the one + * being instantiated + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse instantiate(Client client, int id, int nVMs, + int templateId, String name, boolean onHold, String template) + { + return client.call(INSTANTIATE, id, nVMs, templateId, name, onHold, template); + } + + /** + * Deletes a VirtualRouter from OpenNebula. + * + * @param client XML-RPC Client. + * @param id The id of the target VirtualRouter we want to delete. + * @return A encapsulated response. + */ + public static OneResponse delete(Client client, int id) + { + return client.call(DELETE, id); + } + + /** + * Replaces the template contents. + * + * @param client XML-RPC Client. + * @param id The id of the target VirtualRouter we want to modify. + * @param new_template New template contents. + * @param append True to append new attributes instead of replace the whole template + * @return If successful the message contains the VirtualRouter id. + */ + public static OneResponse update(Client client, int id, String new_template, + boolean append) + { + return client.call(UPDATE, id, new_template, append ? 1 : 0); + } + + /** + * Publishes or unpublishes a VirtualRouter. + * + * @param client XML-RPC Client. + * @param id The id of the target VirtualRouter we want to modify. + * @param publish True for publishing, false for unpublishing. + * @return If successful the message contains the VirtualRouter id. + */ + public static OneResponse publish(Client client, int id, boolean publish) + { + int group_u = publish ? 1 : 0; + + return chmod(client, id, -1, -1, -1, group_u, -1, -1, -1, -1, -1); + } + + /** + * Changes the owner/group + * + * @param client XML-RPC Client. + * @param id The id of the target VirtualRouter we want to modify. + * @param uid The new owner user ID. Set it to -1 to leave the current one. + * @param gid The new group ID. Set it to -1 to leave the current one. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse chown(Client client, int id, int uid, int gid) + { + return client.call(CHOWN, id, uid, gid); + } + + /** + * Changes the VirtualRouter permissions + * + * @param client XML-RPC Client. + * @param id The id of the target VirtualRouter. + * @param owner_u 1 to allow, 0 deny, -1 do not change + * @param owner_m 1 to allow, 0 deny, -1 do not change + * @param owner_a 1 to allow, 0 deny, -1 do not change + * @param group_u 1 to allow, 0 deny, -1 do not change + * @param group_m 1 to allow, 0 deny, -1 do not change + * @param group_a 1 to allow, 0 deny, -1 do not change + * @param other_u 1 to allow, 0 deny, -1 do not change + * @param other_m 1 to allow, 0 deny, -1 do not change + * @param other_a 1 to allow, 0 deny, -1 do not change + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse chmod(Client client, int id, + int owner_u, int owner_m, int owner_a, + int group_u, int group_m, int group_a, + int other_u, int other_m, int other_a) + { + return chmod(client, CHMOD, id, + owner_u, owner_m, owner_a, + group_u, group_m, group_a, + other_u, other_m, other_a); + } + + /** + * Changes the permissions + * + * @param client XML-RPC Client. + * @param id The id of the target object. + * @param octet Permissions octed , e.g. 640 + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse chmod(Client client, int id, String octet) + { + return chmod(client, CHMOD, id, octet); + } + + /** + * Changes the permissions + * + * @param client XML-RPC Client. + * @param id The id of the target object. + * @param octet Permissions octed , e.g. 640 + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse chmod(Client client, int id, int octet) + { + return chmod(client, CHMOD, id, octet); + } + + /** + * Renames this VirtualRouter + * + * @param client XML-RPC Client. + * @param id The id of the target VirtualRouter. + * @param name New name for the VirtualRouter. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse rename(Client client, int id, String name) + { + return client.call(RENAME, id, name); + } + + // ================================= + // Instanced object XML-RPC methods + // ================================= + + /** + * Retrieves the information of the VirtualRouter. + * + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public OneResponse info() + { + OneResponse response = info(client, id); + super.processInfo(response); + return response; + } + + /** + * Deletes the VirtualRouter from OpenNebula. + * + * @return A encapsulated response. + */ + public OneResponse delete() + { + return delete(client, id); + } + + /** + * Replaces the VirtualRouter contents. + * + * @param new_template New template contents. + * @return If successful the message contains the VirtualRouter id. + */ + public OneResponse update(String new_template) + { + return update(new_template, false); + } + + /** + * Replaces the template contents. + * + * @param new_template New template contents. + * @param append True to append new attributes instead of replace the whole template + * @return If successful the message contains the VirtualRouter id. + */ + public OneResponse update(String new_template, boolean append) + { + return update(client, id, new_template, append); + } + + /** + * Publishes or unpublishes the VirtualRouter. + * + * @param publish True for publishing, false for unpublishing. + * @return If successful the message contains the VirtualRouter id. + */ + public OneResponse publish(boolean publish) + { + return publish(client, id, publish); + } + + /** + * Publishes the VirtualRouter. + * + * @return If successful the message contains the VirtualRouter id. + */ + public OneResponse publish() + { + return publish(true); + } + + /** + * Unpublishes the VirtualRouter. + * + * @return If successful the message contains the VirtualRouter id. + */ + public OneResponse unpublish() + { + return publish(false); + } + + /** + * Changes the owner/group + * + * @param uid The new owner user ID. Set it to -1 to leave the current one. + * @param gid The new group ID. Set it to -1 to leave the current one. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse chown(int uid, int gid) + { + return chown(client, id, uid, gid); + } + + /** + * Changes the owner + * + * @param uid The new owner user ID. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse chown(int uid) + { + return chown(uid, -1); + } + + /** + * Changes the group + * + * @param gid The new group ID. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse chgrp(int gid) + { + return chown(-1, gid); + } + + /** + * Changes the VirtualRouter permissions + * + * @param owner_u 1 to allow, 0 deny, -1 do not change + * @param owner_m 1 to allow, 0 deny, -1 do not change + * @param owner_a 1 to allow, 0 deny, -1 do not change + * @param group_u 1 to allow, 0 deny, -1 do not change + * @param group_m 1 to allow, 0 deny, -1 do not change + * @param group_a 1 to allow, 0 deny, -1 do not change + * @param other_u 1 to allow, 0 deny, -1 do not change + * @param other_m 1 to allow, 0 deny, -1 do not change + * @param other_a 1 to allow, 0 deny, -1 do not change + * @return If an error occurs the error message contains the reason. + */ + public OneResponse chmod(int owner_u, int owner_m, int owner_a, + int group_u, int group_m, int group_a, + int other_u, int other_m, int other_a) + { + return chmod(client, id, + owner_u, owner_m, owner_a, + group_u, group_m, group_a, + other_u, other_m, other_a); + } + + /** + * Changes the permissions + * + * @param octet Permissions octed , e.g. 640 + * @return If an error occurs the error message contains the reason. + */ + public OneResponse chmod(String octet) + { + return chmod(client, id, octet); + } + + /** + * Changes the permissions + * + * @param octet Permissions octed , e.g. 640 + * @return If an error occurs the error message contains the reason. + */ + public OneResponse chmod(int octet) + { + return chmod(client, id, octet); + } + + /** + * Creates VM instances from a VM Template. New VMs will be associated + * to this Virtual Router, and its Virtual Networks + * + * @param nVMs Number of VMs to instantiate + * @param templateId VM Template id to instantiate + * @param name Name for the VM instances. If it is an empty string + * OpenNebula will set a default name. Wildcard %i can be used. + * @param onHold False to create this VM in pending state, true on hold + * @param template User provided Template to merge with the one + * being instantiated + * @return If an error occurs the error message contains the reason. + */ + public OneResponse instantiate(int nVMs, int templateId, String name, + boolean onHold, String template) + { + return instantiate(client, id, nVMs, templateId, name, onHold, template); + } + + /** + * Creates VM instances from a VM Template. New VMs will be associated + * to this Virtual Router, and its Virtual Networks + * + * @param nVMs Number of VMs to instantiate + * @param templateId VM Template id to instantiate + * @return If an error occurs the error message contains the reason. + */ + public OneResponse instantiate(int nVMs, int templateId) + { + return instantiate(client, id, nVMs, templateId, "", false, ""); + } + + /** + * Renames this VirtualRouter + * + * @param name New name for the VirtualRouter. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse rename(String name) + { + return rename(client, id, name); + } + + // ================================= + // Helpers + // ================================= +} diff --git a/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouterPool.java b/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouterPool.java new file mode 100644 index 0000000000..69d9215cad --- /dev/null +++ b/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouterPool.java @@ -0,0 +1,263 @@ +/******************************************************************************* + * Copyright 2002-2015, OpenNebula Project, OpenNebula Systems + * + * 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. + ******************************************************************************/ +package org.opennebula.client.vrouter; + +import java.util.AbstractList; +import java.util.Iterator; + +import org.opennebula.client.Client; +import org.opennebula.client.OneResponse; +import org.opennebula.client.Pool; +import org.opennebula.client.PoolElement; +import org.w3c.dom.Node; + +/** + * This class represents an OpenNebula VirtualRouter pool. + * It also offers static XML-RPC call wrappers. + */ +public class VirtualRouterPool extends Pool implements Iterable +{ + private static final String ELEMENT_NAME = "VROUTER"; + private static final String INFO_METHOD = "vrouterpool.info"; + + private int filter; + + /** + * Creates a new VirtualRouter pool with the default filter flag value + * set to {@link Pool#MINE_GROUP} (VirtualRouter belonging to the connected user, + * and the ones in his group) + * + * @param client XML-RPC Client. + * + * @see VirtualRouterPool#VirtualRouterPool(Client, int) + */ + public VirtualRouterPool(Client client) + { + super(ELEMENT_NAME, client, INFO_METHOD); + this.filter = MINE_GROUP; + } + + /** + * Creates a new VirtualRouter pool. + * + * @param client XML-RPC Client. + * @param filter Filter flag to use by default in the method + * {@link VirtualRouterPool#info()}. Possible values: + *
    + *
  • {@link Pool#ALL}: All VirtualRouters
  • + *
  • {@link Pool#MINE}: Connected user's VirtualRouters
  • + *
  • {@link Pool#MINE_GROUP}: Connected user's VirtualRouters, and the ones in + * his group
  • + *
  • >= 0: UID User's VirtualRouters
  • + *
+ */ + public VirtualRouterPool(Client client, int filter) + { + super(ELEMENT_NAME, client, INFO_METHOD); + this.filter = filter; + } + + /* (non-Javadoc) + * @see org.opennebula.client.Pool#factory(org.w3c.dom.Node) + */ + @Override + public PoolElement factory(Node node) + { + return new VirtualRouter(node, client); + } + + /** + * Retrieves all or part of the VirtualRouters in the pool. + * + * @param client XML-RPC Client. + * @param filter Filter flag to use. Possible values: + *
    + *
  • {@link Pool#ALL}: All VirtualRouters
  • + *
  • {@link Pool#MINE}: Connected user's VirtualRouters
  • + *
  • {@link Pool#MINE_GROUP}: Connected user's VirtualRouters, and the ones in + * his group
  • + *
  • >= 0: UID User's VirtualRouters
  • + *
+ * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public static OneResponse info(Client client, int filter) + { + return Pool.info(client, INFO_METHOD, filter, -1, -1); + } + + /** + * Retrieves all the VirtualRouters in the pool. + * + * @param client XML-RPC Client. + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public static OneResponse infoAll(Client client) + { + return Pool.infoAll(client, INFO_METHOD); + } + + /** + * Retrieves all the connected user's VirtualRouters. + * + * @param client XML-RPC Client. + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public static OneResponse infoMine(Client client) + { + return Pool.infoMine(client, INFO_METHOD); + } + + /** + * Retrieves all the connected user's VirtualRouters and the ones in + * his group. + * + * @param client XML-RPC Client. + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public static OneResponse infoGroup(Client client) + { + return Pool.infoGroup(client, INFO_METHOD); + } + + /** + * Retrieves all or part of the VirtualRouters in the pool. The VirtualRouters to retrieve + * can be also filtered by Id, specifying the first and last Id to include. + * + * @param client XML-RPC Client. + * @param filter Filter flag to use. Possible values: + *
    + *
  • {@link Pool#ALL}: All VirtualRouters
  • + *
  • {@link Pool#MINE}: Connected user's VirtualRouters
  • + *
  • {@link Pool#MINE_GROUP}: Connected user's VirtualRouters, and the ones in + * his group
  • + *
  • >= 0: UID User's VirtualRouters
  • + *
+ * @param startId Lowest Id to retrieve + * @param endId Biggest Id to retrieve + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public static OneResponse info(Client client, int filter, + int startId, int endId) + { + return Pool.info(client, INFO_METHOD, filter, startId, endId); + } + + /** + * Loads the xml representation of all or part of the + * VirtualRouters in the pool. The filter used is the one set in + * the constructor. + * + * @see VirtualRouterPool#info(Client, int) + * + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public OneResponse info() + { + return super.info(filter, -1, -1); + } + + /** + * Loads the xml representation of all the VirtualRouters in the pool. + * + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public OneResponse infoAll() + { + return super.infoAll(); + } + + /** + * Loads the xml representation of all the connected user's VirtualRouters. + * + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public OneResponse infoMine() + { + return super.infoMine(); + } + + /** + * Loads the xml representation of all the connected user's VirtualRouters and + * the ones in his group. + * + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public OneResponse infoGroup() + { + return super.infoGroup(); + } + + /** + * Retrieves all or part of the VirtualRouters in the pool. The VirtualRouters to retrieve + * can be also filtered by Id, specifying the first and last Id to include. + * + * @param filter Filter flag to use. Possible values: + *
    + *
  • {@link Pool#ALL}: All VirtualRouters
  • + *
  • {@link Pool#MINE}: Connected user's VirtualRouters
  • + *
  • {@link Pool#MINE_GROUP}: Connected user's VirtualRouters, and the ones in + * his group
  • + *
  • >= 0: UID User's VirtualRouters
  • + *
+ * @param startId Lowest Id to retrieve + * @param endId Biggest Id to retrieve + * @return If successful the message contains the string + * with the information returned by OpenNebula. + */ + public OneResponse info(int filter, int startId, int endId) + { + return super.info(filter, startId, endId); + } + + public Iterator iterator() + { + AbstractList ab = new AbstractList() + { + public int size() + { + return getLength(); + } + + public VirtualRouter get(int index) + { + return (VirtualRouter) item(index); + } + }; + + return ab.iterator(); + } + + /** + * Returns the VirtualRouter with the given Id from the pool. If it is not found, + * then returns null. The method {@link #info()} must be called before. + * + * @param id of the ACl rule to retrieve + * @return The VirtualRouter with the given Id, or null if it was not found. + */ + public VirtualRouter getById(int id) + { + return (VirtualRouter) super.getById(id); + } +} diff --git a/src/oca/java/test/VirtualRouterTest.java b/src/oca/java/test/VirtualRouterTest.java new file mode 100644 index 0000000000..d2b16223d8 --- /dev/null +++ b/src/oca/java/test/VirtualRouterTest.java @@ -0,0 +1,291 @@ +/******************************************************************************* + * Copyright 2002-2015, OpenNebula Project, OpenNebula Systems + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + ******************************************************************************/ +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.opennebula.client.Client; +import org.opennebula.client.OneResponse; +import org.opennebula.client.group.Group; +import org.opennebula.client.template.*; +import org.opennebula.client.vrouter.*; +import org.opennebula.client.vm.*; +import org.opennebula.client.user.User; +import org.opennebula.client.vm.VirtualMachine; + + + +public class VirtualRouterTest +{ + private static VirtualRouter vrouter; + private static VirtualRouterPool vrouterPool; + + private static Client client; + + private static OneResponse res; + private static String name = "new_test_vrouter"; + + + private static String template_str = + "NAME = \"" + name + "\"\n" + + "ATT1 = \"VAL1\"\n" + + "ATT2 = \"VAL2\""; + + /** + * @throws java.lang.Exception + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception + { + client = new Client(); + vrouterPool = new VirtualRouterPool(client); + } + + /** + * @throws java.lang.Exception + */ + @AfterClass + public static void tearDownAfterClass() throws Exception + { + } + + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception + { + res = VirtualRouter.allocate(client, template_str); + + int oid = res.isError() ? -1 : Integer.parseInt(res.getMessage()); + vrouter = new VirtualRouter(oid, client); + } + + /** + * @throws java.lang.Exception + */ + @After + public void tearDown() throws Exception + { + vrouter.delete(); + } + + @Test + public void allocate() + { + vrouter.delete(); + + res = VirtualRouter.allocate(client, template_str); + assertTrue( res.getErrorMessage(), !res.isError() ); + + int oid = res.isError() ? -1 : Integer.parseInt(res.getMessage()); + vrouter = new VirtualRouter(oid, client); + + + vrouterPool.info(); + + boolean found = false; + for(VirtualRouter temp : vrouterPool) + { + found = found || temp.getName().equals(name); + } + + assertTrue( found ); + } + + @Test + public void info() + { + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vrouter.getName().equals(name) ); + } + + @Test + public void publish() + { + res = vrouter.publish(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + vrouter.info(); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_U").equals("1") ); + } + + @Test + public void unpublish() + { + res = vrouter.unpublish(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + vrouter.info(); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_U").equals("0") ); + } + + @Test + public void chmod() + { + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + String owner_a = vrouter.xpath("PERMISSIONS/OWNER_A"); + String group_a = vrouter.xpath("PERMISSIONS/GROUP_A"); + + res = vrouter.chmod(0, 1, -1, 1, 0, -1, 1, 1, 0); + assertTrue( res.getErrorMessage(), !res.isError() ); + + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vrouter.xpath("PERMISSIONS/OWNER_U").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/OWNER_M").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/OWNER_A").equals(owner_a) ); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_U").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_M").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_A").equals(group_a) ); + assertTrue( vrouter.xpath("PERMISSIONS/OTHER_U").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/OTHER_M").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/OTHER_A").equals("0") ); + } + + @Test + public void chmod_octet() + { + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + res = vrouter.chmod(640); + assertTrue( res.getErrorMessage(), !res.isError() ); + + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vrouter.xpath("PERMISSIONS/OWNER_U").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/OWNER_M").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/OWNER_A").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_U").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_M").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_A").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/OTHER_U").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/OTHER_M").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/OTHER_A").equals("0") ); + + res = vrouter.chmod("147"); + assertTrue( res.getErrorMessage(), !res.isError() ); + + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vrouter.xpath("PERMISSIONS/OWNER_U").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/OWNER_M").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/OWNER_A").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_U").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_M").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/GROUP_A").equals("0") ); + assertTrue( vrouter.xpath("PERMISSIONS/OTHER_U").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/OTHER_M").equals("1") ); + assertTrue( vrouter.xpath("PERMISSIONS/OTHER_A").equals("1") ); + } + + @Test + public void attributes() + { + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vrouter.xpath("NAME").equals(name) ); + } + + @Test + public void delete() + { + res = vrouter.delete(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + res = vrouter.info(); + assertTrue( res.isError() ); + } + + @Test + public void chown() + { + // Create a new User and Group + res = User.allocate(client, "template_test_user", "password"); + assertTrue( res.getErrorMessage(), !res.isError() ); + + int uid = Integer.parseInt(res.getMessage()); + + res = Group.allocate(client, "template_test_group"); + assertTrue( res.getErrorMessage(), !res.isError() ); + + int gid = Integer.parseInt(res.getMessage()); + + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vrouter.uid() == 0 ); + assertTrue( vrouter.gid() == 0 ); + + res = vrouter.chown(uid, gid); + assertTrue( res.getErrorMessage(), !res.isError() ); + + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vrouter.uid() == uid ); + assertTrue( vrouter.gid() == gid ); + + res = vrouter.chgrp(0); + + res = vrouter.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vrouter.uid() == uid ); + assertTrue( vrouter.gid() == 0 ); + } + + @Test + public void instantiate() + { + VirtualMachinePool vmPool = new VirtualMachinePool(client); + + res = vmPool.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vmPool.getLength() == 0 ); + + String tmpl_str = + "NAME = vrtemplate\n"+ + "CPU = 0.1\n"+ + "MEMORY = 64\n"; + + res = Template.allocate(client, tmpl_str); + assertTrue( res.getErrorMessage(), !res.isError() ); + + int tmplid = Integer.parseInt(res.getMessage()); + + res = vrouter.instantiate(3, tmplid); + assertTrue( res.getErrorMessage(), !res.isError() ); + + res = vmPool.info(); + assertTrue( res.getErrorMessage(), !res.isError() ); + + assertTrue( vmPool.getLength() == 3 ); + } +} diff --git a/src/oca/java/test/all_tests.sh b/src/oca/java/test/all_tests.sh index 5488dd8518..dff793416c 100755 --- a/src/oca/java/test/all_tests.sh +++ b/src/oca/java/test/all_tests.sh @@ -73,4 +73,7 @@ let RC=RC+$? ./test.sh SecurityGroupTest let RC=RC+$? +./test.sh VirtualRouterTest +let RC=RC+$? + exit $RC \ No newline at end of file diff --git a/src/oca/ruby/opennebula.rb b/src/oca/ruby/opennebula.rb index 287e1b7971..6eea9d95ff 100644 --- a/src/oca/ruby/opennebula.rb +++ b/src/oca/ruby/opennebula.rb @@ -56,6 +56,12 @@ require 'opennebula/security_group_pool' require 'opennebula/vdc' require 'opennebula/vdc_pool' require 'opennebula/system' +require 'opennebula/virtual_router' +require 'opennebula/virtual_router_pool' +require 'opennebula/marketplace' +require 'opennebula/marketplace_pool' +require 'opennebula/marketplaceapp' +require 'opennebula/marketplaceapp_pool' module OpenNebula diff --git a/src/oca/ruby/opennebula/acl.rb b/src/oca/ruby/opennebula/acl.rb index d1e0b5d009..3ce77198e5 100644 --- a/src/oca/ruby/opennebula/acl.rb +++ b/src/oca/ruby/opennebula/acl.rb @@ -33,6 +33,9 @@ module OpenNebula # ACL # SECGROUP # VDC + # VROUTER + # MARKETPLACE + # MARKETPLACEAPP # RIGHTS -> + separated list # USE # MANAGE @@ -49,19 +52,22 @@ module OpenNebula RESOURCES = { - "VM" => 0x1000000000, - "HOST" => 0x2000000000, - "NET" => 0x4000000000, - "IMAGE" => 0x8000000000, - "USER" => 0x10000000000, - "TEMPLATE" => 0x20000000000, - "GROUP" => 0x40000000000, - "DATASTORE" => 0x100000000000, - "CLUSTER" => 0x200000000000, - "DOCUMENT" => 0x400000000000, - "ZONE" => 0x800000000000, - "SECGROUP" => 0x1000000000000, - "VDC" => 0x2000000000000 + "VM" => 0x1000000000, + "HOST" => 0x2000000000, + "NET" => 0x4000000000, + "IMAGE" => 0x8000000000, + "USER" => 0x10000000000, + "TEMPLATE" => 0x20000000000, + "GROUP" => 0x40000000000, + "DATASTORE" => 0x100000000000, + "CLUSTER" => 0x200000000000, + "DOCUMENT" => 0x400000000000, + "ZONE" => 0x800000000000, + "SECGROUP" => 0x1000000000000, + "VDC" => 0x2000000000000, + "VROUTER" => 0x4000000000000, + "MARKETPLACE" => 0x8000000000000, + "MARKETPLACEAPP"=> 0x10000000000000 } RIGHTS = diff --git a/src/oca/ruby/opennebula/datastore_pool.rb b/src/oca/ruby/opennebula/datastore_pool.rb index 3ea21a5b33..411759fb9b 100644 --- a/src/oca/ruby/opennebula/datastore_pool.rb +++ b/src/oca/ruby/opennebula/datastore_pool.rb @@ -36,9 +36,9 @@ module OpenNebula super('DATASTORE_POOL','DATASTORE',client) end - # Factory method to create User objects + # Factory method to create datastore objects def factory(element_xml) - OpenNebula::Group.new(element_xml,@client) + OpenNebula::Datastore.new(element_xml,@client) end ####################################################################### diff --git a/src/oca/ruby/opennebula/image_pool.rb b/src/oca/ruby/opennebula/image_pool.rb index 5316ffcbdb..89402cdbd3 100644 --- a/src/oca/ruby/opennebula/image_pool.rb +++ b/src/oca/ruby/opennebula/image_pool.rb @@ -23,7 +23,6 @@ module OpenNebula # Constants and Class attribute accessors ####################################################################### - IMAGE_POOL_METHODS = { :info => "imagepool.info" } diff --git a/src/oca/ruby/opennebula/marketplace.rb b/src/oca/ruby/opennebula/marketplace.rb new file mode 100644 index 0000000000..439f42c5a7 --- /dev/null +++ b/src/oca/ruby/opennebula/marketplace.rb @@ -0,0 +1,161 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'opennebula/pool_element' + +module OpenNebula + class MarketPlace < PoolElement + ####################################################################### + # Constants and Class Methods + ####################################################################### + + MARKETPLACE_METHODS = { + :info => "market.info", + :allocate => "market.allocate", + :delete => "market.delete", + :update => "market.update", + :chown => "market.chown", + :chmod => "market.chmod", + :rename => "market.rename" + } + + # Creates a MarketPlace description with just its identifier + # this method should be used to create plain MarketPlace objects. + # +id+ the id of the user + # + # Example: + # marketplace = MarketPlace.new(MarketPlace.build_xml(3),rpc_client) + # + def MarketPlace.build_xml(pe_id=nil) + if pe_id + marketplace_xml = "#{pe_id}" + else + marketplace_xml = "" + end + + XMLElement.build_xml(marketplace_xml,'MARKETPLACE') + end + + # Class constructor + def initialize(xml, client) + super(xml,client) + end + + ####################################################################### + # XML-RPC Methods for the MarketPlace Object + ####################################################################### + + # Retrieves the information of the given marketplace. + def info() + super(MARKETPLACE_METHODS[:info], 'MARKETPLACE') + end + + alias_method :info!, :info + + # Allocates a new marketplace in OpenNebula + # + # @param description [String] The template of the marketplace. + # + # @return [Integer, OpenNebula::Error] the new ID in case of + # success, error otherwise + def allocate(description) + super(MARKETPLACE_METHODS[:allocate], description) + end + + # Deletes the marketplace + def delete() + super(MARKETPLACE_METHODS[:delete]) + end + + # Replaces the template contents + # + # @param new_template [String] New template contents + # @param append [true, false] True to append new attributes instead of + # replace the whole template + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def update(new_template, append=false) + super(MARKETPLACE_METHODS[:update], new_template, append ? 1 : 0) + end + + # Changes the owner/group + # + # @param uid [Integer] the new owner id. Set to -1 to leave the current one + # @param gid [Integer] the new group id. Set to -1 to leave the current one + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chown(uid, gid) + super(MARKETPLACE_METHODS[:chown], uid, gid) + end + + # Changes the marketplace permissions. + # + # @param octet [String] Permissions octed , e.g. 640 + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chmod_octet(octet) + super(MARKETPLACE_METHODS[:chmod], octet) + end + + # Changes the marketplace permissions. + # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u, + other_m, other_a) + super(MARKETPLACE_METHODS[:chmod], owner_u, owner_m, owner_a, group_u, + group_m, group_a, other_u, other_m, other_a) + end + + # Renames this marketplace + # + # @param name [String] New name for the marketplace + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(MARKETPLACE_METHODS[:rename], @pe_id, name) + end + + # --------------------------------------------------------------------- + # Helpers to get information + # --------------------------------------------------------------------- + + # Returns whether or not the marketplace app with id 'id' is part of + # this marketplace + def contains(id) + #This doesn't work in ruby 1.8.5 + #return self["MARKETPLACE/MARKETPLACEAPPS/ID[.=#{uid}]"] != nil + + id_array = retrieve_elements('MARKETPLACEAPPS/ID') + return id_array != nil && id_array.include?(uid.to_s) + end + + # Returns an array with the numeric image ids + def marketapp_ids + array = Array.new + + self.each("MARKETPLACEAPPS/ID") do |id| + array << id.text.to_i + end + + return array + end + end +end diff --git a/src/oca/ruby/opennebula/marketplace_pool.rb b/src/oca/ruby/opennebula/marketplace_pool.rb new file mode 100644 index 0000000000..06a26d5971 --- /dev/null +++ b/src/oca/ruby/opennebula/marketplace_pool.rb @@ -0,0 +1,55 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + + +require 'opennebula/pool' + +module OpenNebula + class MarketPlacePool < Pool + ####################################################################### + # Constants and Class attribute accessors + ####################################################################### + + MARKETPLACE_POOL_METHODS = { + :info => "marketpool.info" + } + + ####################################################################### + # Class constructor & Pool Methods + ####################################################################### + + # +client+ a Client object that represents a XML-RPC connection + def initialize(client) + super('MARKETPLACE_POOL','MARKETPLACE', client) + end + + # Factory method to create MarketPlace objects + def factory(element_xml) + OpenNebula::MarketPlace.new(element_xml, @client) + end + + ####################################################################### + # XML-RPC Methods for the User Object + ####################################################################### + + # Retrieves all the marketplace apps + def info() + super(MARKETPLACE_POOL_METHODS[:info]) + end + + alias_method :info!, :info + end +end diff --git a/src/oca/ruby/opennebula/marketplaceapp.rb b/src/oca/ruby/opennebula/marketplaceapp.rb new file mode 100644 index 0000000000..99689d3043 --- /dev/null +++ b/src/oca/ruby/opennebula/marketplaceapp.rb @@ -0,0 +1,263 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'opennebula/pool_element' + +module OpenNebula + class MarketPlaceApp < PoolElement + ####################################################################### + # Constants and Class Methods + ####################################################################### + + MARKETPLACEAPP_METHODS = { + :info => "marketapp.info", + :allocate => "marketapp.allocate", + :delete => "marketapp.delete", + :update => "marketapp.update", + :chown => "marketapp.chown", + :chmod => "marketapp.chmod", + :rename => "marketapp.rename", + :enable => "marketapp.enable" + } + + MARKETPLACEAPP_STATES=%w{INIT READY LOCKED ERROR DISABLED} + + SHORT_MARKETPLACEAPP_STATES={ + "INIT" => "ini", + "READY" => "rdy", + "LOCKED" => "lck", + "ERROR" => "err", + "DISABLED" => "dis" + } + + MARKETPLACEAPP_TYPES=%w{UNKNOWN IMAGE VMTEMPLATE SERVICE_TEMPLATE} + + SHORT_MARKETPLACEAPP_TYPES = { + "UNKNOWN" => "unk", + "IMAGE" => "img", + "VMTEMPLATE" => "tpl", + "SERVICE_TEMPLATE" => "srv" + } + # Creates a MarketPlace description with just its identifier + # this method should be used to create plain MarketPlace objects. + # +id+ the id of the user + # + # Example: + # app = MarketPlaceApp.new(MarketPlace.build_xml(3),rpc_client) + # + def MarketPlaceApp.build_xml(pe_id=nil) + if pe_id + app_xml = "#{pe_id}" + else + app_xml = "" + end + + XMLElement.build_xml(app_xml,'MARKETPLACEAPP') + end + + # Class constructor + def initialize(xml, client) + super(xml, client) + end + + ####################################################################### + # XML-RPC Methods for the MarketPlace Object + ####################################################################### + + # Retrieves the information of the given marketplace app + def info() + super(MARKETPLACEAPP_METHODS[:info], 'MARKETPLACEAPP') + end + + alias_method :info!, :info + + # Allocates a new MarketPlace in OpenNebula + # + # @param description [String] The template of the marketplace app + # @param mp_id [Integer] The id of the marketplace to create the app + # + # @return [Integer, OpenNebula::Error] the new ID in case of + # success, error otherwise + def allocate(description, mp_id) + super(MARKETPLACEAPP_METHODS[:allocate], description, mp_id) + end + + # Deletes the marketplace app + def delete() + super(MARKETPLACEAPP_METHODS[:delete]) + end + + # Replaces the template contents + # + # @param new_template [String] New template contents + # @param append [true, false] True to append new attributes instead of + # replace the whole template + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def update(new_template, append=false) + super(MARKETPLACEAPP_METHODS[:update], new_template, append ? 1 : 0) + end + + # Changes the owner/group + # + # @param uid [Integer] the new owner id. Set to -1 to leave the current one + # @param gid [Integer] the new group id. Set to -1 to leave the current one + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chown(uid, gid) + super(MARKETPLACEAPP_METHODS[:chown], uid, gid) + end + + # Changes the marketplace app permissions. + # + # @param octet [String] Permissions octed , e.g. 640 + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chmod_octet(octet) + super(MARKETPLACEAPP_METHODS[:chmod], octet) + end + + # Changes the marketplace app permissions. + # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u, + other_m, other_a) + super(MARKETPLACEAPP_METHODS[:chmod], owner_u, owner_m, owner_a, + group_u, group_m, group_a, other_u, other_m, other_a) + end + + # Renames this marketplace app + # + # @param name [String] New name for the marketplace app + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(MARKETPLACEAPP_METHODS[:rename], @pe_id, name) + end + + # Exports this app to a suitable OpenNebula object + # @param appid [Integer] id of the marketplace app + # @param options [Hash] to control the export behavior + # dsid [Integer] datastore to save images + # name [String] of the new object + # + # @return [Hash, OpenNebula::Error] with the ID and type of the created + # objects + # { :vm => [ vm ids ], + # :vmtemplate => [vmtemplates ids], + # :image => [ vm ids] } + def export(options={}) + return Error.new("Missing datastore id") if options[:dsid].nil? + return Error.new("Missing name to export app") if options[:name].nil? + + one = Client.new() + + rc = info + return rc if OpenNebula.is_error?(rc) + return Error.new("App is not in READY state") if state_str!="READY" + + case type_str + when "IMAGE" + if !self['APPTEMPLATE64'].nil? + tmpl=Base64::decode64(self['APPTEMPLATE64']) + else + tmpl="" + end + + name = options[:name] || "marketapp-#{self.id}" + + tmpl << "\n" + tmpl << "NAME=\"" << name << "\"\n" + tmpl << "FROM_APP=\"" << self['ID'] << "\"\n" + + image = Image.new(Image.build_xml, one) + rc = image.allocate(tmpl, options[:dsid]) + + return rc if OpenNebula.is_error?(rc) + + image_id = image.id + vmtpl_id = -1 + + if !self['TEMPLATE/VMTEMPLATE64'].nil? + tmpl=Base64::decode64(self['TEMPLATE/VMTEMPLATE64']) + + tmpl << "\nNAME=#{name}\n" + tmpl << "DISK=[ IMAGE_ID = #{image.id} ]\n" + + vmtpl = Template.new(Template.build_xml, one) + rc = vmtpl.allocate(tmpl) + + return rc if OpenNebula.is_error?(rc) + + vmtpl_id = vmtpl.id + end + + return { :image => [image_id], :vmtemplate => [vmtpl_id] } + else + return Error.new("App type #{app.type_str} not supported") + end + end + + # Enables this app + def enable + return call(MARKETPLACEAPP_METHODS[:enable], @pe_id, true) + end + + # Enables this app + def disable + return call(MARKETPLACEAPP_METHODS[:enable], @pe_id, false) + end + + # --------------------------------------------------------------------- + # Helpers to get information + # --------------------------------------------------------------------- + + # Returns the marketplace app type + def type + self['TYPE'].to_i + end + + # Returns the marketplace app type (string value) + def type_str + MARKETPLACEAPP_TYPES[type] + end + + # Returns the marketplace app type (string value) + def short_type_str + SHORT_MARKETPLACEAPP_TYPES[type_str] + end + + # Returns the state of the marketplace app (numeric value) + def state + self['STATE'].to_i + end + + # Returns the state of the marketplace app (string value) + def state_str + MARKETPLACEAPP_STATES[state] + end + + # Returns the state of the marketplace app (string value) + def short_state_str + SHORT_MARKETPLACEAPP_STATES[state_str] + end + end +end diff --git a/src/oca/ruby/opennebula/marketplaceapp_pool.rb b/src/oca/ruby/opennebula/marketplaceapp_pool.rb new file mode 100644 index 0000000000..f17d8b98a9 --- /dev/null +++ b/src/oca/ruby/opennebula/marketplaceapp_pool.rb @@ -0,0 +1,77 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + + +require 'opennebula/pool' + +module OpenNebula + class MarketPlaceAppPool < Pool + ####################################################################### + # Constants and Class attribute accessors + ####################################################################### + + MARKETPLACEAPP_POOL_METHODS = { + :info => "marketapppool.info" + } + + ####################################################################### + # Class constructor & Pool Methods + ####################################################################### + + # +client+ a Client object that represents a XML-RPC connection + def initialize(client, user_id=-1) + super('MARKETPLACEAPP_POOL','MARKETPLACEAPP', client) + + @user_id = user_id + end + + # Factory method to create MarketPlaceApp objects + def factory(element_xml) + OpenNebula::MarketPlaceApp.new(element_xml, @client) + end + + ####################################################################### + # XML-RPC Methods for the User Object + ####################################################################### + + # Retrieves all or part of the Images in the pool. + def info(*args) + case args.size + when 0 + info_filter(MARKETPLACEAPP_POOL_METHODS[:info],@user_id,-1,-1) + when 3 + info_filter(MARKETPLACEAPP_POOL_METHODS[:info],args[0],args[1],args[2]) + end + end + + def info_all() + return super(MARKETPLACEAPP_POOL_METHODS[:info]) + end + + def info_mine() + return super(MARKETPLACEAPP_POOL_METHODS[:info]) + end + + def info_group() + return super(MARKETPLACEAPP_POOL_METHODS[:info]) + end + + alias_method :info!, :info + alias_method :info_all!, :info_all + alias_method :info_mine!, :info_mine + alias_method :info_group!, :info_group + end +end diff --git a/src/oca/ruby/opennebula/virtual_network.rb b/src/oca/ruby/opennebula/virtual_network.rb index d13a333a79..463e372eba 100644 --- a/src/oca/ruby/opennebula/virtual_network.rb +++ b/src/oca/ruby/opennebula/virtual_network.rb @@ -324,6 +324,17 @@ module OpenNebula end end + # Returns an array with the numeric virtual router ids + def vrouter_ids + array = Array.new + + self.each("VROUTERS/ID") do |id| + array << id.text.to_i + end + + return array + end + private def set_publish(published) group_u = published ? 1 : 0 diff --git a/src/oca/ruby/opennebula/virtual_router.rb b/src/oca/ruby/opennebula/virtual_router.rb new file mode 100644 index 0000000000..6f47e02e35 --- /dev/null +++ b/src/oca/ruby/opennebula/virtual_router.rb @@ -0,0 +1,203 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + + +require 'opennebula/pool_element' + +module OpenNebula + class VirtualRouter < PoolElement + ####################################################################### + # Constants and Class Methods + ####################################################################### + + VIRTUAL_ROUTER_METHODS = { + :allocate => "vrouter.allocate", + :instantiate => "vrouter.instantiate", + :info => "vrouter.info", + :update => "vrouter.update", + :delete => "vrouter.delete", + :chown => "vrouter.chown", + :chmod => "vrouter.chmod", + :rename => "vrouter.rename", + :attachnic => "vrouter.attachnic", + :detachnic => "vrouter.detachnic", + } + + # Creates a VirtualRouter description with just its identifier + # this method should be used to create plain VirtualRouter objects. + # +id+ the id of the user + # + # Example: + # vrouter = VirtualRouter.new(VirtualRouter.build_xml(3),rpc_client) + # + def VirtualRouter.build_xml(pe_id=nil) + if pe_id + obj_xml = "#{pe_id}" + else + obj_xml = "" + end + + XMLElement.build_xml(obj_xml,'VROUTER') + end + + # Class constructor + def initialize(xml, client) + super(xml,client) + + @client = client + end + + ####################################################################### + # XML-RPC Methods for the VirtualRouter Object + ####################################################################### + + # Retrieves the information of the given Virtual Router + def info() + super(VIRTUAL_ROUTER_METHODS[:info], 'VROUTER') + end + + alias_method :info!, :info + + # Allocates a new VirtualRouter in OpenNebula + # + # @param description [String] The contents of the VirtualRouter. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def allocate(description) + super(VIRTUAL_ROUTER_METHODS[:allocate], description) + end + + # Creates VM instances from a VM Template. New VMs will be associated + # to this Virtual Router, and its Virtual Networks + # + # @para n_vms [Integer] Number of VMs to instantiate + # @para template_id [Integer] VM Template id to instantiate + # @param name [String] Name for the VM instances. If it is an empty + # string OpenNebula will set a default name. Wildcard %i can be used. + # @param hold [true,false] false to create the VM in pending state, + # true to create it on hold + # @param template [String] User provided Template to merge with the + # one being instantiated + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def instantiate(n_vms, template_id, name="", hold=false, template="") + return call(VIRTUAL_ROUTER_METHODS[:instantiate], @pe_id, + n_vms.to_i, template_id.to_i, name, hold, template) + end + + + # Deletes the VirtualRouter + def delete() + super(VIRTUAL_ROUTER_METHODS[:delete]) + end + + # Replaces the template contents + # + # @param new_template [String] New template contents + # @param append [true, false] True to append new attributes instead of + # replace the whole template + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def update(new_template, append=false) + super(VIRTUAL_ROUTER_METHODS[:update], new_template, append ? 1 : 0) + end + + # Changes the owner/group + # @param uid [Integer] the new owner id. Set to -1 to leave the current one + # @param gid [Integer] the new group id. Set to -1 to leave the current one + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chown(uid, gid) + super(VIRTUAL_ROUTER_METHODS[:chown], uid, gid) + end + + # Changes the VirtualRouter permissions. + # + # @param octet [String] Permissions octed , e.g. 640 + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chmod_octet(octet) + super(VIRTUAL_ROUTER_METHODS[:chmod], octet) + end + + # Changes the VirtualRouter permissions. + # Each [Integer] argument must be 1 to allow, 0 deny, -1 do not change + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def chmod(owner_u, owner_m, owner_a, group_u, group_m, group_a, other_u, + other_m, other_a) + super(VIRTUAL_ROUTER_METHODS[:chmod], owner_u, owner_m, owner_a, group_u, + group_m, group_a, other_u, other_m, other_a) + end + + # Renames this VirtualRouter + # + # @param name [String] New name for the VirtualRouter. + # + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def rename(name) + return call(VIRTUAL_ROUTER_METHODS[:rename], @pe_id, name) + end + + # Attaches a NIC to this VirtualRouter, and each one of its VMs + # + # @param nic_template [String] Template containing a NIC element + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def nic_attach(nic_template) + return call(VIRTUAL_ROUTER_METHODS[:attachnic], @pe_id, nic_template) + end + + # Detaches a NIC from this VirtualRouter, and each one of its VMs + # + # @param nic_id [Integer] Id of the NIC to be detached + # @return [nil, OpenNebula::Error] nil in case of success, Error + # otherwise + def nic_detach(nic_id) + return call(VIRTUAL_ROUTER_METHODS[:detachnic], @pe_id, nic_id) + end + + ####################################################################### + # Helpers to get VirtualRouter information + ####################################################################### + + # Returns the group identifier + # @return [Integer] the element's group ID + def gid + self['GID'].to_i + end + + def owner_id + self['UID'].to_i + end + + # Returns an array with the numeric VM ids + def vm_ids + array = Array.new + + self.each("VMS/ID") do |id| + array << id.text.to_i + end + + return array + end + end +end diff --git a/src/oca/ruby/opennebula/virtual_router_pool.rb b/src/oca/ruby/opennebula/virtual_router_pool.rb new file mode 100644 index 0000000000..3d75d6c5fb --- /dev/null +++ b/src/oca/ruby/opennebula/virtual_router_pool.rb @@ -0,0 +1,79 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + + +require 'opennebula/pool' + +module OpenNebula + class VirtualRouterPool < Pool + ####################################################################### + # Constants and Class attribute accessors + ####################################################################### + + + VIRTUAL_ROUTER_POOL_METHODS = { + :info => "vrouterpool.info" + } + + ####################################################################### + # Class constructor & Pool Methods + ####################################################################### + + # +client+ a Client object that represents an XML-RPC connection + # +user_id+ used to refer to a Pool with Virtual Routers from that user + def initialize(client, user_id=-1) + super('VROUTER_POOL','VROUTER',client) + + @user_id = user_id + end + + # Factory method to create Virtual Router objects + def factory(element_xml) + OpenNebula::VirtualRouter.new(element_xml,@client) + end + + ####################################################################### + # XML-RPC Methods for the Virtual Router Object + ####################################################################### + + # Retrieves all or part of the Virtual Routers in the pool. + def info(*args) + case args.size + when 0 + info_filter(VIRTUAL_ROUTER_POOL_METHODS[:info],@user_id,-1,-1) + when 3 + info_filter(VIRTUAL_ROUTER_POOL_METHODS[:info],args[0],args[1],args[2]) + end + end + + def info_all() + return super(VIRTUAL_ROUTER_POOL_METHODS[:info]) + end + + def info_mine() + return super(VIRTUAL_ROUTER_POOL_METHODS[:info]) + end + + def info_group() + return super(VIRTUAL_ROUTER_POOL_METHODS[:info]) + end + + alias_method :info!, :info + alias_method :info_all!, :info_all + alias_method :info_mine!, :info_mine + alias_method :info_group!, :info_group + end +end diff --git a/src/oca/ruby/opennebula/xml_element.rb b/src/oca/ruby/opennebula/xml_element.rb index 356ca34049..156b92b6e2 100644 --- a/src/oca/ruby/opennebula/xml_element.rb +++ b/src/oca/ruby/opennebula/xml_element.rb @@ -65,6 +65,11 @@ module OpenNebula return doc end + # Checks if the internal XML representation is valid + def xml_nil? + return @xml.nil? + end + # Extract a text element from the XML description of the PoolElement. # # @param [String] key Xpath expression diff --git a/src/onedb/fsck.rb b/src/onedb/fsck.rb index 69e4582924..65b0c0c3bc 100644 --- a/src/onedb/fsck.rb +++ b/src/onedb/fsck.rb @@ -31,7 +31,7 @@ require 'nokogiri' module OneDBFsck VERSION = "4.11.80" - LOCAL_VERSION = "4.13.85" + LOCAL_VERSION = "4.90.0" def check_db_version() db_version = read_db_version() @@ -59,9 +59,10 @@ EOT IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR CLONE DELETE USED_PERS} - VM_BIN = 0x0000001000000000 - NET_BIN = 0x0000004000000000 - HOLD = 0xFFFFFFFF + VM_BIN = 0x0000001000000000 + NET_BIN = 0x0000004000000000 + VROUTER_BIN = 0x0004000000000000 + HOLD = 0xFFFFFFFF def fsck @@ -728,6 +729,7 @@ EOT counters[:host] = {} counters[:image] = {} counters[:vnet] = {} + counters[:vrouter] = {} # Initialize all the host counters to 0 @db.fetch("SELECT oid, name FROM host_pool") do |row| @@ -786,6 +788,15 @@ EOT log_time() + # Initialize all the vrouter counters to 0 + @db.fetch("SELECT oid FROM vrouter_pool") do |row| + counters[:vrouter][row[:oid]] = { + :vms => Set.new + } + end + + log_time() + vms_fix = {} # Aggregate information of the RUNNING vms @@ -825,7 +836,7 @@ EOT if ar_id_e.nil? if !counters[:vnet][net_id][:no_ar_leases][mac_s_to_i(mac)].nil? - log_error("VNet has more than one VM with the same MAC address (#{mac}). "<< + log_error("VNet #{net_id} has more than one lease with the same MAC address (#{mac}). "<< "FSCK can't handle this, and consistency is not guaranteed", false) end @@ -836,7 +847,8 @@ EOT :ip6_ula => nic.at_xpath("IP6_ULA").nil? ? nil : nic.at_xpath("IP6_ULA").text, :mac => mac, :vm => row[:oid], - :vnet => nil + :vnet => nil, + :vrouter => nil } else ar_id = ar_id_e.text.to_i @@ -852,7 +864,8 @@ EOT :ip6_ula => nic.at_xpath("IP6_ULA").nil? ? nil : nic.at_xpath("IP6_ULA").text, :mac => mac, :vm => row[:oid], - :vnet => nil + :vnet => nil, + :vrouter => nil } end end @@ -860,6 +873,21 @@ EOT end end + # See if it's part of a Virtual Router + vrouter_e = vm_doc.root.at_xpath("TEMPLATE/VROUTER_ID") + + if !vrouter_e.nil? + vr_id = vrouter_e.text.to_i + counters_vrouter = counters[:vrouter][vr_id] + + if counters_vrouter.nil? + log_error("VM #{row[:oid]} is part of VRouter #{vr_id}, but "<< + "it does not exist", false) + else + counters_vrouter[:vms].add(row[:oid]) + end + end + # Host resources # Only states that add to Host resources consumption are @@ -969,6 +997,125 @@ EOT log_time() + ######################################################################## + # Virtual Routers + # + # VROUTER/VMS/ID + ######################################################################## + + vrouters_fix = {} + + # Aggregate information of the RUNNING vms + @db.fetch("SELECT oid,body FROM vrouter_pool") do |row| + vrouter_doc = Nokogiri::XML(row[:body],nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks} + + # VNets used by this Virtual Router + vrouter_doc.root.xpath("TEMPLATE/NIC").each do |nic| + net_id = nil + nic.xpath("NETWORK_ID").each do |nid| + net_id = nid.text.to_i + end + + floating = false + + nic.xpath("FLOATING_IP").each do |floating_e| + floating = (floating_e.text.upcase == "YES") + end + + if !net_id.nil? && floating + if counters[:vnet][net_id].nil? + log_error("VRouter #{row[:oid]} is using VNet #{net_id}, "<< + "but it does not exist", false) + else + mac = nic.at_xpath("MAC").nil? ? nil : nic.at_xpath("MAC").text + + ar_id_e = nic.at_xpath('AR_ID') + + if ar_id_e.nil? + if !counters[:vnet][net_id][:no_ar_leases][mac_s_to_i(mac)].nil? + log_error("VNet #{net_id} has more than one lease with the same MAC address (#{mac}). "<< + "FSCK can't handle this, and consistency is not guaranteed", false) + end + + counters[:vnet][net_id][:no_ar_leases][mac_s_to_i(mac)] = { + :ip => nic.at_xpath("IP").nil? ? nil : nic.at_xpath("IP").text, + :ip6_global => nic.at_xpath("IP6_GLOBAL").nil? ? nil : nic.at_xpath("IP6_GLOBAL").text, + :ip6_link => nic.at_xpath("IP6_LINK").nil? ? nil : nic.at_xpath("IP6_LINK").text, + :ip6_ula => nic.at_xpath("IP6_ULA").nil? ? nil : nic.at_xpath("IP6_ULA").text, + :mac => mac, + :vm => nil, + :vnet => nil, + :vrouter => row[:oid], + } + else + ar_id = ar_id_e.text.to_i + + if counters[:vnet][net_id][:ar_leases][ar_id].nil? + log_error("VRouter #{row[:oid]} is using VNet #{net_id}, AR #{ar_id}, "<< + "but the AR does not exist", false) + else + counters[:vnet][net_id][:ar_leases][ar_id][mac_s_to_i(mac)] = { + :ip => nic.at_xpath("IP").nil? ? nil : nic.at_xpath("IP").text, + :ip6_global => nic.at_xpath("IP6_GLOBAL").nil? ? nil : nic.at_xpath("IP6_GLOBAL").text, + :ip6_link => nic.at_xpath("IP6_LINK").nil? ? nil : nic.at_xpath("IP6_LINK").text, + :ip6_ula => nic.at_xpath("IP6_ULA").nil? ? nil : nic.at_xpath("IP6_ULA").text, + :mac => mac, + :vm => nil, + :vnet => nil, + :vrouter => row[:oid], + } + end + end + end + end + end + + # re-do list of VM IDs + error = false + + counters_vrouter = counters[:vrouter][row[:oid]] + + vms_elem = vrouter_doc.root.at_xpath("VMS").remove + + vms_new_elem = vrouter_doc.create_element("VMS") + vrouter_doc.root.add_child(vms_new_elem) + + counters_vrouter[:vms].each do |id| + id_elem = vms_elem.at_xpath("ID[.=#{id}]") + + if id_elem.nil? + log_error( + "VM #{id} is missing from VRouter #{row[:oid]} VM id list") + + error = true + else + id_elem.remove + end + + vms_new_elem.add_child(vrouter_doc.create_element("ID")).content = id.to_s + end + + vms_elem.xpath("ID").each do |id_elem| + log_error( + "VM #{id_elem.text} is in VRouter #{row[:oid]} VM id list, "<< + "but it should not") + + error = true + end + + if (error) + vrouters_fix[row[:oid]] = vrouter_doc.root.to_s + end + end + + @db.transaction do + vrouters_fix.each do |id, body| + @db[:vrouter_pool].where(:oid => id).update(:body => body) + end + end + + log_time() + ######################################################################## # Hosts # @@ -1278,7 +1425,8 @@ EOT :ip6_ula => nil, :mac => nil, :vm => nil, - :vnet => row[:oid] + :vnet => row[:oid], + :vrouter => nil } #MAC @@ -1389,7 +1537,8 @@ EOT :ip6_ula => nil, :mac => nil, :vm => nil, - :vnet => nil + :vnet => nil, + :vrouter => nil } # MAC @@ -1432,9 +1581,12 @@ EOT if (binary_magic & VM_BIN != 0) lease[:vm] = lease_oid lease_obj = "VM" - else # binary_magic & NET_BIN != 0 + elsif (binary_magic & NET_BIN != 0) lease[:vnet] = lease_oid lease_obj = "VNet" + else #(binary_magic & VROUTER_BIN != 0) + lease[:vrouter] = lease_oid + lease_obj = "VRouter" end counter_lease = counter_ar[mac] @@ -1457,8 +1609,9 @@ EOT if counter_lease != lease # Things that can be fixed - if (counter_lease[:vm] != lease[:vm] || - counter_lease[:vnet] != lease[:vnet]) + if (counter_lease[:vm] != lease[:vm] || + counter_lease[:vnet] != lease[:vnet] || + counter_lease[:vrouter] != lease[:vrouter]) new_lease_obj = "" new_lease_oid = 0 @@ -1470,12 +1623,18 @@ EOT new_binary_magic = (VM_BIN | (new_lease_oid & 0xFFFFFFFF)) - else + elsif !counter_lease[:vnet].nil? new_lease_obj = "VNet" new_lease_oid = counter_lease[:vnet].to_i new_binary_magic = (NET_BIN | (new_lease_oid & 0xFFFFFFFF)) + else #if !counter_lease[:vrouter].nil? + new_lease_obj = "VRouter" + new_lease_oid = counter_lease[:vrouter].to_i + + new_binary_magic = (VROUTER_BIN | + (new_lease_oid & 0xFFFFFFFF)) end if (lease[:vm] == HOLD) @@ -1527,12 +1686,18 @@ EOT new_binary_magic = (VM_BIN | (new_lease_oid & 0xFFFFFFFF)) - else + elsif !counter_lease[:vnet].nil? new_lease_obj = "VNet" new_lease_oid = counter_lease[:vnet].to_i new_binary_magic = (NET_BIN | (new_lease_oid & 0xFFFFFFFF)) + else #if !counter_lease[:vrouter].nil? + new_lease_obj = "VRouter" + new_lease_oid = counter_lease[:vrouter].to_i + + new_binary_magic = (VROUTER_BIN | + (new_lease_oid & 0xFFFFFFFF)) end log_error("VNet #{oid} AR #{ar_id} does not have a lease "<< @@ -1799,6 +1964,31 @@ EOT end + @db.fetch("SELECT body FROM vrouter_pool WHERE #{where_filter}") do |vrouter_row| + vrouter_doc = Nokogiri::XML(vrouter_row[:body],nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks} + + # VNet quotas + vrouter_doc.root.xpath("TEMPLATE/NIC").each { |nic| + net_id = nil + nic.xpath("NETWORK_ID").each do |nid| + net_id = nid.text + end + + floating = false + + nic.xpath("FLOATING_IP").each do |floating_e| + floating = (floating_e.text.upcase == "YES") + end + + if !net_id.nil? && floating + vnet_usage[net_id] = 0 if vnet_usage[net_id].nil? + + vnet_usage[net_id] += 1 + end + } + + end + # VM quotas vm_elem = nil diff --git a/src/onedb/local/4.13.85_to_4.90.0.rb b/src/onedb/local/4.13.85_to_4.90.0.rb new file mode 100644 index 0000000000..a5ecf9764f --- /dev/null +++ b/src/onedb/local/4.13.85_to_4.90.0.rb @@ -0,0 +1,123 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'opennebula' + +include OpenNebula + +module Migrator + def db_version + "4.90.0" + end + + def one_version + "OpenNebula 4.90.0" + end + + def up + init_log_time() + + # 4215 + + @db.run "CREATE TABLE vrouter_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER);" + + @db.transaction do + @db.fetch("SELECT oid,body FROM group_pool") do |row| + doc = Nokogiri::XML(row[:body],nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks} + + doc.root.xpath("ADMINS/ID").each do |uid| + user = Acl::USERS["UID"] | uid.text.to_i + resource = 354936097341440 | Acl::USERS["GID"] | row[:oid] + + @db[:acl].where({ + :user=>user, # # + :resource=>resource, # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP/@ + :rights=>3, # USE+MANAGE + :zone=>17179869184 # * + }).update( + # VM+NET+IMAGE+TEMPLATE+DOCUMENT+SECGROUP+VROUTER/@101 + :resource => (1480836004184064 | Acl::USERS["GID"] | row[:oid])) + end + end + end + + log_time() + + @db.run "ALTER TABLE network_pool RENAME TO old_network_pool;" + @db.run "CREATE TABLE network_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, cid INTEGER, pid INTEGER, UNIQUE(name,uid));" + + @db.transaction do + @db.fetch("SELECT * FROM old_network_pool") do |row| + doc = Nokogiri::XML(row[:body],nil,NOKOGIRI_ENCODING){|c| c.default_xml.noblanks} + + doc.root.add_child(doc.create_element("VROUTERS")) + + @db[:network_pool].insert( + :oid => row[:oid], + :name => row[:name], + :body => doc.root.to_s, + :uid => row[:uid], + :gid => row[:gid], + :owner_u => row[:owner_u], + :group_u => row[:group_u], + :other_u => row[:other_u], + :cid => row[:cid], + :pid => row[:pid]) + end + end + + @db.run "DROP TABLE old_network_pool;" + + log_time() + + ######################################################################## + # OpenNebula Systems MarketPlace + ######################################################################## + + oneadmin_uname = nil + + @db.fetch("SELECT name FROM user_pool WHERE oid=0") do |row| + oneadmin_uname = row[:name] + end + + if oneadmin_uname == nil + puts "Error trying to read oneadmin's user name ('SELECT name FROM user_pool WHERE oid=0')" + return false + end + + oneadmin_gname = nil + + @db.fetch("SELECT name FROM group_pool WHERE oid=0") do |row| + oneadmin_gname = row[:name] + end + + if oneadmin_gname == nil + puts "Error trying to read oneadmin's group name ('SELECT name FROM group_pool WHERE oid=0')" + return false + end + + @db.run "CREATE TABLE marketplace_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER);" + + @db.run "INSERT INTO marketplace_pool VALUES(0,'OpenNebula Public','000#{oneadmin_uname}#{oneadmin_gname}OpenNebula Public000111100100',0,0,1,1,1);" + + @db.run "INSERT INTO pool_control VALUES('marketplace_pool',99);" + + @db.run "CREATE TABLE marketplaceapp_pool (oid INTEGER PRIMARY KEY, name VARCHAR(128), body MEDIUMTEXT, uid INTEGER, gid INTEGER, owner_u INTEGER, group_u INTEGER, other_u INTEGER, UNIQUE(name,uid));" + + return true + end + +end diff --git a/src/pool/PoolObjectSQL.cc b/src/pool/PoolObjectSQL.cc index d6fceec1c3..e4e3db6860 100644 --- a/src/pool/PoolObjectSQL.cc +++ b/src/pool/PoolObjectSQL.cc @@ -545,7 +545,7 @@ int PoolObjectSQL::lock_db_from_xml() rc += xpath(locked_int, "/*/LOCK/LOCKED", 0); rc += xpath(lock_owner, "/*/LOCK/OWNER", ""); - rc += xpath(lock_expires, "/*/LOCK/EXPIRES", 0); + rc += xpath(lock_expires, "/*/LOCK/EXPIRES", 0); locked = locked_int; diff --git a/src/pool/PoolSQL.cc b/src/pool/PoolSQL.cc index b6db69349f..478e605afc 100644 --- a/src/pool/PoolSQL.cc +++ b/src/pool/PoolSQL.cc @@ -852,11 +852,9 @@ void PoolSQL::oid_filter(int start_id, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void PoolSQL::register_hooks(vector hook_mads, - const string& remotes_location) +void PoolSQL::register_hooks(vector hook_mads, + const string& remotes_location) { - const VectorAttribute * vattr; - string name; string on; string cmd; @@ -864,14 +862,12 @@ void PoolSQL::register_hooks(vector hook_mads, for (unsigned int i = 0 ; i < hook_mads.size() ; i++ ) { - vattr = static_cast(hook_mads[i]); + name = hook_mads[i]->vector_value("NAME"); + on = hook_mads[i]->vector_value("ON"); + cmd = hook_mads[i]->vector_value("COMMAND"); + arg = hook_mads[i]->vector_value("ARGUMENTS"); - name = vattr->vector_value("NAME"); - on = vattr->vector_value("ON"); - cmd = vattr->vector_value("COMMAND"); - arg = vattr->vector_value("ARGUMENTS"); - - transform (on.begin(),on.end(),on.begin(),(int(*)(int))toupper); + one_util::toupper(on); if ( on.empty() || cmd.empty() ) { diff --git a/src/rm/Request.cc b/src/rm/Request.cc index 1ad3268c1d..ebd40fcd26 100644 --- a/src/rm/Request.cc +++ b/src/rm/Request.cc @@ -19,56 +19,63 @@ #include "PoolObjectAuth.h" -string Request::format_str; - +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* RequestLog Methods */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void Request::execute( - xmlrpc_c::paramList const& _paramList, - xmlrpc_c::value * const _retval) +string Request::object_name(PoolObjectSQL::ObjectType ob) { - RequestAttributes att; - - att.retval = _retval; - att.session = xmlrpc_c::value_string (_paramList.getString(0)); - - att.req_id = (reinterpret_cast(this) * rand()) % 10000; - - Nebula& nd = Nebula::instance(); - UserPool* upool = nd.get_upool(); - - bool authenticated = upool->authenticate(att.session, - att.password, - att.uid, - att.gid, - att.uname, - att.gname, - att.group_ids, - att.umask); - - log_method_invoked(att, _paramList); - - if ( authenticated == false ) + switch (ob) { - failure_response(AUTHENTICATION, authenticate_error(), att); - } - else - { - request_execute(_paramList, att); - } - - log_result(att); + case PoolObjectSQL::VM: + return "virtual machine"; + case PoolObjectSQL::HOST: + return "host"; + case PoolObjectSQL::NET: + return "virtual network"; + case PoolObjectSQL::IMAGE: + return "image"; + case PoolObjectSQL::USER: + return "user"; + case PoolObjectSQL::TEMPLATE: + return "virtual machine template"; + case PoolObjectSQL::GROUP: + return "group"; + case PoolObjectSQL::ACL: + return "ACL"; + case PoolObjectSQL::DATASTORE: + return "datastore"; + case PoolObjectSQL::CLUSTER: + return "cluster"; + case PoolObjectSQL::DOCUMENT: + return "document"; + case PoolObjectSQL::ZONE: + return "zone"; + case PoolObjectSQL::SECGROUP: + return "security group"; + case PoolObjectSQL::VDC: + return "VDC"; + case PoolObjectSQL::VROUTER: + return "virtual router"; + case PoolObjectSQL::MARKETPLACE: + return "marketplace"; + case PoolObjectSQL::MARKETPLACEAPP: + return "marketplaceapp"; + default: + return "-"; + } }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void Request::log_method_invoked( - const RequestAttributes& att, - const xmlrpc_c::paramList& paramList) +void Request::log_method_invoked(const RequestAttributes& att, + const xmlrpc_c::paramList& paramList, const string& format_str, + const std::string& method_name, const std::set& hidden_params) { - ostringstream oss; + std::ostringstream oss; for (unsigned int j = 0 ;j < format_str.length() - 1; j++ ) { @@ -141,16 +148,15 @@ void Request::log_method_invoked( } } - NebulaLog::log("ReM",Log::DEBUG, oss); + NebulaLog::log("ReM", Log::DEBUG, oss); } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void Request::log_result( - const RequestAttributes& att) +void Request::log_result(const RequestAttributes& att, const string& method_name) { - ostringstream oss; + std::ostringstream oss; oss << "Req:" << att.req_id << " UID:"; @@ -177,23 +183,21 @@ void Request::log_result( log_xmlrpc_value(vvalue[i], oss); } - NebulaLog::log("ReM",Log::DEBUG, oss); + NebulaLog::log("ReM", Log::DEBUG, oss); } else { oss << "FAILURE " << static_cast(xmlrpc_c::value_string(vvalue[1])); - NebulaLog::log("ReM",Log::ERROR, oss); + NebulaLog::log("ReM", Log::ERROR, oss); } } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void Request::log_xmlrpc_value( - const xmlrpc_c::value& v, - ostringstream& oss) +void Request::log_xmlrpc_value(const xmlrpc_c::value& v, std::ostringstream& oss) { size_t st_limit = 20; size_t st_newline; @@ -245,6 +249,53 @@ void Request::log_xmlrpc_value( } } +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* Request Methods */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +string Request::format_str; + +/* -------------------------------------------------------------------------- */ + +void Request::execute( + xmlrpc_c::paramList const& _paramList, + xmlrpc_c::value * const _retval) +{ + RequestAttributes att; + + att.retval = _retval; + att.session = xmlrpc_c::value_string (_paramList.getString(0)); + + att.req_id = (reinterpret_cast(this) * rand()) % 10000; + + Nebula& nd = Nebula::instance(); + UserPool* upool = nd.get_upool(); + + bool authenticated = upool->authenticate(att.session, + att.password, + att.uid, + att.gid, + att.uname, + att.gname, + att.group_ids, + att.umask); + + log_method_invoked(att, _paramList, format_str, method_name, hidden_params); + + if ( authenticated == false ) + { + failure_response(AUTHENTICATION, att); + } + else + { + request_execute(_paramList, att); + } + + log_result(att, method_name); +}; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -261,9 +312,8 @@ bool Request::basic_authorization(int oid, if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return false; } @@ -293,9 +343,8 @@ bool Request::basic_authorization(int oid, if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return false; } @@ -449,15 +498,11 @@ bool Request::quota_authorization(Template * tmpl, Quotas::QuotaType qtype, RequestAttributes& att) { - string error_str; - - bool auth = quota_authorization(tmpl, qtype, att, error_str); + bool auth = quota_authorization(tmpl, qtype, att, att.resp_msg); if ( auth == false ) { - failure_response(AUTHORIZATION, - request_error(error_str, ""), - att); + failure_response(AUTHORIZATION, att); } return auth; @@ -538,6 +583,78 @@ void Request::failure_response(ErrorCode ec, const string& str_val, *(att.retval) = arrayresult; } +/* -------------------------------------------------------------------------- */ + +void Request::failure_response(ErrorCode ec, RequestAttributes& att) +{ + std::ostringstream oss; + std::string obname; + + if ( att.resp_obj == PoolObjectSQL::NONE ) + { + obname = object_name(auth_object); + } + else + { + obname = object_name(att.resp_obj); + } + + oss << "[" << method_name << "] "; + + switch(ec) + { + case SUCCESS: + return; + + case AUTHORIZATION: + oss << "User [" << att.uid << "] "; + + if (att.resp_msg.empty()) + { + oss << "not authorized to perform action on " << obname << "."; + } + else + { + oss << ": " << att.resp_msg << "."; + } + break; + + case AUTHENTICATION: + oss << "User couldn't be authenticated, aborting call."; + break; + + case ACTION: + case XML_RPC_API: + case INTERNAL: + oss << att.resp_msg; + break; + + case NO_EXISTS: + oss << "Error getting " << obname; + + if ( att.resp_id != -1 ) + { + oss << " [" << att.resp_id << "]."; + } + else + { + oss << " Pool."; + } + break; + + case ALLOCATE: + oss << "Error allocating a new " << obname << "."; + + if (!att.resp_msg.empty()) + { + oss << " " << att.resp_msg; + } + break; + } + + failure_response(ec, oss.str(), att); +} + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -590,155 +707,6 @@ void Request::success_response(bool val, RequestAttributes& att) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -string Request::object_name(PoolObjectSQL::ObjectType ob) -{ - switch (ob) - { - case PoolObjectSQL::VM: - return "virtual machine"; - case PoolObjectSQL::HOST: - return "host"; - case PoolObjectSQL::NET: - return "virtual network"; - case PoolObjectSQL::IMAGE: - return "image"; - case PoolObjectSQL::USER: - return "user"; - case PoolObjectSQL::TEMPLATE: - return "virtual machine template"; - case PoolObjectSQL::GROUP: - return "group"; - case PoolObjectSQL::ACL: - return "ACL"; - case PoolObjectSQL::DATASTORE: - return "datastore"; - case PoolObjectSQL::CLUSTER: - return "cluster"; - case PoolObjectSQL::DOCUMENT: - return "document"; - case PoolObjectSQL::ZONE: - return "zone"; - case PoolObjectSQL::SECGROUP: - return "security group"; - case PoolObjectSQL::VDC: - return "VDC"; - default: - return "-"; - } -}; - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -string Request::authorization_error (const string &message, - RequestAttributes& att) -{ - ostringstream oss; - - oss << "[" << method_name << "]" << " User [" << att.uid << "] "; - - if ( message.empty() ) - { - oss << "not authorized to perform action on " - << object_name(auth_object) << "."; - } - else - { - oss << ": " << message << "."; - } - - return oss.str(); -} - -/* -------------------------------------------------------------------------- */ - -string Request::authenticate_error() -{ - ostringstream oss; - - oss << "[" << method_name << "]" << " User couldn't be authenticated," << - " aborting call."; - - return oss.str(); -} - -/* -------------------------------------------------------------------------- */ - -string Request::get_error (const string &object, - int id) -{ - ostringstream oss; - - oss << "[" << method_name << "]" << " Error getting " << - object; - - if ( id != -1 ) - { - oss << " [" << id << "]."; - } - else - { - oss << " Pool."; - } - - return oss.str(); -} -/* -------------------------------------------------------------------------- */ - -string Request::request_error (const string &err_desc, const string &err_detail) -{ - ostringstream oss; - - oss << "[" << method_name << "] " << err_desc; - - if (!err_detail.empty()) - { - oss << ". " << err_detail; - } - - return oss.str(); -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -string Request::allocate_error(PoolObjectSQL::ObjectType obj, - const string& error) -{ - ostringstream oss; - - oss << "[" << method_name << "]" << " Error allocating a new " - << object_name(obj) << "."; - - if (!error.empty()) - { - oss << " " << error; - } - - return oss.str(); -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -string Request::allocate_error (const string& error) -{ - ostringstream oss; - - oss << "[" << method_name << "]" << " Error allocating a new " - << object_name(auth_object) << "."; - - if (!error.empty()) - { - oss << " " << error; - } - - return oss.str(); -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - int Request::get_info( PoolSQL * pool, int id, @@ -754,7 +722,9 @@ int Request::get_info( { if (throw_error) { - failure_response(NO_EXISTS, get_error(object_name(type), id), att); + att.resp_obj = type; + att.resp_id = id; + failure_response(NO_EXISTS, att); } return -1; diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index 15f57cdf20..fc881e8864 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -40,6 +40,8 @@ #include "RequestManagerGroup.h" #include "RequestManagerVdc.h" #include "RequestManagerDatastore.h" +#include "RequestManagerMarketPlaceApp.h" +#include "RequestManagerVirtualRouter.h" #include "RequestManagerSystem.h" #include "RequestManagerProxy.h" @@ -349,6 +351,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr doc_update(new DocumentUpdateTemplate()); xmlrpc_c::methodPtr cluster_update(new ClusterUpdateTemplate()); xmlrpc_c::methodPtr secg_update(new SecurityGroupUpdateTemplate()); + xmlrpc_c::methodPtr vrouter_update(new VirtualRouterUpdateTemplate()); // Allocate Methods xmlrpc_c::methodPtr vm_allocate(new VirtualMachineAllocate()); @@ -360,6 +363,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr cluster_allocate(new ClusterAllocate()); xmlrpc_c::methodPtr doc_allocate(new DocumentAllocate()); xmlrpc_c::methodPtr secg_allocate(new SecurityGroupAllocate()); + xmlrpc_c::methodPtr vrouter_allocate(new VirtualRouterAllocate()); // Clone Methods xmlrpc_c::methodPtr template_clone(new VMTemplateClone()); @@ -375,6 +379,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr cluster_delete(new ClusterDelete()); xmlrpc_c::methodPtr doc_delete(new DocumentDelete()); xmlrpc_c::methodPtr secg_delete(new SecurityGroupDelete()); + xmlrpc_c::methodPtr vrouter_delete(new VirtualRouterDelete()); // Info Methods xmlrpc_c::methodPtr vm_info(new VirtualMachineInfo()); @@ -386,6 +391,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr cluster_info(new ClusterInfo()); xmlrpc_c::methodPtr doc_info(new DocumentInfo()); xmlrpc_c::methodPtr secg_info(new SecurityGroupInfo()); + xmlrpc_c::methodPtr vrouter_info(new VirtualRouterInfo()); // Lock Methods xmlrpc_c::methodPtr doc_lock(new DocumentLock()); @@ -401,6 +407,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr clusterpool_info(new ClusterPoolInfo()); xmlrpc_c::methodPtr docpool_info(new DocumentPoolInfo()); xmlrpc_c::methodPtr secgpool_info(new SecurityGroupPoolInfo()); + xmlrpc_c::methodPtr vrouter_pool_info(new VirtualRouterPoolInfo()); // Host Methods xmlrpc_c::methodPtr host_enable(new HostEnable()); @@ -427,6 +434,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr datastore_chown(new DatastoreChown()); xmlrpc_c::methodPtr doc_chown(new DocumentChown()); xmlrpc_c::methodPtr secg_chown(new SecurityGroupChown()); + xmlrpc_c::methodPtr vrouter_chown(new VirtualRouterChown()); // Chmod Methods xmlrpc_c::methodPtr vm_chmod(new VirtualMachineChmod()); @@ -436,6 +444,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr datastore_chmod(new DatastoreChmod()); xmlrpc_c::methodPtr doc_chmod(new DocumentChmod()); xmlrpc_c::methodPtr secg_chmod(new SecurityGroupChmod()); + xmlrpc_c::methodPtr vrouter_chmod(new VirtualRouterChmod()); // Cluster Methods xmlrpc_c::methodPtr cluster_addhost(new ClusterAddHost()); @@ -459,6 +468,12 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr datastore_rename(new DatastoreRename()); xmlrpc_c::methodPtr host_rename(new HostRename()); xmlrpc_c::methodPtr secg_rename(new SecurityGroupRename()); + xmlrpc_c::methodPtr vrouter_rename(new VirtualRouterRename()); + + // Virtual Router Methods + xmlrpc_c::methodPtr vrouter_instantiate(new VirtualRouterInstantiate()); + xmlrpc_c::methodPtr vrouter_attachnic(new VirtualRouterAttachNic()); + xmlrpc_c::methodPtr vrouter_detachnic(new VirtualRouterDetachNic()); /* VM related methods */ RequestManagerRegistry.addMethod("one.vm.deploy", vm_deploy); @@ -884,6 +899,117 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vdcpool.info", vdcpool_info); + /* Virtual Router related methods*/ + RequestManagerRegistry.addMethod("one.vrouter.update", vrouter_update); + RequestManagerRegistry.addMethod("one.vrouter.allocate",vrouter_allocate); + RequestManagerRegistry.addMethod("one.vrouter.delete", vrouter_delete); + RequestManagerRegistry.addMethod("one.vrouter.info", vrouter_info); + RequestManagerRegistry.addMethod("one.vrouter.chown", vrouter_chown); + RequestManagerRegistry.addMethod("one.vrouter.chmod", vrouter_chmod); + RequestManagerRegistry.addMethod("one.vrouter.rename", vrouter_rename); + RequestManagerRegistry.addMethod("one.vrouter.instantiate",vrouter_instantiate); + RequestManagerRegistry.addMethod("one.vrouter.attachnic", vrouter_attachnic); + RequestManagerRegistry.addMethod("one.vrouter.detachnic", vrouter_detachnic); + + RequestManagerRegistry.addMethod("one.vrouterpool.info",vrouter_pool_info); + + /* MarketPlace related methods */ + + xmlrpc_c::method * market_allocate_pt; + xmlrpc_c::method * market_update_pt; + xmlrpc_c::method * market_delete_pt; + xmlrpc_c::method * market_chmod_pt; + xmlrpc_c::method * market_chown_pt; + + if (nebula.is_federation_slave()) + { + market_allocate_pt = new RequestManagerProxy("one.market.allocate"); + market_update_pt = new RequestManagerProxy("one.market.update"); + market_delete_pt = new RequestManagerProxy("one.market.delete"); + market_chmod_pt = new RequestManagerProxy("one.market.chmod"); + market_chown_pt = new RequestManagerProxy("one.market.chown"); + } + else + { + market_allocate_pt = new MarketPlaceAllocate(); + market_update_pt = new MarketPlaceUpdateTemplate(); + market_delete_pt = new MarketPlaceDelete(); + market_chmod_pt = new MarketPlaceChmod(); + market_chown_pt = new MarketPlaceChown(); + } + + xmlrpc_c::methodPtr market_allocate(market_allocate_pt); + xmlrpc_c::methodPtr market_update(market_update_pt); + xmlrpc_c::methodPtr market_delete(market_delete_pt); + xmlrpc_c::methodPtr market_chmod(market_chmod_pt); + xmlrpc_c::methodPtr market_chown(market_chown_pt); + + xmlrpc_c::methodPtr market_info(new MarketPlaceInfo()); + xmlrpc_c::methodPtr market_rename(new MarketPlaceRename()); + xmlrpc_c::methodPtr marketpool_info(new MarketPlacePoolInfo()); + + RequestManagerRegistry.addMethod("one.market.allocate", market_allocate); + RequestManagerRegistry.addMethod("one.market.update", market_update); + RequestManagerRegistry.addMethod("one.market.delete", market_delete); + RequestManagerRegistry.addMethod("one.market.chmod", market_chmod); + RequestManagerRegistry.addMethod("one.market.chown", market_chown); + + RequestManagerRegistry.addMethod("one.market.info", market_info); + RequestManagerRegistry.addMethod("one.market.rename", market_rename); + + RequestManagerRegistry.addMethod("one.marketpool.info", marketpool_info); + + /* MarketPlaceApp related methods */ + + xmlrpc_c::method * marketapp_allocate_pt; + xmlrpc_c::method * marketapp_update_pt; + xmlrpc_c::method * marketapp_delete_pt; + xmlrpc_c::method * marketapp_chmod_pt; + xmlrpc_c::method * marketapp_chown_pt; + xmlrpc_c::method * marketapp_enable_pt; + + if (nebula.is_federation_slave()) + { + marketapp_allocate_pt = new RequestManagerProxy("one.marketapp.allocate"); + marketapp_update_pt = new RequestManagerProxy("one.marketapp.update"); + marketapp_delete_pt = new RequestManagerProxy("one.marketapp.delete"); + marketapp_chmod_pt = new RequestManagerProxy("one.marketapp.chmod"); + marketapp_chown_pt = new RequestManagerProxy("one.marketapp.chown"); + marketapp_enable_pt = new RequestManagerProxy("one.marketapp.enable"); + } + else + { + marketapp_allocate_pt = new MarketPlaceAppAllocate(); + marketapp_update_pt = new MarketPlaceAppUpdateTemplate(); + marketapp_delete_pt = new MarketPlaceAppDelete(); + marketapp_chmod_pt = new MarketPlaceAppChmod(); + marketapp_chown_pt = new MarketPlaceAppChown(); + marketapp_enable_pt = new MarketPlaceAppEnable(); + } + + xmlrpc_c::methodPtr marketapp_allocate(marketapp_allocate_pt); + xmlrpc_c::methodPtr marketapp_update(marketapp_update_pt); + xmlrpc_c::methodPtr marketapp_delete(marketapp_delete_pt); + xmlrpc_c::methodPtr marketapp_chmod(marketapp_chmod_pt); + xmlrpc_c::methodPtr marketapp_chown(marketapp_chown_pt); + xmlrpc_c::methodPtr marketapp_enable(marketapp_enable_pt); + + xmlrpc_c::methodPtr marketapp_info(new MarketPlaceAppInfo()); + xmlrpc_c::methodPtr marketapp_rename(new MarketPlaceAppRename()); + xmlrpc_c::methodPtr marketapppool_info(new MarketPlaceAppPoolInfo()); + + RequestManagerRegistry.addMethod("one.marketapp.allocate", marketapp_allocate); + RequestManagerRegistry.addMethod("one.marketapp.update", marketapp_update); + RequestManagerRegistry.addMethod("one.marketapp.delete", marketapp_delete); + RequestManagerRegistry.addMethod("one.marketapp.chmod", marketapp_chmod); + RequestManagerRegistry.addMethod("one.marketapp.chown", marketapp_chown); + RequestManagerRegistry.addMethod("one.marketapp.enable", marketapp_enable); + + RequestManagerRegistry.addMethod("one.marketapp.info", marketapp_info); + RequestManagerRegistry.addMethod("one.marketapp.rename", marketapp_rename); + + RequestManagerRegistry.addMethod("one.marketapppool.info", marketapppool_info); + /* System related methods */ RequestManagerRegistry.addMethod("one.system.version", system_version); RequestManagerRegistry.addMethod("one.system.config", system_config); diff --git a/src/rm/RequestManagerAcl.cc b/src/rm/RequestManagerAcl.cc index 9349d0e9e7..6cf6a4a214 100644 --- a/src/rm/RequestManagerAcl.cc +++ b/src/rm/RequestManagerAcl.cc @@ -18,8 +18,8 @@ using namespace std; -/* ------------------------------------------------------------------------- */ -/* ------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ void AclAddRule::request_execute(xmlrpc_c::paramList const& paramList, RequestAttributes& att) @@ -61,18 +61,16 @@ void AclAddRule::request_execute(xmlrpc_c::paramList const& paramList, zone = AclRule::INDIVIDUAL_ID | Nebula::instance().get_zone_id(); } - string error_msg; - if ( basic_authorization(-1, att) == false ) { return; } - int rc = aclm->add_rule(user, resource, rights, zone, error_msg); + int rc = aclm->add_rule(user, resource, rights, zone, att.resp_msg); if ( rc < 0 ) { - failure_response(INTERNAL, request_error(error_msg, ""), att); + failure_response(INTERNAL, att); return; } @@ -81,8 +79,8 @@ void AclAddRule::request_execute(xmlrpc_c::paramList const& paramList, return; } -/* ------------------------------------------------------------------------- */ -/* ------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ void AclDelRule::request_execute(xmlrpc_c::paramList const& paramList, RequestAttributes& att) @@ -95,11 +93,11 @@ void AclDelRule::request_execute(xmlrpc_c::paramList const& paramList, return; } - int rc = aclm->del_rule(oid, error_msg); + int rc = aclm->del_rule(oid, att.resp_msg); if ( rc < 0 ) { - failure_response(INTERNAL, request_error(error_msg, ""), att); + failure_response(INTERNAL, att); return; } @@ -108,8 +106,8 @@ void AclDelRule::request_execute(xmlrpc_c::paramList const& paramList, return; } -/* ------------------------------------------------------------------------- */ -/* ------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ void AclInfo::request_execute(xmlrpc_c::paramList const& paramList, RequestAttributes& att) @@ -126,7 +124,8 @@ void AclInfo::request_execute(xmlrpc_c::paramList const& paramList, if ( rc != 0 ) { - failure_response(INTERNAL, request_error("Internal Error",""), att); + att.resp_msg = "Internal Database error"; + failure_response(INTERNAL, att); return; } @@ -135,4 +134,3 @@ void AclInfo::request_execute(xmlrpc_c::paramList const& paramList, return; } -/* ------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerAllocate.cc b/src/rm/RequestManagerAllocate.cc index 3790daf0fc..30d12eb1c6 100644 --- a/src/rm/RequestManagerAllocate.cc +++ b/src/rm/RequestManagerAllocate.cc @@ -18,6 +18,8 @@ #include "Nebula.h" #include "PoolObjectSQL.h" +#include "MarketPlacePool.h" +#include "MarketPlaceAppPool.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -50,9 +52,8 @@ bool RequestManagerAllocate::allocate_authorization( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return false; } @@ -85,13 +86,8 @@ bool VirtualMachineAllocate::allocate_authorization( { if (ttmpl->check(aname)) { - ostringstream oss; - - oss << "VM Template includes a restricted attribute " << aname; - - failure_response(AUTHORIZATION, - authorization_error(oss.str(), att), - att); + att.resp_msg = "VM Template includes a restricted attribute "+aname; + failure_response(AUTHORIZATION, att); return false; } @@ -105,9 +101,8 @@ bool VirtualMachineAllocate::allocate_authorization( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return false; } @@ -134,7 +129,6 @@ void RequestManagerAllocate::request_execute(xmlrpc_c::paramList const& params, { Template * tmpl = 0; - string error_str; int rc, id; Cluster * cluster = 0; @@ -148,11 +142,11 @@ void RequestManagerAllocate::request_execute(xmlrpc_c::paramList const& params, tmpl = get_object_template(); - rc = tmpl->parse_str_or_xml(str_tmpl, error_str); + rc = tmpl->parse_str_or_xml(str_tmpl, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL, allocate_error(error_str), att); + failure_response(INTERNAL, att); delete tmpl; return; @@ -183,11 +177,11 @@ void RequestManagerAllocate::request_execute(xmlrpc_c::paramList const& params, return; } - rc = pool_allocate(params, tmpl, id, error_str,att,cluster_id,cluster_name); + rc = pool_allocate(params, tmpl, id, att, cluster_id, cluster_name); if ( rc < 0 ) { - failure_response(INTERNAL, allocate_error(error_str), att); + failure_response(INTERNAL, att); return; } @@ -199,14 +193,13 @@ void RequestManagerAllocate::request_execute(xmlrpc_c::paramList const& params, if ( cluster == 0 ) { - failure_response( - NO_EXISTS, - get_error(object_name(PoolObjectSQL::CLUSTER), cluster_id), - att); + att.resp_obj = PoolObjectSQL::CLUSTER; + att.resp_id = cluster_id; + failure_response(NO_EXISTS, att); return; } - rc = add_to_cluster(cluster, id, ds_type, error_str); + rc = add_to_cluster(cluster, id, ds_type, att.resp_msg); if ( rc < 0 ) { @@ -223,7 +216,7 @@ void RequestManagerAllocate::request_execute(xmlrpc_c::paramList const& params, obj->unlock(); } - failure_response(INTERNAL, allocate_error(error_str), att); + failure_response(INTERNAL, att); return; } @@ -242,7 +235,6 @@ int VirtualMachineAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { bool on_hold = false; @@ -258,7 +250,7 @@ int VirtualMachineAllocate::pool_allocate( Template tmpl_back(*tmpl); int rc = vmpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, - ttmpl, &id, error_str, on_hold); + ttmpl, &id, att.resp_msg, on_hold); if ( rc < 0 ) { @@ -276,7 +268,6 @@ int VirtualNetworkAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att, int cluster_id, const string& cluster_name) @@ -285,7 +276,7 @@ int VirtualNetworkAllocate::pool_allocate( VirtualNetworkTemplate * vtmpl=static_cast(tmpl); return vpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask,-1, - vtmpl, &id, cluster_id, cluster_name, error_str); + vtmpl, &id, cluster_id, cluster_name, att.resp_msg); } /* -------------------------------------------------------------------------- */ @@ -294,11 +285,11 @@ int VirtualNetworkAllocate::pool_allocate( void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, RequestAttributes& att) { - string error_str; string size_str; long long size_mb; istringstream iss; + ostringstream oss; string ds_name; string ds_data; @@ -320,26 +311,36 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, ImagePool * ipool = static_cast(pool); ImageManager * imagem = nd.get_imagem(); + MarketPlacePool * marketpool = nd.get_marketpool(); + MarketPlaceAppPool * apppool = nd.get_apppool(); + ImageTemplate * tmpl; Template img_usage; Datastore * ds; Image::DiskType ds_disk_type; + MarketPlaceApp * app; + MarketPlace * market; + int app_id; + int market_id; + long long avail; bool ds_check; bool persistent_attr; + string extra_data = ""; + // ------------------------- Parse image template -------------------------- tmpl = new ImageTemplate; - rc = tmpl->parse_str_or_xml(str_tmpl, error_str); + rc = tmpl->parse_str_or_xml(str_tmpl, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL, allocate_error(error_str), att); + failure_response(INTERNAL, att); delete tmpl; return; @@ -349,9 +350,9 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, if ((ds = dspool->get(ds_id,true)) == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::DATASTORE), ds_id), - att); + att.resp_id = ds_id; + att.resp_obj = PoolObjectSQL::DATASTORE; + failure_response(NO_EXISTS, att); delete tmpl; return; @@ -361,15 +362,12 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, if ( ds_type == Datastore::SYSTEM_DS ) { - ostringstream oss; - ds->unlock(); - oss << "New images cannot be allocated in a system datastore."; - failure_response(INTERNAL, allocate_error(oss.str()), att); + att.resp_msg = "New images cannot be allocated in a system datastore."; + failure_response(ALLOCATE, att); delete tmpl; - return; } @@ -386,32 +384,76 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, // --------------- Get the SIZE for the Image, (DS driver) ----------------- - rc = imagem->stat_image(tmpl, ds_data, size_str); - - if ( rc == -1 ) + if ( tmpl->get("FROM_APP", app_id ) ) { - failure_response(INTERNAL, - request_error("Cannot determine Image SIZE", size_str), - att); - delete tmpl; - return; + // This image comes from a MarketPlaceApp. Get the Market info and + // the size. + app = apppool->get(app_id, true); + + if ( app == 0 ) + { + att.resp_msg = "Cannot determine image SIZE."; + failure_response(INTERNAL, att); + + delete tmpl; + return; + } + + app->to_template(tmpl); + + size_mb = app->get_size(); + market_id = app->get_market_id(); + + app->unlock(); + + market = marketpool->get(market_id, true); + + if ( market == 0 ) + { + att.resp_msg = "Could not get the appliance's market."; + failure_response(INTERNAL, att); + + delete tmpl; + return; + } + + market->to_xml(extra_data); + + market->unlock(); + + oss << size_mb; + size_str = oss.str(); } - - iss.str(size_str); - iss >> size_mb; - - if ( iss.fail() ) + else { - failure_response(INTERNAL, - request_error("Cannot parse SIZE", size_str), - att); - delete tmpl; - return; + rc = imagem->stat_image(tmpl, ds_data, size_str); + + if ( rc == -1 ) + { + att.resp_msg = "Cannot parse image SIZE: " + size_str; + failure_response(INTERNAL, att); + + delete tmpl; + return; + } + + iss.str(size_str); + iss >> size_mb; + + if ( iss.fail() ) + { + att.resp_msg = "Cannot parse image SIZE: " + size_str; + failure_response(INTERNAL, att); + + delete tmpl; + return; + } } if (ds_check && (size_mb > avail)) { - failure_response(ACTION, "Not enough space in datastore", att); + att.resp_msg = "Not enough space in datastore"; + failure_response(ACTION, att); delete tmpl; return; @@ -437,13 +479,8 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, { if (tmpl->check(aname)) { - ostringstream oss; - - oss << "Template includes a restricted attribute " << aname; - - failure_response(AUTHORIZATION, - authorization_error(oss.str(), att), - att); + att.resp_msg = "Template includes a restricted attribute "+aname; + failure_response(AUTHORIZATION, att); delete tmpl; return; @@ -459,9 +496,8 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); delete tmpl; return; @@ -482,10 +518,8 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, 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); + att.resp_msg = "This Datastore only accepts persistent images."; + failure_response(ALLOCATE, att); delete tmpl; return; @@ -504,14 +538,15 @@ void ImageAllocate::request_execute(xmlrpc_c::paramList const& params, ds_disk_type, ds_data, ds_type, + extra_data, -1, &id, - error_str); + att.resp_msg); if ( rc < 0 ) { quota_rollback(&img_usage, Quotas::DATASTORE, att); - failure_response(INTERNAL, allocate_error(error_str), att); + failure_response(ALLOCATE, att); return; } @@ -536,7 +571,6 @@ int TemplateAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { VMTemplatePool * tpool = static_cast(pool); @@ -544,7 +578,7 @@ int TemplateAllocate::pool_allocate( VirtualMachineTemplate * ttmpl=static_cast(tmpl); return tpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, - ttmpl, &id, error_str); + ttmpl, &id, att.resp_msg); } /* -------------------------------------------------------------------------- */ @@ -569,14 +603,9 @@ bool TemplateAllocate::allocate_authorization( // ------------ Check template for restricted attributes ------------------- if (ttmpl->check(aname)) { - ostringstream oss; - - oss << "VM Template includes a restricted attribute " << aname; - - failure_response(AUTHORIZATION, - authorization_error(oss.str(), att), - att); + att.resp_msg = "VM Template includes a restricted attribute " + aname; + failure_response(AUTHORIZATION, att); return false; } @@ -590,7 +619,6 @@ int HostAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att, int cluster_id, const string& cluster_name) @@ -603,8 +631,7 @@ int HostAllocate::pool_allocate( HostPool * hpool = static_cast(pool); return hpool->allocate(&id, host, im_mad, vmm_mad, vnm_mad, - cluster_id, cluster_name, error_str); - + cluster_id, cluster_name, att.resp_msg); } /* -------------------------------------------------------------------------- */ @@ -614,7 +641,6 @@ int UserAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { string uname = xmlrpc_c::value_string(paramList.getString(1)); @@ -637,7 +663,7 @@ int UserAllocate::pool_allocate( driver = UserPool::CORE_AUTH; } - return upool->allocate(&id,ugid,uname,ugname,passwd,driver,true,error_str); + return upool->allocate(&id,ugid,uname,ugname,passwd,driver,true,att.resp_msg); } /* -------------------------------------------------------------------------- */ @@ -647,7 +673,6 @@ int GroupAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { int rc; @@ -656,7 +681,7 @@ int GroupAllocate::pool_allocate( GroupPool * gpool = static_cast(pool); - rc = gpool->allocate(gname, &id, error_str); + rc = gpool->allocate(gname, &id, att.resp_msg); if (rc == -1) { @@ -667,7 +692,7 @@ int GroupAllocate::pool_allocate( if (vdc != 0) { - rc = vdc->add_group(id, error_str); + rc = vdc->add_group(id, att.resp_msg); vdcpool->update(vdc); @@ -684,7 +709,6 @@ int DatastoreAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att, int cluster_id, const string& cluster_name) @@ -693,7 +717,7 @@ int DatastoreAllocate::pool_allocate( DatastoreTemplate * ds_tmpl = static_cast(tmpl); return dspool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, - ds_tmpl, &id, cluster_id, cluster_name, error_str); + ds_tmpl, &id, cluster_id, cluster_name, att.resp_msg); } /* -------------------------------------------------------------------------- */ @@ -703,14 +727,13 @@ int ClusterAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { string name = xmlrpc_c::value_string(paramList.getString(1)); ClusterPool * clpool = static_cast(pool); - return clpool->allocate(name, &id, error_str); + return clpool->allocate(name, &id, att.resp_msg); } /* -------------------------------------------------------------------------- */ @@ -720,7 +743,6 @@ int DocumentAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { int type = xmlrpc_c::value_int(paramList.getInt(2)); @@ -728,7 +750,7 @@ int DocumentAllocate::pool_allocate( DocumentPool * docpool = static_cast(pool); return docpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, - type, tmpl, &id, error_str); + type, tmpl, &id, att.resp_msg); } /* -------------------------------------------------------------------------- */ @@ -739,9 +761,8 @@ void ZoneAllocate::request_execute(xmlrpc_c::paramList const& params, { if(!Nebula::instance().is_federation_master()) { - failure_response(INTERNAL, allocate_error( - "New Zones can only be created if OpenNebula " - "is configured as a Federation Master."), att); + att.resp_msg = "New zones can only be created at federation master"; + failure_response(ALLOCATE, att); return; } @@ -755,14 +776,13 @@ int ZoneAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { string name = xmlrpc_c::value_string(paramList.getString(1)); ZonePool * zonepool = static_cast(pool); - return zonepool->allocate(tmpl, &id, error_str); + return zonepool->allocate(tmpl, &id, att.resp_msg); } /* -------------------------------------------------------------------------- */ @@ -772,13 +792,12 @@ int SecurityGroupAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { SecurityGroupPool * sgpool = static_cast(pool); return sgpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, - tmpl, &id, error_str); + tmpl, &id, att.resp_msg); } /* -------------------------------------------------------------------------- */ @@ -788,12 +807,141 @@ int VdcAllocate::pool_allocate( xmlrpc_c::paramList const& paramList, Template * tmpl, int& id, - string& error_str, RequestAttributes& att) { string name = xmlrpc_c::value_string(paramList.getString(1)); VdcPool * vdcpool = static_cast(pool); - return vdcpool->allocate(tmpl, &id, error_str); + return vdcpool->allocate(tmpl, &id, att.resp_msg); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int VirtualRouterAllocate::pool_allocate( + xmlrpc_c::paramList const& paramList, + Template * tmpl, + int& id, + RequestAttributes& att) +{ + VirtualRouterPool * vrpool = static_cast(pool); + + return vrpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, + tmpl, &id, att.resp_msg); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +bool VirtualRouterAllocate::allocate_authorization( + Template * tmpl, + RequestAttributes& att, + PoolObjectAuth * cluster_perms) +{ + if ( att.uid == 0 ) + { + return true; + } + + AuthRequest ar(att.uid, att.group_ids); + string tmpl_str; + + // ------------------ Authorize create operation ------------------------ + + ar.add_create_auth(att.uid, att.gid, auth_object, tmpl->to_xml(tmpl_str)); + + VirtualRouter::set_auth_request(att.uid, ar, tmpl); + + if (UserPool::authorize(ar) == -1) + { + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); + + return false; + } + + // -------------------------- Check Quotas ---------------------------- + + if (quota_authorization(tmpl, Quotas::VIRTUALROUTER, att, att.resp_msg) == false) + { + return AUTHORIZATION; + } + + return true; +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlaceAllocate::pool_allocate( + xmlrpc_c::paramList const& paramList, + Template * tmpl, + int& id, + RequestAttributes& att) +{ + MarketPlacePool * mppool = static_cast(pool); + MarketPlaceTemplate * ttmpl = static_cast(tmpl); + + return mppool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, + ttmpl, &id, att.resp_msg); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +int MarketPlaceAppAllocate::pool_allocate( + xmlrpc_c::paramList const& paramList, + Template * tmpl, + int& id, + RequestAttributes& att) +{ + MarketPlaceAppPool * appool = static_cast(pool); + MarketPlaceAppTemplate * ttmpl = static_cast(tmpl); + + int mp_id = xmlrpc_c::value_int(paramList.getInt(2)); + + MarketPlace * mp = mppool->get(mp_id, true); + + if ( mp == 0 ) + { + att.resp_msg = "Cannot find associated MARKETPLACE"; + return -1; + } + + std::string mp_name = mp->get_name(); + std::string mp_data; + + if ( !mp->is_action_supported(MarketPlaceApp::CREATE) ) + { + att.resp_msg = "Create disabled for market: " + mp_name; + mp->unlock(); + + return -1; + } + + mp->to_xml(mp_data); + + mp->unlock(); + + int rc = appool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, + ttmpl, mp_id, mp_name, mp_data, &id, att.resp_msg); + + if (rc < 0) + { + return rc; + } + + mp = mppool->get(mp_id, true); + + if ( mp != 0 ) // TODO: error otherwise or leave app in ERROR? + { + mp->add_marketapp(id); + + mppool->update(mp); + + mp->unlock(); + } + + return rc; } diff --git a/src/rm/RequestManagerChmod.cc b/src/rm/RequestManagerChmod.cc index 64bd352a87..09ac4b06bf 100644 --- a/src/rm/RequestManagerChmod.cc +++ b/src/rm/RequestManagerChmod.cc @@ -40,7 +40,6 @@ void RequestManagerChmod::request_execute(xmlrpc_c::paramList const& paramList, int other_a = xmlrpc_c::value_int(paramList.getInt(10)); PoolObjectSQL * object; - string error_str; if ( att.uid != 0 && att.gid != 0) { @@ -51,9 +50,8 @@ void RequestManagerChmod::request_execute(xmlrpc_c::paramList const& paramList, if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return; } @@ -100,10 +98,8 @@ void RequestManagerChmod::request_execute(xmlrpc_c::paramList const& paramList, if ( !enable_other ) { - failure_response(AUTHORIZATION, - "Management of 'other' permissions is disabled in oned.conf", - att); - + att.resp_msg = "'other' permissions is disabled in oned.conf"; + failure_response(AUTHORIZATION, att); return; } } @@ -114,9 +110,8 @@ void RequestManagerChmod::request_execute(xmlrpc_c::paramList const& paramList, if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return; } @@ -128,20 +123,17 @@ void RequestManagerChmod::request_execute(xmlrpc_c::paramList const& paramList, if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return; } int rc = object->set_permissions(owner_u, owner_m, owner_a, group_u, - group_m, group_a, other_u, other_m, other_a, error_str); + group_m, group_a, other_u, other_m, other_a, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL, - request_error("Error updating permissions",error_str), - att); + failure_response(INTERNAL, att); object->unlock(); return; diff --git a/src/rm/RequestManagerChown.cc b/src/rm/RequestManagerChown.cc index f6d9957e08..59050d5152 100644 --- a/src/rm/RequestManagerChown.cc +++ b/src/rm/RequestManagerChown.cc @@ -37,15 +37,12 @@ PoolObjectSQL * RequestManagerChown::get_and_quota( PoolObjectSQL * object; Quotas::QuotaType qtype; - string error_str; - object = pool->get(oid,true); if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object), oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return 0; } @@ -70,7 +67,6 @@ PoolObjectSQL * RequestManagerChown::get_and_quota( unsigned int total = vn->get_size(); ostringstream oss; - string tmp_error; int parent = vn->get_parent(); @@ -86,7 +82,7 @@ PoolObjectSQL * RequestManagerChown::get_and_quota( oss << " NIC = [ NETWORK_ID = " << parent << " ]" << endl; } - tmpl->parse_str_or_xml(oss.str(), error_str); + tmpl->parse_str_or_xml(oss.str(), att.resp_msg); qtype = Quotas::NETWORK; } @@ -120,11 +116,9 @@ PoolObjectSQL * RequestManagerChown::get_and_quota( RequestAttributes att_new(new_uid, new_gid, att); RequestAttributes att_old(old_uid, old_gid, att); - if ( quota_authorization(tmpl, qtype, att_new, error_str) == false ) + if ( quota_authorization(tmpl, qtype, att_new, att.resp_msg) == false ) { - failure_response(AUTHORIZATION, - request_error(error_str, ""), - att); + failure_response(AUTHORIZATION, att); delete tmpl; return 0; @@ -138,11 +132,10 @@ PoolObjectSQL * RequestManagerChown::get_and_quota( { quota_rollback(tmpl, qtype, att_new); - quota_authorization(tmpl, qtype, att_old, error_str); + quota_authorization(tmpl, qtype, att_old, att.resp_msg); - failure_response(NO_EXISTS, - get_error(object_name(auth_object), oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); } delete tmpl; @@ -164,10 +157,8 @@ int RequestManagerChown::check_name_unique(int oid, int noid, RequestAttributes& if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object), oid), - att); - + att.resp_id = oid; + failure_response(NO_EXISTS, att); return -1; } @@ -182,12 +173,12 @@ int RequestManagerChown::check_name_unique(int oid, int noid, RequestAttributes& obj_oid = object->get_oid(); object->unlock(); - oss << PoolObjectSQL::type_to_str(PoolObjectSQL::USER) - << " [" << noid << "] already owns " - << PoolObjectSQL::type_to_str(auth_object) << " [" - << obj_oid << "] with NAME " << name; + oss << object_name(PoolObjectSQL::USER) << " ["<get(source_id, true); if ( source_obj == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object), source_id), - att); - + att.resp_id = source_id; + failure_response(NO_EXISTS, att); return; } @@ -71,20 +67,19 @@ void RequestManagerClone::request_execute( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); delete tmpl; return; } } - rc = pool_allocate(source_id, tmpl, new_id, error_str, att); + rc = pool_allocate(source_id, tmpl, new_id, att); if ( rc < 0 ) { - failure_response(INTERNAL, allocate_error(error_str), att); + failure_response(ALLOCATE, att); return; } diff --git a/src/rm/RequestManagerCluster.cc b/src/rm/RequestManagerCluster.cc index f3840d6cef..48a460b25a 100644 --- a/src/rm/RequestManagerCluster.cc +++ b/src/rm/RequestManagerCluster.cc @@ -38,7 +38,6 @@ void RequestManagerCluster::add_generic( Clusterable * cluster_obj = 0; PoolObjectSQL * object = 0; - PoolObjectAuth c_perms; PoolObjectAuth obj_perms; @@ -82,9 +81,8 @@ void RequestManagerCluster::add_generic( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return; } @@ -95,10 +93,9 @@ void RequestManagerCluster::add_generic( if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(type), object_id), - att); - + att.resp_obj = type; + att.resp_id = object_id; + failure_response(NO_EXISTS, att); return; } @@ -127,9 +124,9 @@ void RequestManagerCluster::add_generic( if ( cluster == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::CLUSTER),cluster_id), - att); + att.resp_obj = PoolObjectSQL::CLUSTER; + att.resp_id = cluster_id; + failure_response(NO_EXISTS, att); // Rollback get(object_id, true, &object, &cluster_obj); @@ -146,13 +143,11 @@ void RequestManagerCluster::add_generic( return; } - if ( add_object(cluster, object_id, ds_type, err_msg) < 0 ) + if ( add_object(cluster, object_id, ds_type, att.resp_msg) < 0 ) { cluster->unlock(); - failure_response(INTERNAL, - request_error("Cannot add object to cluster", err_msg), - att); + failure_response(INTERNAL, att); // Rollback get(object_id, true, &object, &cluster_obj); @@ -189,14 +184,11 @@ void RequestManagerCluster::add_generic( return; } - if ( del_object(cluster, object_id, err_msg) < 0 ) + if ( del_object(cluster, object_id, att.resp_msg) < 0 ) { cluster->unlock(); - failure_response(INTERNAL, - request_error("Cannot remove object from cluster", err_msg), - att); - + failure_response(INTERNAL, att); return; } diff --git a/src/rm/RequestManagerDatastore.cc b/src/rm/RequestManagerDatastore.cc index e174d06880..5882a69f31 100644 --- a/src/rm/RequestManagerDatastore.cc +++ b/src/rm/RequestManagerDatastore.cc @@ -29,7 +29,6 @@ void DatastoreEnable::request_execute(xmlrpc_c::paramList const& paramList, int rc; Datastore * ds; - string err_msg; if ( basic_authorization(id, att) == false ) { @@ -40,18 +39,16 @@ void DatastoreEnable::request_execute(xmlrpc_c::paramList const& paramList, if ( ds == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),id), - att); - + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } - rc = ds->enable(enable_flag, err_msg); + rc = ds->enable(enable_flag, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL,request_error(err_msg,""), att); + failure_response(INTERNAL, att); ds->unlock(); return; diff --git a/src/rm/RequestManagerDelete.cc b/src/rm/RequestManagerDelete.cc index e8dcec6223..a79f6e7f92 100644 --- a/src/rm/RequestManagerDelete.cc +++ b/src/rm/RequestManagerDelete.cc @@ -37,9 +37,8 @@ bool RequestManagerDelete::delete_authorization( if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return false; } @@ -53,9 +52,8 @@ bool RequestManagerDelete::delete_authorization( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return false; } @@ -82,8 +80,8 @@ void RequestManagerDelete::request_execute(xmlrpc_c::paramList const& paramList, if ( object == 0 ) { - failure_response(NO_EXISTS, get_error(object_name(auth_object), oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return; } @@ -91,9 +89,8 @@ void RequestManagerDelete::request_execute(xmlrpc_c::paramList const& paramList, if ( rc != 0 ) { - failure_response(ACTION, - request_error("Cannot delete "+object_name(auth_object),error_msg), - att); + att.resp_msg = "Cannot delete " + object_name(auth_object) + ". " + error_msg; + failure_response(ACTION, att); return; } @@ -363,3 +360,49 @@ int SecurityGroupDelete::drop(int oid, PoolObjectSQL * object, string& error_msg return RequestManagerDelete::drop(oid, object, error_msg); } + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +int MarketPlaceAppDelete::drop(int oid, PoolObjectSQL * object, string& emsg) +{ + Nebula& nd = Nebula::instance(); + + MarketPlaceManager * marketm = nd.get_marketm(); + MarketPlacePool * marketpool = nd.get_marketpool(); + + MarketPlaceApp * app = static_cast(object); + + int mp_id = app->get_market_id(); + + app->unlock(); + + MarketPlace * mp = marketpool->get(mp_id, true); + + if ( mp == 0 ) + { + emsg = "Cannot find associated MARKETPLACE"; + return -1; + } + + std::string mp_name = mp->get_name(); + std::string mp_data; + + if ( !mp->is_action_supported(MarketPlaceApp::DELETE) ) + { + emsg = "Delete disabled for market: " + mp_name; + mp->unlock(); + + return -1; + } + + mp->to_xml(mp_data); + + mp->unlock(); + + return marketm->delete_app(oid, mp_data, emsg); +} + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + diff --git a/src/rm/RequestManagerGroup.cc b/src/rm/RequestManagerGroup.cc index dceedeb935..eca3a0a216 100644 --- a/src/rm/RequestManagerGroup.cc +++ b/src/rm/RequestManagerGroup.cc @@ -26,16 +26,14 @@ void GroupSetQuota:: string quota_str = xmlrpc_c::value_string(paramList.getString(2)); Group * group; - string error_str; Template quota_tmpl; int rc; if ( id == GroupPool::ONEADMIN_ID ) { - failure_response(ACTION, - request_error("Cannot set quotas for oneadmin group",""), - att); + att.resp_msg = "Cannot set quotas for oneadmin group"; + failure_response(ACTION, att); return; } @@ -44,11 +42,11 @@ void GroupSetQuota:: return; } - rc = quota_tmpl.parse_str_or_xml(quota_str, error_str); + rc = quota_tmpl.parse_str_or_xml(quota_str, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, request_error(error_str,""), att); + failure_response(ACTION, att); return; } @@ -56,14 +54,12 @@ void GroupSetQuota:: if ( group == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),id), - att); - + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } - group->quota.set("a_tmpl, error_str); + group->quota.set("a_tmpl, att.resp_msg); static_cast(pool)->update_quotas(group); @@ -71,7 +67,7 @@ void GroupSetQuota:: if ( rc != 0 ) { - failure_response(ACTION, request_error(error_str,""), att); + failure_response(ACTION, att); } else { @@ -117,9 +113,9 @@ void GroupEditAdmin::request_execute( if ( rc == -1 ) { - failure_response(NO_EXISTS, get_error(object_name(PoolObjectSQL::USER), - user_id), att); - + att.resp_obj = PoolObjectSQL::USER; + att.resp_id = user_id; + failure_response(NO_EXISTS, att); return; } @@ -133,9 +129,8 @@ void GroupEditAdmin::request_execute( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return; } @@ -145,14 +140,12 @@ void GroupEditAdmin::request_execute( if ( group == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),group_id), - att); - + att.resp_id = group_id; + failure_response(NO_EXISTS, att); return; } - rc = edit_admin(group, user_id, error_str); + rc = edit_admin(group, user_id, att.resp_msg); if (rc == 0) { @@ -163,9 +156,8 @@ void GroupEditAdmin::request_execute( if (rc != 0) { - failure_response(INTERNAL, - request_error("Cannot edit group", error_str), - att); + att.resp_msg = "Cannot edit group. " + att.resp_msg; + failure_response(INTERNAL, att); return; } diff --git a/src/rm/RequestManagerHost.cc b/src/rm/RequestManagerHost.cc index 9c1b96b99c..c8267a745b 100644 --- a/src/rm/RequestManagerHost.cc +++ b/src/rm/RequestManagerHost.cc @@ -30,8 +30,6 @@ void HostEnable::request_execute(xmlrpc_c::paramList const& paramList, HostPool * hpool = static_cast(pool); - string error_str; - if ( basic_authorization(id, att) == false ) { return; @@ -41,9 +39,8 @@ void HostEnable::request_execute(xmlrpc_c::paramList const& paramList, if ( host == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),id), - att); + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } @@ -85,7 +82,8 @@ void HostMonitoring::request_execute( if ( rc != 0 ) { - failure_response(INTERNAL,request_error("Internal Error",""), att); + att.resp_msg = "Internal error"; + failure_response(INTERNAL, att); return; } diff --git a/src/rm/RequestManagerImage.cc b/src/rm/RequestManagerImage.cc index 8e2decd8f6..e849e312ae 100644 --- a/src/rm/RequestManagerImage.cc +++ b/src/rm/RequestManagerImage.cc @@ -28,8 +28,6 @@ void ImageEnable::request_execute(xmlrpc_c::paramList const& paramList, bool enable_flag = xmlrpc_c::value_boolean(paramList.getBoolean(2)); int rc; - string err_msg; - Nebula& nd = Nebula::instance(); ImageManager * imagem = nd.get_imagem(); @@ -38,20 +36,20 @@ void ImageEnable::request_execute(xmlrpc_c::paramList const& paramList, return; } - rc = imagem->enable_image(id,enable_flag, err_msg); + rc = imagem->enable_image(id,enable_flag, att.resp_msg); if( rc < 0 ) { if (enable_flag == true) { - err_msg = "Could not enable image: " + err_msg; + att.resp_msg = "Could not enable image: " + att.resp_msg; } else { - err_msg = "Could not disable image: " + err_msg; + att.resp_msg = "Could not disable image: " + att.resp_msg; } - failure_response(INTERNAL, request_error(err_msg,""), att); + failure_response(INTERNAL, att); return; } @@ -76,7 +74,6 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList, Datastore * ds; Image * image; - std::string err_msg; if ( basic_authorization(id, att) == false ) { @@ -87,9 +84,8 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList, if ( image == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),id), - att); + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } @@ -102,9 +98,8 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList, if ( ds == 0 ) { - failure_response(INTERNAL, - request_error("Datastore no longer exists.", - ""), att); + att.resp_msg = "Datastore no longer exists."; + failure_response(INTERNAL, att); return; } @@ -117,9 +112,8 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList, if ( image == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),id), - att); + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } @@ -134,9 +128,8 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList, case Image::KERNEL: case Image::RAMDISK: case Image::CONTEXT: - failure_response(ACTION, - request_error("KERNEL, RAMDISK and CONTEXT files must be " - "non-persistent",""), att); + att.resp_msg = "KERNEL, RAMDISK and CONTEXT must be non-persistent"; + failure_response(ACTION, att); image->unlock(); return; } @@ -144,28 +137,27 @@ void ImagePersistent::request_execute(xmlrpc_c::paramList const& paramList, /* 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); + att.resp_msg = "This Datastore only accepts persistent images."; + failure_response(INTERNAL, att); image->unlock(); return; } - rc = image->persistent(persistent_flag, err_msg); + rc = image->persistent(persistent_flag, att.resp_msg); if ( rc != 0 ) { if (persistent_flag == true) { - err_msg = "Could not make image persistent: " + err_msg; + att.resp_msg = "Could not make image persistent: " + att.resp_msg; } else { - err_msg = "Could not make image non-persistent: " + err_msg; + att.resp_msg = "Could not make image non-persistent: " + att.resp_msg; } - failure_response(INTERNAL,request_error(err_msg,""), att); + failure_response(INTERNAL, att); image->unlock(); return; @@ -191,7 +183,6 @@ void ImageChangeType::request_execute(xmlrpc_c::paramList const& paramList, Image::ImageType itype; Image * image; - string err_msg; if ( basic_authorization(id, att) == false ) { @@ -202,10 +193,8 @@ void ImageChangeType::request_execute(xmlrpc_c::paramList const& paramList, if ( image == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),id), - att); - + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } @@ -216,14 +205,12 @@ void ImageChangeType::request_execute(xmlrpc_c::paramList const& paramList, case Image::OS: case Image::DATABLOCK: case Image::CDROM: - if ((itype != Image::OS) && - (itype != Image::DATABLOCK)&& - (itype != Image::CDROM) ) + if ((itype != Image::OS) && (itype != Image::DATABLOCK)&& + (itype != Image::CDROM)) { - failure_response(ACTION, - request_error("Cannot change image type to an incompatible" - " type for the current datastore.",""), - att); + att.resp_msg = "Cannot change image type to an incompatible type" + " for the current datastore."; + failure_response(ACTION, att); image->unlock(); return; @@ -237,10 +224,9 @@ void ImageChangeType::request_execute(xmlrpc_c::paramList const& paramList, (itype != Image::RAMDISK)&& (itype != Image::CONTEXT) ) { - failure_response(ACTION, - request_error("Cannot change image type to an incompatible" - " type for the current datastore.",""), - att); + att.resp_msg = "Cannot change image type to an incompatible type" + " for the current datastore."; + failure_response(ACTION, att); image->unlock(); return; @@ -248,11 +234,11 @@ void ImageChangeType::request_execute(xmlrpc_c::paramList const& paramList, break; } - rc = image->set_type(type, err_msg); + rc = image->set_type(type, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL,request_error(err_msg,""), att); + failure_response(INTERNAL, att); image->unlock(); return; @@ -277,7 +263,7 @@ void ImageClone::request_execute( long long avail, size; int rc, new_id, ds_id_orig, ds_id = -1; - string error_str, ds_name, ds_data, ds_mad; + string ds_name, ds_data, ds_mad; bool ds_check; Image::DiskType disk_type; @@ -304,10 +290,8 @@ void ImageClone::request_execute( if ( img == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object), clone_id), - att); - + att.resp_id = clone_id; + failure_response(NO_EXISTS, att); return; } @@ -321,9 +305,8 @@ void ImageClone::request_execute( case Image::KERNEL: case Image::RAMDISK: case Image::CONTEXT: - failure_response(ACTION, - allocate_error("KERNEL, RAMDISK and CONTEXT files cannot be " - "cloned."), att); + att.resp_msg = "KERNEL, RAMDISK and CONTEXT cannot be cloned."; + failure_response(ACTION, att); img->unlock(); return; } @@ -332,8 +315,8 @@ void ImageClone::request_execute( if (snaps.size () > 0) { - failure_response(ACTION, - request_error("Cannot clone images with snapshots",""), att); + att.resp_msg = "Cannot clone images with snapshots"; + failure_response(ACTION, att); img->unlock(); return; } @@ -359,9 +342,9 @@ void ImageClone::request_execute( if ( ds == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::DATASTORE), ds_id), - att); + att.resp_obj = PoolObjectSQL::DATASTORE; + att.resp_id = ds_id; + failure_response(NO_EXISTS, att); delete tmpl; return; @@ -369,8 +352,8 @@ void ImageClone::request_execute( if ( ds->get_type() != Datastore::IMAGE_DS ) { - failure_response(ACTION, - request_error("Clone only supported for IMAGE_DS Datastores",""),att); + att.resp_msg = "Clone only supported for IMAGE_DS Datastores"; + failure_response(ACTION, att); ds->unlock(); @@ -396,8 +379,9 @@ void ImageClone::request_execute( if (ds == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::DATASTORE),ds_id_orig),att); + att.resp_obj = PoolObjectSQL::DATASTORE; + att.resp_id = ds_id_orig; + failure_response(NO_EXISTS, att); delete tmpl; return; @@ -405,8 +389,8 @@ void ImageClone::request_execute( if (ds->get_type() != Datastore::IMAGE_DS) { - failure_response(ACTION, request_error( - "Clone only supported for IMAGE_DS Datastores",""), att); + att.resp_msg = "Clone only supported for IMAGE_DS Datastores"; + failure_response(ACTION, att); ds->unlock(); @@ -416,8 +400,8 @@ void ImageClone::request_execute( if (ds->get_ds_mad() != ds_mad) { - failure_response(ACTION, request_error( - "Clone only supported to same DS_MAD Datastores",""), att); + att.resp_msg = "Clone only supported to same DS_MAD Datastores"; + failure_response(ACTION, att); ds->unlock(); @@ -437,8 +421,8 @@ void ImageClone::request_execute( if (ds_check && (size > avail)) { - failure_response(ACTION, - request_error("Not enough space in datastore",""), att); + att.resp_msg = "Not enough space in datastore"; + failure_response(ACTION, att); delete tmpl; return; @@ -464,9 +448,8 @@ void ImageClone::request_execute( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); delete tmpl; return; @@ -492,14 +475,15 @@ void ImageClone::request_execute( disk_type, ds_data, Datastore::IMAGE_DS, + "", clone_id, &new_id, - error_str); + att.resp_msg); if ( rc < 0 ) { quota_rollback(&img_usage, Quotas::DATASTORE, att); - failure_response(INTERNAL, allocate_error(error_str), att); + failure_response(ALLOCATE, att); return; } @@ -534,12 +518,11 @@ void ImageSnapshotDelete::request_execute(xmlrpc_c::paramList const& paramList, return; } - string err_msg; - int rc = imagem->delete_snapshot(id, snap_id, err_msg); + int rc = imagem->delete_snapshot(id, snap_id, att.resp_msg); if ( rc < 0 ) { - failure_response(ACTION, request_error(err_msg, ""), att); + failure_response(ACTION, att); return; } @@ -563,12 +546,11 @@ void ImageSnapshotRevert::request_execute(xmlrpc_c::paramList const& paramList, return; } - string err_msg; - int rc = imagem->revert_snapshot(id, snap_id, err_msg); + int rc = imagem->revert_snapshot(id, snap_id, att.resp_msg); if ( rc < 0 ) { - failure_response(ACTION, request_error(err_msg, ""), att); + failure_response(ACTION, att); return; } @@ -592,12 +574,11 @@ void ImageSnapshotFlatten::request_execute(xmlrpc_c::paramList const& paramList, return; } - string err_msg; - int rc = imagem->flatten_snapshot(id, snap_id, err_msg); + int rc = imagem->flatten_snapshot(id, snap_id, att.resp_msg); if ( rc < 0 ) { - failure_response(ACTION, request_error(err_msg, ""), att); + failure_response(ACTION, att); return; } diff --git a/src/rm/RequestManagerInfo.cc b/src/rm/RequestManagerInfo.cc index 063a4b4ca6..302a1f27b1 100644 --- a/src/rm/RequestManagerInfo.cc +++ b/src/rm/RequestManagerInfo.cc @@ -50,9 +50,8 @@ void RequestManagerInfo::request_execute(xmlrpc_c::paramList const& paramList, if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return; } @@ -90,10 +89,8 @@ void TemplateInfo::request_execute(xmlrpc_c::paramList const& paramList, if ( vm_tmpl == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); - + att.resp_id = oid; + failure_response(NO_EXISTS, att); return; } @@ -119,9 +116,8 @@ void TemplateInfo::request_execute(xmlrpc_c::paramList const& paramList, { if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); delete extended_tmpl; return; @@ -132,9 +128,8 @@ void TemplateInfo::request_execute(xmlrpc_c::paramList const& paramList, if ( vm_tmpl == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); delete extended_tmpl; return; @@ -166,12 +161,15 @@ void VirtualNetworkInfo::to_xml(RequestAttributes& att, PoolObjectSQL * object, { vector vms; vector vnets; + vector vrs; string where_vnets; string where_vms; + string where_vrs; bool all_reservations; bool all_vms; + bool all_vrs; PoolObjectAuth perms; @@ -185,6 +183,7 @@ void VirtualNetworkInfo::to_xml(RequestAttributes& att, PoolObjectSQL * object, { all_reservations = true; all_vms = true; + all_vrs = true; } else { @@ -193,6 +192,9 @@ void VirtualNetworkInfo::to_xml(RequestAttributes& att, PoolObjectSQL * object, all_vms = RequestManagerPoolInfoFilter::use_filter(att, PoolObjectSQL::VM, false, false, false, "", where_vms); + + all_vrs = RequestManagerPoolInfoFilter::use_filter(att, + PoolObjectSQL::VROUTER, false, false, false, "", where_vrs); } if ( all_reservations == true ) @@ -213,5 +215,14 @@ void VirtualNetworkInfo::to_xml(RequestAttributes& att, PoolObjectSQL * object, Nebula::instance().get_vmpool()->search(vms, where_vms); } - static_cast(object)->to_xml_extended(str, vms, vnets); + if ( all_vrs == true ) + { + vrs.push_back(-1); + } + else + { + Nebula::instance().get_vrouterpool()->search(vrs, where_vrs); + } + + static_cast(object)->to_xml_extended(str, vms, vnets, vrs); }; diff --git a/src/rm/RequestManagerLock.cc b/src/rm/RequestManagerLock.cc index 7df80647b9..349f983e62 100644 --- a/src/rm/RequestManagerLock.cc +++ b/src/rm/RequestManagerLock.cc @@ -40,9 +40,8 @@ void RequestManagerLock::request_execute(xmlrpc_c::paramList const& paramList, if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return; } @@ -78,9 +77,8 @@ void RequestManagerUnlock::request_execute(xmlrpc_c::paramList const& paramList, if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return; } diff --git a/src/rm/RequestManagerMarketPlaceApp.cc b/src/rm/RequestManagerMarketPlaceApp.cc new file mode 100644 index 0000000000..7778860482 --- /dev/null +++ b/src/rm/RequestManagerMarketPlaceApp.cc @@ -0,0 +1,60 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 "RequestManagerMarketPlaceApp.h" + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +void MarketPlaceAppEnable::request_execute(xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + int id = xmlrpc_c::value_int(paramList.getInt(1)); + bool enable_flag = xmlrpc_c::value_boolean(paramList.getBoolean(2)); + int rc; + + MarketPlaceApp * app; + + if ( basic_authorization(id, att) == false ) + { + return; + } + + app = static_cast(pool->get(id, true)); + + if ( app == 0 ) + { + att.resp_id = id; + failure_response(NO_EXISTS, att); + return; + } + + rc = app->enable(enable_flag, att.resp_msg); + + if ( rc != 0 ) + { + failure_response(INTERNAL, att); + + app->unlock(); + return; + } + + pool->update(app); + + app->unlock(); + + success_response(id, att); +} diff --git a/src/rm/RequestManagerPoolInfoFilter.cc b/src/rm/RequestManagerPoolInfoFilter.cc index 37480d8307..6b2f6b8399 100644 --- a/src/rm/RequestManagerPoolInfoFilter.cc +++ b/src/rm/RequestManagerPoolInfoFilter.cc @@ -98,10 +98,8 @@ void VirtualMachinePoolInfo::request_execute( if (( state < VirtualMachinePoolInfo::ALL_VM ) || ( state > VirtualMachine::UNDEPLOYED )) { - failure_response(XML_RPC_API, - request_error("Incorrect filter_flag, state",""), - att); - + att.resp_msg = "Incorrect filter_flag, state"; + failure_response(XML_RPC_API, att); return; } @@ -139,9 +137,8 @@ void VirtualMachinePoolAccounting::request_execute( if ( filter_flag < MINE ) { - failure_response(XML_RPC_API, - request_error("Incorrect filter_flag",""), - att); + att.resp_msg = "Incorrect filter_flag"; + failure_response(XML_RPC_API, att); return; } @@ -153,7 +150,8 @@ void VirtualMachinePoolAccounting::request_execute( time_end); if ( rc != 0 ) { - failure_response(INTERNAL,request_error("Internal Error",""), att); + att.resp_msg = "Internal error"; + failure_response(INTERNAL, att); return; } @@ -181,9 +179,8 @@ void VirtualMachinePoolShowback::request_execute( if ( filter_flag < MINE ) { - failure_response(XML_RPC_API, - request_error("Incorrect filter_flag",""), - att); + att.resp_msg = "Incorrect filter_flag"; + failure_response(XML_RPC_API, att); return; } @@ -197,7 +194,8 @@ void VirtualMachinePoolShowback::request_execute( end_year); if ( rc != 0 ) { - failure_response(INTERNAL,request_error("Internal Error",""), att); + att.resp_msg = "Internal error"; + failure_response(INTERNAL, att); return; } @@ -221,9 +219,8 @@ void VirtualMachinePoolMonitoring::request_execute( if ( filter_flag < MINE ) { - failure_response(XML_RPC_API, - request_error("Incorrect filter_flag",""), - att); + att.resp_msg = "Incorrect filter_flag"; + failure_response(XML_RPC_API, att); return; } @@ -233,7 +230,8 @@ void VirtualMachinePoolMonitoring::request_execute( if ( rc != 0 ) { - failure_response(INTERNAL,request_error("Internal Error",""), att); + att.resp_msg = "Internal error"; + failure_response(INTERNAL, att); return; } @@ -269,7 +267,8 @@ void HostPoolMonitoring::request_execute( if ( rc != 0 ) { - failure_response(INTERNAL,request_error("Internal Error",""), att); + att.resp_msg = "Internal error"; + failure_response(INTERNAL, att); return; } @@ -440,9 +439,8 @@ void RequestManagerPoolInfoFilter::dump( if ( filter_flag < MINE ) { - failure_response(XML_RPC_API, - request_error("Incorrect filter_flag",""), - att); + att.resp_msg = "Incorrect filter_flag"; + failure_response(XML_RPC_API, att); return; } @@ -468,7 +466,8 @@ void RequestManagerPoolInfoFilter::dump( if ( rc != 0 ) { - failure_response(INTERNAL,request_error("Internal Error",""), att); + att.resp_msg = "Internal error"; + failure_response(INTERNAL, att); return; } @@ -489,9 +488,8 @@ void VirtualNetworkPoolInfo::request_execute( if ( filter_flag < MINE ) { - failure_response(XML_RPC_API, - request_error("Incorrect filter_flag",""), - att); + att.resp_msg = "Incorrect filter_flag"; + failure_response(XML_RPC_API, att); return; } @@ -533,7 +531,8 @@ void VirtualNetworkPoolInfo::request_execute( if ( rc != 0 ) { - failure_response(INTERNAL,request_error("Internal Error",""), att); + att.resp_msg = "Internal error"; + failure_response(INTERNAL, att); return; } @@ -551,3 +550,14 @@ void VdcPoolInfo::request_execute( { dump(att, ALL, -1, -1, "", ""); } + +/* ------------------------------------------------------------------------- */ +/* ------------------------------------------------------------------------- */ + +void MarketPlacePoolInfo::request_execute( + xmlrpc_c::paramList const& paramList, + RequestAttributes& att) +{ + dump(att, ALL, -1, -1, "", ""); +} + diff --git a/src/rm/RequestManagerProxy.cc b/src/rm/RequestManagerProxy.cc index bf8b4e5faf..dc71a91bed 100644 --- a/src/rm/RequestManagerProxy.cc +++ b/src/rm/RequestManagerProxy.cc @@ -61,7 +61,8 @@ void RequestManagerProxy::request_execute(xmlrpc_c::paramList const& _paramList, } catch(exception const& e) { - failure_response(INTERNAL, request_error("Could not connect to the federation master oned", ""), att); + att.resp_msg = "Could not connect to the federation master oned"; + failure_response(INTERNAL, att); } } diff --git a/src/rm/RequestManagerRename.cc b/src/rm/RequestManagerRename.cc index 27722a0ea2..e7edef60c7 100644 --- a/src/rm/RequestManagerRename.cc +++ b/src/rm/RequestManagerRename.cc @@ -31,15 +31,14 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, int rc; string old_name; - string error_str; PoolObjectAuth operms; PoolObjectSQL * object; if (test_and_set_rename(oid) == false) { - failure_response(INTERNAL, - request_error("Object is being renamed", ""), att); + att.resp_msg = "Object is being renamed"; + failure_response(INTERNAL, att); return; } @@ -70,9 +69,8 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); clear_rename(oid); return; } @@ -89,13 +87,13 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, object->unlock(); - oss << PoolObjectSQL::type_to_str(auth_object) - << " cannot be renamed to " << new_name - << " because it collides with " - << PoolObjectSQL::type_to_str(auth_object) << " " + oss << object_name(auth_object) << " cannot be renamed to " << new_name + << " because it collides with " << object_name(auth_object) << " " << id; - failure_response(ACTION, request_error(oss.str(), ""), att); + att.resp_msg = oss.str(); + + failure_response(ACTION, att); clear_rename(oid); return; @@ -107,19 +105,18 @@ void RequestManagerRename::request_execute(xmlrpc_c::paramList const& paramList, if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object), oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); clear_rename(oid); return; } - if ( object->set_name(new_name, error_str) != 0 ) + if ( object->set_name(new_name, att.resp_msg) != 0 ) { object->unlock(); - failure_response(ACTION, request_error(error_str, ""), att); + failure_response(ACTION, att); clear_rename(oid); return; @@ -302,3 +299,41 @@ void HostRename::batch_rename(int oid) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +void MarketPlaceRename::batch_rename(int oid) +{ + MarketPlace * market = static_cast(pool)->get(oid, true); + + if (market == 0) + { + return; + } + + const std::set & apps = market->get_marketapp_ids(); + + std::set::iterator it; + + std::string market_name = market->get_name(); + + market->unlock(); + + MarketPlaceApp * app; + MarketPlaceAppPool * apppool = Nebula::instance().get_apppool(); + + for (it = apps.begin(); it != apps.end(); it++) + { + app = apppool->get(*it, true); + + if (app != 0) + { + if (app->get_market_id() == oid) + { + app->set_market_name(market_name); + apppool->update(app); + } + + app->unlock(); + } + } +} + diff --git a/src/rm/RequestManagerSystem.cc b/src/rm/RequestManagerSystem.cc index 3e65eb9bed..d2c814a01e 100644 --- a/src/rm/RequestManagerSystem.cc +++ b/src/rm/RequestManagerSystem.cc @@ -43,9 +43,9 @@ void SystemConfig::request_execute(xmlrpc_c::paramList const& paramList, { if ( att.gid != GroupPool::ONEADMIN_ID ) { - failure_response(AUTHORIZATION, - "The oned configuration can only be retrieved by users in the oneadmin group", - att); + att.resp_msg = "The oned configuration can only be retrieved by users " + "in the oneadmin group"; + failure_response(AUTHORIZATION, att); return; } @@ -94,25 +94,25 @@ void QuotaUpdate::request_execute(xmlrpc_c::paramList const& paramList, if ( att.gid != GroupPool::ONEADMIN_ID ) { - failure_response(AUTHORIZATION, - "The default quotas can only be updated by users in the oneadmin group", - att); + att.resp_msg = "The default quotas can only be updated by users in the" + " oneadmin group"; + failure_response(AUTHORIZATION, att); return; } - rc = quota_tmpl.parse_str_or_xml(quota_str, error_str); + rc = quota_tmpl.parse_str_or_xml(quota_str, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, request_error(error_str,""), att); + failure_response(ACTION, att); return; } - rc = set_default_quota("a_tmpl, error_str); + rc = set_default_quota("a_tmpl, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, request_error(error_str,""), att); + failure_response(ACTION, att); return; } diff --git a/src/rm/RequestManagerUpdateTemplate.cc b/src/rm/RequestManagerUpdateTemplate.cc index 580f03ea90..08209e006a 100644 --- a/src/rm/RequestManagerUpdateTemplate.cc +++ b/src/rm/RequestManagerUpdateTemplate.cc @@ -64,7 +64,6 @@ void RequestManagerUpdateTemplate::request_execute( RequestAttributes& att) { int rc; - string error_str; int oid = xmlrpc_c::value_int(paramList.getInt(1)); string tmpl = xmlrpc_c::value_string(paramList.getString(2)); @@ -85,10 +84,8 @@ void RequestManagerUpdateTemplate::request_execute( if ( update_type < 0 || update_type > 1 ) { - failure_response(XML_RPC_API, - request_error("Wrong update type",error_str), - att); - + att.resp_msg = "Wrong update type"; + failure_response(XML_RPC_API, att); return; } @@ -97,27 +94,24 @@ void RequestManagerUpdateTemplate::request_execute( if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); - + att.resp_id = oid; + failure_response(NO_EXISTS, att); return; } if (update_type == 0) { - rc = replace_template(object, tmpl, att, error_str); + rc = replace_template(object, tmpl, att, att.resp_msg); } else //if (update_type == 1) { - rc = append_template(object, tmpl, att, error_str); + rc = append_template(object, tmpl, att, att.resp_msg); } if ( rc != 0 ) { - failure_response(INTERNAL, - request_error("Cannot update template",error_str), - att); + att.resp_msg = "Cannot update template. " + att.resp_msg; + failure_response(INTERNAL, att); object->unlock(); return; diff --git a/src/rm/RequestManagerUser.cc b/src/rm/RequestManagerUser.cc index 597dd6b0ad..9c8a17876e 100644 --- a/src/rm/RequestManagerUser.cc +++ b/src/rm/RequestManagerUser.cc @@ -35,16 +35,14 @@ void RequestManagerUser:: if ( user == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),id), - att); - + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } - if ( user_action(id,paramList,error_str) < 0 ) + if ( user_action(id, paramList, att.resp_msg) < 0 ) { - failure_response(ACTION, request_error(error_str,""), att); + failure_response(ACTION, att); return; } @@ -214,17 +212,15 @@ void UserEditGroup:: if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); - + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return; } } - if ( secondary_group_action(user_id, group_id, paramList, error_str) < 0 ) + if ( secondary_group_action(user_id, group_id, paramList, att.resp_msg) < 0 ) { - failure_response(ACTION, request_error(error_str,""), att); + failure_response(ACTION, att); return; } @@ -375,10 +371,7 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList, if ( user == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),-1), - att); - + failure_response(NO_EXISTS, att); return; } @@ -393,10 +386,8 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList, if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); - + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return; } } @@ -405,10 +396,7 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList, if ( user == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),-1), - att); - + failure_response(NO_EXISTS, att); return; } @@ -424,11 +412,10 @@ void UserLogin::request_execute(xmlrpc_c::paramList const& paramList, } else { - failure_response(XML_RPC_API, - request_error("Wrong valid period for token",""), att); + att.resp_msg = "Wrong valid period for token"; + failure_response(XML_RPC_API, att); user->unlock(); - return; } diff --git a/src/rm/RequestManagerVMTemplate.cc b/src/rm/RequestManagerVMTemplate.cc index 5df7b0c088..e2d16efcc2 100644 --- a/src/rm/RequestManagerVMTemplate.cc +++ b/src/rm/RequestManagerVMTemplate.cc @@ -29,8 +29,56 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList bool on_hold = false; //Optional XML-RPC argument string str_uattrs; //Optional XML-RPC argument - int rc; - int vid; + if ( paramList.size() > 3 ) + { + on_hold = xmlrpc_c::value_boolean(paramList.getBoolean(3)); + + str_uattrs = xmlrpc_c::value_string(paramList.getString(4)); + } + + VMTemplate * tmpl = static_cast (pool)->get(id,true); + + if ( tmpl == 0 ) + { + att.resp_id = id; + failure_response(NO_EXISTS, att); + return; + } + + bool is_vrouter = tmpl->is_vrouter(); + + tmpl->unlock(); + + if (is_vrouter) + { + att.resp_msg = "Virtual router templates cannot be instantiated as stand-alone VMs"; + failure_response(ACTION, att); + return; + } + + int vid; + ErrorCode ec; + + ec = instantiate(id, name, on_hold, str_uattrs, 0, vid, att); + + if ( ec == SUCCESS ) + { + success_response(vid, att); + } + else + { + failure_response(ec, att); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +Request::ErrorCode VMTemplateInstantiate::instantiate(int id, string name, + bool on_hold, string str_uattrs, Template* extra_attrs, int& vid, + RequestAttributes& att) +{ + int rc; ostringstream sid; @@ -39,38 +87,25 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList Nebula& nd = Nebula::instance(); VirtualMachinePool* vmpool = nd.get_vmpool(); - VMTemplatePool * tpool = static_cast(pool); + VMTemplatePool * tpool = nd.get_tpool(); VirtualMachineTemplate * tmpl; VirtualMachineTemplate * extended_tmpl = 0; VirtualMachineTemplate uattrs; VMTemplate * rtmpl; - string error_str; string aname; - string tmpl_name; - if ( paramList.size() > 3 ) - { - on_hold = xmlrpc_c::value_boolean(paramList.getBoolean(3)); - - str_uattrs = xmlrpc_c::value_string(paramList.getString(4)); - } - /* ---------------------------------------------------------------------- */ /* Get, check and clone the template */ /* ---------------------------------------------------------------------- */ - rtmpl = tpool->get(id,true); if ( rtmpl == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),id), - att); - - return; + att.resp_id = id; + return NO_EXISTS; } tmpl_name = rtmpl->get_name(); @@ -83,39 +118,42 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList // Parse & merge user attributes (check if the request user is not oneadmin) if (!str_uattrs.empty()) { - rc = uattrs.parse_str_or_xml(str_uattrs, error_str); + rc = uattrs.parse_str_or_xml(str_uattrs, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL, error_str, att); delete tmpl; - return; + return INTERNAL; } if (att.uid!=UserPool::ONEADMIN_ID && att.gid!=GroupPool::ONEADMIN_ID) { if (uattrs.check(aname)) { - ostringstream oss; - - oss << "User Template includes a restricted attribute "<< aname; - - failure_response(AUTHORIZATION, - authorization_error(oss.str(), att), - att); + att.resp_msg ="User Template includes a restricted attribute " + aname; delete tmpl; - return; + return AUTHORIZATION; } } - rc = tmpl->merge(&uattrs, error_str); + rc = tmpl->merge(&uattrs, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL, error_str, att); delete tmpl; - return; + return INTERNAL; + } + } + + if (extra_attrs != 0) + { + rc = tmpl->merge(extra_attrs, att.resp_msg); + + if ( rc != 0 ) + { + delete tmpl; + return INTERNAL; } } @@ -136,11 +174,13 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList tmpl->set(new SingleAttribute("NAME",name)); } + //-------------------------------------------------------------------------- + if ( att.uid != 0 ) { AuthRequest ar(att.uid, att.group_ids); - ar.add_auth(auth_op, perms); //USE TEMPLATE + ar.add_auth(AuthRequest::USE, perms); //USE TEMPLATE if (!str_uattrs.empty()) { @@ -149,42 +189,37 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList tmpl->to_xml(tmpl_str); // CREATE TEMPLATE - ar.add_create_auth(att.uid, att.gid, auth_object, tmpl_str); + ar.add_create_auth(att.uid, att.gid, PoolObjectSQL::TEMPLATE, tmpl_str); } VirtualMachine::set_auth_request(att.uid, ar, tmpl); if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; delete tmpl; - return; + return AUTHORIZATION; } extended_tmpl = new VirtualMachineTemplate(*tmpl); VirtualMachine::disk_extended_info(att.uid, extended_tmpl); - if ( quota_authorization(extended_tmpl, Quotas::VIRTUALMACHINE, att) == false ) + if (quota_authorization(extended_tmpl, Quotas::VIRTUALMACHINE, att, + att.resp_msg) == false) { delete tmpl; delete extended_tmpl; - return; + return AUTHORIZATION; } } rc = vmpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, - tmpl, &vid, error_str, on_hold); + tmpl, &vid, att.resp_msg, on_hold); if ( rc < 0 ) { - failure_response(INTERNAL, - allocate_error(PoolObjectSQL::VM,error_str), - att); - if (extended_tmpl != 0) { quota_rollback(extended_tmpl, Quotas::VIRTUALMACHINE, att); @@ -192,12 +227,12 @@ void VMTemplateInstantiate::request_execute(xmlrpc_c::paramList const& paramList delete extended_tmpl; - return; + return ALLOCATE; } delete extended_tmpl; - success_response(vid, att); + return SUCCESS; } /* -------------------------------------------------------------------------- */ diff --git a/src/rm/RequestManagerVdc.cc b/src/rm/RequestManagerVdc.cc index 805cbe2d73..2df98f559d 100644 --- a/src/rm/RequestManagerVdc.cc +++ b/src/rm/RequestManagerVdc.cc @@ -30,7 +30,6 @@ void VdcEditGroup::request_execute( string vdc_name; string group_name; - string error_str; Vdc* vdc; @@ -53,9 +52,9 @@ void VdcEditGroup::request_execute( if ( rc == -1 && check_obj_exist ) { - failure_response(NO_EXISTS, get_error(object_name(PoolObjectSQL::GROUP), - group_id), att); - + att.resp_obj = PoolObjectSQL::GROUP; + att.resp_id = group_id; + failure_response(NO_EXISTS, att); return; } @@ -68,10 +67,8 @@ void VdcEditGroup::request_execute( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); - + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return; } } @@ -80,14 +77,12 @@ void VdcEditGroup::request_execute( if ( vdc == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),vdc_id), - att); - + att.resp_id = vdc_id; + failure_response(NO_EXISTS, att); return; } - rc = edit_group(vdc, group_id, error_str); + rc = edit_group(vdc, group_id, att.resp_msg); if (rc == 0) { @@ -98,10 +93,7 @@ void VdcEditGroup::request_execute( if (rc != 0) { - failure_response(INTERNAL, - request_error("Cannot edit VDC", error_str), - att); - + failure_response(INTERNAL, att); return; } @@ -144,7 +136,6 @@ void VdcEditResource::request_execute( string vdc_name; string zone_name; string res_name; - string error_str; Vdc* vdc; @@ -156,8 +147,7 @@ void VdcEditResource::request_execute( // Authorize the action // ------------------------------------------------------------------------- - rc = get_info(pool, vdc_id, PoolObjectSQL::VDC, - att, vdc_perms, vdc_name, true); + rc = get_info(pool, vdc_id, PoolObjectSQL::VDC, att, vdc_perms, vdc_name, true); if ( rc == -1 ) { @@ -165,32 +155,30 @@ void VdcEditResource::request_execute( } rc = get_info(zonepool, zone_id, PoolObjectSQL::ZONE, att, zone_perms, - zone_name, false); + zone_name, false); zone_exists = (rc == 0); if ( rc == -1 && check_obj_exist ) { - failure_response(NO_EXISTS, get_error(object_name(PoolObjectSQL::ZONE), - zone_id), att); - + att.resp_obj = PoolObjectSQL::ZONE; + att.resp_id = zone_id; + failure_response(NO_EXISTS, att); return; } // TODO: resource must exist in target zone, this code only checks locally - if (res_id != Vdc::ALL_RESOURCES && zone_id == local_zone_id) { - rc = get_info(respool, res_id, res_obj_type, att, - res_perms, res_name, false); + rc = get_info(respool, res_id, res_obj_type, att, res_perms, res_name, false); res_exists = (rc == 0); if ( rc == -1 && check_obj_exist ) { - failure_response(NO_EXISTS, get_error(object_name(res_obj_type), - res_id), att); - + att.resp_obj = res_obj_type; + att.resp_id = res_id; + failure_response(NO_EXISTS, att); return; } } @@ -213,10 +201,8 @@ void VdcEditResource::request_execute( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); - + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return; } } @@ -225,14 +211,12 @@ void VdcEditResource::request_execute( if ( vdc == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),vdc_id), - att); - + att.resp_id = vdc_id; + failure_response(NO_EXISTS, att); return; } - rc = edit_resource(vdc, zone_id, res_id, error_str); + rc = edit_resource(vdc, zone_id, res_id, att.resp_msg); if (rc == 0) { @@ -243,10 +227,7 @@ void VdcEditResource::request_execute( if (rc != 0) { - failure_response(INTERNAL, - request_error("Error updating the VDC", error_str), - att); - + failure_response(INTERNAL, att); return; } diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index c826b1982e..a7fb8234c3 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -39,9 +39,8 @@ bool RequestManagerVirtualMachine::vm_authorization( if ( object == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(auth_object),oid), - att); + att.resp_id = oid; + failure_response(NO_EXISTS, att); return false; } @@ -89,9 +88,8 @@ bool RequestManagerVirtualMachine::vm_authorization( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, - authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); return false; } @@ -112,10 +110,9 @@ bool RequestManagerVirtualMachine::quota_resize_authorization( if (vm == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::VM),oid), - att); - + att.resp_obj = PoolObjectSQL::VM; + att.resp_id = oid; + failure_response(NO_EXISTS, att); return false; } @@ -136,8 +133,6 @@ bool RequestManagerVirtualMachine::quota_resize_authorization( { int rc; - string error_str; - Nebula& nd = Nebula::instance(); UserPool* upool = nd.get_upool(); GroupPool* gpool = nd.get_gpool(); @@ -151,19 +146,18 @@ bool RequestManagerVirtualMachine::quota_resize_authorization( if ( user != 0 ) { - rc = user->quota.quota_update(Quotas::VM, deltas, user_dquotas, error_str); + rc = user->quota.quota_update(Quotas::VM, deltas, user_dquotas, att.resp_msg); if (rc == false) { ostringstream oss; - oss << object_name(PoolObjectSQL::USER) - << " [" << vm_perms.uid << "] " - << error_str; + oss << object_name(PoolObjectSQL::USER) << " [" << vm_perms.uid << "] " + << att.resp_msg; - failure_response(AUTHORIZATION, - request_error(oss.str(), ""), - att); + att.resp_msg = oss.str(); + + failure_response(AUTHORIZATION, att); user->unlock(); @@ -182,20 +176,19 @@ bool RequestManagerVirtualMachine::quota_resize_authorization( if ( group != 0 ) { - rc = group->quota.quota_update(Quotas::VM, deltas, group_dquotas, error_str); + rc = group->quota.quota_update(Quotas::VM, deltas, group_dquotas, att.resp_msg); if (rc == false) { ostringstream oss; RequestAttributes att_tmp(vm_perms.uid, -1, att); - oss << object_name(PoolObjectSQL::GROUP) - << " [" << vm_perms.gid << "] " - << error_str; + oss << object_name(PoolObjectSQL::GROUP) << " [" << vm_perms.gid << "] " + << att.resp_msg; - failure_response(AUTHORIZATION, - request_error(oss.str(), ""), - att); + att.resp_msg = oss.str(); + + failure_response(AUTHORIZATION, att); group->unlock(); @@ -241,9 +234,9 @@ int RequestManagerVirtualMachine::get_default_ds_information( if (cluster == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::CLUSTER), cluster_id), - att); + att.resp_obj = PoolObjectSQL::CLUSTER; + att.resp_id = cluster_id; + failure_response(NO_EXISTS, att); return -1; } @@ -258,12 +251,14 @@ int RequestManagerVirtualMachine::get_default_ds_information( { ostringstream oss; - oss << object_name(PoolObjectSQL::CLUSTER) - << " [" << cluster_id << "] does not have any " - << object_name(PoolObjectSQL::DATASTORE) << " of type " - << Datastore::type_to_str(Datastore::SYSTEM_DS) << "."; + oss << object_name(PoolObjectSQL::CLUSTER) << " [" << cluster_id + << "] does not have any " << object_name(PoolObjectSQL::DATASTORE) + << " of type " << Datastore::type_to_str(Datastore::SYSTEM_DS) + << "."; - failure_response(ACTION, request_error(oss.str(),""), att); + att.resp_msg = oss.str(); + + failure_response(ACTION, att); return -1; } @@ -289,10 +284,9 @@ int RequestManagerVirtualMachine::get_ds_information(int ds_id, if ( ds == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::DATASTORE), ds_id), - att); - + att.resp_obj = PoolObjectSQL::DATASTORE; + att.resp_id = ds_id; + failure_response(NO_EXISTS, att); return -1; } @@ -304,7 +298,9 @@ int RequestManagerVirtualMachine::get_ds_information(int ds_id, << " [" << ds_id << "] to deploy the VM, but it is not of type" << " system datastore."; - failure_response(INTERNAL, request_error(oss.str(),""), att); + att.resp_msg = oss.str(); + + failure_response(INTERNAL, att); ds->unlock(); @@ -346,10 +342,9 @@ int RequestManagerVirtualMachine::get_host_information( if ( host == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::HOST),hid), - att); - + att.resp_obj = PoolObjectSQL::HOST; + att.resp_id = hid; + failure_response(NO_EXISTS, att); return -1; } @@ -367,10 +362,9 @@ int RequestManagerVirtualMachine::get_host_information( if (nd.get_ds_location(cluster_id, ds_location) == -1) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::CLUSTER),cluster_id), - att); - + att.resp_obj = PoolObjectSQL::CLUSTER; + att.resp_id = cluster_id; + failure_response(NO_EXISTS, att); return -1; } @@ -391,7 +385,7 @@ bool RequestManagerVirtualMachine::check_host( string capacity_error; int cpu, mem, disk; - vector pci; + vector pci; vm->get_requirements(cpu, mem, disk, pci); @@ -417,8 +411,8 @@ bool RequestManagerVirtualMachine::check_host( ostringstream oss; oss << object_name(PoolObjectSQL::VM) << " [" << vm->get_oid() - << "] does not fit in " << object_name(PoolObjectSQL::HOST) - << " [" << hid << "]. " << capacity_error; + << "] does not fit in " << object_name(PoolObjectSQL::HOST) << " [" + << hid << "]. " << capacity_error; error = oss.str(); } @@ -440,7 +434,8 @@ VirtualMachine * RequestManagerVirtualMachine::get_vm(int id, if ( vm == 0 ) { - failure_response(NO_EXISTS,get_error(object_name(auth_object),id), att); + att.resp_id = id; + failure_response(NO_EXISTS, att); return 0; } @@ -472,9 +467,8 @@ int RequestManagerVirtualMachine::add_history(VirtualMachine * vm, if ( rc != 0 ) { - failure_response(INTERNAL, - request_error("Cannot update virtual machine history",""), - att); + att.resp_msg = "Cannot update virtual machine history"; + failure_response(INTERNAL, att); return -1; } @@ -543,16 +537,37 @@ void VirtualMachineAction::request_execute(xmlrpc_c::paramList const& paramList, if (vm->is_imported() && !vm->is_imported_action_supported(action)) { - oss << "Action \"" << action_st << "\" is not supported for imported VMs"; - - failure_response(ACTION, - request_error(oss.str(),""), - att); + att.resp_msg = "Action \"" + action_st + "\" is not supported for imported VMs"; + failure_response(ACTION, att); vm->unlock(); return; } + if (vm->is_vrouter() && !VirtualRouter::is_action_supported(action)) + { + bool failure = true; + + // Delete operation is allowed for orphan virtual router VMs. + if (action == History::DELETE_ACTION || + action == History::SHUTDOWN_ACTION || + action == History::SHUTDOWN_HARD_ACTION) + { + VirtualRouterPool* vrpool = Nebula::instance().get_vrouterpool(); + failure = (vrpool->get(vm->get_vrouter_id(), false) != 0); + } + + if (failure) + { + att.resp_msg = "Action \""+action_st+"\" is not supported for " + "virtual router VMs"; + failure_response(ACTION, att); + + vm->unlock(); + return; + } + } + vm->unlock(); switch (action) @@ -619,30 +634,25 @@ void VirtualMachineAction::request_execute(xmlrpc_c::paramList const& paramList, success_response(id, att); break; case -1: - failure_response(NO_EXISTS, - get_error(object_name(auth_object),id), - att); + att.resp_id = id; + failure_response(NO_EXISTS, att); break; case -2: oss << "Error performing action \"" << action_st << "\" on " << object_name(auth_object) << " [" << id << "]"; + att.resp_msg = oss.str(); - failure_response(ACTION, - request_error(oss.str(),error), - att); - break; + failure_response(ACTION, att); + break; case -3: - oss << "Virtual machine action \"" << action_st - << "\" is not supported"; + oss << "Virtual machine action \"" << action_st << "\" is not supported"; + att.resp_msg = oss.str(); - failure_response(ACTION, - request_error(oss.str(),""), - att); + failure_response(ACTION, att); break; default: - failure_response(INTERNAL, - request_error("Internal error","Action result not defined"), - att); + att.resp_msg = "Internal error. Action result not defined"; + failure_response(INTERNAL, att); } return; @@ -674,8 +684,6 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList, bool auth = false; - string error; - // ------------------------------------------------------------------------ // Get request parameters and information about the target host // ------------------------------------------------------------------------ @@ -755,11 +763,13 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList, { ostringstream oss; - oss << object_name(PoolObjectSQL::DATASTORE) - << " [" << ds_id << "] and " << object_name(PoolObjectSQL::HOST) - << " [" << hid <<"] are not in the same cluster."; + oss << object_name(PoolObjectSQL::DATASTORE) << " [" << ds_id << "] and " + << object_name(PoolObjectSQL::HOST) << " [" << hid + << "] are not in the same cluster."; - failure_response(ACTION, request_error(oss.str(),""), att); + att.resp_msg = oss.str(); + + failure_response(ACTION, att); return; } @@ -776,9 +786,9 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList, if (ds == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::DATASTORE), ds_id), - att); + att.resp_obj = PoolObjectSQL::DATASTORE; + att.resp_id = ds_id; + failure_response(NO_EXISTS, att); return; } @@ -817,23 +827,18 @@ void VirtualMachineDeploy::request_execute(xmlrpc_c::paramList const& paramList, vm->get_state() != VirtualMachine::STOPPED && vm->get_state() != VirtualMachine::UNDEPLOYED) { - ostringstream oss; - - oss << "Deploy action is not available for state " << vm->state_str(); - - failure_response(ACTION, - request_error(oss.str(),""), - att); + att.resp_msg = "Deploy action is not available for state " + vm->state_str(); + failure_response(ACTION, att); vm->unlock(); return; } - if (check_host(hid, enforce, vm, error) == false) + if (check_host(hid, enforce, vm, att.resp_msg) == false) { vm->unlock(); - failure_response(ACTION, request_error(error,""), att); + failure_response(ACTION, att); return; } @@ -952,9 +957,9 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList if (ds == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::DATASTORE), ds_id), - att); + att.resp_obj = PoolObjectSQL::DATASTORE; + att.resp_id = ds_id; + failure_response(NO_EXISTS, att); return; } @@ -998,13 +1003,9 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList (vm->get_lcm_state() != VirtualMachine::RUNNING && vm->get_lcm_state() != VirtualMachine::UNKNOWN)))) { - ostringstream oss; + att.resp_msg = "Migrate action is not available for state " + vm->state_str(); - oss << "Migrate action is not available for state " << vm->state_str(); - - failure_response(ACTION, - request_error(oss.str(),""), - att); + failure_response(ACTION, att); vm->unlock(); return; @@ -1021,9 +1022,17 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList if (vm->is_imported() && !vm->is_imported_action_supported(action)) { - failure_response(ACTION, - request_error("Migration is not supported for imported VMs",""), - att); + att.resp_msg = "Migration is not supported for imported VMs"; + failure_response(ACTION, att); + + vm->unlock(); + return; + } + + if (vm->is_vrouter() && !VirtualRouter::is_action_supported(action)) + { + att.resp_msg = "Migration is not supported for virtual router VMs"; + failure_response(ACTION, att); vm->unlock(); return; @@ -1040,23 +1049,22 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList { ostringstream oss; - oss << "VM is already running on " - << object_name(PoolObjectSQL::HOST) << " [" << c_hid << "]"; + oss << "VM is already running on " << object_name(PoolObjectSQL::HOST) + << " [" << c_hid << "]"; - failure_response(ACTION, - request_error(oss.str(),""), - att); + att.resp_msg = oss.str(); + failure_response(ACTION, att); vm->unlock(); return; } // Check the host has enough capacity - if (check_host(hid, enforce, vm, error) == false) + if (check_host(hid, enforce, vm, att.resp_msg) == false) { vm->unlock(); - failure_response(ACTION, request_error(error,""), att); + failure_response(ACTION, att); return; } @@ -1067,9 +1075,9 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList if (host == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::HOST), c_hid), - att); + att.resp_obj = PoolObjectSQL::HOST; + att.resp_id = c_hid; + failure_response(NO_EXISTS, att); } c_cluster_id = host->get_cluster_id(); @@ -1087,18 +1095,16 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList << c_cluster_id << "] , and new host is in " << object_name(PoolObjectSQL::CLUSTER) << " [" << cluster_id << "]"; - failure_response(ACTION, - request_error(oss.str(),""), - att); + att.resp_msg = oss.str(); + failure_response(ACTION, att); return; } if ( is_public_cloud || c_is_public_cloud ) { - failure_response(ACTION, - request_error("Cannot migrate to or from a Public Cloud Host",""), - att); + att.resp_msg = "Cannot migrate to or from a Public Cloud Host"; + failure_response(ACTION, att); return; } @@ -1109,8 +1115,9 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList if ( c_ds_id != ds_id && live ) { - failure_response(ACTION, request_error( "A migration to a different" - " system datastore cannot be performed live.",""), att); + att.resp_msg = "A migration to a different system datastore " + "cannot be performed live."; + failure_response(ACTION, att); return; } @@ -1121,8 +1128,8 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList if (!ds_migr) { - failure_response(ACTION, request_error("System datastore migration" - " not supported by TM driver",""), att); + att.resp_msg = "System datastore migration not supported by TM driver"; + failure_response(ACTION, att); return; } @@ -1131,22 +1138,20 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList ostringstream oss; oss << "Cannot migrate to a different cluster. VM running in a host" - << " in " << object_name(PoolObjectSQL::CLUSTER) << " [" - << c_cluster_id << "] , and new system datastore is in " + << " in " << object_name(PoolObjectSQL::CLUSTER) + << " [" << c_cluster_id << "] , and new system datastore is in " << object_name(PoolObjectSQL::CLUSTER) << " [" << ds_cluster_id << "]"; - failure_response(ACTION, request_error(oss.str(),""), att); + att.resp_msg = oss.str(); + failure_response(ACTION, att); return; } if (c_tm_mad != tm_mad) { - ostringstream oss; - - oss << "Cannot migrate to a system datastore with a different TM driver"; - - failure_response(ACTION, request_error(oss.str(),""), att); + att.resp_msg = "Cannot migrate to a system datastore with a different TM driver"; + failure_response(ACTION, att); return; } @@ -1250,7 +1255,6 @@ void VirtualMachineDiskSaveas::request_execute( int rc; bool rc_auth; - string error; // ------------------------------------------------------------------------- // Prepare and check the VM/DISK to be saved as @@ -1265,7 +1269,7 @@ void VirtualMachineDiskSaveas::request_execute( goto error_state; } - rc = vm->set_saveas_disk(disk_id, snap_id, iid_orig, size, error); + rc = vm->set_saveas_disk(disk_id, snap_id, iid_orig, size, att.resp_msg); if (rc == -1) { @@ -1403,9 +1407,10 @@ void VirtualMachineDiskSaveas::request_execute( ds_disk_type, ds_data, Datastore::IMAGE_DS, + "", -1, &iid, - error); + att.resp_msg); if (rc < 0) { goto error_allocate; @@ -1431,8 +1436,8 @@ void VirtualMachineDiskSaveas::request_execute( error_state: vm->unlock(); - failure_response(INTERNAL,request_error("VM has to be RUNNING, POWEROFF or " - "SUSPENDED to save disks.",""), att); + att.resp_msg = "VM has to be RUNNING, POWEROFF or SUSPENDED to save disks."; + failure_response(INTERNAL, att); return; error_disk: @@ -1441,27 +1446,31 @@ error_disk: vm->clear_saveas_disk(); vm->unlock(); - - failure_response(INTERNAL,request_error("Cannot use DISK", error), att); + att.resp_msg ="Cannot use DISK. " + att.resp_msg; + failure_response(INTERNAL, att); return; error_image: - failure_response(NO_EXISTS, get_error(object_name(PoolObjectSQL::IMAGE), - iid_orig), att); + att.resp_obj = PoolObjectSQL::IMAGE; + att.resp_id = iid_orig; + failure_response(NO_EXISTS, att); goto error_common; error_image_type: - failure_response(INTERNAL, request_error("Cannot save_as image of type " + - Image::type_to_str(type), ""), att); + att.resp_msg = "Cannot save_as image of type " + Image::type_to_str(type); + failure_response(INTERNAL, att); goto error_common; error_ds: - failure_response(NO_EXISTS, get_error(object_name(PoolObjectSQL::DATASTORE), - ds_id), att); +error_ds_removed: + att.resp_obj = PoolObjectSQL::DATASTORE; + att.resp_id = ds_id; + failure_response(NO_EXISTS, att); goto error_common; error_size: - failure_response(ACTION, "Not enough space in datastore", att); + att.resp_msg = "Not enough space in datastore"; + failure_response(ACTION, att); goto error_common; error_auth: @@ -1470,12 +1479,7 @@ error_auth: error_allocate: quota_rollback(&img_usage, Quotas::DATASTORE, att); - failure_response(INTERNAL, allocate_error(PoolObjectSQL::IMAGE, error),att); - goto error_common; - -error_ds_removed: - failure_response(NO_EXISTS,get_error(object_name(PoolObjectSQL::DATASTORE), - ds_id), att); + failure_response(ALLOCATE, att); goto error_common; error_common: @@ -1516,7 +1520,8 @@ void VirtualMachineMonitoring::request_execute( if ( rc != 0 ) { - failure_response(INTERNAL,request_error("Internal Error",""), att); + att.resp_msg = "Internal error"; + failure_response(INTERNAL, att); return; } @@ -1537,11 +1542,9 @@ void VirtualMachineAttach::request_execute(xmlrpc_c::paramList const& paramList, VirtualMachineTemplate tmpl; PoolObjectAuth vm_perms; - VirtualMachinePool * vmpool = static_cast(pool); VirtualMachine * vm; int rc; - string error_str; bool volatile_disk; int id = xmlrpc_c::value_int(paramList.getInt(1)); @@ -1551,11 +1554,11 @@ void VirtualMachineAttach::request_execute(xmlrpc_c::paramList const& paramList, // Parse Disk template // ------------------------------------------------------------------------- - rc = tmpl.parse_str_or_xml(str_tmpl, error_str); + rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL, error_str, att); + failure_response(INTERNAL, att); return; } @@ -1568,13 +1571,8 @@ void VirtualMachineAttach::request_execute(xmlrpc_c::paramList const& paramList, return; } - vm = vmpool->get(id, true); - - if (vm == 0) + if ((vm = get_vm(id, att)) == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::VM),id), - att); return; } @@ -1582,6 +1580,15 @@ void VirtualMachineAttach::request_execute(xmlrpc_c::paramList const& paramList, volatile_disk = vm->volatile_disk_extended_info(&tmpl); + if (vm->is_vrouter() && !VirtualRouter::is_action_supported(History::DISK_ATTACH_ACTION)) + { + att.resp_msg = "Action is not supported for virtual router VMs"; + failure_response(ACTION, att); + + vm->unlock(); + return; + } + vm->unlock(); RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att); @@ -1605,7 +1612,7 @@ void VirtualMachineAttach::request_execute(xmlrpc_c::paramList const& paramList, } } - rc = dm->attach(id, &tmpl, error_str); + rc = dm->attach(id, &tmpl, att.resp_msg); if ( rc != 0 ) { @@ -1616,9 +1623,7 @@ void VirtualMachineAttach::request_execute(xmlrpc_c::paramList const& paramList, quota_rollback(&tmpl, Quotas::IMAGE, att_quota); } - failure_response(ACTION, - request_error(error_str, ""), - att); + failure_response(ACTION, att); } else { @@ -1636,6 +1641,7 @@ void VirtualMachineDetach::request_execute(xmlrpc_c::paramList const& paramList, { Nebula& nd = Nebula::instance(); DispatchManager * dm = nd.get_dm(); + VirtualMachine * vm; int rc; string error_str; @@ -1652,13 +1658,27 @@ void VirtualMachineDetach::request_execute(xmlrpc_c::paramList const& paramList, return; } - rc = dm->detach(id, disk_id, error_str); + if ((vm = get_vm(id, att)) == 0) + { + return; + } + + if (vm->is_vrouter() && !VirtualRouter::is_action_supported(History::NIC_DETACH_ACTION)) + { + att.resp_msg = "Action is not supported for virtual router VMs"; + failure_response(ACTION, att); + + vm->unlock(); + return; + } + + vm->unlock(); + + rc = dm->detach(id, disk_id, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, - request_error(error_str, ""), - att); + failure_response(ACTION, att); } else { @@ -1687,7 +1707,6 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, Host * host; Template deltas; - string error_str; bool rc; int ret; int hid = -1; @@ -1708,19 +1727,17 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, // ------------------------------------------------------------------------- // Parse template // ------------------------------------------------------------------------- - - rc = tmpl.parse_str_or_xml(str_tmpl, error_str); + rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL, error_str, att); + failure_response(INTERNAL, att); return; } /* ---------------------------------------------------------------------- */ /* Authorize the operation & restricted attributes */ /* ---------------------------------------------------------------------- */ - if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false ) { return; @@ -1732,13 +1749,9 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, if (tmpl.check(aname)) { - ostringstream oss; + att.resp_msg = "Template includes a restricted attribute " + aname; + failure_response(AUTHORIZATION, att); - oss << "Template includes a restricted attribute " << aname; - - failure_response(AUTHORIZATION, - authorization_error(oss.str(), att), - att); return; } } @@ -1755,9 +1768,8 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, if (vm == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::VM),id), - att); + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } @@ -1808,27 +1820,20 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, case VirtualMachine::DONE: case VirtualMachine::SUSPENDED: case VirtualMachine::ACTIVE: - ostringstream oss; - - oss << "Resize action is not available for state " << vm->state_str(); - - failure_response(ACTION, - request_error(oss.str(),""), - att); + att.resp_msg="Resize action is not available for state "+vm->state_str(); + failure_response(ACTION, att); vm->unlock(); return; } - ret = vm->check_resize(ncpu, nmemory, nvcpu, error_str); + ret = vm->check_resize(ncpu, nmemory, nvcpu, att.resp_msg); vm->unlock(); if (ret != 0) { - failure_response(INTERNAL, - request_error("Could resize the VM", error_str), - att); + failure_response(INTERNAL, att); return; } @@ -1852,30 +1857,31 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, int dcpu_host = (int) (dcpu * 100);//now in 100% int dmem_host = dmemory * 1024; //now in Kilobytes - vector empty_pci; - string error; + vector empty_pci; host = hpool->get(hid, true); if (host == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::HOST),hid), - att); + att.resp_obj = PoolObjectSQL::HOST; + att.resp_id = hid; + failure_response(NO_EXISTS, att); quota_rollback(&deltas, Quotas::VM, att_rollback); return; } - if ( enforce && host->test_capacity(dcpu_host, dmem_host, 0, empty_pci, error) == false) + if ( enforce && host->test_capacity(dcpu_host, dmem_host, 0, + empty_pci, att.resp_msg) == false) { ostringstream oss; - oss << object_name(PoolObjectSQL::HOST) - << " " << hid << " does not have enough capacity."; + oss << object_name(PoolObjectSQL::HOST) << " " << hid + << " does not have enough capacity."; - failure_response(ACTION, request_error(oss.str(),""), att); + att.resp_msg = oss.str(); + failure_response(ACTION, att); host->unlock(); @@ -1899,9 +1905,8 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, if (vm == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::VM),id), - att); + att.resp_msg = id; + failure_response(NO_EXISTS, att); quota_rollback(&deltas, Quotas::VM, att_rollback); @@ -1928,15 +1933,13 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, case VirtualMachine::HOLD: case VirtualMachine::POWEROFF: case VirtualMachine::UNDEPLOYED: - ret = vm->resize(ncpu, nmemory, nvcpu, error_str); + ret = vm->resize(ncpu, nmemory, nvcpu, att.resp_msg); if (ret != 0) { vm->unlock(); - failure_response(INTERNAL, - request_error("Could not resize the VM", error_str), - att); + failure_response(INTERNAL, att); return; } @@ -1947,13 +1950,8 @@ void VirtualMachineResize::request_execute(xmlrpc_c::paramList const& paramList, case VirtualMachine::DONE: case VirtualMachine::SUSPENDED: case VirtualMachine::ACTIVE: - ostringstream oss; - - oss << "Resize action is not available for state " << vm->state_str(); - - failure_response(ACTION, - request_error(oss.str(),""), - att); + att.resp_msg = "Resize action is not available for state " + vm->state_str(); + failure_response(ACTION, att); vm->unlock(); @@ -1991,7 +1989,6 @@ void VirtualMachineSnapshotCreate::request_execute( int rc; int snap_id; - string error_str; int id = xmlrpc_c::value_int(paramList.getInt(1)); string name = xmlrpc_c::value_string(paramList.getString(2)); @@ -2005,13 +2002,11 @@ void VirtualMachineSnapshotCreate::request_execute( return; } - rc = dm->snapshot_create(id, name, snap_id, error_str); + rc = dm->snapshot_create(id, name, snap_id, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, - request_error(error_str, ""), - att); + failure_response(ACTION, att); } else { @@ -2032,7 +2027,6 @@ void VirtualMachineSnapshotRevert::request_execute( DispatchManager * dm = nd.get_dm(); int rc; - string error_str; int id = xmlrpc_c::value_int(paramList.getInt(1)); int snap_id = xmlrpc_c::value_int(paramList.getInt(2)); @@ -2046,13 +2040,11 @@ void VirtualMachineSnapshotRevert::request_execute( return; } - rc = dm->snapshot_revert(id, snap_id, error_str); + rc = dm->snapshot_revert(id, snap_id, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, - request_error(error_str, ""), - att); + failure_response(ACTION, att); } else { @@ -2073,7 +2065,6 @@ void VirtualMachineSnapshotDelete::request_execute( DispatchManager * dm = nd.get_dm(); int rc; - string error_str; int id = xmlrpc_c::value_int(paramList.getInt(1)); int snap_id = xmlrpc_c::value_int(paramList.getInt(2)); @@ -2087,13 +2078,11 @@ void VirtualMachineSnapshotDelete::request_execute( return; } - rc = dm->snapshot_delete(id, snap_id, error_str); + rc = dm->snapshot_delete(id, snap_id, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, - request_error(error_str, ""), - att); + failure_response(ACTION, att); } else { @@ -2110,56 +2099,106 @@ void VirtualMachineAttachNic::request_execute( xmlrpc_c::paramList const& paramList, RequestAttributes& att) { - Nebula& nd = Nebula::instance(); - DispatchManager * dm = nd.get_dm(); + VirtualMachine * vm; + VirtualMachineTemplate tmpl; - VirtualMachineTemplate tmpl; - - PoolObjectAuth vm_perms; - VirtualMachinePool * vmpool = static_cast(pool); - VirtualMachine * vm; - - int rc; - string error_str; + int rc; int id = xmlrpc_c::value_int(paramList.getInt(1)); string str_tmpl = xmlrpc_c::value_string(paramList.getString(2)); + // ------------------------------------------------------------------------- + // Check if the VM is a Virtual Router + // ------------------------------------------------------------------------- + if ((vm = get_vm(id, att)) == 0) + { + return; + } + + if (vm->is_vrouter() && !VirtualRouter::is_action_supported(History::NIC_ATTACH_ACTION)) + { + att.resp_msg = "Action is not supported for virtual router VMs"; + failure_response(Request::ACTION, att); + + vm->unlock(); + return; + } + + vm->unlock(); + // ------------------------------------------------------------------------- // Parse NIC template // ------------------------------------------------------------------------- - - rc = tmpl.parse_str_or_xml(str_tmpl, error_str); + rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL, error_str, att); + failure_response(INTERNAL, att); return; } + // ------------------------------------------------------------------------- + // Perform the attach + // ------------------------------------------------------------------------- + ErrorCode ec = attach(id, tmpl, att); + + if ( ec == SUCCESS ) + { + success_response(id, att); + } + else + { + failure_response(ec, att); + } +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +Request::ErrorCode VirtualMachineAttachNic::attach(int id, VirtualMachineTemplate& tmpl, + RequestAttributes& att) +{ + Nebula& nd = Nebula::instance(); + + DispatchManager * dm = nd.get_dm(); + VirtualMachinePool* vmpool = nd.get_vmpool(); + + PoolObjectAuth vm_perms; + VirtualMachine * vm; + + int rc; + // ------------------------------------------------------------------------- // Authorize the operation, restricted attributes & check quotas // ------------------------------------------------------------------------- - - if ( vm_authorization(id, 0, &tmpl, att, 0, 0, 0, auth_op) == false ) - { - return; - } - vm = vmpool->get(id, true); - if (vm == 0) + if ( vm == 0 ) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::VM),id), - att); - return; + att.resp_id = id; + att.resp_obj = PoolObjectSQL::VM; + return NO_EXISTS; } vm->get_permissions(vm_perms); vm->unlock(); + if ( att.uid != 0 ) + { + AuthRequest ar(att.uid, att.group_ids); + + ar.add_auth(AuthRequest::MANAGE, vm_perms); + + VirtualMachine::set_auth_request(att.uid, ar, &tmpl); + + if (UserPool::authorize(ar) == -1) + { + att.resp_msg = ar.message; + return AUTHORIZATION; + } + } + RequestAttributes att_quota(vm_perms.uid, vm_perms.gid, att); if (att.uid != UserPool::ONEADMIN_ID && att.gid!=GroupPool::ONEADMIN_ID) @@ -2168,79 +2207,126 @@ void VirtualMachineAttachNic::request_execute( if (tmpl.check(aname)) { - ostringstream oss; - - oss << "NIC includes a restricted attribute " << aname; - - failure_response(AUTHORIZATION, - authorization_error(oss.str(), att), - att); - return; + att.resp_msg = "NIC includes a restricted attribute " + aname; + return AUTHORIZATION; } } - if ( quota_authorization(&tmpl, Quotas::NETWORK, att_quota) == false ) + if (quota_authorization(&tmpl, Quotas::NETWORK, att_quota, att.resp_msg) == false) { - return; + return AUTHORIZATION; } - rc = dm->attach_nic(id, &tmpl, error_str); + // ------------------------------------------------------------------------- + // Perform the attach + // ------------------------------------------------------------------------- + + rc = dm->attach_nic(id, &tmpl, att.resp_msg); if ( rc != 0 ) { quota_rollback(&tmpl, Quotas::NETWORK, att_quota); - - failure_response(ACTION, - request_error(error_str, ""), - att); - } - else - { - success_response(id, att); + return ACTION; } - return; + return SUCCESS; } /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void VirtualMachineDetachNic::request_execute( - xmlrpc_c::paramList const& paramList, - RequestAttributes& att) + xmlrpc_c::paramList const& paramList, RequestAttributes& att) { - Nebula& nd = Nebula::instance(); - DispatchManager * dm = nd.get_dm(); - - int rc; - string error_str; + VirtualMachine * vm; int id = xmlrpc_c::value_int(paramList.getInt(1)); int nic_id = xmlrpc_c::value_int(paramList.getInt(2)); // ------------------------------------------------------------------------- - // Authorize the operation + // Check if the VM is a Virtual Router // ------------------------------------------------------------------------- - if ( vm_authorization(id, 0, 0, att, 0, 0, 0, auth_op) == false ) + if ((vm = get_vm(id, att)) == 0) { return; } - rc = dm->detach_nic(id, nic_id, error_str); - - if ( rc != 0 ) + if (vm->is_vrouter() && !VirtualRouter::is_action_supported(History::NIC_DETACH_ACTION)) { - failure_response(ACTION, - request_error(error_str, ""), - att); + att.resp_msg = "Action is not supported for virtual router VMs"; + failure_response(Request::ACTION, att); + + vm->unlock(); + return; } - else + + vm->unlock(); + + // ------------------------------------------------------------------------- + // Perform the detach + // ------------------------------------------------------------------------- + ErrorCode ec = detach(id, nic_id, att); + + if ( ec == SUCCESS ) { success_response(id, att); } + else + { + failure_response(ec, att); + } +} - return; +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +Request::ErrorCode VirtualMachineDetachNic::detach(int id, int nic_id, + RequestAttributes& att) +{ + Nebula& nd = Nebula::instance(); + DispatchManager * dm = nd.get_dm(); + VirtualMachinePool* vmpool = nd.get_vmpool(); + + PoolObjectAuth vm_perms; + VirtualMachine * vm; + + // ------------------------------------------------------------------------- + // Authorize the operation + // ------------------------------------------------------------------------- + vm = vmpool->get(id, true); + + if ( vm == 0 ) + { + return NO_EXISTS; + } + + vm->get_permissions(vm_perms); + + vm->unlock(); + + if ( att.uid != 0 ) + { + AuthRequest ar(att.uid, att.group_ids); + + ar.add_auth(AuthRequest::MANAGE, vm_perms); + + if (UserPool::authorize(ar) == -1) + { + att.resp_msg = ar.message; + return AUTHORIZATION; + } + } + + // ------------------------------------------------------------------------- + // Perform the detach + // ------------------------------------------------------------------------- + if ( dm->detach_nic(id, nic_id, att.resp_msg) != 0 ) + { + return ACTION; + } + + return SUCCESS; } /* -------------------------------------------------------------------------- */ @@ -2269,13 +2355,8 @@ void VirtualMachineRecover::request_execute( if(vm->get_state() != VirtualMachine::ACTIVE) { - ostringstream oss; - - oss << "Recover action is not available for state " << vm->state_str(); - - failure_response(ACTION, - request_error(oss.str(),""), - att); + att.resp_msg = "Recover action is not available for state " + vm->state_str(); + failure_response(ACTION, att); vm->unlock(); return; @@ -2294,9 +2375,8 @@ void VirtualMachineRecover::request_execute( break; default: - failure_response(ACTION, - request_error("Wrong recovery operation code",""), - att); + att.resp_msg = "Wrong recovery operation code"; + failure_response(ACTION, att); vm->unlock(); return; @@ -2324,24 +2404,20 @@ void VirtualMachinePoolCalculateShowback::request_execute( ostringstream oss; string where; int rc; - string error_str; if ( att.gid != 0 ) { - failure_response(AUTHORIZATION, - authorization_error("Action reserved for group 0 only", att), - att); + att.resp_msg = "Action reserved for group 0 only"; + failure_response(AUTHORIZATION, att); return; } rc = (static_cast(pool))->calculate_showback( - start_month, start_year, end_month, end_year, error_str); + start_month, start_year, end_month, end_year, att.resp_msg); if (rc != 0) { - failure_response(AUTHORIZATION, - request_error(error_str, ""), - att); + failure_response(AUTHORIZATION, att); return; } @@ -2372,7 +2448,6 @@ void VirtualMachineDiskSnapshotCreate::request_execute( int rc; int snap_id; - string error_str; int id = xmlrpc_c::value_int(paramList.getInt(1)); int did = xmlrpc_c::value_int(paramList.getInt(2)); @@ -2390,7 +2465,8 @@ void VirtualMachineDiskSnapshotCreate::request_execute( if (disk == 0) { - failure_response(ACTION, request_error("VM disk does not exist", ""), att); + att.resp_msg = "VM disk does not exist"; + failure_response(ACTION, att); vm->unlock(); @@ -2412,8 +2488,8 @@ void VirtualMachineDiskSnapshotCreate::request_execute( if (is_volatile) { - failure_response(ACTION, request_error("Cannot make snapshots on " - "volatile disks",""), att); + att.resp_msg = "Cannot make snapshots on volatile disks"; + failure_response(ACTION, att); return; } @@ -2429,9 +2505,9 @@ void VirtualMachineDiskSnapshotCreate::request_execute( if (img == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::IMAGE),img_id), - att); + att.resp_obj = PoolObjectSQL::IMAGE; + att.resp_id = img_id; + failure_response(NO_EXISTS, att); return; } @@ -2488,7 +2564,7 @@ void VirtualMachineDiskSnapshotCreate::request_execute( // ------------------------------------------------------------------------ // Do the snapshot // ------------------------------------------------------------------------ - rc = dm->disk_snapshot_create(id, did, name, snap_id, error_str); + rc = dm->disk_snapshot_create(id, did, name, snap_id, att.resp_msg); if ( rc != 0 ) { @@ -2502,7 +2578,7 @@ void VirtualMachineDiskSnapshotCreate::request_execute( quota_rollback(&vm_deltas, Quotas::VM, vm_att_quota); } - failure_response(ACTION, request_error(error_str, ""), att); + failure_response(ACTION, att); } else { @@ -2523,7 +2599,6 @@ void VirtualMachineDiskSnapshotRevert::request_execute( DispatchManager * dm = nd.get_dm(); int rc; - string error_str; int id = xmlrpc_c::value_int(paramList.getInt(1)); int did = xmlrpc_c::value_int(paramList.getInt(2)); @@ -2534,13 +2609,11 @@ void VirtualMachineDiskSnapshotRevert::request_execute( return; } - rc = dm->disk_snapshot_revert(id, did, snap_id, error_str); + rc = dm->disk_snapshot_revert(id, did, snap_id, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, - request_error(error_str, ""), - att); + failure_response(ACTION, att); } else { @@ -2563,8 +2636,7 @@ void VirtualMachineDiskSnapshotDelete::request_execute( const VectorAttribute * disk; - int rc; - string error_str; + int rc; int id = xmlrpc_c::value_int(paramList.getInt(1)); int did = xmlrpc_c::value_int(paramList.getInt(2)); @@ -2579,7 +2651,8 @@ void VirtualMachineDiskSnapshotDelete::request_execute( if (disk == 0) { - failure_response(ACTION, request_error("VM disk does not exist", ""), att); + att.resp_msg = "VM disk does not exist"; + failure_response(ACTION, att); vm->unlock(); @@ -2601,9 +2674,9 @@ void VirtualMachineDiskSnapshotDelete::request_execute( if (img == 0) { - failure_response(NO_EXISTS, - get_error(object_name(PoolObjectSQL::IMAGE),img_id), - att); + att.resp_obj = PoolObjectSQL::IMAGE; + att.resp_id = img_id; + failure_response(NO_EXISTS, att); return; } @@ -2622,11 +2695,11 @@ void VirtualMachineDiskSnapshotDelete::request_execute( return; } - rc = dm->disk_snapshot_delete(id, did, snap_id, error_str); + rc = dm->disk_snapshot_delete(id, did, snap_id, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, request_error(error_str, ""), att); + failure_response(ACTION, att); } else { diff --git a/src/rm/RequestManagerVirtualNetwork.cc b/src/rm/RequestManagerVirtualNetwork.cc index 0e4436bc80..d1d776912a 100644 --- a/src/rm/RequestManagerVirtualNetwork.cc +++ b/src/rm/RequestManagerVirtualNetwork.cc @@ -19,14 +19,6 @@ using namespace std; -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - -string RequestManagerVirtualNetwork::leases_error (const string& error) -{ - return request_error("Error modifying network leases", error); -} - /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ @@ -40,19 +32,18 @@ void RequestManagerVirtualNetwork:: VirtualNetworkTemplate tmpl; VirtualNetwork * vn; - string error_str; - int rc; + int rc; if ( basic_authorization(id, att) == false ) { return; } - rc = tmpl.parse_str_or_xml(str_tmpl, error_str); + rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg); if ( rc != 0 ) { - failure_response(INTERNAL, leases_error(error_str), att); + failure_response(INTERNAL, att); return; } @@ -60,17 +51,16 @@ void RequestManagerVirtualNetwork:: if ( vn == 0 ) { - failure_response(NO_EXISTS, get_error(object_name(auth_object),id),att); + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } - rc = leases_action(vn, &tmpl, att, error_str); + rc = leases_action(vn, &tmpl, att, att.resp_msg); if ( rc < 0 ) { - failure_response(INTERNAL, - request_error("Error modifying network leases",error_str), - att); + failure_response(INTERNAL, att); vn->unlock(); return; @@ -95,12 +85,9 @@ void VirtualNetworkRmAddressRange:: VirtualNetwork * vn; - string error_str; - // ------------------------------------------------------------------------- // Authorize the operation VNET:MANAGE // ------------------------------------------------------------------------- - if (basic_authorization(id, att) == false) { return; @@ -109,12 +96,12 @@ void VirtualNetworkRmAddressRange:: // ------------------------------------------------------------------------- // Get VNET and data for reservations // ------------------------------------------------------------------------- - vn = static_cast(pool->get(id,true)); if ( vn == 0 ) { - failure_response(NO_EXISTS, get_error(object_name(auth_object),id),att); + att.resp_id = id; + failure_response(NO_EXISTS, att); return; } @@ -131,11 +118,9 @@ void VirtualNetworkRmAddressRange:: vn->get_template_attribute("MAC" , mac , ar_id); - if ( vn->rm_ar(ar_id, error_str) < 0 ) + if ( vn->rm_ar(ar_id, att.resp_msg) < 0 ) { - failure_response(INTERNAL, - request_error("Error removing address range",error_str), - att); + failure_response(INTERNAL, att); vn->unlock(); @@ -173,7 +158,7 @@ void VirtualNetworkRmAddressRange:: oss << " NIC = [ NETWORK_ID = " << parent << " ]" << endl; } - tmpl.parse_str_or_xml(oss.str(), error_str); + tmpl.parse_str_or_xml(oss.str(), att.resp_msg); Quotas::quota_del(Quotas::NETWORK, uid, gid, &tmpl); } @@ -198,21 +183,19 @@ void VirtualNetworkReserve::request_execute( VirtualNetwork * vn = 0; VirtualNetwork * rvn = 0; - string error_str; - int rc; - int cluster_id; + int rc; + int cluster_id; PoolObjectAuth reserv_perms; // ------------------------------------------------------------------------- // Process the Reservation Template // ------------------------------------------------------------------------- - rc = tmpl.parse_str_or_xml(str_tmpl, error_str); + rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg); if ( rc != 0 ) { - failure_response(ACTION, - request_error("Error in reservation request", error_str), att); + failure_response(ACTION, att); return; } @@ -222,8 +205,8 @@ void VirtualNetworkReserve::request_execute( if ( !tmpl.get("SIZE", size) || size <= 0 ) { - failure_response(ACTION, request_error("Error in reservation request", - "Reservation SIZE must be a greater than 0"), att); + att.resp_msg = "Reservation SIZE must be a greater than 0"; + failure_response(ACTION, att); return; } @@ -238,15 +221,15 @@ void VirtualNetworkReserve::request_execute( if (rid < 0) { - failure_response(ACTION, request_error("Error in reservation request", - "NETWORK_ID must be equal or greater than 0"), att); + att.resp_msg = "NETWORK_ID must be equal or greater than 0"; + failure_response(ACTION, att); return; } if (rid == id) { - failure_response(ACTION, request_error("Error in reservation request", - "Cannot add a reservation from the same network"), att); + att.resp_msg = "Cannot add a reservation from the same network"; + failure_response(ACTION, att); return; } @@ -254,9 +237,8 @@ void VirtualNetworkReserve::request_execute( if (rvn == 0) { - failure_response(NO_EXISTS, get_error(object_name(auth_object),rid), - att); - + att.resp_id = rid; + failure_response(NO_EXISTS, att); return; } @@ -264,8 +246,8 @@ void VirtualNetworkReserve::request_execute( if (parent == -1) { - failure_response(ACTION, request_error("Error in reservation request", - "Cannot add reservations to a non-reservation VNET"), att); + att.resp_msg = "Cannot add reservations to a non-reservation VNET"; + failure_response(ACTION, att); rvn->unlock(); @@ -279,8 +261,8 @@ void VirtualNetworkReserve::request_execute( oss << "New reservations for virtual network " << rid << " have to be from network " << parent; - failure_response(ACTION, request_error("Error in reservation request", - oss.str()), att); + att.resp_msg = oss.str(); + failure_response(ACTION, att); rvn->unlock(); @@ -300,8 +282,8 @@ void VirtualNetworkReserve::request_execute( if (name.empty() && !on_exisiting) { - failure_response(ACTION, request_error("Error in reservation request", - "NAME for reservation has to be set"), att); + att.resp_msg = "NAME for reservation has to be set"; + failure_response(ACTION, att); return; } @@ -312,8 +294,8 @@ void VirtualNetworkReserve::request_execute( if ( with_ar_id && (ar_id < 0)) { - failure_response(ACTION, request_error("Error in reservation request", - "AR_ID must be equal or greater than 0"), att); + att.resp_msg = "AR_ID must be equal or greater than 0"; + failure_response(ACTION, att); return; } @@ -325,8 +307,8 @@ void VirtualNetworkReserve::request_execute( if (!with_ar_id && (!ip.empty()||!mac.empty())) { - failure_response(ACTION, request_error("Error in reservation request", - "AR_ID must be specified for IP/MAC based reservations"), att); + att.resp_msg = "AR_ID must be specified for IP/MAC based reservations"; + failure_response(ACTION, att); return; } @@ -337,14 +319,15 @@ void VirtualNetworkReserve::request_execute( if ( vn == 0 ) { - failure_response(NO_EXISTS, get_error(object_name(auth_object),id),att); + att.resp_msg = id; + failure_response(NO_EXISTS, att); return; } if (vn->get_parent() != -1) { - failure_response(ACTION, request_error("Error in reservation request", - "Cannot reserve addresses from a reserved VNET"), att); + att.resp_msg = "Cannot reserve addresses from a reserved VNET"; + failure_response(ACTION, att); vn->unlock(); @@ -365,8 +348,8 @@ void VirtualNetworkReserve::request_execute( if (UserPool::authorize(ar) == -1) { - failure_response(AUTHORIZATION, authorization_error(ar.message, att), - att); + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); vn->unlock(); @@ -385,12 +368,11 @@ void VirtualNetworkReserve::request_execute( cluster_id = vn->get_cluster_id(); rc = vnpool->allocate(att.uid, att.gid, att.uname, att.gname, att.umask, - id, vtmpl, &rid, cluster_id, vn->get_cluster_name(), error_str); + id, vtmpl, &rid, cluster_id, vn->get_cluster_name(), att.resp_msg); if (rc < 0) { - failure_response(INTERNAL, - request_error("Cannot create a reservation VNET",error_str),att); + failure_response(INTERNAL, att); vn->unlock(); @@ -402,9 +384,8 @@ void VirtualNetworkReserve::request_execute( if (rvn == 0) { - failure_response(NO_EXISTS, get_error(object_name(auth_object),rid), - att); - + att.resp_id = rid; + failure_response(NO_EXISTS, att); vn->unlock(); return; @@ -423,7 +404,7 @@ void VirtualNetworkReserve::request_execute( qtmpl_s << "NIC = [ NETWORK_ID = " << id << "]" << endl; } - qtmpl.parse_str_or_xml(qtmpl_s.str(), error_str); + qtmpl.parse_str_or_xml(qtmpl_s.str(), att.resp_msg); if (quota_authorization(&qtmpl, Quotas::NETWORK, reservation_att) == false) { @@ -441,31 +422,31 @@ void VirtualNetworkReserve::request_execute( { if (!ip.empty()) { - rc = vn->reserve_addr_by_ip(rvn, size, ar_id, ip, error_str); + rc = vn->reserve_addr_by_ip(rvn, size, ar_id, ip, att.resp_msg); } else if (!mac.empty()) { - rc = vn->reserve_addr_by_mac(rvn, size, ar_id, mac, error_str); + rc = vn->reserve_addr_by_mac(rvn, size, ar_id, mac, att.resp_msg); } else { - rc = vn->reserve_addr(rvn, size, ar_id, error_str); + rc = vn->reserve_addr(rvn, size, ar_id, att.resp_msg); } } else { - rc = vn->reserve_addr(rvn, size, error_str); + rc = vn->reserve_addr(rvn, size, att.resp_msg); } if (rc != 0 ) { quota_rollback(&qtmpl, Quotas::NETWORK, reservation_att); - failure_response(ACTION, request_error(error_str,""), att); + failure_response(ACTION, att); if (!on_exisiting) { - pool->drop(rvn, error_str); + pool->drop(rvn, att.resp_msg); } rvn->unlock(); @@ -495,7 +476,7 @@ void VirtualNetworkReserve::request_execute( if ( cluster != 0 ) { - cluster->add_vnet(rid, error_str); + cluster->add_vnet(rid, att.resp_msg); clpool->update(cluster); diff --git a/src/rm/RequestManagerVirtualRouter.cc b/src/rm/RequestManagerVirtualRouter.cc new file mode 100644 index 0000000000..bc5139e7e1 --- /dev/null +++ b/src/rm/RequestManagerVirtualRouter.cc @@ -0,0 +1,392 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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 "RequestManagerVirtualRouter.h" +#include "RequestManagerVMTemplate.h" +#include "RequestManagerVirtualMachine.h" +#include "PoolObjectAuth.h" +#include "Nebula.h" + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualRouterInstantiate::request_execute( + xmlrpc_c::paramList const& paramList, RequestAttributes& att) +{ + int vrid = xmlrpc_c::value_int(paramList.getInt(1)); + int n_vms = xmlrpc_c::value_int(paramList.getInt(2)); + int tmpl_id = xmlrpc_c::value_int(paramList.getInt(3)); + string name = xmlrpc_c::value_string(paramList.getString(4)); + bool on_hold = xmlrpc_c::value_boolean(paramList.getBoolean(5)); + string str_uattrs = xmlrpc_c::value_string(paramList.getString(6)); + + Nebula& nd = Nebula::instance(); + + VirtualRouterPool* vrpool = nd.get_vrouterpool(); + VirtualRouter * vr; + DispatchManager* dm = nd.get_dm(); + VMTemplatePool* tpool = nd.get_tpool(); + + PoolObjectAuth vr_perms; + Template* extra_attrs; + bool has_vmids; + string error; + string vr_name, tmp_name; + ostringstream oss; + + vector vms; + vector::iterator vmid; + + int vid; + + /* ---------------------------------------------------------------------- */ + /* Get the Virtual Router NICs */ + /* ---------------------------------------------------------------------- */ + vr = vrpool->get(vrid, true); + + if (vr == 0) + { + att.resp_id = vrid; + failure_response(NO_EXISTS, att); + return; + } + + vr->get_permissions(vr_perms); + + extra_attrs = vr->get_vm_template(); + has_vmids = vr->has_vmids(); + vr_name = vr->get_name(); + + vr->unlock(); + + if ( att.uid != 0 ) + { + AuthRequest ar(att.uid, att.group_ids); + + ar.add_auth(AuthRequest::MANAGE, vr_perms); // MANAGE VROUTER + + if (UserPool::authorize(ar) == -1) + { + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); + return; + } + } + + if (has_vmids) + { + att.resp_msg = "Virtual router already has VMs. Cannot instantiate new ones"; + failure_response(ACTION, att); + return; + } + + VMTemplate * tmpl = tpool->get(tmpl_id,true); + + if ( tmpl == 0 ) + { + att.resp_id = tmpl_id; + att.resp_obj = PoolObjectSQL::TEMPLATE; + failure_response(NO_EXISTS, att); + return; + } + + bool is_vrouter = tmpl->is_vrouter(); + + tmpl->unlock(); + + if (!is_vrouter) + { + att.resp_msg = "Only virtual router templates are allowed"; + failure_response(ACTION, att); + return; + } + + if (name.empty()) + { + name = "vr-" + vr_name + "-%i"; + } + + for (int i=0; ifinalize(*vmid, att.resp_msg); + } + + return; + } + + vms.push_back(vid); + } + + vr = vrpool->get(vrid, true); + + if (vr != 0) + { + for (vmid = vms.begin(); vmid != vms.end(); vmid++) + { + vr->add_vmid(*vmid); + } + + vrpool->update(vr); + + vr->unlock(); + } + + // VMs are created on hold to wait for all of them to be created + // successfully, to avoid the rollback dm->finalize call on prolog + if (!on_hold) + { + for (vmid = vms.begin(); vmid != vms.end(); vmid++) + { + dm->release(*vmid, att.resp_msg); + } + } + + success_response(vrid, att); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualRouterAttachNic::request_execute( + xmlrpc_c::paramList const& paramList, RequestAttributes& att) +{ + VirtualRouterPool* vrpool = static_cast(pool); + VirtualRouter * vr; + VectorAttribute* nic; + + VirtualMachineTemplate tmpl; + PoolObjectAuth vr_perms; + + int rc; + + int vrid = xmlrpc_c::value_int(paramList.getInt(1)); + string str_tmpl = xmlrpc_c::value_string(paramList.getString(2)); + + // ------------------------------------------------------------------------- + // Parse NIC template + // ------------------------------------------------------------------------- + rc = tmpl.parse_str_or_xml(str_tmpl, att.resp_msg); + + if ( rc != 0 ) + { + failure_response(INTERNAL, att); + return; + } + + // ------------------------------------------------------------------------- + // Authorize the operation & check quotas + // ------------------------------------------------------------------------- + vr = vrpool->get(vrid, true); + + if (vr == 0) + { + att.resp_id = vrid; + failure_response(NO_EXISTS, att); + return; + } + + vr->get_permissions(vr_perms); + + vr->unlock(); + + if ( att.uid != 0 ) + { + AuthRequest ar(att.uid, att.group_ids); + + ar.add_auth(AuthRequest::MANAGE, vr_perms); // MANAGE VROUTER + + VirtualRouter::set_auth_request(att.uid, ar, &tmpl); // USE VNET + + if (UserPool::authorize(ar) == -1) + { + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); + return; + } + } + + RequestAttributes att_quota(vr_perms.uid, vr_perms.gid, att); + + if ( quota_authorization(&tmpl, Quotas::VIRTUALROUTER, att_quota) == false ) + { + return; + } + + // ------------------------------------------------------------------------- + // Attach NIC to the Virtual Router + // ------------------------------------------------------------------------- + vr = vrpool->get(vrid, true); + + if (vr == 0) + { + quota_rollback(&tmpl, Quotas::VIRTUALROUTER, att_quota); + + att.resp_id = vrid; + failure_response(NO_EXISTS, att); + return; + } + + nic = vr->attach_nic(&tmpl, att.resp_msg); + + set vms = vr->get_vms(); + + vrpool->update(vr); + + vr->unlock(); + + if (nic == 0) + { + quota_rollback(&tmpl, Quotas::VIRTUALROUTER, att_quota); + + failure_response(ACTION, att); + return; + } + + // ------------------------------------------------------------------------- + // Attach NIC to each VM + // ------------------------------------------------------------------------- + for (set::iterator vmid = vms.begin(); vmid != vms.end(); vmid++) + { + VirtualMachineTemplate tmpl; + + tmpl.set(nic->clone()); + + ErrorCode ec = VirtualMachineAttachNic::attach(*vmid, tmpl, att); + + if (ec != SUCCESS) //TODO: manage individual attach error, do rollback? + { + failure_response(ACTION, att); + + delete nic; + return; + } + } + + delete nic; + + success_response(vrid, att); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +void VirtualRouterDetachNic::request_execute( + xmlrpc_c::paramList const& paramList, RequestAttributes& att) +{ + VirtualRouterPool* vrpool = static_cast(pool); + VirtualRouter * vr; + PoolObjectAuth vr_perms; + + int rc; + + int vrid = xmlrpc_c::value_int(paramList.getInt(1)); + int nic_id = xmlrpc_c::value_int(paramList.getInt(2)); + + // ------------------------------------------------------------------------- + // Authorize the operation + // ------------------------------------------------------------------------- + vr = vrpool->get(vrid, true); + + if (vr == 0) + { + att.resp_id = vrid; + failure_response(NO_EXISTS, att); + return; + } + + vr->get_permissions(vr_perms); + + vr->unlock(); + + if ( att.uid != 0 ) + { + AuthRequest ar(att.uid, att.group_ids); + + ar.add_auth(AuthRequest::MANAGE, vr_perms); // MANAGE VROUTER + + if (UserPool::authorize(ar) == -1) + { + att.resp_msg = ar.message; + failure_response(AUTHORIZATION, att); + return; + } + } + + // ------------------------------------------------------------------------- + // Detach the NIC from the Virtual Router + // ------------------------------------------------------------------------- + vr = vrpool->get(vrid, true); + + if (vr == 0) + { + att.resp_id = vrid; + failure_response(NO_EXISTS, att); + return; + } + + rc = vr->detach_nic(nic_id); + + set vms = vr->get_vms(); + + vrpool->update(vr); + + vr->unlock(); + + if (rc != 0) + { + ostringstream oss; + + oss << "NIC with NIC_ID " << nic_id << " does not exist."; + + att.resp_msg = oss.str(); + failure_response(Request::ACTION, att); + + return; + } + + // ------------------------------------------------------------------------- + // Detach NIC from each VM + // ------------------------------------------------------------------------- + for (set::iterator vmid = vms.begin(); vmid != vms.end(); vmid++) + { + ErrorCode ec = VirtualMachineDetachNic::detach(*vmid, nic_id, att); + + if (ec != SUCCESS) //TODO: manage individual attach error, do rollback? + { + failure_response(Request::ACTION, att); + return; + } + } + + success_response(vrid, att); +} + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + diff --git a/src/rm/SConstruct b/src/rm/SConstruct index 09e3d43eea..5b1f32c3a2 100644 --- a/src/rm/SConstruct +++ b/src/rm/SConstruct @@ -47,6 +47,8 @@ source_files=[ 'RequestManagerVdc.cc', 'RequestManagerDatastore.cc', 'RequestManagerLock.cc', + 'RequestManagerMarketPlaceApp.cc', + 'RequestManagerVirtualRouter.cc' ] # Build library diff --git a/src/scheduler/include/HostXML.h b/src/scheduler/include/HostXML.h index f46acff4af..8a9ef3b2f3 100644 --- a/src/scheduler/include/HostXML.h +++ b/src/scheduler/include/HostXML.h @@ -55,7 +55,7 @@ public: * @param error error message * @return true if the share can host the VM */ - bool test_capacity(long long cpu, long long mem, vector &pci, + bool test_capacity(long long cpu, long long mem, vector &pci, string & error); /** @@ -65,7 +65,7 @@ public: * @param pci devices needed by the VM * @return true if the share can host the VM */ - bool test_capacity(long long cpu,long long mem,vector &p) + bool test_capacity(long long cpu,long long mem,vector &p) { string tmp_st; return test_capacity(cpu, mem, p, tmp_st); @@ -79,7 +79,7 @@ public: * @return 0 on success */ void add_capacity(int vmid, long long cpu, long long mem, - vector &p) + vector &p) { cpu_usage += cpu; mem_usage += mem; diff --git a/src/scheduler/include/VirtualMachineXML.h b/src/scheduler/include/VirtualMachineXML.h index bb68bb84c7..c46d06c96d 100644 --- a/src/scheduler/include/VirtualMachineXML.h +++ b/src/scheduler/include/VirtualMachineXML.h @@ -117,7 +117,7 @@ public: } void get_requirements (int& cpu, int& memory, long long& disk, - vector &pci); + vector &pci); map get_storage_usage(); diff --git a/src/scheduler/src/pool/DatastoreXML.cc b/src/scheduler/src/pool/DatastoreXML.cc index c01c16bed0..f39293c83b 100644 --- a/src/scheduler/src/pool/DatastoreXML.cc +++ b/src/scheduler/src/pool/DatastoreXML.cc @@ -53,16 +53,16 @@ void DatastoreXML::init_attributes() xpath(other_m, "/DATASTORE/PERMISSIONS/OTHER_M", 0); xpath(other_a, "/DATASTORE/PERMISSIONS/OTHER_A", 0); - xpath(free_mb, "/DATASTORE/FREE_MB", 0); + xpath(free_mb, "/DATASTORE/FREE_MB", 0); long long total_mb, used_mb, limit_mb; - xpath(total_mb, "/DATASTORE/TOTAL_MB", 0); - xpath(used_mb, "/DATASTORE/USED_MB", 0); + xpath(total_mb, "/DATASTORE/TOTAL_MB", 0); + xpath(used_mb, "/DATASTORE/USED_MB", 0); monitored = (free_mb != 0 || total_mb != 0 || used_mb != 0); - int rc = xpath(limit_mb, "/DATASTORE/TEMPLATE/LIMIT_MB", 0); + int rc = xpath(limit_mb, "/DATASTORE/TEMPLATE/LIMIT_MB", 0); if (rc == 0) { diff --git a/src/scheduler/src/pool/HostXML.cc b/src/scheduler/src/pool/HostXML.cc index 7130ad7c41..da5ea49ac8 100644 --- a/src/scheduler/src/pool/HostXML.cc +++ b/src/scheduler/src/pool/HostXML.cc @@ -40,12 +40,12 @@ void HostXML::init_attributes() { xpath(oid, "/HOST/ID", -1); xpath(cluster_id, "/HOST/CLUSTER_ID", -1); - xpath(mem_usage, "/HOST/HOST_SHARE/MEM_USAGE", 0); - xpath(cpu_usage, "/HOST/HOST_SHARE/CPU_USAGE", 0); - xpath(max_mem, "/HOST/HOST_SHARE/MAX_MEM", 0); - xpath(max_cpu, "/HOST/HOST_SHARE/MAX_CPU", 0); - xpath(free_disk, "/HOST/HOST_SHARE/FREE_DISK", 0); - xpath(running_vms, "/HOST/HOST_SHARE/RUNNING_VMS", 0); + xpath(mem_usage, "/HOST/HOST_SHARE/MEM_USAGE", 0); + xpath(cpu_usage, "/HOST/HOST_SHARE/CPU_USAGE", 0); + xpath(max_mem, "/HOST/HOST_SHARE/MAX_MEM", 0); + xpath(max_cpu, "/HOST/HOST_SHARE/MAX_CPU", 0); + xpath(free_disk, "/HOST/HOST_SHARE/FREE_DISK", 0); + xpath(running_vms, "/HOST/HOST_SHARE/RUNNING_VMS", 0); string public_cloud_st; @@ -133,7 +133,7 @@ int HostXML::search(const char *name, int& value) /* -------------------------------------------------------------------------- */ bool HostXML::test_capacity(long long cpu, long long mem, - vector& p, string & error) + vector& p, string & error) { bool pci_fits = pci.test(p); bool fits = ((max_cpu - cpu_usage ) >= cpu) && diff --git a/src/scheduler/src/pool/VirtualMachinePoolXML.cc b/src/scheduler/src/pool/VirtualMachinePoolXML.cc index 86eb70718e..8b9c4f10c9 100644 --- a/src/scheduler/src/pool/VirtualMachinePoolXML.cc +++ b/src/scheduler/src/pool/VirtualMachinePoolXML.cc @@ -48,7 +48,7 @@ int VirtualMachinePoolXML::set_up() { int cpu, mem; long long disk; - vector pci; + vector pci; string action = "DEPLOY"; diff --git a/src/scheduler/src/pool/VirtualMachineXML.cc b/src/scheduler/src/pool/VirtualMachineXML.cc index efeb4247c7..4f0f84f4da 100644 --- a/src/scheduler/src/pool/VirtualMachineXML.cc +++ b/src/scheduler/src/pool/VirtualMachineXML.cc @@ -36,7 +36,7 @@ void VirtualMachineXML::init_attributes() xpath(gid, "/VM/GID", -1); xpath(memory, "/VM/TEMPLATE/MEMORY", 0); - xpath(cpu, "/VM/TEMPLATE/CPU", 0); + xpath(cpu, "/VM/TEMPLATE/CPU", 0); // ------------------------ RANK & DS_RANK --------------------------------- @@ -142,17 +142,14 @@ void VirtualMachineXML::init_attributes() system_ds_usage = 0; } - vector attrs; - user_template->get("PUBLIC_CLOUD", attrs); + vector attrs; - public_cloud = (attrs.size() > 0); + public_cloud = (user_template->get("PUBLIC_CLOUD", attrs) > 0); if (public_cloud == false) { attrs.clear(); - user_template->get("EC2", attrs); - - public_cloud = (attrs.size() > 0); + public_cloud = (user_template->get("EC2", attrs) > 0); } only_public_cloud = false; @@ -203,7 +200,7 @@ ostream& operator<<(ostream& os, VirtualMachineXML& vm) /* -------------------------------------------------------------------------- */ void VirtualMachineXML::get_requirements (int& cpu, int& memory, - long long& disk, vector &pci) + long long& disk, vector &pci) { pci.clear(); diff --git a/src/scheduler/src/sched/Scheduler.cc b/src/scheduler/src/sched/Scheduler.cc index e2f48748e5..682191ae87 100644 --- a/src/scheduler/src/sched/Scheduler.cc +++ b/src/scheduler/src/sched/Scheduler.cc @@ -165,21 +165,16 @@ void Scheduler::start() try { - vector logs; - int rc; - NebulaLog::LogType log_system = NebulaLog::UNDEFINED; Log::MessageType clevel = Log::ERROR;; - rc = conf.get("LOG", logs); + const VectorAttribute * log = conf.get("LOG"); - if ( rc != 0 ) + if ( log != 0 ) { string value; int ilevel; - const VectorAttribute * log = static_cast - (logs[0]); value = log->vector_value("SYSTEM"); log_system = NebulaLog::str_to_type(value); @@ -297,15 +292,13 @@ void Scheduler::start() NebulaLog::log("SCHED", Log::INFO, "oned successfully contacted."); - vector fed; - zone_id = 0; - if (oned_conf.get("FEDERATION", fed) > 0) - { - const VectorAttribute * va=static_cast(fed[0]); + const VectorAttribute * fed = oned_conf.get("FEDERATION"); - if (va->vector_value("ZONE_ID", zone_id) != 0) + if (fed != 0) + { + if (fed->vector_value("ZONE_ID", zone_id) != 0) { zone_id = 0; } @@ -524,8 +517,8 @@ int Scheduler::set_up_pools() * @return true for a positive match */ 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) + 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 @@ -747,7 +740,7 @@ void Scheduler::match_schedule() int vm_memory; int vm_cpu; long long vm_disk; - vector vm_pci; + vector vm_pci; int n_resources; int n_matched; @@ -1055,7 +1048,7 @@ void Scheduler::dispatch() int cpu, mem; long long dsk; - vector pci; + vector pci; int hid, dsid, cid; bool test_cap_result; diff --git a/src/scheduler/src/sched/SchedulerTemplate.cc b/src/scheduler/src/sched/SchedulerTemplate.cc index cb9499b10b..5d8036796a 100644 --- a/src/scheduler/src/sched/SchedulerTemplate.cc +++ b/src/scheduler/src/sched/SchedulerTemplate.cc @@ -122,18 +122,13 @@ string SchedulerTemplate::get_policy() const istringstream iss; - vector vsched; - const VectorAttribute * sched; + const VectorAttribute * sched = get("DEFAULT_SCHED"); - get("DEFAULT_SCHED", vsched); - - if (vsched.empty()) + if (sched == 0) { return ""; } - sched = static_cast (vsched[0]); - iss.str(sched->vector_value("POLICY")); iss >> policy; @@ -176,18 +171,13 @@ string SchedulerTemplate::get_ds_policy() const istringstream iss; - vector vsched; - const VectorAttribute * sched; + const VectorAttribute * sched = get("DEFAULT_DS_SCHED"); - get("DEFAULT_DS_SCHED", vsched); - - if (vsched.empty()) + if (sched == 0) { return ""; } - sched = static_cast (vsched[0]); - iss.str(sched->vector_value("POLICY")); iss >> policy; diff --git a/src/secgroup/SecurityGroup.cc b/src/secgroup/SecurityGroup.cc index 7a41cbe628..c7738ba1ea 100644 --- a/src/secgroup/SecurityGroup.cc +++ b/src/secgroup/SecurityGroup.cc @@ -67,8 +67,8 @@ SecurityGroup::~SecurityGroup() int SecurityGroup::insert(SqlDB *db, string& error_str) { - vector::const_iterator it; - vector rules; + vector::const_iterator it; + vector rules; erase_template_attribute("NAME",name); @@ -81,14 +81,7 @@ int SecurityGroup::insert(SqlDB *db, string& error_str) for ( it = rules.begin(); it != rules.end(); it++ ) { - const VectorAttribute* rule = dynamic_cast(*it); - - if (rule == 0) - { - goto error_format; - } - - if (!isValidRule(rule, error_str)) + if (!isValidRule(*it, error_str)) { goto error_valid; } @@ -105,10 +98,6 @@ error_name: error_str = "No NAME in template for Security Group."; goto error_common; -error_format: - error_str = "RULE has to be defined as a vector attribute."; - goto error_common; - error_valid: error_db: error_common: @@ -288,22 +277,15 @@ int SecurityGroup::from_xml(const string& xml) void SecurityGroup::get_rules(vector& result) const { - vector::const_iterator it; - vector rules; + vector::const_iterator it; + vector rules; get_template_attribute("RULE", rules); for ( it = rules.begin(); it != rules.end(); it++ ) { - const VectorAttribute* rule = dynamic_cast(*it); - - if ( rule == 0 ) - { - continue; - } - VectorAttribute* new_rule = new VectorAttribute( - "SECURITY_GROUP_RULE", rule->value()); + "SECURITY_GROUP_RULE", (*it)->value()); new_rule->replace("SECURITY_GROUP_ID", this->get_oid()); new_rule->replace("SECURITY_GROUP_NAME", this->get_name()); @@ -430,22 +412,14 @@ bool SecurityGroup::isValidRule(const VectorAttribute * rule, string& error) con int SecurityGroup::post_update_template(string& error) { - vector::const_iterator it; - vector rules; + vector::const_iterator it; + vector rules; get_template_attribute("RULE", rules); for ( it = rules.begin(); it != rules.end(); it++ ) { - const VectorAttribute* rule = dynamic_cast(*it); - - if (rule == 0) - { - error = "RULE has to be defined as a vector attribute."; - return -1; - } - - if (!isValidRule(rule, error)) + if (!isValidRule(*it, error)) { return -1; } diff --git a/src/secgroup/SecurityGroupPool.cc b/src/secgroup/SecurityGroupPool.cc index 5b0b638549..15c15a0d76 100644 --- a/src/secgroup/SecurityGroupPool.cc +++ b/src/secgroup/SecurityGroupPool.cc @@ -133,11 +133,3 @@ error_name: /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ - -int SecurityGroupPool::update(SecurityGroup * securitygroup) -{ - return securitygroup->update(db); -} - -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ diff --git a/src/sql/SqliteDB.cc b/src/sql/SqliteDB.cc index 74b0356015..5cbbde3f36 100644 --- a/src/sql/SqliteDB.cc +++ b/src/sql/SqliteDB.cc @@ -41,7 +41,7 @@ extern "C" int sqlite_callback ( /* -------------------------------------------------------------------------- */ -SqliteDB::SqliteDB(string& db_name) +SqliteDB::SqliteDB(const string& db_name) { int rc; diff --git a/src/sunstone/etc/sunstone-views/admin.yaml b/src/sunstone/etc/sunstone-views/admin.yaml index f2bf7d9255..8d43b8ffe5 100644 --- a/src/sunstone/etc/sunstone-views/admin.yaml +++ b/src/sunstone/etc/sunstone-views/admin.yaml @@ -16,13 +16,16 @@ enabled_tabs: - clusters-tab - hosts-tab - datastores-tab + - vnets-topology-tab - vnets-tab - secgroups-tab + - vrouters-tab - zones-tab - - marketplace-tab - oneflow-dashboard - oneflow-services-tab - oneflow-templates-tab + - marketplaces-tab + - marketplaceapps-tab - settings-tab - support-tab autorefresh: true @@ -262,6 +265,7 @@ tabs: actions: Image.refresh: true Image.create_dialog: true + Image.export_dialog: true Image.rename: true Image.chown: true Image.chgrp: true @@ -386,12 +390,18 @@ tabs: Datastore.delete: true Datastore.enable: true Datastore.disable: true + vnets-topology-tab: + panel_tabs: + actions: + NetworkTopology.refresh: true + NetworkTopology.toggleVMs: true vnets-tab: panel_tabs: vnet_info_tab: true vnet_ar_list_tab: true vnet_leases_tab: true vnet_sg_list_tab: true + vnet_vr_list_tab: true table_columns: - 0 # Checkbox - 1 # ID @@ -440,21 +450,26 @@ tabs: SecurityGroup.chmod: true SecurityGroup.clone_dialog: true SecurityGroup.delete: true - marketplace-tab: + vrouters-tab: panel_tabs: - marketplace_info_tab: true + virtual_router_info_tab: true + virtual_router_vms_tab: true table_columns: - 0 # Checkbox - #- 1 # ID - - 2 # Name - - 3 # Publisher - - 4 # Hypervisor - - 5 # Arch - - 6 # Format - #- 7 # Tags + - 1 # ID + - 2 # Owner + - 3 # Group + - 4 # Name actions: - Marketplace.refresh: true - Marketplace.import: true + VirtualRouter.refresh: true + VirtualRouter.create_dialog: true + VirtualRouter.rename: true + VirtualRouter.chown: true + VirtualRouter.chgrp: true + VirtualRouter.chmod: true + VirtualRouter.delete: true + VirtualRouter.attachnic: true + VirtualRouter.detachnic: true oneflow-dashboard: panel_tabs: table_columns: @@ -569,3 +584,54 @@ tabs: user_showback_tab: true actions: User.quotas_dialog: false + marketplaces-tab: + panel_tabs: + marketplace_info_tab: true + marketplace_apps_tab: true + table_columns: + - 0 # Checkbox + - 1 # ID + - 2 # Owner + - 3 # Group + - 4 # Name + - 5 # Capacity + - 6 # Apps + - 7 # Driver + #- 8 # Labels + actions: + MarketPlace.refresh: true + MarketPlace.create_dialog: true + MarketPlace.update_dialog: true + MarketPlace.rename: true + MarketPlace.chown: true + MarketPlace.chgrp: true + MarketPlace.chmod: true + MarketPlace.delete: true + marketplaceapps-tab: + panel_tabs: + marketplaceapp_info_tab: true + marketplaceapp_templates_tab: true + table_columns: + - 0 # Checkbox + - 1 # ID + - 2 # Owner + - 3 # Group + - 4 # Name + #- 5 # Version + - 6 # Size + - 7 # State + #- 8 # Type + - 9 # Registration + - 10 # Marketplace + #- 11 # Labels + actions: + MarketPlaceApp.refresh: true + MarketPlaceApp.create_dialog: true + MarketPlaceApp.export_dialog: true + MarketPlaceApp.rename: true + MarketPlaceApp.chown: true + MarketPlaceApp.chgrp: true + MarketPlaceApp.chmod: true + MarketPlaceApp.enable: true + MarketPlaceApp.disable: true + MarketPlaceApp.delete: true diff --git a/src/sunstone/etc/sunstone-views/admin_vcenter.yaml b/src/sunstone/etc/sunstone-views/admin_vcenter.yaml index e32b1d0c08..424ed9d84f 100644 --- a/src/sunstone/etc/sunstone-views/admin_vcenter.yaml +++ b/src/sunstone/etc/sunstone-views/admin_vcenter.yaml @@ -18,8 +18,8 @@ enabled_tabs: #- datastores-tab - vnets-tab #- secgroups-tab + - vrouters-tab - zones-tab - #- marketplace-tab - oneflow-dashboard - oneflow-services-tab - oneflow-templates-tab @@ -392,6 +392,7 @@ tabs: vnet_ar_list_tab: true vnet_leases_tab: true vnet_sg_list_tab: true + vnet_vr_list_tab: true table_columns: - 0 # Checkbox - 1 # ID @@ -440,21 +441,26 @@ tabs: SecurityGroup.chmod: true SecurityGroup.clone_dialog: true SecurityGroup.delete: true - marketplace-tab: + vrouters-tab: panel_tabs: - marketplace_info_tab: true + virtual_router_info_tab: true + virtual_router_vms_tab: true table_columns: - 0 # Checkbox - #- 1 # ID - - 2 # Name - - 3 # Publisher - - 4 # Hypervisor - - 5 # Arch - - 6 # Format - #- 7 # Tags + - 1 # ID + - 2 # Owner + - 3 # Group + - 4 # Name actions: - Marketplace.refresh: true - Marketplace.import: true + VirtualRouter.refresh: true + VirtualRouter.create_dialog: true + VirtualRouter.rename: true + VirtualRouter.chown: true + VirtualRouter.chgrp: true + VirtualRouter.chmod: true + VirtualRouter.delete: true + VirtualRouter.attachnic: true + VirtualRouter.detachnic: true oneflow-dashboard: panel_tabs: table_columns: diff --git a/src/sunstone/etc/sunstone-views/user.yaml b/src/sunstone/etc/sunstone-views/user.yaml index 5e03ac338d..f3679cbc7e 100644 --- a/src/sunstone/etc/sunstone-views/user.yaml +++ b/src/sunstone/etc/sunstone-views/user.yaml @@ -18,11 +18,13 @@ enabled_tabs: - datastores-tab - vnets-tab - secgroups-tab + - vrouters-tab #- zones-tab - - marketplace-tab - oneflow-dashboard - oneflow-services-tab - oneflow-templates-tab + - marketplaces-tab + - marketplaceapps-tab - settings-tab #- support-tab autorefresh: true @@ -263,6 +265,7 @@ tabs: actions: Image.refresh: true Image.create_dialog: true + Image.export_dialog: true Image.rename: true Image.chown: false Image.chgrp: false @@ -393,6 +396,7 @@ tabs: vnet_ar_list_tab: true vnet_leases_tab: true vnet_sg_list_tab: true + vnet_vr_list_tab: true table_columns: - 0 # Checkbox - 1 # ID @@ -441,21 +445,26 @@ tabs: SecurityGroup.chmod: true SecurityGroup.clone_dialog: true SecurityGroup.delete: true - marketplace-tab: + vrouters-tab: panel_tabs: - marketplace_info_tab: true + virtual_router_info_tab: true + virtual_router_vms_tab: true table_columns: - 0 # Checkbox - #- 1 # ID - - 2 # Name - - 3 # Publisher - - 4 # Hypervisor - - 5 # Arch - - 6 # Format - #- 7 # Tags + - 1 # ID + - 2 # Owner + - 3 # Group + - 4 # Name actions: - Marketplace.refresh: true - Marketplace.import: true + VirtualRouter.refresh: true + VirtualRouter.create_dialog: true + VirtualRouter.rename: true + VirtualRouter.chown: true + VirtualRouter.chgrp: true + VirtualRouter.chmod: true + VirtualRouter.delete: true + VirtualRouter.attachnic: true + VirtualRouter.detachnic: true oneflow-dashboard: panel_tabs: table_columns: @@ -570,3 +579,54 @@ tabs: user_showback_tab: true actions: User.quotas_dialog: false + marketplaces-tab: + panel_tabs: + marketplace_info_tab: true + marketplaces_app_tab: true + table_columns: + - 0 # Checkbox + - 1 # ID + - 2 # Owner + - 3 # Group + - 4 # Name + - 5 # Capacity + - 6 # Apps + - 7 # Driver + #- 8 # Labels + actions: + MarketPlace.refresh: true + MarketPlace.create_dialog: true + MarketPlace.update_dialog: true + MarketPlace.rename: true + MarketPlace.chown: true + MarketPlace.chgrp: true + MarketPlace.chmod: true + MarketPlace.delete: true + marketplaceapps-tab: + panel_tabs: + marketplaceapp_info_tab: true + marketplaceapp_templates_tab: true + table_columns: + - 0 # Checkbox + - 1 # ID + - 2 # Owner + - 3 # Group + - 4 # Name + #- 5 # Version + - 6 # Size + - 7 # State + #- 8 # Type + - 9 # Registration + - 10 # Marketplace + #- 11 # Labels + actions: + MarketPlaceApp.refresh: true + MarketPlaceApp.create_dialog: true + MarketPlaceApp.export_dialog: true + MarketPlaceApp.rename: true + MarketPlaceApp.chown: true + MarketPlaceApp.chgrp: true + MarketPlaceApp.chmod: true + MarketPlaceApp.enable: true + MarketPlaceApp.disable: true + MarketPlaceApp.delete: true diff --git a/src/sunstone/models/OpenNebulaJSON.rb b/src/sunstone/models/OpenNebulaJSON.rb index 77891e302d..7fbd92247a 100644 --- a/src/sunstone/models/OpenNebulaJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON.rb @@ -32,6 +32,9 @@ require 'OpenNebulaJSON/DatastoreJSON' require 'OpenNebulaJSON/ZoneJSON' require 'OpenNebulaJSON/SecurityGroupJSON' require 'OpenNebulaJSON/VdcJSON' +require 'OpenNebulaJSON/VirtualRouterJSON' +require 'OpenNebulaJSON/MarketPlaceJSON' +require 'OpenNebulaJSON/MarketPlaceAppJSON' module OpenNebula class Error diff --git a/src/sunstone/models/OpenNebulaJSON/MarketPlaceAppJSON.rb b/src/sunstone/models/OpenNebulaJSON/MarketPlaceAppJSON.rb new file mode 100644 index 0000000000..054cfee17d --- /dev/null +++ b/src/sunstone/models/OpenNebulaJSON/MarketPlaceAppJSON.rb @@ -0,0 +1,90 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'OpenNebulaJSON/JSONUtils' + +module OpenNebulaJSON + class MarketPlaceAppJSON < OpenNebula::MarketPlaceApp + include JSONUtils + + def create(template_json) + mp_hash = parse_json(template_json, 'marketplaceapp') + if OpenNebula.is_error?(mp_hash) + return mp_hash + end + + mp_id = parse_json(template_json, 'mp_id') + if OpenNebula.is_error?(mp_id) + return mp_id + end + + if mp_hash['marketplaceapp_raw'] + template = mp_hash['marketplaceapp_raw'] + else + template = template_to_str(mp_hash) + end + + self.allocate(template, mp_id.to_i) + end + + def perform_action(template_json) + action_hash = parse_json(template_json, 'action') + if OpenNebula.is_error?(action_hash) + return action_hash + end + + rc = case action_hash['perform'] + when "update" then self.update(action_hash['params']) + when "export" then self.export(action_hash['params']) + when "chown" then self.chown(action_hash['params']) + when "chmod" then self.chmod_octet(action_hash['params']) + when "rename" then self.rename(action_hash['params']) + when "disable" then self.disable + when "enable" then self.enable + else + error_msg = "#{action_hash['perform']} action not " << + " available for this resource" + OpenNebula::Error.new(error_msg) + end + end + + def update(params=Hash.new) + if !params['append'].nil? + super(params['template_raw'], params['append']) + else + super(params['template_raw']) + end + end + + def export(params=Hash.new) + dsid = params['dsid'] ? params['dsid'].to_i : params['dsid'] + name = params['name'] + super({:dsid => dsid, :name => name}) + end + + def chown(params=Hash.new) + super(params['owner_id'].to_i,params['group_id'].to_i) + end + + def chmod_octet(params=Hash.new) + super(params['octet']) + end + + def rename(params=Hash.new) + super(params['name']) + end + end +end diff --git a/src/sunstone/models/OpenNebulaJSON/MarketPlaceJSON.rb b/src/sunstone/models/OpenNebulaJSON/MarketPlaceJSON.rb new file mode 100644 index 0000000000..0df5f3a44e --- /dev/null +++ b/src/sunstone/models/OpenNebulaJSON/MarketPlaceJSON.rb @@ -0,0 +1,72 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'OpenNebulaJSON/JSONUtils' + +module OpenNebulaJSON + class MarketPlaceJSON < OpenNebula::MarketPlace + include JSONUtils + + def create(template_json) + mp_hash = parse_json(template_json, 'marketplace') + if OpenNebula.is_error?(mp_hash) + return mp_hash + end + + if mp_hash['marketplace_raw'] + template = mp_hash['marketplace_raw'] + else + template = template_to_str(mp_hash) + end + + self.allocate(template) + end + + def perform_action(template_json) + action_hash = parse_json(template_json, 'action') + if OpenNebula.is_error?(action_hash) + return action_hash + end + + rc = case action_hash['perform'] + when "update" then self.update(action_hash['params']) + when "chown" then self.chown(action_hash['params']) + when "chmod" then self.chmod_octet(action_hash['params']) + when "rename" then self.rename(action_hash['params']) + else + error_msg = "#{action_hash['perform']} action not " << + " available for this resource" + OpenNebula::Error.new(error_msg) + end + end + + def update(params=Hash.new) + super(params['template_raw']) + end + + def chown(params=Hash.new) + super(params['owner_id'].to_i,params['group_id'].to_i) + end + + def chmod_octet(params=Hash.new) + super(params['octet']) + end + + def rename(params=Hash.new) + super(params['name']) + end + end +end diff --git a/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb b/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb index 6db16b3511..a89aa998e6 100644 --- a/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/PoolJSON.rb @@ -30,4 +30,7 @@ module OpenNebulaJSON class ZonePoolJSON < OpenNebula::ZonePool; include JSONUtils; end class SecurityGroupPoolJSON < OpenNebula::SecurityGroupPool; include JSONUtils; end class VdcPoolJSON < OpenNebula::VdcPool; include JSONUtils; end + class VirtualRouterPoolJSON < OpenNebula::VirtualRouterPool; include JSONUtils; end + class MarketPlacePoolJSON < OpenNebula::MarketPlacePool; include JSONUtils; end + class MarketPlaceAppPoolJSON < OpenNebula::MarketPlaceAppPool; include JSONUtils; end end diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualRouterJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualRouterJSON.rb new file mode 100644 index 0000000000..4056e7fd44 --- /dev/null +++ b/src/sunstone/models/OpenNebulaJSON/VirtualRouterJSON.rb @@ -0,0 +1,119 @@ +# -------------------------------------------------------------------------- # +# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # +# # +# 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. # +#--------------------------------------------------------------------------- # + +require 'OpenNebulaJSON/JSONUtils' + +module OpenNebulaJSON + class VirtualRouterJSON < OpenNebula::VirtualRouter + include JSONUtils + + def create(template_json) + vrouter_hash = parse_json(template_json, 'virtual_router') + + if OpenNebula.is_error?(vrouter_hash) + return vrouter_hash + end + + if vrouter_hash['virtual_router_raw'] + template = vrouter_hash['virtual_router_raw'] + else + template = template_to_str(vrouter_hash) + end + + self.allocate(template) + + end + + def perform_action(template_json) + action_hash = parse_json(template_json, 'action') + if OpenNebula.is_error?(action_hash) + return action_hash + end + + rc = case action_hash['perform'] + when "instantiate" then self.instantiate(action_hash['params']) + when "update" then self.update(action_hash['params']) + when "chown" then self.chown(action_hash['params']) + when "chmod" then self.chmod_json(action_hash['params']) + when "rename" then self.rename(action_hash['params']) + when "attachnic" then self.nic_attach(action_hash['params']) + when "detachnic" then self.nic_detach(action_hash['params']) + else + error_msg = "#{action_hash['perform']} action not " << + " available for this resource" + OpenNebula::Error.new(error_msg) + end + end + + def instantiate(params=Hash.new) + if params['template'] + select_capacity = self['TEMPLATE/SUNSTONE_CAPACITY_SELECT'] + if (select_capacity && select_capacity.upcase == "NO") + params['template'].delete("CPU") + params['template'].delete("MEMORY") + end + + select_network = self['TEMPLATE/SUNSTONE_NETWORK_SELECT'] + if (select_network && select_network.upcase == "NO") + params['template'].delete("NIC") + end + + template = template_to_str(params['template']) + super(params['n_vms'], params['template_id'], params['vm_name'], params['hold'], template) + else + super(params['n_vms'], params['template_id'], params['vm_name'], params['hold']) + end + end + + def update(params=Hash.new) + super(params['template_raw']) + end + + def chown(params=Hash.new) + super(params['owner_id'].to_i,params['group_id'].to_i) + end + + def chmod_json(params=Hash.new) + if params['octet'] + self.chmod_octet(params['octet']) + else + self.chmod((params['owner_u']||-1), + (params['owner_m']||-1), + (params['owner_a']||-1), + (params['group_u']||-1), + (params['group_m']||-1), + (params['group_a']||-1), + (params['other_u']||-1), + (params['other_m']||-1), + (params['other_a']||-1)) + end + end + + def rename(params=Hash.new) + super(params['name']) + end + + def nic_attach(params=Hash.new) + template_json = params['nic_template'] + template = template_to_str(template_json) + super(template) + end + + def nic_detach(params=Hash.new) + super(params['nic_id'].to_i) + end + end +end diff --git a/src/sunstone/models/SunstoneMarketplace.rb b/src/sunstone/models/SunstoneMarketplace.rb deleted file mode 100644 index 9ea1aa2a4f..0000000000 --- a/src/sunstone/models/SunstoneMarketplace.rb +++ /dev/null @@ -1,55 +0,0 @@ -# ---------------------------------------------------------------------------- # -# Copyright 2002-2015, OpenNebula Project, OpenNebula Systems # -# # -# 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. # -# ---------------------------------------------------------------------------- # - -require 'marketplace/marketplace_client' - -module SunstoneMarketplace - USER_AGENT = "Sunstone" - - def get_appliance_pool - client = Market::ApplianceClient.new( - @config[:marketplace_username], - @config[:marketplace_password], - @config[:marketplace_url], - USER_AGENT) - - response = client.list - - if CloudClient::is_error?(response) - error = Error.new(response.to_s) - return [response.code.to_i, error.to_json] - end - - [200, response.body] - end - - def get_appliance(app_id) - client = Market::ApplianceClient.new( - @config[:marketplace_username], - @config[:marketplace_password], - @config[:marketplace_url], - USER_AGENT) - - response = client.show(app_id) - - if CloudClient::is_error?(response) - error = Error.new(response.to_s) - return [response.code.to_i, error.to_json] - end - - [200, response.body] - end -end diff --git a/src/sunstone/models/SunstoneServer.rb b/src/sunstone/models/SunstoneServer.rb index a5a74a0fa4..8ec3c85a5b 100644 --- a/src/sunstone/models/SunstoneServer.rb +++ b/src/sunstone/models/SunstoneServer.rb @@ -23,8 +23,6 @@ require 'OpenNebulaVNC' require 'OpenNebulaJSON/JSONUtils' #include JSONUtils -require 'SunstoneMarketplace' - class SunstoneServer < CloudServer # FLAG that will filter the elements retrieved from the Pools POOL_FILTER = Pool::INFO_ALL @@ -32,8 +30,6 @@ class SunstoneServer < CloudServer # Secs to sleep between checks to see if image upload to repo is finished IMAGE_POLL_SLEEP_TIME = 5 - include SunstoneMarketplace - def initialize(client, config, logger) super(config, logger) @client = client @@ -52,19 +48,22 @@ class SunstoneServer < CloudServer end pool = case kind - when "group" then GroupPoolJSON.new(client) - when "cluster" then ClusterPoolJSON.new(client) - when "host" then HostPoolJSON.new(client) - when "image" then ImagePoolJSON.new(client, user_flag) - when "vmtemplate" then TemplatePoolJSON.new(client, user_flag) - when "vm" then VirtualMachinePoolJSON.new(client, user_flag) - when "vnet" then VirtualNetworkPoolJSON.new(client, user_flag) - when "user" then UserPoolJSON.new(client) - when "acl" then AclPoolJSON.new(client) - when "datastore" then DatastorePoolJSON.new(client) - when "zone" then ZonePoolJSON.new(client) + when "group" then GroupPoolJSON.new(client) + when "cluster" then ClusterPoolJSON.new(client) + when "host" then HostPoolJSON.new(client) + when "image" then ImagePoolJSON.new(client, user_flag) + when "vmtemplate" then TemplatePoolJSON.new(client, user_flag) + when "vm" then VirtualMachinePoolJSON.new(client, user_flag) + when "vnet" then VirtualNetworkPoolJSON.new(client, user_flag) + when "user" then UserPoolJSON.new(client) + when "acl" then AclPoolJSON.new(client) + when "datastore" then DatastorePoolJSON.new(client) + when "zone" then ZonePoolJSON.new(client) when "security_group" then SecurityGroupPoolJSON.new(client, user_flag) - when "vdc" then VdcPoolJSON.new(client) + when "vdc" then VdcPoolJSON.new(client) + when "vrouter" then VirtualRouterPoolJSON.new(client, user_flag) + when "marketplace" then MarketPlacePoolJSON.new(client) + when "marketplaceapp" then MarketPlaceAppPoolJSON.new(client, user_flag) else error = Error.new("Error: #{kind} resource not supported") return [404, error.to_json] @@ -109,19 +108,22 @@ class SunstoneServer < CloudServer ############################################################################ def create_resource(kind, template) resource = case kind - when "group" then GroupJSON.new(Group.build_xml, @client) - when "cluster" then ClusterJSON.new(Group.build_xml, @client) - when "host" then HostJSON.new(Host.build_xml, @client) - when "image" then ImageJSON.new(Image.build_xml, @client) - when "vmtemplate" then TemplateJSON.new(Template.build_xml, @client) - when "vm" then VirtualMachineJSON.new(VirtualMachine.build_xml,@client) - when "vnet" then VirtualNetworkJSON.new(VirtualNetwork.build_xml, @client) - when "user" then UserJSON.new(User.build_xml, @client) - when "acl" then AclJSON.new(Acl.build_xml, @client) - when "datastore" then DatastoreJSON.new(Acl.build_xml, @client) - when "zone" then ZoneJSON.new(Zone.build_xml, @client) + when "group" then GroupJSON.new(Group.build_xml, @client) + when "cluster" then ClusterJSON.new(Group.build_xml, @client) + when "host" then HostJSON.new(Host.build_xml, @client) + when "image" then ImageJSON.new(Image.build_xml, @client) + when "vmtemplate" then TemplateJSON.new(Template.build_xml, @client) + when "vm" then VirtualMachineJSON.new(VirtualMachine.build_xml,@client) + when "vnet" then VirtualNetworkJSON.new(VirtualNetwork.build_xml, @client) + when "user" then UserJSON.new(User.build_xml, @client) + when "acl" then AclJSON.new(Acl.build_xml, @client) + when "datastore" then DatastoreJSON.new(Datastore.build_xml, @client) + when "zone" then ZoneJSON.new(Zone.build_xml, @client) when "security_group" then SecurityGroupJSON.new(SecurityGroup.build_xml, @client) - when "vdc" then VdcJSON.new(Vdc.build_xml, @client) + when "vdc" then VdcJSON.new(Vdc.build_xml, @client) + when "vrouter" then VirtualRouterJSON.new(VirtualRouter.build_xml, @client) + when "marketplace" then MarketPlaceJSON.new(MarketPlace.build_xml, @client) + when "marketplaceapp" then MarketPlaceAppJSON.new(MarketPlaceApp.build_xml, @client) else error = Error.new("Error: #{kind} resource not supported") return [404, error.to_json] @@ -430,19 +432,22 @@ class SunstoneServer < CloudServer ############################################################################ def retrieve_resource(kind, id, extended=false) resource = case kind - when "group" then GroupJSON.new_with_id(id, @client) - when "cluster" then ClusterJSON.new_with_id(id, @client) - when "host" then HostJSON.new_with_id(id, @client) - when "image" then ImageJSON.new_with_id(id, @client) - when "vmtemplate" then TemplateJSON.new_with_id(id, @client) - when "vm" then VirtualMachineJSON.new_with_id(id, @client) - when "vnet" then VirtualNetworkJSON.new_with_id(id, @client) - when "user" then UserJSON.new_with_id(id, @client) - when "acl" then AclJSON.new_with_id(id, @client) - when "datastore" then DatastoreJSON.new_with_id(id, @client) - when "zone" then ZoneJSON.new_with_id(id, @client) + when "group" then GroupJSON.new_with_id(id, @client) + when "cluster" then ClusterJSON.new_with_id(id, @client) + when "host" then HostJSON.new_with_id(id, @client) + when "image" then ImageJSON.new_with_id(id, @client) + when "vmtemplate" then TemplateJSON.new_with_id(id, @client) + when "vm" then VirtualMachineJSON.new_with_id(id, @client) + when "vnet" then VirtualNetworkJSON.new_with_id(id, @client) + when "user" then UserJSON.new_with_id(id, @client) + when "acl" then AclJSON.new_with_id(id, @client) + when "datastore" then DatastoreJSON.new_with_id(id, @client) + when "zone" then ZoneJSON.new_with_id(id, @client) when "security_group" then SecurityGroupJSON.new_with_id(id, @client) - when "vdc" then VdcJSON.new_with_id(id, @client) + when "vdc" then VdcJSON.new_with_id(id, @client) + when "vrouter" then VirtualRouterJSON.new_with_id(id, @client) + when "marketplace" then MarketPlaceJSON.new_with_id(id, @client) + when "marketplaceapp" then MarketPlaceAppJSON.new_with_id(id, @client) else error = Error.new("Error: #{kind} resource not supported") return error diff --git a/src/sunstone/public/app/main.js b/src/sunstone/public/app/main.js index 5126ed0099..e2a21a566f 100644 --- a/src/sunstone/public/app/main.js +++ b/src/sunstone/public/app/main.js @@ -109,7 +109,10 @@ require.config({ 'spice-sha1': '../bower_components/spice-html5/thirdparty/sha1', 'spice-ticket': '../bower_components/spice-html5/ticket', 'spice-resize': '../bower_components/spice-html5/resize', - 'spice-filexfer': '../bower_components/spice-html5/filexfer' + 'spice-filexfer': '../bower_components/spice-html5/filexfer', + + /* vis.js */ + 'vis': '../bower_components/vis/dist/vis.min' }, shim: { /* Tabs */ @@ -131,13 +134,16 @@ require.config({ 'tabs/clusters-tab', 'tabs/hosts-tab', 'tabs/datastores-tab', + 'tabs/vnets-topology-tab', 'tabs/vnets-tab', 'tabs/secgroups-tab', + 'tabs/vrouters-tab', 'tabs/zones-tab', - 'tabs/marketplace-tab', 'tabs/oneflow-dashboard', 'tabs/oneflow-services-tab', 'tabs/oneflow-templates-tab', + 'tabs/marketplaces-tab', + 'tabs/marketplaceapps-tab', 'tabs/settings-tab', 'tabs/support-tab' ] diff --git a/src/sunstone/public/app/opennebula.js b/src/sunstone/public/app/opennebula.js index f242276aa8..2720d119ee 100644 --- a/src/sunstone/public/app/opennebula.js +++ b/src/sunstone/public/app/opennebula.js @@ -28,7 +28,6 @@ define(function(require) { Group = require('./opennebula/group'), Host = require('./opennebula/host'), Image = require('./opennebula/image'), - Marketplace = require('./opennebula/marketplace'), Network = require('./opennebula/network'), Role = require('./opennebula/role'), securitygroup = require('./opennebula/securitygroup'), @@ -39,7 +38,10 @@ define(function(require) { User = require('./opennebula/user'), Vdc = require('./opennebula/vdc'), Vm = require('./opennebula/vm'), - Zone = require('./opennebula/zone') + Zone = require('./opennebula/zone'), + VirtualRouter = require('./opennebula/virtualrouter'); + MarketPlace = require('./opennebula/marketplace'); + MarketPlaceApp = require('./opennebula/marketplaceapp'); if (typeof(csrftoken) != "undefined") { $.ajaxPrefilter(function(options, originalOptions, jqXHR) { @@ -77,7 +79,6 @@ define(function(require) { 'Host': Host, 'Image': Image, 'File': Image, - 'Marketplace': Marketplace, 'Network': Network, 'Role': Role, 'SecurityGroup': securitygroup, @@ -88,8 +89,11 @@ define(function(require) { 'User': User, 'Vdc': Vdc, 'VM': Vm, - 'Zone': Zone - } + 'Zone': Zone, + 'VirtualRouter': VirtualRouter, + 'MarketPlace': MarketPlace, + 'MarketPlaceApp': MarketPlaceApp + }; return OpenNebula; }); diff --git a/src/sunstone/public/app/opennebula/marketplace.js b/src/sunstone/public/app/opennebula/marketplace.js index d35fdb0b0e..fb566b29b6 100644 --- a/src/sunstone/public/app/opennebula/marketplace.js +++ b/src/sunstone/public/app/opennebula/marketplace.js @@ -16,45 +16,53 @@ define(function(require) { var OpenNebulaAction = require('./action'); - var OpenNebulaError = require('./error'); - var OpenNebulaHelper = require('./helper'); - var Notifier = require('utils/notifier'); var Locale = require('utils/locale'); var RESOURCE = "MARKETPLACE"; - var Marketplace = { + var MarketPlace = { "resource": RESOURCE, - "show" : function(params) { - params.error = function() { - return Notifier.notifyError(Locale.tr("Cannot connect to OpenNebula Marketplace")); - }; - OpenNebulaAction.show(params, RESOURCE); + "create" : function(params) { + OpenNebulaAction.create(params, RESOURCE); + }, + "del" : function(params) { + OpenNebulaAction.del(params, RESOURCE); }, "list" : function(params) { - //Custom list request function, since the contents do not come - //in the same format as the rest of opennebula resources. - var callback = params.success; - var callback_error = params.error; - var timeout = params.timeout || false; - var request = OpenNebulaHelper.request('MARKETPLACE', 'list'); - - $.ajax({ - url: 'marketplace', - type: 'GET', - data: {timeout: timeout}, - dataType: "json", - success: function(response) { - $(".marketplace_error_message").hide(); - return callback ? callback(request, response) : null; - }, - error: function(res) { - $(".marketplace_error_message").show(); - return callback_error ? callback_error(request, OpenNebulaError(res)) : null; - } - }); + OpenNebulaAction.list(params, RESOURCE); + }, + "list_in_zone" : function(params) { + OpenNebulaAction.list_in_zone(params, RESOURCE); + }, + "show" : function(params) { + OpenNebulaAction.show(params, RESOURCE); + }, + "chown" : function(params) { + OpenNebulaAction.chown(params, RESOURCE); + }, + "chgrp" : function(params) { + OpenNebulaAction.chgrp(params, RESOURCE); + }, + "chmod" : function(params) { + var action_obj = params.data.extra_param; + OpenNebulaAction.simple_action(params, RESOURCE, "chmod", action_obj); + }, + "update" : function(params) { + 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); + }, + "getName": function(id){ + return OpenNebulaAction.getName(id, RESOURCE); } - }; + } - return Marketplace; -}); + return MarketPlace; +}) diff --git a/src/sunstone/public/app/opennebula/marketplaceapp.js b/src/sunstone/public/app/opennebula/marketplaceapp.js new file mode 100644 index 0000000000..1ddff61005 --- /dev/null +++ b/src/sunstone/public/app/opennebula/marketplaceapp.js @@ -0,0 +1,116 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var OpenNebulaAction = require('./action'); + var Locale = require('utils/locale'); + + var RESOURCE = "MARKETPLACEAPP"; + + var STATES_STR = [ + Locale.tr("INIT"), + Locale.tr("READY"), + Locale.tr("LOCKED"), + Locale.tr("ERROR"), + Locale.tr("DISABLED") + ]; + + var TYPES_STR = [ + Locale.tr("UNKNOWN"), + Locale.tr("IMAGE"), + Locale.tr("VMTEMPLATE"), + Locale.tr("SERVICE_TEMPLATE") + ]; + + var STATES = { + INIT : 0, + READY : 1, + LOCKED : 2, + ERROR : 3, + DISABLED : 4 + }; + + var TYPES = { + UNKNOWN : 0, + IMAGE : 1, + VMTEMPLATE : 2, + SERVICE_TEMPLATE : 3 + }; + + var MarketPlaceApp = { + "resource": RESOURCE, + "stateStr": function(stateId) { + return STATES_STR[stateId]; + }, + "STATES": STATES, + "typeStr": function(typeId) { + return TYPES_STR[typeId]; + }, + "TYPES": TYPES, + "create" : function(params) { + OpenNebulaAction.create(params, RESOURCE); + }, + "del" : function(params) { + OpenNebulaAction.del(params, RESOURCE); + }, + "list" : function(params) { + OpenNebulaAction.list(params, RESOURCE); + }, + "list_in_zone" : function(params) { + OpenNebulaAction.list_in_zone(params, RESOURCE); + }, + "show" : function(params) { + OpenNebulaAction.show(params, RESOURCE); + }, + "chown" : function(params) { + OpenNebulaAction.chown(params, RESOURCE); + }, + "chgrp" : function(params) { + OpenNebulaAction.chgrp(params, RESOURCE); + }, + "chmod" : function(params) { + var action_obj = params.data.extra_param; + OpenNebulaAction.simple_action(params, RESOURCE, "chmod", action_obj); + }, + "update" : function(params) { + 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); + }, + "export" : function(params) { + var action_obj = params.data.extra_param; + OpenNebulaAction.simple_action(params, RESOURCE, "export", action_obj); + }, + "enable": function(params) { + OpenNebulaAction.simple_action(params, RESOURCE, "enable"); + }, + "disable": function(params) { + OpenNebulaAction.simple_action(params, RESOURCE, "disable"); + }, + "getName": function(id){ + return OpenNebulaAction.getName(id, RESOURCE); + } + } + + return MarketPlaceApp; +}) diff --git a/src/sunstone/public/app/opennebula/virtualrouter.js b/src/sunstone/public/app/opennebula/virtualrouter.js new file mode 100644 index 0000000000..8c6d39e136 --- /dev/null +++ b/src/sunstone/public/app/opennebula/virtualrouter.js @@ -0,0 +1,73 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var OpenNebulaAction = require('./action'); + + var RESOURCE = "VROUTER"; + + var VirtualRouter = { + "resource" : RESOURCE, + + "create" : function(params) { + OpenNebulaAction.create(params, RESOURCE); + }, + "instantiate" : function(params) { + var action_obj = params.data.extra_param ? params.data.extra_param : {}; + OpenNebulaAction.simple_action(params, RESOURCE, "instantiate", action_obj); + }, + "del" : function(params) { + OpenNebulaAction.del(params, RESOURCE); + }, + "list" : function(params) { + OpenNebulaAction.list(params, RESOURCE); + }, + "show" : function(params) { + OpenNebulaAction.show(params, RESOURCE); + }, + "chown" : function(params) { + OpenNebulaAction.chown(params, RESOURCE); + }, + "chgrp" : function(params) { + OpenNebulaAction.chgrp(params, RESOURCE); + }, + "chmod" : function(params) { + var action_obj = params.data.extra_param; + OpenNebulaAction.simple_action(params, RESOURCE, "chmod", action_obj); + }, + "update": function(params) { + var action_obj = {"template_raw" : params.data.extra_param}; + 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); + }, + "attachnic" : function(params) { + var action_obj = {"nic_template": params.data.extra_param}; + OpenNebulaAction.simple_action(params, RESOURCE, "attachnic", action_obj); + }, + "detachnic" : function(params) { + var action_obj = {"nic_id": params.data.extra_param}; + OpenNebulaAction.simple_action(params, RESOURCE, "detachnic", action_obj); + }, + "getName": function(id){ + return OpenNebulaAction.getName(id, RESOURCE); + } + }; + + return VirtualRouter; +}); diff --git a/src/sunstone/public/app/opennebula/vm.js b/src/sunstone/public/app/opennebula/vm.js index 2a096f8fac..3f4f96c064 100644 --- a/src/sunstone/public/app/opennebula/vm.js +++ b/src/sunstone/public/app/opennebula/vm.js @@ -261,6 +261,15 @@ define(function(require) { 'SL_PRIMARYIPADDRESS' ]; + var NIC_IP_ATTRS = [ + "IP", + "IP6_GLOBAL", + "IP6_ULA", + "VROUTER_IP", + "VROUTER_IP6_GLOBAL", + "VROUTER_IP6_ULA" + ]; + var EXTERNAL_NETWORK_ATTRIBUTES = [ 'GUEST_IP', 'GUEST_IP_ADDRESSES', @@ -666,17 +675,11 @@ define(function(require) { } $.each(nic, function(index, value) { - if (value.IP) { - ips.push(value.IP); - } - - if (value.IP6_GLOBAL) { - ips.push(value.IP6_GLOBAL); - } - - if (value.IP6_ULA) { - ips.push(value.IP6_ULA); - } + $.each(NIC_IP_ATTRS, function(j, attr){ + if (value[attr]) { + ips.push(value[attr]); + } + }); }); } } diff --git a/src/sunstone/public/app/sunstone-config.js b/src/sunstone/public/app/sunstone-config.js index ebb8380a91..344ea28d7f 100644 --- a/src/sunstone/public/app/sunstone-config.js +++ b/src/sunstone/public/app/sunstone-config.js @@ -31,6 +31,7 @@ define(function(require) { var _imMadConf = {}; var _vmMadConf = {}; var _authMadConf = {}; + var _marketMadConf = {}; var Config = { 'isTabEnabled': function(tabName) { @@ -161,6 +162,7 @@ define(function(require) { 'imMadConf' : _imMadConf, 'vmMadConf' : _vmMadConf, 'authMadConf' : _authMadConf, + 'marketMadConf' : _marketMadConf, "initOnedConf" : function() { OpenNebulaSystem.onedconf({ data : {}, @@ -182,6 +184,10 @@ define(function(require) { $.extend(true, _dsMadConf, onedconf.DS_MAD_CONF); } + if (onedconf.MARKET_MAD_CONF != undefined){ + $.extend(true, _marketMadConf, onedconf.MARKET_MAD_CONF); + } + if (onedconf.IM_MAD != undefined){ $.extend(true, _imMadConf, onedconf.IM_MAD); } diff --git a/src/sunstone/public/app/tabs/acls-tab/datatable.js b/src/sunstone/public/app/tabs/acls-tab/datatable.js index 4d3b4dafc7..423eacbeb0 100644 --- a/src/sunstone/public/app/tabs/acls-tab/datatable.js +++ b/src/sunstone/public/app/tabs/acls-tab/datatable.js @@ -171,6 +171,9 @@ define(function(require) { case "VDC": resources_str+=Locale.tr("VDCs")+", "; break; + case "VROUTER": + resources_str+=Locale.tr("Virtual Routers")+", "; + break; } } //remove ", " from end diff --git a/src/sunstone/public/app/tabs/acls-tab/form-panels/create/wizard.hbs b/src/sunstone/public/app/tabs/acls-tab/form-panels/create/wizard.hbs index ae847c8fa6..5155069c60 100644 --- a/src/sunstone/public/app/tabs/acls-tab/form-panels/create/wizard.hbs +++ b/src/sunstone/public/app/tabs/acls-tab/form-panels/create/wizard.hbs @@ -116,6 +116,10 @@ +
+ + +
diff --git a/src/sunstone/public/app/tabs/groups-tab/form-panels/create.js b/src/sunstone/public/app/tabs/groups-tab/form-panels/create.js index 277421becb..1e676b02a7 100644 --- a/src/sunstone/public/app/tabs/groups-tab/form-panels/create.js +++ b/src/sunstone/public/app/tabs/groups-tab/form-panels/create.js @@ -171,6 +171,7 @@ define(function(require) { }); $("#group_res_net", context).prop("checked", false); + $("#group_res_vr", context).prop("checked", false); $(context).off("change", ".admin_view_input"); $(context).on("change", ".admin_view_input", function(){ diff --git a/src/sunstone/public/app/tabs/groups-tab/form-panels/create/wizard.hbs b/src/sunstone/public/app/tabs/groups-tab/form-panels/create/wizard.hbs index 02e83c4fdc..ad92dcad2d 100644 --- a/src/sunstone/public/app/tabs/groups-tab/form-panels/create/wizard.hbs +++ b/src/sunstone/public/app/tabs/groups-tab/form-panels/create/wizard.hbs @@ -144,6 +144,7 @@
+ @@ -153,6 +154,7 @@ + diff --git a/src/sunstone/public/app/tabs/images-tab/actions.js b/src/sunstone/public/app/tabs/images-tab/actions.js index bc7fe8f977..8ae81d3f23 100644 --- a/src/sunstone/public/app/tabs/images-tab/actions.js +++ b/src/sunstone/public/app/tabs/images-tab/actions.js @@ -24,8 +24,11 @@ define(function(require) { var RESOURCE = "Image"; var XML_ROOT = "IMAGE"; var TAB_ID = require('./tabId'); + var MARKETPLACEAPPS_TAB_ID = require('tabs/marketplaceapps-tab/tabId'); var CREATE_DIALOG_ID = require('./form-panels/create/formPanelId'); var CLONE_DIALOG_ID = require('./dialogs/clone/dialogId'); + var CREATE_APP_DIALOG_ID = require('tabs/marketplaceapps-tab/form-panels/create/formPanelId'); + var _commonActions = new CommonActions(OpenNebulaResource, RESOURCE, TAB_ID, XML_ROOT); @@ -50,6 +53,23 @@ define(function(require) { "Image.snapshot_flatten": _commonActions.singleAction("snapshot_flatten"), "Image.snapshot_revert": _commonActions.singleAction("snapshot_revert"), "Image.snapshot_delete": _commonActions.singleAction("snapshot_delete"), + "Image.export_dialog" : { + type: "custom", + call: function() { + Sunstone.showTab(MARKETPLACEAPPS_TAB_ID); + Sunstone.showFormPanel(MARKETPLACEAPPS_TAB_ID, CREATE_APP_DIALOG_ID, "export", + function(formPanelInstance, context) { + var selectedNodes = Sunstone.getDataTable(TAB_ID).elements(); + if (selectedNodes.length !== 1) { + Notifier.notifyMessage('Please select one (and just one) Image to export.'); + return false; + } + + var resourceId = '' + selectedNodes[0]; + formPanelInstance.setImageId(resourceId); + }); + } + }, "Image.clone_dialog" : { type: "custom", diff --git a/src/sunstone/public/app/tabs/images-tab/buttons.js b/src/sunstone/public/app/tabs/images-tab/buttons.js index 97b4cca001..68e02808c9 100644 --- a/src/sunstone/public/app/tabs/images-tab/buttons.js +++ b/src/sunstone/public/app/tabs/images-tab/buttons.js @@ -27,6 +27,10 @@ define(function(require) { type: "create_dialog", layout: "create" }, + "Image.export_dialog" : { + type: "action", + text: '' + }, "Image.chown" : { type: "confirm_with_select", text: Locale.tr("Change owner"), diff --git a/src/sunstone/public/app/tabs/marketplace-tab/actions.js b/src/sunstone/public/app/tabs/marketplace-tab/actions.js deleted file mode 100644 index f6f6c62583..0000000000 --- a/src/sunstone/public/app/tabs/marketplace-tab/actions.js +++ /dev/null @@ -1,82 +0,0 @@ -/* -------------------------------------------------------------------------- */ -/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ -/* */ -/* 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. */ -/* -------------------------------------------------------------------------- */ - -define(function(require) { - var Sunstone = require('sunstone'); - var Notifier = require('utils/notifier'); - var Locale = require('utils/locale'); - var DataTable = require('./datatable'); - var OpenNebulaResource = require('opennebula/marketplace'); - - var RESOURCE = "Marketplace"; - var TAB_ID = require('./tabId'); - var IMPORT_DIALOG_ID = require('./dialogs/import/dialogId'); - - var _actions = { - "Marketplace.list" : { - type: "list", - call: OpenNebulaResource.list, - callback: function(request, response) { - Sunstone.getDataTable(TAB_ID).updateView(request, response.appliances); - } - }, - - "Marketplace.refresh" : { - type: "custom", - call: function() { - var tab = $('#' + TAB_ID); - if (Sunstone.rightInfoVisible(tab)) { - Sunstone.runAction(RESOURCE+".show", Sunstone.rightInfoResourceId(tab)); - } else { - Sunstone.getDataTable(TAB_ID).waitingNodes(); - Sunstone.runAction(RESOURCE+".list", {force: true}); - } - }, - }, - - "Marketplace.import" : { - type: "multiple", - call: OpenNebulaResource.show, - callback: function(request, response) { - if (response['status'] && response['status'] != 'ready') { - Notifier.notifyError(Locale.tr("The appliance is not ready")); - return; - } - - Sunstone.getDialog(IMPORT_DIALOG_ID).setParams({element: response}); - Sunstone.getDialog(IMPORT_DIALOG_ID).reset(); - Sunstone.getDialog(IMPORT_DIALOG_ID).show(); - }, - elements: function() { - return Sunstone.getDataTable(TAB_ID).elements(); - }, - error: Notifier.onError - }, - - "Marketplace.show" : { - type: "single", - call: OpenNebulaResource.show, - callback: function(request, response) { - if (Sunstone.rightInfoVisible($('#'+TAB_ID))) { - Sunstone.insertPanels(TAB_ID, response); - } - }, - error: Notifier.onError - } - }; - - return _actions; -}); diff --git a/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import.js b/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import.js deleted file mode 100644 index af342220bd..0000000000 --- a/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import.js +++ /dev/null @@ -1,295 +0,0 @@ -/* -------------------------------------------------------------------------- */ -/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ -/* */ -/* 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. */ -/* -------------------------------------------------------------------------- */ - -define(function(require) { - /* - DEPENDENCIES - */ - - var BaseDialog = require('utils/dialogs/dialog'); - var TemplateHTML = require('hbs!./import/html'); - var ContentHTML = require('hbs!./import/content'); - var Sunstone = require('sunstone'); - var Notifier = require('utils/notifier'); - var Locale = require('utils/locale'); - var ResourceSelect = require('utils/resource-select'); - var OpenNebulaDatastore = require('opennebula/datastore'); - var OpenNebulaImage = require('opennebula/image'); - var OpenNebulaTemplate = require('opennebula/template'); - var TemplateUtils = require('utils/template-utils'); - - /* - CONSTANTS - */ - - var DIALOG_ID = require('./import/dialogId'); - var TAB_ID = require('../tabId'); - - /* - CONSTRUCTOR - */ - - function Dialog() { - this.dialogId = DIALOG_ID; - - BaseDialog.call(this); - } - - Dialog.DIALOG_ID = DIALOG_ID; - Dialog.prototype = Object.create(BaseDialog.prototype); - Dialog.prototype.constructor = Dialog; - Dialog.prototype.html = _html; - Dialog.prototype.onShow = _onShow; - Dialog.prototype.setup = _setup; - Dialog.prototype.setParams = _setParams; - Dialog.prototype.try_to_create_template = _try_to_create_template; - - return Dialog; - - /* - FUNCTION DEFINITIONS - */ - - function _html() { - return TemplateHTML({ - 'dialogId': this.dialogId - }); - } - - function _setup(context) { - var that = this; - - context.foundation('abide', 'reflow'); - $("#market_import_dialog_content", context).html( - ContentHTML({'element': this.element}) - ); - - ResourceSelect.insert({ - context: $('#market_img_datastore', context), - resourceName: 'Datastore', - filterKey: 'TYPE', - filterValue: '' + OpenNebulaDatastore.TYPES.IMAGE_DS - }); - - context.off('invalid.fndtn.abide', '#' + DIALOG_ID + 'Form'); - context.off('valid.fndtn.abide', '#' + DIALOG_ID + 'Form'); - - context.on('invalid.fndtn.abide', '#' + DIALOG_ID + 'Form', function(e) { - Notifier.notifyError(Locale.tr("One or more required fields are missing or malformed.")); - }).on('valid.fndtn.abide', '#' + DIALOG_ID + 'Form', function(e) { - that.number_of_files = that.element['files'].length; - that.template_created = false; - that.images_information = []; - - - $("input, button", context).attr("disabled", "disabled"); - $(".market_image_result:not(.success)", context).html( - ''+ - ''+ - ''+ - ''); - $(".market_template_result", context).html( - ''+ - ''+ - ''+ - ''); - - var template_context = $("#market_import_file_template", context); - - $.each(that.element['files'], function(index, value){ - var local_context = $("#market_import_file_"+index, context); - - if ($(".market_image_result:not(.success)", local_context).length > 0) { - img_obj = { - "image" : { - "NAME": $("input.name",local_context).val(), - "PATH": that.element['links']['download']['href']+'/'+index, - "TYPE": value['type'], - "MD5": value['md5'], - "SHA1": value['sha1'], - "DRIVER": value['driver'], - "DEV_PREFIX": value['dev_prefix'], - "FROM_APP": that.element['_id']["$oid"], - "FROM_APP_NAME": that.element['name'], - "FROM_APP_FILE": index - }, - "ds_id" : $("#market_img_datastore select", context).val() - }; - - OpenNebulaImage.create({ - timeout: true, - data: img_obj, - success: function (file_index, file_context){ - return function(request, response) { - $(".market_image_result", file_context).addClass("success").html( - ''+ - ''+ - ''+ - ''); - - $(".market_image_response", file_context).html( - '

'+ - Locale.tr("Image created successfully")+' ID:'+response.IMAGE.ID+ - '

'); - - that.images_information[file_index] = response; - - that.try_to_create_template(context); - }; - }(index, local_context), - error: function (request, error_json){ - $(".market_template_result", template_context).html(''); - - $(".market_image_result", local_context).html( - ''+ - ''+ - ''+ - ''); - - $(".market_image_response", local_context).html( - '

'+ - (error_json.error.message || Locale.tr("Cannot contact server: is it running and reachable?"))+ - '

'); - - $("input", template_context).removeAttr("disabled"); - $("input", local_context).removeAttr("disabled"); - $("button", context).removeAttr("disabled"); - } - }); - } - }); - - that.try_to_create_template(context); - - return false; - }); - - return false; - } - - function _onShow(context) { - - return false; - } - - /** - * @param {object} params - * - params.element : Marketplace appliance as returned by a .show call - */ - function _setParams(params) { - this.element = params.element; - } - - - function _try_to_create_template(context){ - var that = this; - - var template_context = $("#market_import_file_template", context); - - var images_created = $(".market_image_result.success", context).length; - - if ((images_created == this.number_of_files) && !that.template_created) { - that.template_created = true; - - if (that.element['opennebula_template'] && that.element['opennebula_template'] !== "CPU=1") { - var vm_template; - try { - vm_template = JSON.parse( TemplateUtils.htmlDecode(that.element['opennebula_template']) ); - } catch (error) { - $(".market_template_result", template_context).html( - ''+ - ''+ - ''+ - ''); - - $(".market_template_response", template_context).html( - '

'+ - (error.message || Locale.tr("Cannot contact server: is it running and reachable?"))+ - '

'); - - $("input", template_context).removeAttr("disabled"); - $("button", context).removeAttr("disabled"); - that.template_created = false; - return; - } - - if ($.isEmptyObject(vm_template.DISK)){ - vm_template.DISK = []; - } else if (!$.isArray(vm_template.DISK)){ - vm_template.DISK = [vm_template.DISK]; - } - - vm_template.NAME = $("input", template_context).val(); - if (!vm_template.CPU){ - vm_template.CPU = "1"; - } - if (!vm_template.MEMORY){ - vm_template.MEMORY = "1024"; - } - - $.each(that.images_information, function(image_index, image_info){ - if (!vm_template.DISK[image_index]) { - vm_template.DISK[image_index] = {}; - } - - vm_template.DISK[image_index].IMAGE = image_info.IMAGE.NAME; - vm_template.DISK[image_index].IMAGE_UNAME = image_info.IMAGE.UNAME; - }); - - vm_template.FROM_APP = that.element['_id']["$oid"]; - vm_template.FROM_APP_NAME = that.element['name']; - - OpenNebulaTemplate.create({ - timeout: true, - data: {vmtemplate: vm_template}, - success: function (request, response){ - $(".market_template_result", template_context).addClass("success").html( - ''+ - ''+ - ''+ - ''); - - $(".market_template_response", template_context).html( - '

'+ - Locale.tr("Template created successfully")+' ID:'+response.VMTEMPLATE.ID+ - '

'); - - $("button", context).hide(); - }, - error: function (request, error_json){ - $(".market_template_result", template_context).html( - ''+ - ''+ - ''+ - ''); - - $(".market_template_response", template_context).html( - '

'+ - (error_json.error.message || Locale.tr("Cannot contact server: is it running and reachable?"))+ - '

'); - - $("input", template_context).removeAttr("disabled"); - $("button", context).removeAttr("disabled"); - that.template_created = false; - } - }); - } else { - $("button", context).hide(); - } - } - } - -}); diff --git a/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import/content.hbs b/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import/content.hbs deleted file mode 100644 index 8f652a06b2..0000000000 --- a/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import/content.hbs +++ /dev/null @@ -1,81 +0,0 @@ -{{! -------------------------------------------------------------------------- }} -{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} -{{! }} -{{! 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. }} -{{! -------------------------------------------------------------------------- }} - -
-
-

{{tr "The following images will be created in OpenNebula."}} {{tr "If you want to edit parameters of the image you can do it later in the images tab"}}

-
-
-
-
-
- -
-
-
-
-
-
-
-{{#each element.files}} -
-
-
- - {{#if name}} - - {{else}} - - {{/if}} -
-
-
-
-
-
-
-{{/each}} -{{#if element.opennebula_template}} -
-
-
-

{{tr "The following template will be created in OpenNebula and the previous images will be referenced in the disks"}} {{tr "If you want to edit parameters of the template you can do it later in the templates tab"}}

-
-
-
-
-
- - {{#if NAME}} - - {{else}} - - {{/if}} -
-
-
-
-
-
-
-{{/if}} diff --git a/src/sunstone/public/app/tabs/marketplace-tab/panels/info/html.hbs b/src/sunstone/public/app/tabs/marketplace-tab/panels/info/html.hbs deleted file mode 100644 index 38a114c697..0000000000 --- a/src/sunstone/public/app/tabs/marketplace-tab/panels/info/html.hbs +++ /dev/null @@ -1,154 +0,0 @@ -{{! -------------------------------------------------------------------------- }} -{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} -{{! }} -{{! 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. }} -{{! -------------------------------------------------------------------------- }} - -
-
-
{{tr "VMs"}} {{tr "VNets"}} {{tr "Security Groups"}}{{tr "Virtual Routers"}} {{tr "Images"}} {{tr "Templates"}} {{tr "Documents"}}{{tr "Documents are a special tool used for general purposes, mainly by OneFlow. If you want to enable users of this group to use service composition via OneFlow, let it checked."}}
- - - - - - - - - - - - - - - - - - - - - - - - - {{#if element.status}} - - - - - {{/if}} - {{#if element.tags}} - - - - - {{/if}} - {{#if element.catalog}} - - - - - {{/if}} - - - - - - - - - {{#if element.files}} - - - - - {{/if}} - - - - - - - - - -
{{tr "Information"}}
{{tr "ID"}}{{element._id.$oid}}
{{tr "Name"}}{{htmlDecode element.name}}
{{tr "URL"}} - {{tr "link"}} -
{{tr "Publisher"}}{{htmlDecode element.publisher}}
{{tr "Downloads"}}{{htmlDecode element.downloads}}
{{tr "Status"}}{{htmlDecode element.status}}
{{tr "Tags"}}{{htmlDecode element.tags}}
{{tr "Catalog"}}{{htmlDecode element.catalog}}
{{tr "OS"}}{{htmlDecode element.os-id}} {{htmlDecode element.os-release}}
{{tr "Arch"}}{{htmlDecode element.os-arch}}
{{tr "Size"}}{{humanizeSize "B" element.files.[0].size}}
{{tr "Hypervisor"}}{{htmlDecode element.hypervisor}}
{{tr "Format"}}{{htmlDecode element.format}}
- -
- {{#if element.short_description}} - - - - - - - - - - - -
{{tr "Short Description"}}
- {{~htmlDecode element.short_description~}} -
- {{/if}} - - - - - - - - - - - -
{{tr "Description"}}
- {{~htmlDecode element.description~}} -
- - - - - - - - {{#each element.files}} - - - - - {{else}} - - - - {{/each}} - -
{{tr "Images"}}
{{htmlDecode name}}{{humanizeSize "B" size}}
{{tr "No Images defined"}}
- {{#if element.opennebula_template}} - - - - - - - - - - - -
{{tr "OpenNebula Template"}}
{{htmlDecode element.opennebula_template}}
- {{/if}} -
- diff --git a/src/sunstone/public/app/tabs/marketplace-tab.js b/src/sunstone/public/app/tabs/marketplaceapps-tab.js similarity index 70% rename from src/sunstone/public/app/tabs/marketplace-tab.js rename to src/sunstone/public/app/tabs/marketplaceapps-tab.js index dc7b69a1c8..1a3d89a8e3 100644 --- a/src/sunstone/public/app/tabs/marketplace-tab.js +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab.js @@ -16,40 +16,37 @@ define(function(require) { var Locale = require('utils/locale'); - var Buttons = require('./marketplace-tab/buttons'); - var Actions = require('./marketplace-tab/actions'); - var Table = require('./marketplace-tab/datatable'); + var Buttons = require('./marketplaceapps-tab/buttons'); + var Actions = require('./marketplaceapps-tab/actions'); + var Table = require('./marketplaceapps-tab/datatable'); - var TAB_ID = require('./marketplace-tab/tabId'); - var DATATABLE_ID = "dataTableMarketplace"; + var TAB_ID = require('./marketplaceapps-tab/tabId'); + var DATATABLE_ID = "dataTableMarketplaceApps"; var _dialogs = [ - require('./marketplace-tab/dialogs/import') ]; var _panels = [ - require('./marketplace-tab/panels/info') + require('./marketplaceapps-tab/panels/info'), + require('./marketplaceapps-tab/panels/templates') ]; var _panelsHooks = [ - require('./marketplace-tab/hooks/header') + require('../utils/hooks/header') ]; var _formPanels = [ + require('./marketplaceapps-tab/form-panels/create'), + require('./marketplaceapps-tab/form-panels/export') ]; var Tab = { tabId: TAB_ID, - title: ' ' + Locale.tr("Marketplace"), - listHeader: ' '+Locale.tr("OpenNebula Marketplace"), - infoHeader: ' '+Locale.tr("Appliance"), + title: ' ' + Locale.tr("Apps"), + listHeader: ' '+Locale.tr("Apps"), + infoHeader: ' '+Locale.tr("App"), subheader: '  ', - resource: 'Marketplace', - content: '', + resource: 'MarketPlaceApp', buttons: Buttons, actions: Actions, dataTable: new Table(DATATABLE_ID, {actions: true, info: true, oneSelection: true}), diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/actions.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/actions.js new file mode 100644 index 0000000000..c43ac57ce8 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/actions.js @@ -0,0 +1,75 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var Sunstone = require('sunstone'); + var Notifier = require('utils/notifier'); + var Locale = require('utils/locale'); + var CommonActions = require('utils/common-actions'); + var OpenNebulaResource = require('opennebula/marketplaceapp'); + + var RESOURCE = "MarketPlaceApp"; + var XML_ROOT = "MARKETPLACEAPP"; + var TAB_ID = require('./tabId'); + var CREATE_DIALOG_ID = require('./form-panels/create/formPanelId'); + var EXPORT_DIALOG_ID = require('./form-panels/export/formPanelId'); + + var _commonActions = new CommonActions(OpenNebulaResource, RESOURCE, TAB_ID, XML_ROOT); + + var _actions = { + "MarketPlaceApp.create" : _commonActions.create(CREATE_DIALOG_ID), + "MarketPlaceApp.create_dialog" : _commonActions.showCreate(CREATE_DIALOG_ID), + "MarketPlaceApp.export_dialog" : { + type: "custom", + call: function() { + Sunstone.showFormPanel(TAB_ID, EXPORT_DIALOG_ID, "export"); + } + }, + "MarketPlaceApp.export" : { + type: "multiple", + call: OpenNebulaResource.export, + callback: function(req) { + Sunstone.hideFormPanel(TAB_ID); + OpenNebulaAction.clear_cache("IMAGE"); + OpenNebulaAction.clear_cache("VMTEMPLATE"); + }, + elements: function() { + return Sunstone.getDataTable(TAB_ID).elements(); + }, + error: function(request, response){ + // without tab id param to work for both templates and vms tab + Sunstone.hideFormPanelLoading(); + Notifier.onError(request, response); + }, + notify: true + }, + "MarketPlaceApp.list" : _commonActions.list(), + "MarketPlaceApp.show" : _commonActions.show(), + "MarketPlaceApp.refresh" : _commonActions.refresh(), + "MarketPlaceApp.delete" : _commonActions.del(), + "MarketPlaceApp.chown": _commonActions.multipleAction('chown'), + "MarketPlaceApp.chgrp": _commonActions.multipleAction('chgrp'), + "MarketPlaceApp.chmod": _commonActions.singleAction('chmod'), + "MarketPlaceApp.enable": _commonActions.multipleAction('enable'), + "MarketPlaceApp.disable": _commonActions.multipleAction('disable'), + //"MarketPlaceApp.update" : _commonActions.updateTemplate(), + "MarketPlaceApp.update_template" : _commonActions.updateTemplate(), + "MarketPlaceApp.append_template" : _commonActions.appendTemplate(), + "MarketPlaceApp.rename": _commonActions.singleAction('rename') + } + + return _actions; +}); diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js new file mode 100644 index 0000000000..3958f60bf6 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js @@ -0,0 +1,66 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var Locale = require('utils/locale'); + + var MarketPlaceAppButtons = { + "MarketPlaceApp.refresh" : { + type: "action", + layout: "refresh", + alwaysActive: true + }, + "MarketPlaceApp.create_dialog" : { + type: "create_dialog", + layout: "create" + }, + "MarketPlaceApp.export_dialog" : { + type: "action", + text: '' + }, + "MarketPlaceApp.chown" : { + type: "confirm_with_select", + text: Locale.tr("Change owner"), + select: "User", + layout: "user_select", + tip: Locale.tr("Select the new owner") + ":" + }, + "MarketPlaceApp.chgrp" : { + type: "confirm_with_select", + text: Locale.tr("Change group"), + select: "Group", + layout: "user_select", + tip: Locale.tr("Select the new group") + ":" + }, + "MarketPlaceApp.enable" : { + type: "action", + layout: "more_select", + text: Locale.tr("Enable") + }, + "MarketPlaceApp.disable" : { + type: "action", + layout: "more_select", + text: Locale.tr("Disable") + }, + "MarketPlaceApp.delete" : { + type: "confirm", + text: Locale.tr("Delete"), + layout: "del" + } + }; + + return MarketPlaceAppButtons; +}) diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/datatable.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/datatable.js new file mode 100644 index 0000000000..6a08ea3052 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/datatable.js @@ -0,0 +1,146 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + var TabDataTable = require('utils/tab-datatable'); + var SunstoneConfig = require('sunstone-config'); + var Locale = require('utils/locale'); + var OpenNebulaMarketPlaceApp = require('opennebula/marketplaceapp'); + var OpenNebulaMarketPlace = require('opennebula/marketplace'); + var LabelsUtils = require('utils/labels/utils'); + var Humanize = require('utils/humanize'); + + /* + CONSTANTS + */ + + var RESOURCE = "MarketPlaceApp"; + var XML_ROOT = "MARKETPLACEAPP"; + var TAB_NAME = require('./tabId'); + var LABELS_COLUMN = 11; + var TEMPLATE_ATTR = 'TEMPLATE'; + + /* + CONSTRUCTOR + */ + + /* + @dataTableId + @param {String} dataTableId unique identifier + @param {Object} conf + conf = { + 'info': true, enable on click row will show the element + 'action': true, enable actions on row elements + 'select': true, enable selecting elements from the table + 'selectOptions': { + 'filter_fn': function(ds) { return ds.TYPE == 0; } + } + } + @returns {Table} A new table object + */ + function Table(dataTableId, conf) { + this.conf = conf || {}; + this.tabId = TAB_NAME; + this.dataTableId = dataTableId; + this.resource = RESOURCE; + this.xmlRoot = XML_ROOT; + this.labelsColumn = LABELS_COLUMN; + + this.dataTableOptions = { + "bAutoWidth": false, + "bSortClasses" : false, + "bDeferRender": true, + "aoColumnDefs": [ + {"bSortable": false, "aTargets": ["check"]}, + {"sWidth": "35px", "aTargets": [0]}, + {"sWidth": "250px", "aTargets": [5]}, + {"bVisible": true, "aTargets": SunstoneConfig.tabTableColumns(TAB_NAME)}, + {"bVisible": false, "aTargets": ['_all']} + ] + } + + this.columns = [ + Locale.tr("ID"), + Locale.tr("Owner"), + Locale.tr("Group"), + Locale.tr("Name"), + Locale.tr("Version"), + Locale.tr("Size"), + Locale.tr("State"), + Locale.tr("Type"), + Locale.tr("Registration Time"), + Locale.tr("Marketplace"), + Locale.tr("Labels") + ] + + this.selectOptions = { + "id_index": 1, + "name_index": 4, + "uname_index": 2, + "select_resource": Locale.tr("Please select an appliance from the list"), + "you_selected": Locale.tr("You selected the following appliance:"), + "select_resource_multiple": Locale.tr("Please select one or more appliances from the list"), + "you_selected_multiple": Locale.tr("You selected the following appliances:") + } + + TabDataTable.call(this); + }; + + Table.prototype = Object.create(TabDataTable.prototype); + Table.prototype.constructor = Table; + Table.prototype.elementArray = _elementArray; + + return Table; + + /* + FUNCTION DEFINITIONS + */ + + function _elementArray(element_json) { + var element = element_json[XML_ROOT]; + + return [ + '', + element.ID, + element.UNAME, + element.GNAME, + element.NAME, + element.VERSION, + Humanize.sizeFromMB(element.SIZE), + OpenNebulaMarketPlaceApp.stateStr(element.STATE), + OpenNebulaMarketPlaceApp.typeStr(element.TYPE), + Humanize.prettyTime(element.REGTIME), + element.MARKETPLACE, + (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||'') + ]; + } + + function _lengthOf(ids){ + var l = 0; + if ($.isArray(ids)) + l = ids.length; + else if (!$.isEmptyObject(ids)) + l = 1; + + return l; + } +}); diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create.js new file mode 100644 index 0000000000..4cfec71761 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create.js @@ -0,0 +1,185 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + var BaseFormPanel = require('utils/form-panels/form-panel'); + var Sunstone = require('sunstone'); + var Locale = require('utils/locale'); + var Notifier = require('utils/notifier'); + var Tips = require('utils/tips'); + var ImagesTable = require('tabs/images-tab/datatable'); + var MarketPlacesTable = require('tabs/marketplaces-tab/datatable'); + var Config = require('sunstone-config'); + var WizardFields = require('utils/wizard-fields'); + + /* + TEMPLATES + */ + + var TemplateWizardHTML = require('hbs!./create/wizard'); + var TemplateAdvancedHTML = require('hbs!./create/advanced'); + + /* + CONSTANTS + */ + + var FORM_PANEL_ID = require('./create/formPanelId'); + var TAB_ID = require('../tabId'); + + /* + CONSTRUCTOR + */ + + function FormPanel() { + this.formPanelId = FORM_PANEL_ID; + this.tabId = TAB_ID; + this.actions = { + 'create': { + 'title': Locale.tr("Create MarketPlace App"), + 'buttonText': Locale.tr("Create"), + 'resetButton': true + }, + 'export': { + 'title': Locale.tr("Create MarketPlace App from Image"), + 'buttonText': Locale.tr("Create"), + 'resetButton': true + } + }; + + this.imagesTable = new ImagesTable( + FORM_PANEL_ID + 'imagesTable', + {'select': true}); + + this.marketPlacesTable = new MarketPlacesTable( + FORM_PANEL_ID + 'marketPlacesTable', + {'select': true}); + + this.marketPlacesTableAdvanced = new MarketPlacesTable( + FORM_PANEL_ID + 'marketPlacesTableAdvanced', + {'select': true}); + + BaseFormPanel.call(this); + } + + FormPanel.FORM_PANEL_ID = FORM_PANEL_ID; + FormPanel.prototype = Object.create(BaseFormPanel.prototype); + FormPanel.prototype.constructor = FormPanel; + FormPanel.prototype.htmlWizard = _htmlWizard; + FormPanel.prototype.htmlAdvanced = _htmlAdvanced; + FormPanel.prototype.submitWizard = _submitWizard; + FormPanel.prototype.submitAdvanced = _submitAdvanced; + FormPanel.prototype.setImageId = _setImageId; + FormPanel.prototype.onShow = _onShow; + FormPanel.prototype.setup = _setup; + + return FormPanel; + + /* + FUNCTION DEFINITIONS + */ + + function _htmlWizard() { + return TemplateWizardHTML({ + 'formPanelId': this.formPanelId, + 'imagesTableHTML': this.imagesTable.dataTableHTML, + 'marketPlacesTableHTML': this.marketPlacesTable.dataTableHTML + }); + } + + function _htmlAdvanced() { + return TemplateAdvancedHTML({ + 'formPanelId': this.formPanelId, + 'marketPlacesTableAdvancedHTML': this.marketPlacesTableAdvanced.dataTableHTML + }); + } + + function _onShow(context) { + this.imagesTable.resetResourceTableSelect(); + this.marketPlacesTable.resetResourceTableSelect(); + this.marketPlacesTableAdvanced.resetResourceTableSelect(); + + $("#NAME", context).focus(); + + return false; + } + + function _setImageId(imageId) { + var selectedResources = { + ids : imageId + } + + this.imagesTable.selectResourceTableSelect(selectedResources); + } + + // Set up the create datastore context + function _setup(context) { + Tips.setup(context); + + this.imagesTable.initialize(); + this.marketPlacesTable.initialize(); + this.marketPlacesTableAdvanced.initialize(); + + this.imagesTable.idInput(). + attr('required', ''). + attr('wizard_field', 'ORIGIN_ID'); + + this.marketPlacesTable.idInput().attr('required', ''); + this.marketPlacesTableAdvanced.idInput().attr('required', ''); + } + + + function _submitWizard(context) { + var marketPlaceJSON = {}; + $.extend(marketPlaceJSON, WizardFields.retrieve(context)); + + var vmTemplate = $('#VMTEMPLATE', context).val(); + if (vmTemplate) { + marketPlaceJSON['VMTEMPLATE64'] = btoa(vmTemplate); + } + + var appTemplate = $('#APPTEMPLATE', context).val(); + if (appTemplate) { + marketPlaceJSON['APPTEMPLATE64'] = btoa(appTemplate); + } + + var marketPlaceAppObj = { + "marketplaceapp" : marketPlaceJSON, + "mp_id" : this.marketPlacesTable.idInput().val() + }; + + Sunstone.runAction("MarketPlaceApp.create", marketPlaceAppObj); + return false; + } + + function _submitAdvanced(context) { + var template = $('#template', context).val(); + var marketPlaceAppObj = { + "marketplaceapp" : { + "marketplaceapp_raw" : template + }, + "mp_id" : this.marketPlacesTableAdvanced.idInput().val() + }; + + Sunstone.runAction("MarketPlaceApp.create", marketPlaceAppObj); + + return false; + } +}); + diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create/advanced.hbs b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create/advanced.hbs new file mode 100644 index 0000000000..244d3f3136 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create/advanced.hbs @@ -0,0 +1,32 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! 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. }} +{{! -------------------------------------------------------------------------- }} + +
+
+ {{tr "Select the Marketplace where the App will be created"}} + {{{marketPlacesTableAdvancedHTML}}} +
+
+
+

{{tr "Write the MarketPlace Appliance template here"}}

+
+
+
+
+ +
+
+
\ No newline at end of file diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create/formPanelId.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create/formPanelId.js new file mode 100644 index 0000000000..feae10b60f --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create/formPanelId.js @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require){ + return 'createMarketPlaceAppForm'; +}) diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create/wizard.hbs b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create/wizard.hbs new file mode 100644 index 0000000000..191e3f123a --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/create/wizard.hbs @@ -0,0 +1,84 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! 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. }} +{{! -------------------------------------------------------------------------- }} +
+
+
+ + +
+ +
+
+
+ + +
+
+ + +
+
+
+
+
+ {{tr "Select the Image to be exported"}} + {{{imagesTableHTML}}} +
+
+ {{tr "Select the Marketplace where the App will be created"}} + {{{marketPlacesTableHTML}}} +
+
+
+ + +
+
+ + +
+
+
\ No newline at end of file diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/export.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/export.js new file mode 100644 index 0000000000..875b01da34 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/export.js @@ -0,0 +1,119 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + var BaseFormPanel = require('utils/form-panels/form-panel'); + var Sunstone = require('sunstone'); + var Locale = require('utils/locale'); + var Notifier = require('utils/notifier'); + var Tips = require('utils/tips'); + var DataStoresTable = require('tabs/datastores-tab/datatable'); + var DataStore = require('opennebula/datastore'); + var Config = require('sunstone-config'); + var WizardFields = require('utils/wizard-fields'); + + /* + TEMPLATES + */ + + var TemplateWizardHTML = require('hbs!./export/wizard'); + + /* + CONSTANTS + */ + + var FORM_PANEL_ID = require('./export/formPanelId'); + var TAB_ID = require('../tabId'); + + /* + CONSTRUCTOR + */ + + function FormPanel() { + this.formPanelId = FORM_PANEL_ID; + this.tabId = TAB_ID; + this.actions = { + 'export': { + 'title': Locale.tr("Export App To OpenNebula"), + 'buttonText': Locale.tr("Export"), + 'resetButton': true + } + }; + + this.datastoresTable = new DataStoresTable( + FORM_PANEL_ID + 'datastoresTable', { + 'select': true, + 'selectOptions': { + 'filter_fn': function(ds) { return ds.TYPE == DataStore.TYPES.IMAGE_DS; } // Show system DS only + } + }); + + BaseFormPanel.call(this); + } + + FormPanel.FORM_PANEL_ID = FORM_PANEL_ID; + FormPanel.prototype = Object.create(BaseFormPanel.prototype); + FormPanel.prototype.constructor = FormPanel; + FormPanel.prototype.htmlWizard = _htmlWizard; + FormPanel.prototype.submitWizard = _submitWizard; + FormPanel.prototype.onShow = _onShow; + FormPanel.prototype.setup = _setup; + + return FormPanel; + + /* + FUNCTION DEFINITIONS + */ + + function _htmlWizard() { + return TemplateWizardHTML({ + 'formPanelId': this.formPanelId, + 'datastoresTableHTML': this.datastoresTable.dataTableHTML + }); + } + + function _onShow(context) { + this.datastoresTable.resetResourceTableSelect(); + + $("#NAME", context).focus(); + + return false; + } + + // Set up the create datastore context + function _setup(context) { + Tips.setup(context); + + this.datastoresTable.initialize(); + this.datastoresTable.idInput().attr('required', ''); + } + + + function _submitWizard(context) { + var marketPlaceAppObj = { + "name" : $("#NAME", context).val(), + "dsid" : this.datastoresTable.idInput().val() + }; + + Sunstone.runAction("MarketPlaceApp.export", Sunstone.getDataTable(TAB_ID).elements(), marketPlaceAppObj); + return false; + } +}); + diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/export/formPanelId.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/export/formPanelId.js new file mode 100644 index 0000000000..5a8f5cb6b1 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/export/formPanelId.js @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require){ + return 'exportMarketPlaceAppForm'; +}) diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/export/wizard.hbs b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/export/wizard.hbs new file mode 100644 index 0000000000..3e06f92298 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/form-panels/export/wizard.hbs @@ -0,0 +1,32 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! 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. }} +{{! -------------------------------------------------------------------------- }} +
+
+
+ + +
+
+
+ {{tr "Select the Datastore to store the resource"}} + {{{datastoresTableHTML}}} +
+
\ No newline at end of file diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/info.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/info.js new file mode 100644 index 0000000000..1e27a3cd73 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/info.js @@ -0,0 +1,118 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + var Locale = require('utils/locale'); + var Humanize = require('utils/humanize'); + var RenameTr = require('utils/panel/rename-tr'); + var TemplateTable = require('utils/panel/template-table'); + var PermissionsTable = require('utils/panel/permissions-table'); + var OpenNebulaMarketPlaceApp = require('opennebula/marketplaceapp'); + var Sunstone = require('sunstone'); + + /* + TEMPLATES + */ + + var TemplateInfo = require('hbs!./info/html'); + + /* + CONSTANTS + */ + + var TAB_ID = require('../tabId'); + var PANEL_ID = require('./info/panelId'); + var RESOURCE = "MarketPlaceApp" + var XML_ROOT = "MARKETPLACEAPP" + + /* + CONSTRUCTOR + */ + + function Panel(info) { + this.title = Locale.tr("Info"); + this.icon = "fa-info-circle"; + + this.element = info[XML_ROOT]; + + return this; + }; + + Panel.PANEL_ID = PANEL_ID; + Panel.prototype.html = _html; + Panel.prototype.setup = _setup; + + return Panel; + + /* + FUNCTION DEFINITIONS + */ + + + function _html() { + var strippedTemplate = $.extend({}, this.element.TEMPLATE); + delete strippedTemplate["VMTEMPLATE64"]; + delete strippedTemplate["APPTEMPLATE64"]; + + var templateTableHTML = TemplateTable.html( + strippedTemplate, RESOURCE, + Locale.tr("Attributes")); + + var renameTrHTML = RenameTr.html(TAB_ID, RESOURCE, this.element.NAME); + var permissionsTableHTML = PermissionsTable.html(TAB_ID, RESOURCE, this.element); + var prettyRegTime = Humanize.prettyTime(this.element.REGTIME); + var stateStr = OpenNebulaMarketPlaceApp.stateStr(this.element.STATE); + var typeStr = OpenNebulaMarketPlaceApp.typeStr(this.element.TYPE); + var sizeStr = Humanize.sizeFromMB(this.element.SIZE); + + + return TemplateInfo({ + 'element': this.element, + 'renameTrHTML': renameTrHTML, + 'templateTableHTML': templateTableHTML, + 'permissionsTableHTML': permissionsTableHTML, + 'prettyRegTime': prettyRegTime, + 'stateStr': stateStr, + 'typeStr': typeStr, + 'sizeStr': sizeStr + }); + } + + function _setup(context) { + var strippedTemplate = $.extend({}, this.element.TEMPLATE); + delete strippedTemplate["VMTEMPLATE64"]; + delete strippedTemplate["APPTEMPLATE64"]; + + var hiddenValues = {}; + + if (this.element.TEMPLATE.VMTEMPLATE64 !== undefined) { + hiddenValues.VMTEMPLATE64 = this.element.TEMPLATE.VMTEMPLATE64; + } + if (this.element.TEMPLATE.APPTEMPLATE64 !== undefined) { + hiddenValues.APPTEMPLATE64 = this.element.TEMPLATE.APPTEMPLATE64; + } + + TemplateTable.setup(strippedTemplate, RESOURCE, this.element.ID, context, hiddenValues); + + RenameTr.setup(TAB_ID, RESOURCE, this.element.ID, context); + PermissionsTable.setup(TAB_ID, RESOURCE, this.element, context); + return false; + } +}); diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/info/html.hbs b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/info/html.hbs new file mode 100644 index 0000000000..08a1ebac9b --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/info/html.hbs @@ -0,0 +1,76 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! 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. }} +{{! -------------------------------------------------------------------------- }} + +
+
+ + + + + + + + + + + + {{{renameTrHTML}}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{{tr "Information"}}
{{tr "ID"}}{{element.ID}}
{{tr "MarketPlace"}}{{element.MARKETPLACE}}
{{tr "Register time"}}{{prettyRegTime}}
{{tr "Type"}}{{typeStr}}
{{tr "Size"}}{{sizeStr}}
{{tr "State"}}{{stateStr}}
{{tr "Format"}}{{element.FORMAT}}
{{tr "Version"}}{{element.VERSION}}
+
+
+ {{{permissionsTableHTML}}} +
+
+
+
+ {{{templateTableHTML}}} +
+
diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/info/panelId.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/info/panelId.js new file mode 100644 index 0000000000..938ea72f7b --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/info/panelId.js @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require){ + return 'marketplaceapp_info_tab'; +}); diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/templates.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/templates.js new file mode 100644 index 0000000000..2d5d793660 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/templates.js @@ -0,0 +1,121 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + var Locale = require('utils/locale'); + var Humanize = require('utils/humanize'); + var RenameTr = require('utils/panel/rename-tr'); + var TemplateTable = require('utils/panel/template-table'); + var PermissionsTable = require('utils/panel/permissions-table'); + var OpenNebulaMarketPlaceApp = require('opennebula/marketplaceapp'); + var Sunstone = require('sunstone'); + + /* + TEMPLATES + */ + + var TemplateInfo = require('hbs!./templates/html'); + + /* + CONSTANTS + */ + + var TAB_ID = require('../tabId'); + var PANEL_ID = require('./templates/panelId'); + var RESOURCE = "MarketPlaceApp" + var XML_ROOT = "MARKETPLACEAPP" + + /* + CONSTRUCTOR + */ + + function Panel(info) { + this.title = Locale.tr("Templates"); + this.icon = "fa-file-o"; + + this.element = info[XML_ROOT]; + + return this; + }; + + Panel.PANEL_ID = PANEL_ID; + Panel.prototype.html = _html; + Panel.prototype.setup = _setup; + + return Panel; + + /* + FUNCTION DEFINITIONS + */ + + + function _html() { + var vmTemplate = atob(this.element.TEMPLATE.VMTEMPLATE64 || ''); + var appTemplate = atob(this.element.TEMPLATE.APPTEMPLATE64 || ''); + + return TemplateInfo({ + 'element': this.element, + 'vmTemplate': vmTemplate, + 'appTemplate': appTemplate + }); + } + + function _setup(context) { + var that = this; + + context.off("click", ".vmTemplate_edit"); + context.on("click", ".vmTemplate_edit", function() { + $("#vmTemplate_text", context).hide(); + $("#vmTemplate_textarea", context).show().focus(); + }); + + context.off("change", "#vmTemplate_textarea"); + context.on("change", "#vmTemplate_textarea", function() { + var templateStr = 'VMTEMPLATE64 = "' + btoa($(this).val()) + '"'; + Sunstone.runAction("MarketPlaceApp.append_template", that.element.ID, templateStr); + }); + + context.off("focusout", "#vmTemplate_textarea"); + context.on("focusout", "#vmTemplate_textarea", function() { + $("#vmTemplate_text", context).show(); + $("#vmTemplate_textarea", context).hide(); + }); + + context.off("click", ".appTemplate_edit"); + context.on("click", ".appTemplate_edit", function() { + $("#appTemplate_text", context).hide(); + $("#appTemplate_textarea", context).show().focus(); + }); + + context.off("change", "#appTemplate_textarea"); + context.on("change", "#appTemplate_textarea", function() { + var templateStr = 'APPTEMPLATE64 = "' + btoa($(this).val()) + '"'; + Sunstone.runAction("MarketPlaceApp.append_template", that.element.ID, templateStr); + }); + + context.off("focusout", "#appTemplate_textarea"); + context.on("focusout", "#appTemplate_textarea", function() { + $("#appTemplate_text", context).show(); + $("#appTemplate_textarea", context).hide(); + }); + + return false; + } +}); diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/templates/html.hbs b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/templates/html.hbs new file mode 100644 index 0000000000..831b608790 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/templates/html.hbs @@ -0,0 +1,62 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! 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. }} +{{! -------------------------------------------------------------------------- }} + +
+
+ + + + + + + +
{{tr "App Template"}} + +
+ + {{#if appTemplate}} +
+        {{~htmlDecode appTemplate~}}
+        
+ {{else}} +

+ {{~tr "You can provide a template for the resource that will be created in OpenNebula"~}} +

+ {{/if}} +
+
+ + + + + + + +
{{tr "VM Template"}} + +
+ + {{#if vmTemplate}} +
+        {{~htmlDecode vmTemplate~}}
+        
+ {{else}} +

+ {{~tr "You can provide a VM template associated to the resource that will be created in OpenNebula"~}} +

+ {{/if}} +
+
diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/templates/panelId.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/templates/panelId.js new file mode 100644 index 0000000000..751de77571 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/panels/templates/panelId.js @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require){ + return 'marketplaceapp_templates_tab'; +}); diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/tabId.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/tabId.js new file mode 100644 index 0000000000..dc659b47c1 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/tabId.js @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require){ + return 'marketplaceapps-tab'; +}); diff --git a/src/sunstone/public/app/tabs/marketplaces-tab.js b/src/sunstone/public/app/tabs/marketplaces-tab.js new file mode 100644 index 0000000000..69c90b4bae --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaces-tab.js @@ -0,0 +1,59 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var Locale = require('utils/locale'); + var Buttons = require('./marketplaces-tab/buttons'); + var Actions = require('./marketplaces-tab/actions'); + var Table = require('./marketplaces-tab/datatable'); + + var TAB_ID = require('./marketplaces-tab/tabId'); + var DATATABLE_ID = "dataTableMarketplaces"; + + var _dialogs = [ + ]; + + var _panels = [ + require('./marketplaces-tab/panels/info'), + require('./marketplaces-tab/panels/apps') + ]; + + var _panelsHooks = [ + require('../utils/hooks/header') + ]; + + var _formPanels = [ + require('./marketplaces-tab/form-panels/create') + ]; + + var Tab = { + tabId: TAB_ID, + title: ' ' + Locale.tr("MarketPlaces"), + listHeader: ' '+Locale.tr("MarketPlaces"), + infoHeader: ' '+Locale.tr("MarketPlace"), + subheader: '  ', + resource: 'MarketPlace', + buttons: Buttons, + actions: Actions, + dataTable: new Table(DATATABLE_ID, {actions: true, info: true, oneSelection: true}), + panels: _panels, + panelsHooks: _panelsHooks, + formPanels: _formPanels, + dialogs: _dialogs + }; + + return Tab; +}); diff --git a/src/sunstone/public/app/tabs/marketplaces-tab/actions.js b/src/sunstone/public/app/tabs/marketplaces-tab/actions.js new file mode 100644 index 0000000000..d99647fe22 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaces-tab/actions.js @@ -0,0 +1,50 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var Sunstone = require('sunstone'); + var Notifier = require('utils/notifier'); + var Locale = require('utils/locale'); + var CommonActions = require('utils/common-actions'); + var OpenNebulaResource = require('opennebula/marketplace'); + + var RESOURCE = "MarketPlace"; + var XML_ROOT = "MARKETPLACE"; + var TAB_ID = require('./tabId'); + var CREATE_DIALOG_ID = require('./form-panels/create/formPanelId'); + + var _commonActions = new CommonActions(OpenNebulaResource, RESOURCE, TAB_ID, XML_ROOT); + + var _actions = { + "MarketPlace.create" : _commonActions.create(CREATE_DIALOG_ID), + "MarketPlace.create_dialog" : _commonActions.showCreate(CREATE_DIALOG_ID), + "MarketPlace.list" : _commonActions.list(), + "MarketPlace.show" : _commonActions.show(), + "MarketPlace.refresh" : _commonActions.refresh(), + "MarketPlace.delete" : _commonActions.del(), + "MarketPlace.chown": _commonActions.multipleAction('chown'), + "MarketPlace.chgrp": _commonActions.multipleAction('chgrp'), + "MarketPlace.chmod": _commonActions.singleAction('chmod'), + "MarketPlace.update" : _commonActions.update(), + "MarketPlace.update_template" : _commonActions.updateTemplate(), + "MarketPlace.append_template" : _commonActions.appendTemplate(), + "MarketPlace.update_dialog" : _commonActions.checkAndShowUpdate(), + "MarketPlace.show_to_update" : _commonActions.showUpdate(CREATE_DIALOG_ID), + "MarketPlace.rename": _commonActions.singleAction('rename') + } + + return _actions; +}); diff --git a/src/sunstone/public/app/tabs/marketplaces-tab/buttons.js b/src/sunstone/public/app/tabs/marketplaces-tab/buttons.js new file mode 100644 index 0000000000..fa4300b9b8 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaces-tab/buttons.js @@ -0,0 +1,57 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var Locale = require('utils/locale'); + + var MarketPlaceButtons = { + "MarketPlace.refresh" : { + type: "action", + layout: "refresh", + alwaysActive: true + }, + "MarketPlace.create_dialog" : { + type: "create_dialog", + layout: "create" + }, + "MarketPlace.update_dialog" : { + type: "action", + layout: "main", + text: Locale.tr("Update") + }, + "MarketPlace.chown" : { + type: "confirm_with_select", + text: Locale.tr("Change owner"), + select: "User", + layout: "user_select", + tip: Locale.tr("Select the new owner") + ":" + }, + "MarketPlace.chgrp" : { + type: "confirm_with_select", + text: Locale.tr("Change group"), + select: "Group", + layout: "user_select", + tip: Locale.tr("Select the new group") + ":" + }, + "MarketPlace.delete" : { + type: "confirm", + text: Locale.tr("Delete"), + layout: "del" + } + }; + + return MarketPlaceButtons; +}) diff --git a/src/sunstone/public/app/tabs/marketplaces-tab/datatable.js b/src/sunstone/public/app/tabs/marketplaces-tab/datatable.js new file mode 100644 index 0000000000..8e6b788cac --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaces-tab/datatable.js @@ -0,0 +1,139 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + var TabDataTable = require('utils/tab-datatable'); + var SunstoneConfig = require('sunstone-config'); + var Locale = require('utils/locale'); + var OpenNebulaMarketPlace = require('opennebula/marketplace'); + var DatastoreCapacityBar = require('../datastores-tab/utils/datastore-capacity-bar'); + var LabelsUtils = require('utils/labels/utils'); + + /* + CONSTANTS + */ + + var RESOURCE = "MarketPlace"; + var XML_ROOT = "MARKETPLACE"; + var TAB_NAME = require('./tabId'); + var LABELS_COLUMN = 8; + var TEMPLATE_ATTR = 'TEMPLATE'; + + /* + CONSTRUCTOR + */ + + /* + @dataTableId + @param {String} dataTableId unique identifier + @param {Object} conf + conf = { + 'info': true, enable on click row will show the element + 'action': true, enable actions on row elements + 'select': true, enable selecting elements from the table + 'selectOptions': { + 'filter_fn': function(ds) { return ds.TYPE == 0; } + } + } + @returns {Table} A new table object + */ + function Table(dataTableId, conf) { + this.conf = conf || {}; + this.tabId = TAB_NAME; + this.dataTableId = dataTableId; + this.resource = RESOURCE; + this.xmlRoot = XML_ROOT; + this.labelsColumn = LABELS_COLUMN; + + this.dataTableOptions = { + "bAutoWidth": false, + "bSortClasses" : false, + "bDeferRender": true, + "aoColumnDefs": [ + {"bSortable": false, "aTargets": ["check"]}, + {"sWidth": "35px", "aTargets": [0]}, + {"sWidth": "250px", "aTargets": [5]}, + {"bVisible": true, "aTargets": SunstoneConfig.tabTableColumns(TAB_NAME)}, + {"bVisible": false, "aTargets": ['_all']} + ] + } + + this.columns = [ + Locale.tr("ID"), + Locale.tr("Owner"), + Locale.tr("Group"), + Locale.tr("Name"), + Locale.tr("Capacity"), + Locale.tr("Apps"), + Locale.tr("Driver"), + Locale.tr("Labels") + ] + + this.selectOptions = { + "id_index": 1, + "name_index": 4, + "uname_index": 2, + "select_resource": Locale.tr("Please select a marketplace from the list"), + "you_selected": Locale.tr("You selected the following marketplace:"), + "select_resource_multiple": Locale.tr("Please select one or more marketplaces from the list"), + "you_selected_multiple": Locale.tr("You selected the following marketplaces:") + } + + TabDataTable.call(this); + }; + + Table.prototype = Object.create(TabDataTable.prototype); + Table.prototype.constructor = Table; + Table.prototype.elementArray = _elementArray; + + return Table; + + /* + FUNCTION DEFINITIONS + */ + + function _elementArray(element_json) { + var element = element_json[XML_ROOT]; + + return [ + '', + element.ID, + element.UNAME, + element.GNAME, + element.NAME, + DatastoreCapacityBar.html(element), + _lengthOf(element.MARKETPLACEAPPS.ID), + element.MARKET_MAD, + (LabelsUtils.labelsStr(element[TEMPLATE_ATTR])||'') + ]; + } + + function _lengthOf(ids){ + var l = 0; + if ($.isArray(ids)) + l = ids.length; + else if (!$.isEmptyObject(ids)) + l = 1; + + return l; + } +}); diff --git a/src/sunstone/public/app/tabs/marketplaces-tab/form-panels/create.js b/src/sunstone/public/app/tabs/marketplaces-tab/form-panels/create.js new file mode 100644 index 0000000000..b5bd95a151 --- /dev/null +++ b/src/sunstone/public/app/tabs/marketplaces-tab/form-panels/create.js @@ -0,0 +1,266 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + var BaseFormPanel = require('utils/form-panels/form-panel'); + var Sunstone = require('sunstone'); + var Locale = require('utils/locale'); + var Tips = require('utils/tips'); + var Config = require('sunstone-config'); + var WizardFields = require('utils/wizard-fields'); + var TemplateUtils = require('utils/template-utils'); + + /* + TEMPLATES + */ + + var TemplateWizardHTML = require('hbs!./create/wizard'); + var TemplateAdvancedHTML = require('hbs!./create/advanced'); + + /* + CONSTANTS + */ + + var FORM_PANEL_ID = require('./create/formPanelId'); + var TAB_ID = require('../tabId'); + var MARKET_MAD_ATTRS = [ + { + name: 'ENDPOINT', + label: Locale.tr("Endpoint"), + tooltip: Locale.tr("URL of AppMarket."), + driver: 'one' + }, + { + name: 'BASE_URL', + label: Locale.tr("Base URL"), + tooltip: Locale.tr("URL base to generate app end points, where the PUBLIC_DIR is accessible."), + driver: 'http' + }, + { + name: 'PUBLIC_DIR', + label: Locale.tr("Public Directory"), + tooltip: Locale.tr("Absolute directory path to place images, the document root for http server, in the frontend or in the hosts pointed at by the BRIDGE_LIST directive."), + driver: 'http' + }, + { + name: 'BRIDGE_LIST', + label: Locale.tr("Bridge List"), + tooltip: Locale.tr("Comma separated list of servers to access the public directory. If not defined, public directory will be local"), + driver: 'http' + }, + { + name: 'ACCESS_KEY_ID', + label: Locale.tr("Access Key Id"), + tooltip: Locale.tr("The access key of the S3 user."), + driver: 's3' + }, + { + name: 'SECRET_ACCESS_KEY', + label: Locale.tr("Secret Access Key"), + tooltip: Locale.tr("The secret key of the S3 user."), + driver: 's3' + }, + { + name: 'BUCKET', + label: Locale.tr("Bucket"), + tooltip: Locale.tr("The bucket where the files will be stored."), + driver: 's3' + }, + { + name: 'REGION', + label: Locale.tr("Region"), + tooltip: Locale.tr("The region to connect to. If you are using Ceph-S3 any value here will work."), + driver: 's3' + }, + { + name: 'TOTAL_MB', + label: Locale.tr("Total MB"), + tooltip: Locale.tr("This parameter defines the Total size of the MarketPlace in MB. It defaults to 1024 GB."), + driver: 's3' + }, + { + name: 'SIGNATURE_VERSION', + label: Locale.tr("Signature Version"), + tooltip: Locale.tr("Leave blank for Amazon AWS S3 service. If connecting to Ceph S3 it **must** be 's3'."), + driver: 's3' + }, + { + name: 'ENDPOINT', + label: Locale.tr("Endpoint"), + tooltip: Locale.tr("The URL of AppMarket."), + driver: 's3' + }, + { + name: 'FORCE_PATH_STYLE', + label: Locale.tr("Force Path Style"), + tooltip: Locale.tr("Leave blank for Amazon AWS S3 service. If connecting to Ceph S3 it **must** be 'YES'."), + driver: 's3' + } + ] + /* + CONSTRUCTOR + */ + + function FormPanel() { + var that = this; + + that.formPanelId = FORM_PANEL_ID; + that.tabId = TAB_ID; + that.actions = { + 'create': { + 'title': Locale.tr("Create MarketPlace"), + 'buttonText': Locale.tr("Create"), + 'resetButton': true + }, + 'update': { + 'title': Locale.tr("Update MarketPlace"), + 'buttonText': Locale.tr("Update"), + 'resetButton': false + } + }; + + that.marketMadNameList = []; + if (Config.marketMadConf !== undefined) { + $.each(Config.marketMadConf, function(index, marketMad) { + that.marketMadNameList.push(marketMad["NAME"]); + }); + } + + BaseFormPanel.call(this); + } + + FormPanel.FORM_PANEL_ID = FORM_PANEL_ID; + FormPanel.prototype = Object.create(BaseFormPanel.prototype); + FormPanel.prototype.constructor = FormPanel; + FormPanel.prototype.htmlWizard = _htmlWizard; + FormPanel.prototype.htmlAdvanced = _htmlAdvanced; + FormPanel.prototype.submitWizard = _submitWizard; + FormPanel.prototype.submitAdvanced = _submitAdvanced; + FormPanel.prototype.onShow = _onShow; + FormPanel.prototype.fill = _fill; + FormPanel.prototype.setup = _setup; + + return FormPanel; + + /* + FUNCTION DEFINITIONS + */ + + function _htmlWizard() { + return TemplateWizardHTML({ + 'formPanelId': this.formPanelId, + 'marketMadNameList': this.marketMadNameList, + 'marketMadAttrs': MARKET_MAD_ATTRS + }); + } + + function _htmlAdvanced() { + return TemplateAdvancedHTML({formPanelId: this.formPanelId}); + } + + function _onShow(dialog) { + $("#NAME", dialog).focus(); + $('#MARKET_MAD', dialog).change(); + + return false; + } + + function _fill(context, element) { + if (this.action != "update") { + return false; + } + + this.resourceId = element.ID; + + WizardFields.fill(context, element.TEMPLATE); + $('#NAME', context).val(element.NAME). + prop("disabled", true). + prop('wizard_field_disabled', true);; + $('#MARKET_MAD', context).val(element.MARKET_MAD).change(); + } + + // Set up the create datastore dialog + function _setup(dialog) { + Tips.setup(dialog); + + dialog.on('change', '#MARKET_MAD', function() { + _setRequiredFields(dialog, this.value); + }); + } + + + function _submitWizard(dialog) { + var that = this; + var marketObj = {}; + + $.extend(marketObj, WizardFields.retrieve(dialog)); + + if (this.action == "create") { + marketObj = { + "marketplace" : marketObj + }; + + Sunstone.runAction("MarketPlace.create", marketObj); + return false; + } else if (this.action == "update") { + Sunstone.runAction("MarketPlace.update", this.resourceId, TemplateUtils.templateToString(marketObj)); + return false; + } + } + + function _submitAdvanced(dialog) { + var template = $('#template', dialog).val(); + + if (this.action == "create") { + var marketObj = { + "marketplace" : { + "marketplace_raw" : template + } + }; + Sunstone.runAction("MarketPlace.create", marketObj); + } else if (this.action == "update") { + Sunstone.runAction("Network.update", this.resourceId, template); + return false; + } + + return false; + } + + function _setRequiredFields(dialog, marketMADName) { + // Hide all market mad attributes and remove required + $('.market-mad-attr-container', dialog).hide(); + $('.market-mad-attr-container input', dialog).removeAttr('required'); + + // Show attributes for the selected market mad and set the required ones + $('.market-mad-attr-container.' + marketMADName).show(); + $.each(Config.marketMadConf, function(i, e){ + if (e["NAME"] == marketMADName) { + if (!$.isEmptyObject(e["REQUIRED_ATTRS"])) { + $.each(e["REQUIRED_ATTRS"].split(","), function(i, attrName){ + $('#' + attrName, dialog).attr('required', true); + }); + } + return false; + } + } + ); + } +}); + diff --git a/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import/html.hbs b/src/sunstone/public/app/tabs/marketplaces-tab/form-panels/create/advanced.hbs similarity index 75% rename from src/sunstone/public/app/tabs/marketplace-tab/dialogs/import/html.hbs rename to src/sunstone/public/app/tabs/marketplaces-tab/form-panels/create/advanced.hbs index 25315e0511..e971338993 100644 --- a/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import/html.hbs +++ b/src/sunstone/public/app/tabs/marketplaces-tab/form-panels/create/advanced.hbs @@ -14,18 +14,19 @@ {{! limitations under the License. }} {{! -------------------------------------------------------------------------- }} - +
+
+ + +
+
\ No newline at end of file diff --git a/src/sunstone/public/app/tabs/vms-tab/panels/info.js b/src/sunstone/public/app/tabs/vms-tab/panels/info.js index 9af32bd89a..f8d893b2bb 100644 --- a/src/sunstone/public/app/tabs/vms-tab/panels/info.js +++ b/src/sunstone/public/app/tabs/vms-tab/panels/info.js @@ -25,6 +25,8 @@ define(function(require) { var PermissionsTable = require('utils/panel/permissions-table'); var TemplateTable = require('utils/panel/template-table'); var OpenNebulaVM = require('opennebula/vm'); + var Sunstone = require('sunstone'); + var Config = require('sunstone-config'); /* TEMPLATES @@ -73,7 +75,7 @@ define(function(require) { var lcmStateStr = OpenNebulaVM.lcmStateStr(this.element.LCM_STATE); var hostname = OpenNebulaVM.hostnameStr(this.element); - var deployId = (typeof(this.element.DEPLOY_ID) == "object" ? "-" : this.element.DEPLOY_ID); + var deployId = (typeof(this.element.DEPLOY_ID) == "object" ? "--" : this.element.DEPLOY_ID); var resched = (parseInt(this.element.RESCHED) ? Locale.tr("yes") : Locale.tr("no")) var templateTableHTML = TemplateTable.html(this.element.USER_TEMPLATE, RESOURCE, Locale.tr("Attributes")); @@ -110,6 +112,15 @@ define(function(require) { RenameTr.setup(TAB_ID, RESOURCE, this.element.ID, context); PermissionsTable.setup(TAB_ID, RESOURCE, this.element, context); + $("a.vrid", context).on("click", function(){ + // TODO: this should be checked internally in showElement, + // but it won't work because of bug #4198 + + if (Config.isTabEnabled("vrouters-tab")){ + Sunstone.showElement("vrouters-tab", "VirtualRouter.show", $(this).text()); + } + }); + // Get rid of the unwanted (for show) SCHED_* keys var that = this; var strippedTemplate = {}; diff --git a/src/sunstone/public/app/tabs/vms-tab/panels/info/html.hbs b/src/sunstone/public/app/tabs/vms-tab/panels/info/html.hbs index 35e02b0bb4..aaef4af219 100644 --- a/src/sunstone/public/app/tabs/vms-tab/panels/info/html.hbs +++ b/src/sunstone/public/app/tabs/vms-tab/panels/info/html.hbs @@ -58,6 +58,17 @@ {{resched}} + + {{tr "Virtual Router ID"}} + + {{#if element.TEMPLATE.VROUTER_ID}} + {{element.TEMPLATE.VROUTER_ID}} + {{else}} + -- + {{/if}} + + + diff --git a/src/sunstone/public/app/tabs/vms-tab/panels/network.js b/src/sunstone/public/app/tabs/vms-tab/panels/network.js index 6312070656..e31cb03d1a 100644 --- a/src/sunstone/public/app/tabs/vms-tab/panels/network.js +++ b/src/sunstone/public/app/tabs/vms-tab/panels/network.js @@ -262,13 +262,27 @@ define(function(require) { }); } + function ipTr(attr){ + var v = "--"; + + if (nic[attr] != undefined){ + v = nic[attr]; + + if (nic["VROUTER_"+attr] != undefined){ + v += ("
" + nic["VROUTER_"+attr] + Locale.tr(" (VRouter)")); + } + } + + return v; + } + nic_dt_data.push({ NIC_ID : nic.NIC_ID, NETWORK : nic.NETWORK, - IP : (nic.IP ? nic.IP : "--"), + IP : ipTr("IP"), MAC : nic.MAC, - IP6_ULA : (nic.IP6_ULA ? nic.IP6_ULA : "--"), - IP6_GLOBAL : (nic.IP6_GLOBAL ? nic.IP6_GLOBAL : "--"), + IP6_ULA : ipTr("IP6_ULA"), + IP6_GLOBAL : ipTr("IP6_GLOBAL"), ACTIONS : actions, SECURITY_GROUP_RULES : secgroups }); @@ -287,10 +301,10 @@ define(function(require) { }, {"data": "NIC_ID", "defaultContent": ""}, {"data": "NETWORK", "defaultContent": ""}, - {"data": "IP", "defaultContent": ""}, + {"data": "IP", "defaultContent": "", "class": "nowrap"}, {"data": "MAC", "defaultContent": ""}, - {"data": "IP6_ULA", "defaultContent": ""}, - {"data": "IP6_GLOBAL", "defaultContent": ""}, + {"data": "IP6_ULA", "defaultContent": "", "class": "nowrap"}, + {"data": "IP6_GLOBAL", "defaultContent": "", "class": "nowrap"}, {"data": "ACTIONS", "defaultContent": "", "orderable": false}, {"defaultContent": "", "orderable": false} ], diff --git a/src/sunstone/public/app/tabs/vnets-tab.js b/src/sunstone/public/app/tabs/vnets-tab.js index 095464034f..603ac35726 100644 --- a/src/sunstone/public/app/tabs/vnets-tab.js +++ b/src/sunstone/public/app/tabs/vnets-tab.js @@ -33,7 +33,8 @@ define(function(require) { require('./vnets-tab/panels/info'), require('./vnets-tab/panels/ar'), require('./vnets-tab/panels/leases'), - require('./vnets-tab/panels/secgroups') + require('./vnets-tab/panels/secgroups'), + require('./vnets-tab/panels/vrouters') ]; var _panelsHooks = [ diff --git a/src/sunstone/public/app/tabs/vnets-tab/panels/leases.js b/src/sunstone/public/app/tabs/vnets-tab/panels/leases.js index 8eeed2e794..6591251c3b 100644 --- a/src/sunstone/public/app/tabs/vnets-tab/panels/leases.js +++ b/src/sunstone/public/app/tabs/vnets-tab/panels/leases.js @@ -91,6 +91,9 @@ define(function(require) { } else if (lease.VNET != undefined) { //used by a VNET col0HTML = ''; col1HTML = Locale.tr("NET:") + lease.VNET; + } else if (lease.VROUTER != undefined) { //used by a VR + col0HTML = ''; + col1HTML = Locale.tr("VR:") + lease.VROUTER; } else { col0HTML = ''; col1HTML = '--'; diff --git a/src/sunstone/public/app/tabs/vnets-tab/panels/vrouters.js b/src/sunstone/public/app/tabs/vnets-tab/panels/vrouters.js new file mode 100644 index 0000000000..6df69d6455 --- /dev/null +++ b/src/sunstone/public/app/tabs/vnets-tab/panels/vrouters.js @@ -0,0 +1,88 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + var Locale = require('utils/locale'); + var VirtualRoutersTable = require('tabs/vrouters-tab/datatable'); + + /* + CONSTANTS + */ + + var PANEL_ID = require('./vrouters/panelId'); + var VR_TABLE_ID = PANEL_ID + "VirtualRoutersTable"; + var RESOURCE = "Network"; + var XML_ROOT = "VNET"; + + /* + CONSTRUCTOR + */ + + function Panel(info) { + this.title = Locale.tr("V. Routers"); + this.icon = "fa-random"; + + this.element = info[XML_ROOT]; + + return this; + } + + Panel.PANEL_ID = PANEL_ID; + Panel.prototype.html = _html; + Panel.prototype.setup = _setup; + + return Panel; + + /* + FUNCTION DEFINITIONS + */ + + function _html() { + var vrs = []; + + if (this.element.VROUTERS.ID != undefined){ + vrs = this.element.VROUTERS.ID; + + if (!$.isArray(vrs)){ + vrs = [vrs]; + } + } + + var opts = { + info: true, + select: true, + selectOptions: { + read_only: true, + fixed_ids: vrs + } + }; + + this.vroutersTable = new VirtualRoutersTable(VR_TABLE_ID, opts); + + return this.vroutersTable.dataTableHTML; + } + + function _setup(context) { + this.vroutersTable.initialize(); + this.vroutersTable.refreshResourceTableSelect(); + + return false; + } +}); diff --git a/src/sunstone/public/app/tabs/vnets-tab/panels/vrouters/panelId.js b/src/sunstone/public/app/tabs/vnets-tab/panels/vrouters/panelId.js new file mode 100644 index 0000000000..a189897582 --- /dev/null +++ b/src/sunstone/public/app/tabs/vnets-tab/panels/vrouters/panelId.js @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require){ + return 'vnet_vr_list_tab'; +}) diff --git a/src/sunstone/public/app/tabs/vnets-topology-tab.js b/src/sunstone/public/app/tabs/vnets-topology-tab.js new file mode 100644 index 0000000000..b26a5e6dba --- /dev/null +++ b/src/sunstone/public/app/tabs/vnets-topology-tab.js @@ -0,0 +1,608 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var Locale = require('utils/locale'); + var Config = require('sunstone-config'); + var Sunstone = require('sunstone'); + var Notifier = require('utils/notifier'); + var OpenNebula = require('opennebula'); + var VNetUtils = require('tabs/vnets-tab/utils/common'); + + var Vis = require('vis'); + + var TemplateDashboard = require('hbs!./vnets-topology-tab/html'); + + var _network; + var _vnetList; + var _vrList; + var _indexedVRs; + var _vrouterVMs; + var _vnetLevel; + + var _buttons = { + "NetworkTopology.refresh" : { + type: "action", + layout: "refresh", + alwaysActive: true + }, + "NetworkTopology.fit" : { + type: "action", + layout: "main", + text: '', + alwaysActive: true + }, + "NetworkTopology.collapseVMs" : { + type: "action", + layout: "main", + text: Locale.tr("Collapse VMs"), + alwaysActive: true + }, + "NetworkTopology.openVMs" : { + type: "action", + layout: "main", + text: Locale.tr("Open VMs"), + alwaysActive: true + } + }; + + var _actions = { + "NetworkTopology.refresh" : { + type: "custom", + call: _refresh + }, + "NetworkTopology.fit" : { + type: "custom", + call: _fit + }, + "NetworkTopology.collapseVMs" : { + type: "custom", + call: _collapseVMs + }, + "NetworkTopology.openVMs" : { + type: "custom", + call: _openVMs + } + }; + + var TAB_ID = require('./vnets-topology-tab/tabId'); + + var Tab = { + tabId: TAB_ID, + resource: 'NetworkTopology', + tabClass: "subTab", + parentTab: "infra-tab", + title: Locale.tr("Network Topology"), + listHeader: ' ' + Locale.tr("Network Topology"), + buttons: _buttons, + actions: _actions, + content: _html() + }; + + return Tab; + + function _html() { + return TemplateDashboard(); + } + + function _onShow() { + } + + function _refresh() { + + OpenNebula.VirtualRouter.list({ + error: Notifier.onError, + success: function(request, item_list) { + _vrList = item_list; + + OpenNebula.Network.list({ + timeout: true, + success: function (request, item_list) { + + // TODO: naive way to request all the individual networks info. It might + // be better to use promises, or a Network.list with an 'extended' option + + var vnetList = []; + + var i = 0; + + function _getVNet(index){ + var vnetId = item_list[index].VNET.ID; + + OpenNebula.Network.show({ + data : { + id: vnetId + }, + timeout:true, + success: function(request,info){ + vnetList.push(info); + + i += 1; + if (i == item_list.length){ + _vnetList = vnetList; + _doTopology(); + } else { + _getVNet(i); + } + }, + error: Notifier.onError + }); + } + + _getVNet(i); + }, + error: Notifier.onError + }); + } + }); + } + + function _doTopology(){ + _vnetLevel = {}; + + var nodes = []; + var edges = []; + + // Aux object to keep track of duplicated nodes (vms/vr attached to 2 vnets) + var nodeIndex = {}; + + var level = 0; + + _indexedVRs = {}; + _vrouterVMs = {}; + + $.each(_vrList, function(i, element){ + var vr = element.VROUTER; + _indexedVRs[vr.ID] = vr; + + var vms = []; + + if (vr.VMS.ID != undefined){ + vms = vr.VMS.ID; + + if (!$.isArray(vms)){ + vms = [vms]; + } + } + + $.each(vms, function(n, vm){ + _vrouterVMs[vm] = { + vmid: vm, + vrid: vr.ID, + leases: {} + }; + }); + }); + + $.each(_vnetList, function(i,element){ + var vnet = element.VNET; + var vnetId = vnet.ID; + + // VNet node + // ---------------- + + if (vnet.PARENT_NETWORK_ID.length > 0){ + vnetId = vnet.PARENT_NETWORK_ID; + } + + var vnetNodeId = "vnet"+vnetId; + + if (!nodeIndex[vnetNodeId]){ + level += 2; + + _vnetLevel[vnetId] = level; + + nodeIndex[vnetNodeId] = true; + nodes.push({ + id: vnetNodeId, + level: level, + label: " VNet "+vnet.NAME + " ", // Spaces for padding, no other reason + group: "vnet"}); + } + + // VRouter nodes + // ---------------- + + var vrs = []; + + if (vnet.VROUTERS.ID != undefined){ + vrs = vnet.VROUTERS.ID; + + if (!$.isArray(vrs)){ + vrs = [vrs]; + } + } + + $.each(vrs, function(j,vr){ + var nodeId = "vr"+vr; + + if (!nodeIndex[nodeId]){ + nodeIndex[nodeId] = true; + nodes.push({ + id: nodeId, + level: level+1, + title: '', + label: "VR "+vr, + group: "vr"}); + } + + edges.push({from: vnetNodeId, to: nodeId}); + }); + + // VM nodes + // ---------------- + + var arList = VNetUtils.getARList(vnet); + + for (var i=0; i1 lease + leases = [leases]; + } + + for (var j=0; j"+ + ""+Locale.tr("VM")+""; + + $.each(vm.leases, function(vnetId,ip){ + headers += ""+Locale.tr("VNet")+" " +vnetId+""; + }); + + headers += ""; + } + + var tr = ""+vmid+""; + + $.each(vm.leases, function(vnetId,ips){ + tr += "" + ips.join("
") + ""; + }); + + tr += ""; + + trs.push(tr); + }); + + var html = + ""+ + headers+ + ""+ + trs.join("")+ + ""+ + "
"; + + return html; + } + + function _collapseVMs(){ + + // Clusters all VMs for each vnet, except those attached to more than one vnet + $.each(_vnetList, function(i,element){ + var vnet = element.VNET; + var vnetId = vnet.ID; + + if (vnet.PARENT_NETWORK_ID.length > 0){ + vnetId = vnet.PARENT_NETWORK_ID; + } + + var clusterOptionsByData = { + joinCondition:function(childOptions) { + return (childOptions.group == "vm" && + childOptions.vnet == vnetId && + childOptions.amountOfConnections == 1); + }, + clusterNodeProperties: { + id:"vmCluster"+vnetId, + level: _vnetLevel[vnetId]+1, + label: "VMs", + group: "vmCluster" + }, + clusterEdgeProperties: { + label: '' + } + }; + + _network.cluster(clusterOptionsByData); + }); + + _network.stabilize(); + } + + function _openVMs(){ + + // Opens all VMs Clusters + $.each(_vnetList, function(i,element){ + var vnet = element.VNET; + var clusterId = "vmCluster"+vnet.ID; + + try{ + _network.openCluster(clusterId); + }catch(err){ + } + }); + + _network.stabilize(); + } + + function _fit(){ + _network.fit(); + } +}); diff --git a/src/sunstone/public/app/tabs/vnets-topology-tab/html.hbs b/src/sunstone/public/app/tabs/vnets-topology-tab/html.hbs new file mode 100644 index 0000000000..459145a70f --- /dev/null +++ b/src/sunstone/public/app/tabs/vnets-topology-tab/html.hbs @@ -0,0 +1,17 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! 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. }} +{{! -------------------------------------------------------------------------- }} + +
diff --git a/src/sunstone/public/app/tabs/marketplace-tab/buttons.js b/src/sunstone/public/app/tabs/vnets-topology-tab/tabId.js similarity index 80% rename from src/sunstone/public/app/tabs/marketplace-tab/buttons.js rename to src/sunstone/public/app/tabs/vnets-topology-tab/tabId.js index 52ff943fa4..b2aa76cca8 100644 --- a/src/sunstone/public/app/tabs/marketplace-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vnets-topology-tab/tabId.js @@ -15,20 +15,5 @@ /* -------------------------------------------------------------------------- */ define(function(require) { - var Locale = require('utils/locale'); - - var Buttons = { - "Marketplace.refresh" : { - type: "action", - layout: "refresh", - alwaysActive: true - }, - "Marketplace.import" : { - type: "action", - layout: "main", - text: Locale.tr('Import') - } - }; - - return Buttons; + return 'vnets-topology-tab'; }); diff --git a/src/sunstone/public/app/tabs/vrouters-tab.js b/src/sunstone/public/app/tabs/vrouters-tab.js new file mode 100644 index 0000000000..122e8a1a0b --- /dev/null +++ b/src/sunstone/public/app/tabs/vrouters-tab.js @@ -0,0 +1,62 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var Locale = require('utils/locale'); + var Buttons = require('./vrouters-tab/buttons'); + var Actions = require('./vrouters-tab/actions'); + var Table = require('./vrouters-tab/datatable'); + + var TAB_ID = require('./vrouters-tab/tabId'); + var DATATABLE_ID = "dataTableVirtualRouters"; + + var _dialogs = [ + require('./vrouters-tab/dialogs/attach-nic') + ]; + + var _panels = [ + require('./vrouters-tab/panels/info'), + require('./vrouters-tab/panels/vms') + ]; + + var _panelsHooks = [ + require('../utils/hooks/header') + ]; + + var _formPanels = [ + require('./vrouters-tab/form-panels/create') + ]; + + var Tab = { + tabId: TAB_ID, + title: Locale.tr("Virtual Routers"), + tabClass: "subTab", + parentTab: "infra-tab", + listHeader: ' '+Locale.tr("Virtual Routers"), + infoHeader: ' '+Locale.tr("Virtual Router"), + subheader: '  ', + resource: 'VirtualRouter', + buttons: Buttons, + actions: Actions, + dataTable: new Table(DATATABLE_ID, {actions: true, info: true}), + panels: _panels, + panelsHooks: _panelsHooks, + formPanels: _formPanels, + dialogs: _dialogs + }; + + return Tab; +}); diff --git a/src/sunstone/public/app/tabs/vrouters-tab/actions.js b/src/sunstone/public/app/tabs/vrouters-tab/actions.js new file mode 100644 index 0000000000..c479da52b4 --- /dev/null +++ b/src/sunstone/public/app/tabs/vrouters-tab/actions.js @@ -0,0 +1,52 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var Sunstone = require('sunstone'); + var Notifier = require('utils/notifier'); + var Locale = require('utils/locale'); + var DataTable = require('./datatable'); + var OpenNebulaResource = require('opennebula/virtualrouter'); + var CommonActions = require('utils/common-actions'); + + var RESOURCE = "VirtualRouter"; + var XML_ROOT = "VROUTER"; + var TAB_ID = require('./tabId'); + var CREATE_DIALOG_ID = require('./form-panels/create/formPanelId'); + + var _commonActions = new CommonActions(OpenNebulaResource, RESOURCE, TAB_ID, XML_ROOT); + + var _actions = { + "VirtualRouter.create" : _commonActions.create(CREATE_DIALOG_ID), + "VirtualRouter.create_dialog" : _commonActions.showCreate(CREATE_DIALOG_ID), + "VirtualRouter.list" : _commonActions.list(), + "VirtualRouter.show" : _commonActions.show(), + "VirtualRouter.refresh" : _commonActions.refresh(), + "VirtualRouter.delete" : _commonActions.del(), + "VirtualRouter.chown": _commonActions.multipleAction('chown'), + "VirtualRouter.chgrp": _commonActions.multipleAction('chgrp'), + "VirtualRouter.chmod": _commonActions.singleAction('chmod'), + "VirtualRouter.rename": _commonActions.singleAction('rename'), + "VirtualRouter.attachnic": _commonActions.singleAction('attachnic'), + "VirtualRouter.detachnic": _commonActions.singleAction('detachnic'), + "VirtualRouter.update" : _commonActions.update(), + "VirtualRouter.update_template" : _commonActions.updateTemplate(), + "VirtualRouter.update_dialog" : _commonActions.checkAndShowUpdate(), + "VirtualRouter.show_to_update" : _commonActions.showUpdate(CREATE_DIALOG_ID), + }; + + return _actions; +}); diff --git a/src/sunstone/public/app/tabs/vrouters-tab/buttons.js b/src/sunstone/public/app/tabs/vrouters-tab/buttons.js new file mode 100644 index 0000000000..d376ffd1f3 --- /dev/null +++ b/src/sunstone/public/app/tabs/vrouters-tab/buttons.js @@ -0,0 +1,52 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + var Locale = require('utils/locale'); + + var Buttons = { + "VirtualRouter.refresh" : { + type: "action", + layout: "refresh", + alwaysActive: true + }, + "VirtualRouter.create_dialog" : { + type: "create_dialog", + layout: "create" + }, + "VirtualRouter.chown" : { + type: "confirm_with_select", + text: Locale.tr("Change owner"), + layout: "user_select", + select: "User", + tip: Locale.tr("Select the new owner")+":" + }, + "VirtualRouter.chgrp" : { + type: "confirm_with_select", + text: Locale.tr("Change group"), + layout: "user_select", + select: "Group", + tip: Locale.tr("Select the new group")+":" + }, + "VirtualRouter.delete" : { + type: "confirm", + layout: "del", + text: Locale.tr("Delete") + } + }; + + return Buttons; +}); diff --git a/src/sunstone/public/app/tabs/marketplace-tab/datatable.js b/src/sunstone/public/app/tabs/vrouters-tab/datatable.js similarity index 64% rename from src/sunstone/public/app/tabs/marketplace-tab/datatable.js rename to src/sunstone/public/app/tabs/vrouters-tab/datatable.js index 79396ed7cd..c9a6b79610 100644 --- a/src/sunstone/public/app/tabs/marketplace-tab/datatable.js +++ b/src/sunstone/public/app/tabs/vrouters-tab/datatable.js @@ -27,8 +27,8 @@ define(function(require) { CONSTANTS */ - var RESOURCE = "Marketplace"; - //var XML_ROOT = ""; + var RESOURCE = "VirtualRouter"; + var XML_ROOT = "VROUTER"; var TAB_NAME = require('./tabId'); /* @@ -40,7 +40,7 @@ define(function(require) { this.tabId = TAB_NAME; this.dataTableId = dataTableId; this.resource = RESOURCE; - //this.xmlRoot = XML_ROOT; + this.xmlRoot = XML_ROOT; this.dataTableOptions = { "bAutoWidth": false, @@ -56,17 +56,20 @@ define(function(require) { this.columns = [ Locale.tr("ID"), - Locale.tr("Name"), - Locale.tr("Publisher"), - Locale.tr("Hypervisor"), - Locale.tr("Arch"), - Locale.tr("Format"), - Locale.tr("Tags") + Locale.tr("Owner"), + Locale.tr("Group"), + Locale.tr("Name") ]; - /* + this.selectOptions = { + "id_index": 1, + "name_index": 4, + "select_resource": Locale.tr("Please select a virtual router from the list"), + "you_selected": Locale.tr("You selected the following virtual router:"), + "select_resource_multiple": Locale.tr("Please select one or more virtual routers from the list"), + "you_selected_multiple": Locale.tr("You selected the following virtual routers:") }; - */ + TabDataTable.call(this); } @@ -80,47 +83,17 @@ define(function(require) { FUNCTION DEFINITIONS */ - function _elementArray(element) { - var publisher = '-'; - var hypervisor = '-'; - var arch = '-'; - var format = '-'; - var tags = '-'; - - if(element.publisher != undefined){ - publisher = element.publisher; - } - - if(element.files != undefined && element.files.length > 0){ - if(element.files[0]["hypervisor"] != undefined){ - hypervisor = element.files[0]["hypervisor"]; - } - - if(element.files[0]["os-arch"] != undefined){ - arch = element.files[0]["os-arch"]; - } - - if(element.files[0]["format"] != undefined){ - format = element.files[0]["format"]; - } - } - - if(element.tags != undefined){ - tags = element.tags; - } + function _elementArray(element_json) { + var element = element_json[XML_ROOT]; return [ - '', - element._id.$oid, - element.name, - publisher, - hypervisor, - arch, - format, - tags + '', + element.ID, + element.UNAME, + element.GNAME, + element.NAME ]; } }); diff --git a/src/sunstone/public/app/tabs/vrouters-tab/dialogs/attach-nic.js b/src/sunstone/public/app/tabs/vrouters-tab/dialogs/attach-nic.js new file mode 100644 index 0000000000..e6ca5565a4 --- /dev/null +++ b/src/sunstone/public/app/tabs/vrouters-tab/dialogs/attach-nic.js @@ -0,0 +1,100 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + var BaseDialog = require('utils/dialogs/dialog'); + var TemplateHTML = require('hbs!./attach-nic/html'); + var Sunstone = require('sunstone'); + var Notifier = require('utils/notifier'); + var NicsSection = require('utils/nics-section'); + var WizardFields = require('utils/wizard-fields'); + + /* + CONSTANTS + */ + + var DIALOG_ID = require('./attach-nic/dialogId'); + var TAB_ID = require('../tabId') + + /* + CONSTRUCTOR + */ + + function Dialog() { + this.dialogId = DIALOG_ID; + + BaseDialog.call(this); + } + + Dialog.DIALOG_ID = DIALOG_ID; + Dialog.prototype = Object.create(BaseDialog.prototype); + Dialog.prototype.constructor = Dialog; + Dialog.prototype.html = _html; + Dialog.prototype.onShow = _onShow; + Dialog.prototype.setup = _setup; + Dialog.prototype.setElement = _setElement; + + return Dialog; + + /* + FUNCTION DEFINITIONS + */ + + function _html() { + return TemplateHTML({ + 'dialogId': this.dialogId + }); + } + + function _setup(context) { + var that = this; + + NicsSection.insert({}, + $(".nicsContext", context), + {floatingIP: true, management: true, + hide_add_button:true, + click_add_button:true + }); + + $('#' + DIALOG_ID + 'Form', context).submit(function() { + var templateJSON = NicsSection.retrieve($(".nicsContext", context)); + var obj = { + "NIC": templateJSON + }; + + Sunstone.runAction('VirtualRouter.attachnic', that.element.ID, obj); + + Sunstone.getDialog(DIALOG_ID).hide(); + Sunstone.getDialog(DIALOG_ID).reset(); + return false; + }); + + return false; + } + + function _onShow(context) { + $("#vr_id", context).val(this.element.ID); + return false; + } + + function _setElement(element) { + this.element = element; + } +}); diff --git a/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import/dialogId.js b/src/sunstone/public/app/tabs/vrouters-tab/dialogs/attach-nic/dialogId.js similarity index 94% rename from src/sunstone/public/app/tabs/marketplace-tab/dialogs/import/dialogId.js rename to src/sunstone/public/app/tabs/vrouters-tab/dialogs/attach-nic/dialogId.js index 04947a6055..334e377274 100644 --- a/src/sunstone/public/app/tabs/marketplace-tab/dialogs/import/dialogId.js +++ b/src/sunstone/public/app/tabs/vrouters-tab/dialogs/attach-nic/dialogId.js @@ -14,6 +14,6 @@ /* limitations under the License. */ /* -------------------------------------------------------------------------- */ -define(function(require){ - return 'importMarketplaceDialog'; +define(function(require) { + return 'attachNICVirtualRouterDialog'; }); diff --git a/src/sunstone/public/app/tabs/vrouters-tab/dialogs/attach-nic/html.hbs b/src/sunstone/public/app/tabs/vrouters-tab/dialogs/attach-nic/html.hbs new file mode 100644 index 0000000000..15b8839419 --- /dev/null +++ b/src/sunstone/public/app/tabs/vrouters-tab/dialogs/attach-nic/html.hbs @@ -0,0 +1,46 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! 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. }} +{{! -------------------------------------------------------------------------- }} + + diff --git a/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create.js b/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create.js new file mode 100644 index 0000000000..50f7226150 --- /dev/null +++ b/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create.js @@ -0,0 +1,229 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require) { + /* + DEPENDENCIES + */ + + require('foundation.tab'); + var BaseFormPanel = require('utils/form-panels/form-panel'); + var Sunstone = require('sunstone'); + var Locale = require('utils/locale'); + var Tips = require('utils/tips'); + var TemplateUtils = require('utils/template-utils'); + var UserInputs = require('utils/user-inputs'); + var WizardFields = require('utils/wizard-fields'); + var NicsSection = require('utils/nics-section'); + var TemplatesTable = require('tabs/templates-tab/datatable'); + var OpenNebulaVirtualRouter = require('opennebula/virtualrouter'); + var OpenNebulaTemplate = require('opennebula/template'); + var OpenNebulaAction = require('opennebula/action'); + var Notifier = require('utils/notifier'); + + /* + TEMPLATES + */ + + var TemplateWizardHTML = require('hbs!./create/wizard'); + var TemplateAdvancedHTML = require('hbs!./create/advanced'); + + /* + CONSTANTS + */ + + var FORM_PANEL_ID = require('./create/formPanelId'); + var TAB_ID = require('../tabId'); + + /* + CONSTRUCTOR + */ + + function FormPanel() { + this.formPanelId = FORM_PANEL_ID; + this.tabId = TAB_ID; + this.actions = { + 'create': { + 'title': Locale.tr("Create Virtual Router"), + 'buttonText': Locale.tr("Create"), + 'resetButton': true + } + }; + + this.templatesTable = new TemplatesTable( + 'vr_create', + { 'select': true, + 'selectOptions': { + 'filter_fn': function(tmpl){ + return (tmpl.TEMPLATE.VROUTER != undefined && tmpl.TEMPLATE.VROUTER.toUpperCase() == "YES"); + } + } + }); + + BaseFormPanel.call(this); + } + + FormPanel.FORM_PANEL_ID = FORM_PANEL_ID; + FormPanel.prototype = Object.create(BaseFormPanel.prototype); + FormPanel.prototype.constructor = FormPanel; + FormPanel.prototype.htmlWizard = _htmlWizard; + FormPanel.prototype.htmlAdvanced = _htmlAdvanced; + FormPanel.prototype.submitWizard = _submitWizard; + FormPanel.prototype.submitAdvanced = _submitAdvanced; + FormPanel.prototype.onShow = _onShow; + FormPanel.prototype.setup = _setup; + + return FormPanel; + + /* + FUNCTION DEFINITIONS + */ + + function _htmlWizard() { + return TemplateWizardHTML({ + 'formPanelId': this.formPanelId, + 'templatesTableHTML': this.templatesTable.dataTableHTML + }); + } + + function _htmlAdvanced() { + return TemplateAdvancedHTML({formPanelId: this.formPanelId}); + } + + function _setup(context) { + var that = this; + + NicsSection.insert({}, + $(".nicsContext", context), + {floatingIP: true, management: true}); + + this.templatesTable.initialize(); + + this.templatesTable.idInput().attr("required", ""); + + this.templatesTable.idInput().on("change", function(){ + var templateId = $(this).val(); + + var inputs_div = $(".template_user_inputs", context); + inputs_div.empty(); + + OpenNebulaTemplate.show({ + data : { + id: templateId + }, + timeout: true, + success: function (request, template_json) { + UserInputs.vmTemplateInsert( + inputs_div, + template_json, + {text_header: ' '+Locale.tr("Custom Attributes")}); + }, + error: Notifier.onError + }); + }); + + $(".vr_attributes #name", context).on("input", function(){ + $('#vm_name', context).val("vr-"+$(this).val()+"-%i"); + }); + + Tips.setup(context); + + return false; + } + + function _submitWizard(context) { + var virtual_router_json = WizardFields.retrieve($(".vr_attributes", context)); + + var nics = NicsSection.retrieve($(".nicsContext", context)); + if (nics.length > 0) { + virtual_router_json.NIC = nics; + } + + var tmplId = this.templatesTable.retrieveResourceTableSelect(); + + if (this.action == "create") { + virtual_router_json = { + "virtual_router" : virtual_router_json + }; + + var vm_name = $('#vm_name', context).val(); + var n_times = parseInt($('#vm_n_times', context).val()); + + if (isNaN(n_times)){ + n_times = 1; + } + + var hold = $('#hold', context).prop("checked"); + + OpenNebulaVirtualRouter.create({ + data : virtual_router_json, + timeout: true, + success: function (request, response) { + + var tmpl = WizardFields.retrieve($(".template_user_inputs", context)); + + var extra_info = { + 'n_vms': n_times, + 'template_id': tmplId, + 'vm_name': vm_name, + 'hold': hold, + 'template': tmpl + }; + + OpenNebulaVirtualRouter.instantiate({ + data:{ + id: response.VROUTER.ID, + extra_param: extra_info + }, + timeout: true, + success: function(request, response){ + OpenNebulaAction.clear_cache("VM"); + + Sunstone.resetFormPanel(TAB_ID, FORM_PANEL_ID); + Sunstone.hideFormPanel(TAB_ID); + }, + error: function(request, response) { + Sunstone.hideFormPanelLoading(TAB_ID); + + Notifier.notifyError(Locale.tr( + "Failed to create VMs. Virtual Router may need to be deleted manually.")); + Notifier.onError(request, response); + } + }); + }, + error: function(request, response) { + Sunstone.hideFormPanelLoading(TAB_ID); + Notifier.onError(request, response); + }, + }); + + return false; + } + } + + function _submitAdvanced(context) { + if (this.action == "create") { + var template = $('textarea#template', context).val(); + var virtual_router_json = {virtual_router: {virtual_router_raw: template}}; + Sunstone.runAction("VirtualRouter.create",virtual_router_json); + return false; + } + } + + function _onShow(context) { + this.templatesTable.refreshResourceTableSelect(); + } +}); diff --git a/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create/advanced.hbs b/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create/advanced.hbs new file mode 100644 index 0000000000..8807bf3da4 --- /dev/null +++ b/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create/advanced.hbs @@ -0,0 +1,28 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! 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. }} +{{! -------------------------------------------------------------------------- }} + +
+
+
+

{{tr "Write the Virtual Router template here"}}

+
+
+
+
+ +
+
+
diff --git a/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create/formPanelId.js b/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create/formPanelId.js new file mode 100644 index 0000000000..bd1cd4665b --- /dev/null +++ b/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create/formPanelId.js @@ -0,0 +1,19 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2015, OpenNebula Project, OpenNebula Systems */ +/* */ +/* 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. */ +/* -------------------------------------------------------------------------- */ + +define(function(require){ + return 'createVirtualRouterForm'; +}); diff --git a/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create/wizard.hbs b/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create/wizard.hbs new file mode 100644 index 0000000000..3eb9faf22e --- /dev/null +++ b/src/sunstone/public/app/tabs/vrouters-tab/form-panels/create/wizard.hbs @@ -0,0 +1,101 @@ +{{! -------------------------------------------------------------------------- }} +{{! Copyright 2002-2015, OpenNebula Project, OpenNebula Systems }} +{{! }} +{{! 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. }} +{{! -------------------------------------------------------------------------- }} + +
+
+
+
+
+ + +
+
+
+
+ +