def __init__(self, index, settings, frame, start, call): """Create new configuration Handler. :param index: The UI tab index. :param frame: The shared plug-in UI frame. :type frame: :class:`.AzureBatchUI` :param func call: The shared REST API call wrapper. """ self.session = start self._tab_index = index self._data_dir = os.path.join(maya.prefs_dir(), 'AzureBatchData') self._ini_file = "azure_batch.ini" self._user_agent = "batchmaya/{}".format( os.environ.get('AZUREBATCH_VERSION')) self._cfg = ConfigParser.ConfigParser() self._call = call self.aad_environment_provider = AADEnvironmentProvider() self._log = self._configure_logging( LOG_LEVELS['debug'] ) #config hasn't been loaded yet so use a default logging level self.ui = ConfigUI(self, settings, frame) self._configure_plugin(False) self.aad_environment = None
def initialize_ui(self, index, settings, frame, start, call): """Create new configuration Handler. :param index: The UI tab index. :param frame: The shared plug-in UI frame. :type frame: :class:`.AzureBatchUI` :param func call: The shared REST API call wrapper. """ self.session = start self._tab_index = index self._ini_file = "azure_batch.ini" self._user_agent = "batchmaya/{}".format( os.environ.get('AZUREBATCH_VERSION')) self._cfg = ConfigParser.ConfigParser() self._call = call self.aad_environment_provider = AADEnvironmentProvider() self.ui = ConfigUI(self, settings, frame) self._configure_plugin(False) self.aad_environment = None
def __init__(self, index, frame, start): """Create new configuration Handler. :param index: The UI tab index. :param frame: The shared plug-in UI frame. :type frame: :class:`.AzureBatchUI` :param func call: The shared REST API call wrapper. """ self.ui = None self.session = start self._tab_index = index self._data_dir = os.path.join(maya.prefs_dir(), 'AzureBatchData') self._ini_file = "azure_batch.ini" self._user_agent = "batchmaya/{}".format( os.environ.get('AZUREBATCH_VERSION')) self._cfg = ConfigParser.ConfigParser() self._client = None self._log = None self._storage = None self._configure_plugin() self.ui = ConfigUI(self, frame) self._auth = self._auto_authentication() self._update_config_ui()
class AzureBatchConfig(object): """Handler for authentication and configuration of the SDK clients.""" aadClientId = "04b07795-8ddb-461a-bbee-02f9e1bf7b46" #Azure CLI def __init__(self, index, settings, frame, start, call): """Create new configuration Handler. :param index: The UI tab index. :param frame: The shared plug-in UI frame. :type frame: :class:`.AzureBatchUI` :param func call: The shared REST API call wrapper. """ self.session = start self._tab_index = index self._data_dir = os.path.join(maya.prefs_dir(), 'AzureBatchData') self._ini_file = "azure_batch.ini" self._user_agent = "batchmaya/{}".format( os.environ.get('AZUREBATCH_VERSION')) self._cfg = ConfigParser.ConfigParser() self._call = call self.aad_environment_provider = AADEnvironmentProvider() self._log = self._configure_logging( LOG_LEVELS['debug'] ) #config hasn't been loaded yet so use a default logging level self.ui = ConfigUI(self, settings, frame) self._configure_plugin(False) self.aad_environment = None #TODO as part of init should check batch and storage clients work somehow #old method with dummy listPool etc calls slowed down opening, #so maybe do this in background after UI has been fully loaded def __getattr__(self, attr): #return None rather than throw AttributeError so we don't have to init everything return self.__dict__.get(attr, None) #property helpers def _get_cached_config_value(self, identifier): try: return self._cfg.get('AzureBatch', identifier) except ConfigParser.NoOptionError: return None def _store_config_value(self, identifier, value): self._cfg.set('AzureBatch', identifier, str(value)) self._save_config() #properties from config file @property def mgmt_auth_token(self): value_from_config = self._get_cached_config_value('mgmt_auth_token') if value_from_config is None: return None json_loaded_value = json.loads(value_from_config) return self.convert_utc_expireson_to_local_timezone_naive( json_loaded_value) @mgmt_auth_token.setter def mgmt_auth_token(self, value): self._store_config_value( 'mgmt_auth_token', json.dumps(self.convert_timezone_naive_expireson_to_utc(value))) @property def batch_auth_token(self): value_from_config = self._get_cached_config_value('batch_auth_token') if value_from_config is None: return None json_loaded_value = json.loads(value_from_config) return self.convert_utc_expireson_to_local_timezone_naive( json_loaded_value) @batch_auth_token.setter def batch_auth_token(self, value): self._store_config_value( 'batch_auth_token', json.dumps(self.convert_timezone_naive_expireson_to_utc(value))) @property def subscription_id(self): return self._get_cached_config_value('subscription_id') @subscription_id.setter def subscription_id(self, value): self._store_config_value('subscription_id', value) @property def subscription_name(self): return self._get_cached_config_value('subscription_name') @subscription_name.setter def subscription_name(self, value): self._store_config_value('subscription_name', value) @property def vm_sku(self): value_in_config = self._get_cached_config_value('vm_sku') if value_in_config is None: return self.default_vm_sku() return value_in_config @vm_sku.setter def vm_sku(self, value): self._store_config_value('vm_sku', value) @property def batch_account(self): return self._get_cached_config_value('batch_account') @batch_account.setter def batch_account(self, value): self._store_config_value('batch_account', value) @property def batch_url(self): return self._get_cached_config_value('batch_url') @batch_url.setter def batch_url(self, value): self._store_config_value('batch_url', value) @property def storage_account_resource_id(self): return self._get_cached_config_value('storage_account_resource_id') @storage_account_resource_id.setter def storage_account_resource_id(self, value): self._store_config_value('storage_account_resource_id', value) @property def custom_image_resource_id(self): return self._get_cached_config_value('custom_image_resource_id') @custom_image_resource_id.setter def custom_image_resource_id(self, value): self._store_config_value('custom_image_resource_id', value) @property def container_image(self): return self._get_cached_config_value('container_image') @container_image.setter def container_image(self, value): self._store_config_value('container_image', value) @property def node_sku_id(self): return self._get_cached_config_value('node_sku_id') @node_sku_id.setter def node_sku_id(self, value): self._store_config_value('node_sku_id', value) @property def batch_image(self): return self._get_cached_config_value('batch_image') @batch_image.setter def batch_image(self, value): self._store_config_value('batch_image', value) @property def aad_tenant_name(self): return self._get_cached_config_value('aad_tenant_name') @aad_tenant_name.setter def aad_tenant_name(self, value): self._store_config_value('aad_tenant_name', value) @property def aad_environment_id(self): value = self._get_cached_config_value('aad_environment_id') return value @aad_environment_id.setter def aad_environment_id(self, value): self._store_config_value('aad_environment_id', value) #properties from config file with additional behaviour @property def logging_level(self): value_in_config = self._get_cached_config_value('logging') if value_in_config is None: return self.default_logging() return value_in_config @logging_level.setter def logging_level(self, value): self._log.setLevel(level) self._store_config_value('logging', value) @property def threads(self): value_in_config = self._get_cached_config_value('threads') if value_in_config is None: return self.default_threads() return int(value_in_config) @threads.setter def threads(self, value): if self._client != None: self._client.threads = self.threads self._store_config_value('threads', value) #non config file properties @property def batch(self): return self._client @property def subscription_client(self): return self._subscription_client @subscription_client.setter def subscription_client(self, value): self._subscription_client = value @property def batch_mgmt_client(self): try: return self._batch_mgmt_client except AttributeError: self._batch_mgmt_client = None return self._batch_mgmt_client @batch_mgmt_client.setter def batch_mgmt_client(self, value): self._batch_mgmt_client = value @property def storage(self): return self._storage @property def path(self): return os.path.join(self._data_dir, self._ini_file) @property def auth(self): return self._auth @auth.setter def auth(self, value): self._auth = value def _configure_plugin(self, from_auth_button): """Set up the config file, authenticate the SDK clients and set up the log file. """ if not os.path.exists(self._data_dir): os.makedirs(self._data_dir) config_file = os.path.join(self._data_dir, self._ini_file) try: self._cfg.read(config_file) self.ui.disable(True) self._read_config_file() except Exception as exp: # We should only worry about this if it happens when authenticating # using the UI, otherwise it's expected. if from_auth_button: raise ValueError("Invalid Configuration: {}".format(exp)) self.ui.init_post_config_file_read() if (not self.batch_auth_token or not self.mgmt_auth_token): self.ui.prompt_for_aad_tenant() if self.aad_tenant_name and self.aad_tenant_name != None and self.aad_tenant_name != 'None': maya.text_field(self.ui._aad_tenant_field, edit=True, text=self.aad_tenant_name) self.ui.aad_tenant_name_changed(self.aad_tenant_name) maya.refresh() else: if self.need_to_refresh_auth_tokens( [self.batch_auth_token, self.mgmt_auth_token]): refreshedTokens = self.refresh_auth_tokens( self.batch_auth_token, self.mgmt_auth_token) if not refreshedTokens: self.prompt_for_and_obtain_aad_tokens() return self._configure_post_auth() def _configure_post_auth(self): self.mgmtCredentials = AADTokenCredentials( self.mgmt_auth_token, cloud_environment=self.aad_environment_provider. getEnvironmentForId(self.aad_environment_id), tenant=self.aad_tenant_name) self.batchCredentials = AADTokenCredentials( self.batch_auth_token, cloud_environment=self.aad_environment_provider. getEnvironmentForId(self.aad_environment_id), tenant=self.aad_tenant_name) if self.can_init_from_config: self.init_from_config() self.ui.init_from_config() else: self.subscription_client = SubscriptionClient( self.mgmtCredentials, base_url=self.aad_environment_provider.getResourceManager( self.aad_environment_id)) self.ui.init_post_auth() def update_batch_and_storage_client_creds(self, batch_auth_token, mgmt_auth_token): self.batchCredentials = AADTokenCredentials( batch_auth_token, cloud_environment=self.aad_environment_provider. getEnvironmentForId(self.aad_environment_id), tenant=self.aad_tenant_name) self.mgmtCredentials = AADTokenCredentials( mgmt_auth_token, cloud_environment=self.aad_environment_provider. getEnvironmentForId(self.aad_environment_id), tenant=self.aad_tenant_name) self._client._mgmt_credentials = self.mgmtCredentials self._client._client.creds = self.batchCredentials self.storage_mgmt_client._client.creds = self.mgmtCredentials def need_to_refresh_auth_tokens(self, auth_token_list): currentTime = datetime.datetime.now() tokenRefreshThresholdSeconds = 5 * 60 for token in auth_token_list: if (dateparse(token['expiresOn']) - currentTime ).total_seconds() < tokenRefreshThresholdSeconds: return True return False def refresh_auth_tokens(self, batch_token, mgmt_token): context = adal.AuthenticationContext( self.aad_environment_provider.getAadAuthorityHostUrl( self.aad_environment_id) + '/' + self.aad_tenant_name, api_version=None) try: self.mgmt_auth_token = context.acquire_token_with_refresh_token( mgmt_token['refreshToken'], self.aadClientId, self.aad_environment_provider.getAadManagementUrl( self.aad_environment_id)) self.batch_auth_token = context.acquire_token_with_refresh_token( batch_token['refreshToken'], self.aadClientId, self.aad_environment_provider.getBatchResourceUrl( self.aad_environment_id)) return True except AdalError as exp: errors = exp.error_response['error_codes'] if 70002 in errors or 70008 in errors: #70002 is: Error validating credentials. 70008 is: The refresh token has expired due to inactivity. return False raise exp def prompt_for_and_obtain_aad_tokens(self): self.obtain_aad_tokens() self.ui.auth_status = "Please follow instructions below to sign in." maya.refresh() def obtain_aad_tokens(self): ui_environment_id = self.ui.aad_environment_dropdown.value() ui_tenant_name = self.ui.aadTenant context = adal.AuthenticationContext( self.aad_environment_provider.getAadAuthorityHostUrl( ui_environment_id) + '/' + ui_tenant_name, api_version=None) code = context.acquire_user_code( self.aad_environment_provider.getAadManagementUrl( ui_environment_id), self.aadClientId) self._log.info(code['message']) self.ui.prompt_for_login(code['message']) def aad_auth_thread_func(context, code): self.mgmt_auth_token = context.acquire_token_with_device_code( self.aad_environment_provider.getAadManagementUrl( ui_environment_id), code, self.aadClientId) self.batch_auth_token = context.acquire_token( self.aad_environment_provider.getBatchResourceUrl( ui_environment_id), self.mgmt_auth_token['userId'], self.aadClientId) self.aad_environment_id = ui_environment_id self.aad_tenant_name = ui_tenant_name self.remove_old_batch_account_from_config() maya.execute_in_main_thread(self._configure_post_auth) authThread = threading.Thread(target=aad_auth_thread_func, args=(context, code)) authThread.start() def remove_old_batch_account_from_config(self): self._cfg.remove_option('AzureBatch', 'batch_url') self._cfg.remove_option('AzureBatch', 'batch_account') self._cfg.remove_option('AzureBatch', 'subscription_id') self._cfg.remove_option('AzureBatch', 'subscription_name') self._cfg.remove_option('AzureBatch', 'storage_account_resource_id') self._save_config() def _configure_logging(self, log_level): """Configure the logger. Setup the file output and format the log messages. :param log_level: The specified level of logging verbosity. """ level = int(log_level) logger = logging.getLogger('AzureBatchMaya') file_format = logging.Formatter( "%(asctime)-15s [%(levelname)s] %(module)s: %(message)s") logfile = os.path.join(self._data_dir, "azure_batch.log") if not os.path.exists(logfile): with open(logfile, 'w') as handle: handle.write("Azure Batch Plugin Log") file_logging = logging.FileHandler(logfile) file_logging.setFormatter(file_format) logger.addHandler(file_logging) logger.setLevel(level) return logger def _read_config_file(self): """Populate the config tab UI with the values loaded from the configuration file. """ self.ensure_azurebatch_config_section_exists() #set to true optimistically here, if any values are missing then this must be an old config format self.can_init_from_config = True required_config_values = [ self.subscription_id, self.aad_tenant_name, self.subscription_name, self.aad_environment_id, self.batch_url, self.batch_account, self.storage_account_resource_id, self.mgmt_auth_token, self.batch_auth_token ] #if a required value is not present in the config, the relevant property will return 'None' if None in required_config_values: self.can_init_from_config = False self._log = self._configure_logging(self.logging_level) if self._client != None: self._client.threads = self.threads def _save_config(self): """Persist the current plugin configuration to file.""" config_file = os.path.join(self._data_dir, self._ini_file) with open(config_file, 'w') as handle: self._cfg.write(handle) def save_changes(self): """Persist auth config changes to file for future sessions.""" self.ensure_azurebatch_config_section_exists() #TODO is this method necessary anymore? self._cfg.set('AzureBatch', 'batch_url', self.batch_url) self._cfg.set('AzureBatch', 'batch_account', self.batch_account) self._cfg.set('AzureBatch', 'subscription_id', self.subscription_id) self._cfg.set('AzureBatch', 'subscription_name', self.subscription_name) self._cfg.set('AzureBatch', 'storage_account_resource_id', self.storage_account_resource_id) self._cfg.set('AzureBatch', 'logging', str(self.logging_level)) self._cfg.set('AzureBatch', 'aad_tenant_name', self.aad_tenant_name) self._cfg.set('AzureBatch', 'aad_environment_id', self.aad_environment_id) self._save_config() def ensure_azurebatch_config_section_exists(self): try: self._cfg.add_section('AzureBatch') except ConfigParser.DuplicateSectionError: pass def available_subscriptions(self): """Retrieve the currently available subscriptions to populate the subscription selection drop down. """ if not self.subscription_client: self.subscription_client = SubscriptionClient( self.mgmtCredentials, base_url=self.aad_environment_provider.getResourceManager( self.aad_environment_id)) all_subscriptions = self._call( self.subscription_client.subscriptions.list) self.subscriptions = [] for subscription in all_subscriptions: self.subscriptions.append(subscription) self.count = len(self.subscriptions) return self.subscriptions def init_after_subscription_selected(self, subscription_id, subscription_name): self.subscription_id = subscription_id self.subscription_name = subscription_name self.batch_mgmt_client = BatchManagementClient( self.mgmtCredentials, str(subscription_id), base_url=self.aad_environment_provider.getResourceManager( self.aad_environment_id)) def init_after_batch_account_selected(self, batchaccount, subscription_id): self.batch_account = batchaccount.name self.batch_url = "https://" + batchaccount.account_endpoint storageAccountId = batchaccount.auto_storage.storage_account_id self.storage_account_resource_id = storageAccountId parsedStorageAccountId = msrestazuretools.parse_resource_id( storageAccountId) self.storage_account = parsedStorageAccountId['name'] self.storage_mgmt_client = StorageManagementClient( self.mgmtCredentials, str(subscription_id), base_url=self.aad_environment_provider.getResourceManager( self.aad_environment_id)) try: self.storage_key = self._call( self.storage_mgmt_client.storage_accounts.list_keys, parsedStorageAccountId['resource_group'], self.storage_account).keys[0].value except Exception as exp: self.remove_old_batch_account_from_config() raise exp self._storage = storage.BlockBlobService(self.storage_account, self.storage_key) self._storage.MAX_SINGLE_PUT_SIZE = 2 * 1024 * 1024 #TODO refactor move the below shared block into def configureClient(client) self._client = batch.BatchExtensionsClient( self.batchCredentials, base_url=self.batch_url, storage_client=self._storage) self._client.config.add_user_agent(self._user_agent) self._client.threads = self.threads self._log = self._configure_logging(self.logging_level) def init_from_config(self): parsedStorageAccountId = msrestazuretools.parse_resource_id( self.storage_account_resource_id) self.storage_account = parsedStorageAccountId['name'] self.storage_mgmt_client = StorageManagementClient( self.mgmtCredentials, str(self.subscription_id), base_url=self.aad_environment_provider.getResourceManager( self.aad_environment_id)) self.storage_key = self._call( self.storage_mgmt_client.storage_accounts.list_keys, parsedStorageAccountId['resource_group'], self.storage_account).keys[0].value self._storage = storage.BlockBlobService(self.storage_account, self.storage_key) self._storage.MAX_SINGLE_PUT_SIZE = 2 * 1024 * 1024 #TODO refactor move the below shared block into def configureClient(client) self._client = batch.BatchExtensionsClient( self.batchCredentials, base_url=self.batch_url, storage_client=self._storage) self._client.config.add_user_agent(self._user_agent) self._client.threads = self.threads self.save_changes() self._log = self._configure_logging(self.logging_level) def available_batch_accounts(self): """Retrieve the currently available batch accounts to populate the account selection drop down. """ if not self.batch_mgmt_client: self.batch_mgmt_client = BatchManagementClient( self.mgmtCredentials, str(self.subscription_id), base_url=self.aad_environment_provider.getResourceManager( self.aad_environment_id)) batch_accounts = self._call(self.batch_mgmt_client.batch_account.list) accounts = [] for account in batch_accounts: if account.auto_storage != None: accounts.append(account) self.count = len(accounts) self._available_batch_accounts = accounts return self._available_batch_accounts def default_logging(self): return 10 def default_threads(self): return 20 def default_vm_sku(self): return "STANDARD_A1" def convert_timezone_naive_expireson_to_utc(self, token): # we want to store token expiry times as UTC for consistency if token and token is not None and 'expiresOn' in token: token_copy = copy.deepcopy(token) expireson_local = dateparse( token_copy['expiresOn']).replace(tzinfo=dateutil.tz.tzlocal()) expireson_utc = expireson_local.astimezone( dateutil.tz.gettz('UTC')) token_copy['expiresOnUTC'] = str(expireson_utc) del token_copy['expiresOn'] return token_copy else: return token def convert_utc_expireson_to_local_timezone_naive(self, token): #the standard token expireson format which the various AAD libraries expect / return is a vanilla datetime string, in local time and timezone naive (no tz specified) if token and token is not None and 'expiresOnUTC' in token: token_copy = copy.deepcopy(token) localtz = dateutil.tz.tzlocal() expireson_utc = dateparse(token_copy['expiresOnUTC']).replace( tzinfo=dateutil.tz.gettz('UTC')) expireson_local = expireson_utc.astimezone(dateutil.tz.tzlocal()) expireson_local_tz_naive = expireson_local.replace(tzinfo=None) token_copy['expiresOn'] = str(expireson_local_tz_naive) del token_copy['expiresOnUTC'] return token_copy else: return token
class AzureBatchConfig(object): """Handler for authentication and configuration of the SDK clients.""" def __init__(self, index, frame, start): """Create new configuration Handler. :param index: The UI tab index. :param frame: The shared plug-in UI frame. :type frame: :class:`.AzureBatchUI` :param func call: The shared REST API call wrapper. """ self.ui = None self.session = start self._tab_index = index self._data_dir = os.path.join(maya.prefs_dir(), 'AzureBatchData') self._ini_file = "azure_batch.ini" self._user_agent = "batchmaya/{}".format( os.environ.get('AZUREBATCH_VERSION')) self._cfg = ConfigParser.ConfigParser() self._client = None self._log = None self._storage = None self._configure_plugin() self.ui = ConfigUI(self, frame) self._auth = self._auto_authentication() self._update_config_ui() @property def batch(self): return self._client @property def storage(self): return self._storage @property def auth(self): return self._auth @property def path(self): return os.path.join(self._data_dir, self._ini_file) def _configure_plugin(self): """Set up the the config file, authenticate the SDK clients and set up the log file. """ if not os.path.exists(self._data_dir): os.makedirs(self._data_dir) config_file = os.path.join(self._data_dir, self._ini_file) try: self._cfg.read(config_file) self._storage = storage.BlockBlobService( self._cfg.get('AzureBatch', 'storage_account'), self._cfg.get('AzureBatch', 'storage_key'), endpoint_suffix=self._cfg.get('AzureBatch', 'storage_suffix')) self._storage.MAX_SINGLE_PUT_SIZE = 2 * 1024 * 1024 credentials = SharedKeyCredentials( self._cfg.get('AzureBatch', 'batch_account'), self._cfg.get('AzureBatch', 'batch_key')) self._client = batch.BatchExtensionsClient( credentials, base_url=self._cfg.get('AzureBatch', 'batch_url'), storage_client=self._storage) self._client.threads = self._cfg.getint('AzureBatch', 'threads') self._client.config.add_user_agent(self._user_agent) self._log = self._configure_logging( self._cfg.get('AzureBatch', 'logging')) except Exception as exp: # We should only worry about this if it happens when authenticating # using the UI, otherwise it's expected. if self.ui: raise ValueError("Invalid Configuration: {}".format(exp)) else: # We'll need a place holder logger self._log = self._configure_logging(LOG_LEVELS['debug']) def _configure_logging(self, log_level): """Configure the logger. Setup the file output and format the log messages. :param log_level: The specified level of logging verbosity. """ level = int(log_level) logger = logging.getLogger('AzureBatchMaya') file_format = logging.Formatter( "%(asctime)-15s [%(levelname)s] %(module)s: %(message)s") logfile = os.path.join(self._data_dir, "azure_batch.log") if not os.path.exists(logfile): with open(logfile, 'w') as handle: handle.write("Azure Batch Plugin Log") file_logging = logging.FileHandler(logfile) file_logging.setFormatter(file_format) logger.addHandler(file_logging) logger.setLevel(level) return logger def _update_config_ui(self): """Populate the config tab UI with the values loaded from the configuration file. """ try: self._cfg.add_section('AzureBatch') except ConfigParser.DuplicateSectionError: pass try: self.ui.endpoint = self._cfg.get('AzureBatch', 'batch_url') except ConfigParser.NoOptionError: self.ui.endpoint = "" try: self.ui.account = self._cfg.get('AzureBatch', 'batch_account') except ConfigParser.NoOptionError: self.ui.account = "" try: self.ui.key = self._cfg.get('AzureBatch', 'batch_key') except ConfigParser.NoOptionError: self.ui.key = "" try: self.ui.storage = self._cfg.get('AzureBatch', 'storage_account') except ConfigParser.NoOptionError: self.ui.storage = "" try: self.ui.storage_key = self._cfg.get('AzureBatch', 'storage_key') except ConfigParser.NoOptionError: self.ui.storage_key = "" try: self.ui.storage_suffix = self._cfg.get('AzureBatch', 'storage_suffix') except ConfigParser.NoOptionError: self.ui.storage_suffix = "core.windows.net" try: self.ui.logging = self._cfg.getint('AzureBatch', 'logging') except ConfigParser.NoOptionError: self.ui.logging = 10 self._cfg.set('AzureBatch', 'logging', LOG_LEVELS['debug']) try: self.ui.threads = self._cfg.getint('AzureBatch', 'threads') except ConfigParser.NoOptionError: self.ui.threads = 20 self._cfg.set('AzureBatch', 'threads', 20) finally: if self._client != None: self._client.threads = self.ui.threads self.ui.set_authenticate(self._auth) def _auto_authentication(self): """Test whether the clients are correctly authenticated by doing some quick API calls. """ try: filter = batch.models.PoolListOptions(max_results=1, select="id") list(self._client.pool.list(filter)) self._storage.list_containers(num_results=1) return True except Exception as exp: self._log.info("Failed to authenticate: {0}".format(exp)) return False def _save_config(self): """Persist the current plugin configuration to file.""" config_file = os.path.join(self._data_dir, self._ini_file) with open(config_file, 'w') as handle: self._cfg.write(handle) def set_logging(self, level): """Set the logging level to that specified in the UI. :param str level: The specified logging level. """ self._log.setLevel(level) self._cfg.set('AzureBatch', 'logging', level) self._save_config() def set_threads(self, threads): """Set the number of threads to that specified in the UI. :param int threads: The specified number of threads. """ self._cfg.set('AzureBatch', 'threads', threads) self._client.threads = threads self._save_config() def save_changes(self): """Persist auth config changes to file for future sessions.""" try: self._cfg.add_section('AzureBatch') except ConfigParser.DuplicateSectionError: pass self._cfg.set('AzureBatch', 'batch_url', self.ui.endpoint) self._cfg.set('AzureBatch', 'batch_account', self.ui.account) self._cfg.set('AzureBatch', 'batch_key', self.ui.key) self._cfg.set('AzureBatch', 'storage_account', self.ui.storage) self._cfg.set('AzureBatch', 'storage_key', self.ui.storage_key) self._cfg.set('AzureBatch', 'storage_suffix', self.ui.storage_suffix) self._save_config() def authenticate(self): """Begin authentication - initiated by the UI button.""" try: self._configure_plugin() self._auth = self._auto_authentication() except ValueError as exp: maya.error(str(exp)) self._auth = False finally: self.ui.set_authenticate(self._auth) self.session() def get_threads(self): """Attempt to retrieve number of threads configured for the plugin.""" return self._client.threads def get_cached_vm_sku(self): """Attempt to retrieve a selected VM SKU from a previous session.""" try: return self._cfg.get('AzureBatch', 'vm_sku') except ConfigParser.NoOptionError: return None def store_vm_sku(self, sku): """Cache selected VM SKU for later sessions.""" self._cfg.set('AzureBatch', 'vm_sku', sku) self._save_config() def get_cached_image(self): """Attempt to retrieve a selected image a previous session.""" try: return self._cfg.get('AzureBatch', 'image') except ConfigParser.NoOptionError: return None def store_image(self, image): """Cache selected image for later sessions.""" self._cfg.set('AzureBatch', 'image', image) self._save_config() def get_cached_autoscale_formula(self): """Attempt to retrieve an autoscale forumla from a previous session.""" try: return self._cfg.get('AzureBatch', 'autoscale') except ConfigParser.NoOptionError: return None def store_autoscale_formula(self, formula): """Cache selected VM SKU for later sessions.""" self._cfg.set('AzureBatch', 'autoscale', formula) self._save_config()