diff options
-rw-r--r-- | doc/source/usage/osc/v2/network-trunk.rst | 10 | ||||
-rw-r--r-- | neutronclient/neutron/v2_0/quota.py | 4 | ||||
-rw-r--r-- | neutronclient/neutron/v2_0/router.py | 7 | ||||
-rw-r--r-- | neutronclient/osc/v2/trunk/network_trunk.py | 22 | ||||
-rw-r--r-- | neutronclient/tests/unit/osc/v2/trunk/fakes.py | 5 | ||||
-rw-r--r-- | neutronclient/tests/unit/osc/v2/trunk/test_network_trunk.py | 63 | ||||
-rw-r--r-- | neutronclient/tests/unit/test_cli20_router.py | 13 | ||||
-rw-r--r-- | neutronclient/tests/unit/test_quota.py | 8 | ||||
-rw-r--r-- | releasenotes/notes/fix-quota-update-zero-args-d596c4169c2d2e30.yaml | 9 | ||||
-rw-r--r-- | requirements.txt | 2 | ||||
-rwxr-xr-x | tools/tox_install.sh | 66 |
11 files changed, 154 insertions, 55 deletions
diff --git a/doc/source/usage/osc/v2/network-trunk.rst b/doc/source/usage/osc/v2/network-trunk.rst index 5a79310..a39e3bd 100644 --- a/doc/source/usage/osc/v2/network-trunk.rst +++ b/doc/source/usage/osc/v2/network-trunk.rst @@ -37,6 +37,7 @@ Create a network trunk for a given project [--subport <port=,segmentation-type=,segmentation-id=>] [--enable | --disable] [--project <project> [--project-domain <project-domain>]] + [--description <description>] <name> .. option:: --parent-port <parent-port> @@ -65,6 +66,10 @@ Create a network trunk for a given project Domain the project belongs to (name or ID). This can be used in case collisions between project names exist. +.. option:: --description <description> + + A description of the trunk. + network trunk delete -------------------- @@ -106,6 +111,7 @@ Set network trunk properties os network trunk set [--name <name>] + [--description <description>] [--subport <port=,segmentation-type=,segmentation-id=>] [--enable | --disable] <trunk> @@ -114,6 +120,10 @@ Set network trunk properties Set trunk name +.. option:: --description <description> + + A description of the trunk. + .. option:: --subport <port=,segmentation-type=,segmentation-id=> Subport to add. Subport is of form 'port=<name or ID>,segmentation-type=,segmentation-ID=' diff --git a/neutronclient/neutron/v2_0/quota.py b/neutronclient/neutron/v2_0/quota.py index ad36194..160b6e4 100644 --- a/neutronclient/neutron/v2_0/quota.py +++ b/neutronclient/neutron/v2_0/quota.py @@ -216,6 +216,10 @@ class UpdateQuota(neutronV20.NeutronCommand, show.ShowOne): quota[resource] = self._validate_int( resource, getattr(parsed_args, resource)) + if not quota: + raise exceptions.CommandError( + message=_('Must specify a valid resource with new quota ' + 'value')) return {self.resource: quota} def take_action(self, parsed_args): diff --git a/neutronclient/neutron/v2_0/router.py b/neutronclient/neutron/v2_0/router.py index 200feee..b431daa 100644 --- a/neutronclient/neutron/v2_0/router.py +++ b/neutronclient/neutron/v2_0/router.py @@ -71,6 +71,9 @@ class CreateRouter(neutronV20.CreateCommand): parser.add_argument( '--description', help=_('Description of router.')) + parser.add_argument( + '--flavor', + help=_('ID or name of flavor.')) utils.add_boolean_argument( parser, '--distributed', dest='distributed', help=_('Create a distributed router.')) @@ -82,6 +85,10 @@ class CreateRouter(neutronV20.CreateCommand): def args2body(self, parsed_args): body = {'admin_state_up': parsed_args.admin_state} + if parsed_args.flavor: + _flavor_id = neutronV20.find_resourceid_by_name_or_id( + self.get_client(), 'flavor', parsed_args.flavor) + body['flavor_id'] = _flavor_id neutronV20.update_dict(parsed_args, body, ['name', 'tenant_id', 'distributed', 'ha', 'description']) diff --git a/neutronclient/osc/v2/trunk/network_trunk.py b/neutronclient/osc/v2/trunk/network_trunk.py index e3eed82..70f791f 100644 --- a/neutronclient/osc/v2/trunk/network_trunk.py +++ b/neutronclient/osc/v2/trunk/network_trunk.py @@ -45,6 +45,11 @@ class CreateNetworkTrunk(command.ShowOne): help=_("Name of the trunk to create") ) parser.add_argument( + '--description', + metavar='<description>', + help=_("A description of the trunk") + ) + parser.add_argument( '--parent-port', metavar='<parent-port>', required=True, @@ -141,21 +146,27 @@ class ListNetworkTrunk(command.Lister): headers = ( 'ID', 'Name', - 'Parent Port' + 'Parent Port', + 'Description' ) columns = ( 'id', 'name', - 'port_id' + 'port_id', + 'description' ) if parsed_args.long: headers += ( 'Status', 'State', + 'Created At', + 'Updated At', ) columns += ( 'status', 'admin_state_up', + 'created_at', + 'updated_at' ) return (headers, (utils.get_dict_properties( @@ -180,6 +191,11 @@ class SetNetworkTrunk(command.Command): help=_("Set trunk name") ) parser.add_argument( + '--description', + metavar='<description>', + help=_("A description of the trunk") + ) + parser.add_argument( '--subport', metavar='<port=,segmentation-type=,segmentation-id=>', action=parseractions.MultiKeyValueAction, dest='set_subports', @@ -313,6 +329,8 @@ def _get_attrs_for_trunk(client_manager, parsed_args): attrs = {} if parsed_args.name is not None: attrs['name'] = str(parsed_args.name) + if parsed_args.description is not None: + attrs['description'] = str(parsed_args.description) if parsed_args.enable: attrs['admin_state_up'] = True if parsed_args.disable: diff --git a/neutronclient/tests/unit/osc/v2/trunk/fakes.py b/neutronclient/tests/unit/osc/v2/trunk/fakes.py index 0eb6f97..1acbcc3 100644 --- a/neutronclient/tests/unit/osc/v2/trunk/fakes.py +++ b/neutronclient/tests/unit/osc/v2/trunk/fakes.py @@ -24,8 +24,8 @@ class FakeTrunk(object): :param Dictionary attrs: A dictionary with all attributes :return: - A Dictionary with id, name, admin_state_up, - port_id, sub_ports, status and project_id + A Dictionary with id, name, description, admin_state_up, port_id, + sub_ports, status and project_id """ attrs = attrs or {} @@ -33,6 +33,7 @@ class FakeTrunk(object): trunk_attrs = { 'id': 'trunk-id-' + uuid.uuid4().hex, 'name': 'trunk-name-' + uuid.uuid4().hex, + 'description': '', 'port_id': 'port-' + uuid.uuid4().hex, 'admin_state_up': True, 'project_id': 'project-id-' + uuid.uuid4().hex, diff --git a/neutronclient/tests/unit/osc/v2/trunk/test_network_trunk.py b/neutronclient/tests/unit/osc/v2/trunk/test_network_trunk.py index 5bb5ea2..d965815 100644 --- a/neutronclient/tests/unit/osc/v2/trunk/test_network_trunk.py +++ b/neutronclient/tests/unit/osc/v2/trunk/test_network_trunk.py @@ -36,6 +36,7 @@ class TestCreateNetworkTrunk(test_fakes.TestNeutronClientOSCV2): columns = ( 'admin_state_up', + 'description', 'id', 'name', 'port_id', @@ -43,15 +44,18 @@ class TestCreateNetworkTrunk(test_fakes.TestNeutronClientOSCV2): 'status', 'sub_ports', ) - data = ( - trunk._format_admin_state(_trunk['admin_state_up']), - _trunk['id'], - _trunk['name'], - _trunk['port_id'], - _trunk['project_id'], - _trunk['status'], - utils.format_list_of_dicts(_trunk['sub_ports']), - ) + + def get_data(self): + return ( + trunk._format_admin_state(self._trunk['admin_state_up']), + self._trunk['description'], + self._trunk['id'], + self._trunk['name'], + self._trunk['port_id'], + self._trunk['project_id'], + self._trunk['status'], + utils.format_list_of_dicts(self._trunk['sub_ports']), + ) def setUp(self): super(TestCreateNetworkTrunk, self).setUp() @@ -59,6 +63,7 @@ class TestCreateNetworkTrunk(test_fakes.TestNeutronClientOSCV2): new=_get_id).start() self.neutronclient.create_trunk = mock.Mock( return_value={trunk.TRUNK: self._trunk}) + self.data = self.get_data() # Get the command object to test self.cmd = trunk.CreateNetworkTrunk(self.app, self.namespace) @@ -92,9 +97,12 @@ class TestCreateNetworkTrunk(test_fakes.TestNeutronClientOSCV2): self.assertEqual(self.data, data) def test_create_full_options(self): + self._trunk['description'] = 'foo description' + self.data = self.get_data() subport = self._trunk['sub_ports'][0] arglist = [ "--disable", + "--description", self._trunk['description'], "--parent-port", self._trunk['port_id'], "--subport", 'port=%(port)s,segmentation-type=%(seg_type)s,' 'segmentation-id=%(seg_id)s' % { @@ -105,6 +113,7 @@ class TestCreateNetworkTrunk(test_fakes.TestNeutronClientOSCV2): ] verifylist = [ ('name', self._trunk['name']), + ('description', self._trunk['description']), ('parent_port', self._trunk['port_id']), ('add_subports', [{ 'port': subport['port_id'], @@ -119,6 +128,7 @@ class TestCreateNetworkTrunk(test_fakes.TestNeutronClientOSCV2): self.neutronclient.create_trunk.assert_called_once_with({ trunk.TRUNK: {'name': self._trunk['name'], + 'description': self._trunk['description'], 'admin_state_up': False, 'sub_ports': [subport], 'port_id': self._trunk['port_id']} @@ -229,6 +239,7 @@ class TestShowNetworkTrunk(test_fakes.TestNeutronClientOSCV2): columns = ( 'admin_state_up', + 'description', 'id', 'name', 'port_id', @@ -238,6 +249,7 @@ class TestShowNetworkTrunk(test_fakes.TestNeutronClientOSCV2): ) data = ( trunk._format_admin_state(_trunk['admin_state_up']), + _trunk['description'], _trunk['id'], _trunk['name'], _trunk['port_id'], @@ -283,16 +295,21 @@ class TestShowNetworkTrunk(test_fakes.TestNeutronClientOSCV2): class TestListNetworkTrunk(test_fakes.TestNeutronClientOSCV2): # Create trunks to be listed. - _trunks = fakes.FakeTrunk.create_trunks(count=3) + _trunks = fakes.FakeTrunk.create_trunks( + {'created_at': '2001-01-01 00:00:00', + 'updated_at': '2001-01-01 00:00:00'}, count=3) columns = ( 'ID', 'Name', 'Parent Port', + 'Description' ) columns_long = columns + ( 'Status', 'State', + 'Created At', + 'Updated At' ) data = [] for t in _trunks: @@ -300,6 +317,7 @@ class TestListNetworkTrunk(test_fakes.TestNeutronClientOSCV2): t['id'], t['name'], t['port_id'], + t['description'] )) data_long = [] for t in _trunks: @@ -307,8 +325,11 @@ class TestListNetworkTrunk(test_fakes.TestNeutronClientOSCV2): t['id'], t['name'], t['port_id'], + t['description'], t['status'], trunk._format_admin_state(t['admin_state_up']), + '2001-01-01 00:00:00', + '2001-01-01 00:00:00', )) def setUp(self): @@ -356,6 +377,7 @@ class TestSetNetworkTrunk(test_fakes.TestNeutronClientOSCV2): 'admin_state_up', 'id', 'name', + 'description', 'port_id', 'project_id', 'status', @@ -365,6 +387,7 @@ class TestSetNetworkTrunk(test_fakes.TestNeutronClientOSCV2): trunk._format_admin_state(_trunk['admin_state_up']), _trunk['id'], _trunk['name'], + _trunk['description'], _trunk['port_id'], _trunk['project_id'], _trunk['status'], @@ -383,26 +406,32 @@ class TestSetNetworkTrunk(test_fakes.TestNeutronClientOSCV2): # Get the command object to test self.cmd = trunk.SetNetworkTrunk(self.app, self.namespace) - def test_set_network_trunk_name(self): + def _test_set_network_trunk_attr(self, attr, value): arglist = [ - '--name', 'trunky', - self._trunk['name'], + '--%s' % attr, value, + self._trunk[attr], ] verifylist = [ - ('name', 'trunky'), - ('trunk', self._trunk['name']), + (attr, value), + ('trunk', self._trunk[attr]), ] parsed_args = self.check_parser(self.cmd, arglist, verifylist) result = self.cmd.take_action(parsed_args) attrs = { - 'name': 'trunky', + attr: value, } self.neutronclient.update_trunk.assert_called_once_with( - self._trunk['name'], {trunk.TRUNK: attrs}) + self._trunk[attr], {trunk.TRUNK: attrs}) self.assertIsNone(result) + def test_set_network_trunk_name(self): + self._test_set_network_trunk_attr('name', 'trunky') + + def test_test_set_network_trunk_description(self): + self._test_set_network_trunk_attr('description', 'description') + def test_set_network_trunk_admin_state_up_disable(self): arglist = [ '--disable', diff --git a/neutronclient/tests/unit/test_cli20_router.py b/neutronclient/tests/unit/test_cli20_router.py index cd7ed03..1ca818d 100644 --- a/neutronclient/tests/unit/test_cli20_router.py +++ b/neutronclient/tests/unit/test_cli20_router.py @@ -35,6 +35,19 @@ class CLITestV20RouterJSON(test_cli20.CLITestV20Base): position_names, position_values, description='rooter') + def test_create_router_flavor(self): + resource = 'router' + cmd = router.CreateRouter(test_cli20.MyApp(sys.stdout), None) + name = 'router1' + myid = 'myid' + flavor = 'router-flavor' + args = [name, '--flavor', flavor] + position_names = ['name', ] + position_values = [name, flavor] + self._test_create_resource(resource, cmd, name, myid, args, + position_names, position_values, + flavor_id='router-flavor') + def test_create_router_tenant(self): # Create router: --tenant_id tenantid myname. resource = 'router' diff --git a/neutronclient/tests/unit/test_quota.py b/neutronclient/tests/unit/test_quota.py index b9d7b44..78f4dae 100644 --- a/neutronclient/tests/unit/test_quota.py +++ b/neutronclient/tests/unit/test_quota.py @@ -92,3 +92,11 @@ class CLITestV20Quota(test_cli20.CLITestV20Base): self.assertIn('subnet', _str) self.assertIn('port', _str) self.assertNotIn('subnetpool', _str) + + def test_update_quota_noargs(self): + resource = 'quota' + cmd = test_quota.UpdateQuota(test_cli20.MyApp(sys.stdout), None) + args = [self.test_id] + self.assertRaises(exceptions.CommandError, self._test_update_resource, + resource, cmd, self.test_id, args=args, + extrafields=None) diff --git a/releasenotes/notes/fix-quota-update-zero-args-d596c4169c2d2e30.yaml b/releasenotes/notes/fix-quota-update-zero-args-d596c4169c2d2e30.yaml new file mode 100644 index 0000000..eb70752 --- /dev/null +++ b/releasenotes/notes/fix-quota-update-zero-args-d596c4169c2d2e30.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fix CLI quota-update to return an error message for no args + + * ``quota-update`` CLI will return an error message + ``Must specify a valid resource with new quota value`` if no + argument is provided while executing it. If arguments are + provided with CLI, no existing behavior is changed. diff --git a/requirements.txt b/requirements.txt index 1f8e59e..709fa2e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,7 +10,7 @@ osc-lib>=1.0.2 # Apache-2.0 oslo.i18n>=2.1.0 # Apache-2.0 oslo.serialization>=1.10.0 # Apache-2.0 oslo.utils>=3.16.0 # Apache-2.0 -os-client-config!=1.19.0,!=1.19.1,!=1.20.0,!=1.20.1,>=1.13.1 # Apache-2.0 +os-client-config!=1.19.0,!=1.19.1,!=1.20.0,!=1.20.1,!=1.21.0,>=1.13.1 # Apache-2.0 keystoneauth1>=2.10.0 # Apache-2.0 requests>=2.10.0 # Apache-2.0 simplejson>=2.2.0 # MIT diff --git a/tools/tox_install.sh b/tools/tox_install.sh index c800a41..e3fb459 100755 --- a/tools/tox_install.sh +++ b/tools/tox_install.sh @@ -15,41 +15,41 @@ CONSTRAINTS_FILE=$1 shift install_cmd="pip install" -if [ $CONSTRAINTS_FILE != "unconstrained" ]; then - - mydir=$(mktemp -dt "$CLIENT_NAME-tox_install-XXXXXXX") - localfile=$mydir/upper-constraints.txt - if [[ $CONSTRAINTS_FILE != http* ]]; then - CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE - fi - curl $CONSTRAINTS_FILE -k -o $localfile - install_cmd="$install_cmd -c$localfile" - - if [ $requirements_installed -eq 0 ]; then - echo "ALREADY INSTALLED" > /tmp/tox_install.txt - echo "Requirements already installed; using existing package" - elif [ -x "$ZUUL_CLONER" ]; then - export ZUUL_BRANCH=${ZUUL_BRANCH-$BRANCH} - echo "ZUUL CLONER" > /tmp/tox_install.txt - pushd $mydir - $ZUUL_CLONER --cache-dir \ - /opt/git \ - --branch $BRANCH_NAME \ - git://git.openstack.org \ - openstack/requirements - cd openstack/requirements - $install_cmd -e . - popd - else - echo "PIP HARDCODE" > /tmp/tox_install.txt - if [ -z "$REQUIREMENTS_PIP_LOCATION" ]; then - REQUIREMENTS_PIP_LOCATION="git+https://git.openstack.org/openstack/requirements@$BRANCH_NAME#egg=requirements" - fi - $install_cmd -U -e ${REQUIREMENTS_PIP_LOCATION} +mydir=$(mktemp -dt "$CLIENT_NAME-tox_install-XXXXXXX") +trap "rm -rf $mydir" EXIT +localfile=$mydir/upper-constraints.txt +if [[ $CONSTRAINTS_FILE != http* ]]; then + CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE +fi +curl $CONSTRAINTS_FILE -k -o $localfile +install_cmd="$install_cmd -c$localfile" + +if [ $requirements_installed -eq 0 ]; then + echo "ALREADY INSTALLED" > /tmp/tox_install.txt + echo "Requirements already installed; using existing package" +elif [ -x "$ZUUL_CLONER" ]; then + echo "ZUUL CLONER" > /tmp/tox_install.txt + pushd $mydir + $ZUUL_CLONER --cache-dir \ + /opt/git \ + --branch $BRANCH_NAME \ + git://git.openstack.org \ + openstack/requirements + cd openstack/requirements + $install_cmd -e . + popd +else + echo "PIP HARDCODE" > /tmp/tox_install.txt + if [ -z "$REQUIREMENTS_PIP_LOCATION" ]; then + REQUIREMENTS_PIP_LOCATION="git+https://git.openstack.org/openstack/requirements@$BRANCH_NAME#egg=requirements" fi - - edit-constraints $localfile -- $CLIENT_NAME "-e file://$PWD#egg=$CLIENT_NAME" + $install_cmd -U -e ${REQUIREMENTS_PIP_LOCATION} fi +# This is the main purpose of the script: Allow local installation of +# the current repo. It is listed in constraints file and thus any +# install will be constrained and we need to unconstrain it. +edit-constraints $localfile -- $CLIENT_NAME "-e file://$PWD#egg=$CLIENT_NAME" + $install_cmd -U $* exit $? |