Sophie

Sophie

distrib > Fedora > 18 > i386 > by-pkgid > 0305113317f9e80328b139dce3f45533 > files > 16

python-quantumclient-2.1-1.fc18.src.rpm

From 91734d2b87064879c3aab76de4f732e7f8d8f2b2 Mon Sep 17 00:00:00 2001
From: gongysh <gongysh@cn.ibm.com>
Date: Tue, 11 Dec 2012 23:40:16 +0800
Subject: [PATCH] Allow known options defined after position arguments.

We run the argument parser to split known options and unknown options.
Make '-' work and have the same effect as '_' in both known and unknown
option parts.
Make metavar Uppercase.

blueprint options-location

Change-Id: Ic27b278484133c8b83e3b031a0810a76b050219f
---
 quantumclient/quantum/v2_0/__init__.py             | 70 ++++++++++++++++------
 quantumclient/quantum/v2_0/floatingip.py           |  4 +-
 quantumclient/quantum/v2_0/network.py              |  2 +-
 quantumclient/quantum/v2_0/port.py                 |  2 +-
 quantumclient/quantum/v2_0/router.py               |  2 +-
 quantumclient/quantum/v2_0/subnet.py               |  8 +--
 quantumclient/shell.py                             | 40 +++++++++++++
 quantumclient/tests/unit/test_casual_args.py       |  2 +-
 quantumclient/tests/unit/test_cli20.py             |  5 +-
 quantumclient/tests/unit/test_cli20_floatingips.py |  4 +-
 quantumclient/tests/unit/test_cli20_subnet.py      | 61 +++++++++++++++++++
 11 files changed, 168 insertions(+), 32 deletions(-)

diff --git a/quantumclient/quantum/v2_0/__init__.py b/quantumclient/quantum/v2_0/__init__.py
index c73795b..5eae661 100644
--- a/quantumclient/quantum/v2_0/__init__.py
+++ b/quantumclient/quantum/v2_0/__init__.py
@@ -77,11 +77,17 @@ def add_show_list_common_argument(parser):
         action='store_true',
         help=argparse.SUPPRESS)
     parser.add_argument(
-        '-F', '--fields',
+        '--fields',
+        help=argparse.SUPPRESS,
+        action='append',
+        default=[])
+    parser.add_argument(
+        '-F', '--field',
+        dest='fields', metavar='FIELD',
         help='specify the field(s) to be returned by server,'
         ' can be repeated',
         action='append',
-        default=[], )
+        default=[])
 
 
 def add_extra_argument(parser, name, _help):
@@ -108,15 +114,16 @@ def parse_args_to_dict(values_specs):
 
     '''
     # -- is a pseudo argument
-    if values_specs and values_specs[0] == '--':
-        del values_specs[0]
+    values_specs_copy = values_specs[:]
+    if values_specs_copy and values_specs_copy[0] == '--':
+        del values_specs_copy[0]
     _options = {}
     current_arg = None
     _values_specs = []
     _value_number = 0
     _list_flag = False
     current_item = None
-    for _item in values_specs:
+    for _item in values_specs_copy:
         if _item.startswith('--'):
             if current_arg is not None:
                 if _value_number > 1 or _list_flag:
@@ -166,22 +173,49 @@ def parse_args_to_dict(values_specs):
             current_arg.update({'nargs': '+'})
         elif _value_number == 0:
             current_arg.update({'action': 'store_true'})
-    _parser = argparse.ArgumentParser(add_help=False)
-    for opt, optspec in _options.iteritems():
-        _parser.add_argument(opt, **optspec)
-    _args = _parser.parse_args(_values_specs)
+    _args = None
+    if _values_specs:
+        _parser = argparse.ArgumentParser(add_help=False)
+        for opt, optspec in _options.iteritems():
+            _parser.add_argument(opt, **optspec)
+        _args = _parser.parse_args(_values_specs)
     result_dict = {}
-    for opt in _options.iterkeys():
-        _opt = opt.split('--', 2)[1]
-        _value = getattr(_args, _opt.replace('-', '_'))
-        if _value is not None:
-            result_dict.update({_opt: _value})
+    if _args:
+        for opt in _options.iterkeys():
+            _opt = opt.split('--', 2)[1]
+            _opt = _opt.replace('-', '_')
+            _value = getattr(_args, _opt)
+            if _value is not None:
+                result_dict.update({_opt: _value})
     return result_dict
 
 
+def _merge_args(qCmd, parsed_args, _extra_values, value_specs):
+    """Merge arguments from _extra_values into parsed_args.
+
+    If an argument value are provided in both and it is a list,
+    the values in _extra_values will be merged into parsed_args.
+
+    @param parsed_args: the parsed args from known options
+    @param _extra_values: the other parsed arguments in unknown parts
+    @param values_specs: the unparsed unknown parts
+    """
+    temp_values = _extra_values.copy()
+    for key, value in temp_values.iteritems():
+        if hasattr(parsed_args, key):
+            arg_value = getattr(parsed_args, key)
+            if arg_value is not None and value is not None:
+                if isinstance(arg_value, list):
+                    if value and isinstance(value, list):
+                        if type(arg_value[0]) == type(value[0]):
+                            arg_value.extend(value)
+                            _extra_values.pop(key)
+
+
 class QuantumCommand(command.OpenStackCommand):
     api = 'network'
     log = logging.getLogger(__name__ + '.QuantumCommand')
+    values_specs = []
 
     def get_client(self):
         return self.app.client_manager.quantum
@@ -227,14 +261,12 @@ class CreateCommand(QuantumCommand, show.ShowOne):
     def get_parser(self, prog_name):
         parser = super(CreateCommand, self).get_parser(prog_name)
         parser.add_argument(
-            '--tenant-id', metavar='tenant-id',
+            '--tenant-id', metavar='TENANT_ID',
             help=_('the owner tenant ID'), )
         parser.add_argument(
             '--tenant_id',
             help=argparse.SUPPRESS)
         self.add_known_arguments(parser)
-        add_extra_argument(parser, 'value_specs',
-                           'new values for the %s' % self.resource)
         return parser
 
     def add_known_arguments(self, parser):
@@ -247,8 +279,10 @@ class CreateCommand(QuantumCommand, show.ShowOne):
         self.log.debug('get_data(%s)' % parsed_args)
         quantum_client = self.get_client()
         quantum_client.format = parsed_args.request_format
+        _extra_values = parse_args_to_dict(self.values_specs)
+        _merge_args(self, parsed_args, _extra_values,
+                    self.values_specs)
         body = self.args2body(parsed_args)
-        _extra_values = parse_args_to_dict(parsed_args.value_specs)
         body[self.resource].update(_extra_values)
         obj_creator = getattr(quantum_client,
                               "create_%s" % self.resource)
diff --git a/quantumclient/quantum/v2_0/floatingip.py b/quantumclient/quantum/v2_0/floatingip.py
index 5613af8..3198dfe 100644
--- a/quantumclient/quantum/v2_0/floatingip.py
+++ b/quantumclient/quantum/v2_0/floatingip.py
@@ -52,8 +52,8 @@ class CreateFloatingIP(CreateCommand):
 
     def add_known_arguments(self, parser):
         parser.add_argument(
-            'floating_network_id',
-            help='Network to allocate floating IP from')
+            'floating_network_id', metavar='FLOATING_NETWORK',
+            help='Network name or id to allocate floating IP from')
         parser.add_argument(
             '--port-id',
             help='ID of the port to be associated with the floatingip')
diff --git a/quantumclient/quantum/v2_0/network.py b/quantumclient/quantum/v2_0/network.py
index 19b9978..4d88ab3 100644
--- a/quantumclient/quantum/v2_0/network.py
+++ b/quantumclient/quantum/v2_0/network.py
@@ -84,7 +84,7 @@ class CreateNetwork(CreateCommand):
             default=argparse.SUPPRESS,
             help='Set the network as shared')
         parser.add_argument(
-            'name', metavar='name',
+            'name', metavar='NAME',
             help='Name of network to create')
 
     def args2body(self, parsed_args):
diff --git a/quantumclient/quantum/v2_0/port.py b/quantumclient/quantum/v2_0/port.py
index 7f39365..98661b5 100644
--- a/quantumclient/quantum/v2_0/port.py
+++ b/quantumclient/quantum/v2_0/port.py
@@ -112,7 +112,7 @@ class CreatePort(CreateCommand):
             action='append',
             help='desired IP for this port: '
             'subnet_id=<name_or_id>,ip_address=<ip>, '
-            'can be repeated')
+            '(This option can be repeated.)')
         parser.add_argument(
             '--fixed_ip',
             action='append',
diff --git a/quantumclient/quantum/v2_0/router.py b/quantumclient/quantum/v2_0/router.py
index db85b80..a0de0c8 100644
--- a/quantumclient/quantum/v2_0/router.py
+++ b/quantumclient/quantum/v2_0/router.py
@@ -68,7 +68,7 @@ class CreateRouter(CreateCommand):
             action='store_false',
             help=argparse.SUPPRESS)
         parser.add_argument(
-            'name', metavar='name',
+            'name', metavar='NAME',
             help='Name of router to create')
 
     def args2body(self, parsed_args):
diff --git a/quantumclient/quantum/v2_0/subnet.py b/quantumclient/quantum/v2_0/subnet.py
index 390f7bf..9339ff5 100644
--- a/quantumclient/quantum/v2_0/subnet.py
+++ b/quantumclient/quantum/v2_0/subnet.py
@@ -91,7 +91,7 @@ class CreateSubnet(CreateCommand):
             choices=[4, 6],
             help=argparse.SUPPRESS)
         parser.add_argument(
-            '--gateway', metavar='gateway',
+            '--gateway', metavar='GATEWAY_IP',
             help='gateway ip of this subnet')
         parser.add_argument(
             '--no-gateway',
@@ -120,10 +120,10 @@ class CreateSubnet(CreateCommand):
             action='store_true',
             help='Disable DHCP for this subnet')
         parser.add_argument(
-            'network_id', metavar='network',
-            help='Network id or name this subnet belongs to')
+            'network_id', metavar='NETWORK',
+            help='network id or name this subnet belongs to')
         parser.add_argument(
-            'cidr', metavar='cidr',
+            'cidr', metavar='CIDR',
             help='cidr of subnet to create')
 
     def args2body(self, parsed_args):
diff --git a/quantumclient/shell.py b/quantumclient/shell.py
index 36f3e0c..a95bf09 100644
--- a/quantumclient/shell.py
+++ b/quantumclient/shell.py
@@ -349,6 +349,46 @@ class QuantumShell(App):
             result = self.run_subcommand(remainder)
         return result
 
+    def run_subcommand(self, argv):
+        subcommand = self.command_manager.find_command(argv)
+        cmd_factory, cmd_name, sub_argv = subcommand
+        cmd = cmd_factory(self, self.options)
+        err = None
+        result = 1
+        try:
+            self.prepare_to_run_command(cmd)
+            full_name = (cmd_name
+                         if self.interactive_mode
+                         else ' '.join([self.NAME, cmd_name])
+                         )
+            cmd_parser = cmd.get_parser(full_name)
+            known_args, values_specs = cmd_parser.parse_known_args(sub_argv)
+            cmd.values_specs = values_specs
+            result = cmd.run(known_args)
+        except Exception as err:
+            if self.options.debug:
+                self.log.exception(err)
+            else:
+                self.log.error(err)
+            try:
+                self.clean_up(cmd, result, err)
+            except Exception as err2:
+                if self.options.debug:
+                    self.log.exception(err2)
+                else:
+                    self.log.error('Could not clean up: %s', err2)
+            if self.options.debug:
+                raise
+        else:
+            try:
+                self.clean_up(cmd, result, None)
+            except Exception as err3:
+                if self.options.debug:
+                    self.log.exception(err3)
+                else:
+                    self.log.error('Could not clean up: %s', err3)
+        return result
+
     def authenticate_user(self):
         """Make sure the user has provided all of the authentication
         info we need.
diff --git a/quantumclient/tests/unit/test_casual_args.py b/quantumclient/tests/unit/test_casual_args.py
index 4192ff8..4eb2b66 100644
--- a/quantumclient/tests/unit/test_casual_args.py
+++ b/quantumclient/tests/unit/test_casual_args.py
@@ -35,7 +35,7 @@ class CLITestArgs(unittest.TestCase):
     def test_bool_true(self):
         _specs = ['--my-bool', 'type=bool', 'true',  '--arg1', 'value1']
         _mydict = quantumV20.parse_args_to_dict(_specs)
-        self.assertTrue(_mydict['my-bool'])
+        self.assertTrue(_mydict['my_bool'])
 
     def test_bool_false(self):
         _specs = ['--my_bool', 'type=bool', 'false',  '--arg1', 'value1']
diff --git a/quantumclient/tests/unit/test_cli20.py b/quantumclient/tests/unit/test_cli20.py
index 950c23d..4c8f61c 100644
--- a/quantumclient/tests/unit/test_cli20.py
+++ b/quantumclient/tests/unit/test_cli20.py
@@ -168,8 +168,9 @@ class CLITestV20Base(unittest.TestCase):
                                                         resstr))
         self.mox.ReplayAll()
         cmd_parser = cmd.get_parser('create_' + resource)
-        parsed_args = cmd_parser.parse_args(args)
-        cmd.run(parsed_args)
+        known_args, values_specs = cmd_parser.parse_known_args(args)
+        cmd.values_specs = values_specs
+        cmd.run(known_args)
         self.mox.VerifyAll()
         self.mox.UnsetStubs()
         _str = self.fake_stdout.make_string()
diff --git a/quantumclient/tests/unit/test_cli20_floatingips.py b/quantumclient/tests/unit/test_cli20_floatingips.py
index e48d29e..7d0da04 100644
--- a/quantumclient/tests/unit/test_cli20_floatingips.py
+++ b/quantumclient/tests/unit/test_cli20_floatingips.py
@@ -57,7 +57,7 @@ class CLITestV20FloatingIps(CLITestV20Base):
 
         # Test dashed options
         args = [name, '--port-id', pid]
-        position_names = ['floating_network_id', 'port-id']
+        position_names = ['floating_network_id', 'port_id']
         _str = self._test_create_resource(resource, cmd, name, myid, args,
                                           position_names, position_values)
 
@@ -76,7 +76,7 @@ class CLITestV20FloatingIps(CLITestV20Base):
                                           position_names, position_values)
         # Test dashed options
         args = [name, '--port-id', pid, '--fixed-ip-address', addr]
-        position_names = ['floating_network_id', 'port-id', 'fixed-ip-address']
+        position_names = ['floating_network_id', 'port_id', 'fixed_ip_address']
         _str = self._test_create_resource(resource, cmd, name, myid, args,
                                           position_names, position_values)
 
diff --git a/quantumclient/tests/unit/test_cli20_subnet.py b/quantumclient/tests/unit/test_cli20_subnet.py
index e07f6c7..ec4396f 100644
--- a/quantumclient/tests/unit/test_cli20_subnet.py
+++ b/quantumclient/tests/unit/test_cli20_subnet.py
@@ -239,6 +239,67 @@ class CLITestV20Subnet(CLITestV20Base):
                                           position_names, position_values,
                                           tenant_id='tenantid')
 
+    def test_create_subnet_merge_single_plurar(self):
+        resource = 'subnet'
+        cmd = CreateSubnet(MyApp(sys.stdout), None)
+        name = 'myname'
+        myid = 'myid'
+        netid = 'netid'
+        cidr = 'prefixvalue'
+        args = ['--tenant_id', 'tenantid',
+                '--allocation-pool', 'start=1.1.1.10,end=1.1.1.20',
+                netid, cidr,
+                '--allocation-pools', 'list=true', 'type=dict',
+                'start=1.1.1.30,end=1.1.1.40']
+        position_names = ['ip_version', 'allocation_pools', 'network_id',
+                          'cidr']
+        pools = [{'start': '1.1.1.10', 'end': '1.1.1.20'},
+                 {'start': '1.1.1.30', 'end': '1.1.1.40'}]
+        position_values = [4, pools, netid, cidr]
+        _str = self._test_create_resource(resource, cmd, name, myid, args,
+                                          position_names, position_values,
+                                          tenant_id='tenantid')
+
+    def test_create_subnet_merge_plurar(self):
+        resource = 'subnet'
+        cmd = CreateSubnet(MyApp(sys.stdout), None)
+        name = 'myname'
+        myid = 'myid'
+        netid = 'netid'
+        cidr = 'prefixvalue'
+        args = ['--tenant_id', 'tenantid',
+                netid, cidr,
+                '--allocation-pools', 'list=true', 'type=dict',
+                'start=1.1.1.30,end=1.1.1.40']
+        position_names = ['ip_version', 'allocation_pools', 'network_id',
+                          'cidr']
+        pools = [{'start': '1.1.1.30', 'end': '1.1.1.40'}]
+        position_values = [4, pools, netid, cidr]
+        _str = self._test_create_resource(resource, cmd, name, myid, args,
+                                          position_names, position_values,
+                                          tenant_id='tenantid')
+
+    def test_create_subnet_merge_single_single(self):
+        resource = 'subnet'
+        cmd = CreateSubnet(MyApp(sys.stdout), None)
+        name = 'myname'
+        myid = 'myid'
+        netid = 'netid'
+        cidr = 'prefixvalue'
+        args = ['--tenant_id', 'tenantid',
+                '--allocation-pool', 'start=1.1.1.10,end=1.1.1.20',
+                netid, cidr,
+                '--allocation-pool',
+                'start=1.1.1.30,end=1.1.1.40']
+        position_names = ['ip_version', 'allocation_pools', 'network_id',
+                          'cidr']
+        pools = [{'start': '1.1.1.10', 'end': '1.1.1.20'},
+                 {'start': '1.1.1.30', 'end': '1.1.1.40'}]
+        position_values = [4, pools, netid, cidr]
+        _str = self._test_create_resource(resource, cmd, name, myid, args,
+                                          position_names, position_values,
+                                          tenant_id='tenantid')
+
     def test_list_subnets_detail(self):
         """List subnets: -D."""
         resources = "subnets"