def set_shared(self, shared): """Set the shared status of the storage backend""" # Check permissions self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_STORAGE_BACKEND) ArgumentValidator.validate_boolean(shared) # Check if there's no change to configuration if self.shared == shared: raise NoConfigurationChangeError('Storage backend is already set to %s' % str(shared)) if self.shared and self.in_use(): raise CannotUnshareInUseStorageBackendError( 'Storage backend is in use, so cannot unshare') def update_shared_config(config): """Set sared parameter to new value""" config['shared'] = shared self.update_config(update_shared_config, 'Update shared status to %s' % shared) if self._is_cluster_master: def update_shared_remote_nodes(connection): """Update shared status of remote nodes""" remote_storage_backend = self.get_remote_object(node_object=connection) remote_storage_backend.set_shared(shared) self._get_registered_object('cluster').run_remote_command( update_shared_remote_nodes)
def add_user_permission_group(self, permission_group, user_object, vm_object=None, ignore_duplicate=False): """Add a user to a permissions group on a 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) ArgumentValidator.validate_boolean(ignore_duplicate) # Check if user running script is able to add users to permission group if not (self.is_superuser() or (vm_object and self.assert_permission( PERMISSIONS.MANAGE_VM_USERS, vm_object) and permission_group == 'user')): raise InsufficientPermissionsException( 'VM owners cannot add manager other owners') user_object = self._convert_remote_object(user_object) vm_object = self._convert_remote_object( vm_object) if vm_object is not None else None username = user_object.get_username() # Check if user is already in the group if (vm_object): config_object = vm_object.get_config_object() else: config_object = MCVirtConfig() if (username not in self.get_users_in_permission_group( permission_group, vm_object)): # Add user to permission configuration for VM def add_user_to_config(config): config['permissions'][permission_group].append(username) config_object.update_config( add_user_to_config, 'Added user \'%s\' to group \'%s\'' % (username, permission_group)) # @TODO FIX ME if self._is_cluster_master: cluster_object = self._get_registered_object('cluster') vm_name = vm_object.get_name() if vm_object else None cluster_object.run_remote_command( 'auth-add_user_permission_group', { 'permission_group': permission_group, 'username': username, 'vm_name': vm_name }) elif not ignore_duplicate: raise DuplicatePermissionException( 'User \'%s\' already in group \'%s\'' % (username, permission_group))
def add_user(self, user, virtual_machine=None, ignore_duplicate=False): """Add uesr to group""" assert isinstance(self._convert_remote_object(user), self._get_registered_object('user_factory').USER_CLASS) if virtual_machine: assert isinstance(self._convert_remote_object(virtual_machine), self._get_registered_object( 'virtual_machine_factory').VIRTUAL_MACHINE_CLASS) ArgumentValidator.validate_boolean(ignore_duplicate) if virtual_machine is not None: virtual_machine = self._convert_remote_object(virtual_machine) # Check if user running script is able to add users to permission group self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_GROUP_MEMBERS, vm_object=virtual_machine) # Convert remote objects user = self._convert_remote_object(user) # Ensure that the user is not already in the group if (user in self.get_users(virtual_machine=virtual_machine) and not ignore_duplicate): raise DuplicatePermissionException('User %s already in group %s' % (user.get_username(), self.name)) cluster = self._get_registered_object('cluster') if virtual_machine: # Convert remote objects self.add_user_to_vm_config( user, virtual_machine, nodes=cluster.get_nodes(include_local=True)) else: self.add_user_to_config(user, nodes=cluster.get_nodes(include_local=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 [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 set_autostart_interval(self, interval_time): """Update the autostart interval for the node""" self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_NODE) ArgumentValidator.validate_integer(interval_time) interval_time = int(interval_time) def update_config(config): config['autostart_interval'] = interval_time self._get_registered_object('mcvirt_config')().update_config(update_config, 'Update autostart interval') if self._is_cluster_master: def remote_update(node): autostart_watchdog = node.get_connection('autostart_watchdog') autostart_watchdog.set_autostart_interval(interval_time) cluster = self._get_registered_object('cluster') cluster.run_remote_command(remote_update) # If the timer has been set to 0, disable the timer if interval_time == 0: self.repeat = False self.timer.cancel() self.timer = None else: # Otherwise update the running timer if self.timer is None: self.repeat = True self.repeat_run()
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 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, id_): """Determines if a VM exists, given a name""" try: ArgumentValidator.validate_id(id_, VirtualMachine) except (MCVirtTypeError, InvalidVirtualMachineNameException): return False return id_ in self.get_all_vm_ids()
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 set_cluster_ip_address(self, ip_address): """Update the cluster IP address for the node.""" self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_NODE) ArgumentValidator.validate_ip_address(ip_address) # Update global MCVirt configuration def update_config(config): config['cluster']['cluster_ip'] = ip_address mcvirt_config = MCVirtConfig() mcvirt_config.update_config(update_config, 'Set node cluster IP address to %s' % ip_address)
def set_global_interval(self, interval): """Set global default watchdog check interval""" ArgumentValidator.validate_positive_integer(interval) # Check permissions self._get_registered_object('auth').assert_permission( PERMISSIONS.MANAGE_GLOBAL_WATCHDOG) self.update_watchdog_config( change_dict={'interval': interval}, reason='Update global watchdog interval', nodes=self._get_registered_object('cluster').get_nodes(include_local=True))
def set_global_reset_fail_count(self, count): """Set global default watchdog reset fail count""" ArgumentValidator.validate_positive_integer(count) # Check permissions self._get_registered_object('auth').assert_permission( PERMISSIONS.MANAGE_GLOBAL_WATCHDOG) self.update_watchdog_config( change_dict={'reset_fail_count': count}, reason='Update global watchdog reset fail count', nodes=self._get_registered_object('cluster').get_nodes(include_local=True))
def set_global_boot_wait(self, wait): """Set the global default boot wait period""" ArgumentValidator.validate_positive_integer(wait) # Check permissions self._get_registered_object('auth').assert_permission( PERMISSIONS.MANAGE_GLOBAL_WATCHDOG) self.update_watchdog_config( change_dict={'boot_wait': wait}, reason='Update global watchdog boot wait period', nodes=self._get_registered_object('cluster').get_nodes(include_local=True))
def set_storage_volume_group(self, volume_group): """Update the MCVirt configuration to set the volume group for VM storage.""" self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_NODE) ArgumentValidator.validate_vg_name(volume_group) # Update global MCVirt configuration def update_config(config): config['vm_storage_vg'] = volume_group mcvirt_config = MCVirtConfig() mcvirt_config.update_config(update_config, 'Set virtual machine storage volume group to %s' % volume_group)
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 add_user_permission_group(self, permission_group, user_object, vm_object=None, ignore_duplicate=False): """Add a user to a permissions group on a 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) ArgumentValidator.validate_boolean(ignore_duplicate) # Check if user running script is able to add users to permission group if not (self.is_superuser() or (vm_object and self.assert_permission(PERMISSIONS.MANAGE_VM_USERS, vm_object) and permission_group == 'user')): raise InsufficientPermissionsException('VM owners cannot add manager other owners') user_object = self._convert_remote_object(user_object) vm_object = self._convert_remote_object(vm_object) if vm_object is not None else None username = user_object.get_username() # Check if user is already in the group if (vm_object): config_object = vm_object.get_config_object() else: config_object = MCVirtConfig() if (username not in self.get_users_in_permission_group(permission_group, vm_object)): # Add user to permission configuration for VM def add_user_to_config(config): config['permissions'][permission_group].append(username) config_object.update_config(add_user_to_config, 'Added user \'%s\' to group \'%s\'' % (username, permission_group)) # @TODO FIX ME if self._is_cluster_master: cluster_object = self._get_registered_object('cluster') vm_name = vm_object.get_name() if vm_object else None cluster_object.run_remote_command('auth-add_user_permission_group', {'permission_group': permission_group, 'username': username, 'vm_name': vm_name}) elif not ignore_duplicate: raise DuplicatePermissionException( 'User \'%s\' already in group \'%s\'' % (username, permission_group) )
def remove_permission(self, permission): """Remove a permission from the group""" self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_GROUPS) ArgumentValidator.validate_permission(permission) permission_enum = PERMISSIONS[permission] if permission_enum not in self.get_permissions(): raise GroupDoesNotContainPermissionError( 'Group \'%s\' does not contain permission \'%s\'' % (self.name, permission)) cluster = self._get_registered_object('cluster') self.remove_permission_from_config(permission, nodes=cluster.get_nodes(include_local=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_by_name(name) and not ignore_exists: raise VmAlreadyExistsException('VM already exists') return True
def add_permission(self, permission): """Add a permission to the group""" self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_GROUPS) # Check that permission is valid ArgumentValidator.validate_permission(permission) permission_enum = PERMISSIONS[permission] if permission_enum in self.get_permissions(): raise GroupAlreadyContainsPermissionError( 'Group \'%s\' already contains permission \'%s\'' % (self.name, permission)) cluster = self._get_registered_object('cluster') self.add_permission_to_config(permission, nodes=cluster.get_nodes(include_local=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 add_superuser(self, user_object, ignore_duplicate=False): """Add a new superuser.""" assert isinstance( self._convert_remote_object(user_object), self._get_registered_object('user_factory').USER_CLASS) ArgumentValidator.validate_boolean(ignore_duplicate) # Ensure the user is a superuser if not self.is_superuser(): raise InsufficientPermissionsException( 'User must be a superuser to manage superusers') user_object = self._convert_remote_object(user_object) username = user_object.get_username() mcvirt_config = MCVirtConfig() # Ensure user is not already a superuser if username not in self.get_superusers(): def update_config(config): config['superusers'].append(username) mcvirt_config.update_config(update_config, 'Added superuser \'%s\'' % username) elif not ignore_duplicate: raise DuplicatePermissionException( 'User \'%s\' is already a superuser' % username) if self._is_cluster_master: def remote_command(connection): remote_user_factory = connection.get_connection('user_factory') remote_user = remote_user_factory.get_user_by_username( user_object.get_username()) remote_auth = connection.get_connection('auth') remote_auth.add_superuser(remote_user, ignore_duplicate=ignore_duplicate) cluster = self._get_registered_object('cluster') cluster.run_remote_command(remote_command)
def get_logs(self, start_log=None, back=0, newer=False): """Return a dict containing log information""" if start_log is not None: ArgumentValidator.validate_integer(start_log) ArgumentValidator.validate_integer(back) ArgumentValidator.validate_boolean(newer) if start_log is None: start_log = len(Logger.LOGS) - 1 if start_log < 0: start_log = 0 if start_log > (len(Logger.LOGS) - 1): start_log = len(Logger.LOGS) - 1 if back: start = 0 if (start_log - back) < 0 else (len(Logger.LOGS) - back) finish = start_log + 1 elif newer: start = start_log + 1 # Length would provide an indicy out of the range, # since len(['a']) = 1, but ['a'][1] == error # However, this is made up for the fact that range(0, 2) = [0, 1] finish = len(Logger.LOGS) else: # Start at the current log, to return it # Finish at current log + 1 as range(1, 2) = [1] start = start_log finish = start_log + 1 return_logs = {} for itx in range(start, finish): if itx < 0: continue if len(Logger.LOGS) < itx: break log = Logger.LOGS[itx] return_logs[itx] = { 'start_date': str(log.start_time), 'status': log.status['status'], 'status_name': log.status['name'], 'user': log.user, 'method': log.method_name, 'object_name': log.object_name, 'object_type': log.object_type, 'description': '%s %s %s' % (log.method_name.capitalize(), log.object_name, log.object_type), 'exception_message': log.exception_message } return return_logs
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 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 add_superuser(self, user_object, ignore_duplicate=False): """Add a new superuser.""" assert isinstance(self._convert_remote_object(user_object), self._get_registered_object('user_factory').USER_CLASS) ArgumentValidator.validate_boolean(ignore_duplicate) # Ensure the user is a superuser if not self.is_superuser(): raise InsufficientPermissionsException( 'User must be a superuser to manage superusers' ) user_object = self._convert_remote_object(user_object) username = user_object.get_username() mcvirt_config = MCVirtConfig() # Ensure user is not already a superuser if username not in self.get_superusers(): def update_config(config): config['superusers'].append(username) mcvirt_config.update_config(update_config, 'Added superuser \'%s\'' % username) elif not ignore_duplicate: raise DuplicatePermissionException( 'User \'%s\' is already a superuser' % username ) if self._is_cluster_master: def remote_command(connection): remote_user_factory = connection.get_connection('user_factory') remote_user = remote_user_factory.get_user_by_username(user_object.get_username()) remote_auth = connection.get_connection('auth') remote_auth.add_superuser(remote_user, ignore_duplicate=ignore_duplicate) cluster = self._get_registered_object('cluster') cluster.run_remote_command(remote_command)
def validate_location_name(cls, location): """Ensure volume group name is valid""" ArgumentValidator.validate_directory(location)
def _validate_name(self): """Ensurue name of object is valid""" ArgumentValidator.validate_file_name(self.name)
def create(self, name, physical_interface): """Create a network on the node""" # Ensure user has permission to manage networks self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_HOST_NETWORKS) # Validate name ArgumentValidator.validate_network_name(name) # Ensure network does not already exist if self.check_exists(name): raise NetworkAlreadyExistsException('Network already exists: %s' % name) # Ensure that the physical interface eixsts if not self._interface_exists(physical_interface): raise InterfaceDoesNotExist( 'Physical interface %s does not exist' % physical_interface ) # Create XML for network network_xml = ET.Element('network') network_xml.set('ipv6', 'no') network_name_xml = ET.SubElement(network_xml, 'name') network_name_xml.text = name # Create 'forward' network_forward_xml = ET.SubElement(network_xml, 'forward') network_forward_xml.set('mode', 'bridge') # Set interface bridge network_bridge_xml = ET.SubElement(network_xml, 'bridge') network_bridge_xml.set('name', physical_interface) # Convert XML object to string network_xml_string = ET.tostring(network_xml, encoding='utf8', method='xml') # Attempt to register network with LibVirt try: self._get_registered_object('libvirt_connector').get_connection( ).networkDefineXML(network_xml_string) except: raise LibvirtException('An error occurred whilst registering network with LibVirt') # Update MCVirt config def update_config(config): config['networks'][name] = physical_interface from mcvirt.mcvirt_config import MCVirtConfig MCVirtConfig().update_config(update_config, 'Created network \'%s\'' % name) # Obtain instance of the network object network_instance = self.get_network_by_name(name) # Start network network_instance._get_libvirt_object().create() # Set network to autostart network_instance._get_libvirt_object().setAutostart(True) if self._is_cluster_master: def remote_add(node): network_factory = node.get_connection('network_factory') network_factory.create(name, physical_interface) cluster = self._get_registered_object('cluster') cluster.run_remote_command(remote_add) return network_instance
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
def validate_location_name(cls, location): """Ensure directory is a valid name""" ArgumentValidator.validate_vg_name(location)
def _validate_name(self): """Ensurue name of object is valid""" ArgumentValidator.validate_logical_volume_name(self.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, storage_type, location, shared=False, id_=None, node_config={}): """Create storage backend""" # Check permissions self._get_registered_object('auth').assert_permission(PERMISSIONS.MANAGE_STORAGE_BACKEND) # Ensure storage backend does not already exist with same name if self.get_id_by_name(name): raise StorageBackendAlreadyExistsError('Storage backend already exists: %s' % name) t = Transaction() # Ensure that nodes are valid cluster = self._get_registered_object('cluster') for node in node_config: cluster.ensure_node_exists(node, include_local=True) # Ensure that either: # a default location is defined # all nodes provide an override location if (not location and (None in [node_config[node]['location'] if 'location' in node_config[node] else None for node in node_config] or not node_config)): raise InvalidStorageConfiguration(('A default location has not been set and ' 'some nodes do not have an override set')) storage_class = self.get_class(storage_type) # Generate ID for the storage backend id_ = storage_class.generate_id(name) # Ensure name is valid ArgumentValidator.validate_storage_name(name) # Get all locations and verify that the names are valid # @TODO - Refactor this to be more readable for location_itx in [] if not location else [location] + \ [node_config[node]['location'] if 'location' in node_config[node] else None for node in node_config]: if location_itx is not None: storage_class.validate_location_name(location_itx) # If no nodes have been specified, get all nodes in cluster if not node_config: cluster = self._get_registered_object('cluster') node_config = { node: {'location': None} for node in cluster.get_nodes(return_all=True, include_local=True) } # Create config config = {'name': name, 'type': storage_type, 'shared': shared, 'nodes': node_config, 'location': location} # Ensure that config requirements and system requirements # are as expected for the type of storage backend # Only required on cluster master, as this checks all nodes in the cluster self.validate_config( storage_type=storage_type, config=config ) # Ensure pre-requisites for storage backend pass on each node for node in node_config: node_location = (node_config[node]['location'] if 'location' in node_config[node] and node_config[node]['location'] is not None else location) self.node_pre_check(location=node_location, storage_type=storage_type, nodes=[node]) self.create_config(id_, config, nodes=cluster.get_nodes(include_local=True)) storage_object = self.get_object(id_) # Create ID volume storage_object.create_id_volume() t.finish() return storage_object