def __init__(self): """ Initialize the driver session, this function is called everytime a new instance of the driver is created in here the driver is going to be bootstrapped :param context: models.QualiDriverModels.InitCommandContext """ self.cs_helper = CloudshellDriverHelper() synchronous_task_waiter = SynchronousTaskWaiter() pv_service = pyVmomiService(connect=SmartConnect, disconnect=Disconnect, task_waiter=synchronous_task_waiter) self.resource_model_parser = ResourceModelParser() port_group_name_generator = DvPortGroupNameGenerator() vnic_to_network_mapper = VnicToNetworkMapper( quali_name_generator=port_group_name_generator) resource_remover = CloudshellResourceRemover() ovf_service = OvfImageDeployerService(self.resource_model_parser) self.vm_loader = VMLoader(pv_service) vm_deployer = VirtualMachineDeployer( pv_service=pv_service, name_generator=generate_unique_name, ovf_service=ovf_service, cs_helper=self.cs_helper, resource_model_parser=ResourceModelParser()) dv_port_group_creator = DvPortGroupCreator( pyvmomi_service=pv_service, synchronous_task_waiter=synchronous_task_waiter) virtual_machine_port_group_configurer = \ VirtualMachinePortGroupConfigurer(pyvmomi_service=pv_service, synchronous_task_waiter=synchronous_task_waiter, vnic_to_network_mapper=vnic_to_network_mapper, vnic_service=VNicService(), name_gen=port_group_name_generator) virtual_switch_to_machine_connector = VirtualSwitchToMachineConnector( dv_port_group_creator, virtual_machine_port_group_configurer) # Command Wrapper self.command_wrapper = CommandWrapper( pv_service=pv_service, cloud_shell_helper=self.cs_helper, resource_model_parser=self.resource_model_parser, context_based_logger_factory=ContextBasedLoggerFactory()) # Deploy Command self.deploy_command = DeployCommand(deployer=vm_deployer) # Virtual Switch Revoke self.virtual_switch_disconnect_command = \ VirtualSwitchToMachineDisconnectCommand( pyvmomi_service=pv_service, port_group_configurer=virtual_machine_port_group_configurer, resource_model_parser=self.resource_model_parser) # Virtual Switch Connect virtual_switch_connect_command = \ VirtualSwitchConnectCommand( pv_service=pv_service, virtual_switch_to_machine_connector=virtual_switch_to_machine_connector, dv_port_group_name_generator=DvPortGroupNameGenerator(), vlan_spec_factory=VlanSpecFactory(), vlan_id_range_parser=VLanIdRangeParser()) self.connection_orchestrator = ConnectionCommandOrchestrator( connector=virtual_switch_connect_command, disconnector=self.virtual_switch_disconnect_command, resource_model_parser=self.resource_model_parser) # Destroy VM Command self.destroy_virtual_machine_command = \ DestroyVirtualMachineCommand(pv_service=pv_service, resource_remover=resource_remover, disconnector=self.virtual_switch_disconnect_command) # Power Command self.vm_power_management_command = \ VirtualMachinePowerManagementCommand(pyvmomi_service=pv_service, synchronous_task_waiter=synchronous_task_waiter) ip_manager = VMIPManager() # Refresh IP command self.refresh_ip_command = RefreshIpCommand( pyvmomi_service=pv_service, resource_model_parser=ResourceModelParser(), ip_manager=ip_manager) # Save Snapshot self.snapshot_saver = SaveSnapshotCommand( pyvmomi_service=pv_service, task_waiter=synchronous_task_waiter) # Snapshot Restorer self.snapshot_restorer = SnapshotRestoreCommand( pyvmomi_service=pv_service, task_waiter=synchronous_task_waiter) self.snapshots_retriever = RetrieveSnapshotsCommand( pyvmomi_service=pv_service)
def __init__(self): self.parser = ResourceModelParser() self.pv_service = pyVmomiService(SmartConnect, Disconnect, SynchronousTaskWaiter()) self.context_based_logger_factory = ContextBasedLoggerFactory()
def __init__(self): self.parser = ResourceModelParser() self.pv_service = pyVmomiService(SmartConnect, Disconnect) self.cs_helper = CloudshellDriverHelper() self.context_based_logger_factory = ContextBasedLoggerFactory()
class VCenterAutoModelDiscovery(object): def __init__(self): self.parser = ResourceModelParser() self.pv_service = pyVmomiService(SmartConnect, Disconnect, SynchronousTaskWaiter()) self.context_based_logger_factory = ContextBasedLoggerFactory() def _get_logger(self, context): """Get Quali logger from the given context :param context: models.QualiDriverModels.AutoLoadCommandContext """ return self.context_based_logger_factory.create_logger_for_context( logger_name='vCenterShell', context=context) def validate_and_discover(self, context): """ :type context: models.QualiDriverModels.AutoLoadCommandContext """ logger = self._get_logger(context) logger.info('Autodiscovery started') si = None resource = None with CloudShellSessionContext(context) as cloudshell_session: self._check_if_attribute_not_empty(context.resource, ADDRESS) resource = context.resource si = self._check_if_vcenter_user_pass_valid( context, cloudshell_session, resource.attributes) resource.attributes = VCenterAutoModelDiscovery._make_attributes_slash_backslash_agnostic( resource.attributes) auto_attr = [] if not si: error_message = 'Could not connect to the vCenter: {0}, with given credentials'\ .format(context.resource.address) logger.error(error_message) raise ValueError(error_message) try: all_dc = self.pv_service.get_all_items_in_vcenter( si, vim.Datacenter) dc = self._validate_datacenter(si, all_dc, auto_attr, resource.attributes) all_items_in_dc = self.pv_service.get_all_items_in_vcenter( si, None, dc) dc_name = dc.name for key, value in resource.attributes.items(): if key in [USER, PASSWORD, DEFAULT_DATACENTER, VM_CLUSTER]: continue validation_method = self._get_validation_method(key) validation_method(si, all_items_in_dc, auto_attr, dc_name, resource.attributes, key) except vim.fault.NoPermission: logger.exception('Autodiscovery failed due to permissions error:') raise Exception( "vCenter permissions for configured resource(s) are invalid") logger.info('Autodiscovery completed') return AutoLoadDetails([], auto_attr) @staticmethod def _get_default_from_vc_by_type_and_name(items_in_vc, vim_type, name=None): items = [] if not isinstance(vim_type, collections.Iterable): vim_type = [vim_type] for item in items_in_vc: if item.name == name: return item item_type = type(item) if [t for t in vim_type if item_type is t]: items.append(item) if len(items) == 1: return items[0] if len(items) > 1: return 'too many options' return 'not found' def _validate_datacenter(self, si, all_item_in_vc, auto_att, attributes): dc = self._validate_attribute(si, attributes, vim.Datacenter, DEFAULT_DATACENTER) if not dc: dc = self._get_default(all_item_in_vc, vim.Datacenter, DEFAULT_DATACENTER) auto_att.append(AutoLoadAttribute('', DEFAULT_DATACENTER, dc.name)) return dc def _validate_default_dvswitch(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): dvs_path = attributes[key] # optional pararm if (not attributes[key]): return path = "{}/{}".format(dc_name, dvs_path) dv = self.pv_service.find_dvs_by_path(si, path) auto_att.append(AutoLoadAttribute('', DEFAULT_DVSWITCH, dvs_path)) return dv def _validate_attribute(self, si, attributes, vim_type, name, prefix=''): if name in attributes and attributes[name]: att_value = attributes[name] if prefix: att_value = '{0}/{1}'.format(prefix, att_value) obj = self.pv_service.get_folder(si, att_value) if not obj or isinstance(obj, str): raise ValueError('Could not find {0}'.format(name)) if vim_type and not isinstance(obj, vim_type): raise ValueError( 'The given {0}: {1} is not of the correct type'.format( name, attributes[name])) return obj return False def _get_default(self, all_item_in_vc, vim_type, key): obj = self._get_default_from_vc_by_type_and_name( all_item_in_vc, vim_type) if isinstance(obj, str): if obj == 'too many options': raise ValueError('{0} must be selected'.format(key)) raise ValueError('Could not find {0}'.format(key)) return obj def _check_if_vcenter_user_pass_valid(self, context, session, attributes): self._check_if_attribute_not_empty(attributes, USER) self._check_if_attribute_not_empty(attributes, PASSWORD) connection_details = self._get_connection_details( session, attributes[PASSWORD], attributes[USER], context.resource.address) try: si = self.pv_service.connect(connection_details.host, connection_details.username, connection_details.password, connection_details.port) except Exception: logger = self._get_logger(context) logger.exception("Could not connect to the vcenter") raise ValueError( 'could not connect to the vcenter: {0}, with the given credentials ({1})' .format(connection_details.host, connection_details.username)) return si def _validate_vm_storage(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): accepted_types = (vim.Datastore, vim.StoragePod) datastore = self._validate_attribute(si, attributes, accepted_types, key, dc_name) if not datastore: datastore = self._get_default(all_items_in_vc, accepted_types, key) d_name = self.get_full_name(dc_name, datastore) # removing the upper folder d_name = d_name.replace('datastore/', '') else: d_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, d_name)) def _validate_saved_sandbox_storage(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): accepted_types = (vim.Datastore, vim.StoragePod) # saved sandbox storage isnt mandatory so if not configured exit without validation if key not in attributes or not attributes[key]: return datastore = self._validate_attribute(si, attributes, accepted_types, key, dc_name) if not datastore: datastore = self._get_default(all_items_in_vc, accepted_types, key) d_name = self.get_full_name(dc_name, datastore) # removing the upper folder d_name = d_name.replace('datastore/', '') else: d_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, d_name)) def _validate_vm_location(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): accepted_types = None folder = self._validate_attribute(si, attributes, accepted_types, key, dc_name) if not folder: raise ValueError('VM Folder cannot be empty') f_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, f_name)) def _validate_vm_cluster(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): accepted_types = (vim.ClusterComputeResource, vim.HostSystem) cluster = self._validate_attribute(si, attributes, accepted_types, key, dc_name) if not cluster: cluster = self._get_default(all_items_in_vc, accepted_types, key) c_name = self.get_full_name(dc_name, cluster) # removing the upper folder c_name = c_name.replace('host/', '') else: c_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, c_name)) return cluster def _validate_vm_resource_pool(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): cluster = self._validate_vm_cluster(si, all_items_in_vc, auto_att, dc_name, attributes, VM_CLUSTER) if key not in attributes or not attributes[key]: return pool_name = attributes[key] pool = self._find_resource_pool_by_path(pool_name, cluster) if pool: auto_att.append(AutoLoadAttribute('', key, pool_name)) return raise ValueError( 'The given resource pool not found: {0}'.format(pool_name)) def _find_resource_pool_by_path(self, name, root): paths = name.split('/') for path in paths: root = self._find_resource_pool(path, root) if not root: return None return root def _find_resource_pool(self, name, root): if hasattr(root, 'resourcePool'): resource_pool = root.resourcePool if hasattr(resource_pool, 'name') and resource_pool.name == name: return resource_pool if isinstance(resource_pool, collections.Iterable): for pool in resource_pool: if pool.name == name: return pool if hasattr(resource_pool, 'resourcePool'): return self._find_resource_pool(name, resource_pool) return None def _validate_holding_network(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): holding_network = self._validate_attribute(si, attributes, vim.Network, key, dc_name) if not holding_network: raise ValueError('Holding Network cannot be empty') n_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, n_name)) def _validate_shutdown_method(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): method = attributes[key] if self._is_in_array(key, method, SHUTDOWN_METHODS): auto_att.append(AutoLoadAttribute('', key, method)) @staticmethod def _is_in_array(key, value, arr): if value in arr: return True raise ValueError('{0} can only be: {1} instead of: {2}'.format( key, arr, value)) @staticmethod def _is_found(item, key): if not item: raise ValueError( 'The {0} could not be found in the given vCenter'.format(key)) @staticmethod def _get_connection_details(session, password, user, address): password = session.DecryptPassword(password).Value return VCenterConnectionDetails(address, user, password) @staticmethod def _check_if_attribute_not_empty(attributes, name): if not ((hasattr(attributes, name) and getattr(attributes, name)) or (isinstance(attributes, dict) and name in attributes and attributes[name])): raise ValueError('{0} cannot be empty'.format(name)) @staticmethod def _validate_empty(si, all_items_in_vc, attributes, auto_attr, dc_name, key): return def _get_validation_method(self, name): if not name: return self._validate_empty name = name.lower() name = name.split(' ') name = '_'.join(name) method_name = '_validate_{0}'.format(name) return getattr(self, method_name, self._validate_empty) @staticmethod def get_full_name(dc_name, managed_object, name=''): if managed_object.name == dc_name: return name curr_path = managed_object.name if name: curr_path = '{0}/{1}'.format(managed_object.name, name) return VCenterAutoModelDiscovery.get_full_name(dc_name, managed_object.parent, curr_path) @staticmethod def _make_attributes_slash_backslash_agnostic( attributes_with_slash_or_backslash): """ :param attributes_with_slash_or_backslash: resource attributes from cloudshell.cp.vcenter.models.QualiDriverModels.ResourceContextDetails :type attributes_with_slash_or_backslash: dict[str,str] :return: attributes_with_slash :rtype attributes_with_slash: dict[str,str] """ attributes_with_slash = dict() for key, value in attributes_with_slash_or_backslash.items(): if key in ATTRIBUTE_NAMES_THAT_ARE_SLASH_BACKSLASH_AGNOSTIC: value = back_slash_to_front_converter(value) attributes_with_slash[key] = value return attributes_with_slash
class VCenterAutoModelDiscovery(object): def __init__(self): self.parser = ResourceModelParser() self.pv_service = pyVmomiService(SmartConnect, Disconnect) self.cs_helper = CloudshellDriverHelper() self.context_based_logger_factory = ContextBasedLoggerFactory() def validate_and_discover(self, context): """ :type context: models.QualiDriverModels.AutoLoadCommandContext """ logger = self.context_based_logger_factory.create_logger_for_context( logger_name='vCenterShell', context=context) logger.info('Autodiscovery started') session = self.cs_helper.get_session(context.connectivity.server_address, context.connectivity.admin_auth_token, DOMAIN) self._check_if_attribute_not_empty(context.resource, ADDRESS) resource = context.resource auto_attr = [] si = self._check_if_vcenter_user_pass_valid(context, session, resource.attributes) if not si: error_message = 'Could not connect to the vCenter: {0}, with given credentials'\ .format(context.resource.address) logger.error(error_message) raise ValueError(error_message) all_dc = self.pv_service.get_all_items_in_vcenter(si, vim.Datacenter) dc = self._validate_datacenter(si, all_dc, auto_attr, resource.attributes) all_items_in_dc = self.pv_service.get_all_items_in_vcenter(si, None, dc) dc_name = dc.name for key, value in resource.attributes.items(): if key in [USER, PASSWORD, DEFAULT_DATACENTER, VM_CLUSTER]: continue validation_method = self._get_validation_method(key) validation_method(si, all_items_in_dc, auto_attr, dc_name, resource.attributes, key) logger.info('Autodiscovery completed') return AutoLoadDetails([], auto_attr) @staticmethod def _get_default_from_vc_by_type_and_name(items_in_vc, vim_type, name=None): items = [] if not isinstance(vim_type, collections.Iterable): vim_type = [vim_type] for item in items_in_vc: if item.name == name: return item item_type = type(item) if [t for t in vim_type if item_type is t]: items.append(item) if len(items) == 1: return items[0] if len(items) > 1: return 'too many options' return 'not found' def _validate_datacenter(self, si, all_item_in_vc, auto_att, attributes): dc = self._validate_attribute(si, attributes, vim.Datacenter, DEFAULT_DATACENTER) if not dc: dc = self._get_default(all_item_in_vc, vim.Datacenter, DEFAULT_DATACENTER) auto_att.append(AutoLoadAttribute('', DEFAULT_DATACENTER, dc.name)) return dc def _validate_attribute(self, si, attributes, vim_type, name, prefix=''): if name in attributes and attributes[name]: att_value = attributes[name] if prefix: att_value = '{0}/{1}'.format(prefix, att_value) obj = self.pv_service.get_folder(si, att_value) if not obj or isinstance(obj, str): raise ValueError('Could not find {0}'.format(name)) if vim_type and not isinstance(obj, vim_type): raise ValueError('The given {0}: {1} is not of the correct type'.format(name, attributes[name])) return obj return False def _get_default(self, all_item_in_vc, vim_type, key): obj = self._get_default_from_vc_by_type_and_name(all_item_in_vc, vim_type) if isinstance(obj, str): if obj == 'too many options': raise ValueError('{0} must be selected'.format(key)) raise ValueError('Could not find {0}'.format(key)) return obj def _check_if_vcenter_user_pass_valid(self, context, session, attributes): self._check_if_attribute_not_empty(attributes, USER) self._check_if_attribute_not_empty(attributes, PASSWORD) connection_details = self._get_connection_details(session, attributes[PASSWORD], attributes[USER], context.resource.address) try: si = self.pv_service.connect(connection_details.host, connection_details.username, connection_details.password, connection_details.port) except Exception: raise ValueError('could not connect to the vcenter: {0}, with the given credentials ({1})'.format( connection_details.host, connection_details.username)) return si def _validate_default_dvswitch(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): accepted_types = (vim.DistributedVirtualSwitch, vim.VmwareDistributedVirtualSwitch) d_switch = self._validate_attribute(si, attributes, accepted_types, key, dc_name) if not d_switch: d_switch = self._get_default(all_items_in_vc, accepted_types, key) d_name = self.get_full_name(dc_name, d_switch) # removing the upper folder d_name = d_name.replace('network/', '') else: d_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, d_name)) def _validate_vm_storage(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): accepted_types = (vim.Datastore, vim.StoragePod) datastore = self._validate_attribute(si, attributes, accepted_types, key, dc_name) if not datastore: datastore = self._get_default(all_items_in_vc, accepted_types, key) d_name = self.get_full_name(dc_name, datastore) # removing the upper folder d_name = d_name.replace('datastore/', '') else: d_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, d_name)) def _validate_vm_location(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): accepted_types = None folder = self._validate_attribute(si, attributes, accepted_types, key, dc_name) if not folder: raise ValueError('VM Folder cannot be empty') f_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, f_name)) def _validate_default_port_group_location(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): if not attributes[key]: return self._validate_attribute(si, attributes, None, key, dc_name) def _validate_vm_cluster(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): accepted_types = (vim.ClusterComputeResource, vim.HostSystem) cluster = self._validate_attribute(si, attributes, accepted_types, key, dc_name) if not cluster: cluster = self._get_default(all_items_in_vc, accepted_types, key) c_name = self.get_full_name(dc_name, cluster) # removing the upper folder c_name = c_name.replace('host/', '') else: c_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, c_name)) return cluster def _validate_vm_resource_pool(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): cluster = self._validate_vm_cluster(si, all_items_in_vc, auto_att, dc_name, attributes, VM_CLUSTER) if key not in attributes or not attributes[key]: return pool_name = attributes[key] pool = self._find_resource_pool_by_path(pool_name, cluster) if pool: auto_att.append(AutoLoadAttribute('', key, pool_name)) return raise ValueError('The given resource pool not found: {0}'.format(pool_name)) def _find_resource_pool_by_path(self, name, root): paths = name.split('/') for path in paths: root = self._find_resource_pool(path, root) if not root: return None return root def _find_resource_pool(self, name, root): if hasattr(root, 'resourcePool'): resource_pool = root.resourcePool if hasattr(resource_pool, 'name') and resource_pool.name == name: return resource_pool if isinstance(resource_pool, collections.Iterable): for pool in resource_pool: if pool.name == name: return pool if hasattr(resource_pool, 'resourcePool'): return self._find_resource_pool(name, resource_pool) return None def _validate_holding_network(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): holding_network = self._validate_attribute(si, attributes, vim.Network, key, dc_name) if not holding_network: raise ValueError('Holding Network cannot be empty') n_name = attributes[key] auto_att.append(AutoLoadAttribute('', key, n_name)) def _validate_shutdown_method(self, si, all_items_in_vc, auto_att, dc_name, attributes, key): method = attributes[key] if self._is_in_array(key, method, SHUTDOWN_METHODS): auto_att.append(AutoLoadAttribute('', key, method)) @staticmethod def _is_in_array(key, value, arr): if value in arr: return True raise ValueError('{0} can only be: {1} instead of: {2}'.format(key, arr, value)) @staticmethod def _is_found(item, key): if not item: raise ValueError('The {0} could not be found in the given vCenter'.format(key)) @staticmethod def _get_connection_details(session, password, user, address): password = session.DecryptPassword(password).Value return VCenterConnectionDetails(address, user, password) @staticmethod def _check_if_attribute_not_empty(attributes, name): if not ((hasattr(attributes, name) and getattr(attributes, name)) or (isinstance(attributes, dict) and name in attributes and attributes[name])): raise ValueError('{0} cannot be empty'.format(name)) @staticmethod def _validate_empty(si, all_items_in_vc, attributes, auto_attr, dc_name, key): return def _get_validation_method(self, name): if not name: return self._validate_empty name = name.lower() name = name.split(' ') name = '_'.join(name) method_name = '_validate_{0}'.format(name) return getattr(self, method_name, self._validate_empty) @staticmethod def get_full_name(dc_name, managed_object, name=''): if managed_object.name == dc_name: return name curr_path = managed_object.name if name: curr_path = '{0}/{1}'.format(managed_object.name, name) return VCenterAutoModelDiscovery.get_full_name(dc_name, managed_object.parent, curr_path)