def test_case_insensitive_command_path(self):
        import argparse

        def handler(args):
            return 'PASSED'

        command = CliCommand('test command', handler)
        command.add_argument('var', '--var', '-v')
        cmd_table = {'test command': command}

        def _test(cmd_line):
            argv = cmd_line.split()
            config = Configuration()
            config.get_command_table = lambda argv: cmd_table
            application = Application(config)
            return application.execute(argv[1:])

        # case insensitive command paths
        result = _test('az TEST command --var blah')
        self.assertEqual(result.result, 'PASSED')

        result = _test('az test COMMAND --var blah')
        self.assertEqual(result.result, 'PASSED')

        result = _test('az test command -v blah')
        self.assertEqual(result.result, 'PASSED')

        # verify that long and short options remain case sensitive
        with self.assertRaises(SystemExit):
            _test('az test command --vAR blah')

        with self.assertRaises(SystemExit):
            _test('az test command -V blah')
Beispiel #2
0
    def test_help_full_documentations(self, _):
        app = Application(Configuration())

        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('foobar', '--foobar', '-fb', required=False)
        command.add_argument('foobar2', '--foobar2', '-fb2', required=True)
        command.help = """
                short-summary: this module does xyz one-line or so
                long-summary: |
                    this module.... kjsdflkj... klsfkj paragraph1
                    this module.... kjsdflkj... klsfkj paragraph2
                parameters:
                    - name: --foobar -fb
                      type: string
                      required: false
                      short-summary: one line partial sentence
                      long-summary: text, markdown, etc.
                      populator-commands:
                        - az vm list
                        - default
                    - name: --foobar2 -fb2
                      type: string
                      required: true
                      short-summary: one line partial sentence
                      long-summary: paragraph(s)
                examples:
                    - name: foo example
                      text: example details
            """
        cmd_table = {'n1': command}

        config = Configuration()
        config.get_command_table = lambda args: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())
        s = """
Command
    az n1: This module does xyz one-line or so.
        This module.... kjsdflkj... klsfkj paragraph1
        this module.... kjsdflkj... klsfkj paragraph2.

Arguments
    --foobar2 -fb2 [Required]: One line partial sentence.
        Paragraph(s).
    --foobar -fb             : One line partial sentence.  Values from: az vm list, default.
        Text, markdown, etc.

Global Arguments
    --help -h                : Show this help message and exit.

Examples
    foo example
        example details
"""
        self.assertEqual(s, io.getvalue())
Beispiel #3
0
    def test_help_with_param_specified(self, _):
        app = Application(Configuration([]))
        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('arg', '--arg', '-a', required=False)
        command.add_argument('b', '-b', required=False)
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 --arg foo -h'.split())

        s = """
Command
    az n1

Arguments
    --arg -a
    -b

Global Arguments
    --help -h: Show this help message and exit.
"""

        self.assertEqual(s, io.getvalue())
Beispiel #4
0
    def test_case_insensitive_enum_choices(self):
        from enum import Enum

        class TestEnum(Enum):  # pylint: disable=too-few-public-methods

            opt1 = "ALL_CAPS"
            opt2 = "camelCase"
            opt3 = "snake_case"

        def test_handler():
            pass

        command = CliCommand('test command', test_handler)
        command.add_argument('opt', '--opt', required=True, **enum_choice_list(TestEnum))
        cmd_table = {'test command': command}

        parser = AzCliCommandParser()
        parser.load_command_table(cmd_table)

        args = parser.parse_args('test command --opt alL_cAps'.split())
        self.assertEqual(args.opt, 'ALL_CAPS')

        args = parser.parse_args('test command --opt CAMELCASE'.split())
        self.assertEqual(args.opt, 'camelCase')

        args = parser.parse_args('test command --opt sNake_CASE'.split())
        self.assertEqual(args.opt, 'snake_case')
Beispiel #5
0
    def test_help_global_params(self, mock_register_extensions, _):
        def register_globals(global_group):
            global_group.add_argument(
                "--query2",
                dest="_jmespath_query",
                metavar="JMESPATH",
                help="JMESPath query string. See http://jmespath.org/ " "for more information and examples.",
            )

        mock_register_extensions.return_value = None

        def _register_global_parser(appl):
            # noqa pylint: disable=protected-access
            appl._event_handlers[appl.GLOBAL_PARSER_CREATED].append(register_globals)

        mock_register_extensions.side_effect = _register_global_parser

        def test_handler():
            pass

        command = CliCommand("n1", test_handler)
        command.add_argument("arg", "--arg", "-a", required=False)
        command.add_argument("b", "-b", required=False)
        command.help = """
            long-summary: |
                line1
                line2
        """
        cmd_table = {"n1": command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute("n1 -h".split())

        s = """
Command
    az n1
        Line1
        line2.

Arguments
    --arg -a
    -b

Global Arguments
    --help -h: Show this help message and exit.
    --query2 : JMESPath query string. See http://jmespath.org/ for more information and examples.
"""

        self.assertEqual(s, io.getvalue())
Beispiel #6
0
    def test_help_group_children(self):
        app = Application(Configuration([]))
        def test_handler():
            pass
        def test_handler2():
            pass

        command = CliCommand('group1 group3 n1', test_handler)
        command.add_argument('foobar', '--foobar', '-fb', required=False)
        command.add_argument('foobar2', '--foobar2', '-fb2', required=True)

        command2 = CliCommand('group1 group2 n1', test_handler2)
        command2.add_argument('foobar', '--foobar', '-fb', required=False)
        command2.add_argument('foobar2', '--foobar2', '-fb2', required=True)

        cmd_table = {'group1 group3 n1': command, 'group1 group2 n1': command2}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('group1 -h'.split())
        s = '\nGroup\n    az group1\n\nSubgroups:\n    group2\n    group3\n\n'
        self.assertEqual(s, io.getvalue())
Beispiel #7
0
    def test_choice_list_with_ints(self):
        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('arg', '--arg', '-a', required=False, choices=[1, 2, 3])
        command.add_argument('b', '-b', required=False, choices=['a', 'b', 'c'])
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application()
        app.initialize(config)
        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())
Beispiel #8
0
    def test_choice_list_with_ints(self):
        def test_handler():
            pass

        command = CliCommand("n1", test_handler)
        command.add_argument("arg", "--arg", "-a", required=False, choices=[1, 2, 3])
        command.add_argument("b", "-b", required=False, choices=["a", "b", "c"])
        cmd_table = {"n1": command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application()
        app.initialize(config)
        with self.assertRaises(SystemExit):
            app.execute("n1 -h".split())
Beispiel #9
0
    def test_help_plain_short_description(self):
        def test_handler():
            pass

        command = CliCommand('n1', test_handler, description='the description')
        command.add_argument('arg', '--arg', '-a', required=False)
        command.add_argument('b', '-b', required=False)
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())
        self.assertEqual(True, 'n1: The description.' in io.getvalue())
Beispiel #10
0
    def test_help_plain_short_description(self):
        def test_handler():
            pass

        command = CliCommand("n1", test_handler, description="the description")
        command.add_argument("arg", "--arg", "-a", required=False)
        command.add_argument("b", "-b", required=False)
        cmd_table = {"n1": command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute("n1 -h".split())
        self.assertEqual(True, "n1: The description." in io.getvalue())
Beispiel #11
0
    def test_help_docstring_description_overrides_short_description(self):
        def test_handler():
            pass

        command = CliCommand('n1', test_handler, description='short description')
        command.add_argument('arg', '--arg', '-a', required=False)
        command.add_argument('b', '-b', required=False)
        command.help = 'short-summary: docstring summary'
        cmd_table = {'n1': command}

        config = Configuration()
        config.get_command_table = lambda args: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())
        self.assertEqual(True, 'n1: Docstring summary.' in io.getvalue())
Beispiel #12
0
    def test_help_long_description_and_short_description(self):
        def test_handler():
            pass

        command = CliCommand('n1', test_handler, description='short description')
        command.add_argument('arg', '--arg', '-a', required=False)
        command.add_argument('b', '-b', required=False)
        command.help = 'long description'
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())
        self.assertEqual(True, io.getvalue().startswith('\nCommand\n    az n1: Short description.\n        Long description.')) # pylint: disable=line-too-long
Beispiel #13
0
    def test_required_parameter(self):
        def test_handler(args): # pylint: disable=unused-argument
            pass

        command = CliCommand('test command', test_handler)
        command.add_argument('req', '--req', required=True)
        cmd_table = {'test command': command}

        parser = AzCliCommandParser()
        parser.load_command_table(cmd_table)

        args = parser.parse_args('test command --req yep'.split())
        self.assertIs(args.func, test_handler)

        AzCliCommandParser.error = VerifyError(self)
        parser.parse_args('test command'.split())
        self.assertTrue(AzCliCommandParser.error.called)
Beispiel #14
0
    def test_help_global_params(self, mock_register_extensions, _):
        def register_globals(global_group):
            global_group.add_argument('--query2', dest='_jmespath_query', metavar='JMESPATH',
                                      help='JMESPath query string. See http://jmespath.org/ '
                                      'for more information and examples.')

        mock_register_extensions.return_value = None
        mock_register_extensions.side_effect = lambda app: \
            app._event_handlers[app.GLOBAL_PARSER_CREATED].append(register_globals) # pylint: disable=protected-access

        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('arg', '--arg', '-a', required=False)
        command.add_argument('b', '-b', required=False)
        command.help = """
            long-summary: |
                line1
                line2
        """
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())

        s = """
Command
    az n1
        Line1
        line2.

Arguments
    --arg -a
    -b

Global Arguments
    --help -h: Show this help message and exit.
    --query2 : JMESPath query string. See http://jmespath.org/ for more information and examples.
"""

        self.assertEqual(s, io.getvalue())
Beispiel #15
0
    def test_nargs_parameter(self):
        def test_handler():
            pass

        command = CliCommand('test command', test_handler)
        command.add_argument('req', '--req', required=True, nargs=2)
        cmd_table = {'test command': command}

        parser = AzCliCommandParser()
        parser.load_command_table(cmd_table)

        args = parser.parse_args('test command --req yep nope'.split())
        self.assertIs(args.func, command)

        AzCliCommandParser.error = VerifyError(self)
        parser.parse_args('test command -req yep'.split())
        self.assertTrue(AzCliCommandParser.error.called)
Beispiel #16
0
    def test_help_param(self):
        def test_handler():
            pass

        command = CliCommand("n1", test_handler)
        command.add_argument("arg", "--arg", "-a", required=False)
        command.add_argument("b", "-b", required=False)
        cmd_table = {"n1": command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application()
        app.initialize(config)
        with self.assertRaises(SystemExit):
            app.execute("n1 -h".split())

        with self.assertRaises(SystemExit):
            app.execute("n1 --help".split())
Beispiel #17
0
    def test_help_param(self):
        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('arg', '--arg', '-a', required=False)
        command.add_argument('b', '-b', required=False)
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application()
        app.initialize(config)
        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())

        with self.assertRaises(SystemExit):
            app.execute('n1 --help'.split())
Beispiel #18
0
    def test_help_long_description_and_short_description(self):
        def test_handler():
            pass

        command = CliCommand("n1", test_handler, description="short description")
        command.add_argument("arg", "--arg", "-a", required=False)
        command.add_argument("b", "-b", required=False)
        command.help = "long description"
        cmd_table = {"n1": command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute("n1 -h".split())
        self.assertEqual(
            True, io.getvalue().startswith("\nCommand\n    az n1: Short description.\n        Long description.")
        )  # pylint: disable=line-too-long
Beispiel #19
0
    def test_help_long_description_and_short_description(self):
        def test_handler():
            pass

        command = CliCommand('n1',
                             test_handler,
                             description='short description')
        command.add_argument('arg', '--arg', '-a', required=False)
        command.add_argument('b', '-b', required=False)
        command.help = 'long description'
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())
        self.assertEqual(True, io.getvalue().startswith('\nCommand\n    az n1: Short description.\n        Long description.'))  # pylint: disable=line-too-long
    def test_list_value_parameter(self):
        hellos = []

        def handler(args):
            hellos.append(args)

        command = CliCommand('test command', handler)
        command.add_argument('hello', '--hello', nargs='+', action=IterateAction)
        command.add_argument('something', '--something')
        cmd_table = {'test command': command}

        argv = 'az test command --hello world sir --something else'.split()
        config = Configuration()
        config.get_command_table = lambda argv: cmd_table
        application = Application(config)
        application.execute(argv[1:])

        self.assertEqual(2, len(hellos))
        self.assertEqual(hellos[0]['hello'], 'world')
        self.assertEqual(hellos[0]['something'], 'else')
        self.assertEqual(hellos[1]['hello'], 'sir')
        self.assertEqual(hellos[1]['something'], 'else')
Beispiel #21
0
    def test_help_long_description_multi_line(self):
        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('arg', '--arg', '-a', required=False)
        command.add_argument('b', '-b', required=False)
        command.help = """
            long-summary: |
                line1
                line2
            """
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())

        self.assertEqual(True, io.getvalue().startswith('\nCommand\n    az n1\n        Line1\n        line2.')) # pylint: disable=line-too-long
Beispiel #22
0
    def test_list_value_parameter(self):
        hellos = []

        def handler(args):
            hellos.append(args)

        command = CliCommand('test command', handler)
        command.add_argument('hello', '--hello', nargs='+', action=IterateAction)
        command.add_argument('something', '--something')
        cmd_table = {'test command': command}

        argv = 'az test command --hello world sir --something else'.split()
        config = Configuration(argv)
        config.get_command_table = lambda: cmd_table
        application = Application(config)
        application.execute(argv[1:])

        self.assertEqual(2, len(hellos))
        self.assertEqual(hellos[0]['hello'], 'world')
        self.assertEqual(hellos[0]['something'], 'else')
        self.assertEqual(hellos[1]['hello'], 'sir')
        self.assertEqual(hellos[1]['something'], 'else')
Beispiel #23
0
    def test_help_long_description_multi_line(self):
        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('arg', '--arg', '-a', required=False)
        command.add_argument('b', '-b', required=False)
        command.help = """
            long-summary: |
                line1
                line2
            """
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())

        self.assertEqual(True, io.getvalue().startswith('\nCommand\n    az n1\n        Line1\n        line2.')) # pylint: disable=line-too-long
Beispiel #24
0
    def test_help_extra_missing_params(self):
        app = Application(Configuration([]))

        def test_handler(foobar2, foobar=None):  # pylint: disable=unused-argument
            pass

        command = CliCommand("n1", test_handler)
        command.add_argument("foobar", "--foobar", "-fb", required=False)
        command.add_argument("foobar2", "--foobar2", "-fb2", required=True)
        cmd_table = {"n1": command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        # work around an argparse behavior where output is not printed and SystemExit
        # is not raised on Python 2.7.9
        if sys.version_info < (2, 7, 10):
            try:
                app.execute("n1 -fb a --foobar value".split())
            except SystemExit:
                pass

            try:
                app.execute("n1 -fb a --foobar2 value --foobar3 extra".split())
            except SystemExit:
                pass
        else:
            with self.assertRaises(SystemExit):
                app.execute("n1 -fb a --foobar value".split())
            with self.assertRaises(SystemExit):
                app.execute("n1 -fb a --foobar2 value --foobar3 extra".split())

            self.assertTrue(
                "required" in io.getvalue()
                and "--foobar/-fb" not in io.getvalue()
                and "--foobar2/-fb2" in io.getvalue()
                and "unrecognized arguments: --foobar3 extra" in io.getvalue()
            )
Beispiel #25
0
    def test_choice_list_with_ints(self):
        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('arg',
                             '--arg',
                             '-a',
                             required=False,
                             choices=[1, 2, 3])
        command.add_argument('b',
                             '-b',
                             required=False,
                             choices=['a', 'b', 'c'])
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application()
        app.initialize(config)
        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())
Beispiel #26
0
    def test_help_extra_missing_params(self):
        app = Application(Configuration([]))

        def test_handler(foobar2, foobar=None):  # pylint: disable=unused-argument
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('foobar', '--foobar', '-fb', required=False)
        command.add_argument('foobar2', '--foobar2', '-fb2', required=True)
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        # work around an argparse behavior where output is not printed and SystemExit
        # is not raised on Python 2.7.9
        if sys.version_info < (2, 7, 10):
            try:
                app.execute('n1 -fb a --foobar value'.split())
            except SystemExit:
                pass

            try:
                app.execute('n1 -fb a --foobar2 value --foobar3 extra'.split())
            except SystemExit:
                pass
        else:
            with self.assertRaises(SystemExit):
                app.execute('n1 -fb a --foobar value'.split())
            with self.assertRaises(SystemExit):
                app.execute('n1 -fb a --foobar2 value --foobar3 extra'.split())

            self.assertTrue(
                'required' in io.getvalue()
                and '--foobar/-fb' not in io.getvalue()
                and '--foobar2/-fb2' in io.getvalue()
                and 'unrecognized arguments: --foobar3 extra' in io.getvalue())
Beispiel #27
0
    def test_help_params_documentations(self, _):
        app = Application(Configuration([]))

        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('foobar', '--foobar', '-fb', required=False)
        command.add_argument('foobar2', '--foobar2', '-fb2', required=True)
        command.add_argument('foobar3',
                             '--foobar3',
                             '-fb3',
                             required=False,
                             help='the foobar3')
        command.help = """
            parameters:
                - name: --foobar -fb
                  type: string
                  required: false
                  short-summary: one line partial sentence
                  long-summary: text, markdown, etc.
                  populator-commands:
                    - az vm list
                    - default
                - name: --foobar2 -fb2
                  type: string
                  required: true
                  short-summary: one line partial sentence
                  long-summary: paragraph(s)
            """
        cmd_table = {'n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())
        s = """
Command
    az n1

Arguments
    --foobar2 -fb2 [Required]: One line partial sentence.
        Paragraph(s).
    --foobar -fb             : One line partial sentence.  Values from: az vm list, default.
        Text, markdown, etc.
    --foobar3 -fb3           : The foobar3.

Global Arguments
    --help -h                : Show this help message and exit.
"""
        self.assertEqual(s, io.getvalue())
Beispiel #28
0
    def test_help_params_documentations(self, _):
        app = Application(Configuration())

        def test_handler():
            pass

        command = CliCommand('n1', test_handler)
        command.add_argument('foobar', '--foobar', '-fb', required=False)
        command.add_argument('foobar2', '--foobar2', '-fb2', required=True)
        command.add_argument('foobar3', '--foobar3', '-fb3', required=False, help='the foobar3')
        command.help = """
            parameters:
                - name: --foobar -fb
                  type: string
                  required: false
                  short-summary: one line partial sentence
                  long-summary: text, markdown, etc.
                  populator-commands:
                    - az vm list
                    - default
                - name: --foobar2 -fb2
                  type: string
                  required: true
                  short-summary: one line partial sentence
                  long-summary: paragraph(s)
            """
        cmd_table = {'n1': command}

        config = Configuration()
        config.get_command_table = lambda argv: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('n1 -h'.split())
        s = """
Command
    az n1

Arguments
    --foobar2 -fb2 [Required]: One line partial sentence.
        Paragraph(s).
    --foobar -fb             : One line partial sentence.  Values from: az vm list, default.
        Text, markdown, etc.
    --foobar3 -fb3           : The foobar3.

Global Arguments
    --help -h                : Show this help message and exit.
"""
        self.assertEqual(s, io.getvalue())
def cli_generic_wait_command(module_name, name, getter_op, factory=None):

    if not isinstance(getter_op, string_types):
        raise ValueError("Getter operation must be a string. Got '{}'".format(type(getter_op)))

    def get_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(getter_op)))

    def arguments_loader():
        arguments = {}
        arguments.update(get_arguments_loader())
        return arguments

    def get_provisioning_state(instance):
        provisioning_state = getattr(instance, 'provisioning_state', None)
        if not provisioning_state:
            # some SDK, like resource-group, has 'provisioning_state' under 'properties'
            properties = getattr(instance, 'properties', None)
            if properties:
                provisioning_state = getattr(properties, 'provisioning_state', None)
        return provisioning_state

    def handler(args):
        from msrest.exceptions import ClientException
        import time
        try:
            client = factory() if factory else None
        except TypeError:
            client = factory(None) if factory else None

        getterargs = {key: val for key, val in args.items()
                      if key in get_arguments_loader()}

        getter = get_op_handler(getter_op)

        timeout = args.pop('timeout')
        interval = args.pop('interval')
        wait_for_created = args.pop('created')
        wait_for_deleted = args.pop('deleted')
        wait_for_updated = args.pop('updated')
        wait_for_exists = args.pop('exists')
        custom_condition = args.pop('custom')
        if not any([wait_for_created, wait_for_updated, wait_for_deleted,
                    wait_for_exists, custom_condition]):
            raise CLIError(
                "incorrect usage: --created | --updated | --deleted | --exists | --custom JMESPATH")  # pylint: disable=line-too-long

        for _ in range(0, timeout, interval):
            try:
                instance = getter(client, **getterargs) if client else getter(**getterargs)
                if wait_for_exists:
                    return
                provisioning_state = get_provisioning_state(instance)
                # until we have any needs to wait for 'Failed', let us bail out on this
                if provisioning_state == 'Failed':
                    raise CLIError('The operation failed')
                if wait_for_created or wait_for_updated:
                    if provisioning_state == 'Succeeded':
                        return
                if custom_condition and bool(verify_property(instance, custom_condition)):
                    return
            except ClientException as ex:
                if getattr(ex, 'status_code', None) == 404:
                    if wait_for_deleted:
                        return
                    if not any([wait_for_created, wait_for_exists, custom_condition]):
                        raise
                else:
                    raise

            time.sleep(interval)

        return CLIError('Wait operation timed-out after {} seconds'.format(timeout))

    cmd = CliCommand(name, handler, arguments_loader=arguments_loader)
    group_name = 'Wait Condition'
    cmd.add_argument('timeout', '--timeout', default=3600, arg_group=group_name, type=int,
                     help='maximum wait in seconds')
    cmd.add_argument('interval', '--interval', default=30, arg_group=group_name, type=int,
                     help='polling interval in seconds')
    cmd.add_argument('deleted', '--deleted', action='store_true', arg_group=group_name,
                     help='wait till deleted')
    cmd.add_argument('created', '--created', action='store_true', arg_group=group_name,
                     help="wait till created with 'provisioningState' at 'Succeeded'")
    cmd.add_argument('updated', '--updated', action='store_true', arg_group=group_name,
                     help="wait till updated with provisioningState at 'Succeeded'")
    cmd.add_argument('exists', '--exists', action='store_true', arg_group=group_name,
                     help="wait till the resource exists")
    cmd.add_argument('custom', '--custom', arg_group=group_name,
                     help=("Wait until the condition satisfies a custom JMESPath query. E.g. "
                           "provisioningState!='InProgress', "
                           "instanceView.statuses[?code=='PowerState/running']"))
    main_command_table[name] = cmd
    main_command_module_map[name] = module_name
def cli_generic_update_command(module_name, name, getter_op, setter_op, factory=None,
                               setter_arg_name='parameters', table_transformer=None,
                               child_collection_prop_name=None, child_collection_key='name',
                               child_arg_name='item_name', custom_function_op=None,
                               no_wait_param=None, transform=None):
    if not isinstance(getter_op, string_types):
        raise ValueError("Getter operation must be a string. Got '{}'".format(getter_op))
    if not isinstance(setter_op, string_types):
        raise ValueError("Setter operation must be a string. Got '{}'".format(setter_op))
    if custom_function_op and not isinstance(custom_function_op, string_types):
        raise ValueError("Custom function operation must be a string. Got '{}'".format(
            custom_function_op))

    def get_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(getter_op)))

    def set_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(setter_op),
                                                no_wait_param=no_wait_param))

    def function_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(custom_function_op))) \
            if custom_function_op else {}

    def arguments_loader():
        arguments = {}
        arguments.update(set_arguments_loader())
        arguments.update(get_arguments_loader())
        arguments.update(function_arguments_loader())
        arguments.pop('instance', None)  # inherited from custom_function(instance, ...)
        arguments.pop('parent', None)
        arguments.pop('expand', None)  # possibly inherited from the getter
        arguments.pop(setter_arg_name, None)
        return arguments

    def handler(args):  # pylint: disable=too-many-branches,too-many-statements
        from msrestazure.azure_operation import AzureOperationPoller

        ordered_arguments = args.pop('ordered_arguments', [])
        for item in ['properties_to_add', 'properties_to_set', 'properties_to_remove']:
            if args[item]:
                raise CLIError("Unexpected '{}' was not empty.".format(item))
            del args[item]

        try:
            client = factory() if factory else None
        except TypeError:
            client = factory(None) if factory else None

        getterargs = {key: val for key, val in args.items() if key in get_arguments_loader()}
        getter = get_op_handler(getter_op)
        if child_collection_prop_name:
            parent = getter(client, **getterargs) if client else getter(**getterargs)
            instance = _get_child(
                parent,
                child_collection_prop_name,
                args.get(child_arg_name),
                child_collection_key
            )
        else:
            parent = None
            instance = getter(client, **getterargs) if client else getter(**getterargs)

        # pass instance to the custom_function, if provided
        if custom_function_op:
            custom_function = get_op_handler(custom_function_op)
            custom_func_args = {k: v for k, v in args.items() if k in function_arguments_loader()}
            if child_collection_prop_name:
                parent = custom_function(instance, parent, **custom_func_args)
            else:
                instance = custom_function(instance, **custom_func_args)

        # apply generic updates after custom updates
        setterargs = {key: val for key, val in args.items() if key in set_arguments_loader()}

        for arg in ordered_arguments:
            arg_type, arg_values = arg
            if arg_type == '--set':
                try:
                    for expression in arg_values:
                        set_properties(instance, expression)
                except ValueError:
                    raise CLIError('invalid syntax: {}'.format(set_usage))
            elif arg_type == '--add':
                try:
                    add_properties(instance, arg_values)
                except ValueError:
                    raise CLIError('invalid syntax: {}'.format(add_usage))
            elif arg_type == '--remove':
                try:
                    remove_properties(instance, arg_values)
                except ValueError:
                    raise CLIError('invalid syntax: {}'.format(remove_usage))

        # Done... update the instance!
        setterargs[setter_arg_name] = parent if child_collection_prop_name else instance
        setter = get_op_handler(setter_op)

        opres = setter(client, **setterargs) if client else setter(**setterargs)

        if setterargs.get(no_wait_param, None):
            return None

        result = opres.result() if isinstance(opres, AzureOperationPoller) else opres
        if child_collection_prop_name:
            result = _get_child(
                result,
                child_collection_prop_name,
                args.get(child_arg_name),
                child_collection_key
            )

        # apply results transform if specified
        if transform:
            return transform(result)

        return result

    class OrderedArgsAction(argparse.Action):  # pylint:disable=too-few-public-methods

        def __call__(self, parser, namespace, values, option_string=None):
            if not getattr(namespace, 'ordered_arguments', None):
                setattr(namespace, 'ordered_arguments', [])
            namespace.ordered_arguments.append((option_string, values))

    cmd = CliCommand(name, handler, table_transformer=table_transformer,
                     arguments_loader=arguments_loader)
    group_name = 'Generic Update'
    cmd.add_argument('properties_to_set', '--set', nargs='+', action=OrderedArgsAction, default=[],
                     help='Update an object by specifying a property path and value to set.'
                     '  Example: {}'.format(set_usage),
                     metavar='KEY=VALUE', arg_group=group_name)
    cmd.add_argument('properties_to_add', '--add', nargs='+', action=OrderedArgsAction, default=[],
                     help='Add an object to a list of objects by specifying a path and key'
                     ' value pairs.  Example: {}'.format(add_usage),
                     metavar='LIST KEY=VALUE', arg_group=group_name)
    cmd.add_argument('properties_to_remove', '--remove', nargs='+', action=OrderedArgsAction,
                     default=[], help='Remove a property or an element from a list.  Example: '
                     '{}'.format(remove_usage), metavar='LIST INDEX',
                     arg_group=group_name)
    main_command_table[name] = cmd
    main_command_module_map[name] = module_name
Beispiel #31
0
def cli_generic_wait_command(module_name,
                             name,
                             getter_op,
                             factory=None,
                             exception_handler=None):

    if not isinstance(getter_op, string_types):
        raise ValueError("Getter operation must be a string. Got '{}'".format(
            type(getter_op)))

    def get_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(getter_op)))

    def arguments_loader():
        arguments = {}
        arguments.update(get_arguments_loader())
        return arguments

    def get_provisioning_state(instance):
        provisioning_state = getattr(instance, 'provisioning_state', None)
        if not provisioning_state:
            # some SDK, like resource-group, has 'provisioning_state' under 'properties'
            properties = getattr(instance, 'properties', None)
            if properties:
                provisioning_state = getattr(properties, 'provisioning_state',
                                             None)
        return provisioning_state

    def _handle_exception(ex):
        if exception_handler:
            return exception_handler(ex)
        else:
            raise ex

    def handler(args):
        from msrest.exceptions import ClientException
        import time
        try:
            client = factory() if factory else None
        except TypeError:
            client = factory(None) if factory else None

        getterargs = {
            key: val
            for key, val in args.items() if key in get_arguments_loader()
        }

        getter = get_op_handler(getter_op)

        timeout = args.pop('timeout')
        interval = args.pop('interval')
        wait_for_created = args.pop('created')
        wait_for_deleted = args.pop('deleted')
        wait_for_updated = args.pop('updated')
        wait_for_exists = args.pop('exists')
        custom_condition = args.pop('custom')
        if not any([
                wait_for_created, wait_for_updated, wait_for_deleted,
                wait_for_exists, custom_condition
        ]):
            raise CLIError(
                "incorrect usage: --created | --updated | --deleted | --exists | --custom JMESPATH"
            )

        for _ in range(0, timeout, interval):
            try:
                instance = getter(client, **getterargs) if client else getter(
                    **getterargs)
                if wait_for_exists:
                    return
                provisioning_state = get_provisioning_state(instance)
                # until we have any needs to wait for 'Failed', let us bail out on this
                if provisioning_state == 'Failed':
                    raise CLIError('The operation failed')
                if wait_for_created or wait_for_updated:
                    if provisioning_state == 'Succeeded':
                        return
                if custom_condition and bool(
                        verify_property(instance, custom_condition)):
                    return
            except ClientException as ex:
                if getattr(ex, 'status_code', None) == 404:
                    if wait_for_deleted:
                        return
                    if not any(
                        [wait_for_created, wait_for_exists, custom_condition]):
                        _handle_exception(ex)
                else:
                    _handle_exception(ex)
            except Exception as ex:  # pylint: disable=broad-except
                _handle_exception(ex)

            time.sleep(interval)

        return CLIError(
            'Wait operation timed-out after {} seconds'.format(timeout))

    cmd = CliCommand(name, handler, arguments_loader=arguments_loader)
    group_name = 'Wait Condition'
    cmd.add_argument('timeout',
                     '--timeout',
                     default=3600,
                     arg_group=group_name,
                     type=int,
                     help='maximum wait in seconds')
    cmd.add_argument('interval',
                     '--interval',
                     default=30,
                     arg_group=group_name,
                     type=int,
                     help='polling interval in seconds')
    cmd.add_argument('deleted',
                     '--deleted',
                     action='store_true',
                     arg_group=group_name,
                     help='wait till deleted')
    cmd.add_argument(
        'created',
        '--created',
        action='store_true',
        arg_group=group_name,
        help="wait till created with 'provisioningState' at 'Succeeded'")
    cmd.add_argument(
        'updated',
        '--updated',
        action='store_true',
        arg_group=group_name,
        help="wait till updated with provisioningState at 'Succeeded'")
    cmd.add_argument('exists',
                     '--exists',
                     action='store_true',
                     arg_group=group_name,
                     help="wait till the resource exists")
    cmd.add_argument(
        'custom',
        '--custom',
        arg_group=group_name,
        help=(
            "Wait until the condition satisfies a custom JMESPath query. E.g. "
            "provisioningState!='InProgress', "
            "instanceView.statuses[?code=='PowerState/running']"))
    main_command_table[name] = cmd
    main_command_module_map[name] = module_name
Beispiel #32
0
def cli_generic_update_command(module_name,
                               name,
                               getter_op,
                               setter_op,
                               factory=None,
                               setter_arg_name='parameters',
                               table_transformer=None,
                               child_collection_prop_name=None,
                               child_collection_key='name',
                               child_arg_name='item_name',
                               custom_function_op=None,
                               no_wait_param=None,
                               transform=None,
                               confirmation=None,
                               exception_handler=None,
                               formatter_class=None):
    if not isinstance(getter_op, string_types):
        raise ValueError(
            "Getter operation must be a string. Got '{}'".format(getter_op))
    if not isinstance(setter_op, string_types):
        raise ValueError(
            "Setter operation must be a string. Got '{}'".format(setter_op))
    if custom_function_op and not isinstance(custom_function_op, string_types):
        raise ValueError(
            "Custom function operation must be a string. Got '{}'".format(
                custom_function_op))

    def get_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(getter_op)))

    def set_arguments_loader():
        return dict(
            extract_args_from_signature(get_op_handler(setter_op),
                                        no_wait_param=no_wait_param))

    def function_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(custom_function_op))) \
            if custom_function_op else {}

    def arguments_loader():
        arguments = {}
        arguments.update(set_arguments_loader())
        arguments.update(get_arguments_loader())
        arguments.update(function_arguments_loader())
        arguments.pop('instance',
                      None)  # inherited from custom_function(instance, ...)
        arguments.pop('parent', None)
        arguments.pop('expand', None)  # possibly inherited from the getter
        arguments.pop(setter_arg_name, None)
        return arguments

    def handler(args):  # pylint: disable=too-many-branches,too-many-statements
        from msrestazure.azure_operation import AzureOperationPoller

        if confirmation \
            and not args.items().get(CONFIRM_PARAM_NAME) \
            and not az_config.getboolean('core', 'disable_confirm_prompt', fallback=False) \
                and not _user_confirmed(confirmation, args.items()):
            raise CLIError('Operation cancelled.')

        ordered_arguments = args.pop('ordered_arguments', [])
        for item in [
                'properties_to_add', 'properties_to_set',
                'properties_to_remove'
        ]:
            if args[item]:
                raise CLIError("Unexpected '{}' was not empty.".format(item))
            del args[item]

        try:
            client = factory() if factory else None
        except TypeError:
            client = factory(None) if factory else None

        getterargs = {
            key: val
            for key, val in args.items() if key in get_arguments_loader()
        }
        getter = get_op_handler(getter_op)
        try:
            if child_collection_prop_name:
                parent = getter(client, **getterargs) if client else getter(
                    **getterargs)
                instance = _get_child(parent, child_collection_prop_name,
                                      args.get(child_arg_name),
                                      child_collection_key)
            else:
                parent = None
                instance = getter(client, **getterargs) if client else getter(
                    **getterargs)

            # pass instance to the custom_function, if provided
            if custom_function_op:
                custom_function = get_op_handler(custom_function_op)
                custom_func_args = \
                    {k: v for k, v in args.items() if k in function_arguments_loader()}
                if child_collection_prop_name:
                    parent = custom_function(instance, parent,
                                             **custom_func_args)
                else:
                    instance = custom_function(instance, **custom_func_args)

            # apply generic updates after custom updates
            setterargs = {
                key: val
                for key, val in args.items() if key in set_arguments_loader()
            }

            for arg in ordered_arguments:
                arg_type, arg_values = arg
                if arg_type == '--set':
                    try:
                        for expression in arg_values:
                            set_properties(instance, expression)
                    except ValueError:
                        raise CLIError('invalid syntax: {}'.format(set_usage))
                elif arg_type == '--add':
                    try:
                        add_properties(instance, arg_values)
                    except ValueError:
                        raise CLIError('invalid syntax: {}'.format(add_usage))
                elif arg_type == '--remove':
                    try:
                        remove_properties(instance, arg_values)
                    except ValueError:
                        raise CLIError(
                            'invalid syntax: {}'.format(remove_usage))

            # Done... update the instance!
            setterargs[
                setter_arg_name] = parent if child_collection_prop_name else instance
            setter = get_op_handler(setter_op)

            opres = setter(client, **setterargs) if client else setter(
                **setterargs)

            if setterargs.get(no_wait_param, None):
                return None

            result = opres.result() if isinstance(
                opres, AzureOperationPoller) else opres
            if child_collection_prop_name:
                result = _get_child(result, child_collection_prop_name,
                                    args.get(child_arg_name),
                                    child_collection_key)
        except Exception as ex:  # pylint: disable=broad-except
            if exception_handler:
                result = exception_handler(ex)
            else:
                raise ex

        # apply results transform if specified
        if transform:
            return transform(result)

        return result

    class OrderedArgsAction(argparse.Action):  # pylint:disable=too-few-public-methods
        def __call__(self, parser, namespace, values, option_string=None):
            if not getattr(namespace, 'ordered_arguments', None):
                setattr(namespace, 'ordered_arguments', [])
            namespace.ordered_arguments.append((option_string, values))

    cmd = CliCommand(name,
                     handler,
                     table_transformer=table_transformer,
                     arguments_loader=arguments_loader,
                     formatter_class=formatter_class)
    group_name = 'Generic Update'
    cmd.add_argument(
        'properties_to_set',
        '--set',
        nargs='+',
        action=OrderedArgsAction,
        default=[],
        help='Update an object by specifying a property path and value to set.'
        '  Example: {}'.format(set_usage),
        metavar='KEY=VALUE',
        arg_group=group_name)
    cmd.add_argument(
        'properties_to_add',
        '--add',
        nargs='+',
        action=OrderedArgsAction,
        default=[],
        help='Add an object to a list of objects by specifying a path and key'
        ' value pairs.  Example: {}'.format(add_usage),
        metavar='LIST KEY=VALUE',
        arg_group=group_name)
    cmd.add_argument(
        'properties_to_remove',
        '--remove',
        nargs='+',
        action=OrderedArgsAction,
        default=[],
        help='Remove a property or an element from a list.  Example: '
        '{}'.format(remove_usage),
        metavar='LIST INDEX',
        arg_group=group_name)
    main_command_table[name] = cmd
    main_command_module_map[name] = module_name
Beispiel #33
0
    def test_help_group_help(self):
        app = Application(Configuration([]))

        def test_handler():
            pass

        azure.cli.core.help_files.helps['test_group1 test_group2'] = """
            type: group
            short-summary: this module does xyz one-line or so
            long-summary: |
                this module.... kjsdflkj... klsfkj paragraph1
                this module.... kjsdflkj... klsfkj paragraph2
            examples:
                - name: foo example
                  text: example details
            """

        command = CliCommand('test_group1 test_group2 n1', test_handler)
        command.add_argument('foobar', '--foobar', '-fb', required=False)
        command.add_argument('foobar2', '--foobar2', '-fb2', required=True)
        command.help = """
            short-summary: this module does xyz one-line or so
            long-summary: |
                this module.... kjsdflkj... klsfkj paragraph1
                this module.... kjsdflkj... klsfkj paragraph2
            parameters:
                - name: --foobar -fb
                  type: string
                  required: false
                  short-summary: one line partial sentence
                  long-summary: text, markdown, etc.
                  populator-commands:
                    - az vm list
                    - default
                - name: --foobar2 -fb2
                  type: string
                  required: true
                  short-summary: one line partial sentence
                  long-summary: paragraph(s)
            examples:
                - name: foo example
                  text: example details
        """
        cmd_table = {'test_group1 test_group2 n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('test_group1 test_group2 --help'.split())
        s = """
Group
    az test_group1 test_group2: This module does xyz one-line or so.
        This module.... kjsdflkj... klsfkj paragraph1
        this module.... kjsdflkj... klsfkj paragraph2.

Commands:
    n1: This module does xyz one-line or so.


Examples
    foo example
        example details
"""
        self.assertEqual(s, io.getvalue())

        del azure.cli.core.help_files.helps['test_group1 test_group2']
Beispiel #34
0
def cli_generic_update_command(name, getter, setter, factory=None, setter_arg_name='parameters', # pylint: disable=too-many-arguments
                               table_transformer=None, child_collection_prop_name=None,
                               child_collection_key='name', child_arg_name='item_name',
                               custom_function=None):

    get_arguments = dict(extract_args_from_signature(getter))
    set_arguments = dict(extract_args_from_signature(setter))
    function_arguments = dict(extract_args_from_signature(custom_function)) \
        if custom_function else None

    def handler(args):
        ordered_arguments = args.pop('ordered_arguments') if 'ordered_arguments' in args else []

        try:
            client = factory() if factory else None
        except TypeError:
            client = factory(None) if factory else None

        getterargs = {key: val for key, val in args.items()
                      if key in get_arguments}
        if child_collection_prop_name:
            parent = getter(client, **getterargs) if client else getter(**getterargs)
            instance = _get_child(
                parent,
                child_collection_prop_name,
                args.get(child_arg_name),
                child_collection_key
            )
        else:
            parent = None
            instance = getter(client, **getterargs) if client else getter(**getterargs)

        # pass instance to the custom_function, if provided
        if custom_function:
            custom_func_args = {k: v for k, v in args.items() if k in function_arguments}
            if child_collection_prop_name:
                parent = custom_function(instance, parent, **custom_func_args)
            else:
                instance = custom_function(instance, **custom_func_args)

        # apply generic updates after custom updates
        for k in args.copy().keys():
            if k in get_arguments or k in set_arguments \
                or k in ('properties_to_add', 'properties_to_remove', 'properties_to_set'):
                args.pop(k)
        for key, val in args.items():
            ordered_arguments.append((key, val))

        for arg in ordered_arguments:
            arg_type, arg_values = arg
            if arg_type == '--set':
                try:
                    for expression in arg_values:
                        set_properties(instance, expression)
                except ValueError:
                    raise CLIError('invalid syntax: {}'.format(set_usage))
            elif arg_type == '--add':
                try:
                    add_properties(instance, arg_values)
                except ValueError:
                    raise CLIError('invalid syntax: {}'.format(add_usage))
            elif arg_type == '--remove':
                try:
                    remove_properties(instance, arg_values)
                except ValueError:
                    raise CLIError('invalid syntax: {}'.format(remove_usage))

        # Done... update the instance!
        getterargs[setter_arg_name] = parent if child_collection_prop_name else instance
        opres = setter(client, **getterargs) if client else setter(**getterargs)
        result = opres.result() if isinstance(opres, AzureOperationPoller) else opres
        if child_collection_prop_name:
            return _get_child(
                result,
                child_collection_prop_name,
                args.get(child_arg_name),
                child_collection_key
            )
        else:
            return result

    class OrderedArgsAction(argparse.Action): #pylint:disable=too-few-public-methods
        def __call__(self, parser, namespace, values, option_string=None):
            if not getattr(namespace, 'ordered_arguments', None):
                setattr(namespace, 'ordered_arguments', [])
            namespace.ordered_arguments.append((option_string, values))

    cmd = CliCommand(name, handler, table_transformer=table_transformer)
    cmd.arguments.update(set_arguments)
    cmd.arguments.update(get_arguments)
    if function_arguments:
        cmd.arguments.update(function_arguments)
    cmd.arguments.pop('instance', None) # inherited from custom_function(instance, ...)
    cmd.arguments.pop('parent', None)
    cmd.arguments.pop('expand', None) # possibly inherited from the getter
    cmd.arguments.pop(setter_arg_name, None)
    group_name = 'Generic Update'
    cmd.add_argument('properties_to_set', '--set', nargs='+', action=OrderedArgsAction, default=[],
                     help='Update an object by specifying a property path and value to set.'
                     '  Example: {}'.format(set_usage),
                     metavar='KEY=VALUE', arg_group=group_name)
    cmd.add_argument('properties_to_add', '--add', nargs='+', action=OrderedArgsAction, default=[],
                     help='Add an object to a list of objects by specifying a path and key'
                     ' value pairs.  Example: {}'.format(add_usage),
                     metavar='LIST KEY=VALUE', arg_group=group_name)
    cmd.add_argument('properties_to_remove', '--remove', nargs='+', action=OrderedArgsAction,
                     default=[], help='Remove a property or an element from a list.  Example: '
                     '{}'.format(remove_usage), metavar='LIST INDEX',
                     arg_group=group_name)
    main_command_table[name] = cmd
Beispiel #35
0
    def test_help_group_help(self):
        app = Application(Configuration([]))
        def test_handler():
            pass

        azure.cli.core.help_files.helps['test_group1 test_group2'] = """
            type: group
            short-summary: this module does xyz one-line or so
            long-summary: |
                this module.... kjsdflkj... klsfkj paragraph1
                this module.... kjsdflkj... klsfkj paragraph2
            examples:
                - name: foo example
                  text: example details
            """

        command = CliCommand('test_group1 test_group2 n1', test_handler)
        command.add_argument('foobar', '--foobar', '-fb', required=False)
        command.add_argument('foobar2', '--foobar2', '-fb2', required=True)
        command.help = """
            short-summary: this module does xyz one-line or so
            long-summary: |
                this module.... kjsdflkj... klsfkj paragraph1
                this module.... kjsdflkj... klsfkj paragraph2
            parameters: 
                - name: --foobar -fb
                  type: string
                  required: false
                  short-summary: one line partial sentence
                  long-summary: text, markdown, etc.
                  populator-commands: 
                    - az vm list
                    - default
                - name: --foobar2 -fb2
                  type: string
                  required: true
                  short-summary: one line partial sentence
                  long-summary: paragraph(s)
            examples:
                - name: foo example
                  text: example details        
        """
        cmd_table = {'test_group1 test_group2 n1': command}

        config = Configuration([])
        config.get_command_table = lambda: cmd_table
        app = Application(config)

        with self.assertRaises(SystemExit):
            app.execute('test_group1 test_group2 --help'.split())
        s = """
Group
    az test_group1 test_group2: This module does xyz one-line or so.
        This module.... kjsdflkj... klsfkj paragraph1
        this module.... kjsdflkj... klsfkj paragraph2.

Commands:
    n1: This module does xyz one-line or so.


Examples
    foo example
        example details
"""
        self.assertEqual(s, io.getvalue())

        del azure.cli.core.help_files.helps['test_group1 test_group2']
Beispiel #36
0
def cli_generic_update_command(
    module_name,
    name,
    getter_op,
    setter_op,
    factory=None,
    setter_arg_name="parameters",
    table_transformer=None,
    child_collection_prop_name=None,
    child_collection_key="name",
    child_arg_name="item_name",
    custom_function_op=None,
    no_wait_param=None,
    transform=None,
):
    if not isinstance(getter_op, string_types):
        raise ValueError("Getter operation must be a string. Got '{}'".format(getter_op))
    if not isinstance(setter_op, string_types):
        raise ValueError("Setter operation must be a string. Got '{}'".format(setter_op))
    if custom_function_op and not isinstance(custom_function_op, string_types):
        raise ValueError("Custom function operation must be a string. Got '{}'".format(custom_function_op))

    def get_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(getter_op)))

    def set_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(setter_op), no_wait_param=no_wait_param))

    def function_arguments_loader():
        return dict(extract_args_from_signature(get_op_handler(custom_function_op))) if custom_function_op else {}

    def arguments_loader():
        arguments = {}
        arguments.update(set_arguments_loader())
        arguments.update(get_arguments_loader())
        arguments.update(function_arguments_loader())
        arguments.pop("instance", None)  # inherited from custom_function(instance, ...)
        arguments.pop("parent", None)
        arguments.pop("expand", None)  # possibly inherited from the getter
        arguments.pop(setter_arg_name, None)
        return arguments

    def handler(args):  # pylint: disable=too-many-branches,too-many-statements
        from msrestazure.azure_operation import AzureOperationPoller

        ordered_arguments = args.pop("ordered_arguments") if "ordered_arguments" in args else []

        try:
            client = factory() if factory else None
        except TypeError:
            client = factory(None) if factory else None

        getterargs = {key: val for key, val in args.items() if key in get_arguments_loader()}
        getter = get_op_handler(getter_op)
        if child_collection_prop_name:
            parent = getter(client, **getterargs) if client else getter(**getterargs)
            instance = _get_child(parent, child_collection_prop_name, args.get(child_arg_name), child_collection_key)
        else:
            parent = None
            instance = getter(client, **getterargs) if client else getter(**getterargs)

        # pass instance to the custom_function, if provided
        if custom_function_op:
            custom_function = get_op_handler(custom_function_op)
            custom_func_args = {k: v for k, v in args.items() if k in function_arguments_loader()}
            if child_collection_prop_name:
                parent = custom_function(instance, parent, **custom_func_args)
            else:
                instance = custom_function(instance, **custom_func_args)

        # apply generic updates after custom updates
        setterargs = set_arguments_loader()
        for k in args.copy().keys():
            if (
                k in get_arguments_loader()
                or k in setterargs
                or k in ("properties_to_add", "properties_to_remove", "properties_to_set")
            ):
                args.pop(k)
        for key, val in args.items():
            ordered_arguments.append((key, val))

        for arg in ordered_arguments:
            arg_type, arg_values = arg
            if arg_type == "--set":
                try:
                    for expression in arg_values:
                        set_properties(instance, expression)
                except ValueError:
                    raise CLIError("invalid syntax: {}".format(set_usage))
            elif arg_type == "--add":
                try:
                    add_properties(instance, arg_values)
                except ValueError:
                    raise CLIError("invalid syntax: {}".format(add_usage))
            elif arg_type == "--remove":
                try:
                    remove_properties(instance, arg_values)
                except ValueError:
                    raise CLIError("invalid syntax: {}".format(remove_usage))

        # Done... update the instance!
        getterargs[setter_arg_name] = parent if child_collection_prop_name else instance
        setter = get_op_handler(setter_op)
        no_wait = no_wait_param and setterargs.get(no_wait_param, None)
        if no_wait:
            getterargs[no_wait_param] = True

        opres = setter(client, **getterargs) if client else setter(**getterargs)

        if no_wait:
            return None

        result = opres.result() if isinstance(opres, AzureOperationPoller) else opres
        if child_collection_prop_name:
            result = _get_child(result, child_collection_prop_name, args.get(child_arg_name), child_collection_key)

        # apply results transform if specified
        if transform:
            return transform(result)

        return result

    class OrderedArgsAction(argparse.Action):  # pylint:disable=too-few-public-methods
        def __call__(self, parser, namespace, values, option_string=None):
            if not getattr(namespace, "ordered_arguments", None):
                setattr(namespace, "ordered_arguments", [])
            namespace.ordered_arguments.append((option_string, values))

    cmd = CliCommand(name, handler, table_transformer=table_transformer, arguments_loader=arguments_loader)
    group_name = "Generic Update"
    cmd.add_argument(
        "properties_to_set",
        "--set",
        nargs="+",
        action=OrderedArgsAction,
        default=[],
        help="Update an object by specifying a property path and value to set." "  Example: {}".format(set_usage),
        metavar="KEY=VALUE",
        arg_group=group_name,
    )
    cmd.add_argument(
        "properties_to_add",
        "--add",
        nargs="+",
        action=OrderedArgsAction,
        default=[],
        help="Add an object to a list of objects by specifying a path and key"
        " value pairs.  Example: {}".format(add_usage),
        metavar="LIST KEY=VALUE",
        arg_group=group_name,
    )
    cmd.add_argument(
        "properties_to_remove",
        "--remove",
        nargs="+",
        action=OrderedArgsAction,
        default=[],
        help="Remove a property or an element from a list.  Example: " "{}".format(remove_usage),
        metavar="LIST INDEX",
        arg_group=group_name,
    )
    main_command_table[name] = cmd
    main_command_module_map[name] = module_name