def init_after_account_selected(self): try: if not hasattr(self, "submission"): self.submission = AzureBatchSubmission( self.tab_index['SUBMIT'], self.frame, self.call) if not hasattr(self, "assets"): self.assets = AzureBatchAssets(self.tab_index['ASSETS'], self.frame, self.call) if not hasattr(self, "pools"): self.pools = AzureBatchPools(self.tab_index['POOLS'], self.frame, self.call) if not hasattr(self, "jobhistory"): self.jobhistory = AzureBatchJobHistory( self.tab_index['JOBHISTORY'], self.frame, self.call) if not hasattr(self, "env"): self.env = AzureBatchEnvironment(self.tab_index['ENV'], self.frame, self.call) self.config.auth = True self.start() except Exception as exp: if (maya.window("AzureBatch", q=1, exists=1)): maya.delete_ui("AzureBatch") message = "Batch Plugin Failed to Start: {0}".format(exp) maya.error(message) raise
def test_submission_start(self, mock_maya): session = mock.Mock(batch="batch_client", storage="storage_client") self.mock_self.ui = mock.create_autospec(SubmissionUI) self.mock_self.ui.render_module = "module" self.mock_self.renderer = mock.Mock() AzureBatchSubmission.start(self.mock_self, session, "assets", "pools", "env") self.mock_self.renderer.delete.assert_called_with() self.mock_self._configure_renderer.assert_called_with() self.mock_self.renderer.display.assert_called_with("module") self.mock_self.ui.is_logged_in.assert_called_with()
def test_submission_configure_renderer(self, mock_maya, mock_default): mock_default.return_value = mock.Mock(render_engine="default") mock_maya.get_attr.return_value = "test_renderer" renderer = mock.Mock(render_engine="my_renderer") self.mock_self.modules = [renderer, "test", None] AzureBatchSubmission._configure_renderer(self.mock_self) self.assertEqual(self.mock_self.renderer.render_engine, "default") renderer = mock.Mock(render_engine="test_renderer") self.mock_self.modules.append(renderer) AzureBatchSubmission._configure_renderer(self.mock_self) self.assertEqual(self.mock_self.renderer.render_engine, "test_renderer")
def test_submission_available_pools(self): def list_pools(**kwargs): self.assertTrue(kwargs.get("lazy")) return ["pool1", "pool2"] self.mock_self.pool_manager = mock.Mock(list_pools=list_pools) pools = AzureBatchSubmission.available_pools(self.mock_self) self.assertEqual(pools, ["pool1", "pool2"])
def __init__(self): """Initialize all the tabs and attempt to authenticate using cached credentials if available. """ self._log = logging.getLogger('AzureBatchMaya') try: self.frame = AzureBatchUI(self) self.config = AzureBatchConfig(self.tab_index['AUTH'], self.frame, self.start) self.submission = AzureBatchSubmission(self.tab_index['SUBMIT'], self.frame, self.call) self.assets = AzureBatchAssets(self.tab_index['ASSETS'], self.frame, self.call) self.pools = AzureBatchPools(self.tab_index['POOLS'], self.frame, self.call) self.jobhistory = AzureBatchJobHistory(self.tab_index['JOBHISTORY'], self.frame, self.call) self.env = AzureBatchEnvironment(self.tab_index['ENV'], self.frame, self.call) self.start() except Exception as exp: if (maya.window("AzureBatch", q=1, exists=1)): maya.delete_ui("AzureBatch") message = "Batch Plugin Failed to Start: {0}".format(exp) maya.error(message) raise
def test_submission_collect_modules(self): mods = AzureBatchSubmission._collect_modules(self.mock_self) self.assertEqual(len(mods), 4)
def test_submission_create(self, mock_ui, mock_call, mock_mods): submission = AzureBatchSubmission(2, "frame", "call") mock_mods.assert_called_with() mock_ui.assert_called_with(submission, "frame")
def test_submission_submit(self, mock_maya, mock_utils): def call(func, *args, **kwargs): self.assertTrue(callable(func)) return func(*args, **kwargs) mock_prog = mock.create_autospec(ProgressBar) mock_prog.is_cancelled.return_value = False mock_utils.ProgressBar.return_value = mock_prog mock_utils.format_scene_path.return_value = "test_file_path" mock_utils.build_template_filename.side_effect = azurebatchutils.build_template_filename self.mock_self._configure_pool = lambda t: AzureBatchSubmission._configure_pool( self.mock_self, t) self.mock_self._submit_threads = lambda: 6 self.mock_self._check_plugins.return_value = [] self.mock_self._get_os_flavor.return_value = OperatingSystem.windows self.mock_self.pool_manager.create_auto_pool.return_value = { 'autoPool': 'auto-pool' } self.mock_self.pool_manager.create_pool.return_value = { 'poolId': 'new-pool' } self.mock_self.env_manager.get_environment_settings.return_value = [{ 'name': 'foo', 'value': 'bar' }] self.mock_self.renderer = mock.Mock(render_engine='arnold') self.mock_self.renderer.get_jobdata.return_value = ("a", "b") self.mock_self.renderer.get_params.return_value = {"foo": "bar"} self.mock_self.renderer.get_title.return_value = "job name" self.mock_self._get_task_container_image.return_value = "containerImage" self.mock_self._call = call mock_job = mock.create_autospec(models.ExtendedJobParameter) self.mock_self.batch.job.jobparameter_from_json.return_value = mock_job self.mock_self.asset_manager.upload.return_value = ({ "project": "files", "path_map": "maps", "thumb_script": "thumbs", "workspace": "workspace" }, mock_prog) self.mock_self.asset_manager.generate_sas_token.return_value = "0123456789ABCDEF" self.mock_self.batch.threads = 6 mock_maya.about.return_value = "2017" self.mock_self.ui.get_pool.return_value = {1: (4, 4)} AzureBatchSubmission.submit(self.mock_self) self.assertEqual(mock_maya.error.call_count, 0) self.mock_self.renderer.disable.assert_called_with(True) self.mock_self.pool_manager.create_auto_pool.assert_called_with( (4, 4), "job name") self.mock_self.batch.job.add.assert_called_with(mock_job) self.mock_self.batch.job.jobparameter_from_json.assert_called_with({ 'commonEnvironmentSettings': [{ 'name': 'foo', 'value': 'bar' }], 'poolInfo': { 'autoPool': 'auto-pool' }, 'displayName': 'job name', 'id': mock.ANY, 'applicationTemplateInfo': { 'parameters': { 'taskContainerImageName': 'containerImage', 'sceneFile': 'test_file_path', 'outputs': mock.ANY, 'assetScript': 'maps', 'foo': 'bar', 'projectData': 'files', 'thumbScript': 'thumbs', 'storageURL': '0123456789ABCDEF', 'workspace': 'workspace' }, 'filePath': os.path.join(os.environ['AZUREBATCH_TEMPLATES'], 'containers', 'arnold-2017-windows.json') }, 'metadata': [{ 'name': 'JobType', 'value': 'Maya' }] }) self.mock_self.ui.get_pool.return_value = {2: 4} AzureBatchSubmission.submit(self.mock_self) self.assertEqual(mock_maya.error.call_count, 0) self.mock_self.renderer.disable.assert_called_with(True) self.mock_self.batch.job.add.assert_called_with(mock_job) self.mock_self.batch.job.jobparameter_from_json.assert_called_with({ 'commonEnvironmentSettings': [{ 'name': 'foo', 'value': 'bar' }], 'poolInfo': { 'poolId': '4' }, 'displayName': 'job name', 'id': mock.ANY, 'applicationTemplateInfo': { 'parameters': { 'taskContainerImageName': 'containerImage', 'sceneFile': 'test_file_path', 'outputs': mock.ANY, 'assetScript': 'maps', 'foo': 'bar', 'projectData': 'files', 'thumbScript': 'thumbs', 'storageURL': '0123456789ABCDEF', 'workspace': 'workspace' }, 'filePath': os.path.join(os.environ['AZUREBATCH_TEMPLATES'], 'containers', 'arnold-2017-windows.json') }, 'metadata': [{ 'name': 'JobType', 'value': 'Maya' }] }) self.mock_self._check_outputs.side_effect = ValueError("No camera") AzureBatchSubmission.submit(self.mock_self) self.assertEqual(mock_maya.error.call_count, 1) self.mock_self._check_outputs.side_effect = None self.mock_self.ui.get_pool.return_value = {3: (4, 4)} AzureBatchSubmission.submit(self.mock_self) self.assertEqual(mock_maya.error.call_count, 1) self.mock_self.renderer.disable.assert_called_with(True) self.mock_self.batch.job.add.assert_called_with(mock_job) self.mock_self.batch.job.add.call_count = 0 self.mock_self.pool_manager.create_pool.assert_called_with((4, 4), 'job name') mock_prog.is_cancelled.side_effect = CancellationException("cancelled") AzureBatchSubmission.submit(self.mock_self) self.assertEqual(mock_maya.info.call_count, 4) self.mock_self.renderer.disable.assert_called_with(True) self.assertEqual(self.mock_self.batch.job.add.call_count, 0) mock_prog.is_cancelled.side_effect = None self.mock_self.pool_manager.create_pool.side_effect = ValueError( "Bad data") AzureBatchSubmission.submit(self.mock_self) self.assertEqual(mock_maya.error.call_count, 2) self.mock_self.renderer.disable.assert_called_with(True) self.assertEqual(self.mock_self.batch.job.add.call_count, 0)
def test_submission_refresh_renderer(self): self.mock_self.ui = mock.create_autospec(SubmissionUI) self.mock_self.renderer = mock.Mock() AzureBatchSubmission.refresh_renderer(self.mock_self, "layout") self.mock_self.renderer.delete.assert_called_with() self.mock_self.renderer.display.assert_called_with("layout")
class AzureBatchSettings(object): tab_index = { 'AUTH': 1, 'SUBMIT': 2, 'ASSETS': 3, 'POOLS': 4, 'JOBHISTORY': 5, 'ENV': 6 } @staticmethod def starter(): """Called by the mel script when the shelf button is clicked.""" AzureBatchSettings() def __init__(self): """Initialize all the tabs and attempt to authenticate using cached credentials if available. """ self._log = logging.getLogger('AzureBatchMaya') try: self.frame = AzureBatchUI(self) self.config = AzureBatchConfig(self.tab_index['AUTH'], self.frame, self.start) self.submission = AzureBatchSubmission(self.tab_index['SUBMIT'], self.frame, self.call) self.assets = AzureBatchAssets(self.tab_index['ASSETS'], self.frame, self.call) self.pools = AzureBatchPools(self.tab_index['POOLS'], self.frame, self.call) self.jobhistory = AzureBatchJobHistory(self.tab_index['JOBHISTORY'], self.frame, self.call) self.env = AzureBatchEnvironment(self.tab_index['ENV'], self.frame, self.call) self.start() except Exception as exp: if (maya.window("AzureBatch", q=1, exists=1)): maya.delete_ui("AzureBatch") message = "Batch Plugin Failed to Start: {0}".format(exp) maya.error(message) raise def start(self): """Start the plugin UI. Depending on whether auto-authentication was successful, the plugin will start by displaying the submission tab. Otherwise the UI will be disabled, and the login tab will be displayed. """ try: self._log.debug("Starting AzureBatchShared...") if self.config.auth: self.frame.is_logged_in() self.env.configure(self.config) self.jobhistory.configure(self.config) self.assets.configure(self.config) self.pools.configure(self.config, self.env) self.submission.start(self.config, self.assets, self.pools, self.env) else: self.frame.is_logged_out() except Exception as exp: self._log.warning(exp) if (maya.window("AzureBatch", q=1, exists=1)): maya.delete_ui("AzureBatch") maya.error("Batch Plugin UI failed to load:\n{0}".format(exp)) def call(self, command, *args, **kwargs): """Wrap all Batch and Storage API calls in order to handle errors. Some errors we anticipate and raise without a dialog (e.g. PoolNotFound). Others we raise and display to the user. """ try: return command(*args, **kwargs) except BatchErrorException as exp: if exp.error.code in ACCEPTED_ERRORS: self._log.info("Call failed: {}".format(exp.error.code)) raise else: message = exp.error.message.value if exp.error.values: message += "Details:\n" for detail in exp.error.values: message += "{}: {}".format(detail.key, detail.value) raise ValueError(message) except Exception as exp: if (maya.window("AzureBatch", q=1, exists=1)): maya.delete_ui("AzureBatch") exc_type, exc_value, exc_traceback = sys.exc_info() self._log.error("".join(traceback.format_exception(exc_type, exc_value, exc_traceback))) raise ValueError("Error: {0}".format(exp))
class AzureBatchSettings(object): tab_index = { 'AUTH': 1, 'SUBMIT': 2, 'ASSETS': 3, 'POOLS': 4, 'JOBHISTORY': 5, 'ENV': 6 } @staticmethod def starter(): """Called by the mel script when the shelf button is clicked.""" AzureBatchSettings() def __init__(self): """Initialize all the tabs and attempt to authenticate using cached credentials if available. """ self._log = logging.getLogger('AzureBatchMaya') try: self.frame = AzureBatchUI(self) self.config = AzureBatchConfig(self.tab_index['AUTH'], self, self.frame, self.start, self.call) if (self.config.can_init_from_config): self.init_after_account_selected() except Exception as exp: if (maya.window("AzureBatch", q=1, exists=1)): maya.delete_ui("AzureBatch") message = "Batch Plugin Failed to Start: {0}".format(exp) maya.error(message) raise def init_after_account_selected(self): try: if not hasattr(self, "submission"): self.submission = AzureBatchSubmission( self.tab_index['SUBMIT'], self.frame, self.call) if not hasattr(self, "assets"): self.assets = AzureBatchAssets(self.tab_index['ASSETS'], self.frame, self.call) if not hasattr(self, "pools"): self.pools = AzureBatchPools(self.tab_index['POOLS'], self.frame, self.call) if not hasattr(self, "jobhistory"): self.jobhistory = AzureBatchJobHistory( self.tab_index['JOBHISTORY'], self.frame, self.call) if not hasattr(self, "env"): self.env = AzureBatchEnvironment(self.tab_index['ENV'], self.frame, self.call) self.config.auth = True self.start() except Exception as exp: if (maya.window("AzureBatch", q=1, exists=1)): maya.delete_ui("AzureBatch") message = "Batch Plugin Failed to Start: {0}".format(exp) maya.error(message) raise def start(self): """Start the plugin UI. Depending on whether auto-authentication was successful, the plugin will start by displaying the submission tab. Otherwise the UI will be disabled, and the login tab will be displayed. """ try: self._log.debug("Starting AzureBatchShared...") if self.config.auth: self.frame.is_logged_in() self.env.configure(self.config, self.submission, self.assets) self.jobhistory.configure(self.config) self.assets.configure(self.config, self.submission, self.env) self.pools.configure(self.config, self.env) self.submission.start(self.config, self.assets, self.pools, self.env) else: self.frame.is_logged_out() except Exception as exp: self._log.warning(exp) if (maya.window("AzureBatch", q=1, exists=1)): maya.delete_ui("AzureBatch") maya.error("Batch Plugin UI failed to load:\n{0}".format(exp)) def call(self, command, *args, **kwargs): """Wrap all Batch and Storage API calls in order to handle errors. Some errors we anticipate and raise without a dialog (e.g. PoolNotFound). Others we raise and display to the user. """ try: result = command(*args, **kwargs) return self.ensure_iter_called(result) except BatchErrorException as exp: #if auth error (401) refresh tokens and recreate clients, before repeating the call if exp.response.status_code in [401]: self.config.refresh_auth_tokens(self.config.batch_auth_token, self.config.mgmt_auth_token) self.config.update_batch_and_storage_client_creds( self.config.batch_auth_token, self.config.mgmt_auth_token) result = command(*args, **kwargs) try: return self.ensure_iter_called(result) except BatchErrorException as exp: self.handle_batch_exception(exp) else: self.handle_batch_exception(exp) except Exception as exp: if (maya.window("AzureBatch", q=1, exists=1)): maya.delete_ui("AzureBatch") exc_type, exc_value, exc_traceback = sys.exc_info() self._log.error("".join( traceback.format_exception(exc_type, exc_value, exc_traceback))) raise ValueError("Error: {0}".format(exp)) def handle_batch_exception(self, exp): if exp.error.code in ACCEPTED_ERRORS: self._log.info("Call failed: {}".format(exp.error.code)) raise else: message = exp.error.message.value if exp.error.values: message += "Details:\n" for detail in exp.error.values: message += "{}: {}".format(detail.key, detail.value) raise ValueError(message) def ensure_iter_called(self, result): if isinstance(result, collections.Iterator): #peek at the first result to force the first call and make sure any auth errors are raised here try: peek = result.next() result.reset() except StopIteration: pass return result