summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/command-objects/compute-service.rst11
-rw-r--r--doc/source/command-objects/port.rst62
-rw-r--r--openstackclient/compute/v2/service.py22
-rw-r--r--openstackclient/network/v2/port.py52
-rw-r--r--openstackclient/tests/compute/v2/test_service.py26
-rw-r--r--openstackclient/tests/identity/v2_0/test_endpoint.py3
-rw-r--r--openstackclient/tests/identity/v2_0/test_project.py4
-rw-r--r--openstackclient/tests/identity/v2_0/test_role.py6
-rw-r--r--openstackclient/tests/identity/v2_0/test_service.py3
-rw-r--r--openstackclient/tests/identity/v2_0/test_token.py3
-rw-r--r--openstackclient/tests/identity/v2_0/test_user.py24
-rw-r--r--openstackclient/tests/network/v2/test_port.py79
-rw-r--r--releasenotes/notes/add-disable-reason-6e0f28459a09a60d.yaml4
-rw-r--r--releasenotes/notes/add-port-set-command-2b4fe38ec71ad48f.yaml5
-rw-r--r--setup.cfg1
15 files changed, 276 insertions, 29 deletions
diff --git a/doc/source/command-objects/compute-service.rst b/doc/source/command-objects/compute-service.rst
index 7bcab4d6..25a133d9 100644
--- a/doc/source/command-objects/compute-service.rst
+++ b/doc/source/command-objects/compute-service.rst
@@ -50,19 +50,24 @@ Set service command
.. program:: compute service set
.. code:: bash
- os compute service list
+ os compute service set
[--enable | --disable]
+ [--disable-reason <reason>]
<host> <service>
.. _compute-service-set:
-.. describe:: --enable
+.. option:: --enable
Enable service (default)
-.. describe:: --disable
+.. option:: --disable
Disable service
+.. option:: --disable-reason <reason>
+
+ Reason for disabling the service (in quotes)
+
.. describe:: <host>
Name of host
diff --git a/doc/source/command-objects/port.rst b/doc/source/command-objects/port.rst
index 3083b075..e9c09173 100644
--- a/doc/source/command-objects/port.rst
+++ b/doc/source/command-objects/port.rst
@@ -45,7 +45,8 @@ Create new port
.. option:: --vnic-type <vnic-type>
- VNIC type for this port (direct | direct-physical | macvtap | normal(default) | baremetal)
+ VNIC type for this port (direct | direct-physical | macvtap | normal | baremetal).
+ If unspecified during port creation, default value will be 'normal'.
.. option:: --binding-profile <binding-profile>
@@ -108,6 +109,65 @@ List ports
os port list
+port set
+--------
+
+Set port properties
+
+.. program:: port set
+.. code:: bash
+
+ os port set
+ [--fixed-ip subnet=<subnet>,ip-address=<ip-address>]
+ [--device-id <device-id>]
+ [--device-owner <device-owner>]
+ [--vnic-type <vnic-type>]
+ [--binding-profile <binding-profile>]
+ [--host-id <host-id>]
+ [--enable | --disable]
+ <port>
+
+.. option:: --fixed-ip subnet=<subnet>,ip-address=<ip-address>
+
+ Desired IP and/or subnet for this port:
+ subnet=<subnet>,ip-address=<ip-address>
+ (you can repeat this option)
+
+.. option:: --device-id <device-id>
+
+ Device ID of this port
+
+.. option:: --device-owner <device-owner>
+
+ Device owner of this port
+
+.. option:: --vnic-type <vnic-type>
+
+ VNIC type for this port (direct | direct-physical | macvtap | normal | baremetal).
+ If unspecified during port creation, default value will be 'normal'.
+
+.. option:: --binding-profile <binding-profile>
+
+ Custom data to be passed as binding:profile: <key>=<value>
+ (this option can be repeated)
+
+.. option:: --host-id <host-id>
+
+ The ID of the host where the port is allocated
+
+.. option:: --enable
+
+ Enable port
+
+.. option:: --disable
+
+ Disable port
+
+.. _port_set-port:
+.. describe:: <port>
+
+ Port to modify (name or ID)
+
port show
---------
diff --git a/openstackclient/compute/v2/service.py b/openstackclient/compute/v2/service.py
index 3c062724..1cc91711 100644
--- a/openstackclient/compute/v2/service.py
+++ b/openstackclient/compute/v2/service.py
@@ -95,14 +95,24 @@ class SetService(command.Command):
dest="enabled",
help="Disable a service",
action="store_false")
+ parser.add_argument(
+ "--disable-reason",
+ default=None,
+ metavar="<reason>",
+ help="Reason for disabling the service (in quotas)"
+ )
return parser
def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute
-
- if parsed_args.enabled:
- action = compute_client.services.enable
+ cs = compute_client.services
+
+ if not parsed_args.enabled:
+ if parsed_args.disable_reason:
+ cs.disable_log_reason(parsed_args.host,
+ parsed_args.service,
+ parsed_args.disable_reason)
+ else:
+ cs.disable(parsed_args.host, parsed_args.service)
else:
- action = compute_client.services.disable
-
- action(parsed_args.host, parsed_args.service)
+ cs.enable(parsed_args.host, parsed_args.service)
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index 449dcfd4..b618a4b0 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -14,6 +14,7 @@
"""Port action implementations"""
from openstackclient.common import command
+from openstackclient.common import exceptions
from openstackclient.common import parseractions
from openstackclient.common import utils
from openstackclient.identity import common as identity_common
@@ -56,8 +57,6 @@ def _get_columns(item):
def _get_attrs(client_manager, parsed_args):
attrs = {}
- if parsed_args.name is not None:
- attrs['name'] = str(parsed_args.name)
if parsed_args.fixed_ip is not None:
attrs['fixed_ips'] = parsed_args.fixed_ip
if parsed_args.device_id is not None:
@@ -75,6 +74,8 @@ def _get_attrs(client_manager, parsed_args):
# The remaining options do not support 'port set' command, so they require
# additional check
+ if 'name' in parsed_args and parsed_args.name is not None:
+ attrs['name'] = str(parsed_args.name)
if 'mac_address' in parsed_args and parsed_args.mac_address is not None:
attrs['mac_address'] = parsed_args.mac_address
if 'network' in parsed_args and parsed_args.network is not None:
@@ -145,8 +146,9 @@ def _add_updatable_args(parser):
metavar='<vnic-type>',
choices=['direct', 'direct-physical', 'macvtap',
'normal', 'baremetal'],
- help='VNIC type for this port (direct | direct-physical |'
- ' macvtap | normal(default) | baremetal)')
+ help="VNIC type for this port (direct | direct-physical |"
+ " macvtap | normal | baremetal). If unspecified during"
+ " port creation, default value will be 'normal'.")
parser.add_argument(
'--binding-profile',
metavar='<binding-profile>',
@@ -265,6 +267,48 @@ class ListPort(command.Lister):
) for s in data))
+class SetPort(command.Command):
+ """Set port properties"""
+
+ def get_parser(self, prog_name):
+ parser = super(SetPort, self).get_parser(prog_name)
+ _add_updatable_args(parser)
+ admin_group = parser.add_mutually_exclusive_group()
+ admin_group.add_argument(
+ '--enable',
+ dest='admin_state',
+ action='store_true',
+ default=None,
+ help='Enable port',
+ )
+ admin_group.add_argument(
+ '--disable',
+ dest='admin_state',
+ action='store_false',
+ help='Disable port',
+ )
+ parser.add_argument(
+ 'port',
+ metavar="<port>",
+ help=("Port to modify (name or ID)")
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+
+ _prepare_fixed_ips(self.app.client_manager, parsed_args)
+ attrs = _get_attrs(self.app.client_manager, parsed_args)
+
+ if attrs == {}:
+ msg = "Nothing specified to be set"
+ raise exceptions.CommandError(msg)
+
+ obj = client.find_port(parsed_args.port, ignore_missing=False)
+ client.update_port(obj, **attrs)
+
+
class ShowPort(command.ShowOne):
"""Display port details"""
diff --git a/openstackclient/tests/compute/v2/test_service.py b/openstackclient/tests/compute/v2/test_service.py
index 2f8b2e7d..0246fbc8 100644
--- a/openstackclient/tests/compute/v2/test_service.py
+++ b/openstackclient/tests/compute/v2/test_service.py
@@ -153,3 +153,29 @@ class TestServiceSet(TestService):
compute_fakes.service_binary,
)
self.assertIsNone(result)
+
+ def test_service_set_disable_with_reason(self):
+ reason = 'earthquake'
+ arglist = [
+ compute_fakes.service_host,
+ compute_fakes.service_binary,
+ '--disable',
+ '--disable-reason',
+ reason
+ ]
+ verifylist = [
+ ('host', compute_fakes.service_host),
+ ('service', compute_fakes.service_binary),
+ ('enabled', False),
+ ('disable_reason', reason)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ result = self.cmd.take_action(parsed_args)
+
+ self.service_mock.disable_log_reason.assert_called_with(
+ compute_fakes.service_host,
+ compute_fakes.service_binary,
+ reason
+ )
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/identity/v2_0/test_endpoint.py b/openstackclient/tests/identity/v2_0/test_endpoint.py
index 088fdcd1..45ece45a 100644
--- a/openstackclient/tests/identity/v2_0/test_endpoint.py
+++ b/openstackclient/tests/identity/v2_0/test_endpoint.py
@@ -132,11 +132,12 @@ class TestEndpointDelete(TestEndpoint):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
self.endpoints_mock.delete.assert_called_with(
identity_fakes.endpoint_id,
)
+ self.assertIsNone(result)
class TestEndpointList(TestEndpoint):
diff --git a/openstackclient/tests/identity/v2_0/test_project.py b/openstackclient/tests/identity/v2_0/test_project.py
index 98570297..38684aaf 100644
--- a/openstackclient/tests/identity/v2_0/test_project.py
+++ b/openstackclient/tests/identity/v2_0/test_project.py
@@ -613,10 +613,9 @@ class TestProjectUnset(TestProject):
verifylist = [
('property', ['fee', 'fo']),
]
-
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'description': identity_fakes.project_description,
@@ -631,3 +630,4 @@ class TestProjectUnset(TestProject):
identity_fakes.project_id,
**kwargs
)
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/identity/v2_0/test_role.py b/openstackclient/tests/identity/v2_0/test_role.py
index 03b7f924..3c4b79a4 100644
--- a/openstackclient/tests/identity/v2_0/test_role.py
+++ b/openstackclient/tests/identity/v2_0/test_role.py
@@ -240,11 +240,12 @@ class TestRoleDelete(TestRole):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
self.roles_mock.delete.assert_called_with(
identity_fakes.role_id,
)
+ self.assertIsNone(result)
class TestRoleList(TestRole):
@@ -459,7 +460,7 @@ class TestRoleRemove(TestRole):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
# RoleManager.remove_user_role(user, role, tenant=None)
self.roles_mock.remove_user_role.assert_called_with(
@@ -467,6 +468,7 @@ class TestRoleRemove(TestRole):
identity_fakes.role_id,
identity_fakes.project_id,
)
+ self.assertIsNone(result)
class TestRoleShow(TestRole):
diff --git a/openstackclient/tests/identity/v2_0/test_service.py b/openstackclient/tests/identity/v2_0/test_service.py
index 606b1433..dc0fbcd1 100644
--- a/openstackclient/tests/identity/v2_0/test_service.py
+++ b/openstackclient/tests/identity/v2_0/test_service.py
@@ -194,11 +194,12 @@ class TestServiceDelete(TestService):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
self.services_mock.delete.assert_called_with(
identity_fakes.service_id,
)
+ self.assertIsNone(result)
class TestServiceList(TestService):
diff --git a/openstackclient/tests/identity/v2_0/test_token.py b/openstackclient/tests/identity/v2_0/test_token.py
index c90477f9..613139dd 100644
--- a/openstackclient/tests/identity/v2_0/test_token.py
+++ b/openstackclient/tests/identity/v2_0/test_token.py
@@ -99,6 +99,7 @@ class TestTokenRevoke(TestToken):
verifylist = [('token', self.TOKEN)]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
self.tokens_mock.delete.assert_called_with(self.TOKEN)
+ self.assertIsNone(result)
diff --git a/openstackclient/tests/identity/v2_0/test_user.py b/openstackclient/tests/identity/v2_0/test_user.py
index 9afe4ad1..921e215d 100644
--- a/openstackclient/tests/identity/v2_0/test_user.py
+++ b/openstackclient/tests/identity/v2_0/test_user.py
@@ -414,11 +414,12 @@ class TestUserDelete(TestUser):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
self.users_mock.delete.assert_called_with(
identity_fakes.user_id,
)
+ self.assertIsNone(result)
class TestUserList(TestUser):
@@ -578,7 +579,7 @@ class TestUserSet(TestUser):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
@@ -590,6 +591,7 @@ class TestUserSet(TestUser):
identity_fakes.user_id,
**kwargs
)
+ self.assertIsNone(result)
def test_user_set_password(self):
arglist = [
@@ -608,13 +610,14 @@ class TestUserSet(TestUser):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
# UserManager.update_password(user, password)
self.users_mock.update_password.assert_called_with(
identity_fakes.user_id,
'secret',
)
+ self.assertIsNone(result)
def test_user_set_password_prompt(self):
arglist = [
@@ -636,13 +639,14 @@ class TestUserSet(TestUser):
mocker = mock.Mock()
mocker.return_value = 'abc123'
with mock.patch("openstackclient.common.utils.get_password", mocker):
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
# UserManager.update_password(user, password)
self.users_mock.update_password.assert_called_with(
identity_fakes.user_id,
'abc123',
)
+ self.assertIsNone(result)
def test_user_set_email(self):
arglist = [
@@ -660,7 +664,7 @@ class TestUserSet(TestUser):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
@@ -672,6 +676,7 @@ class TestUserSet(TestUser):
identity_fakes.user_id,
**kwargs
)
+ self.assertIsNone(result)
def test_user_set_project(self):
arglist = [
@@ -689,13 +694,14 @@ class TestUserSet(TestUser):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
# UserManager.update_tenant(user, tenant)
self.users_mock.update_tenant.assert_called_with(
identity_fakes.user_id,
identity_fakes.project_id,
)
+ self.assertIsNone(result)
def test_user_set_enable(self):
arglist = [
@@ -713,7 +719,7 @@ class TestUserSet(TestUser):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
@@ -724,6 +730,7 @@ class TestUserSet(TestUser):
identity_fakes.user_id,
**kwargs
)
+ self.assertIsNone(result)
def test_user_set_disable(self):
arglist = [
@@ -741,7 +748,7 @@ class TestUserSet(TestUser):
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
- self.cmd.take_action(parsed_args)
+ result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
@@ -752,6 +759,7 @@ class TestUserSet(TestUser):
identity_fakes.user_id,
**kwargs
)
+ self.assertIsNone(result)
class TestUserShow(TestUser):
diff --git a/openstackclient/tests/network/v2/test_port.py b/openstackclient/tests/network/v2/test_port.py
index 30e290c6..7b1c655f 100644
--- a/openstackclient/tests/network/v2/test_port.py
+++ b/openstackclient/tests/network/v2/test_port.py
@@ -240,6 +240,85 @@ class TestListPort(TestPort):
self.assertEqual(self.data, list(data))
+class TestSetPort(TestPort):
+
+ _port = network_fakes.FakePort.create_one_port()
+
+ def setUp(self):
+ super(TestSetPort, self).setUp()
+
+ self.fake_subnet = network_fakes.FakeSubnet.create_one_subnet()
+ self.network.find_subnet = mock.Mock(return_value=self.fake_subnet)
+ self.network.find_port = mock.Mock(return_value=self._port)
+ self.network.update_port = mock.Mock(return_value=None)
+
+ # Get the command object to test
+ self.cmd = port.SetPort(self.app, self.namespace)
+
+ def test_set_fixed_ip(self):
+ arglist = [
+ '--fixed-ip', 'ip-address=10.0.0.11',
+ self._port.name,
+ ]
+ verifylist = [
+ ('fixed_ip', [{'ip-address': '10.0.0.11'}]),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'fixed_ips': [{'ip_address': '10.0.0.11'}],
+ }
+ self.network.update_port.assert_called_with(self._port, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_this(self):
+ arglist = [
+ '--disable',
+ self._port.name,
+ ]
+ verifylist = [
+ ('admin_state', False),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'admin_state_up': False,
+ }
+ self.network.update_port.assert_called_with(self._port, **attrs)
+ self.assertIsNone(result)
+
+ def test_set_that(self):
+ arglist = [
+ '--enable',
+ '--vnic-type', 'macvtap',
+ '--binding-profile', 'foo=bar',
+ '--host-id', 'binding-host-id-xxxx',
+ self._port.name,
+ ]
+ verifylist = [
+ ('admin_state', True),
+ ('vnic_type', 'macvtap'),
+ ('binding_profile', {'foo': 'bar'}),
+ ('host_id', 'binding-host-id-xxxx'),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ attrs = {
+ 'admin_state_up': True,
+ 'binding:vnic_type': 'macvtap',
+ 'binding:profile': {'foo': 'bar'},
+ 'binding:host_id': 'binding-host-id-xxxx',
+ }
+ self.network.update_port.assert_called_with(self._port, **attrs)
+ self.assertIsNone(result)
+
+
class TestShowPort(TestPort):
# The port to show.
diff --git a/releasenotes/notes/add-disable-reason-6e0f28459a09a60d.yaml b/releasenotes/notes/add-disable-reason-6e0f28459a09a60d.yaml
new file mode 100644
index 00000000..298ccad5
--- /dev/null
+++ b/releasenotes/notes/add-disable-reason-6e0f28459a09a60d.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Add support for the ``--disable-reason`` of ``service set`` command
diff --git a/releasenotes/notes/add-port-set-command-2b4fe38ec71ad48f.yaml b/releasenotes/notes/add-port-set-command-2b4fe38ec71ad48f.yaml
new file mode 100644
index 00000000..89784d2b
--- /dev/null
+++ b/releasenotes/notes/add-port-set-command-2b4fe38ec71ad48f.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Add support for the ``port set`` command.
+ [Bug `1519909 <https://bugs.launchpad.net/python-openstackclient/+bug/1519909>`_]
diff --git a/setup.cfg b/setup.cfg
index 728b5d64..981d2fef 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -336,6 +336,7 @@ openstack.network.v2 =
port_create = openstackclient.network.v2.port:CreatePort
port_delete = openstackclient.network.v2.port:DeletePort
port_list = openstackclient.network.v2.port:ListPort
+ port_set = openstackclient.network.v2.port:SetPort
port_show = openstackclient.network.v2.port:ShowPort
router_create = openstackclient.network.v2.router:CreateRouter