From a4460bea2bbd727f3266a7e4b8a5085b5b54b158 Mon Sep 17 00:00:00 2001 From: juanmont <jjmontiel@opennebula.org> Date: Tue, 23 Jan 2018 12:57:24 +0100 Subject: [PATCH 1/6] B #1412: Prevented attach action with images in LOCKED state --- include/ImageManager.h | 9 ++++++--- include/ImagePool.h | 3 ++- src/image/ImageManagerActions.cc | 31 ++++++++++++++++++++++++++----- src/image/ImagePool.cc | 7 ++++--- src/vm/VirtualMachineDisk.cc | 4 ++-- 5 files changed, 40 insertions(+), 14 deletions(-) diff --git a/include/ImageManager.h b/include/ImageManager.h index a155758775..6548eb28a1 100644 --- a/include/ImageManager.h +++ b/include/ImageManager.h @@ -94,18 +94,20 @@ public: * Try to acquire an image from the repository for a VM. * @param image_id id of image * @param error string describing the error + * @param attach indicates that are trying to make an attachment of the image * @return pointer to the image or 0 if could not be acquired */ - Image * acquire_image(int vm_id, int image_id, string& error); + Image * acquire_image(int vm_id, int image_id, string& error, bool attach); /** * Try to acquire an image from the repository for a VM. * @param name of the image * @param id of owner * @param error string describing the error + * @param attach indicates that are trying to make an attachment of the image * @return pointer to the image or 0 if could not be acquired */ - Image * acquire_image(int vm_id, const string& name, int uid, string& error); + Image * acquire_image(int vm_id, const string& name, int uid, string& error, bool attach); /** * Releases an image and triggers any needed operations in the repo @@ -358,9 +360,10 @@ private: /** * Acquires an image updating its state. * @param image pointer to image, it should be locked + * @param attach indicates that are trying to make an attachment of the image * @return 0 on success */ - int acquire_image(int vm_id, Image *img, string& error); + int acquire_image(int vm_id, Image *img, string& error, bool attach); /** * Moves a file to an image in the repository diff --git a/include/ImagePool.h b/include/ImagePool.h index a5fb6a37dd..d38faa8e3a 100644 --- a/include/ImagePool.h +++ b/include/ImagePool.h @@ -166,7 +166,8 @@ public: int uid, int& image_id, Snapshots ** snaps, - string& error_str); + string& error_str, + bool attach); /** * Generates a DISK attribute for VM templates using the Image metadata * diff --git a/src/image/ImageManagerActions.cc b/src/image/ImageManagerActions.cc index a1071caf12..d4703507d7 100644 --- a/src/image/ImageManagerActions.cc +++ b/src/image/ImageManagerActions.cc @@ -25,7 +25,7 @@ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -Image * ImageManager::acquire_image(int vm_id, int image_id, string& error) +Image * ImageManager::acquire_image(int vm_id, int image_id, string& error, bool attach) { Image * img; int rc; @@ -41,7 +41,7 @@ Image * ImageManager::acquire_image(int vm_id, int image_id, string& error) return 0; } - rc = acquire_image(vm_id, img, error); + rc = acquire_image(vm_id, img, error, attach); if ( rc != 0 ) { @@ -54,7 +54,7 @@ Image * ImageManager::acquire_image(int vm_id, int image_id, string& error) /* -------------------------------------------------------------------------- */ -Image * ImageManager::acquire_image(int vm_id, const string& name, int uid, string& error) +Image * ImageManager::acquire_image(int vm_id, const string& name, int uid, string& error, bool attach) { Image * img; int rc; @@ -71,7 +71,7 @@ Image * ImageManager::acquire_image(int vm_id, const string& name, int uid, stri return 0; } - rc = acquire_image(vm_id, img, error); + rc = acquire_image(vm_id, img, error, attach); if ( rc != 0 ) { @@ -84,7 +84,7 @@ Image * ImageManager::acquire_image(int vm_id, const string& name, int uid, stri /* -------------------------------------------------------------------------- */ -int ImageManager::acquire_image(int vm_id, Image *img, string& error) +int ImageManager::acquire_image(int vm_id, Image *img, string& error, bool attach) { int rc = 0; @@ -126,6 +126,15 @@ int ImageManager::acquire_image(int vm_id, Image *img, string& error) break; case Image::LOCKED: + if (attach) + { + oss << "Cannot acquire image " << img->get_oid() + << ", it is locked"; + + error = oss.str(); + rc = -1; + } + img->inc_running(vm_id); if ( img->is_persistent() ) @@ -150,7 +159,19 @@ int ImageManager::acquire_image(int vm_id, Image *img, string& error) break; case Image::USED: + img->inc_running(vm_id); + ipool->update(img); + break; case Image::LOCKED_USED: + if (attach) + { + oss << "Cannot acquire image " << img->get_oid() + << ", it is locked"; + + error = oss.str(); + rc = -1; + } + img->inc_running(vm_id); ipool->update(img); break; diff --git a/src/image/ImagePool.cc b/src/image/ImagePool.cc index c31490c85f..85f5145e94 100644 --- a/src/image/ImagePool.cc +++ b/src/image/ImagePool.cc @@ -297,7 +297,8 @@ int ImagePool::acquire_disk(int vm_id, int uid, int& image_id, Snapshots ** snap, - string& error_str) + string& error_str, + bool attach) { string source; Image * img = 0; @@ -314,7 +315,7 @@ int ImagePool::acquire_disk(int vm_id, if ( disk->vector_value("IMAGE_ID", iid) == 0 ) { - img = imagem->acquire_image(vm_id, iid, error_str); + img = imagem->acquire_image(vm_id, iid, error_str, attach); if ( img == 0 ) { @@ -336,7 +337,7 @@ int ImagePool::acquire_disk(int vm_id, return -1; } - img = imagem->acquire_image(vm_id, source, uiid, error_str); + img = imagem->acquire_image(vm_id, source, uiid, error_str, attach); if ( img == 0 ) { diff --git a/src/vm/VirtualMachineDisk.cc b/src/vm/VirtualMachineDisk.cc index b51b38c3f9..53951c6afb 100644 --- a/src/vm/VirtualMachineDisk.cc +++ b/src/vm/VirtualMachineDisk.cc @@ -751,7 +751,7 @@ int VirtualMachineDisks::get_images(int vm_id, int uid, const std::string& tsys, } if ( ipool->acquire_disk(vm_id, disk, disk_id, image_type, dev_prefix, - uid, image_id, &snapshots, error_str) != 0 ) + uid, image_id, &snapshots, error_str, false) != 0 ) { oss << "DISK " << disk_id << ": " << error_str; error_str = oss.str(); @@ -1076,7 +1076,7 @@ VirtualMachineDisk * VirtualMachineDisks::set_up_attach(int vmid, int uid, VirtualMachineDisk * disk = new VirtualMachineDisk(vdisk, max_disk_id + 1); int rc = ipool->acquire_disk(vmid, disk, max_disk_id + 1, img_type, - dev_prefix, uid, image_id, &snap, error); + dev_prefix, uid, image_id, &snap, error, true); if ( rc != 0 ) { return 0; From 113200229a9b55c29c316008eb5e8772e68bca70 Mon Sep 17 00:00:00 2001 From: Vlastimil Holer <vlastimil.holer@gmail.com> Date: Tue, 23 Jan 2018 15:43:43 +0100 Subject: [PATCH 2/6] B #1222: Avoid using rbd map in tm_mad Ceph --- src/mad/sh/scripts_common.sh | 2 +- src/tm_mad/ceph/mkimage | 27 +++++++++++++++++++++++---- src/tm_mad/ceph/mvds | 11 ++++++++--- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/mad/sh/scripts_common.sh b/src/mad/sh/scripts_common.sh index 5ec094f37a..7333493b72 100644 --- a/src/mad/sh/scripts_common.sh +++ b/src/mad/sh/scripts_common.sh @@ -38,7 +38,7 @@ MD5SUM=${MD5SUM:-md5sum} MKFS=${MKFS:-mkfs} MKISOFS=${MKISOFS:-genisoimage} MKSWAP=${MKSWAP:-mkswap} -QEMU_IMG=${QMEMU_IMG:-qemu-img} +QEMU_IMG=${QEMU_IMG:-qemu-img} RADOS=${RADOS:-rados} RBD=${RBD:-rbd} READLINK=${READLINK:-readlink} diff --git a/src/tm_mad/ceph/mkimage b/src/tm_mad/ceph/mkimage index a24b7c159a..8d87eba7e4 100755 --- a/src/tm_mad/ceph/mkimage +++ b/src/tm_mad/ceph/mkimage @@ -83,16 +83,21 @@ CEPH_CONF="${XPATH_ELEMENTS[j++]}" POOL_NAME="${XPATH_ELEMENTS[j++]:-$POOL_NAME}" RBD_FORMAT="${XPATH_ELEMENTS[j++]:-$RBD_FORMAT}" +QEMU_OPTS='' + if [ -n "$CEPH_USER" ]; then RBD="$RBD --id ${CEPH_USER}" + QEMU_OPTS="${QEMU_OPTS}:id=${CEPH_USER}" fi if [ -n "$CEPH_KEY" ]; then RBD="$RBD --keyfile ${CEPH_KEY}" + QEMU_OPTS="${QEMU_OPTS}:keyfile=${CEPH_KEY}" fi if [ -n "$CEPH_CONF" ]; then RBD="$RBD --conf ${CEPH_CONF}" + QEMU_OPTS="${QEMU_OPTS}:conf=${CEPH_CONF}" fi if [ "$RBD_FORMAT" = "2" ]; then @@ -101,14 +106,27 @@ fi RBD_SOURCE="${POOL_NAME}/one-sys-${VMID}-${DISK_ID}" +ssh_make_path $DST_HOST $DST_DIR + +# if user requested a swap, we need to create a local +# swap formatted image and upload into existing Ceph image +MKFS_CMD=`mkfs_command $DST_PATH $FSTYPE $SIZE` + MKIMAGE_CMD=$(cat <<EOF + set -e -o pipefail + export PATH=/usr/sbin:/sbin:\$PATH - $RBD create $FORMAT_OPT $RBD_SOURCE --size ${SIZE} || exit \$? + + $RBD create $FORMAT_OPT $RBD_SOURCE --size ${SIZE} if [ "$FSTYPE" = "swap" ]; then - $SUDO $RBD map $RBD_SOURCE || exit \$? - $SUDO $MKSWAP -L swap /dev/rbd/$RBD_SOURCE - $SUDO $RBD unmap /dev/rbd/$RBD_SOURCE + ${MKFS_CMD} + + ${QEMU_IMG} convert -n \ + -f raw "${DST_PATH}" \ + -O rbd "rbd:${RBD_SOURCE}${QEMU_OPTS}" + + ${RM} -f "${DST_PATH}" fi EOF ) @@ -116,6 +134,7 @@ EOF DELIMAGE_CMD=$(cat <<EOF export PATH=/usr/sbin:/sbin:\$PATH $RBD rm $RBD_SOURCE + ${RM} -f "${DST_PATH}" EOF ) diff --git a/src/tm_mad/ceph/mvds b/src/tm_mad/ceph/mvds index a2dbfb3f29..c3600ea474 100755 --- a/src/tm_mad/ceph/mvds +++ b/src/tm_mad/ceph/mvds @@ -89,16 +89,21 @@ ORIGINAL_SIZE="${XPATH_ELEMENTS[j++]}" # Copy Image back to the datastore #------------------------------------------------------------------------------- +QEMU_OPTS='' + if [ -n "$CEPH_USER" ]; then RBD="$RBD --id ${CEPH_USER}" + QEMU_OPTS="${QEMU_OPTS}:id=${CEPH_USER}" fi if [ -n "$CEPH_KEY" ]; then RBD="$RBD --keyfile ${CEPH_KEY}" + QEMU_OPTS="${QEMU_OPTS}:keyfile=${CEPH_KEY}" fi if [ -n "$CEPH_CONF" ]; then RBD="$RBD --conf ${CEPH_CONF}" + QEMU_OPTS="${QEMU_OPTS}:conf=${CEPH_CONF}" fi if [ "${TYPE}" = 'FILE' ]; then @@ -111,9 +116,9 @@ if [ "${TYPE}" = 'FILE' ]; then $RBD resize $RBD_SRC --size $SIZE fi - $SUDO $RBD map $RBD_SRC - trap "$SUDO $RBD unmap /dev/rbd/$RBD_SRC" EXIT TERM INT HUP - $DD if=$SRC_PATH of=/dev/rbd/$RBD_SRC bs=64k + ${QEMU_IMG} convert -n \ + -f raw "${SRC_PATH}" \ + -O rbd "rbd:${RBD_SRC}${QEMU_OPTS}" EOF ) else From edd9b65956ddf4c8e8e82c901573327539d5b684 Mon Sep 17 00:00:00 2001 From: Stefan Kooman <stefan@bit.nl> Date: Tue, 23 Jan 2018 17:19:16 +0100 Subject: [PATCH 3/6] Add CEPH_KEY to snap_revert driver operation (I missed this one apperently) --- src/tm_mad/ceph/snap_revert | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tm_mad/ceph/snap_revert b/src/tm_mad/ceph/snap_revert index 2029c688c7..25c88f8bf0 100755 --- a/src/tm_mad/ceph/snap_revert +++ b/src/tm_mad/ceph/snap_revert @@ -107,6 +107,10 @@ if [ -n "$CEPH_USER" ]; then RBD="$RBD --id ${CEPH_USER}" fi +if [ -n "$CEPH_KEY" ]; then + RBD="$RBD --keyfile ${CEPH_KEY}" +fi + if [ -n "$CEPH_CONF" ]; then RBD="$RBD --conf ${CEPH_CONF}" fi From 6d86753f648405b1365bd14482338f3730174c74 Mon Sep 17 00:00:00 2001 From: juanmont <jjmontiel@opennebula.org> Date: Wed, 24 Jan 2018 15:33:12 +0100 Subject: [PATCH 4/6] F #1377: User locks for resources (#1675) --- include/AuthRequest.h | 12 +- include/PoolObjectAuth.h | 5 +- include/PoolObjectSQL.h | 57 +++- include/Request.h | 3 +- include/RequestManagerInfo.h | 2 +- include/RequestManagerLock.h | 257 +++++++++++++++++- include/RequestManagerVirtualMachine.h | 11 +- src/acl/AclManager.cc | 9 + src/authm/AuthManager.cc | 2 +- src/cli/one_helper.rb | 17 ++ src/cli/one_helper/oneimage_helper.rb | 1 + src/cli/one_helper/onemarketapp_helper.rb | 1 + src/cli/one_helper/onetemplate_helper.rb | 1 + src/cli/one_helper/onevm_helper.rb | 1 + src/cli/one_helper/onevmgroup_helper.rb | 1 + src/cli/one_helper/onevnet_helper.rb | 1 + src/cli/one_helper/onevrouter_helper.rb | 1 + src/cli/oneimage | 64 +++++ src/cli/onemarketapp | 64 +++++ src/cli/onetemplate | 64 +++++ src/cli/onevm | 60 ++++ src/cli/onevmgroup | 64 +++++ src/cli/onevnet | 64 +++++ src/cli/onevrouter | 64 +++++ src/image/Image.cc | 12 + src/market/MarketPlaceApp.cc | 5 + .../org/opennebula/client/image/Image.java | 48 ++++ .../client/marketplaceapp/MarketPlaceApp.java | 48 ++++ .../opennebula/client/template/Template.java | 48 ++++ .../opennebula/client/vmgroup/VMGroup.java | 48 ++++ .../client/vnet/VirtualNetwork.java | 48 ++++ .../client/vrouter/VirtualRouter.java | 48 ++++ src/oca/ruby/opennebula/image.rb | 12 +- src/oca/ruby/opennebula/marketplaceapp.rb | 14 +- src/oca/ruby/opennebula/template.rb | 14 +- src/oca/ruby/opennebula/virtual_machine.rb | 18 +- src/oca/ruby/opennebula/virtual_network.rb | 12 +- src/oca/ruby/opennebula/virtual_router.rb | 12 + src/oca/ruby/opennebula/vm_group.rb | 14 +- src/pool/PoolObjectSQL.cc | 65 +++-- src/rm/Request.cc | 8 + src/rm/RequestManager.cc | 35 ++- src/rm/RequestManagerLock.cc | 26 +- src/rm/RequestManagerVirtualMachine.cc | 2 +- .../models/OpenNebulaJSON/ImageJSON.rb | 10 + .../OpenNebulaJSON/MarketPlaceAppJSON.rb | 10 + .../models/OpenNebulaJSON/TemplateJSON.rb | 10 + .../models/OpenNebulaJSON/VMGroupJSON.rb | 10 + .../OpenNebulaJSON/VirtualMachineJSON.rb | 10 + .../OpenNebulaJSON/VirtualNetworkJSON.rb | 10 + .../OpenNebulaJSON/VirtualRouterJSON.rb | 10 + src/sunstone/public/app/opennebula/action.js | 7 + src/sunstone/public/app/opennebula/image.js | 6 + .../public/app/opennebula/marketplaceapp.js | 6 + src/sunstone/public/app/opennebula/network.js | 8 +- .../public/app/opennebula/template.js | 6 + .../public/app/opennebula/virtualrouter.js | 6 + src/sunstone/public/app/opennebula/vm.js | 6 + src/sunstone/public/app/opennebula/vmgroup.js | 6 + src/sunstone/public/app/sunstone.js | 19 +- src/sunstone/public/app/sunstone/buttons.hbs | 6 + src/sunstone/public/app/sunstone/tab.hbs | 9 +- src/sunstone/public/app/tabs/acls-tab.js | 1 + src/sunstone/public/app/tabs/clusters-tab.js | 1 + .../public/app/tabs/datastores-tab.js | 1 + src/sunstone/public/app/tabs/files-tab.js | 1 + src/sunstone/public/app/tabs/groups-tab.js | 1 + src/sunstone/public/app/tabs/hosts-tab.js | 1 + src/sunstone/public/app/tabs/images-tab.js | 1 + .../public/app/tabs/images-tab/actions.js | 4 + .../public/app/tabs/images-tab/buttons.js | 24 ++ .../public/app/tabs/marketplaceapps-tab.js | 1 + .../app/tabs/marketplaceapps-tab/actions.js | 4 + .../app/tabs/marketplaceapps-tab/buttons.js | 24 ++ .../public/app/tabs/marketplaces-tab.js | 1 + .../public/app/tabs/oneflow-services-tab.js | 1 + .../public/app/tabs/oneflow-templates-tab.js | 1 + src/sunstone/public/app/tabs/secgroups-tab.js | 1 + src/sunstone/public/app/tabs/templates-tab.js | 1 + .../app/tabs/templates-tab/actions-common.js | 10 +- .../public/app/tabs/templates-tab/buttons.js | 24 ++ src/sunstone/public/app/tabs/users-tab.js | 1 + src/sunstone/public/app/tabs/vdcs-tab.js | 1 + src/sunstone/public/app/tabs/vmgroup-tab.js | 1 + .../public/app/tabs/vmgroup-tab/actions.js | 6 +- .../public/app/tabs/vmgroup-tab/buttons.js | 24 ++ src/sunstone/public/app/tabs/vms-tab.js | 1 + .../public/app/tabs/vms-tab/actions.js | 4 + .../public/app/tabs/vms-tab/buttons.js | 23 ++ .../public/app/tabs/vms-tab/hooks/header.js | 9 + src/sunstone/public/app/tabs/vnets-tab.js | 1 + .../public/app/tabs/vnets-tab/actions.js | 4 + .../public/app/tabs/vnets-tab/buttons.js | 24 ++ .../public/app/tabs/vrouter-templates-tab.js | 1 + src/sunstone/public/app/tabs/vrouters-tab.js | 1 + .../public/app/tabs/vrouters-tab/actions.js | 4 + .../public/app/tabs/vrouters-tab/buttons.js | 24 ++ src/sunstone/public/app/tabs/zones-tab.js | 1 + src/sunstone/public/app/utils/hooks/header.js | 8 + src/sunstone/public/app/utils/humanize.js | 25 +- src/vm/VirtualMachine.cc | 4 + src/vm_group/VMGroup.cc | 5 + src/vm_template/VMTemplate.cc | 3 + src/vnm/VirtualNetwork.cc | 4 + src/vrouter/VirtualRouter.cc | 5 + 105 files changed, 1712 insertions(+), 93 deletions(-) diff --git a/include/AuthRequest.h b/include/AuthRequest.h index e5a0e92cac..f30317dc1a 100644 --- a/include/AuthRequest.h +++ b/include/AuthRequest.h @@ -46,10 +46,14 @@ public: */ enum Operation { - USE = 0x1LL, /**< Auth. to use an object */ - MANAGE = 0x2LL, /**< Auth. to perform management actions */ - ADMIN = 0x4LL, /**< Auth. to perform administrative actions */ - CREATE = 0x8LL /**< Auth. to create an object */ + USE = 0x1LL, /**< Auth. to use an object */ + USE_NO_LCK = 0x11LL, /**< Auth. to use an object no lockable */ + MANAGE = 0x2LL, /**< Auth. to perform management actions */ + MANAGE_NO_LCK = 0x12LL, /**< Auth. to perform management actions of an object no lockable */ + ADMIN = 0x4LL, /**< Auth. to perform administrative actions */ + ADMIN_NO_LCK = 0x14LL, /**< Auth. to perform administrative actions of an object no lockable */ + CREATE = 0x8LL, /**< Auth. to create an object */ + CREATE_NO_LCK = 0x18LL /**< Auth. to create an object of an object no lockable */ }; static string operation_to_str(Operation op) diff --git a/include/PoolObjectAuth.h b/include/PoolObjectAuth.h index 79070e9dc3..2a6185f978 100644 --- a/include/PoolObjectAuth.h +++ b/include/PoolObjectAuth.h @@ -45,7 +45,8 @@ public: other_a(0), disable_all_acl(false), disable_cluster_acl(false), - disable_group_acl(false) {}; + disable_group_acl(false), + locked(0) {}; void get_acl_rules(AclRule& owner_rule, AclRule& group_rule, @@ -81,6 +82,8 @@ public: bool disable_all_acl; // All objects of this type (e.g. NET/*) bool disable_cluster_acl; // All objects in a cluster (e.g. NET/%100) bool disable_group_acl; // All objects own by this group (e.g. NET/@101) + + int locked; }; #endif /*POOL_OBJECT_AUTH_H_*/ diff --git a/include/PoolObjectSQL.h b/include/PoolObjectSQL.h index d01d175c65..cd130d8ee4 100644 --- a/include/PoolObjectSQL.h +++ b/include/PoolObjectSQL.h @@ -70,6 +70,19 @@ public: VMGROUP = 0x0020000000000000LL }; + /** + * OpenNebula objects. This definitions are used for define the level of lock + */ + enum LockStates + { + ST_NONE = 0x0LL, + ST_USE = 0x1LL, + ST_MANAGE = 0x2LL, + ST_ADMIN = 0x4LL + }; + + static const long int LockableObject; + static string type_to_str(ObjectType ob) { switch (ob) @@ -96,6 +109,18 @@ public: } }; + static string lock_state_to_str(LockStates ob) + { + switch (ob) + { + case ST_NONE: return "NONE" ; break; + case ST_USE: return "USE" ; break; + case ST_MANAGE: return "MANAGE" ; break; + case ST_ADMIN: return "ADMIN" ; break; + default: return ""; + } + }; + /* ---------------------------------------------------------------------- */ PoolObjectSQL(int id, @@ -126,9 +151,10 @@ public: other_m(0), other_a(0), obj_template(0), - locked(false), - lock_owner(""), - lock_expires(0), + locked(LockStates::ST_NONE), + lock_owner(-1), + lock_req_id(-1), + lock_time(0), table(_table) { pthread_mutex_init(&mutex,0); @@ -520,7 +546,7 @@ public: * * @return 0 if the lock was granted, -1 if the object is already locked */ - int lock_db(const string& owner); + int lock_db(const int owner,const int req_id, const int level); /** * Unlocks the DB lock for external applications. The object must be locked @@ -528,7 +554,17 @@ public: * * @param owner String to identify who requested the lock */ - void unlock_db(const string& owner); + void unlock_db(const int owner, const int req_id); + + /** + * Unlocks the DB lock for external applications. The object must be locked + * (internal memory mutex) before this method is called + * + * @param owner String to identify who requested the lock + */ + LockStates get_lock_state(){ + return locked; + } protected: @@ -730,17 +766,22 @@ protected: /** * Flag for the DB lock */ - bool locked; + LockStates locked; /** * Owner of the DB lock */ - string lock_owner; + int lock_owner; + + /** + * Owner of the DB lock + */ + int lock_req_id; /** * Expiration time for the DB lock */ - time_t lock_expires; + time_t lock_time; private: /** diff --git a/include/Request.h b/include/Request.h index ad7e671ed5..b5f6ab2e65 100644 --- a/include/Request.h +++ b/include/Request.h @@ -131,7 +131,8 @@ public: ACTION = 0x0800, XML_RPC_API = 0x1000, INTERNAL = 0x2000, - ALLOCATE = 0x4000 + ALLOCATE = 0x4000, + LOCKED = 0x8000 }; /** diff --git a/include/RequestManagerInfo.h b/include/RequestManagerInfo.h index 6c36e74af4..76ec93e6a5 100644 --- a/include/RequestManagerInfo.h +++ b/include/RequestManagerInfo.h @@ -33,7 +33,7 @@ protected: const string& help) :Request(method_name, "A:si", help) { - auth_op = AuthRequest::USE; + auth_op = AuthRequest::USE_NO_LCK; leader_only = false; }; diff --git a/include/RequestManagerLock.h b/include/RequestManagerLock.h index 55d6a91991..d690d3206a 100644 --- a/include/RequestManagerLock.h +++ b/include/RequestManagerLock.h @@ -33,7 +33,7 @@ protected: const string& help) :Request(method_name, "A:sis", help) { - auth_op = AuthRequest::MANAGE; + auth_op = AuthRequest::MANAGE_NO_LCK; }; ~RequestManagerLock(){}; @@ -43,7 +43,10 @@ protected: void request_execute(xmlrpc_c::paramList const& _paramList, RequestAttributes& att); - virtual int lock_db(PoolObjectSQL * object, const string& owner) = 0; + int lock_db(PoolObjectSQL * object, const int owner, const int req_id, const int level) + { + return object->lock_db(owner, req_id, level); + }; }; /* ------------------------------------------------------------------------- */ @@ -54,9 +57,9 @@ class RequestManagerUnlock: public Request protected: RequestManagerUnlock(const string& method_name, const string& help) - :Request(method_name, "A:sis", help) + :Request(method_name, "A:sii", help) { - auth_op = AuthRequest::MANAGE; + auth_op = AuthRequest::MANAGE_NO_LCK; }; ~RequestManagerUnlock(){}; @@ -66,7 +69,10 @@ protected: void request_execute(xmlrpc_c::paramList const& _paramList, RequestAttributes& att); - virtual void unlock_db(PoolObjectSQL * object, const string& owner) = 0; + void unlock_db(PoolObjectSQL * object, const int owner, const int req_id) + { + object->unlock_db(owner, req_id); + }; }; /* ------------------------------------------------------------------------- */ @@ -85,11 +91,6 @@ public: }; ~DocumentLock(){}; - - int lock_db(PoolObjectSQL * object, const string& owner) - { - return static_cast<Document*>(object)->lock_db(owner); - }; }; /* ------------------------------------------------------------------------- */ @@ -108,15 +109,241 @@ public: }; ~DocumentUnlock(){}; - - void unlock_db(PoolObjectSQL * object, const string& owner) - { - return static_cast<Document*>(object)->unlock_db(owner); - }; }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ + +class VirtualMachineLock: public RequestManagerLock +{ +public: + VirtualMachineLock(): + RequestManagerLock("one.vm.lock", + "Lock a VM"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::VM; + pool = nd.get_vmpool(); + }; + + ~VirtualMachineLock(){}; +}; +/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ +class VirtualMachineUnlock: public RequestManagerUnlock +{ +public: + VirtualMachineUnlock(): + RequestManagerUnlock("one.vm.unlock", + "Unlock a VM"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::VM; + pool = nd.get_vmpool(); + }; + + ~VirtualMachineUnlock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VMTemplateLock: public RequestManagerLock +{ +public: + VMTemplateLock(): + RequestManagerLock("one.template.lock", + "Lock a Template"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::TEMPLATE; + pool = nd.get_tpool(); + }; + + ~VMTemplateLock(){}; +}; +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VMTemplateUnlock: public RequestManagerUnlock +{ +public: + VMTemplateUnlock(): + RequestManagerUnlock("one.template.unlock", + "Unlock a Template"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::TEMPLATE; + pool = nd.get_tpool(); + }; + + ~VMTemplateUnlock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VirtualNetworkLock: public RequestManagerLock +{ +public: + VirtualNetworkLock(): + RequestManagerLock("one.vn.lock", + "Lock a VNet"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::NET; + pool = nd.get_vnpool(); + }; + + ~VirtualNetworkLock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VirtualNetworkUnlock: public RequestManagerUnlock +{ +public: + VirtualNetworkUnlock(): + RequestManagerUnlock("one.vn.unlock", + "Unlock a VNet"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::NET; + pool = nd.get_vnpool(); + }; + + ~VirtualNetworkUnlock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class ImageLock: public RequestManagerLock +{ +public: + ImageLock(): + RequestManagerLock("one.image.lock", + "Lock a Image"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::IMAGE; + pool = nd.get_ipool(); + }; + + ~ImageLock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class ImageUnlock: public RequestManagerUnlock +{ +public: + ImageUnlock(): + RequestManagerUnlock("one.image.unlock", + "Unlock a Image"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::IMAGE; + pool = nd.get_ipool(); + }; + + ~ImageUnlock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class MarketPlaceAppLock: public RequestManagerLock +{ +public: + MarketPlaceAppLock(): + RequestManagerLock("one.marketapp.lock", + "Lock a MarketPlaceApp"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + pool = nd.get_apppool(); + }; + + ~MarketPlaceAppLock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class MarketPlaceAppUnlock: public RequestManagerUnlock +{ +public: + MarketPlaceAppUnlock(): + RequestManagerUnlock("one.marketapp.unlock", + "Unlock a MarketPlaceApp"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::MARKETPLACEAPP; + pool = nd.get_apppool(); + }; + + ~MarketPlaceAppUnlock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VirtualRouterLock: public RequestManagerLock +{ +public: + VirtualRouterLock(): + RequestManagerLock("one.vrouter.lock", + "Lock a VirtualRouter"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::VROUTER; + pool = nd.get_vrouterpool(); + }; + + ~VirtualRouterLock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VirtualRouterUnlock: public RequestManagerUnlock +{ +public: + VirtualRouterUnlock(): + RequestManagerUnlock("one.vrouter.unlock", + "Unlock a VirtualRouter"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::VROUTER; + pool = nd.get_vrouterpool(); + }; + + ~VirtualRouterUnlock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VMGroupLock: public RequestManagerLock +{ +public: + VMGroupLock(): + RequestManagerLock("one.vmgroup.lock", + "Lock a VMGroup"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::VMGROUP; + pool = nd.get_vmgrouppool(); + }; + + ~VMGroupLock(){}; +}; + +/* -------------------------------------------------------------------------- */ +/* -------------------------------------------------------------------------- */ + +class VMGroupUnlock: public RequestManagerUnlock +{ +public: + VMGroupUnlock(): + RequestManagerUnlock("one.vmgroup.unlock", + "Unlock a VMGroup"){ + Nebula& nd = Nebula::instance(); + auth_object = PoolObjectSQL::VMGROUP; + pool = nd.get_vmgrouppool(); + }; + + ~VMGroupUnlock(){}; +}; #endif diff --git a/include/RequestManagerVirtualMachine.h b/include/RequestManagerVirtualMachine.h index 069df26e37..52e0ed3009 100644 --- a/include/RequestManagerVirtualMachine.h +++ b/include/RequestManagerVirtualMachine.h @@ -32,7 +32,7 @@ protected: RequestManagerVirtualMachine(const string& method_name, const string& help, const string& params) - :Request(method_name,params,help) + :Request(method_name, params, help) { Nebula& nd = Nebula::instance(); pool = nd.get_vmpool(); @@ -193,13 +193,17 @@ public: RequestManagerVirtualMachine("one.vm.monitoring", "Returns the virtual machine monitoring records", "A:si"){ - auth_op = AuthRequest::USE; + auth_op = AuthRequest::USE_NO_LCK; }; ~VirtualMachineMonitoring(){}; void request_execute( xmlrpc_c::paramList const& paramList, RequestAttributes& att); + + virtual bool is_locked(xmlrpc_c::paramList const& paramList, RequestAttributes& att){ + return false; + }; }; /* ------------------------------------------------------------------------- */ @@ -521,9 +525,6 @@ public: RequestAttributes& att); }; -/* -------------------------------------------------------------------------- */ -/* -------------------------------------------------------------------------- */ - class VirtualMachineDiskResize : public RequestManagerVirtualMachine { public: diff --git a/src/acl/AclManager.cc b/src/acl/AclManager.cc index bb47f9053d..404809d1a8 100644 --- a/src/acl/AclManager.cc +++ b/src/acl/AclManager.cc @@ -228,6 +228,15 @@ const bool AclManager::authorize( long long user_req; long long resource_oid_req; + if (static_cast<long long int>(op) & 0x10LL) //No lockable object + { + op = static_cast<AuthRequest::Operation>(op & 0x0FLL); + } + else if (obj_perms.locked > 0 && obj_perms.locked <= static_cast<long long int>(op)) + { + return false; + } + if ( obj_perms.oid >= 0 ) { resource_oid_req = obj_perms.obj_type | diff --git a/src/authm/AuthManager.cc b/src/authm/AuthManager.cc index 499678cee9..e91124839e 100644 --- a/src/authm/AuthManager.cc +++ b/src/authm/AuthManager.cc @@ -56,7 +56,7 @@ void AuthRequest::add_auth(Operation op, oss << ob_perms.oid << ":"; } - oss << operation_to_str(op) << ":"; + oss << operation_to_str(static_cast<AuthRequest::Operation>(op & 0x0FLL)) << ":"; oss << ob_perms.uid << ":"; diff --git a/src/cli/one_helper.rb b/src/cli/one_helper.rb index d80e24e3b9..9b786703b7 100644 --- a/src/cli/one_helper.rb +++ b/src/cli/one_helper.rb @@ -1267,4 +1267,21 @@ EOT return OpenNebula::Error.new("Remote server error: #{error_message}") end end + + def OpenNebulaHelper.level_lock_to_str(str) + level = str.to_i + if level == 0 + "None" + elsif level == 1 + "Use" + elsif level == 2 + "Manage" + elsif level == 3 + "Admin" + elsif level == 4 + "All" + else + "-" + end + end end diff --git a/src/cli/one_helper/oneimage_helper.rb b/src/cli/one_helper/oneimage_helper.rb index fdb0ee0087..c72743b84c 100644 --- a/src/cli/one_helper/oneimage_helper.rb +++ b/src/cli/one_helper/oneimage_helper.rb @@ -265,6 +265,7 @@ class OneImageHelper < OpenNebulaHelper::OneHelper puts str % ["NAME", image.name] puts str % ["USER", image['UNAME']] puts str % ["GROUP",image['GNAME']] + puts str % ["LOCK", OpenNebulaHelper.level_lock_to_str(image['LOCK/LOCKED'])] puts str % ["DATASTORE",image['DATASTORE']] puts str % ["TYPE", image.type_str] puts str % ["REGISTER TIME", diff --git a/src/cli/one_helper/onemarketapp_helper.rb b/src/cli/one_helper/onemarketapp_helper.rb index 934b4c15f8..e0fbacfdde 100644 --- a/src/cli/one_helper/onemarketapp_helper.rb +++ b/src/cli/one_helper/onemarketapp_helper.rb @@ -150,6 +150,7 @@ class OneMarketPlaceAppHelper < OpenNebulaHelper::OneHelper puts str % ["GROUP", app['GNAME']] puts str % ["MARKETPLACE", app['MARKETPLACE']] puts str % ["STATE", OneMarketPlaceAppHelper.state_to_str(app["STATE"])] + puts str % ["LOCK", OpenNebulaHelper.level_lock_to_str(app['LOCK/LOCKED'])] puts diff --git a/src/cli/one_helper/onetemplate_helper.rb b/src/cli/one_helper/onetemplate_helper.rb index eefd1fa61b..f5ceb4426c 100644 --- a/src/cli/one_helper/onetemplate_helper.rb +++ b/src/cli/one_helper/onetemplate_helper.rb @@ -321,6 +321,7 @@ EOT puts str % ["NAME", template.name] puts str % ["USER", template['UNAME']] puts str % ["GROUP", template['GNAME']] + puts str % ["LOCK", OpenNebulaHelper.level_lock_to_str(template['LOCK/LOCKED'])] puts str % ["REGISTER TIME", OpenNebulaHelper.time_to_str(template['REGTIME'])] puts diff --git a/src/cli/one_helper/onevm_helper.rb b/src/cli/one_helper/onevm_helper.rb index 40b7da279b..6969dd6db0 100644 --- a/src/cli/one_helper/onevm_helper.rb +++ b/src/cli/one_helper/onevm_helper.rb @@ -516,6 +516,7 @@ in the frontend machine. puts str % ["GROUP", vm['GNAME']] puts str % ["STATE", vm.state_str] puts str % ["LCM_STATE", vm.lcm_state_str] + puts str % ["LOCK", OpenNebulaHelper.level_lock_to_str(vm['LOCK/LOCKED'])] puts str % ["RESCHED", OpenNebulaHelper.boolean_to_str(vm['RESCHED'])] puts str % ["HOST", vm['/VM/HISTORY_RECORDS/HISTORY[last()]/HOSTNAME']] if diff --git a/src/cli/one_helper/onevmgroup_helper.rb b/src/cli/one_helper/onevmgroup_helper.rb index 23dc54cce4..ea8c01ed11 100644 --- a/src/cli/one_helper/onevmgroup_helper.rb +++ b/src/cli/one_helper/onevmgroup_helper.rb @@ -102,6 +102,7 @@ class OneVMGroupHelper < OpenNebulaHelper::OneHelper puts str % ["NAME", vmgroup.name] puts str % ["USER", vmgroup['UNAME']] puts str % ["GROUP", vmgroup['GNAME']] + puts str % ["LOCK", OpenNebulaHelper.level_lock_to_str(vmgroup['LOCK/LOCKED'])] CLIHelper.print_header(str_h1 % "PERMISSIONS",false) diff --git a/src/cli/one_helper/onevnet_helper.rb b/src/cli/one_helper/onevnet_helper.rb index 2799f46eac..0647ceeb57 100644 --- a/src/cli/one_helper/onevnet_helper.rb +++ b/src/cli/one_helper/onevnet_helper.rb @@ -219,6 +219,7 @@ class OneVNetHelper < OpenNebulaHelper::OneHelper puts str % ["NAME", vn['NAME']] puts str % ["USER", vn['UNAME']] puts str % ["GROUP", vn['GNAME']] + puts str % ["LOCK", OpenNebulaHelper.level_lock_to_str(vn['LOCK/LOCKED'])] puts str % ["CLUSTERS", OpenNebulaHelper.clusters_str(vn.retrieve_elements("CLUSTERS/ID"))] puts str % ["BRIDGE", vn["BRIDGE"]] diff --git a/src/cli/one_helper/onevrouter_helper.rb b/src/cli/one_helper/onevrouter_helper.rb index c08d41a915..34a1f1f446 100644 --- a/src/cli/one_helper/onevrouter_helper.rb +++ b/src/cli/one_helper/onevrouter_helper.rb @@ -109,6 +109,7 @@ class OneVirtualRouterHelper < OpenNebulaHelper::OneHelper puts str % ["NAME", obj.name] puts str % ["USER", obj['UNAME']] puts str % ["GROUP", obj['GNAME']] + puts str % ["LOCK", OpenNebulaHelper.level_lock_to_str(obj['LOCK/LOCKED'])] puts CLIHelper.print_header(str_h1 % "PERMISSIONS",false) diff --git a/src/cli/oneimage b/src/cli/oneimage index fa0d6632b1..de9d2d8850 100755 --- a/src/cli/oneimage +++ b/src/cli/oneimage @@ -41,6 +41,30 @@ cmd=CommandParser::CmdParser.new(ARGV) do helper.set_client(options) end + USE={ + :name => "use", + :large => "--use", + :description => "lock use actions" + } + + MANAGE={ + :name => "manage", + :large => "--manage", + :description => "lock manage actions" + } + + ADMIN={ + :name => "admin", + :large => "--admin", + :description => "lock admin actions" + } + + ALL={ + :name => "all", + :large => "--all", + :description => "lock all actions" + } + ######################################################################## # Global Options ######################################################################## @@ -357,4 +381,44 @@ cmd=CommandParser::CmdParser.new(ARGV) do command :top, top_desc, [:filterflag, nil], :options=>list_options do helper.list_pool(options, true, args[0]) end + + lock_desc = <<-EOT.unindent + Locks a VM with differents levels for lock any actions with this VM, show and + monitoring never will be locked. + Valid states are: All. + Levels: + [Use]: locks Admin, Manage and Use actions. + [Manage]: locks Manage and Use actions. + [Admin]: locks only Admin actions. + EOT + + command :lock, lock_desc, :vmid, + :options => [USE, MANAGE, ADMIN, ALL] do + helper.perform_action(args[0],options,"Image locked") do |i| + if !options[:use].nil? + level = 1 + elsif !options[:manage].nil? + level = 2 + elsif !options[:admin].nil? + level = 3 + elsif !options[:all].nil? + level = 4 + else + STDERR.puts "Need to level of lock." + exit -1 + end + i.lock(level) + end + end + + unlock_desc = <<-EOT.unindent + Unlocks a VM for unlock any actions with this VM. + Valid states are: All. + EOT + + command :unlock, unlock_desc, :vmid do + helper.perform_action(args[0],options,"Image unlocked") do |i| + i.unlock + end + end end diff --git a/src/cli/onemarketapp b/src/cli/onemarketapp index b209c4d567..7a34785782 100755 --- a/src/cli/onemarketapp +++ b/src/cli/onemarketapp @@ -44,6 +44,30 @@ CommandParser::CmdParser.new(ARGV) do helper.set_client(options) end + USE={ + :name => "use", + :large => "--use", + :description => "lock use actions" + } + + MANAGE={ + :name => "manage", + :large => "--manage", + :description => "lock manage actions" + } + + ADMIN={ + :name => "admin", + :large => "--admin", + :description => "lock admin actions" + } + + ALL={ + :name => "all", + :large => "--all", + :description => "lock all actions" + } + ######################################################################## # Global Options ######################################################################## @@ -279,4 +303,44 @@ CommandParser::CmdParser.new(ARGV) do obj.disable end end + + lock_desc = <<-EOT.unindent + Locks a VM with differents levels for lock any actions with this VM, show and + monitoring never will be locked. + Valid states are: All. + Levels: + [Use]: locks Admin, Manage and Use actions. + [Manage]: locks Manage and Use actions. + [Admin]: locks only Admin actions. + EOT + + command :lock, lock_desc, :appid, + :options => [USE, MANAGE, ADMIN, ALL] do + helper.perform_action(args[0],options,"MarketPlaceApp locked") do |app| + if !options[:use].nil? + level = 1 + elsif !options[:manage].nil? + level = 2 + elsif !options[:admin].nil? + level = 3 + elsif !options[:all].nil? + level = 4 + else + STDERR.puts "Need to level of lock." + exit -1 + end + app.lock(level) + end + end + + unlock_desc = <<-EOT.unindent + Unlocks a VM for unlock any actions with this VM. + Valid states are: All. + EOT + + command :unlock, unlock_desc, :vmid do + helper.perform_action(args[0],options,"MarketPlaceApp unlocked") do |app| + app.unlock + end + end end diff --git a/src/cli/onetemplate b/src/cli/onetemplate index b8a7b8aa5b..0e9ecb2957 100755 --- a/src/cli/onetemplate +++ b/src/cli/onetemplate @@ -41,6 +41,30 @@ cmd=CommandParser::CmdParser.new(ARGV) do helper.set_client(options) end + USE={ + :name => "use", + :large => "--use", + :description => "lock use actions" + } + + MANAGE={ + :name => "manage", + :large => "--manage", + :description => "lock manage actions" + } + + ADMIN={ + :name => "admin", + :large => "--admin", + :description => "lock admin actions" + } + + ALL={ + :name => "all", + :large => "--all", + :description => "lock all actions" + } + ######################################################################## # Global Options ######################################################################## @@ -341,4 +365,44 @@ cmd=CommandParser::CmdParser.new(ARGV) do command :top, top_desc, [:filterflag, nil], :options=>list_options do helper.list_pool(options, true, args[0]) end + + lock_desc = <<-EOT.unindent + Locks a VM with differents levels for lock any actions with this VM, show and + monitoring never will be locked. + Valid states are: All. + Levels: + [Use]: locks Admin, Manage and Use actions. + [Manage]: locks Manage and Use actions. + [Admin]: locks only Admin actions. + EOT + + command :lock, lock_desc, :templateid, + :options => [USE, MANAGE, ADMIN, ALL] do + helper.perform_action(args[0],options,"Template locked") do |t| + if !options[:use].nil? + level = 1 + elsif !options[:manage].nil? + level = 2 + elsif !options[:admin].nil? + level = 3 + elsif !options[:all].nil? + level = 4 + else + STDERR.puts "Need to level of lock." + exit -1 + end + t.lock(level) + end + end + + unlock_desc = <<-EOT.unindent + Unlocks a VM for unlock any actions with this VM. + Valid states are: All. + EOT + + command :unlock, unlock_desc, :templateid do + helper.perform_action(args[0],options,"Template unlocked") do |t| + t.unlock + end + end end diff --git a/src/cli/onevm b/src/cli/onevm index dc1eedaff5..4e705eb010 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -137,6 +137,30 @@ cmd=CommandParser::CmdParser.new(ARGV) do :description => "Make the new images persistent" } + USE={ + :name => "use", + :large => "--use", + :description => "lock use actions" + } + + MANAGE={ + :name => "manage", + :large => "--manage", + :description => "lock manage actions" + } + + ADMIN={ + :name => "admin", + :large => "--admin", + :description => "lock admin actions" + } + + ALL={ + :name => "all", + :large => "--all", + :description => "lock all actions" + } + ######################################################################## # Global Options ######################################################################## @@ -996,6 +1020,42 @@ cmd=CommandParser::CmdParser.new(ARGV) do end end + lock_desc = <<-EOT.unindent + Locks a VM with differents levels for lock any actions with this VM, show and + monitoring never will be locked. + Aalid states are: All. + EOT + + command :lock, lock_desc, :vmid, + :options => [USE, MANAGE, ADMIN, ALL] do + helper.perform_action(args[0],options,"VM locked") do |vm| + if !options[:use].nil? + level = 1 + elsif !options[:manage].nil? + level = 2 + elsif !options[:admin].nil? + level = 3 + elsif !options[:all].nil? + level = 4 + else + STDERR.puts "Need to level of lock." + exit -1 + end + vm.lock(level) + end + end + + unlock_desc = <<-EOT.unindent + Unlocks a VM for unlock any actions with this VM. + Valid states are: All. + EOT + + command :unlock, unlock_desc, :vmid do + helper.perform_action(args[0],options,"VM unlocked") do |vm| + vm.unlock + end + end + # Deprecated commands deprecated_command(:shutdown, 'terminate') diff --git a/src/cli/onevmgroup b/src/cli/onevmgroup index a9edb33217..7e15c27e18 100755 --- a/src/cli/onevmgroup +++ b/src/cli/onevmgroup @@ -40,6 +40,30 @@ cmd=CommandParser::CmdParser.new(ARGV) do helper.set_client(options) end + USE={ + :name => "use", + :large => "--use", + :description => "lock use actions" + } + + MANAGE={ + :name => "manage", + :large => "--manage", + :description => "lock manage actions" + } + + ADMIN={ + :name => "admin", + :large => "--admin", + :description => "lock admin actions" + } + + ALL={ + :name => "all", + :large => "--all", + :description => "lock all actions" + } + ######################################################################## # Global Options ######################################################################## @@ -182,4 +206,44 @@ cmd=CommandParser::CmdParser.new(ARGV) do o.rename(args[1]) end end + + lock_desc = <<-EOT.unindent + Locks a VM with differents levels for lock any actions with this VM, show and + monitoring never will be locked. + Valid states are: All. + Levels: + [Use]: locks Admin, Manage and Use actions. + [Manage]: locks Manage and Use actions. + [Admin]: locks only Admin actions. + EOT + + command :lock, lock_desc, :vmid, + :options => [USE, MANAGE, ADMIN, ALL] do + helper.perform_action(args[0],options,"VMGroup locked") do |vmg| + if !options[:use].nil? + level = 1 + elsif !options[:manage].nil? + level = 2 + elsif !options[:admin].nil? + level = 3 + elsif !options[:all].nil? + level = 4 + else + STDERR.puts "Need to level of lock." + exit -1 + end + vmg.lock(level) + end + end + + unlock_desc = <<-EOT.unindent + Unlocks a VM for unlock any actions with this VM. + Valid states are: All. + EOT + + command :unlock, unlock_desc, :vmid do + helper.perform_action(args[0],options,"VMGroup unlocked") do |vmg| + vmg.unlock + end + end end diff --git a/src/cli/onevnet b/src/cli/onevnet index d09e9ad7fc..3a5db4e529 100755 --- a/src/cli/onevnet +++ b/src/cli/onevnet @@ -41,6 +41,30 @@ cmd=CommandParser::CmdParser.new(ARGV) do helper.set_client(options) end + USE={ + :name => "use", + :large => "--use", + :description => "lock use actions" + } + + MANAGE={ + :name => "manage", + :large => "--manage", + :description => "lock manage actions" + } + + ADMIN={ + :name => "admin", + :large => "--admin", + :description => "lock admin actions" + } + + ALL={ + :name => "all", + :large => "--all", + :description => "lock all actions" + } + ######################################################################## # Global Options ######################################################################## @@ -422,4 +446,44 @@ cmd=CommandParser::CmdParser.new(ARGV) do o.rename(args[1]) end end + + lock_desc = <<-EOT.unindent + Locks a VM with differents levels for lock any actions with this VM, show and + monitoring never will be locked. + Valid states are: All. + Levels: + [Use]: locks Admin, Manage and Use actions. + [Manage]: locks Manage and Use actions. + [Admin]: locks only Admin actions. + EOT + + command :lock, lock_desc, :vnetid, + :options => [USE, MANAGE, ADMIN, ALL] do + helper.perform_action(args[0],options,"VNet locked") do |vnet| + if !options[:use].nil? + level = 1 + elsif !options[:manage].nil? + level = 2 + elsif !options[:admin].nil? + level = 3 + elsif !options[:all].nil? + level = 4 + else + STDERR.puts "Need to level of lock." + exit -1 + end + vnet.lock(level) + end + end + + unlock_desc = <<-EOT.unindent + Unlocks a VM for unlock any actions with this VM. + Valid states are: All. + EOT + + command :unlock, unlock_desc, :vnetid do + helper.perform_action(args[0],options,"VNet unlocked") do |vnet| + vnet.unlock + end + end end diff --git a/src/cli/onevrouter b/src/cli/onevrouter index 5088fcd985..3a8c99d8a9 100755 --- a/src/cli/onevrouter +++ b/src/cli/onevrouter @@ -42,6 +42,30 @@ cmd=CommandParser::CmdParser.new(ARGV) do helper.set_client(options) end + USE={ + :name => "use", + :large => "--use", + :description => "lock use actions" + } + + MANAGE={ + :name => "manage", + :large => "--manage", + :description => "lock manage actions" + } + + ADMIN={ + :name => "admin", + :large => "--admin", + :description => "lock admin actions" + } + + ALL={ + :name => "all", + :large => "--all", + :description => "lock all actions" + } + ######################################################################## # Global Options ######################################################################## @@ -314,4 +338,44 @@ cmd=CommandParser::CmdParser.new(ARGV) do command :top, top_desc, [:filterflag, nil], :options=>list_options do helper.list_pool(options, true, args[0]) end + + lock_desc = <<-EOT.unindent + Locks a VM with differents levels for lock any actions with this VM, show and + monitoring never will be locked. + Valid states are: All. + Levels: + [Use]: locks Admin, Manage and Use actions. + [Manage]: locks Manage and Use actions. + [Admin]: locks only Admin actions. + EOT + + command :lock, lock_desc, :vmid, + :options => [USE, MANAGE, ADMIN, ALL] do + helper.perform_action(args[0],options,"VRouter locked") do |vr| + if !options[:use].nil? + level = 1 + elsif !options[:manage].nil? + level = 2 + elsif !options[:admin].nil? + level = 3 + elsif !options[:all].nil? + level = 4 + else + STDERR.puts "Need to level of lock." + exit -1 + end + vr.lock(level) + end + end + + unlock_desc = <<-EOT.unindent + Unlocks a VM for unlock any actions with this VM. + valid states are: All. + EOT + + command :unlock, unlock_desc, :vmid do + helper.perform_action(args[0],options,"VRouter unlocked") do |vr| + vr.unlock + end + end end diff --git a/src/image/Image.cc b/src/image/Image.cc index 60a9ba4d93..7ad3f2b945 100644 --- a/src/image/Image.cc +++ b/src/image/Image.cc @@ -201,6 +201,7 @@ int Image::insert(SqlDB *db, string& error_str) } state = LOCKED; //LOCKED till the ImageManager copies it to the Repository + lock_db(-1,-1, PoolObjectSQL::LockStates::ST_USE); //-------------------------------------------------------------------------- // Insert the Image @@ -329,6 +330,7 @@ string& Image::to_xml(string& xml) const string clone_collection_xml; string app_clone_collection_xml; string snapshots_xml; + string lock_str; oss << "<IMAGE>" << @@ -338,6 +340,7 @@ string& Image::to_xml(string& xml) const "<UNAME>" << uname << "</UNAME>" << "<GNAME>" << gname << "</GNAME>" << "<NAME>" << name << "</NAME>" << + lock_db_to_xml(lock_str) << perms_to_xml(perms_xml) << "<TYPE>" << type << "</TYPE>" << "<DISK_TYPE>" << disk_type << "</DISK_TYPE>" << @@ -409,6 +412,7 @@ int Image::from_xml(const string& xml) rc += xpath(ds_id, "/IMAGE/DATASTORE_ID", -1); rc += xpath(ds_name, "/IMAGE/DATASTORE", "not_found"); + rc += lock_db_from_xml(); // Permissions rc += perms_from_xml(); @@ -804,6 +808,13 @@ void Image::set_state(ImageState _state) { lcm->trigger(LCMAction::DISK_LOCK_FAILURE, *i); } + } else if( _state == LOCKED) + { + lock_db(-1,-1, PoolObjectSQL::LockStates::ST_USE); + } + if (_state != LOCKED ) + { + unlock_db(-1,-1); } state = _state; @@ -820,6 +831,7 @@ void Image::set_state_unlock() switch (state) { case LOCKED: + unlock_db(-1,-1); set_state(READY); break; diff --git a/src/market/MarketPlaceApp.cc b/src/market/MarketPlaceApp.cc index e4dbd866c9..a08c230b27 100644 --- a/src/market/MarketPlaceApp.cc +++ b/src/market/MarketPlaceApp.cc @@ -222,6 +222,7 @@ std::string& MarketPlaceApp::to_xml(std::string& xml) const std::ostringstream oss; std::string template_xml; std::string perm_str; + string lock_str; oss << "<MARKETPLACEAPP>" "<ID>" << oid << "</ID>" << @@ -229,6 +230,7 @@ std::string& MarketPlaceApp::to_xml(std::string& xml) const "<GID>" << gid << "</GID>" << "<UNAME>" << uname << "</UNAME>" << "<GNAME>" << gname << "</GNAME>" << + lock_db_to_xml(lock_str) << "<REGTIME>" << regtime << "</REGTIME>" << "<NAME>" << name << "</NAME>" << "<ZONE_ID>" << one_util::escape_xml(zone_id) << "</ZONE_ID>" << @@ -294,6 +296,9 @@ int MarketPlaceApp::from_xml(const std::string &xml_str) // ----- Permissions ----- rc += perms_from_xml(); + // ------ Lock ------- + rc += lock_db_from_xml(); + // ----- TEMPLATE ----- ObjectXML::get_nodes("/MARKETPLACEAPP/TEMPLATE", content); diff --git a/src/oca/java/src/org/opennebula/client/image/Image.java b/src/oca/java/src/org/opennebula/client/image/Image.java index 8690508429..087f0214cf 100644 --- a/src/oca/java/src/org/opennebula/client/image/Image.java +++ b/src/oca/java/src/org/opennebula/client/image/Image.java @@ -42,6 +42,8 @@ public class Image extends PoolElement private static final String SNAPSHOTDELETE = METHOD_PREFIX + "snapshotdelete"; private static final String SNAPSHOTREVERT = METHOD_PREFIX + "snapshotrevert"; private static final String SNAPSHOTFLATTEN = METHOD_PREFIX + "snapshotflatten"; + private static final String LOCK = METHOD_PREFIX + "lock"; + private static final String UNLOCK = METHOD_PREFIX + "unlock"; private static final String[] IMAGE_STATES = {"INIT", "READY", "USED", "DISABLED", "LOCKED", @@ -323,6 +325,31 @@ public class Image extends PoolElement return client.call(SNAPSHOTFLATTEN, id, snapId); } + /** + * lock this Image + * + * @param client XML-RPC Client. + * @param id The Image id. + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse lock(Client client, int id, int level) + { + return client.call(LOCK, id, level); + } + + /** + * Unlock this Image + * + * @param client XML-RPC Client. + * @param id The Image id. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse unlock(Client client, int id) + { + return client.call(UNLOCK, id); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -622,6 +649,27 @@ public class Image extends PoolElement return snapshotFlatten(client, id, snapId); } + /** + * Lock this Image + * + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse lock(int level) + { + return rename(client, id, level); + } + + /** + * Unlock this Image + * + * @return If an error occurs the error message contains the reason. + */ + public OneResponse unlock() + { + return rename(client, id); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/src/org/opennebula/client/marketplaceapp/MarketPlaceApp.java b/src/oca/java/src/org/opennebula/client/marketplaceapp/MarketPlaceApp.java index a7ef69698b..ee0d47d079 100644 --- a/src/oca/java/src/org/opennebula/client/marketplaceapp/MarketPlaceApp.java +++ b/src/oca/java/src/org/opennebula/client/marketplaceapp/MarketPlaceApp.java @@ -36,6 +36,8 @@ public class MarketPlaceApp extends PoolElement 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 LOCK = METHOD_PREFIX + "lock"; + private static final String UNLOCK = METHOD_PREFIX + "unlock"; private static final String[] MARKETPLACEAPP_STATES = {"INIT", "READY", "LOCKED", "ERROR", "DISABLED"}; @@ -222,6 +224,31 @@ public class MarketPlaceApp extends PoolElement return client.call(RENAME, id, name); } + /** + * lock this MarketPlaceApp + * + * @param client XML-RPC Client. + * @param id The MarketPlaceApp id. + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse lock(Client client, int id, int level) + { + return client.call(LOCK, id, level); + } + + /** + * Unlock this MarketPlaceApp + * + * @param client XML-RPC Client. + * @param id The MarketPlaceApp id. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse unlock(Client client, int id) + { + return client.call(UNLOCK, id); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -394,6 +421,27 @@ public class MarketPlaceApp extends PoolElement return rename(client, id, name); } + /** + * Lock this MarketPlaceApp + * + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse lock(int level) + { + return rename(client, id, level); + } + + /** + * Unlock this MarketPlaceApp + * + * @return If an error occurs the error message contains the reason. + */ + public OneResponse unlock() + { + return rename(client, id); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/src/org/opennebula/client/template/Template.java b/src/oca/java/src/org/opennebula/client/template/Template.java index f115abb323..1953d1b37e 100644 --- a/src/oca/java/src/org/opennebula/client/template/Template.java +++ b/src/oca/java/src/org/opennebula/client/template/Template.java @@ -37,6 +37,8 @@ public class Template extends PoolElement private static final String INSTANTIATE = METHOD_PREFIX + "instantiate"; private static final String CLONE = METHOD_PREFIX + "clone"; private static final String RENAME = METHOD_PREFIX + "rename"; + private static final String LOCK = METHOD_PREFIX + "lock"; + private static final String UNLOCK = METHOD_PREFIX + "unlock"; /** * Creates a new Template representation. @@ -352,6 +354,31 @@ public class Template extends PoolElement return client.call(RENAME, id, name); } + /** + * lock this template + * + * @param client XML-RPC Client. + * @param id The template id. + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse lock(Client client, int id, int level) + { + return client.call(LOCK, id, level); + } + + /** + * Unlock this template + * + * @param client XML-RPC Client. + * @param id The template id. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse unlock(Client client, int id) + { + return client.call(UNLOCK, id); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -666,6 +693,27 @@ public class Template extends PoolElement return rename(client, id, name); } + /** + * Lock this template + * + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse lock(int level) + { + return rename(client, id, level); + } + + /** + * Unlock this template + * + * @return If an error occurs the error message contains the reason. + */ + public OneResponse unlock() + { + return rename(client, id); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/src/org/opennebula/client/vmgroup/VMGroup.java b/src/oca/java/src/org/opennebula/client/vmgroup/VMGroup.java index d18d654b84..ef83e94d77 100644 --- a/src/oca/java/src/org/opennebula/client/vmgroup/VMGroup.java +++ b/src/oca/java/src/org/opennebula/client/vmgroup/VMGroup.java @@ -35,6 +35,8 @@ public class VMGroup extends PoolElement{ 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 LOCK = METHOD_PREFIX + "lock"; + private static final String UNLOCK = METHOD_PREFIX + "unlock"; /** * Creates a new vmgroup representation. @@ -197,6 +199,31 @@ public class VMGroup extends PoolElement{ return client.call(RENAME, id, name); } + /** + * lock this vmgroup + * + * @param client XML-RPC Client. + * @param id The id of the target vmgroup. + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse lock(Client client, int id, int level) + { + return client.call(LOCK, id, level); + } + + /** + * Unlock this vmgroup + * + * @param client XML-RPC Client. + * @param id The id of the target vmgroup. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse unlock(Client client, int id) + { + return client.call(UNLOCK, id); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -338,6 +365,27 @@ public class VMGroup extends PoolElement{ return rename(client, id, name); } + /** + * Lock this vmgroup + * + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse lock(int level) + { + return rename(client, id, level); + } + + /** + * Unlock this vmgroup + * + * @return If an error occurs the error message contains the reason. + */ + public OneResponse unlock() + { + return rename(client, id); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java b/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java index e3b8617dd5..398f58d366 100644 --- a/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java +++ b/src/oca/java/src/org/opennebula/client/vnet/VirtualNetwork.java @@ -42,6 +42,8 @@ public class VirtualNetwork extends PoolElement{ private static final String RENAME = METHOD_PREFIX + "rename"; private static final String RESERVE = METHOD_PREFIX + "reserve"; private static final String FREEAR = METHOD_PREFIX + "free_ar"; + private static final String LOCK = METHOD_PREFIX + "lock"; + private static final String UNLOCK = METHOD_PREFIX + "unlock"; /** * Creates a new virtual network representation. @@ -362,6 +364,31 @@ public class VirtualNetwork extends PoolElement{ return client.call(FREEAR, id, arId); } + /** + * lock this virtual network + * + * @param client XML-RPC Client. + * @param id The virtual network id (nid) + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse lock(Client client, int id, int level) + { + return client.call(LOCK, id, level); + } + + /** + * Unlock this virtual network + * + * @param client XML-RPC Client. + * @param id The virtual network id (nid) + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse unlock(Client client, int id) + { + return client.call(UNLOCK, id); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -679,6 +706,27 @@ public class VirtualNetwork extends PoolElement{ return free(client, id, arId); } + /** + * Lock this virtual network + * + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse lock(int level) + { + return rename(client, id, level); + } + + /** + * Unlock this virtual network + * + * @return If an error occurs the error message contains the reason. + */ + public OneResponse unlock() + { + return rename(client, id); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouter.java b/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouter.java index da003b1000..6c2d59bbeb 100644 --- a/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouter.java +++ b/src/oca/java/src/org/opennebula/client/vrouter/VirtualRouter.java @@ -38,6 +38,8 @@ public class VirtualRouter extends PoolElement private static final String RENAME = METHOD_PREFIX + "rename"; private static final String ATTACHNIC = METHOD_PREFIX + "attachnic"; private static final String DETACHNIC = METHOD_PREFIX + "detachnic"; + private static final String LOCK = METHOD_PREFIX + "lock"; + private static final String UNLOCK = METHOD_PREFIX + "unlock"; /** * Creates a new VirtualRouter representation. @@ -259,6 +261,31 @@ public class VirtualRouter extends PoolElement return client.call(DETACHNIC, id, nicId); } + /** + * lock this virtual router + * + * @param client XML-RPC Client. + * @param id The virtual router id. + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse lock(Client client, int id, int level) + { + return client.call(LOCK, id, level); + } + + /** + * Unlock this virtual router + * + * @param client XML-RPC Client. + * @param id The virtual router id. + * @return If an error occurs the error message contains the reason. + */ + public static OneResponse unlock(Client client, int id) + { + return client.call(UNLOCK, id); + } + // ================================= // Instanced object XML-RPC methods // ================================= @@ -485,6 +512,27 @@ public class VirtualRouter extends PoolElement return nicDetach(client, id, nicId); } + /** + * Lock this virtual router + * + * @param level Lock level. + * @return If an error occurs the error message contains the reason. + */ + public OneResponse lock(int level) + { + return rename(client, id, level); + } + + /** + * Unlock this virtual router + * + * @return If an error occurs the error message contains the reason. + */ + public OneResponse unlock() + { + return rename(client, id); + } + // ================================= // Helpers // ================================= diff --git a/src/oca/ruby/opennebula/image.rb b/src/oca/ruby/opennebula/image.rb index d434633f17..fbcfd50308 100644 --- a/src/oca/ruby/opennebula/image.rb +++ b/src/oca/ruby/opennebula/image.rb @@ -38,7 +38,9 @@ module OpenNebula :rename => "image.rename", :snapshotdelete => "image.snapshotdelete", :snapshotrevert => "image.snapshotrevert", - :snapshotflatten=> "image.snapshotflatten" + :snapshotflatten=> "image.snapshotflatten", + :lock => "image.lock", + :unlock => "image.unlock" } IMAGE_STATES=%w{INIT READY USED DISABLED LOCKED ERROR CLONE DELETE @@ -296,6 +298,14 @@ module OpenNebula self['GID'].to_i end + def lock(level) + return call(IMAGE_METHODS[:lock], @pe_id, level) + end + + def unlock() + return call(IMAGE_METHODS[:unlock], @pe_id) + end + def public? if self['PERMISSIONS/GROUP_U'] == "1" || self['PERMISSIONS/OTHER_U'] == "1" true diff --git a/src/oca/ruby/opennebula/marketplaceapp.rb b/src/oca/ruby/opennebula/marketplaceapp.rb index 1c58f5a210..a0b1c48121 100644 --- a/src/oca/ruby/opennebula/marketplaceapp.rb +++ b/src/oca/ruby/opennebula/marketplaceapp.rb @@ -30,7 +30,9 @@ module OpenNebula :chown => "marketapp.chown", :chmod => "marketapp.chmod", :rename => "marketapp.rename", - :enable => "marketapp.enable" + :enable => "marketapp.enable", + :lock => "marketapp.lock", + :unlock => "marketapp.unlock" } MARKETPLACEAPP_STATES=%w{INIT READY LOCKED ERROR DISABLED} @@ -263,5 +265,15 @@ module OpenNebula def short_state_str SHORT_MARKETPLACEAPP_STATES[state_str] end + + #Locked a MarketplaceApp + def lock(level) + return call(MARKETPLACEAPP_METHODS[:lock], @pe_id, level) + end + + #Unlocked a MarketplaceApp + def unlock() + return call(MARKETPLACEAPP_METHODS[:unlock], @pe_id) + end end end diff --git a/src/oca/ruby/opennebula/template.rb b/src/oca/ruby/opennebula/template.rb index e089802058..cde90349b6 100644 --- a/src/oca/ruby/opennebula/template.rb +++ b/src/oca/ruby/opennebula/template.rb @@ -33,7 +33,9 @@ module OpenNebula :chown => "template.chown", :chmod => "template.chmod", :clone => "template.clone", - :rename => "template.rename" + :rename => "template.rename", + :lock => "template.lock", + :unlock => "template.unlock" } # Creates a Template description with just its identifier @@ -241,6 +243,16 @@ module OpenNebula self['UID'].to_i end + # Lock a Template + def lock(level) + return call(TEMPLATE_METHODS[:lock], @pe_id, level) + end + + # Unlock a Template + def unlock() + return call(TEMPLATE_METHODS[:unlock], @pe_id) + end + def public? if self['PERMISSIONS/GROUP_U'] == "1" || self['PERMISSIONS/OTHER_U'] == "1" true diff --git a/src/oca/ruby/opennebula/virtual_machine.rb b/src/oca/ruby/opennebula/virtual_machine.rb index 2ae4f75c1d..4a4cfd23b9 100644 --- a/src/oca/ruby/opennebula/virtual_machine.rb +++ b/src/oca/ruby/opennebula/virtual_machine.rb @@ -47,7 +47,9 @@ module OpenNebula :disksnapshotrevert => "vm.disksnapshotrevert", :disksnapshotdelete => "vm.disksnapshotdelete", :diskresize => "vm.diskresize", - :updateconf => "vm.updateconf" + :updateconf => "vm.updateconf", + :lock => "vm.lock", + :unlock => "vm.unlock" } VM_STATE=%w{INIT PENDING HOLD ACTIVE STOPPED SUSPENDED DONE FAILED @@ -686,7 +688,17 @@ module OpenNebula # otherwise def updateconf(new_conf) return call(VM_METHODS[:updateconf], @pe_id, new_conf) - end + end + + # Lock a VM + def lock(level) + return call(VM_METHODS[:lock], @pe_id, level) + end + + # Unlock a VM + def unlock() + return call(VM_METHODS[:unlock], @pe_id) + end ######################################################################## # Helpers to get VirtualMachine information @@ -853,7 +865,7 @@ module OpenNebula REMOVE_VNET_ATTRS.each do |attr| nic.delete_element(attr) end - + replace << "NIC = [ " << nic.template_like_str(".").tr("\n", ",\n") << " ] \n" end diff --git a/src/oca/ruby/opennebula/virtual_network.rb b/src/oca/ruby/opennebula/virtual_network.rb index af07aebc10..57aa62ca41 100644 --- a/src/oca/ruby/opennebula/virtual_network.rb +++ b/src/oca/ruby/opennebula/virtual_network.rb @@ -38,7 +38,9 @@ module OpenNebula :release => "vn.release", :rename => "vn.rename", :reserve => "vn.reserve", - :free_ar => "vn.free_ar" + :free_ar => "vn.free_ar", + :lock => "vn.lock", + :unlock => "vn.unlock" } # Creates a VirtualNetwork description with just its identifier @@ -330,6 +332,14 @@ module OpenNebula return array end + def lock(level) + return call(VN_METHODS[:lock], @pe_id, level) + end + + def unlock() + return call(VN_METHODS[:unlock], @pe_id) + 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 index 73cf7f5a1a..4a6dfcdf2b 100644 --- a/src/oca/ruby/opennebula/virtual_router.rb +++ b/src/oca/ruby/opennebula/virtual_router.rb @@ -34,6 +34,8 @@ module OpenNebula :rename => "vrouter.rename", :attachnic => "vrouter.attachnic", :detachnic => "vrouter.detachnic", + :lock => "vrouter.lock", + :unlock => "vrouter.unlock" } # Creates a VirtualRouter description with just its identifier @@ -175,6 +177,16 @@ module OpenNebula return call(VIRTUAL_ROUTER_METHODS[:detachnic], @pe_id, nic_id) end + # Lock a VRouter + def lock(level) + return call(VIRTUAL_ROUTER_METHODS[:lock], @pe_id, level) + end + + # Unlock a VRouter + def unlock() + return call(VIRTUAL_ROUTER_METHODS[:unlock], @pe_id) + end + ####################################################################### # Helpers to get VirtualRouter information ####################################################################### diff --git a/src/oca/ruby/opennebula/vm_group.rb b/src/oca/ruby/opennebula/vm_group.rb index fc73df6d59..59c0da3812 100644 --- a/src/oca/ruby/opennebula/vm_group.rb +++ b/src/oca/ruby/opennebula/vm_group.rb @@ -28,7 +28,9 @@ module OpenNebula :delete => "vmgroup.delete", :chown => "vmgroup.chown", :chmod => "vmgroup.chmod", - :rename => "vmgroup.rename" + :rename => "vmgroup.rename", + :lock => "vmgroup.lock", + :unlock => "vmgroup.unlock" } # Creates a VMGroup description with just its identifier @@ -129,6 +131,16 @@ module OpenNebula return call(VMGROUP_METHODS[:rename], @pe_id, name) end + # Lock a VMGroup + def lock(level) + return call(VMGROUP_METHODS[:lock], @pe_id, level) + end + + # Unlock a VMGroup + def unlock() + return call(VMGROUP_METHODS[:unlock], @pe_id) + end + ####################################################################### # Helpers to get VMGroup information ####################################################################### diff --git a/src/pool/PoolObjectSQL.cc b/src/pool/PoolObjectSQL.cc index 49a21298db..d53a099eb2 100644 --- a/src/pool/PoolObjectSQL.cc +++ b/src/pool/PoolObjectSQL.cc @@ -24,6 +24,14 @@ const string PoolObjectSQL::INVALID_NAME_CHARS = "&|:\\\";/'#{}$<>"; const int PoolObjectSQL::LOCK_DB_EXPIRATION = 120; +const long int PoolObjectSQL::LockableObject = PoolObjectSQL::ObjectType::VM + | PoolObjectSQL::ObjectType::TEMPLATE + | PoolObjectSQL::ObjectType::IMAGE + | PoolObjectSQL::ObjectType::MARKETPLACEAPP + | PoolObjectSQL::ObjectType::NET + | PoolObjectSQL::ObjectType::VROUTER + | PoolObjectSQL::ObjectType::VMGROUP; + /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ @@ -369,6 +377,8 @@ void PoolObjectSQL::get_permissions(PoolObjectAuth& auth) auth.other_m = other_m; auth.other_a = other_a; + auth.locked = static_cast<int>(locked); + Clusterable* cl = dynamic_cast<Clusterable*>(this); if(cl != 0) @@ -511,16 +521,12 @@ bool PoolObjectSQL::name_is_valid(const string& obj_name, /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int PoolObjectSQL::lock_db(const string& owner) +int PoolObjectSQL::lock_db(const int owner, const int req_id, const int level) { - if (locked && time(0) < lock_expires) - { - return -1; - } - - locked = true; - lock_expires = time(0) + LOCK_DB_EXPIRATION; + locked = static_cast<LockStates>(level); + lock_time = time(0); lock_owner = owner; + lock_req_id = req_id; return 0; } @@ -528,13 +534,15 @@ int PoolObjectSQL::lock_db(const string& owner) /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void PoolObjectSQL::unlock_db(const string& owner) +void PoolObjectSQL::unlock_db(const int owner, const int req_id) { - // Check if owner == lock_owner? - - locked = false; - lock_expires = 0; - lock_owner = ""; + if ( owner == lock_owner ) + { + locked = LockStates::ST_NONE; + lock_time = time(0); + lock_owner = -1; + lock_req_id = -1; + } } /* -------------------------------------------------------------------------- */ @@ -543,13 +551,15 @@ void PoolObjectSQL::unlock_db(const string& owner) string& PoolObjectSQL::lock_db_to_xml(string& xml) const { ostringstream oss; - int locked_int = locked ? 1 : 0; - - oss << "<LOCK>" - << "<LOCKED>" << locked_int << "</LOCKED>" - << "<OWNER>" << one_util::escape_xml(lock_owner) << "</OWNER>" - << "<EXPIRES>" << lock_expires << "</EXPIRES>" - << "</LOCK>"; + if (locked != LockStates::ST_NONE) + { + oss << "<LOCK>" + << "<LOCKED>" << static_cast<int>(locked) << "</LOCKED>" + << "<OWNER>" << lock_owner << "</OWNER>" + << "<TIME>" << lock_time << "</TIME>" + << "<REQ_ID>" << lock_req_id << "</REQ_ID>" + << "</LOCK>"; + } xml = oss.str(); return xml; @@ -562,12 +572,17 @@ int PoolObjectSQL::lock_db_from_xml() { int rc = 0; int locked_int; + vector<xmlNodePtr> content; - rc += xpath(locked_int, "/*/LOCK/LOCKED", 0); - rc += xpath(lock_owner, "/*/LOCK/OWNER", ""); - rc += xpath<time_t>(lock_expires, "/*/LOCK/EXPIRES", 0); + if (ObjectXML::get_nodes("/*/LOCK/LOCKED", content) > 0) + { + rc += xpath(locked_int, "/*/LOCK/LOCKED", 0); + rc += xpath(lock_req_id, "/*/LOCK/REQ_ID", -1); + rc += xpath(lock_owner, "/*/LOCK/OWNER", -1); + xpath<time_t>(lock_time, "/*/LOCK/TIME", time(0)); - locked = locked_int; + locked = static_cast<LockStates>(locked_int); + } return rc; } diff --git a/src/rm/Request.cc b/src/rm/Request.cc index b7833d33a9..0685cfce17 100644 --- a/src/rm/Request.cc +++ b/src/rm/Request.cc @@ -722,6 +722,14 @@ string Request::failure_message(ErrorCode ec, RequestAttributes& att) oss << " " << att.resp_msg; } break; + case LOCKED: + oss << "The resource " << obname << " is locked."; + + if ( att.resp_id != -1 ) + { + oss << " [" << att.resp_id << "]."; + } + break; } return oss.str(); diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index a94c9e1f71..3a06d74b22 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -382,6 +382,18 @@ void RequestManager::register_xml_methods() // Lock Methods xmlrpc_c::methodPtr doc_lock(new DocumentLock()); xmlrpc_c::methodPtr doc_unlock(new DocumentUnlock()); + xmlrpc_c::methodPtr vm_lock(new VirtualMachineLock()); + xmlrpc_c::methodPtr vm_unlock(new VirtualMachineUnlock()); + xmlrpc_c::methodPtr template_lock(new VMTemplateLock()); + xmlrpc_c::methodPtr template_unlock(new VMTemplateUnlock()); + xmlrpc_c::methodPtr vn_lock(new VirtualNetworkLock()); + xmlrpc_c::methodPtr vn_unlock(new VirtualNetworkUnlock()); + xmlrpc_c::methodPtr image_lock(new ImageLock()); + xmlrpc_c::methodPtr image_unlock(new ImageUnlock()); + xmlrpc_c::methodPtr vrouter_lock(new VirtualRouterLock()); + xmlrpc_c::methodPtr vrouter_unlock(new VirtualRouterUnlock()); + xmlrpc_c::methodPtr vmg_lock(new VMGroupLock()); + xmlrpc_c::methodPtr vmg_unlock(new VMGroupUnlock()); // PoolInfo Methods xmlrpc_c::methodPtr hostpool_info(new HostPoolInfo()); @@ -495,6 +507,8 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vm.disksnapshotdelete", vm_dsnap_delete); RequestManagerRegistry.addMethod("one.vm.recover", vm_recover); RequestManagerRegistry.addMethod("one.vm.updateconf", vm_updateconf); + RequestManagerRegistry.addMethod("one.vm.lock", vm_lock); + RequestManagerRegistry.addMethod("one.vm.unlock", vm_unlock); RequestManagerRegistry.addMethod("one.vm.diskresize", vm_disk_resize); RequestManagerRegistry.addMethod("one.vmpool.info", vm_pool_info); @@ -513,7 +527,8 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.template.chmod", template_chmod); RequestManagerRegistry.addMethod("one.template.clone", template_clone); RequestManagerRegistry.addMethod("one.template.rename", template_rename); - + RequestManagerRegistry.addMethod("one.template.lock", template_lock); + RequestManagerRegistry.addMethod("one.template.unlock", template_unlock); RequestManagerRegistry.addMethod("one.templatepool.info",template_pool_info); /* Host related methods*/ @@ -593,6 +608,8 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vn.chown", vn_chown); RequestManagerRegistry.addMethod("one.vn.chmod", vn_chmod); RequestManagerRegistry.addMethod("one.vn.rename", vn_rename); + RequestManagerRegistry.addMethod("one.vn.lock", vn_lock); + RequestManagerRegistry.addMethod("one.vn.unlock", vn_unlock); RequestManagerRegistry.addMethod("one.vnpool.info", vnpool_info); @@ -685,6 +702,8 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.image.snapshotdelete", image_snap_delete); RequestManagerRegistry.addMethod("one.image.snapshotrevert", image_snap_revert); RequestManagerRegistry.addMethod("one.image.snapshotflatten", image_snap_flatten); + RequestManagerRegistry.addMethod("one.image.lock", image_lock); + RequestManagerRegistry.addMethod("one.image.unlock", image_unlock); RequestManagerRegistry.addMethod("one.imagepool.info", imagepool_info); @@ -833,6 +852,8 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vmgroup.chmod", vmg_chmod); RequestManagerRegistry.addMethod("one.vmgroup.rename", vmg_rename); RequestManagerRegistry.addMethod("one.vmgroup.update", vmg_update); + RequestManagerRegistry.addMethod("one.vmgroup.lock", vmg_lock); + RequestManagerRegistry.addMethod("one.vmgroup.unlock", vmg_unlock); RequestManagerRegistry.addMethod("one.vmgrouppool.info", vmgpool_info); @@ -943,6 +964,8 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vrouter.instantiate",vrouter_instantiate); RequestManagerRegistry.addMethod("one.vrouter.attachnic", vrouter_attachnic); RequestManagerRegistry.addMethod("one.vrouter.detachnic", vrouter_detachnic); + RequestManagerRegistry.addMethod("one.vrouter.lock", vrouter_lock); + RequestManagerRegistry.addMethod("one.vrouter.unlock", vrouter_unlock); RequestManagerRegistry.addMethod("one.vrouterpool.info",vrouter_pool_info); @@ -1008,6 +1031,8 @@ void RequestManager::register_xml_methods() xmlrpc_c::method * marketapp_chown_pt; xmlrpc_c::method * marketapp_enable_pt; xmlrpc_c::method * marketapp_rename_pt; + xmlrpc_c::method * marketapp_lock_pt; + xmlrpc_c::method * marketapp_unlock_pt; if (nebula.is_federation_slave()) { @@ -1016,6 +1041,8 @@ void RequestManager::register_xml_methods() marketapp_chown_pt = new RequestManagerProxy("one.marketapp.chown"); marketapp_enable_pt = new RequestManagerProxy("one.marketapp.enable"); marketapp_rename_pt = new RequestManagerProxy("one.marketapp.rename"); + marketapp_lock_pt = new RequestManagerProxy("one.marketapp.lock"); + marketapp_unlock_pt = new RequestManagerProxy("one.marketapp.unlock"); } else { @@ -1024,6 +1051,8 @@ void RequestManager::register_xml_methods() marketapp_chown_pt = new MarketPlaceAppChown(); marketapp_enable_pt = new MarketPlaceAppEnable(); marketapp_rename_pt = new MarketPlaceAppRename(); + marketapp_lock_pt = new MarketPlaceAppLock(); + marketapp_unlock_pt = new MarketPlaceAppUnlock(); xmlrpc_c::methodPtr marketapp_updatedb(new MarketPlaceAppUpdateDB()); xmlrpc_c::methodPtr marketapp_dropdb(new MarketPlaceAppDropDB()); @@ -1046,6 +1075,8 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr marketapp_chown(marketapp_chown_pt); xmlrpc_c::methodPtr marketapp_enable(marketapp_enable_pt); xmlrpc_c::methodPtr marketapp_rename(marketapp_rename_pt); + xmlrpc_c::methodPtr marketapp_lock(marketapp_lock_pt); + xmlrpc_c::methodPtr marketapp_unlock(marketapp_unlock_pt); xmlrpc_c::methodPtr marketapp_info(new MarketPlaceAppInfo()); xmlrpc_c::methodPtr marketapppool_info(new MarketPlaceAppPoolInfo()); @@ -1056,6 +1087,8 @@ void RequestManager::register_xml_methods() 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.lock", marketapp_lock); + RequestManagerRegistry.addMethod("one.marketapp.unlock", marketapp_unlock); RequestManagerRegistry.addMethod("one.marketapp.info", marketapp_info); RequestManagerRegistry.addMethod("one.marketapp.rename", marketapp_rename); diff --git a/src/rm/RequestManagerLock.cc b/src/rm/RequestManagerLock.cc index 3e2a37c986..64e7092755 100644 --- a/src/rm/RequestManagerLock.cc +++ b/src/rm/RequestManagerLock.cc @@ -25,8 +25,8 @@ void RequestManagerLock::request_execute(xmlrpc_c::paramList const& paramList, RequestAttributes& att) { int oid = xmlrpc_c::value_int(paramList.getInt(1)); - string owner = xmlrpc_c::value_string(paramList.getString(2)); - + int level = xmlrpc_c::value_int(paramList.getInt(2)); + int owner = att.uid; PoolObjectSQL * object; string error_str; int rc; @@ -45,13 +45,22 @@ void RequestManagerLock::request_execute(xmlrpc_c::paramList const& paramList, return; } - rc = lock_db(object, owner); + if ((auth_object & PoolObjectSQL::LockableObject) != 0) + { + rc = lock_db(object, owner, att.req_id, level); - pool->update(object); + pool->update(object); - object->unlock(); + object->unlock(); - success_response((rc == 0), att); + success_response((rc == 0), att); + } + else + { + object->unlock(); + + failure_response(AUTHORIZATION, att); + } return; } @@ -63,10 +72,11 @@ void RequestManagerUnlock::request_execute(xmlrpc_c::paramList const& paramList, RequestAttributes& att) { int oid = xmlrpc_c::value_int(paramList.getInt(1)); - string owner = xmlrpc_c::value_string(paramList.getString(2)); PoolObjectSQL * object; string error_str; + int owner = att.uid; + int req_id = att.req_id; if ( basic_authorization(oid, att) == false ) { @@ -82,7 +92,7 @@ void RequestManagerUnlock::request_execute(xmlrpc_c::paramList const& paramList, return; } - unlock_db(object, owner); + unlock_db(object, owner, req_id); pool->update(object); diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index 7fc800a774..1880c8d303 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -69,7 +69,7 @@ bool RequestManagerVirtualMachine::vm_authorization( { string t_xml; - ar.add_create_auth(att.uid, att.gid, PoolObjectSQL::IMAGE, + ar.add_create_auth(att.uid, att.gid, PoolObjectSQL::IMAGE, tmpl->to_xml(t_xml)); } diff --git a/src/sunstone/models/OpenNebulaJSON/ImageJSON.rb b/src/sunstone/models/OpenNebulaJSON/ImageJSON.rb index 46f94dff55..b1e2e99d80 100644 --- a/src/sunstone/models/OpenNebulaJSON/ImageJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/ImageJSON.rb @@ -63,6 +63,8 @@ module OpenNebulaJSON when "snapshot_flatten" then self.snapshot_flatten(action_hash['params']) when "snapshot_revert" then self.snapshot_revert(action_hash['params']) when "snapshot_delete" then self.snapshot_delete(action_hash['params']) + when "lock" then self.lock(action_hash['params']) + when "unlock" then self.unlock(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -135,5 +137,13 @@ module OpenNebulaJSON def snapshot_delete(params=Hash.new) super(params['snapshot_id'].to_i) end + + def lock(params=Hash.new) + super(params['level'].to_i) + end + + def unlock(params=Hash.new) + super() + end end end diff --git a/src/sunstone/models/OpenNebulaJSON/MarketPlaceAppJSON.rb b/src/sunstone/models/OpenNebulaJSON/MarketPlaceAppJSON.rb index 0a24bd9e38..7584355a1c 100644 --- a/src/sunstone/models/OpenNebulaJSON/MarketPlaceAppJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/MarketPlaceAppJSON.rb @@ -54,6 +54,8 @@ module OpenNebulaJSON when "rename" then self.rename(action_hash['params']) when "disable" then self.disable when "enable" then self.enable + when "lock" then self.lock(action_hash['params']) + when "unlock" then self.unlock(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -122,5 +124,13 @@ module OpenNebulaJSON def rename(params=Hash.new) super(params['name']) end + + def lock(params=Hash.new) + super(params['level'].to_i) + end + + def unlock(params=Hash.new) + super() + end end end diff --git a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb index 85a1fdd733..6c2c9f660b 100644 --- a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb @@ -51,6 +51,8 @@ module OpenNebulaJSON when "clone" then self.clone(action_hash['params']) when "rename" then self.rename(action_hash['params']) when "delete_recursive" then self.delete_recursive(action_hash['params']) + when "lock" then self.lock(action_hash['params']) + when "unlock" then self.unlock(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -140,5 +142,13 @@ module OpenNebulaJSON recursive = (params['recursive'] == true) self.delete(recursive) end + + def lock(params=Hash.new) + super(params['level'].to_i) + end + + def unlock(params=Hash.new) + super() + end end end diff --git a/src/sunstone/models/OpenNebulaJSON/VMGroupJSON.rb b/src/sunstone/models/OpenNebulaJSON/VMGroupJSON.rb index 332312f542..841e726241 100644 --- a/src/sunstone/models/OpenNebulaJSON/VMGroupJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VMGroupJSON.rb @@ -47,6 +47,8 @@ module OpenNebulaJSON when "chmod" then self.chmod_octet(action_hash['params']) when "update" then self.update(action_hash['params']) when "rename" then self.rename(action_hash['params']) + when "lock" then self.lock(action_hash['params']) + when "unlock" then self.unlock(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -77,5 +79,13 @@ module OpenNebulaJSON def rename(params=Hash.new) super(params['name']) end + + def lock(params=Hash.new) + super(params['level'].to_i) + end + + def unlock(params=Hash.new) + super() + end end end diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb index 13ee9a99b5..aeee8750ed 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb @@ -77,6 +77,8 @@ module OpenNebulaJSON when "recover" then self.recover(action_hash['params']) when "save_as_template" then self.save_as_template(action_hash['params']) when "disk_resize" then self.disk_resize(action_hash['params']) + when "lock" then self.lock(action_hash['params']) + when "unlock" then self.unlock(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -191,6 +193,14 @@ module OpenNebulaJSON super(params['name']) end + def lock(params=Hash.new) + super(params['level'].to_i) + end + + def unlock(params=Hash.new) + super() + end + def recover(params=Hash.new) super(params['result'].to_i) end diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb index 3104c45385..fadbd6250d 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualNetworkJSON.rb @@ -54,6 +54,8 @@ module OpenNebulaJSON when "add_ar" then self.add_ar(action_hash['params']) when "update_ar" then self.update_ar(action_hash['params']) when "reserve" then self.reserve(action_hash['params']) + when "lock" then self.lock(action_hash['params']) + when "unlock" then self.unlock(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -111,5 +113,13 @@ module OpenNebulaJSON super(params['name'], params['size'], params['ar_id'], params['addr'], params['vnet']) end + + def lock(params=Hash.new) + super(params['level'].to_i) + end + + def unlock(params=Hash.new) + super() + end end end diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualRouterJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualRouterJSON.rb index c807b1ec98..76f32a6b63 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualRouterJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualRouterJSON.rb @@ -51,6 +51,8 @@ module OpenNebulaJSON 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']) + when "lock" then self.lock(action_hash['params']) + when "unlock" then self.unlock(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -113,5 +115,13 @@ module OpenNebulaJSON def nic_detach(params=Hash.new) super(params['nic_id'].to_i) end + + def lock(params=Hash.new) + super(params['level'].to_i) + end + + def unlock(params=Hash.new) + super() + end end end diff --git a/src/sunstone/public/app/opennebula/action.js b/src/sunstone/public/app/opennebula/action.js index 39decd0046..e9fa1b6464 100644 --- a/src/sunstone/public/app/opennebula/action.js +++ b/src/sunstone/public/app/opennebula/action.js @@ -291,6 +291,13 @@ define(function(require) { _simple_action(params, resource, "chown", action_obj, path); }, + "lock": function(params, resource, path) { + var level = params.data.extra_param; + var action_obj = {"level": level}; + + _simple_action(params, resource, "lock", action_obj, path); + }, + "chgrp": function(params, resource, path) { var id = params.data.extra_param; var action_obj = {"owner_id": "-1", diff --git a/src/sunstone/public/app/opennebula/image.js b/src/sunstone/public/app/opennebula/image.js index 3ea69218e6..6d31270758 100644 --- a/src/sunstone/public/app/opennebula/image.js +++ b/src/sunstone/public/app/opennebula/image.js @@ -164,6 +164,12 @@ define(function(require) { }, "getName": function(id){ return OpenNebulaAction.getName(id, RESOURCE); + }, + "lock" : function(params) { + OpenNebulaAction.lock(params, RESOURCE); + }, + "unlock" : function(params) { + OpenNebulaAction.simple_action(params, RESOURCE, "unlock"); } } diff --git a/src/sunstone/public/app/opennebula/marketplaceapp.js b/src/sunstone/public/app/opennebula/marketplaceapp.js index db854ab5a6..dbdb928159 100644 --- a/src/sunstone/public/app/opennebula/marketplaceapp.js +++ b/src/sunstone/public/app/opennebula/marketplaceapp.js @@ -109,6 +109,12 @@ define(function(require) { }, "getName": function(id){ return OpenNebulaAction.getName(id, RESOURCE); + }, + "lock" : function(params) { + OpenNebulaAction.lock(params, RESOURCE); + }, + "unlock" : function(params) { + OpenNebulaAction.simple_action(params, RESOURCE, "unlock"); } } diff --git a/src/sunstone/public/app/opennebula/network.js b/src/sunstone/public/app/opennebula/network.js index 9a5f7c6868..39b42ae6b0 100644 --- a/src/sunstone/public/app/opennebula/network.js +++ b/src/sunstone/public/app/opennebula/network.js @@ -90,7 +90,13 @@ define(function(require) { }, "getName": function(id){ return OpenNebulaAction.getName(id, RESOURCE); - } + }, + "lock" : function(params) { + OpenNebulaAction.lock(params, RESOURCE); + }, + "unlock" : function(params) { + OpenNebulaAction.simple_action(params, RESOURCE, "unlock"); + }, } return Network; diff --git a/src/sunstone/public/app/opennebula/template.js b/src/sunstone/public/app/opennebula/template.js index e033d5e0a2..3f8fe0c5f9 100644 --- a/src/sunstone/public/app/opennebula/template.js +++ b/src/sunstone/public/app/opennebula/template.js @@ -97,6 +97,12 @@ define(function(require) { return true; } }, + "lock" : function(params) { + OpenNebulaAction.lock(params, RESOURCE); + }, + "unlock" : function(params) { + OpenNebulaAction.simple_action(params, RESOURCE, "unlock"); + }, "cost": function(template) { var cost = 0; var capacity = template.VMTEMPLATE.TEMPLATE; diff --git a/src/sunstone/public/app/opennebula/virtualrouter.js b/src/sunstone/public/app/opennebula/virtualrouter.js index a44e37d873..5fe433e3ee 100644 --- a/src/sunstone/public/app/opennebula/virtualrouter.js +++ b/src/sunstone/public/app/opennebula/virtualrouter.js @@ -70,6 +70,12 @@ define(function(require) { }, "getName": function(id){ return OpenNebulaAction.getName(id, RESOURCE); + }, + "lock" : function(params) { + OpenNebulaAction.lock(params, RESOURCE); + }, + "unlock" : function(params) { + OpenNebulaAction.simple_action(params, RESOURCE, "unlock"); } }; diff --git a/src/sunstone/public/app/opennebula/vm.js b/src/sunstone/public/app/opennebula/vm.js index ab03a098f8..5b01a885d0 100644 --- a/src/sunstone/public/app/opennebula/vm.js +++ b/src/sunstone/public/app/opennebula/vm.js @@ -563,6 +563,12 @@ define(function(require) { var action_obj = params.data.extra_param; OpenNebulaAction.simple_action(params, RESOURCE, "save_as_template", action_obj); }, + "lock" : function(params) { + OpenNebulaAction.lock(params, RESOURCE); + }, + "unlock" : function(params) { + OpenNebulaAction.simple_action(params, RESOURCE, "unlock"); + }, "stateStr": function(stateId) { return STATES_STR[stateId]; }, diff --git a/src/sunstone/public/app/opennebula/vmgroup.js b/src/sunstone/public/app/opennebula/vmgroup.js index 3943cb00fc..c7c91378b1 100644 --- a/src/sunstone/public/app/opennebula/vmgroup.js +++ b/src/sunstone/public/app/opennebula/vmgroup.js @@ -50,6 +50,12 @@ define(function(require) { }, "getName": function(id){ return OpenNebulaAction.getName(id, RESOURCE); + }, + "lock" : function(params) { + OpenNebulaAction.lock(params, RESOURCE); + }, + "unlock" : function(params) { + OpenNebulaAction.simple_action(params, RESOURCE, "unlock"); } }; diff --git a/src/sunstone/public/app/sunstone.js b/src/sunstone/public/app/sunstone.js index ee74b28760..0d7100ee70 100644 --- a/src/sunstone/public/app/sunstone.js +++ b/src/sunstone/public/app/sunstone.js @@ -269,6 +269,7 @@ define(function(require) { } var type = button.type + "_button"; + var data = ""; var strClass = [type]; switch (button.type) { case "select": @@ -292,6 +293,10 @@ define(function(require) { strClass.push(button.custom_classes); } + if (button.data) { + data = button.data; + } + var buttonContext; var text; switch (button.layout) { @@ -330,6 +335,11 @@ define(function(require) { strClass.push("button"); buttonCode = "<button class=\"" + strClass.join(" ") + "\" href=\"" + buttonName + "\">" + text + "</button>"; break; + case "lock_buttons": + buttonContext = $("#" + customId + "lock_buttons", buttonsRow); + text = button.text; + buttonCode = "<li><a class=\"" + strClass.join(" ") + "\" href=\"" + buttonName + "\" data=\"" + data + "\">" + text + "</a></li>"; + break; case "vmspause_buttons": buttonContext = $("#" + customId + "vmspause_buttons", buttonsRow); text = button.text; @@ -416,8 +426,8 @@ define(function(require) { $("button[data-toggle=" + customId + "vmsstop_buttons]", actionBlock).remove(); } - if ($("#" + customId + "vmspause_buttons li", actionBlock).length == 0) { - $("button[data-toggle=" + customId + "vmspause_buttons]", actionBlock).remove(); + if ($("#" + customId + "lock_buttons li", actionBlock).length == 0) { + $("button[data-toggle=" + customId + "lock_buttons]", actionBlock).remove(); } if ($("#" + customId + "vmsrepeat_buttons li", actionBlock).length == 0) { @@ -459,6 +469,7 @@ define(function(require) { $(document).on("click", ".action_button", function() { var error = 0; var value = $(this).val(); + var data = ($(this).attr("data") == "")? undefined: $(this).attr("data"); if ($.isEmptyObject(value)) { value = $(this).attr("href"); } @@ -474,10 +485,10 @@ define(function(require) { case "multiple": //find the datatable var context = $(this).parents(".tab"); var nodes = action.elements(); - error = _runAction(value, nodes); + error = _runAction(value, nodes, data); break; default: - error = _runAction(value); + error = _runAction(value,undefined, data); } return false; diff --git a/src/sunstone/public/app/sunstone/buttons.hbs b/src/sunstone/public/app/sunstone/buttons.hbs index a7852d74e5..29f55e68e3 100644 --- a/src/sunstone/public/app/sunstone/buttons.hbs +++ b/src/sunstone/public/app/sunstone/buttons.hbs @@ -39,6 +39,12 @@ <span id="{{customId}}vmsplay_buttons" class='only-sunstone-info only-sunstone-list'></span> + <button type='button' data-toggle='{{customId}}lock_buttons' class='lock-sunstone-info only-sunstone-info only-sunstone-list top_button button secondary dropdown'> + <i class='fa fa-lock'/> + </button> + <ul id='{{customId}}lock_buttons' class='lock-sunstone-info only-sunstone-info only-sunstone-list dropdown-pane menu vertical' data-dropdown></ul> + + <button type='button' data-toggle='{{customId}}vmspause_buttons' class='only-sunstone-info only-sunstone-list top_button button secondary dropdown'> <i class='fa fa-pause'/> </button> diff --git a/src/sunstone/public/app/sunstone/tab.hbs b/src/sunstone/public/app/sunstone/tab.hbs index 319b8a0d8b..8ee7c1989a 100644 --- a/src/sunstone/public/app/sunstone/tab.hbs +++ b/src/sunstone/public/app/sunstone/tab.hbs @@ -22,9 +22,12 @@ </h5> <h5 class="header-title only-sunstone-info" hidden> <span class="header-resource"> - {{{infoHeader}}} - <small class="resource-id"></small> - <small class="resource-info-header"></small> + {{#if lockable }} + <small class="resource-lock-header-small"></small> + {{/if}} + {{{infoHeader}}} + <small class="resource-id"></small> + <small class="resource-info-header"></small> <small class="resource-info-header-small"></small> </span> </h5> diff --git a/src/sunstone/public/app/tabs/acls-tab.js b/src/sunstone/public/app/tabs/acls-tab.js index 455c3a3173..60e0d7eeff 100644 --- a/src/sunstone/public/app/tabs/acls-tab.js +++ b/src/sunstone/public/app/tabs/acls-tab.js @@ -40,6 +40,7 @@ define(function(require) { tabClass: "subTab", parentTab: "system-top-tab", listHeader: Locale.tr("Access Control Lists"), + lockable: false, subheader: '<span>\ <span class="total_acl"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/clusters-tab.js b/src/sunstone/public/app/tabs/clusters-tab.js index 5881903b40..90965c3dd9 100644 --- a/src/sunstone/public/app/tabs/clusters-tab.js +++ b/src/sunstone/public/app/tabs/clusters-tab.js @@ -49,6 +49,7 @@ define(function(require) { parentTab: "infrastructure-top-tab", listHeader: Locale.tr("Clusters"), infoHeader: Locale.tr("Cluster"), + lockable: false, subheader: '<span>\ <span class="total_clusters"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/datastores-tab.js b/src/sunstone/public/app/tabs/datastores-tab.js index 2c00fa7b58..a1bb9c2acd 100644 --- a/src/sunstone/public/app/tabs/datastores-tab.js +++ b/src/sunstone/public/app/tabs/datastores-tab.js @@ -49,6 +49,7 @@ define(function(require) { parentTab: "storage-top-tab", listHeader: Locale.tr("Datastores"), infoHeader: Locale.tr("Datastore"), + lockable: false, subheader: '<span class="total_ds"/> <small>'+Locale.tr("TOTAL")+'</small> \ <span class="total_on"/> <small>'+Locale.tr("ON")+'</small> \ <span class="total_off"/> <small>'+Locale.tr("OFF")+'</small>', diff --git a/src/sunstone/public/app/tabs/files-tab.js b/src/sunstone/public/app/tabs/files-tab.js index 31ff1a3ffc..76eb42bc1d 100644 --- a/src/sunstone/public/app/tabs/files-tab.js +++ b/src/sunstone/public/app/tabs/files-tab.js @@ -45,6 +45,7 @@ define(function(require) { parentTab: "storage-top-tab", listHeader: Locale.tr("Files"), infoHeader: Locale.tr("File"), + lockable: false, subheader: '<span>\ <span class="total_files"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/groups-tab.js b/src/sunstone/public/app/tabs/groups-tab.js index 4789c22592..b31214d71e 100644 --- a/src/sunstone/public/app/tabs/groups-tab.js +++ b/src/sunstone/public/app/tabs/groups-tab.js @@ -52,6 +52,7 @@ define(function(require) { parentTab: "system-top-tab", listHeader: Locale.tr("Groups"), infoHeader: Locale.tr("Group"), + lockable: false, subheader: '<span>\ <span class="total_groups"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/hosts-tab.js b/src/sunstone/public/app/tabs/hosts-tab.js index d8ed07a934..fecd6655b6 100644 --- a/src/sunstone/public/app/tabs/hosts-tab.js +++ b/src/sunstone/public/app/tabs/hosts-tab.js @@ -54,6 +54,7 @@ define(function(require) { parentTab: "infrastructure-top-tab", listHeader: Locale.tr("Hosts"), infoHeader: Locale.tr("Host"), + lockable: false, subheader: '<span class="total_hosts"/> <small>' + Locale.tr("TOTAL") + '</small> \ <span class="on_hosts"/> <small>' + Locale.tr("ON") + '</small> \ <span class="off_hosts"/> <small>' + Locale.tr("OFF") + '</small> \ diff --git a/src/sunstone/public/app/tabs/images-tab.js b/src/sunstone/public/app/tabs/images-tab.js index c1a515f8e6..e751834525 100644 --- a/src/sunstone/public/app/tabs/images-tab.js +++ b/src/sunstone/public/app/tabs/images-tab.js @@ -50,6 +50,7 @@ define(function(require) { parentTab: "storage-top-tab", listHeader: Locale.tr("Images"), infoHeader: Locale.tr("Image"), + lockable: true, subheader: '<span class="total_images"/> <small>'+Locale.tr("TOTAL")+'</small> \ <span class="size_images"/> <small>'+Locale.tr("TOTAL SIZE")+'</small>', resource: 'Image', diff --git a/src/sunstone/public/app/tabs/images-tab/actions.js b/src/sunstone/public/app/tabs/images-tab/actions.js index 67b37e2a18..40d2033cab 100644 --- a/src/sunstone/public/app/tabs/images-tab/actions.js +++ b/src/sunstone/public/app/tabs/images-tab/actions.js @@ -64,6 +64,10 @@ 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.lockM": _commonActions.multipleAction('lock'), + "Image.lockU": _commonActions.multipleAction('lock'), + "Image.lockA": _commonActions.multipleAction('lock'), + "Image.unlock": _commonActions.multipleAction('unlock'), "Image.upload_marketplace_dialog" : { type: "custom", call: function(params) { diff --git a/src/sunstone/public/app/tabs/images-tab/buttons.js b/src/sunstone/public/app/tabs/images-tab/buttons.js index c4f61a5787..8f8b40a58c 100644 --- a/src/sunstone/public/app/tabs/images-tab/buttons.js +++ b/src/sunstone/public/app/tabs/images-tab/buttons.js @@ -16,6 +16,7 @@ define(function(require) { var Locale = require('utils/locale'); + var Tips = require('utils/tips'); var Buttons = { "Image.refresh" : { @@ -83,6 +84,29 @@ define(function(require) { }, "Image.edit_labels" : { layout: "labels", + }, + "Image.lockA" : { + type: "action", + text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + layout: "lock_buttons", + data: 3 + }, + "Image.lockM" : { + type: "action", + text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + layout: "lock_buttons", + data: 2 + }, + "Image.lockU" : { + type: "action", + text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + layout: "lock_buttons", + data: 1 + }, + "Image.unlock" : { + type: "action", + text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + layout: "lock_buttons" } } diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab.js b/src/sunstone/public/app/tabs/marketplaceapps-tab.js index 516547d8bb..35d89ddb63 100644 --- a/src/sunstone/public/app/tabs/marketplaceapps-tab.js +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab.js @@ -52,6 +52,7 @@ define(function(require) { parentTab: "storage-top-tab", listHeader: Locale.tr("Apps"), infoHeader: Locale.tr("App"), + lockable: true, subheader: '<span>\ <span class="total_apps"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/actions.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/actions.js index 35a4d3ff6d..d65572d5e0 100644 --- a/src/sunstone/public/app/tabs/marketplaceapps-tab/actions.js +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/actions.js @@ -37,6 +37,10 @@ define(function(require) { var _actions = { "MarketPlaceApp.create" : _commonActions.create(CREATE_DIALOG_ID), "MarketPlaceApp.create_dialog" : _commonActions.showCreate(CREATE_DIALOG_ID), + "MarketPlaceApp.lockM": _commonActions.multipleAction('lock'), + "MarketPlaceApp.lockU": _commonActions.multipleAction('lock'), + "MarketPlaceApp.lockA": _commonActions.multipleAction('lock'), + "MarketPlaceApp.unlock": _commonActions.multipleAction('unlock'), "MarketPlaceApp.download_opennebula_dialog" : { type: "custom", call: function() { diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js index f04ea48d52..5d9ba5fcf9 100644 --- a/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js @@ -16,6 +16,7 @@ define(function(require) { var Locale = require('utils/locale'); + var Tips = require('utils/tips'); var MarketPlaceAppButtons = { "MarketPlaceApp.refresh" : { @@ -66,6 +67,29 @@ define(function(require) { }, "MarketPlaceApp.edit_labels" : { layout: "labels", + }, + "MarketPlaceApp.lockA" : { + type: "action", + text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + layout: "lock_buttons", + data: 3 + }, + "MarketPlaceApp.lockM" : { + type: "action", + text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + layout: "lock_buttons", + data: 2 + }, + "MarketPlaceApp.lockU" : { + type: "action", + text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + layout: "lock_buttons", + data: 1 + }, + "MarketPlaceApp.unlock" : { + type: "action", + text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + layout: "lock_buttons" } }; diff --git a/src/sunstone/public/app/tabs/marketplaces-tab.js b/src/sunstone/public/app/tabs/marketplaces-tab.js index 2feea51b4b..0389c36794 100644 --- a/src/sunstone/public/app/tabs/marketplaces-tab.js +++ b/src/sunstone/public/app/tabs/marketplaces-tab.js @@ -51,6 +51,7 @@ define(function(require) { parentTab: "storage-top-tab", listHeader: Locale.tr("MarketPlaces"), infoHeader: Locale.tr("MarketPlace"), + lockable: false, subheader: '<span>\ <span class="total_markets"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/oneflow-services-tab.js b/src/sunstone/public/app/tabs/oneflow-services-tab.js index 12391238ea..bb50c513d5 100644 --- a/src/sunstone/public/app/tabs/oneflow-services-tab.js +++ b/src/sunstone/public/app/tabs/oneflow-services-tab.js @@ -50,6 +50,7 @@ define(function(require) { parentTab: "instances-top-tab", listHeader: Locale.tr("Services"), infoHeader: Locale.tr("Service"), + lockable: false, subheader: '', content: '<div class="row oneflow_services_error_message" hidden>\ <div class="small-6 columns small-centered text-center">\ diff --git a/src/sunstone/public/app/tabs/oneflow-templates-tab.js b/src/sunstone/public/app/tabs/oneflow-templates-tab.js index 40c89d1f78..d20933629f 100644 --- a/src/sunstone/public/app/tabs/oneflow-templates-tab.js +++ b/src/sunstone/public/app/tabs/oneflow-templates-tab.js @@ -51,6 +51,7 @@ define(function(require) { parentTab: "templates-top-tab", listHeader: Locale.tr("Service Templates"), infoHeader: Locale.tr("Service Template"), + lockable: false, subheader: '', content: '<div class="row oneflow_templates_error_message" hidden>\ <div class="small-6 columns small-centered text-center">\ diff --git a/src/sunstone/public/app/tabs/secgroups-tab.js b/src/sunstone/public/app/tabs/secgroups-tab.js index a444671faf..d53ac0d78a 100644 --- a/src/sunstone/public/app/tabs/secgroups-tab.js +++ b/src/sunstone/public/app/tabs/secgroups-tab.js @@ -48,6 +48,7 @@ define(function(require) { parentTab: "network-top-tab", listHeader: Locale.tr("Security Groups"), infoHeader: Locale.tr("Security Group"), + lockable: false, subheader: '<span>\ <span class="total_secgroups"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/templates-tab.js b/src/sunstone/public/app/tabs/templates-tab.js index ddc37667de..e0ded27fad 100644 --- a/src/sunstone/public/app/tabs/templates-tab.js +++ b/src/sunstone/public/app/tabs/templates-tab.js @@ -50,6 +50,7 @@ define(function(require) { parentTab: "templates-top-tab", listHeader: Locale.tr("VM Templates"), infoHeader: Locale.tr("VM Template"), + lockable: true, subheader: '<span>\ <span class="total_templates"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/templates-tab/actions-common.js b/src/sunstone/public/app/tabs/templates-tab/actions-common.js index 9259448321..650b759a40 100644 --- a/src/sunstone/public/app/tabs/templates-tab/actions-common.js +++ b/src/sunstone/public/app/tabs/templates-tab/actions-common.js @@ -45,7 +45,7 @@ define(function(require) { _actions[resource+".show"] = _commonActions.show(), _actions[resource+".refresh"] = _commonActions.refresh(), _actions[resource+".delete"] = _commonActions.del(), - + _actions[resource+".delete_dialog"] = { type: "custom", @@ -250,9 +250,13 @@ define(function(require) { }, error: Notifier.onError, notify: true - } + }, + _actions[resource+".lockA"] = _commonActions.multipleAction("lock"), + _actions[resource+".lockM"] = _commonActions.multipleAction("lock"), + _actions[resource+".lockU"] = _commonActions.multipleAction("lock"), + _actions[resource+".unlock"] = _commonActions.multipleAction("unlock") + - return _actions; } diff --git a/src/sunstone/public/app/tabs/templates-tab/buttons.js b/src/sunstone/public/app/tabs/templates-tab/buttons.js index ed7831e3bd..bad31000c5 100644 --- a/src/sunstone/public/app/tabs/templates-tab/buttons.js +++ b/src/sunstone/public/app/tabs/templates-tab/buttons.js @@ -16,6 +16,7 @@ define(function(require) { var Locale = require('utils/locale'); + var Tips = require('utils/tips'); var Buttons = { "Template.refresh" : { @@ -82,6 +83,29 @@ define(function(require) { }, "Template.edit_labels" : { layout: "labels", + }, + "Template.lockA" : { + type: "action", + text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + layout: "lock_buttons", + data: 3 + }, + "Template.lockM" : { + type: "action", + text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + layout: "lock_buttons", + data: 2 + }, + "Template.lockU" : { + type: "action", + text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + layout: "lock_buttons", + data: 1 + }, + "Template.unlock" : { + type: "action", + text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + layout: "lock_buttons" } }; diff --git a/src/sunstone/public/app/tabs/users-tab.js b/src/sunstone/public/app/tabs/users-tab.js index 5dbea857a3..e16e823476 100644 --- a/src/sunstone/public/app/tabs/users-tab.js +++ b/src/sunstone/public/app/tabs/users-tab.js @@ -56,6 +56,7 @@ define(function(require) { parentTab: "system-top-tab", listHeader: Locale.tr("Users"), infoHeader: Locale.tr("User"), + lockable: false, subheader: '<span>\ <span class="total_users"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/vdcs-tab.js b/src/sunstone/public/app/tabs/vdcs-tab.js index 8fcbe3c35c..4453556012 100644 --- a/src/sunstone/public/app/tabs/vdcs-tab.js +++ b/src/sunstone/public/app/tabs/vdcs-tab.js @@ -48,6 +48,7 @@ define(function(require) { parentTab: "system-top-tab", listHeader: Locale.tr("Virtual Data Centers"), infoHeader: Locale.tr("Virtual Data Center"), + lockable: false, subheader: '<span>\ <span class="total_vdcs"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/vmgroup-tab.js b/src/sunstone/public/app/tabs/vmgroup-tab.js index 926ac408a3..0d49e26028 100644 --- a/src/sunstone/public/app/tabs/vmgroup-tab.js +++ b/src/sunstone/public/app/tabs/vmgroup-tab.js @@ -40,6 +40,7 @@ define(function(require) { parentTab: "templates-top-tab", listHeader: Locale.tr("VM Groups"), infoHeader: Locale.tr("VM Groups"), + lockable: true, subheader: '<span>\ <span class="total_vmgroup"/> <small>'+Locale.tr("TOTAL")+'</small>\ </small> \ diff --git a/src/sunstone/public/app/tabs/vmgroup-tab/actions.js b/src/sunstone/public/app/tabs/vmgroup-tab/actions.js index f6965cbcde..e004e6e366 100644 --- a/src/sunstone/public/app/tabs/vmgroup-tab/actions.js +++ b/src/sunstone/public/app/tabs/vmgroup-tab/actions.js @@ -46,7 +46,11 @@ define(function(require) { "VMGroup.append_template" : _commonActions.appendTemplate(), "VMGroup.chown": _commonActions.multipleAction('chown'), "VMGroup.chgrp": _commonActions.multipleAction('chgrp'), - "VMGroup.chmod": _commonActions.singleAction('chmod') + "VMGroup.chmod": _commonActions.singleAction('chmod'), + "VMGroup.lockM": _commonActions.multipleAction('lock'), + "VMGroup.lockU": _commonActions.multipleAction('lock'), + "VMGroup.lockA": _commonActions.multipleAction('lock'), + "VMGroup.unlock": _commonActions.multipleAction('unlock') }; return _actions; diff --git a/src/sunstone/public/app/tabs/vmgroup-tab/buttons.js b/src/sunstone/public/app/tabs/vmgroup-tab/buttons.js index dc4933d710..7414111f14 100644 --- a/src/sunstone/public/app/tabs/vmgroup-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vmgroup-tab/buttons.js @@ -17,6 +17,7 @@ define(function(require) { var Locale = require('utils/locale'); var TemplateButtons = require('tabs/templates-tab/buttons'); + var Tips = require('utils/tips'); var Buttons = { "VMGroup.refresh" : { @@ -51,6 +52,29 @@ define(function(require) { type: "confirm", text: Locale.tr("Delete"), layout: "del" + }, + "VMGroup.lockA" : { + type: "action", + text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + layout: "lock_buttons", + data: 3 + }, + "VMGroup.lockM" : { + type: "action", + text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + layout: "lock_buttons", + data: 2 + }, + "VMGroup.lockU" : { + type: "action", + text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + layout: "lock_buttons", + data: 1 + }, + "VMGroup.unlock" : { + type: "action", + text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + layout: "lock_buttons" }/*, "VMGroup.edit_labels" : { layout: "labels", diff --git a/src/sunstone/public/app/tabs/vms-tab.js b/src/sunstone/public/app/tabs/vms-tab.js index 423e318ae6..ae247d9c7f 100644 --- a/src/sunstone/public/app/tabs/vms-tab.js +++ b/src/sunstone/public/app/tabs/vms-tab.js @@ -70,6 +70,7 @@ define(function(require) { parentTab: "instances-top-tab", listHeader: Locale.tr("VMs"), infoHeader: Locale.tr("VM"), + lockable: true, subheader: '<span class="total_vms"/> <small>' + Locale.tr("TOTAL") + '</small> \ <span class="active_vms"/> <small>' + Locale.tr("ACTIVE") + '</small> \ <span class="off_vms"/> <small>' + Locale.tr("OFF") + '</small> \ diff --git a/src/sunstone/public/app/tabs/vms-tab/actions.js b/src/sunstone/public/app/tabs/vms-tab/actions.js index 38d65c32cd..b0763043a3 100644 --- a/src/sunstone/public/app/tabs/vms-tab/actions.js +++ b/src/sunstone/public/app/tabs/vms-tab/actions.js @@ -75,6 +75,10 @@ define(function(require) { "VM.recover": _commonActions.multipleAction('recover'), "VM.resched": _commonActions.multipleAction('resched'), "VM.unresched": _commonActions.multipleAction('unresched'), + "VM.lockM": _commonActions.multipleAction('lock'), + "VM.lockU": _commonActions.multipleAction('lock'), + "VM.lockA": _commonActions.multipleAction('lock'), + "VM.unlock": _commonActions.multipleAction('unlock'), "VM.chmod": _commonActions.singleAction('chmod'), "VM.rename": _commonActions.singleAction('rename'), diff --git a/src/sunstone/public/app/tabs/vms-tab/buttons.js b/src/sunstone/public/app/tabs/vms-tab/buttons.js index f578e902d0..912bb8c5b2 100644 --- a/src/sunstone/public/app/tabs/vms-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vms-tab/buttons.js @@ -197,6 +197,29 @@ define(function(require) { }, "VM.edit_labels" : { layout: "labels", + }, + "VM.lockA" : { + type: "action", + text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + layout: "lock_buttons", + data: 3 + }, + "VM.lockM" : { + type: "action", + text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + layout: "lock_buttons", + data: 2 + }, + "VM.lockU" : { + type: "action", + text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + layout: "lock_buttons", + data: 1 + }, + "VM.unlock" : { + type: "action", + text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + layout: "lock_buttons" } } return Buttons; diff --git a/src/sunstone/public/app/tabs/vms-tab/hooks/header.js b/src/sunstone/public/app/tabs/vms-tab/hooks/header.js index eca1454a82..e2a201fb6e 100644 --- a/src/sunstone/public/app/tabs/vms-tab/hooks/header.js +++ b/src/sunstone/public/app/tabs/vms-tab/hooks/header.js @@ -20,6 +20,8 @@ define(function(require) { */ var OpenNebulaVM = require('opennebula/vm'); + var Locale = require('utils/locale'); + var Humanize = require('utils/humanize'); /* CONSTANTS @@ -45,6 +47,13 @@ define(function(require) { $('.resource-info-header', '#' + TAB_ID).text(element.NAME); $('.resource-info-header-small', '#' + TAB_ID).text(state); + + if (element.LOCK){ + $('.resource-lock-header-small', '#' + TAB_ID).html("<i class='header-title fa fa-lock'> "+Locale.tr(Humanize.lock_to_str(element.LOCK.LOCKED))+"</i>"); + $('.resource-lock-header-small', '#' + TAB_ID).show(); + } else { + $('.resource-lock-header-small', '#' + TAB_ID).hide(); + } } function _post(info, contextTabId) { diff --git a/src/sunstone/public/app/tabs/vnets-tab.js b/src/sunstone/public/app/tabs/vnets-tab.js index 40e24b26af..426d53aedb 100644 --- a/src/sunstone/public/app/tabs/vnets-tab.js +++ b/src/sunstone/public/app/tabs/vnets-tab.js @@ -55,6 +55,7 @@ define(function(require) { parentTab: "network-top-tab", listHeader: Locale.tr("Virtual Networks"), infoHeader: Locale.tr("Virtual Network"), + lockable: true, subheader: '<span class="total_vnets"/> <small>'+Locale.tr("TOTAL")+'</small> \ <span class="addresses_vnets"/> <small>'+Locale.tr("USED IPs")+'</small>', resource: 'Network', diff --git a/src/sunstone/public/app/tabs/vnets-tab/actions.js b/src/sunstone/public/app/tabs/vnets-tab/actions.js index 6353d2c9e8..795662d1f0 100644 --- a/src/sunstone/public/app/tabs/vnets-tab/actions.js +++ b/src/sunstone/public/app/tabs/vnets-tab/actions.js @@ -55,6 +55,10 @@ define(function(require) { "Network.append_template" : _commonActions.appendTemplate(), "Network.update_dialog" : _commonActions.checkAndShowUpdate(), "Network.show_to_update" : _commonActions.showUpdate(CREATE_DIALOG_ID), + "Network.lockM": _commonActions.multipleAction('lock'), + "Network.lockU": _commonActions.multipleAction('lock'), + "Network.lockA": _commonActions.multipleAction('lock'), + "Network.unlock": _commonActions.multipleAction('unlock'), "Network.import_dialog" : { type: "custom", diff --git a/src/sunstone/public/app/tabs/vnets-tab/buttons.js b/src/sunstone/public/app/tabs/vnets-tab/buttons.js index 1721133d0e..db19b24136 100644 --- a/src/sunstone/public/app/tabs/vnets-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vnets-tab/buttons.js @@ -16,6 +16,7 @@ define(function(require) { var Locale = require('utils/locale'); + var Tips = require('utils/tips'); var VNetButtons = { "Network.refresh" : { @@ -73,6 +74,29 @@ define(function(require) { }, "Network.edit_labels" : { layout: "labels", + }, + "Network.lockA" : { + type: "action", + text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + layout: "lock_buttons", + data: 3 + }, + "Network.lockM" : { + type: "action", + text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + layout: "lock_buttons", + data: 2 + }, + "Network.lockU" : { + type: "action", + text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + layout: "lock_buttons", + data: 1 + }, + "Network.unlock" : { + type: "action", + text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + layout: "lock_buttons" } }; diff --git a/src/sunstone/public/app/tabs/vrouter-templates-tab.js b/src/sunstone/public/app/tabs/vrouter-templates-tab.js index 3dbb7b2440..f8ab20bb13 100644 --- a/src/sunstone/public/app/tabs/vrouter-templates-tab.js +++ b/src/sunstone/public/app/tabs/vrouter-templates-tab.js @@ -48,6 +48,7 @@ define(function(require) { parentTab: "templates-top-tab", listHeader: Locale.tr("Virtual Router VM Templates"), infoHeader: Locale.tr("Virtual Router VM Template"), + lockable: true, subheader: '<span>\ <span class="total_vrouters"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/vrouters-tab.js b/src/sunstone/public/app/tabs/vrouters-tab.js index d9b4fa9236..7af6e72229 100644 --- a/src/sunstone/public/app/tabs/vrouters-tab.js +++ b/src/sunstone/public/app/tabs/vrouters-tab.js @@ -49,6 +49,7 @@ define(function(require) { parentTab: "instances-top-tab", listHeader: Locale.tr("Virtual Routers"), infoHeader: Locale.tr("Virtual Router"), + lockable: true, subheader: '<span>\ <span class="total_routers"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/tabs/vrouters-tab/actions.js b/src/sunstone/public/app/tabs/vrouters-tab/actions.js index 0259a89fe5..838371b9c3 100644 --- a/src/sunstone/public/app/tabs/vrouters-tab/actions.js +++ b/src/sunstone/public/app/tabs/vrouters-tab/actions.js @@ -34,6 +34,10 @@ define(function(require) { var _actions = { "VirtualRouter.create" : _commonActions.create(CREATE_DIALOG_ID), "VirtualRouter.create_dialog" : _commonActions.showCreate(CREATE_DIALOG_ID), + "VirtualRouter.lockM": _commonActions.multipleAction('lock'), + "VirtualRouter.lockU": _commonActions.multipleAction('lock'), + "VirtualRouter.lockA": _commonActions.multipleAction('lock'), + "VirtualRouter.unlock": _commonActions.multipleAction('unlock'), "VirtualRouter.instantiate_vms" : { type: "custom", call: function() { diff --git a/src/sunstone/public/app/tabs/vrouters-tab/buttons.js b/src/sunstone/public/app/tabs/vrouters-tab/buttons.js index f921277b5b..a73ed8ec77 100644 --- a/src/sunstone/public/app/tabs/vrouters-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vrouters-tab/buttons.js @@ -16,6 +16,7 @@ define(function(require) { var Locale = require('utils/locale'); + var Tips = require('utils/tips'); var Buttons = { "VirtualRouter.refresh" : { @@ -53,6 +54,29 @@ define(function(require) { }, "VirtualRouter.edit_labels" : { layout: "labels", + }, + "VirtualRouter.lockA" : { + type: "action", + text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + layout: "lock_buttons", + data: 3 + }, + "VirtualRouter.lockM" : { + type: "action", + text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + layout: "lock_buttons", + data: 2 + }, + "VirtualRouter.lockU" : { + type: "action", + text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + layout: "lock_buttons", + data: 1 + }, + "VirtualRouter.unlock" : { + type: "action", + text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + layout: "lock_buttons" } }; diff --git a/src/sunstone/public/app/tabs/zones-tab.js b/src/sunstone/public/app/tabs/zones-tab.js index caa6895f33..3a52f3746e 100644 --- a/src/sunstone/public/app/tabs/zones-tab.js +++ b/src/sunstone/public/app/tabs/zones-tab.js @@ -43,6 +43,7 @@ define(function(require) { parentTab: "infrastructure-top-tab", listHeader: Locale.tr("Zones"), infoHeader: Locale.tr("Zone"), + lockable: false, subheader: '<span>\ <span class="total_zones"/> <small>'+Locale.tr("TOTAL")+'</small>\ </span>', diff --git a/src/sunstone/public/app/utils/hooks/header.js b/src/sunstone/public/app/utils/hooks/header.js index 83da714615..3912b25284 100644 --- a/src/sunstone/public/app/utils/hooks/header.js +++ b/src/sunstone/public/app/utils/hooks/header.js @@ -19,11 +19,19 @@ define(function(require) { /* FUNCTION DEFINITIONS */ + var Locale = require('utils/locale'); + var Humanize = require('utils/humanize'); function _pre(info, contextTabId) { var element = info[Object.keys(info)[0]]; $('.resource-info-header', '#' + contextTabId).text(element.NAME); + + if (element.LOCK){ + $('.resource-lock-header-small', '#' + contextTabId).html("<span data-tooltip aria-haspopup='true' class='has-tip' data-disable-hover='false' tabindex='1' title="+Locale.tr(Humanize.lock_to_str(element.LOCK.LOCKED))+"><i class='fa fa-lock fa-2x'/></span>"); + } else { + $('.resource-lock-header-small', '#' + contextTabId).html("<i style='color: #cacedd;' class='fa fa-unlock-alt fa-2x'/>"); + } } function _post(info, contextTabId) { diff --git a/src/sunstone/public/app/utils/humanize.js b/src/sunstone/public/app/utils/humanize.js index af9c21d189..cd045ccc34 100644 --- a/src/sunstone/public/app/utils/humanize.js +++ b/src/sunstone/public/app/utils/humanize.js @@ -34,7 +34,8 @@ define(function(require) { 'prettyTimeAxis': _prettyTimeAxis, 'prettyPrintJSON': _prettyPrintJSON, 'prettyTimeAgo': _format_date, - 'prettyTimeDatatable': _prettyTimeDatatable + 'prettyTimeDatatable': _prettyTimeDatatable, + 'lock_to_str': _lock_to_str } /* @@ -299,7 +300,9 @@ define(function(require) { return difference_in_seconds; function _fourdigits(number) { - return (number < 1000) ? number + 1900 : number;} + return (number < 1000) ? number + 1900 : number; + } + //function _plural(number) { // if(parseInt(number) === 1) { @@ -308,4 +311,22 @@ define(function(require) { // return "s"; //} } + function _lock_to_str(level) { + var level_str = ""; + switch(level) { + case "1": + level_str = "Use"; + break; + case "2": + level_str = "Manage"; + break; + case "3": + level_str = "Admin"; + break; + case "4": + level_str = "All"; + break; + } + return level_str; + } }) diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index a493f6b7e9..2d4a213e85 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -1953,6 +1953,7 @@ string& VirtualMachine::to_xml_extended(string& xml, int n_history) const string history_xml; string perm_xml; string snap_xml; + string lock_str; ostringstream oss; @@ -1973,6 +1974,7 @@ string& VirtualMachine::to_xml_extended(string& xml, int n_history) const << "<STIME>" << stime << "</STIME>" << "<ETIME>" << etime << "</ETIME>" << "<DEPLOY_ID>" << deploy_id << "</DEPLOY_ID>" + << lock_db_to_xml(lock_str) << monitoring.to_xml(monitoring_xml) << obj_template->to_xml(template_xml) << user_obj_template->to_xml(user_template_xml); @@ -2072,6 +2074,8 @@ int VirtualMachine::from_xml(const string &xml_str) prev_state = static_cast<VmState>(istate); prev_lcm_state = static_cast<LcmState>(ilcmstate); + rc += lock_db_from_xml(); + // ------------------------------------------------------------------------- // Virtual Machine template and attributes // ------------------------------------------------------------------------- diff --git a/src/vm_group/VMGroup.cc b/src/vm_group/VMGroup.cc index b4bfe2c2d3..3eb7357fb0 100644 --- a/src/vm_group/VMGroup.cc +++ b/src/vm_group/VMGroup.cc @@ -63,6 +63,7 @@ string& VMGroup::to_xml(string& xml) const string template_xml; string perms_xml; string roles_xml; + string lock_str; oss << "<VM_GROUP>" << @@ -73,6 +74,7 @@ string& VMGroup::to_xml(string& xml) const "<GNAME>" << gname << "</GNAME>" << "<NAME>" << name << "</NAME>" << perms_to_xml(perms_xml) << + lock_db_to_xml(lock_str) << roles.to_xml(roles_xml) << obj_template->to_xml(template_xml) << "</VM_GROUP>"; @@ -103,6 +105,9 @@ int VMGroup::from_xml(const string &xml_str) // Permissions rc += perms_from_xml(); + // Lock + rc += lock_db_from_xml(); + // Get associated template ObjectXML::get_nodes("/VM_GROUP/TEMPLATE", content); diff --git a/src/vm_template/VMTemplate.cc b/src/vm_template/VMTemplate.cc index 7347aba17f..45a5f6ed2b 100644 --- a/src/vm_template/VMTemplate.cc +++ b/src/vm_template/VMTemplate.cc @@ -208,6 +208,7 @@ string& VMTemplate::to_xml(string& xml, const Template* tmpl) const ostringstream oss; string template_xml; string perm_str; + string lock_str; oss << "<VMTEMPLATE>" << "<ID>" << oid << "</ID>" @@ -216,6 +217,7 @@ string& VMTemplate::to_xml(string& xml, const Template* tmpl) const << "<UNAME>" << uname << "</UNAME>" << "<GNAME>" << gname << "</GNAME>" << "<NAME>" << name << "</NAME>" + << lock_db_to_xml(lock_str) << perms_to_xml(perm_str) << "<REGTIME>" << regtime << "</REGTIME>" << tmpl->to_xml(template_xml) @@ -246,6 +248,7 @@ int VMTemplate::from_xml(const string& xml) rc += xpath(name, "/VMTEMPLATE/NAME", "not_found"); rc += xpath<time_t>(regtime, "/VMTEMPLATE/REGTIME", 0); + rc += lock_db_from_xml(); // Permissions rc += perms_from_xml(); diff --git a/src/vnm/VirtualNetwork.cc b/src/vnm/VirtualNetwork.cc index ac51b305ed..1c6b93aa42 100644 --- a/src/vnm/VirtualNetwork.cc +++ b/src/vnm/VirtualNetwork.cc @@ -428,6 +428,7 @@ string& VirtualNetwork::to_xml_extended(string& xml, bool extended, string template_xml; string leases_xml; string perm_str; + string lock_str; int int_vlan_id_automatic = vlan_id_automatic ? 1 : 0; @@ -439,6 +440,7 @@ string& VirtualNetwork::to_xml_extended(string& xml, bool extended, "<UNAME>" << uname << "</UNAME>" << "<GNAME>" << gname << "</GNAME>" << "<NAME>" << name << "</NAME>" << + lock_db_to_xml(lock_str) << perms_to_xml(perm_str) << Clusterable::to_xml(clusters_xml) << "<BRIDGE>" << one_util::escape_xml(bridge) << "</BRIDGE>"; @@ -518,6 +520,8 @@ int VirtualNetwork::from_xml(const string &xml_str) rc += xpath(name, "/VNET/NAME", "not_found"); rc += xpath(bridge, "/VNET/BRIDGE","not_found"); + rc += lock_db_from_xml(); + // Permissions rc += perms_from_xml(); diff --git a/src/vrouter/VirtualRouter.cc b/src/vrouter/VirtualRouter.cc index a4fdd9c312..584379e2ba 100644 --- a/src/vrouter/VirtualRouter.cc +++ b/src/vrouter/VirtualRouter.cc @@ -307,6 +307,7 @@ string& VirtualRouter::to_xml(string& xml) const string template_xml; string vm_collection_xml; string perm_str; + string lock_str; oss << "<VROUTER>" << "<ID>" << oid << "</ID>" @@ -316,6 +317,7 @@ string& VirtualRouter::to_xml(string& xml) const << "<GNAME>" << gname << "</GNAME>" << "<NAME>" << name << "</NAME>" << perms_to_xml(perm_str) + << lock_db_to_xml(lock_str) << vms.to_xml(vm_collection_xml) << obj_template->to_xml(template_xml) << "</VROUTER>"; @@ -347,6 +349,9 @@ int VirtualRouter::from_xml(const string& xml) // Permissions rc += perms_from_xml(); + // Lock + rc += lock_db_from_xml(); + // Get associated classes rc += vms.from_xml(this, "/VROUTER/"); From 5399f21a8e4fe5a835853cc3f35bd821331c705a Mon Sep 17 00:00:00 2001 From: juanmont <jjmontiel@opennebula.org> Date: Wed, 24 Jan 2018 17:04:17 +0100 Subject: [PATCH 5/6] F #1377: Resolved Bugs --- src/sunstone/public/app/sunstone.js | 4 ++++ src/sunstone/public/app/tabs/images-tab/buttons.js | 8 ++++---- .../public/app/tabs/marketplaceapps-tab/buttons.js | 8 ++++---- src/sunstone/public/app/tabs/templates-tab/buttons.js | 8 ++++---- src/sunstone/public/app/tabs/vmgroup-tab/buttons.js | 8 ++++---- src/sunstone/public/app/tabs/vms-tab/buttons.js | 8 ++++---- src/sunstone/public/app/tabs/vms-tab/hooks/header.js | 5 ++--- src/sunstone/public/app/tabs/vnets-tab/buttons.js | 8 ++++---- src/sunstone/public/app/tabs/vrouters-tab/buttons.js | 8 ++++---- 9 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/sunstone/public/app/sunstone.js b/src/sunstone/public/app/sunstone.js index 0d7100ee70..089795d4cc 100644 --- a/src/sunstone/public/app/sunstone.js +++ b/src/sunstone/public/app/sunstone.js @@ -430,6 +430,10 @@ define(function(require) { $("button[data-toggle=" + customId + "lock_buttons]", actionBlock).remove(); } + if ($("#" + customId + "vmspause_buttons li", actionBlock).length == 0) { + $("button[data-toggle=" + customId + "vmspause_buttons]", actionBlock).remove(); + } + if ($("#" + customId + "vmsrepeat_buttons li", actionBlock).length == 0) { $("button[data-toggle=" + customId + "vmsrepeat_buttons]", actionBlock).remove(); } diff --git a/src/sunstone/public/app/tabs/images-tab/buttons.js b/src/sunstone/public/app/tabs/images-tab/buttons.js index 8f8b40a58c..4f76f09d04 100644 --- a/src/sunstone/public/app/tabs/images-tab/buttons.js +++ b/src/sunstone/public/app/tabs/images-tab/buttons.js @@ -87,25 +87,25 @@ define(function(require) { }, "Image.lockA" : { type: "action", - text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + text: Locale.tr("Admin"), layout: "lock_buttons", data: 3 }, "Image.lockM" : { type: "action", - text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + text: Locale.tr("Manage"), layout: "lock_buttons", data: 2 }, "Image.lockU" : { type: "action", - text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + text: Locale.tr("Use"), layout: "lock_buttons", data: 1 }, "Image.unlock" : { type: "action", - text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + text: Locale.tr("Unlock"), layout: "lock_buttons" } } diff --git a/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js b/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js index 5d9ba5fcf9..26c2550d2b 100644 --- a/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js +++ b/src/sunstone/public/app/tabs/marketplaceapps-tab/buttons.js @@ -70,25 +70,25 @@ define(function(require) { }, "MarketPlaceApp.lockA" : { type: "action", - text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + text: Locale.tr("Admin"), layout: "lock_buttons", data: 3 }, "MarketPlaceApp.lockM" : { type: "action", - text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + text: Locale.tr("Manage"), layout: "lock_buttons", data: 2 }, "MarketPlaceApp.lockU" : { type: "action", - text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + text: Locale.tr("Use"), layout: "lock_buttons", data: 1 }, "MarketPlaceApp.unlock" : { type: "action", - text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + text: Locale.tr("Unlock"), layout: "lock_buttons" } }; diff --git a/src/sunstone/public/app/tabs/templates-tab/buttons.js b/src/sunstone/public/app/tabs/templates-tab/buttons.js index bad31000c5..718c67eed9 100644 --- a/src/sunstone/public/app/tabs/templates-tab/buttons.js +++ b/src/sunstone/public/app/tabs/templates-tab/buttons.js @@ -86,25 +86,25 @@ define(function(require) { }, "Template.lockA" : { type: "action", - text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + text: Locale.tr("Admin"), layout: "lock_buttons", data: 3 }, "Template.lockM" : { type: "action", - text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + text: Locale.tr("Manage"), layout: "lock_buttons", data: 2 }, "Template.lockU" : { type: "action", - text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + text: Locale.tr("Use"), layout: "lock_buttons", data: 1 }, "Template.unlock" : { type: "action", - text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + text: Locale.tr("Unlock"), layout: "lock_buttons" } }; diff --git a/src/sunstone/public/app/tabs/vmgroup-tab/buttons.js b/src/sunstone/public/app/tabs/vmgroup-tab/buttons.js index 7414111f14..6f34fbedf8 100644 --- a/src/sunstone/public/app/tabs/vmgroup-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vmgroup-tab/buttons.js @@ -55,25 +55,25 @@ define(function(require) { }, "VMGroup.lockA" : { type: "action", - text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + text: Locale.tr("Admin"), layout: "lock_buttons", data: 3 }, "VMGroup.lockM" : { type: "action", - text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + text: Locale.tr("Manage"), layout: "lock_buttons", data: 2 }, "VMGroup.lockU" : { type: "action", - text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + text: Locale.tr("Use"), layout: "lock_buttons", data: 1 }, "VMGroup.unlock" : { type: "action", - text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + text: Locale.tr("Unlock"), layout: "lock_buttons" }/*, "VMGroup.edit_labels" : { diff --git a/src/sunstone/public/app/tabs/vms-tab/buttons.js b/src/sunstone/public/app/tabs/vms-tab/buttons.js index 912bb8c5b2..34a0aa07ca 100644 --- a/src/sunstone/public/app/tabs/vms-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vms-tab/buttons.js @@ -200,25 +200,25 @@ define(function(require) { }, "VM.lockA" : { type: "action", - text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + text: Locale.tr("Admin"), layout: "lock_buttons", data: 3 }, "VM.lockM" : { type: "action", - text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + text: Locale.tr("Manage"), layout: "lock_buttons", data: 2 }, "VM.lockU" : { type: "action", - text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + text: Locale.tr("Use"), layout: "lock_buttons", data: 1 }, "VM.unlock" : { type: "action", - text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + text: Locale.tr("Unlock"), layout: "lock_buttons" } } diff --git a/src/sunstone/public/app/tabs/vms-tab/hooks/header.js b/src/sunstone/public/app/tabs/vms-tab/hooks/header.js index e2a201fb6e..ecf19ee1db 100644 --- a/src/sunstone/public/app/tabs/vms-tab/hooks/header.js +++ b/src/sunstone/public/app/tabs/vms-tab/hooks/header.js @@ -49,10 +49,9 @@ define(function(require) { $('.resource-info-header-small', '#' + TAB_ID).text(state); if (element.LOCK){ - $('.resource-lock-header-small', '#' + TAB_ID).html("<i class='header-title fa fa-lock'> "+Locale.tr(Humanize.lock_to_str(element.LOCK.LOCKED))+"</i>"); - $('.resource-lock-header-small', '#' + TAB_ID).show(); + $('.resource-lock-header-small', '#' + contextTabId).html("<span data-tooltip aria-haspopup='true' class='has-tip' data-disable-hover='false' tabindex='1' title="+Locale.tr(Humanize.lock_to_str(element.LOCK.LOCKED))+"><i class='fa fa-lock fa-2x'/></span>"); } else { - $('.resource-lock-header-small', '#' + TAB_ID).hide(); + $('.resource-lock-header-small', '#' + contextTabId).html("<i style='color: #cacedd;' class='fa fa-unlock-alt fa-2x'/>"); } } diff --git a/src/sunstone/public/app/tabs/vnets-tab/buttons.js b/src/sunstone/public/app/tabs/vnets-tab/buttons.js index db19b24136..a7dcdfc027 100644 --- a/src/sunstone/public/app/tabs/vnets-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vnets-tab/buttons.js @@ -77,25 +77,25 @@ define(function(require) { }, "Network.lockA" : { type: "action", - text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + text: Locale.tr("Admin"), layout: "lock_buttons", data: 3 }, "Network.lockM" : { type: "action", - text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + text: Locale.tr("Manage"), layout: "lock_buttons", data: 2 }, "Network.lockU" : { type: "action", - text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + text: Locale.tr("Use"), layout: "lock_buttons", data: 1 }, "Network.unlock" : { type: "action", - text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + text: Locale.tr("Unlock"), layout: "lock_buttons" } }; diff --git a/src/sunstone/public/app/tabs/vrouters-tab/buttons.js b/src/sunstone/public/app/tabs/vrouters-tab/buttons.js index a73ed8ec77..ca2b3099b4 100644 --- a/src/sunstone/public/app/tabs/vrouters-tab/buttons.js +++ b/src/sunstone/public/app/tabs/vrouters-tab/buttons.js @@ -57,25 +57,25 @@ define(function(require) { }, "VirtualRouter.lockA" : { type: "action", - text: Locale.tr("Admin") + "<span class='right'> " + Tips.html(Locale.tr("Lock Admin actions")) + "</span>", + text: Locale.tr("Admin"), layout: "lock_buttons", data: 3 }, "VirtualRouter.lockM" : { type: "action", - text: Locale.tr("Manage") + "<span class='right'> " + Tips.html(Locale.tr("Lock Manage actions")) + "</span>", + text: Locale.tr("Manage"), layout: "lock_buttons", data: 2 }, "VirtualRouter.lockU" : { type: "action", - text: Locale.tr("Use") + "<span class='right'> " + Tips.html(Locale.tr("Lock Use actions")) + "</span>", + text: Locale.tr("Use"), layout: "lock_buttons", data: 1 }, "VirtualRouter.unlock" : { type: "action", - text: Locale.tr("Unlock") + "<span class='right'> " + Tips.html(Locale.tr("Unlock all actions")) + "</span>", + text: Locale.tr("Unlock"), layout: "lock_buttons" } }; From 3cd612540feb6fc48d209ec160722ff54ee955b1 Mon Sep 17 00:00:00 2001 From: "Ruben S. Montero" <rsmontero@opennebula.org> Date: Thu, 25 Jan 2018 12:04:35 +0100 Subject: [PATCH 6/6] B #1412: Fix missing condition when image was locked --- include/ImageManager.h | 12 ++++---- include/ImagePool.h | 5 ++-- src/image/ImageManagerActions.cc | 47 ++++++++++++++++++-------------- src/image/ImagePool.cc | 8 +++--- src/vm/VirtualMachineDisk.cc | 4 +-- 5 files changed, 42 insertions(+), 34 deletions(-) diff --git a/include/ImageManager.h b/include/ImageManager.h index 6548eb28a1..b205c3d59d 100644 --- a/include/ImageManager.h +++ b/include/ImageManager.h @@ -94,20 +94,20 @@ public: * Try to acquire an image from the repository for a VM. * @param image_id id of image * @param error string describing the error - * @param attach indicates that are trying to make an attachment of the image + * @param attach true if attaching the image to a VM * @return pointer to the image or 0 if could not be acquired */ - Image * acquire_image(int vm_id, int image_id, string& error, bool attach); + Image * acquire_image(int vm_id, int image_id, bool attach, string& error); /** * Try to acquire an image from the repository for a VM. * @param name of the image * @param id of owner * @param error string describing the error - * @param attach indicates that are trying to make an attachment of the image + * @param attach true if attaching the image to a VM * @return pointer to the image or 0 if could not be acquired */ - Image * acquire_image(int vm_id, const string& name, int uid, string& error, bool attach); + Image * acquire_image(int vm_id, const string& name, int uid, bool attach, string& error); /** * Releases an image and triggers any needed operations in the repo @@ -360,10 +360,10 @@ private: /** * Acquires an image updating its state. * @param image pointer to image, it should be locked - * @param attach indicates that are trying to make an attachment of the image + * @param attach true if attaching the image to a VM * @return 0 on success */ - int acquire_image(int vm_id, Image *img, string& error, bool attach); + int acquire_image(int vm_id, Image *img, bool attach, string& error); /** * Moves a file to an image in the repository diff --git a/include/ImagePool.h b/include/ImagePool.h index d38faa8e3a..96c453282d 100644 --- a/include/ImagePool.h +++ b/include/ImagePool.h @@ -154,6 +154,7 @@ public: * @param uid of VM owner (to look for the image id within its images) * @param image_id on success returns the acquired image id * @param snaps list of snapshots associated to this image + * @param attach true if attaching the image to a VM * @param error_str string describing the error * * @return 0 on success, -1 otherwise @@ -166,8 +167,8 @@ public: int uid, int& image_id, Snapshots ** snaps, - string& error_str, - bool attach); + bool attach, + string& error_str); /** * Generates a DISK attribute for VM templates using the Image metadata * diff --git a/src/image/ImageManagerActions.cc b/src/image/ImageManagerActions.cc index d4703507d7..9af29d6f14 100644 --- a/src/image/ImageManagerActions.cc +++ b/src/image/ImageManagerActions.cc @@ -25,7 +25,8 @@ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -Image * ImageManager::acquire_image(int vm_id, int image_id, string& error, bool attach) +Image * ImageManager::acquire_image(int vm_id, int image_id, bool attach, + string& error) { Image * img; int rc; @@ -41,7 +42,7 @@ Image * ImageManager::acquire_image(int vm_id, int image_id, string& error, bool return 0; } - rc = acquire_image(vm_id, img, error, attach); + rc = acquire_image(vm_id, img, attach, error); if ( rc != 0 ) { @@ -54,7 +55,8 @@ Image * ImageManager::acquire_image(int vm_id, int image_id, string& error, bool /* -------------------------------------------------------------------------- */ -Image * ImageManager::acquire_image(int vm_id, const string& name, int uid, string& error, bool attach) +Image * ImageManager::acquire_image(int vm_id, const string& name, int uid, + bool attach, string& error) { Image * img; int rc; @@ -71,7 +73,7 @@ Image * ImageManager::acquire_image(int vm_id, const string& name, int uid, stri return 0; } - rc = acquire_image(vm_id, img, error, attach); + rc = acquire_image(vm_id, img, attach, error); if ( rc != 0 ) { @@ -84,7 +86,7 @@ Image * ImageManager::acquire_image(int vm_id, const string& name, int uid, stri /* -------------------------------------------------------------------------- */ -int ImageManager::acquire_image(int vm_id, Image *img, string& error, bool attach) +int ImageManager::acquire_image(int vm_id, Image *img, bool attach, string& error) { int rc = 0; @@ -129,24 +131,26 @@ int ImageManager::acquire_image(int vm_id, Image *img, string& error, bool attac if (attach) { oss << "Cannot acquire image " << img->get_oid() - << ", it is locked"; + << ", it is locked"; error = oss.str(); rc = -1; } - - img->inc_running(vm_id); - - if ( img->is_persistent() ) - { - img->set_state(Image::LOCKED_USED_PERS); - } else { - img->set_state(Image::LOCKED_USED); - } + img->inc_running(vm_id); - ipool->update(img); + if ( img->is_persistent() ) + { + img->set_state(Image::LOCKED_USED_PERS); + } + else + { + img->set_state(Image::LOCKED_USED); + } + + ipool->update(img); + } break; case Image::USED_PERS: @@ -162,18 +166,21 @@ int ImageManager::acquire_image(int vm_id, Image *img, string& error, bool attac img->inc_running(vm_id); ipool->update(img); break; + case Image::LOCKED_USED: if (attach) { oss << "Cannot acquire image " << img->get_oid() - << ", it is locked"; + << ", it is locked"; error = oss.str(); rc = -1; } - - img->inc_running(vm_id); - ipool->update(img); + else + { + img->inc_running(vm_id); + ipool->update(img); + } break; case Image::INIT: diff --git a/src/image/ImagePool.cc b/src/image/ImagePool.cc index 85f5145e94..b15520e5b3 100644 --- a/src/image/ImagePool.cc +++ b/src/image/ImagePool.cc @@ -297,8 +297,8 @@ int ImagePool::acquire_disk(int vm_id, int uid, int& image_id, Snapshots ** snap, - string& error_str, - bool attach) + bool attach, + string& error_str) { string source; Image * img = 0; @@ -315,7 +315,7 @@ int ImagePool::acquire_disk(int vm_id, if ( disk->vector_value("IMAGE_ID", iid) == 0 ) { - img = imagem->acquire_image(vm_id, iid, error_str, attach); + img = imagem->acquire_image(vm_id, iid, attach, error_str); if ( img == 0 ) { @@ -337,7 +337,7 @@ int ImagePool::acquire_disk(int vm_id, return -1; } - img = imagem->acquire_image(vm_id, source, uiid, error_str, attach); + img = imagem->acquire_image(vm_id, source, uiid, attach, error_str); if ( img == 0 ) { diff --git a/src/vm/VirtualMachineDisk.cc b/src/vm/VirtualMachineDisk.cc index 53951c6afb..ecfacee071 100644 --- a/src/vm/VirtualMachineDisk.cc +++ b/src/vm/VirtualMachineDisk.cc @@ -751,7 +751,7 @@ int VirtualMachineDisks::get_images(int vm_id, int uid, const std::string& tsys, } if ( ipool->acquire_disk(vm_id, disk, disk_id, image_type, dev_prefix, - uid, image_id, &snapshots, error_str, false) != 0 ) + uid, image_id, &snapshots, false, error_str) != 0 ) { oss << "DISK " << disk_id << ": " << error_str; error_str = oss.str(); @@ -1076,7 +1076,7 @@ VirtualMachineDisk * VirtualMachineDisks::set_up_attach(int vmid, int uid, VirtualMachineDisk * disk = new VirtualMachineDisk(vdisk, max_disk_id + 1); int rc = ipool->acquire_disk(vmid, disk, max_disk_id + 1, img_type, - dev_prefix, uid, image_id, &snap, error, true); + dev_prefix, uid, image_id, &snap, true, error); if ( rc != 0 ) { return 0;