def getAllVmNames(self, node=None): """Returns a list of all VMs within the cluster or those registered on a specific node""" if node is not None: ArgumentValidator.validate_hostname(node) # If no node was defined, check the local configuration for all VMs if node is None: return [vm['name'] for vm in VirtualMachineConfig.get_global_config().values()] elif node == get_hostname(): # @TODO - Why is this using libvirt?! Should use # VM objects (i.e. config file to determine) # and use a seperate function to get libvirt # registered VMs # Obtain array of all domains from libvirt all_domains = self._get_registered_object( 'libvirt_connector').get_connection().listAllDomains() return [vm.name() for vm in all_domains] else: # Return list of VMs registered on remote node cluster = self._get_registered_object('cluster') def remote_command(node_connection): """Get virtual machine names from remote node""" virtual_machine_factory = node_connection.get_connection('virtual_machine_factory') return virtual_machine_factory.getAllVmNames(node=node) return cluster.run_remote_command(callback_method=remote_command, nodes=[node])[node]
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 check_exists(self, vm_name): """Determines if a VM exists, given a name""" try: ArgumentValidator.validate_hostname(vm_name) except (MCVirtTypeError, InvalidVirtualMachineNameException): return False return (vm_name in self.getAllVmNames())
def check_exists_by_name(self, name): """Determines if a VM exists, given a name""" try: ArgumentValidator.validate_hostname(name) except (MCVirtTypeError, InvalidVirtualMachineNameException): return False return name in self.getAllVmNames()
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 get_virtual_machine_by_name(self, vm_name): """Obtain a VM object, based on VM name""" ArgumentValidator.validate_hostname(vm_name) name_id_dict = { val['name']: key for key, val in VirtualMachineConfig.get_global_config().items() } if vm_name not in name_id_dict: raise VirtualMachineDoesNotExistException( 'Error: Virtual Machine does not exist: %s' % vm_name ) return self.get_virtual_machine_by_id(name_id_dict[vm_name])
def checkName(self, name, ignore_exists=False): try: ArgumentValidator.validate_hostname(name) except MCVirtTypeError: raise InvalidVirtualMachineNameException( 'Error: Invalid VM Name - VM Name can only contain 0-9 a-Z and dashes' ) if len(name) < 3: raise InvalidVirtualMachineNameException('VM Name must be at least 3 characters long') if self.check_exists_by_name(name) and not ignore_exists: raise VmAlreadyExistsException('VM already exists') return True
def checkName(self, name, ignore_exists=False): try: ArgumentValidator.validate_hostname(name) except MCVirtTypeError: raise InvalidVirtualMachineNameException( 'Error: Invalid VM Name - VM Name can only contain 0-9 a-Z and dashes' ) if len(name) < 3: raise InvalidVirtualMachineNameException( 'VM Name must be at least 3 characters long') if self.check_exists(name) and not ignore_exists: raise VmAlreadyExistsException('VM already exists') return True
def getAllVmNames(self, node=None): """Returns a list of all VMs within the cluster or those registered on a specific node""" if node is not None: ArgumentValidator.validate_hostname(node) # If no node was defined, check the local configuration for all VMs if (node is None): return MCVirtConfig().get_config()['virtual_machines'] elif node == get_hostname(): # Obtain array of all domains from libvirt all_domains = self._get_registered_object( 'libvirt_connector').get_connection().listAllDomains() return [vm.name() for vm in all_domains] else: # Return list of VMs registered on remote node cluster = self._get_registered_object('cluster') def remote_command(node_connection): virtual_machine_factory = node_connection.get_connection('virtual_machine_factory') return virtual_machine_factory.getAllVmNames(node=node) return cluster.run_remote_command(callback_method=remote_command, nodes=[node])[node]
def getAllVmNames(self, node=None): """Returns a list of all VMs within the cluster or those registered on a specific node""" if node is not None: ArgumentValidator.validate_hostname(node) # If no node was defined, check the local configuration for all VMs if (node is None): return MCVirtConfig().get_config()['virtual_machines'] elif node == get_hostname(): # Obtain array of all domains from libvirt all_domains = self._get_registered_object( 'libvirt_connector').get_connection().listAllDomains() return [vm.name() for vm in all_domains] else: # Return list of VMs registered on remote node cluster = self._get_registered_object('cluster') def remote_command(node_connection): virtual_machine_factory = node_connection.get_connection( 'virtual_machine_factory') return virtual_machine_factory.getAllVmNames(node=node) return cluster.run_remote_command(callback_method=remote_command, nodes=[node])[node]
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 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
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