def test_add_extension_with_name_invalid_checksum(self):
     extension_name = MY_EXT_NAME
     bad_sha256 = 'thishashisclearlywrong'
     with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(MY_EXT_SOURCE, bad_sha256)):
         with self.assertRaises(CLIError) as err:
             add_extension(cmd=self.cmd, extension_name=extension_name)
         self.assertTrue('The checksum of the extension does not match the expected value.' in str(err.exception))
 def test_add_extension_with_name_valid_checksum(self):
     extension_name = MY_EXT_NAME
     computed_extension_sha256 = _compute_file_hash(MY_EXT_SOURCE)
     with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(MY_EXT_SOURCE, computed_extension_sha256)):
         add_extension(cmd=self.cmd, extension_name=extension_name)
     ext = show_extension(MY_EXT_NAME)
     self.assertEqual(ext[OUT_KEY_NAME], MY_EXT_NAME)
 def test_update_extension_no_updates(self):
     add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
     ext = show_extension(MY_EXT_NAME)
     self.assertEqual(ext[OUT_KEY_VERSION], '0.0.3+dev')
     with mock.patch('azure.cli.core.extension.operations.resolve_from_index', side_effect=NoExtensionCandidatesError()):
         with self.assertRaises(CLIError) as err:
             update_extension(self.cmd, MY_EXT_NAME)
         self.assertTrue("No updates available for '{}'.".format(MY_EXT_NAME) in str(err.exception))
 def test_add_list_show_remove_extension(self):
     add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
     actual = list_extensions()
     self.assertEqual(len(actual), 1)
     ext = show_extension(MY_EXT_NAME)
     self.assertEqual(ext[OUT_KEY_NAME], MY_EXT_NAME)
     remove_extension(MY_EXT_NAME)
     num_exts = len(list_extensions())
     self.assertEqual(num_exts, 0)
 def test_update_extension(self):
     add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
     ext = show_extension(MY_EXT_NAME)
     self.assertEqual(ext[OUT_KEY_VERSION], '0.0.3+dev')
     newer_extension = _get_test_data_file('myfirstcliextension-0.0.4+dev-py2.py3-none-any.whl')
     computed_extension_sha256 = _compute_file_hash(newer_extension)
     with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(newer_extension, computed_extension_sha256)):
         update_extension(self.cmd, MY_EXT_NAME)
     ext = show_extension(MY_EXT_NAME)
     self.assertEqual(ext[OUT_KEY_VERSION], '0.0.4+dev')
 def test_add_list_show_remove_extension_with_dashes(self):
     add_extension(cmd=self.cmd, source=MY_SECOND_EXT_SOURCE_DASHES)
     actual = list_extensions()
     self.assertEqual(len(actual), 1)
     ext = show_extension(MY_SECOND_EXT_NAME_DASHES)
     self.assertEqual(ext[OUT_KEY_NAME], MY_SECOND_EXT_NAME_DASHES)
     self.assertIn(OUT_KEY_NAME, ext[OUT_KEY_METADATA], "Unable to get full metadata")
     self.assertEqual(ext[OUT_KEY_METADATA][OUT_KEY_NAME], MY_SECOND_EXT_NAME_DASHES)
     remove_extension(MY_SECOND_EXT_NAME_DASHES)
     num_exts = len(list_extensions())
     self.assertEqual(num_exts, 0)
 def test_add_extension_verify_no_pip_proxy(self):
     extension_name = MY_EXT_NAME
     computed_extension_sha256 = _compute_file_hash(MY_EXT_SOURCE)
     with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(MY_EXT_SOURCE, computed_extension_sha256)), \
             mock.patch('azure.cli.core.extension.operations.shutil'), \
             mock.patch('azure.cli.core.extension.operations.check_output') as check_output:
         add_extension(cmd=self.cmd, extension_name=extension_name)
         args = check_output.call_args
         pip_cmd = args[0][0]
         if '--proxy' in pip_cmd:
             raise AssertionError("proxy parameter in check_output args although no proxy specified")
 def test_update_extension_exception_in_update_and_rolled_back(self):
     add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
     ext = show_extension(MY_EXT_NAME)
     self.assertEqual(ext[OUT_KEY_VERSION], '0.0.3+dev')
     newer_extension = _get_test_data_file('myfirstcliextension-0.0.4+dev-py2.py3-none-any.whl')
     bad_sha256 = 'thishashisclearlywrong'
     with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(newer_extension, bad_sha256)):
         with self.assertRaises(CLIError) as err:
             update_extension(self.cmd, MY_EXT_NAME)
         self.assertTrue('Failed to update. Rolled {} back to {}.'.format(ext['name'], ext[OUT_KEY_VERSION]) in str(err.exception))
     ext = show_extension(MY_EXT_NAME)
     self.assertEqual(ext[OUT_KEY_VERSION], '0.0.3+dev')
 def test_add_extension_with_pip_proxy(self):
     extension_name = MY_EXT_NAME
     proxy_param = '--proxy'
     proxy_endpoint = "https://*****:*****@proxy.microsoft.com"
     computed_extension_sha256 = _compute_file_hash(MY_EXT_SOURCE)
     with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(MY_EXT_SOURCE, computed_extension_sha256)), \
             mock.patch('azure.cli.core.extension.operations.shutil'), \
             mock.patch('azure.cli.core.extension.operations.check_output') as check_output:
         add_extension(cmd=self.cmd, extension_name=extension_name, pip_proxy=proxy_endpoint)
         args = check_output.call_args
         pip_cmd = args[0][0]
         proxy_index = pip_cmd.index(proxy_param)
         assert pip_cmd[proxy_index + 1] == proxy_endpoint
 def test_add_extension_with_name_but_it_already_exists(self):
     # Add extension without name first
     add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
     ext = show_extension(MY_EXT_NAME)
     self.assertEqual(ext[OUT_KEY_NAME], MY_EXT_NAME)
     # Now add using name
     computed_extension_sha256 = _compute_file_hash(MY_EXT_SOURCE)
     with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(MY_EXT_SOURCE, computed_extension_sha256)):
         with mock.patch('azure.cli.core.extension.operations.logger') as mock_logger:
             add_extension(cmd=self.cmd, extension_name=MY_EXT_NAME)
             call_args = mock_logger.warning.call_args
             self.assertEqual("Extension '%s' is already installed.", call_args[0][0])
             self.assertEqual(MY_EXT_NAME, call_args[0][1])
             self.assertEqual(mock_logger.warning.call_count, 1)
    def test_add_list_show_remove_extension_extra_index_url(self):
        """
        Tests extension addition while specifying --extra-index-url parameter.
        :return:
        """
        extra_index_urls = ['https://testpypi.python.org/simple', 'https://pypi.python.org/simple']

        add_extension(cmd=self.cmd, source=MY_EXT_SOURCE, pip_extra_index_urls=extra_index_urls)
        actual = list_extensions()
        self.assertEqual(len(actual), 1)
        ext = show_extension(MY_EXT_NAME)
        self.assertEqual(ext[OUT_KEY_NAME], MY_EXT_NAME)
        remove_extension(MY_EXT_NAME)
        num_exts = len(list_extensions())
        self.assertEqual(num_exts, 0)
Exemple #12
0
def start_shell(cmd, update=None, style=None):
    from importlib import import_module
    try:
        get_extension(INTERACTIVE_EXTENSION_NAME)
        if update:
            logger.warning("Updating the Interactive extension to the latest available..")
            update_extension(INTERACTIVE_EXTENSION_NAME)
            reload_extension(INTERACTIVE_EXTENSION_NAME)
    except ExtensionNotInstalledException:
        logger.warning("Installing the Interactive extension..")
        add_extension(extension_name=INTERACTIVE_EXTENSION_NAME)

    add_extension_to_path(INTERACTIVE_EXTENSION_NAME)
    interactive_module = get_extension_modname(ext_name=INTERACTIVE_EXTENSION_NAME)
    azext_interactive = import_module(interactive_module)
    azext_interactive.start_shell(cmd, style=style)
    def test_update_extension_extra_index_url(self):
        """
        Tests extension update while specifying --extra-index-url parameter.
        :return:
        """
        extra_index_urls = ['https://testpypi.python.org/simple', 'https://pypi.python.org/simple']

        add_extension(cmd=self.cmd, source=MY_EXT_SOURCE, pip_extra_index_urls=extra_index_urls)
        ext = show_extension(MY_EXT_NAME)
        self.assertEqual(ext[OUT_KEY_VERSION], '0.0.3+dev')
        newer_extension = _get_test_data_file('myfirstcliextension-0.0.4+dev-py2.py3-none-any.whl')
        computed_extension_sha256 = _compute_file_hash(newer_extension)
        with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(newer_extension, computed_extension_sha256)):
            update_extension(self.cmd, MY_EXT_NAME, pip_extra_index_urls=extra_index_urls)
        ext = show_extension(MY_EXT_NAME)
        self.assertEqual(ext[OUT_KEY_VERSION], '0.0.4+dev')
    def test_update_extension_verify_no_pip_proxy(self):
        add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
        ext = show_extension(MY_EXT_NAME)
        self.assertEqual(ext[OUT_KEY_VERSION], '0.0.3+dev')
        newer_extension = _get_test_data_file('myfirstcliextension-0.0.4+dev-py2.py3-none-any.whl')
        computed_extension_sha256 = _compute_file_hash(newer_extension)

        with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(MY_EXT_SOURCE, computed_extension_sha256)), \
                mock.patch('azure.cli.core.extension.operations.shutil'), \
                mock.patch('azure.cli.core.extension.operations.is_valid_sha256sum', return_value=(True, computed_extension_sha256)), \
                mock.patch('azure.cli.core.extension.operations.extension_exists', return_value=None), \
                mock.patch('azure.cli.core.extension.operations.check_output') as check_output:

            update_extension(self.cmd, MY_EXT_NAME)
            args = check_output.call_args
            pip_cmd = args[0][0]
            if '--proxy' in pip_cmd:
                raise AssertionError("proxy parameter in check_output args although no proxy specified")
    def test_update_extension_with_pip_proxy(self):
        add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
        ext = show_extension(MY_EXT_NAME)
        self.assertEqual(ext[OUT_KEY_VERSION], '0.0.3+dev')
        newer_extension = _get_test_data_file('myfirstcliextension-0.0.4+dev-py2.py3-none-any.whl')
        computed_extension_sha256 = _compute_file_hash(newer_extension)

        proxy_param = '--proxy'
        proxy_endpoint = "https://*****:*****@proxy.microsoft.com"
        with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=(MY_EXT_SOURCE, computed_extension_sha256)), \
                mock.patch('azure.cli.core.extension.operations.shutil'), \
                mock.patch('azure.cli.core.extension.operations.is_valid_sha256sum', return_value=(True, computed_extension_sha256)), \
                mock.patch('azure.cli.core.extension.operations.extension_exists', return_value=None), \
                mock.patch('azure.cli.core.extension.operations.check_output') as check_output:

            update_extension(self.cmd, MY_EXT_NAME, pip_proxy=proxy_endpoint)
            args = check_output.call_args
            pip_cmd = args[0][0]
            proxy_index = pip_cmd.index(proxy_param)
            assert pip_cmd[proxy_index + 1] == proxy_endpoint
Exemple #16
0
    def _check_value(self, action, value):  # pylint: disable=too-many-statements, too-many-locals, too-many-branches
        # Override to customize the error message when a argument is not among the available choices
        # converted value must be one of the choices (if specified)
        if action.choices is not None and value not in action.choices:  # pylint: disable=too-many-nested-blocks
            # self.cli_ctx is None when self.prog is beyond 'az', such as 'az iot'.
            # use cli_ctx from cli_help which is not lost.
            cli_ctx = self.cli_ctx or (self.cli_help.cli_ctx
                                       if self.cli_help else None)

            caused_by_extension_not_installed = False
            command_name_inferred = self.prog
            error_msg = None
            use_dynamic_install = 'no'
            if not self.command_source:
                candidates = []
                args = self.prog.split() + self._raw_arguments
                use_dynamic_install = self._get_extension_use_dynamic_install_config(
                )
                if use_dynamic_install != 'no':
                    # Check if the command is from an extension
                    from azure.cli.core.util import roughly_parse_command
                    command_str = roughly_parse_command(args[1:])
                    ext_name = self._search_in_extension_commands(command_str)
                    # The input command matches the prefix of one or more extension commands
                    if isinstance(ext_name, list):
                        if len(ext_name) > 1:
                            from knack.prompting import prompt_choice_list, NoTTYException
                            prompt_msg = "The command requires the latest version of one of the following " \
                                "extensions. You need to pick one to install:"
                            try:
                                choice_idx = prompt_choice_list(
                                    prompt_msg, ext_name)
                                ext_name = ext_name[choice_idx]
                                use_dynamic_install = 'yes_without_prompt'
                            except NoTTYException:
                                error_msg = "{}{}\nUnable to prompt for selection as no tty available. Please " \
                                    "update or install the extension with 'az extension add --upgrade -n " \
                                    "<extension-name>'.".format(prompt_msg, ext_name)
                                logger.error(error_msg)
                                telemetry.set_user_fault(error_msg)
                                self.exit(2)
                        else:
                            ext_name = ext_name[0]

                    if ext_name:
                        caused_by_extension_not_installed = True
                        telemetry.set_command_details(
                            command_str,
                            parameters=AzCliCommandInvoker.
                            _extract_parameter_names(args),  # pylint: disable=protected-access
                            extension_name=ext_name)
                        run_after_extension_installed = self._get_extension_run_after_dynamic_install_config(
                        )
                        prompt_info = ""
                        if use_dynamic_install == 'yes_without_prompt':
                            logger.warning(
                                'The command requires the extension %s. '
                                'It will be installed first.', ext_name)
                            go_on = True
                        else:
                            from knack.prompting import prompt_y_n, NoTTYException
                            prompt_msg = 'The command requires the extension {}. ' \
                                'Do you want to install it now?'.format(ext_name)
                            if run_after_extension_installed:
                                prompt_msg = '{} The command will continue to run after the extension is installed.' \
                                    .format(prompt_msg)
                            NO_PROMPT_CONFIG_MSG = "Run 'az config set extension.use_dynamic_install=" \
                                "yes_without_prompt' to allow installing extensions without prompt."
                            try:
                                go_on = prompt_y_n(prompt_msg, default='y')
                                if go_on:
                                    prompt_info = " with prompt"
                                    logger.warning(NO_PROMPT_CONFIG_MSG)
                            except NoTTYException:
                                error_msg = "The command requires the extension {}. " \
                                            "Unable to prompt for extension install confirmation as no tty " \
                                            "available. {}".format(ext_name, NO_PROMPT_CONFIG_MSG)
                                go_on = False
                        if go_on:
                            from azure.cli.core.extension.operations import add_extension
                            add_extension(cli_ctx=cli_ctx,
                                          extension_name=ext_name,
                                          upgrade=True)
                            if run_after_extension_installed:
                                import subprocess
                                import platform
                                exit_code = subprocess.call(
                                    args, shell=platform.system() == 'Windows')
                                error_msg = (
                                    "Extension {} dynamically installed{} and commands will be "
                                    "rerun automatically.").format(
                                        ext_name, prompt_info)
                                telemetry.set_user_fault(error_msg)
                                self.exit(exit_code)
                            else:
                                with CommandLoggerContext(logger):
                                    error_msg = 'Extension {} installed{}. Please rerun your command.' \
                                        .format(ext_name, prompt_info)
                                    logger.error(error_msg)
                                    telemetry.set_user_fault(error_msg)
                                self.exit(2)
                        else:
                            error_msg = "The command requires the latest version of extension {ext_name}. " \
                                "To install, run 'az extension add --upgrade -n {ext_name}'.".format(
                                    ext_name=ext_name) if not error_msg else error_msg
                if not error_msg:
                    # parser has no `command_source`, value is part of command itself
                    error_msg = "'{value}' is misspelled or not recognized by the system.".format(
                        value=value)
                az_error = CommandNotFoundError(error_msg)
                if not caused_by_extension_not_installed:
                    candidates = difflib.get_close_matches(value,
                                                           action.choices,
                                                           cutoff=0.7)
                    if candidates:
                        # use the most likely candidate to replace the misspelled command
                        args_inferred = [
                            item if item != value else candidates[0]
                            for item in args
                        ]
                        command_name_inferred = ' '.join(args_inferred).split(
                            '-')[0]

            else:
                # `command_source` indicates command values have been parsed, value is an argument
                parameter = action.option_strings[
                    0] if action.option_strings else action.dest
                error_msg = "{prog}: '{value}' is not a valid value for '{param}'.".format(
                    prog=self.prog, value=value, param=parameter)
                candidates = difflib.get_close_matches(value,
                                                       action.choices,
                                                       cutoff=0.7)
                az_error = InvalidArgumentValueError(error_msg)

            command_arguments = self._get_failure_recovery_arguments(action)
            if candidates:
                az_error.set_recommendation("Did you mean '{}' ?".format(
                    candidates[0]))

            # recommend a command for user
            if not caused_by_extension_not_installed:
                recommender = CommandRecommender(*command_arguments, error_msg,
                                                 cli_ctx)
                recommender.set_help_examples(
                    self.get_examples(command_name_inferred))
                recommendations = recommender.provide_recommendations()
                if recommendations:
                    az_error.set_aladdin_recommendation(recommendations)

                # remind user to check extensions if we can not find a command to recommend
                if isinstance(az_error, CommandNotFoundError) \
                        and not az_error.recommendations and self.prog == 'az' \
                        and use_dynamic_install == 'no':
                    az_error.set_recommendation(EXTENSION_REFERENCE)

            az_error.print_error()
            az_error.send_telemetry()

            self.exit(2)
 def test_add_extension_invalid(self):
     with self.assertRaises(ValueError):
         add_extension(cmd=self.cmd, source=MY_BAD_EXT_SOURCE)
     actual = list_extensions()
     self.assertEqual(len(actual), 0)
 def test_add_extension_twice(self):
     add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
     num_exts = len(list_extensions())
     self.assertEqual(num_exts, 1)
     with self.assertRaises(CLIError):
         add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
 def test_add_same_extension_user_system(self):
     add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
     num_exts = len(list_extensions())
     self.assertEqual(num_exts, 1)
     with self.assertRaises(CLIError):
         add_extension(cmd=self.cmd, source=MY_EXT_SOURCE, system=True)
 def test_add_extension_valid_whl_name_filenotfound(self):
     with self.assertRaises(CLIError):
         add_extension(cmd=self.cmd, source=_get_test_data_file('mywheel-0.0.3+dev-py2.py3-none-any.whl'))
     actual = list_extensions()
     self.assertEqual(len(actual), 0)
 def test_add_extension_invalid_whl_name(self):
     with self.assertRaises(CLIError):
         add_extension(cmd=self.cmd, source=os.path.join('invalid', 'ext', 'path', 'file.whl'))
     actual = list_extensions()
     self.assertEqual(len(actual), 0)
 def test_add_extension_invalid(self):
     with self.assertRaises(ValueError):
         add_extension(cmd=self.cmd, source=MY_BAD_EXT_SOURCE)
     actual = list_extensions()
     self.assertEqual(len(actual), 0)
 def test_add_extension_twice(self):
     add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
     num_exts = len(list_extensions())
     self.assertEqual(num_exts, 1)
     with self.assertRaises(CLIError):
         add_extension(cmd=self.cmd, source=MY_EXT_SOURCE)
 def test_add_extension_with_name_source_not_whl(self):
     extension_name = 'myextension'
     with mock.patch('azure.cli.core.extension.operations.resolve_from_index', return_value=('{}.notwhl'.format(extension_name), None)):
         with self.assertRaises(ValueError) as err:
             add_extension(cmd=self.cmd, extension_name=extension_name)
         self.assertTrue('Unknown extension type. Only Python wheels are supported.' in str(err.exception))
Exemple #25
0
def add_extension_cmd(source=None, extension_name=None, index_url=None, yes=None,
                      pip_extra_index_urls=None, pip_proxy=None):
    return add_extension(source=source, extension_name=extension_name, index_url=index_url, yes=yes,
                         pip_extra_index_urls=pip_extra_index_urls, pip_proxy=pip_proxy)