def set_connect(self, secret_data): subscription_id = secret_data['subscription_id'] os.environ["AZURE_SUBSCRIPTION_ID"] = subscription_id os.environ["AZURE_TENANT_ID"] = secret_data['tenant_id'] os.environ["AZURE_CLIENT_ID"] = secret_data['client_id'] os.environ["AZURE_CLIENT_SECRET"] = secret_data['client_secret'] credential = DefaultAzureCredential() self.compute_client = ComputeManagementClient( credential=credential, subscription_id=subscription_id) self.vm_compute_client = ComputeManagementClient( credential=credential, subscription_id=subscription_id, expand='instanceView') self.resource_client = ResourceManagementClient( credential=credential, subscription_id=subscription_id) self.network_client = NetworkManagementClient( credential=credential, subscription_id=subscription_id) self.subscription_client: SubscriptionClient = SubscriptionClient( credential=credential) self.sql_client = SqlManagementClient(credential=credential, subscription_id=subscription_id) self.monitor_client = MonitorManagementClient( credential=credential, subscription_id=subscription_id)
def get_azure_compute_client(config): from azure.mgmt.compute import ComputeManagementClient cloud_environment = get_azure_cloud_environment(config) credentials = get_azure_credentials(config) if cloud_environment: compute_client = ComputeManagementClient( credentials, config.SubscriptionId, base_url=cloud_environment.endpoints.resource_manager) else: compute_client = ComputeManagementClient(credentials, config.SubscriptionId) return compute_client
def __init_client(secrets, configuration): with auth(secrets) as cred: subscription_id = configuration['azure']['subscription_id'] client = ComputeManagementClient(credentials=cred, subscription_id=subscription_id) return client
def init_services(self): """Delay imports and activation of Azure RM services until needed.""" from azure.common.credentials import ServicePrincipalCredentials from azure.mgmt.resource.resources import ( ResourceManagementClient, ResourceManagementClientConfiguration, ) from azure.mgmt.storage import ( StorageManagementClient, StorageManagementClientConfiguration, ) from azure.mgmt.compute import ( ComputeManagementClient, ComputeManagementClientConfiguration, ) from azure.mgmt.network import ( NetworkManagementClient, NetworkManagementClientConfiguration, ) self.credentials = ServicePrincipalCredentials( client_id=self.client_id, secret=self.secret, tenant=self.tenant) self.storage = StorageManagementClient( StorageManagementClientConfiguration(self.credentials, self.subscription_id)) self.resource = ResourceManagementClient( ResourceManagementClientConfiguration(self.credentials, self.subscription_id)) self.compute = ComputeManagementClient( ComputeManagementClientConfiguration(self.credentials, self.subscription_id)) self.network = NetworkManagementClient( NetworkManagementClientConfiguration(self.credentials, self.subscription_id))
def main(): vmss = sys.argv[1] appgwy = sys.argv[2] resource_group = sys.argv[3] #Creating az_rollout instance. rollout = az_rollout(tenant_id, subscription_id, vmss, resource_group, appgwy) #Obtaining credentials. credentials = rollout.credentials #Creating ComputeManagementClient instance. client_C = ComputeManagementClient(credentials, subscription_id) #Executing policy check. rollout.policy_check(client_C) #Obtaining vmss running vms list. id_list = rollout.get_vms(client_C) #Calculating the original scale set vm capacity. original_size = str(len(id_list)) #Getting the new scale vm capacity size by multiplying the original size by 2. new_size = str(len(id_list) * 2) #Executing the scale command. rollout.scale_commnad(new_size) #Creating NetworkManagementClient instance. client_N = NetworkManagementClient(credentials, subscription_id) #Executing healthcheck and returning the scale set to the original vm capacity. rollout.health_check(client_N) rollout.scale_commnad(original_size)
def __init__(self, provider_config, cluster_name): NodeProvider.__init__(self, provider_config, cluster_name) kwargs = {} if "subscription_id" in provider_config: kwargs["subscription_id"] = provider_config["subscription_id"] try: self.compute_client = get_client_from_cli_profile( client_class=ComputeManagementClient, **kwargs) self.network_client = get_client_from_cli_profile( client_class=NetworkManagementClient, **kwargs) self.resource_client = get_client_from_cli_profile( client_class=ResourceManagementClient, **kwargs) except CLIError as e: if str(e) != "Please run 'az login' to setup account.": raise else: logger.info("CLI profile authentication failed. Trying MSI") credentials = MSIAuthentication() self.compute_client = ComputeManagementClient( credentials=credentials, **kwargs) self.network_client = NetworkManagementClient( credentials=credentials, **kwargs) self.resource_client = ResourceManagementClient( credentials=credentials, **kwargs) self.lock = RLock() # cache node objects self.cached_nodes = {}
def init_resources(): """ Init resources """ global resource_client global network_client global compute_client # Acquire the Azure Subscription Id try: azure_subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"] except KeyError: print( 'Error: Enviroment variable "AZURE_SUBSCRIPTION_ID" does not exist' ) sys.exit(1) # Acquire a credential object using CLI-based authentication credential = DefaultAzureCredential() # Obtain the management object for resources resource_client = ResourceManagementClient(credential, azure_subscription_id) # Obtain the management object for networks network_client = NetworkManagementClient(credential, azure_subscription_id) # Obtain the management object for virtual machines compute_client = ComputeManagementClient(credential, azure_subscription_id) # Provision the resource group resource_group_result = create_resource_group(resource_client) return resource_group_result
def get_client(self, client_type): """ Return resource management client type based on what's requested """ try: # Check to see if credentials exist before returning an azure client object if self.credentials: # there is probably a better whay than a big case statement if client_type == "ComputeManagementClient": return (ComputeManagementClient(self.credentials, self.subscription_id)) elif client_type == "ResourceGraphClient": return (ResourceGraphClient(self.credentials, base_url=None)) else: raise NotImplementedError( "No such client type {} supported".format(client_type)) else: raise ServicePrincipalError( "Missing or bad credentials for tenant {}".format( self.tenant_name)) except ServicePrincipalError as e: raise (e) except NotImplementedError as e: raise (e) except Exception as e: raise (e)
def get_resource_group_details(subscription_id, creds, resource_group_name): storage_client = StorageManagementClient(creds, subscription_id) resource_client = ResourceManagementClient(creds, subscription_id) compute_client = ComputeManagementClient(creds, subscription_id) network_client = NetworkManagementClient(creds, subscription_id) model = ResourceGroupDetails() model.storage_accounts = list( storage_client.storage_accounts.list_by_resource_group( resource_group_name)) provider = resource_client.providers.get('Microsoft.Storage') resource_type = [ r for r in provider.resource_types if r.resource_type == 'storageAccounts' ][0] model.storage_accounts_locations = resource_type.locations # TODO: make an iterate function model.vms = list(compute_client.virtual_machines.list(resource_group_name)) model.public_ip_addresses = list( network_client.public_ip_addresses.list(resource_group_name)) model.virtual_networks = list( network_client.virtual_networks.list(resource_group_name)) return model
def get_vm_types(project): client = '' location = '' machine_types = [] try: con = create_db_con() subscription_id = Project.objects(name=project)[0]['subscription_id'] client_id = Project.objects(name=project)[0]['client_id'] tenant_id = Project.objects(name=project)[0]['tenant_id'] secret_id = Project.objects(name=project)[0]['secret'] location = Project.objects(name=project)[0]['location'] creds = ServicePrincipalCredentials(client_id=client_id, secret=secret_id, tenant=tenant_id) client = ComputeManagementClient(creds, subscription_id) machine_types = list_available_vm_sizes(client, region=location, minimum_cores=1, minimum_memory_MB=768) flag = True except Exception as e: print(repr(e)) logger("Fetching vm details failed: " + repr(e), "warning") flag = False con.close() return machine_types, flag
def _init_az_api(self): """ Initialise client objects for talking to Azure API. This is in a separate function so to be called by ``__init__`` and ``__setstate__``. """ with self.__lock: if self._resource_client is None: log.debug("Making Azure `ServicePrincipalcredentials` object" " with tenant=%r, client_id=%r, secret=%r ...", self.tenant_id, self.client_id, ('<redacted>' if self.secret else None)) credentials = ServicePrincipalCredentials( tenant=self.tenant_id, client_id=self.client_id, secret=self.secret, ) log.debug("Initializing Azure `ComputeManagementclient` ...") self._compute_client = ComputeManagementClient(credentials, self.subscription_id) log.debug("Initializing Azure `NetworkManagementclient` ...") self._network_client = NetworkManagementClient(credentials, self.subscription_id) log.debug("Initializing Azure `ResourceManagementclient` ...") self._resource_client = ResourceManagementClient(credentials, self.subscription_id) log.info("Azure API clients initialized.")
def __init__(self): credentials = UserPassCredentials(CONF.azure.username, CONF.azure.password) LOG.info(_LI('Login with Azure username and password.')) self.resource = ResourceManagementClient(credentials, CONF.azure.subscription_id) self.compute = ComputeManagementClient(credentials, CONF.azure.subscription_id) self.network = NetworkManagementClient(credentials, CONF.azure.subscription_id) try: self.resource.providers.register('Microsoft.Network') LOG.info(_LI("Register Microsoft.Network")) self.resource.providers.register('Microsoft.Compute') LOG.info(_LI("Register Microsoft.Compute")) except Exception as e: msg = six.text_type(e) ex = exception.ProviderRegisterFailure(reason=msg) LOG.exception(msg) raise ex try: self.resource.resource_groups.create_or_update( CONF.azure.resource_group, {'location': CONF.azure.location}) LOG.info(_LI("Create/Update Resource Group")) except Exception as e: msg = six.text_type(e) ex = exception.ResourceGroupCreateFailure(reason=msg) LOG.exception(msg) raise ex
def run_example(): """Resource Group management example.""" # # Get Subscription Information # subscription_id = os.environ.get( 'AZURE_SUBSCRIPTION_ID', '11111111-1111-1111-1111-111111111111') # your Azure Subscription Id # # Create all clients with an Application (service principal) token provider # credentials = ServicePrincipalCredentials( client_id=os.environ['AZURE_CLIENT_ID'], secret=os.environ['AZURE_CLIENT_SECRET'], tenant=os.environ['AZURE_TENANT_ID'] ) resource_client = ResourceManagementClient(credentials, subscription_id) compute_client = ComputeManagementClient(credentials, subscription_id) storage_client = StorageManagementClient(credentials, subscription_id) network_client = NetworkManagementClient(credentials, subscription_id) ########### # Prepare # ########### # Create Resource group print('\nCreate Resource Group') resource_client.resource_groups.create_or_update(GROUP_NAME, {'location':LOCATION})
def __init__(self, metadata): self.metadata = metadata self.credentials = get_credentials() self.compute_client = ComputeManagementClient(self.credentials, SUBSCRIPTION_ID) self.network_client = NetworkManagementClient(self.credentials, SUBSCRIPTION_ID) self.dns_client = None
def cmc(self): if not self._cmc: self.rmc().providers.register('Microsoft.Compute') self._cmc = ComputeManagementClient(self.get_mgmt_credentials()) self._cmc.long_running_operation_initial_timeout = 3 self._cmc.long_running_operation_retry_timeout = 5 return self._cmc
def create_connection_from_config(): """ Creates a new Azure api connection """ resource_client = None compute_client = None network_client = None try: os.environ['AZURE_AUTH_LOCATION'] except KeyError: try: subscription_id = os.environ['AZURE_SUBSCRIPTION_ID'] credentials = ServicePrincipalCredentials( client_id=os.environ['AZURE_CLIENT_ID'], secret=os.environ['AZURE_CLIENT_SECRET'], tenant=os.environ['AZURE_TENANT_ID'] ) except KeyError: sys.exit("No Azure Connection Defined") else: resource_client = ResourceManagementClient(credentials, subscription_id) compute_client = ComputeManagementClient(credentials, subscription_id) network_client = NetworkManagementClient(credentials, subscription_id) else: resource_client = get_client_from_auth_file(ResourceManagementClient) compute_client = get_client_from_auth_file(ComputeManagementClient) network_client = get_client_from_auth_file(NetworkManagementClient) return resource_client, compute_client, network_client
async def run_example(): start = time.time() credentials, subscription_id = get_credentials() resource_client = ResourceManagementClient(credentials, subscription_id) compute_client = ComputeManagementClient(credentials, subscription_id) network_client = NetworkManagementClient(credentials, subscription_id) resource_client.resource_groups.create_or_update(GROUP_NAME, {'location': LOCATION}) subnet = create_vnet(network_client) with concurrent.futures.ThreadPoolExecutor(max_workers=100) as executor: loop = asyncio.get_event_loop() futures = [ loop.run_in_executor(executor, create_vm, network_client, compute_client, subnet) for i in range(vmnumber) ] for vm in await asyncio.gather(*futures): pass end = time.time() print('\n ' + str(vmnumber) + ' VMs created in ' + stopWatch(end - start))
def __init__(self, metadata, region): self.region = region self.credentials = get_credentials() self.compute_client = ComputeManagementClient(self.credentials, SUBSCRIPTION_ID) self.network_client = NetworkManagementClient(self.credentials, SUBSCRIPTION_ID)
def __init__(self, clusterName, zone, nodeStorage): self.playbook = { 'create-cluster': 'create-azure-resourcegroup.yml', 'create': 'create-azure-vm.yml', 'delete': 'delete-azure-vm.yml', 'destroy': 'delete-azure-cluster.yml' } playbooks = os.path.dirname(os.path.realpath(__file__)) super(AzureProvisioner, self).__init__(playbooks, clusterName, zone, nodeStorage) # Fetch Azure credentials from the CLI config # FIXME: do error checking on this azureCredentials = ConfigParser.SafeConfigParser() azureCredentials.read(os.path.expanduser("~/.azure/credentials")) client_id = azureCredentials.get("default", "client_id") secret = azureCredentials.get("default", "secret") tenant = azureCredentials.get("default", "tenant") subscription = azureCredentials.get("default", "subscription_id") # Authenticate to Azure API credentials = ServicePrincipalCredentials(client_id=client_id, secret=secret, tenant=tenant) self._azureComputeClient = ComputeManagementClient( credentials, subscription) self._azureNetworkClient = NetworkManagementClient( credentials, subscription) if not clusterName: # If no clusterName, Toil must be running on the leader. self._readClusterSettings()
def updateVMInfo(self, vm, auth_data): self.log_debug("Get the VM info with the id: " + vm.id) group_name = vm.id.split('/')[0] vm_name = vm.id.split('/')[1] try: credentials, subscription_id = self.get_credentials(auth_data) compute_client = ComputeManagementClient(credentials, subscription_id) # Get one the virtual machine by name virtual_machine = compute_client.virtual_machines.get(group_name, vm_name) except Exception as ex: if "NotFound" in str(ex): vm.state = VirtualMachine.OFF return (True, vm) else: self.log_exception("Error getting the VM info: " + vm.id) return (False, "Error getting the VM info: " + vm.id + ". " + str(ex)) self.log_debug("VM info: " + vm.id + " obtained.") vm.state = self.PROVISION_STATE_MAP.get(virtual_machine.provisioning_state, VirtualMachine.UNKNOWN) self.log_debug("The VM state is: " + vm.state) instance_type = self.get_instance_type_by_name(virtual_machine.hardware_profile.vm_size, virtual_machine.location, credentials, subscription_id) self.update_system_info_from_instance(vm.info.systems[0], instance_type) # Update IP info self.setIPs(vm, virtual_machine.network_profile, credentials, subscription_id) return (True, vm)
def main(): mdUrl = "http://169.254.169.254/metadata/instance/compute?api-version=2017-08-01" header = {'Metadata': 'True'} request = urllib2.Request(url=mdUrl, headers=header) response = urllib2.urlopen(request) data = response.read() metaData = data.decode("utf-8") vm_meta_json = json.loads(metaData) print(vm_meta_json) GROUP_NAME = vm_meta_json["resourceGroupName"] VM_NAME = sys.argv[1] sched_event_url = "http://169.254.169.254/metadata/scheduledevents?api-version=2017-08-01" request2 = urllib2.Request(url=sched_event_url, headers=header) response = urllib2.urlopen(request2) sched_events_json = response.read() print(sched_events_json) subscription_id = os.environ.get('AZURE_SUBSCRIPTION_ID') credentials = ServicePrincipalCredentials( client_id=os.environ['AZURE_CLIENT_ID'], secret=os.environ['AZURE_SECRET'], tenant=os.environ['AZURE_TENANT']) compute_client = ComputeManagementClient(credentials, subscription_id) r_virtual_machine = compute_client.virtual_machines.get( GROUP_NAME, VM_NAME) async_vm_redeploy = compute_client.virtual_machines.redeploy( GROUP_NAME, VM_NAME) r_virtual_machine = async_vm_redeploy.result()
def __init__(self, logger, config): self.name = 'azure' self.location = config["location"] self.logger = logger self.config = config logger.info('Connecting to Azure...') try: credentials = ClientSecretCredential( client_id=config["client_id"], client_secret=config["client_secret"], tenant_id=config["tenant_id"]) self.compute_client = ComputeManagementClient( credential=credentials, subscription_id=config["subscription_id"]) self.network_client = NetworkManagementClient( credential=credentials, subscription_id=config["subscription_id"]) self.id = os.getpid() logger.info('Connection Successful.') except Exception as e: logger.error(f'Unable to connect to Azure: {str(e)}') self.config["username"] = "******" self.config["password"] = "******" self.instance_name = "" self.public_ip = ""
def compute_client(self): if self._compute_client is None: with SingletonByArgsMeta.lock: if self._compute_client is None: self._compute_client = ComputeManagementClient(self._service_credentials, self._subscription_id) return self._compute_client
def get_resource_group_details(subscription_id, creds, resource_group_name): compute_client = ComputeManagementClient(creds, subscription_id) model = ResourceGroupDetails() model.vms = list(compute_client.virtual_machines.list(resource_group_name)) return model
def describe_instances(self, parameters, pending=False): """ Queries Microsoft Azure to see which instances are currently running, and retrieves information about their public and private IPs. Args: parameters: A dict containing values necessary to authenticate with the underlying cloud. pending: If we should show pending instances. Returns: public_ips: A list of public IP addresses. private_ips: A list of private IP addresses. instance_ids: A list of unique Azure VM names. """ credentials = self.open_connection(parameters) subscription_id = str(parameters[self.PARAM_SUBSCRIBER_ID]) resource_group = parameters[self.PARAM_RESOURCE_GROUP] network_client = NetworkManagementClient(credentials, subscription_id) compute_client = ComputeManagementClient(credentials, subscription_id) public_ips = [] private_ips = [] instance_ids = [] public_ip_addresses = network_client.public_ip_addresses.list(resource_group) for public_ip in public_ip_addresses: public_ips.append(public_ip.ip_address) network_interfaces = network_client.network_interfaces.list(resource_group) for network_interface in network_interfaces: for ip_config in network_interface.ip_configurations: private_ips.append(ip_config.private_ip_address) virtual_machines = compute_client.virtual_machines.list(resource_group) for vm in virtual_machines: instance_ids.append(vm.name) return public_ips, private_ips, instance_ids
def alterVM(self, vm, radl, auth_data): try: group_name = vm.id.split('/')[0] vm_name = vm.id.split('/')[1] credentials, subscription_id = self.get_credentials(auth_data) compute_client = ComputeManagementClient(credentials, subscription_id) # Deallocating the VM (resize prepare) async_vm_deallocate = compute_client.virtual_machines.deallocate(group_name, vm_name) async_vm_deallocate.wait() instance_type = self.get_instance_type(radl.systems[0], credentials, subscription_id) vm_parameters = " { 'hardware_profile': { 'vm_size': %s } } " % instance_type.name async_vm_update = compute_client.virtual_machines.create_or_update(group_name, vm_name, vm_parameters) async_vm_update.wait() # Start the VM async_vm_start = compute_client.virtual_machines.start(group_name, vm_name) async_vm_start.wait() return self.updateVMInfo(vm, auth_data) except Exception as ex: self.log_exception("Error altering the VM") return False, "Error altering the VM: " + str(ex) return (True, "")
def _login(self) -> Boolean: """Login into MS Azure Cloud account and get usable client object(s). :return: Boolean True value depends on successful login operation """ try: subscription_id: str = self.config["subscription_id"] self.tenant_id = self.config["tenant_id"] client_id = self.config["client_id"] client_secret = self.config["client_secret"] credential = ClientSecretCredential( tenant_id=self.tenant_id, client_id=client_id, client_secret=client_secret, ) self.compute_client = ComputeManagementClient( credential=credential, subscription_id=subscription_id ) self.resource_client = ResourceManagementClient( credential=credential, subscription_id=subscription_id ) self.network_client = NetworkManagementClient( credential=credential, subscription_id=subscription_id ) logging.info("logging in Microsoft Azure Cloud={}".format(self.name)) return True except Error as e: logging.error(e) return False
def handle_dead_uuid(vmss_data,uuid): subscriptionId = vmss_data['context']['subscriptionId'] resourceGroupName = vmss_data['context']['resourceGroupName'] vmScaleSetName = vmss_data['context']['resourceName'] location = vmss_data['context']['resourceRegion'] credential = CredentialWrapper() compute = ComputeManagementClient(credential,subscriptionId) vmScaleSetData = get_vmss_data(compute,vmScaleSetName,resourceGroupName) vmScaleSetTags = vmScaleSetData.tags if vmss_data['disaster']: correlationId = vmss_data['data']['context']['activityLog']['correlationId'] if uuid in vmScaleSetTags: if vmScaleSetTags[uuid] == correlationId: logging.info('No need to update dead_uuid_list Tag,As this is a Re-Run for correlationId:{}'.format(correlationId)) return True else: logging.info('Set Existing uuid to CorrelationID mapping ==> {}:{}'.format(uuid,correlationId)) vmScaleSetTags[uuid] = correlationId else: vmScaleSetTags[uuid] = correlationId logging.info('Set uuid to CorrelationID mapping for First Time==> {}:{}'.format(uuid,correlationId)) try: dead_uuid_list = vmScaleSetTags['dead_uuid_list'] if len(dead_uuid_list) > 0: dead_uuid_list = dead_uuid_list.split(',') dead_uuid_list.append(uuid) updated_dead_uuid_list = ','.join(set(dead_uuid_list)) vmScaleSetTags['dead_uuid_list'] = updated_dead_uuid_list else: vmScaleSetTags['dead_uuid_list'] = uuid except KeyError: vmScaleSetTags['dead_uuid_list'] = uuid logging.info('Updating Scale Set : {} with tag dead_uuid_list with value {}'.format(vmScaleSetName,vmScaleSetTags['dead_uuid_list'])) create_vmss_tag(compute,vmScaleSetName,resourceGroupName,location,vmScaleSetTags)
def __init__(self, config): """Set up platform.""" super(AzureCloudPlatform, self).__init__(config) self.tag = '%s-%s' % ( config['tag'], datetime.now().strftime('%Y%m%d%H%M%S')) self.storage_sku = config['storage_sku'] self.vm_size = config['vm_size'] self.location = config['region'] try: self.credentials, self.subscription_id = self._get_credentials() self.resource_client = ResourceManagementClient( self.credentials, self.subscription_id) self.compute_client = ComputeManagementClient( self.credentials, self.subscription_id) self.network_client = NetworkManagementClient( self.credentials, self.subscription_id) self.storage_client = StorageManagementClient( self.credentials, self.subscription_id) self.resource_group = self._create_resource_group() self.public_ip = self._create_public_ip_address() self.storage = self._create_storage_account(config) self.vnet = self._create_vnet() self.subnet = self._create_subnet() self.nic = self._create_nic() except CloudError: raise RuntimeError('failed creating a resource:\n{}'.format( traceback.format_exc()))
def _get_vm_instance_views(self, vm_index, vm, sub_index, sub): """Get virtual machine records with instance view details. Arguments: vm_index (int): Virtual machine index (for logging only). vm (dict): Raw virtual machine record. sub_index (int): Subscription index (for logging only). sub (Subscription): Azure subscription object. Yields: dict: An Azure virtual machine record with instance view details. """ vm_name = vm.get('name') _log.info('Working on VM #%d: %s; %s', vm_index, vm_name, util.outline_az_sub(sub_index, sub, self._tenant)) try: creds = self._credentials sub_id = sub.get('subscription_id') compute_client = ComputeManagementClient(creds, sub_id) vm_id = vm.get('id') rg_name = tools.parse_resource_id(vm_id)['resource_group'] vm_iv = compute_client.virtual_machines.instance_view( rg_name, vm_name) vm_iv = vm_iv.as_dict() yield _process_vm_instance_view(vm_index, vm, vm_iv, sub_index, sub, self._tenant) except Exception as e: _log.error( 'Failed to fetch vm_instance_view for VM #%d: ' '%s; %s; error: %s: %s', vm_index, vm_name, util.outline_az_sub(sub_index, sub, self._tenant), type(e).__name__, e)