def test_add_user(self): """Adds a user to a virtual machine, using the argument parser""" # Ensure VM does not exist test_vm_object = VirtualMachine.create( self.mcvirt, self.test_vm['name'], self.test_vm['cpu_count'], self.test_vm['memory_allocation'], self.test_vm['disks'], self.test_vm['networks']) self.assertTrue( VirtualMachine._check_exists( self.mcvirt.getLibvirtConnection(), self.test_vm['name'])) # Ensure user is not in 'user' group self.assertFalse( self.test_user in self.auth_object.get_users_in_permission_group( 'user', test_vm_object)) # Add user to 'user' group using parser self.parser.parse_arguments( 'permission --add-user %s %s' % (self.test_user, self.test_vm['name']), mcvirt_instance=self.mcvirt) # Ensure VM exists self.assertTrue( self.test_user in self.auth_object.get_users_in_permission_group( 'user', test_vm_object))
def getVirtualMachineByName(self, vm_name): """Obtain a VM object, based on VM name""" ArgumentValidator.validate_hostname(vm_name) if vm_name not in Factory.CACHED_OBJECTS: vm_object = VirtualMachine(self, vm_name) self._register_object(vm_object) Factory.CACHED_OBJECTS[vm_name] = vm_object return Factory.CACHED_OBJECTS[vm_name]
def test_vm_directory_already_exists(self): """Attempt to create a VM whilst the directory for the VM already exists""" # Create the directory for the VM os.makedirs(VirtualMachine._get_vm_dir(self.test_vms['TEST_VM_1']['name'])) # Attempt to create VM, expecting an exception for the directory already existing with self.assertRaises(VmDirectoryAlreadyExistsException): self.parser.parse_arguments('create %s' % self.test_vms['TEST_VM_1']['name'] + ' --cpu-count %s --disk-size %s --memory %s' % (self.test_vms['TEST_VM_1']['cpu_count'], self.test_vms['TEST_VM_1']['disk_size'][0], self.test_vms['TEST_VM_1']['memory_allocation']) + ' --network %s --storage-type %s' % (self.test_vms['TEST_VM_1']['networks'][0], 'Local')) # Ensure the VM has not been created self.assertFalse(self.vm_factory.check_exists(self.test_vms['TEST_VM_1']['name'])) # Remove directory shutil.rmtree(VirtualMachine._get_vm_dir(self.test_vms['TEST_VM_1']['name']))
def get_virtual_machine_by_id(self, vm_id): """Obtain a VM object, based on VM name""" # Validate VM ID ArgumentValidator.validate_id(vm_id, VirtualMachine) # Check that the domain exists if not self.check_exists(vm_id): raise VirtualMachineDoesNotExistException( 'Error: Virtual Machine does not exist: %s' % vm_id ) # Determine if VM object has been cached if vm_id not in Factory.CACHED_OBJECTS: # If not, create object, register with pyro # and store in cached object dict vm_object = VirtualMachine(vm_id) self._register_object(vm_object) vm_object.initialise() Factory.CACHED_OBJECTS[vm_id] = vm_object # Return the cached object return Factory.CACHED_OBJECTS[vm_id]
def test_delete(self, storage_type): """Test the deletion of a VM through the argument parser""" # Create Virtual machine self.create_vm('TEST_VM_1', storage_type) # Remove VM using parser self.parser.parse_arguments('delete %s --delete-data' % self.test_vms['TEST_VM_1']['name']) # Ensure VM has been deleted self.assertFalse(self.vm_factory.check_exists(self.test_vms['TEST_VM_1']['name'])) # Ensure that VM directory does not exist self.assertFalse(os.path.exists( VirtualMachine._get_vm_dir(self.test_vms['TEST_VM_1']['name']) ))
def test_attempt_add_superuser_to_vm(self): """Attempts to add a user as a superuser to a VM""" test_vm_object = VirtualMachine.create( self.mcvirt, self.test_vm['name'], self.test_vm['cpu_count'], self.test_vm['memory_allocation'], self.test_vm['disks'], self.test_vm['networks'] ) with self.assertRaises(MCVirtException): self.parser.parse_arguments('permission --add-superuser %s %s' % (self.test_user, self.test_vm['name']), mcvirt_instance=self.mcvirt)
def test_remove_user(self): """Removes a user from a virtual machine, using the argument parser""" # Ensure VM does not exist test_vm_object = VirtualMachine.create( self.mcvirt, self.test_vm['name'], self.test_vm['cpu_count'], self.test_vm['memory_allocation'], self.test_vm['disks'], self.test_vm['networks']) self.assertTrue( VirtualMachine._check_exists( self.mcvirt.getLibvirtConnection(), self.test_vm['name'])) # Add user to 'user' group and ensure they have been added self.auth_object.add_user_permission_group(self.mcvirt, 'user', self.test_user, test_vm_object) self.assertTrue( self.test_user in self.auth_object.get_users_in_permission_group( 'user', test_vm_object)) # Remove user from 'user' group using parser self.parser.parse_arguments( 'permission --delete-user %s %s' % (self.test_user, self.test_vm['name']), mcvirt_instance=self.mcvirt) # Ensure user is no longer in 'user' group self.assertFalse( self.test_user in self.auth_object.get_users_in_permission_group( 'user', test_vm_object ))
def get_config_path(vm_name): """Provides the path of the VM-spefic configuration file""" from mcvirt.virtual_machine.virtual_machine import VirtualMachine return ('%s/config.json' % VirtualMachine._get_vm_dir(vm_name))
def get_config_path(vm_name): """Provides the path of the VM-spefic configuration file""" from mcvirt.virtual_machine.virtual_machine import VirtualMachine return ('%s/config.json' % VirtualMachine._get_vm_dir(vm_name))
def _create(self, name, cpu_cores, memory_allocation, hard_drives=None, network_interfaces=None, node=None, available_nodes=None, storage_type=None, hard_drive_driver=None, graphics_driver=None, modification_flags=None): """Create a VM and returns the virtual_machine object for it""" network_interfaces = [] if network_interfaces is None else network_interfaces hard_drives = [] if hard_drives is None else hard_drives available_nodes = [] if available_nodes is None else available_nodes modification_flags = [] if modification_flags is None else modification_flags self.checkName(name) ArgumentValidator.validate_positive_integer(cpu_cores) ArgumentValidator.validate_positive_integer(memory_allocation) for hard_drive in hard_drives: ArgumentValidator.validate_positive_integer(hard_drive) if network_interfaces: for network_interface in network_interfaces: ArgumentValidator.validate_network_name(network_interface) if node is not None: ArgumentValidator.validate_hostname(node) for available_node in available_nodes: ArgumentValidator.validate_hostname(available_node) assert storage_type in [None] + [ storage_type_itx.__name__ for storage_type_itx in self._get_registered_object('hard_drive_factory').STORAGE_TYPES ] if hard_drive_driver is not None: HardDriveDriver[hard_drive_driver] # If no graphics driver has been specified, set it to the default if graphics_driver is None: graphics_driver = self.DEFAULT_GRAPHICS_DRIVER # Check the driver name is valid self.check_graphics_driver(graphics_driver) # Ensure the cluster has not been ignored, as VMs cannot be created with MCVirt running # in this state if self._cluster_disabled: raise ClusterNotInitialisedException( 'VM cannot be created whilst the cluster' + ' is not initialised') # Determine if VM already exists if self.check_exists(name): raise VmAlreadyExistsException('Error: VM already exists') # If a node has not been specified, assume the local node if node is None: node = get_hostname() # If Drbd has been chosen as a storage type, ensure it is enabled on the node node_drbd = self._get_registered_object('node_drbd') if storage_type == 'Drbd' and not node_drbd.is_enabled(): raise DrbdNotEnabledOnNode('Drbd is not enabled on this node') # Create directory for VM on the local and remote nodes if os_path_exists(VirtualMachine._get_vm_dir(name)): raise VmDirectoryAlreadyExistsException( 'Error: VM directory already exists') # If available nodes has not been passed, assume the local machine is the only # available node if local storage is being used. Use the machines in the cluster # if Drbd is being used cluster_object = self._get_registered_object('cluster') all_nodes = cluster_object.get_nodes(return_all=True) all_nodes.append(get_hostname()) if len(available_nodes) == 0: if storage_type == 'Drbd': # If the available nodes are not specified, use the # nodes in the cluster available_nodes = all_nodes else: # For local VMs, only use the local node as the available nodes available_nodes = [get_hostname()] # If there are more than the maximum number of Drbd machines in the cluster, # add an option that forces the user to specify the nodes for the Drbd VM # to be added to if storage_type == 'Drbd' and len( available_nodes) != node_drbd.CLUSTER_SIZE: raise InvalidNodesException('Exactly %i nodes must be specified' % node_drbd.CLUSTER_SIZE) for check_node in available_nodes: if check_node not in all_nodes: raise NodeDoesNotExistException('Node \'%s\' does not exist' % check_node) if get_hostname() not in available_nodes and self._is_cluster_master: raise InvalidNodesException( 'One of the nodes must be the local node') # Check whether the hard drives can be created. if self._is_cluster_master: hard_drive_factory = self._get_registered_object( 'hard_drive_factory') for hard_drive_size in hard_drives: hard_drive_factory.ensure_hdd_valid( hard_drive_size, storage_type, [ node_itx for node_itx in available_nodes if node_itx != get_hostname() ]) # Create directory for VM makedirs(VirtualMachine._get_vm_dir(name)) # Add VM to MCVirt configuration def updateMCVirtConfig(config): config['virtual_machines'].append(name) MCVirtConfig().update_config( updateMCVirtConfig, 'Adding new VM \'%s\' to global MCVirt configuration' % name) # Create VM configuration file VirtualMachineConfig.create(name, available_nodes, cpu_cores, memory_allocation, graphics_driver) # Add VM to remote nodes if self._is_cluster_master: def remote_command(remote_connection): virtual_machine_factory = remote_connection.get_connection( 'virtual_machine_factory') virtual_machine_factory.create( name=name, memory_allocation=memory_allocation, cpu_cores=cpu_cores, node=node, available_nodes=available_nodes, modification_flags=modification_flags) cluster_object.run_remote_command(callback_method=remote_command) # Obtain an object for the new VM, to use to create disks/network interfaces vm_object = self.getVirtualMachineByName(name) vm_object.get_config_object().gitAdd('Created VM \'%s\'' % vm_object.get_name()) if node == get_hostname(): # Register VM with LibVirt. If MCVirt has not been initialised on this node, # do not set the node in the VM configuration, as the change can't be # replicated to remote nodes vm_object._register(set_node=self._is_cluster_master) elif self._is_cluster_master: # If MCVirt has been initialised on this node and the local machine is # not the node that the VM will be registered on, set the node on the VM vm_object._setNode(node) if self._is_cluster_master: # Create disk images hard_drive_factory = self._get_registered_object( 'hard_drive_factory') for hard_drive_size in hard_drives: hard_drive_factory.create(vm_object=vm_object, size=hard_drive_size, storage_type=storage_type, driver=hard_drive_driver) # If any have been specified, add a network configuration for each of the # network interfaces to the domain XML network_adapter_factory = self._get_registered_object( 'network_adapter_factory') network_factory = self._get_registered_object('network_factory') if network_interfaces is not None: for network in network_interfaces: network_object = network_factory.get_network_by_name( network) network_adapter_factory.create(vm_object, network_object) # Add modification flags vm_object._update_modification_flags(add_flags=modification_flags) return vm_object
def _create(self, name, cpu_cores, memory_allocation, # Basic details, name etc. hard_drives=None, # List of hard drive sizes to be created network_interfaces=None, # List of networks to create network interfaces # to attach to node=None, # The node to initially register the VM on available_nodes=None, # List of nodes that the VM will be availble to. # For DRBD, this will be the two nodes # that DRBD is setup on. For other storage types, # it will be the nodes that the VM 'MUST' be # compatible with, i.e. storage backend must span # across them and networks exist on all nodes. storage_type=None, # Storage type (string) hard_drive_driver=None, graphics_driver=None, modification_flags=None, storage_backend=None, # Storage backend to be used. If not specified, # will default to an available storage backend, # if only 1 is avaiallbe. is_static=None): # Manually override whether the VM is marked as static """Create a VM and returns the virtual_machine object for it""" # @TODO: Does this method need to do EVERYTHING? # Maybe it should create the BARE MINIMUM required for a VM # and leave it up to the parser to create everything else. # The benefit to doing it in one function is to be able to # validate that everything will work before-hand. # Set iterative items to empty array if not specified. # Can't set these to empty arrays by default, as if we attempt to append to them, # it will alter the default array (since it will be a reference)! network_interfaces = [] if network_interfaces is None else network_interfaces hard_drives = [] if hard_drives is None else hard_drives nodes_predefined = available_nodes is not None available_nodes = [] if available_nodes is None else available_nodes modification_flags = [] if modification_flags is None else modification_flags # Convert memory and disk sizes to bytes hard_drives = [hdd_size if isinstance(hdd_size, int) else SizeConverter.from_string(hdd_size, storage=True).to_bytes() for hdd_size in hard_drives] memory_allocation = (memory_allocation if memory_allocation is isinstance(memory_allocation, int) else SizeConverter.from_string(memory_allocation).to_bytes()) if storage_backend: storage_backend = self._convert_remote_object(storage_backend) # Ensure name is valid, as well as other attributes self.checkName(name) ArgumentValidator.validate_positive_integer(cpu_cores) ArgumentValidator.validate_positive_integer(memory_allocation) for hard_drive in hard_drives: ArgumentValidator.validate_positive_integer(hard_drive) if network_interfaces: for network_interface in network_interfaces: ArgumentValidator.validate_network_name(network_interface) if node is not None: ArgumentValidator.validate_hostname(node) for available_node in available_nodes: ArgumentValidator.validate_hostname(available_node) cluster_object = self._get_registered_object('cluster') local_hostname = get_hostname() if node and available_nodes and node not in available_nodes: raise InvalidNodesException('Node must be in available nodes') total_storage_size = sum(hard_drives) if hard_drives else None available_nodes, storage_backend, storage_type = self._pre_create_checks( required_storage_size=total_storage_size, networks=network_interfaces, storage_type=storage_type, nodes=available_nodes, storage_backend=storage_backend ) # If a node has not been specified, assume the local node if node is None: node = local_hostname # Ensure that the local node is included in the list of available nodes if self._is_cluster_master and local_hostname not in available_nodes: raise InvalidNodesException('Local node must included in available nodes') # Ensure storage_type is a valid type, if specified hard_drive_factory = self._get_registered_object('hard_drive_factory') assert storage_type in [None] + [ storage_type_itx.__name__ for storage_type_itx in self._get_registered_object( 'hard_drive_factory').get_all_storage_types() ] # Obtain the hard drive driver enum from the name if hard_drive_driver is not None: HardDriveDriver[hard_drive_driver] # If no graphics driver has been specified, set it to the default if graphics_driver is None: graphics_driver = self.DEFAULT_GRAPHICS_DRIVER # Check the driver name is valid self.ensure_graphics_driver_valid(graphics_driver) # Ensure the cluster has not been ignored, as VMs cannot be created with MCVirt running # in this state if self._cluster_disabled: raise ClusterNotInitialisedException('VM cannot be created whilst the cluster' + ' is not initialised') # Determine if VM already exists if self.check_exists_by_name(name): raise VmAlreadyExistsException('Error: VM already exists') # Create directory for VM on the local and remote nodes if os_path_exists(VirtualMachine.get_vm_dir(name)): raise VmDirectoryAlreadyExistsException('Error: VM directory already exists') if local_hostname not in available_nodes and self._is_cluster_master: raise InvalidNodesException('One of the nodes must be the local node') # Create VM configuration file # This is hard coded method of determining is_static, as seen in hard drive object # @TODO Refactor into method that's shared with is_static config_nodes = (None if ((storage_backend and storage_backend.shared and storage_type == 'Local') or (is_static is not None and not is_static)) else available_nodes) id_ = VirtualMachine.generate_id(name) # Start transaction t = Transaction() vm_object = self.create_config( id_, name, config_nodes, cpu_cores, memory_allocation, graphics_driver, nodes=self._get_registered_object('cluster').get_nodes(include_local=True)) if node == get_hostname(): # Register VM with LibVirt. If MCVirt has not been initialised on this node, # do not set the node in the VM configuration, as the change can't be # replicated to remote nodes vm_object._register(set_node=self._is_cluster_master) elif self._is_cluster_master: # If MCVirt has been initialised on this node and the local machine is # not the node that the VM will be registered on, set the node on the VM vm_object._setNode(node) if self._is_cluster_master: # Create disk images hard_drive_factory = self._get_registered_object('hard_drive_factory') for hard_drive_size in hard_drives: hard_drive_factory.create(vm_object=vm_object, size=hard_drive_size, storage_type=storage_type, driver=hard_drive_driver, storage_backend=storage_backend, nodes=available_nodes) # If any have been specified, add a network configuration for each of the # network interfaces to the domain XML network_adapter_factory = self._get_registered_object('network_adapter_factory') network_factory = self._get_registered_object('network_factory') if network_interfaces is not None: for network in network_interfaces: network_object = network_factory.get_network_by_name(network) network_adapter_factory.create(vm_object, network_object) # Add modification flags vm_object._update_modification_flags(add_flags=modification_flags) t.finish() return vm_object
def _create(self, name, cpu_cores, memory_allocation, hard_drives=[], network_interfaces=[], node=None, available_nodes=[], storage_type=None, hard_drive_driver=None): """Creates a VM and returns the virtual_machine object for it""" self.checkName(name) ArgumentValidator.validate_positive_integer(cpu_cores) ArgumentValidator.validate_positive_integer(memory_allocation) for hard_drive in hard_drives: ArgumentValidator.validate_positive_integer(hard_drive) if network_interfaces: for network_interface in network_interfaces: ArgumentValidator.validate_network_name(network_interface) if node is not None: ArgumentValidator.validate_hostname(node) for available_node in available_nodes: ArgumentValidator.validate_hostname(available_node) assert storage_type in [None] + [ storage_type_itx.__name__ for storage_type_itx in self._get_registered_object( 'hard_drive_factory').STORAGE_TYPES ] if hard_drive_driver is not None: HardDriveDriver[hard_drive_driver] # Ensure the cluster has not been ignored, as VMs cannot be created with MCVirt running # in this state if self._cluster_disabled: raise ClusterNotInitialisedException('VM cannot be created whilst the cluster' + ' is not initialised') # Determine if VM already exists if self.check_exists(name): raise VmAlreadyExistsException('Error: VM already exists') # If a node has not been specified, assume the local node if node is None: node = get_hostname() # If Drbd has been chosen as a storage type, ensure it is enabled on the node node_drbd = self._get_registered_object('node_drbd') if storage_type == 'Drbd' and not node_drbd.is_enabled(): raise DrbdNotEnabledOnNode('Drbd is not enabled on this node') # Create directory for VM on the local and remote nodes if os_path_exists(VirtualMachine._get_vm_dir(name)): raise VmDirectoryAlreadyExistsException('Error: VM directory already exists') # If available nodes has not been passed, assume the local machine is the only # available node if local storage is being used. Use the machines in the cluster # if Drbd is being used cluster_object = self._get_registered_object('cluster') all_nodes = cluster_object.get_nodes(return_all=True) all_nodes.append(get_hostname()) if len(available_nodes) == 0: if storage_type == 'Drbd': # If the available nodes are not specified, use the # nodes in the cluster available_nodes = all_nodes else: # For local VMs, only use the local node as the available nodes available_nodes = [get_hostname()] # If there are more than the maximum number of Drbd machines in the cluster, # add an option that forces the user to specify the nodes for the Drbd VM # to be added to if storage_type == 'Drbd' and len(available_nodes) != node_drbd.CLUSTER_SIZE: raise InvalidNodesException('Exactly two nodes must be specified') for check_node in available_nodes: if check_node not in all_nodes: raise NodeDoesNotExistException('Node \'%s\' does not exist' % check_node) if get_hostname() not in available_nodes and self._is_cluster_master: raise InvalidNodesException('One of the nodes must be the local node') # Create directory for VM makedirs(VirtualMachine._get_vm_dir(name)) # Add VM to MCVirt configuration def updateMCVirtConfig(config): config['virtual_machines'].append(name) MCVirtConfig().update_config( updateMCVirtConfig, 'Adding new VM \'%s\' to global MCVirt configuration' % name) # Create VM configuration file VirtualMachineConfig.create(name, available_nodes, cpu_cores, memory_allocation) # Add VM to remote nodes if self._is_cluster_master: def remote_command(remote_connection): virtual_machine_factory = remote_connection.get_connection( 'virtual_machine_factory' ) virtual_machine_factory.create( name=name, memory_allocation=memory_allocation, cpu_cores=cpu_cores, node=node, available_nodes=available_nodes ) cluster_object.run_remote_command(callback_method=remote_command) # Obtain an object for the new VM, to use to create disks/network interfaces vm_object = self.getVirtualMachineByName(name) vm_object.get_config_object().gitAdd('Created VM \'%s\'' % vm_object.get_name()) if node == get_hostname(): # Register VM with LibVirt. If MCVirt has not been initialised on this node, # do not set the node in the VM configuration, as the change can't be # replicated to remote nodes vm_object._register(set_node=self._is_cluster_master) elif self._is_cluster_master: # If MCVirt has been initialised on this node and the local machine is # not the node that the VM will be registered on, set the node on the VM vm_object._setNode(node) if self._is_cluster_master: # Create disk images hard_drive_factory = self._get_registered_object('hard_drive_factory') for hard_drive_size in hard_drives: hard_drive_factory.create(vm_object=vm_object, size=hard_drive_size, storage_type=storage_type, driver=hard_drive_driver) # If any have been specified, add a network configuration for each of the # network interfaces to the domain XML network_adapter_factory = self._get_registered_object('network_adapter_factory') network_factory = self._get_registered_object('network_factory') if network_interfaces is not None: for network in network_interfaces: network_object = network_factory.get_network_by_name(network) network_adapter_factory.create(vm_object, network_object) return vm_object
def getVirtualMachineByName(self, vm_name): """Obtain a VM object, based on VM name""" ArgumentValidator.validate_hostname(vm_name) vm_object = VirtualMachine(self, vm_name) self._register_object(vm_object) return vm_object