diff --git a/VERSION b/VERSION index ae9a76b9..8104cabd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.0.0 +8.1.0 diff --git a/source/DEBIAN/control b/source/DEBIAN/control index 90d8896d..c7ec4796 100644 --- a/source/DEBIAN/control +++ b/source/DEBIAN/control @@ -1,5 +1,5 @@ Package: mcvirt -Version: 8.0.0 +Version: 8.1.0 Section: utils Maintainer: I.T. Dev Ltd Architecture: all diff --git a/source/usr/lib/python2.7/dist-packages/mcvirt/auth/auth.py b/source/usr/lib/python2.7/dist-packages/mcvirt/auth/auth.py index c7464a5d..7ee741e1 100644 --- a/source/usr/lib/python2.7/dist-packages/mcvirt/auth/auth.py +++ b/source/usr/lib/python2.7/dist-packages/mcvirt/auth/auth.py @@ -239,9 +239,10 @@ def add_user_permission_group(self, permission_group, user_object, assert permission_group in PERMISSION_GROUPS.keys() assert isinstance(self._convert_remote_object(user_object), self._get_registered_object('user_factory').USER_CLASS) - assert isinstance(self._convert_remote_object(vm_object), - self._get_registered_object( - 'virtual_machine_factory').VIRTUAL_MACHINE_CLASS) + if vm_object: + assert isinstance(self._convert_remote_object(vm_object), + self._get_registered_object( + 'virtual_machine_factory').VIRTUAL_MACHINE_CLASS) ArgumentValidator.validate_boolean(ignore_duplicate) # Check if user running script is able to add users to permission group @@ -302,9 +303,10 @@ def delete_user_permission_group(self, permission_group, user_object, vm_object= assert permission_group in PERMISSION_GROUPS.keys() assert isinstance(self._convert_remote_object(user_object), self._get_registered_object('user_factory').USER_CLASS) - assert isinstance(self._convert_remote_object(vm_object), - self._get_registered_object( - 'virtual_machine_factory').VIRTUAL_MACHINE_CLASS) + if vm_object: + assert isinstance(self._convert_remote_object(vm_object), + self._get_registered_object( + 'virtual_machine_factory').VIRTUAL_MACHINE_CLASS) # Check if user running script is able to remove users to permission group if not (self.is_superuser() or (self.assert_permission(PERMISSIONS.MANAGE_VM_USERS, vm_object) and diff --git a/source/usr/lib/python2.7/dist-packages/mcvirt/parser.py b/source/usr/lib/python2.7/dist-packages/mcvirt/parser.py index dbf0502e..473b12fa 100644 --- a/source/usr/lib/python2.7/dist-packages/mcvirt/parser.py +++ b/source/usr/lib/python2.7/dist-packages/mcvirt/parser.py @@ -294,6 +294,8 @@ def __init__(self, verbose=True): ) self.update_parser.add_argument('--add-disk', dest='add_disk', metavar='Add Disk', type=int, help='Add disk to the VM (size in MB)') + self.update_parser.add_argument('--delete-disk', dest='delete_disk', metavar='Disk ID', + type=int, help='Remove a hard drive from a VM') self.update_parser.add_argument('--storage-type', dest='storage_type', metavar='Storage backing type', type=str, default=None, choices=['Local', 'Drbd']) @@ -1027,6 +1029,11 @@ def parse_arguments(self, script_args=None): hard_drive_factory.create(vm_object, size=args.add_disk, storage_type=args.storage_type, driver=args.hard_disk_driver) + if args.delete_disk: + hard_drive_factory = rpc.get_connection('hard_drive_factory') + hard_drive_object = hard_drive_factory.getObject(vm_object, args.disk_id) + rpc.annotate_object(hard_drive_object) + hard_drive_object.increaseSize(args.delete()) if args.increase_disk and args.disk_id: hard_drive_factory = rpc.get_connection('hard_drive_factory') diff --git a/source/usr/lib/python2.7/dist-packages/mcvirt/test/auth_tests.py b/source/usr/lib/python2.7/dist-packages/mcvirt/test/auth_tests.py index d3cc675b..2a5db1fa 100644 --- a/source/usr/lib/python2.7/dist-packages/mcvirt/test/auth_tests.py +++ b/source/usr/lib/python2.7/dist-packages/mcvirt/test/auth_tests.py @@ -84,7 +84,8 @@ def tearDown(self): def suite(): """Returns a test suite of the Auth tests""" suite = unittest.TestSuite() - suite.addTest(AuthTests('test_add_remove_user_permission')) + suite.addTest(AuthTests('test_add_remove_user_vm_permission')) + suite.addTest(AuthTests('test_add_remove_user_global_permission')) suite.addTest(AuthTests('test_add_delete_superuser')) suite.addTest(AuthTests('test_attempt_add_superuser_to_vm')) suite.addTest(AuthTests('test_add_duplicate_superuser')) @@ -94,11 +95,21 @@ def suite(): suite.addTest(AuthTests('test_remove_user_account')) return suite - def test_add_remove_user_permission(self): + def test_add_remove_user_vm_permission(self): + """Permission permission tests using VM role""" + self.test_add_remove_user_permission(global_permission=False) + + def test_add_remove_user_global_permission(self): + """Permission permission tests using global role""" + self.test_add_remove_user_permission(global_permission=True) + + def test_add_remove_user_permission(self, global_permission): """Add a user to a virtual machine, using the argument parser""" # Ensure VM does not exist test_vm_object = self.create_vm('TEST_VM_1', 'Local') + permission_string = '--global' if global_permission else test_vm_object.get_name() + # Ensure user is not in 'user' group self.assertFalse( self.test_user.get_username() in @@ -112,12 +123,12 @@ def test_add_remove_user_permission(self): # Add user to 'user' group using parser self.parser.parse_arguments('permission --add-user %s %s' % (self.test_user.get_username(), - test_vm_object.get_name())) + permission_string)) # Ensure VM exists self.assertTrue( self.test_user.get_username() in self.auth.get_users_in_permission_group( - 'user', test_vm_object) + 'user', test_vm_object if (not global_permission) else None) ) # Ensure that user can now start the VM @@ -132,17 +143,17 @@ def test_add_remove_user_permission(self): # Add user to 'user' group using parser self.parser.parse_arguments('permission --add-user %s %s' % (self.test_user.get_username(), - test_vm_object.get_name())) + permission_string)) # Remove user to 'user' group using parser self.parser.parse_arguments('permission --delete-user %s %s' % (self.test_user.get_username(), - test_vm_object.get_name())) + permission_string)) # Assert that user is no longer part of the group self.assertFalse( self.test_user.get_username() in self.auth.get_users_in_permission_group( - 'user', test_vm_object) + 'user', test_vm_object if (not global_permission) else None) ) # Assert that the test user cannot stop the test VM diff --git a/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/hard_drive/base.py b/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/hard_drive/base.py index 4bb32489..dd3c640b 100644 --- a/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/hard_drive/base.py +++ b/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/hard_drive/base.py @@ -200,12 +200,22 @@ def get_type(self): """Return the type of storage for the hard drive""" return self.__class__.__name__ + @Expose(locking=True) def delete(self): """Delete the logical volume for the disk""" self._ensure_exists() + # Ensure that the user has permissions to add create storage + self._get_registered_object('auth').assert_permission( + PERMISSIONS.MODIFY_VM, + self.vm_object + ) + cache_key = (self.vm_object.get_name(), self.disk_id, self.get_type()) + self.vm_object.ensureUnlocked() + self.vm_object.ensure_stopped() + if self.vm_object.isRegisteredLocally(): # Remove from LibVirt, if registered, so that libvirt doesn't # hold the device open when the storage is removed diff --git a/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/hard_drive/drbd.py b/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/hard_drive/drbd.py index 2e459124..8da21356 100644 --- a/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/hard_drive/drbd.py +++ b/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/hard_drive/drbd.py @@ -925,6 +925,11 @@ def verify(self): PERMISSIONS.MANAGE_DRBD, self.vm_object ) + if get_hostname() not in self.vm_object.getAvailableNodes(): + remote_object = self.get_remote_object( + node_name=(self.vm_object.getNode() or self.vm_object.getAvailableNodes()[0])) + return remote_object.verify() + # Check Drbd state of disk if self._drbdGetConnectionState() != DrbdConnectionState.CONNECTED: raise DrbdStateException( @@ -969,6 +974,11 @@ def resync(self, source_node=None, auto_determine=False): self._get_registered_object('auth').assert_permission( PERMISSIONS.MANAGE_DRBD, self.vm_object) + if get_hostname() not in self.vm_object.getAvailableNodes(): + remote_object = self.get_remote_object( + node_name=(self.vm_object.getNode() or self.vm_object.getAvailableNodes()[0])) + return remote_object.resync(source_node=source_node, auto_determine=auto_determine) + if source_node: if source_node not in self.vm_object.getAvailableNodes(): raise InvalidNodesException('Invalid node name') diff --git a/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/virtual_machine.py b/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/virtual_machine.py index 4194d07c..ec50206f 100644 --- a/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/virtual_machine.py +++ b/source/usr/lib/python2.7/dist-packages/mcvirt/virtual_machine/virtual_machine.py @@ -187,6 +187,11 @@ def shutdown(self): 'VM registered elsewhere and cluster is not initialised' ) + def ensure_stopped(self): + """Ensure VM is stopped""" + if self._getPowerState() is not PowerStates.STOPPED: + raise VmAlreadyStartedException('VM is not stopped') + @Expose(locking=True) def start(self, iso_name=None): """Starts the VM"""