Example #1
0
    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()
Example #3
0
    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"])
Example #5
0
 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")
Example #10
0
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))
Example #11
0
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