summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/cli/command-objects/network-agent.rst121
-rw-r--r--doc/source/cli/command-objects/router.rst5
-rw-r--r--doc/source/cli/command-objects/server.rst7
-rw-r--r--doc/source/cli/plugin-commands.rst10
-rw-r--r--openstackclient/compute/v2/server.py60
-rw-r--r--openstackclient/identity/common.py8
-rw-r--r--openstackclient/identity/v3/project.py3
-rw-r--r--openstackclient/identity/v3/user.py6
-rw-r--r--openstackclient/network/v2/network_agent.py121
-rw-r--r--openstackclient/network/v2/router.py32
-rw-r--r--openstackclient/tests/functional/network/v2/test_floating_ip.py13
-rw-r--r--openstackclient/tests/functional/network/v2/test_ip_availability.py3
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_agent.py36
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_meter_rule.py3
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_qos_policy.py5
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_qos_rule.py3
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_rbac.py7
-rw-r--r--openstackclient/tests/functional/network/v2/test_network_segment.py7
-rw-r--r--openstackclient/tests/functional/network/v2/test_port.py7
-rw-r--r--openstackclient/tests/functional/network/v2/test_router.py34
-rw-r--r--openstackclient/tests/functional/network/v2/test_security_group.py5
-rw-r--r--openstackclient/tests/functional/network/v2/test_security_group_rule.py5
-rw-r--r--openstackclient/tests/functional/network/v2/test_subnet.py3
-rw-r--r--openstackclient/tests/unit/compute/v2/test_server.py47
-rw-r--r--openstackclient/tests/unit/identity/v3/test_project.py46
-rw-r--r--openstackclient/tests/unit/identity/v3/test_user.py38
-rw-r--r--openstackclient/tests/unit/network/v2/test_network_agent.py173
-rw-r--r--openstackclient/tests/unit/network/v2/test_router.py50
-rw-r--r--releasenotes/notes/bp-network-l3-adv-commands-cc1df715a184f1b2.yaml8
-rw-r--r--releasenotes/notes/bug-1704097-8ff1ce1444b81b04.yaml9
-rw-r--r--releasenotes/notes/skip-name-lookups-9f499927173c1eee.yaml6
-rw-r--r--setup.cfg2
-rw-r--r--test-requirements.txt4
33 files changed, 751 insertions, 136 deletions
diff --git a/doc/source/cli/command-objects/network-agent.rst b/doc/source/cli/command-objects/network-agent.rst
index f69d0ece..2ceb263f 100644
--- a/doc/source/cli/command-objects/network-agent.rst
+++ b/doc/source/cli/command-objects/network-agent.rst
@@ -33,7 +33,34 @@ Add network to an agent
.. describe:: <network>
- Network to be added to an agent (ID or name)
+ Network to be added to an agent (name or ID)
+
+network agent add router
+------------------------
+
+Add router to an agent
+
+.. program:: network agent add router
+.. code:: bash
+
+ openstack network agent add router
+ [--l3]
+ <agent-id>
+ <router>
+
+.. option:: --l3
+
+ Add router to L3 agent
+
+.. _network_agent_add_router-agent-id:
+.. describe:: <agent-id>
+
+ Agent to which a router is added (ID only)
+
+.. _network_agent_add_router-router:
+.. describe:: <router>
+
+ Router to be added to an agent (name or ID)
network agent delete
--------------------
@@ -62,7 +89,8 @@ List network agents
openstack network agent list
[--agent-type <agent-type>]
[--host <host>]
- [--network <network>]
+ [--network <network> | --router <router>]
+ [--long]
.. option:: --agent-type <agent-type>
@@ -77,7 +105,69 @@ List network agents
.. option:: --network <network>
- List agents hosting a network (ID or name)
+ List agents hosting a network (name or ID)
+
+.. option:: --router <router>
+
+ List agents hosting this router (name or ID)
+
+.. option:: --long
+
+ List additional fields in output
+
+network agent remove network
+----------------------------
+
+Remove network from an agent
+
+.. program:: network agent remove network
+.. code:: bash
+
+ openstack network agent remove network
+ [--dhcp]
+ <agent-id>
+ <network>
+
+.. option:: --dhcp
+
+ Remove network from DHCP agent
+
+.. _network_agent_remove_network-agent-id:
+.. describe:: <agent-id>
+
+ Agent to which a network is removed (ID only)
+
+.. _network_agent_remove_network-network:
+.. describe:: <network>
+
+ Network to be removed from an agent (name or ID)
+
+network agent remove router
+---------------------------
+
+Remove router from an agent
+
+.. program:: network agent remove router
+.. code:: bash
+
+ openstack agent remove router
+ [--l3]
+ <agent-id>
+ <router>
+
+.. option:: --l3
+
+ Remove router from L3 agent
+
+.. _network_agent_remove_router-agent-id:
+.. describe:: <agent-id>
+
+ Agent from which router will be removed (ID only)
+
+.. _network_agent_remove_router-router:
+.. describe:: <router>
+
+ Router to be removed from an agent (name or ID)
network agent set
-----------------
@@ -124,28 +214,3 @@ Display network agent details
.. describe:: <network-agent>
Network agent to display (ID only)
-
-network agent remove network
-----------------------------
-
-Remove network from an agent
-
-.. program:: network agent remove network
-.. code:: bash
-
- openstack network agent remove network
- [--dhcp]
- <agent-id>
- <network>
-
-.. describe:: --dhcp
-
- Remove network from DHCP agent.
-
-.. describe:: <agent-id>
-
- Agent to which a network is removed (ID only)
-
-.. describe:: <network>
-
- Network to be removed from an agent (ID or name)
diff --git a/doc/source/cli/command-objects/router.rst b/doc/source/cli/command-objects/router.rst
index 50e791ea..8bdf81db 100644
--- a/doc/source/cli/command-objects/router.rst
+++ b/doc/source/cli/command-objects/router.rst
@@ -155,6 +155,11 @@ List routers
[--enable | --disable]
[--long]
[--project <project> [--project-domain <project-domain>]]
+ [--agent <agent-id>]
+
+.. option:: --agent <agent-id>
+
+ List routers hosted by an agent (ID only)
.. option:: --long
diff --git a/doc/source/cli/command-objects/server.rst b/doc/source/cli/command-objects/server.rst
index cc580603..11182822 100644
--- a/doc/source/cli/command-objects/server.rst
+++ b/doc/source/cli/command-objects/server.rst
@@ -330,6 +330,7 @@ List servers
[--all-projects]
[--project <project> [--project-domain <project-domain>]]
[--long]
+ [--no-name-lookup | -n]
[--marker <server>]
[--limit <num-servers>]
[--deleted]
@@ -397,6 +398,12 @@ List servers
List additional fields in output
+.. option:: --no-name-lookup
+
+ Skips image and flavor names lookup
+
+ ``-n`` may be used as an alias for this option.
+
.. option:: --marker <server>
The last server of the previous page. Display list of servers
diff --git a/doc/source/cli/plugin-commands.rst b/doc/source/cli/plugin-commands.rst
index 34efdc3d..90c14b87 100644
--- a/doc/source/cli/plugin-commands.rst
+++ b/doc/source/cli/plugin-commands.rst
@@ -58,11 +58,11 @@ ironic-inspector
.. list-plugins:: openstack.baremetal_introspection.v1
:detailed:
-karbor
-------
-
-.. list-plugins:: openstack.data_protection.v1
- :detailed:
+.. karbor
+.. ------
+.. bug 1705258: Exclude karborclient 0.4.0 until a fixed version is released.
+.. .. list-plugins:: openstack.data_protection.v1
+.. :detailed:
mistral
-------
diff --git a/openstackclient/compute/v2/server.py b/openstackclient/compute/v2/server.py
index e8846d16..a991ed45 100644
--- a/openstackclient/compute/v2/server.py
+++ b/openstackclient/compute/v2/server.py
@@ -922,6 +922,12 @@ class ListServer(command.Lister):
help=_('List additional fields in output'),
)
parser.add_argument(
+ '-n', '--no-name-lookup',
+ action='store_true',
+ default=False,
+ help=_('Skip flavor and image name lookup.'),
+ )
+ parser.add_argument(
'--marker',
metavar='<server>',
default=None,
@@ -1055,19 +1061,31 @@ class ListServer(command.Lister):
'OS-EXT-SRV-ATTR:host',
]
else:
- columns = (
- 'ID',
- 'Name',
- 'Status',
- 'Networks',
- 'Image Name',
- )
+ if parsed_args.no_name_lookup:
+ columns = (
+ 'ID',
+ 'Name',
+ 'Status',
+ 'Networks',
+ 'Image ID',
+ 'Flavor ID',
+ )
+ else:
+ columns = (
+ 'ID',
+ 'Name',
+ 'Status',
+ 'Networks',
+ 'Image Name',
+ 'Flavor Name',
+ )
column_headers = (
'ID',
'Name',
'Status',
'Networks',
- 'Image Name',
+ 'Image',
+ 'Flavor',
)
mixed_case_fields = []
@@ -1084,23 +1102,25 @@ class ListServer(command.Lister):
# Create a dict that maps image_id to image object.
# Needed so that we can display the "Image Name" column.
# "Image Name" is not crucial, so we swallow any exceptions.
- try:
- images_list = self.app.client_manager.image.images.list()
- for i in images_list:
- images[i.id] = i
- except Exception:
- pass
+ if not parsed_args.no_name_lookup:
+ try:
+ images_list = self.app.client_manager.image.images.list()
+ for i in images_list:
+ images[i.id] = i
+ except Exception:
+ pass
flavors = {}
# Create a dict that maps flavor_id to flavor object.
# Needed so that we can display the "Flavor Name" column.
# "Flavor Name" is not crucial, so we swallow any exceptions.
- try:
- flavors_list = compute_client.flavors.list()
- for i in flavors_list:
- flavors[i.id] = i
- except Exception:
- pass
+ if not parsed_args.no_name_lookup:
+ try:
+ flavors_list = compute_client.flavors.list()
+ for i in flavors_list:
+ flavors[i.id] = i
+ except Exception:
+ pass
# Populate image_name, image_id, flavor_name and flavor_id attributes
# of server objects so that we can display those columns.
diff --git a/openstackclient/identity/common.py b/openstackclient/identity/common.py
index 1f645b7d..3dc5adbb 100644
--- a/openstackclient/identity/common.py
+++ b/openstackclient/identity/common.py
@@ -58,7 +58,7 @@ def find_service(identity_client, name_type_or_id):
raise exceptions.CommandError(msg % name_type_or_id)
-def _get_token_resource(client, resource, parsed_name):
+def _get_token_resource(client, resource, parsed_name, parsed_domain=None):
"""Peek into the user's auth token to get resource IDs
Look into a user's token to try and find the ID of a domain, project or
@@ -71,6 +71,8 @@ def _get_token_resource(client, resource, parsed_name):
`project_domain`, `user_domain`, `project`, or `user`.
:param parsed_name: This is input from parsed_args that the user is hoping
to find in the token.
+ :param parsed_domain: This is domain filter from parsed_args that used to
+ filter the results.
:returns: The ID of the resource from the token, or the original value from
parsed_args if it does not match.
@@ -85,6 +87,10 @@ def _get_token_resource(client, resource, parsed_name):
if resource == 'domain':
token_dict = token_dict['project']
obj = token_dict[resource]
+
+ # user/project under different domain may has a same name
+ if parsed_domain and parsed_domain not in obj['domain'].values():
+ return parsed_name
return obj['id'] if obj['name'] == parsed_name else parsed_name
# diaper defense in case parsing the token fails
except Exception: # noqa
diff --git a/openstackclient/identity/v3/project.py b/openstackclient/identity/v3/project.py
index 873ee9c7..c7806ee1 100644
--- a/openstackclient/identity/v3/project.py
+++ b/openstackclient/identity/v3/project.py
@@ -360,7 +360,8 @@ class ShowProject(command.ShowOne):
identity_client = self.app.client_manager.identity
project_str = common._get_token_resource(identity_client, 'project',
- parsed_args.project)
+ parsed_args.project,
+ parsed_args.domain)
if parsed_args.domain:
domain = common.find_domain(identity_client, parsed_args.domain)
diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py
index 9c289a6d..5f4fb544 100644
--- a/openstackclient/identity/v3/user.py
+++ b/openstackclient/identity/v3/user.py
@@ -358,7 +358,8 @@ class SetUser(command.Command):
"when a user does not have a password."))
user_str = common._get_token_resource(identity_client, 'user',
- parsed_args.user)
+ parsed_args.user,
+ parsed_args.domain)
if parsed_args.domain:
domain = common.find_domain(identity_client, parsed_args.domain)
user = utils.find_resource(identity_client.users,
@@ -473,7 +474,8 @@ class ShowUser(command.ShowOne):
identity_client = self.app.client_manager.identity
user_str = common._get_token_resource(identity_client, 'user',
- parsed_args.user)
+ parsed_args.user,
+ parsed_args.domain)
if parsed_args.domain:
domain = common.find_domain(identity_client, parsed_args.domain)
user = utils.find_resource(identity_client.users,
diff --git a/openstackclient/network/v2/network_agent.py b/openstackclient/network/v2/network_agent.py
index 1334f77e..ed4970a4 100644
--- a/openstackclient/network/v2/network_agent.py
+++ b/openstackclient/network/v2/network_agent.py
@@ -26,10 +26,16 @@ from openstackclient.network import sdk_utils
LOG = logging.getLogger(__name__)
+def _format_alive(alive):
+ return ":-)" if alive else "XXX"
+
+
def _format_admin_state(state):
return 'UP' if state else 'DOWN'
_formatters = {
+ 'is_alive': _format_alive,
+ 'alive': _format_alive,
'admin_state_up': _format_admin_state,
'is_admin_state_up': _format_admin_state,
'configurations': utils.format_dict,
@@ -60,7 +66,7 @@ class AddNetworkToAgent(command.Command):
parser.add_argument(
'network',
metavar='<network>',
- help=_('Network to be added to an agent (ID or name)'))
+ help=_('Network to be added to an agent (name or ID)'))
return parser
@@ -78,6 +84,37 @@ class AddNetworkToAgent(command.Command):
exceptions.CommandError(msg)
+class AddRouterToAgent(command.Command):
+ _description = _("Add router to an agent")
+
+ def get_parser(self, prog_name):
+ parser = super(AddRouterToAgent, self).get_parser(prog_name)
+ parser.add_argument(
+ '--l3',
+ action='store_true',
+ help=_('Add router to an L3 agent')
+ )
+ parser.add_argument(
+ 'agent_id',
+ metavar='<agent-id>',
+ help=_("Agent to which a router is added (ID only)")
+ )
+ parser.add_argument(
+ 'router',
+ metavar='<router>',
+ help=_("Router to be added to an agent (name or ID)")
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ agent = client.get_agent(parsed_args.agent_id)
+ router = client.find_router(parsed_args.router, ignore_missing=False)
+ if parsed_args.l3:
+ client.add_router_to_agent(agent, router)
+
+
class DeleteNetworkAgent(command.Command):
_description = _("Delete network agent(s)")
@@ -135,11 +172,24 @@ class ListNetworkAgent(command.Lister):
metavar='<host>',
help=_("List only agents running on the specified host")
)
- parser.add_argument(
+ agent_type_group = parser.add_mutually_exclusive_group()
+ agent_type_group.add_argument(
'--network',
metavar='<network>',
help=_('List agents hosting a network (name or ID)')
)
+ agent_type_group.add_argument(
+ '--router',
+ metavar='<router>',
+ help=_('List agents hosting this router (name or ID)')
+ )
+ parser.add_argument(
+ '--long',
+ action='store_true',
+ default=False,
+ help=_("List additional fields in output")
+ )
+
return parser
def take_action(self, parsed_args):
@@ -178,28 +228,18 @@ class ListNetworkAgent(command.Lister):
}
filters = {}
+
if parsed_args.network is not None:
- columns = (
- 'id',
- 'host',
- 'is_admin_state_up',
- 'is_alive',
- )
- column_headers = (
- 'ID',
- 'Host',
- 'Admin State Up',
- 'Alive',
- )
network = client.find_network(
parsed_args.network, ignore_missing=False)
data = client.network_hosting_dhcp_agents(network)
-
- return (column_headers,
- (utils.get_item_properties(
- s, columns,
- formatters=_formatters,
- ) for s in data))
+ elif parsed_args.router is not None:
+ if parsed_args.long:
+ columns += ('ha_state',)
+ column_headers += ('HA State',)
+ router = client.find_router(parsed_args.router,
+ ignore_missing=False)
+ data = client.routers_hosting_l3_agents(router)
else:
if parsed_args.agent_type is not None:
filters['agent_type'] = key_value[parsed_args.agent_type]
@@ -207,10 +247,10 @@ class ListNetworkAgent(command.Lister):
filters['host'] = parsed_args.host
data = client.agents(**filters)
- return (column_headers,
- (utils.get_item_properties(
- s, columns, formatters=_formatters,
- ) for s in data))
+ return (column_headers,
+ (utils.get_item_properties(
+ s, columns, formatters=_formatters,
+ ) for s in data))
class RemoveNetworkFromAgent(command.Command):
@@ -229,7 +269,7 @@ class RemoveNetworkFromAgent(command.Command):
parser.add_argument(
'network',
metavar='<network>',
- help=_('Network to be removed from an agent (ID or name)'))
+ help=_('Network to be removed from an agent (name or ID)'))
return parser
def take_action(self, parsed_args):
@@ -246,6 +286,37 @@ class RemoveNetworkFromAgent(command.Command):
exceptions.CommandError(msg)
+class RemoveRouterFromAgent(command.Command):
+ _description = _("Remove router from an agent")
+
+ def get_parser(self, prog_name):
+ parser = super(RemoveRouterFromAgent, self).get_parser(prog_name)
+ parser.add_argument(
+ '--l3',
+ action='store_true',
+ help=_('Remove router from an L3 agent')
+ )
+ parser.add_argument(
+ 'agent_id',
+ metavar='<agent-id>',
+ help=_("Agent from which router will be removed (ID only)")
+ )
+ parser.add_argument(
+ 'router',
+ metavar='<router>',
+ help=_("Router to be removed from an agent (name or ID)")
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ agent = client.get_agent(parsed_args.agent_id)
+ router = client.find_router(parsed_args.router, ignore_missing=False)
+ if parsed_args.l3:
+ client.remove_router_from_agent(agent, router)
+
+
# TODO(huanxuan): Use the SDK resource mapped attribute names once the
# OSC minimum requirements include SDK 1.0.
class SetNetworkAgent(command.Command):
diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py
index 0da91baa..8db0c439 100644
--- a/openstackclient/network/v2/router.py
+++ b/openstackclient/network/v2/router.py
@@ -305,11 +305,18 @@ class ListRouter(command.Lister):
help=_("List routers according to their project (name or ID)")
)
identity_common.add_project_domain_option_to_parser(parser)
+ parser.add_argument(
+ '--agent',
+ metavar='<agent-id>',
+ help=_("List routers hosted by an agent (ID only)")
+ )
+
return parser
def take_action(self, parsed_args):
identity_client = self.app.client_manager.identity
client = self.app.client_manager.network
+
columns = (
'id',
'name',
@@ -349,6 +356,16 @@ class ListRouter(command.Lister):
).id
args['tenant_id'] = project_id
args['project_id'] = project_id
+
+ if parsed_args.agent is not None:
+ agent = client.get_agent(parsed_args.agent)
+ data = client.agent_hosted_routers(agent)
+ # NOTE: Networking API does not support filtering by parameters,
+ # so we need filtering in the client side.
+ data = [d for d in data if self._filter_match(d, args)]
+ else:
+ data = client.routers(**args)
+
if parsed_args.long:
columns = columns + (
'routes',
@@ -368,13 +385,26 @@ class ListRouter(command.Lister):
'Availability zones',
)
- data = client.routers(**args)
return (column_headers,
(utils.get_item_properties(
s, columns,
formatters=_formatters,
) for s in data))
+ @staticmethod
+ def _filter_match(data, conditions):
+ for key, value in conditions.items():
+ try:
+ if getattr(data, key) != value:
+ return False
+ except AttributeError:
+ # Some filter attributes like tenant_id or admin_state_up
+ # are backward compatibility in older OpenStack SDK support.
+ # They does not exist in the latest release.
+ # In this case we just skip checking such filter condition.
+ continue
+ return True
+
class RemovePortFromRouter(command.Command):
_description = _("Remove a port from a router")
diff --git a/openstackclient/tests/functional/network/v2/test_floating_ip.py b/openstackclient/tests/functional/network/v2/test_floating_ip.py
index 96521f09..9e34622c 100644
--- a/openstackclient/tests/functional/network/v2/test_floating_ip.py
+++ b/openstackclient/tests/functional/network/v2/test_floating_ip.py
@@ -19,17 +19,18 @@ from openstackclient.tests.functional.network.v2 import common
class FloatingIpTests(common.NetworkTests):
"""Functional tests for floating ip"""
- EXTERNAL_NETWORK_NAME = uuid.uuid4().hex
- EXTERNAL_SUBNET_NAME = uuid.uuid4().hex
- PRIVATE_NETWORK_NAME = uuid.uuid4().hex
- PRIVATE_SUBNET_NAME = uuid.uuid4().hex
- ROUTER = uuid.uuid4().hex
- PORT_NAME = uuid.uuid4().hex
@classmethod
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
+ cls.EXTERNAL_NETWORK_NAME = uuid.uuid4().hex
+ cls.EXTERNAL_SUBNET_NAME = uuid.uuid4().hex
+ cls.PRIVATE_NETWORK_NAME = uuid.uuid4().hex
+ cls.PRIVATE_SUBNET_NAME = uuid.uuid4().hex
+ cls.ROUTER = uuid.uuid4().hex
+ cls.PORT_NAME = uuid.uuid4().hex
+
# Create a network for the floating ip
json_output = json.loads(cls.openstack(
'network create -f json ' +
diff --git a/openstackclient/tests/functional/network/v2/test_ip_availability.py b/openstackclient/tests/functional/network/v2/test_ip_availability.py
index 1aa0f64a..cb4b8150 100644
--- a/openstackclient/tests/functional/network/v2/test_ip_availability.py
+++ b/openstackclient/tests/functional/network/v2/test_ip_availability.py
@@ -23,9 +23,10 @@ class IPAvailabilityTests(common.NetworkTests):
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
- # Create a network for the subnet.
cls.NAME = uuid.uuid4().hex
cls.NETWORK_NAME = uuid.uuid4().hex
+
+ # Create a network for the subnet
cls.openstack(
'network create ' +
cls.NETWORK_NAME
diff --git a/openstackclient/tests/functional/network/v2/test_network_agent.py b/openstackclient/tests/functional/network/v2/test_network_agent.py
index 16487955..0c74ea1d 100644
--- a/openstackclient/tests/functional/network/v2/test_network_agent.py
+++ b/openstackclient/tests/functional/network/v2/test_network_agent.py
@@ -137,3 +137,39 @@ class NetworkAgentListTests(common.NetworkTests):
self.assertIn(
agent_id, col_name
)
+
+ def test_network_agent_list_routers(self):
+ """Add agent to router, list agents on router, delete."""
+ name = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'router create -f json ' + name))
+
+ self.addCleanup(self.openstack, 'router delete ' + name)
+ # Get router ID
+ router_id = cmd_output['id']
+ # Get l3 agent id
+ cmd_output = json.loads(self.openstack(
+ 'network agent list -f json --agent-type l3'))
+
+ # Check at least one L3 agent is included in the response.
+ self.assertTrue(cmd_output)
+ agent_id = cmd_output[0]['ID']
+
+ # Add router to agent
+ self.openstack(
+ 'network agent add router --l3 ' + agent_id + ' ' + router_id)
+
+ # Test router list --agent
+ cmd_output = json.loads(self.openstack(
+ 'network agent list -f json --router ' + router_id))
+
+ agent_ids = [x['ID'] for x in cmd_output]
+ self.assertIn(agent_id, agent_ids)
+
+ # Remove router from agent
+ self.openstack(
+ 'network agent remove router --l3 ' + agent_id + ' ' + router_id)
+ cmd_output = json.loads(self.openstack(
+ 'network agent list -f json --router ' + router_id))
+ agent_ids = [x['ID'] for x in cmd_output]
+ self.assertNotIn(agent_id, agent_ids)
diff --git a/openstackclient/tests/functional/network/v2/test_network_meter_rule.py b/openstackclient/tests/functional/network/v2/test_network_meter_rule.py
index b7090707..71b406b4 100644
--- a/openstackclient/tests/functional/network/v2/test_network_meter_rule.py
+++ b/openstackclient/tests/functional/network/v2/test_network_meter_rule.py
@@ -22,7 +22,6 @@ from openstackclient.tests.functional.network.v2 import common
class TestMeterRule(common.NetworkTests):
"""Functional tests for meter rule"""
- METER_NAME = uuid.uuid4().hex
METER_ID = None
METER_RULE_ID = None
@@ -30,6 +29,8 @@ class TestMeterRule(common.NetworkTests):
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
+ cls.METER_NAME = uuid.uuid4().hex
+
json_output = json.loads(cls.openstack(
'network meter create -f json ' +
cls.METER_NAME
diff --git a/openstackclient/tests/functional/network/v2/test_network_qos_policy.py b/openstackclient/tests/functional/network/v2/test_network_qos_policy.py
index ac3e0fc6..ccbf437c 100644
--- a/openstackclient/tests/functional/network/v2/test_network_qos_policy.py
+++ b/openstackclient/tests/functional/network/v2/test_network_qos_policy.py
@@ -19,8 +19,7 @@ from openstackclient.tests.functional.network.v2 import common
class NetworkQosPolicyTests(common.NetworkTests):
- """Functional tests for QoS policy. """
- NAME = uuid.uuid4().hex
+ """Functional tests for QoS policy"""
HEADERS = ['Name']
FIELDS = ['name']
@@ -28,6 +27,8 @@ class NetworkQosPolicyTests(common.NetworkTests):
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
+ cls.NAME = uuid.uuid4().hex
+
opts = cls.get_opts(cls.FIELDS)
raw_output = cls.openstack(
'network qos policy create ' +
diff --git a/openstackclient/tests/functional/network/v2/test_network_qos_rule.py b/openstackclient/tests/functional/network/v2/test_network_qos_rule.py
index 056bc1f6..6e40d8e0 100644
--- a/openstackclient/tests/functional/network/v2/test_network_qos_rule.py
+++ b/openstackclient/tests/functional/network/v2/test_network_qos_rule.py
@@ -21,7 +21,6 @@ from openstackclient.tests.functional.network.v2 import common
class NetworkQosRuleTestsMinimumBandwidth(common.NetworkTests):
"""Functional tests for QoS minimum bandwidth rule"""
RULE_ID = None
- QOS_POLICY_NAME = 'qos_policy_' + uuid.uuid4().hex
MIN_KBPS = 2800
MIN_KBPS_MODIFIED = 7500
DIRECTION = '--egress'
@@ -33,6 +32,8 @@ class NetworkQosRuleTestsMinimumBandwidth(common.NetworkTests):
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
+ cls.QOS_POLICY_NAME = 'qos_policy_' + uuid.uuid4().hex
+
opts = cls.get_opts(cls.FIELDS)
cls.openstack(
'network qos policy create ' +
diff --git a/openstackclient/tests/functional/network/v2/test_network_rbac.py b/openstackclient/tests/functional/network/v2/test_network_rbac.py
index 0d5492e5..893f1993 100644
--- a/openstackclient/tests/functional/network/v2/test_network_rbac.py
+++ b/openstackclient/tests/functional/network/v2/test_network_rbac.py
@@ -16,9 +16,7 @@ from openstackclient.tests.functional.network.v2 import common
class NetworkRBACTests(common.NetworkTests):
- """Functional tests for network rbac. """
- NET_NAME = uuid.uuid4().hex
- PROJECT_NAME = uuid.uuid4().hex
+ """Functional tests for network rbac"""
OBJECT_ID = None
ID = None
HEADERS = ['ID']
@@ -28,6 +26,9 @@ class NetworkRBACTests(common.NetworkTests):
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
+ cls.NET_NAME = uuid.uuid4().hex
+ cls.PROJECT_NAME = uuid.uuid4().hex
+
opts = cls.get_opts(cls.FIELDS)
raw_output = cls.openstack(
'network create ' + cls.NET_NAME + opts
diff --git a/openstackclient/tests/functional/network/v2/test_network_segment.py b/openstackclient/tests/functional/network/v2/test_network_segment.py
index 7fc79746..6dec82d9 100644
--- a/openstackclient/tests/functional/network/v2/test_network_segment.py
+++ b/openstackclient/tests/functional/network/v2/test_network_segment.py
@@ -17,8 +17,6 @@ from openstackclient.tests.functional.network.v2 import common
class NetworkSegmentTests(common.NetworkTests):
"""Functional tests for network segment"""
- NETWORK_NAME = uuid.uuid4().hex
- PHYSICAL_NETWORK_NAME = uuid.uuid4().hex
NETWORK_SEGMENT_ID = None
NETWORK_ID = None
NETWORK_SEGMENT_EXTENSION = None
@@ -27,7 +25,10 @@ class NetworkSegmentTests(common.NetworkTests):
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
- # Create a network for the segment.
+ cls.NETWORK_NAME = uuid.uuid4().hex
+ cls.PHYSICAL_NETWORK_NAME = uuid.uuid4().hex
+
+ # Create a network for the segment
opts = cls.get_opts(['id'])
raw_output = cls.openstack(
'network create ' + cls.NETWORK_NAME + opts
diff --git a/openstackclient/tests/functional/network/v2/test_port.py b/openstackclient/tests/functional/network/v2/test_port.py
index 6659e3e0..14454454 100644
--- a/openstackclient/tests/functional/network/v2/test_port.py
+++ b/openstackclient/tests/functional/network/v2/test_port.py
@@ -18,14 +18,15 @@ from openstackclient.tests.functional.network.v2 import common
class PortTests(common.NetworkTests):
"""Functional tests for port"""
- NAME = uuid.uuid4().hex
- NETWORK_NAME = uuid.uuid4().hex
@classmethod
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
- # Create a network for the port
+ cls.NAME = uuid.uuid4().hex
+ cls.NETWORK_NAME = uuid.uuid4().hex
+
+ # Create a network for the port tests
cls.openstack(
'network create ' + cls.NETWORK_NAME
)
diff --git a/openstackclient/tests/functional/network/v2/test_router.py b/openstackclient/tests/functional/network/v2/test_router.py
index 313feefc..2e5cb5ef 100644
--- a/openstackclient/tests/functional/network/v2/test_router.py
+++ b/openstackclient/tests/functional/network/v2/test_router.py
@@ -151,6 +151,40 @@ class RouterTests(common.NetworkTests):
self.assertIn(name1, names)
self.assertIn(name2, names)
+ def test_router_list_l3_agent(self):
+ """Tests create router, add l3 agent, list, delete"""
+ name = uuid.uuid4().hex
+ cmd_output = json.loads(self.openstack(
+ 'router create -f json ' + name))
+
+ self.addCleanup(self.openstack, 'router delete ' + name)
+ # Get router ID
+ router_id = cmd_output['id']
+ # Get l3 agent id
+ cmd_output = json.loads(self.openstack(
+ 'network agent list -f json --agent-type l3'))
+
+ # Check at least one L3 agent is included in the response.
+ self.assertTrue(cmd_output)
+ agent_id = cmd_output[0]['ID']
+
+ # Add router to agent
+ self.openstack(
+ 'network agent add router --l3 ' + agent_id + ' ' + router_id)
+
+ cmd_output = json.loads(self.openstack(
+ 'router list -f json --agent ' + agent_id))
+ router_ids = [x['ID'] for x in cmd_output]
+ self.assertIn(router_id, router_ids)
+
+ # Remove router from agent
+ self.openstack(
+ 'network agent remove router --l3 ' + agent_id + ' ' + router_id)
+ cmd_output = json.loads(self.openstack(
+ 'router list -f json --agent ' + agent_id))
+ router_ids = [x['ID'] for x in cmd_output]
+ self.assertNotIn(router_id, router_ids)
+
def test_router_set_show_unset(self):
"""Tests create router, set, unset, show"""
diff --git a/openstackclient/tests/functional/network/v2/test_security_group.py b/openstackclient/tests/functional/network/v2/test_security_group.py
index 2a9c0b0a..6da7e204 100644
--- a/openstackclient/tests/functional/network/v2/test_security_group.py
+++ b/openstackclient/tests/functional/network/v2/test_security_group.py
@@ -17,8 +17,6 @@ from openstackclient.tests.functional.network.v2 import common
class SecurityGroupTests(common.NetworkTests):
"""Functional tests for security group"""
- NAME = uuid.uuid4().hex
- OTHER_NAME = uuid.uuid4().hex
HEADERS = ['Name']
FIELDS = ['name']
@@ -26,6 +24,9 @@ class SecurityGroupTests(common.NetworkTests):
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
+ cls.NAME = uuid.uuid4().hex
+ cls.OTHER_NAME = uuid.uuid4().hex
+
opts = cls.get_opts(cls.FIELDS)
raw_output = cls.openstack(
'security group create ' +
diff --git a/openstackclient/tests/functional/network/v2/test_security_group_rule.py b/openstackclient/tests/functional/network/v2/test_security_group_rule.py
index 93f98642..e153116b 100644
--- a/openstackclient/tests/functional/network/v2/test_security_group_rule.py
+++ b/openstackclient/tests/functional/network/v2/test_security_group_rule.py
@@ -17,7 +17,6 @@ from openstackclient.tests.functional.network.v2 import common
class SecurityGroupRuleTests(common.NetworkTests):
"""Functional tests for security group rule"""
- SECURITY_GROUP_NAME = uuid.uuid4().hex
SECURITY_GROUP_RULE_ID = None
NAME_FIELD = ['name']
ID_FIELD = ['id']
@@ -27,7 +26,9 @@ class SecurityGroupRuleTests(common.NetworkTests):
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
- # Create the security group to hold the rule.
+ cls.SECURITY_GROUP_NAME = uuid.uuid4().hex
+
+ # Create the security group to hold the rule
opts = cls.get_opts(cls.NAME_FIELD)
raw_output = cls.openstack(
'security group create ' +
diff --git a/openstackclient/tests/functional/network/v2/test_subnet.py b/openstackclient/tests/functional/network/v2/test_subnet.py
index 93e0593d..41375415 100644
--- a/openstackclient/tests/functional/network/v2/test_subnet.py
+++ b/openstackclient/tests/functional/network/v2/test_subnet.py
@@ -24,8 +24,9 @@ class SubnetTests(common.NetworkTests):
def setUpClass(cls):
common.NetworkTests.setUpClass()
if cls.haz_network:
- # Create a network for the all subnet tests
cls.NETWORK_NAME = uuid.uuid4().hex
+
+ # Create a network for the all subnet tests
cmd_output = json.loads(cls.openstack(
'network create -f json ' +
cls.NETWORK_NAME
diff --git a/openstackclient/tests/unit/compute/v2/test_server.py b/openstackclient/tests/unit/compute/v2/test_server.py
index 084171ac..b02b1491 100644
--- a/openstackclient/tests/unit/compute/v2/test_server.py
+++ b/openstackclient/tests/unit/compute/v2/test_server.py
@@ -395,6 +395,8 @@ class TestServerCreate(TestServer):
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist(), data)
+ self.assertFalse(self.images_mock.called)
+ self.assertFalse(self.flavors_mock.called)
def test_server_create_with_options(self):
arglist = [
@@ -1439,7 +1441,8 @@ class TestServerList(TestServer):
'Name',
'Status',
'Networks',
- 'Image Name',
+ 'Image',
+ 'Flavor',
)
columns_long = (
'ID',
@@ -1515,6 +1518,7 @@ class TestServerList(TestServer):
# Prepare data returned by fake Nova API.
self.data = []
self.data_long = []
+ self.data_no_name_lookup = []
Image = collections.namedtuple('Image', 'id name')
self.images_mock.list.return_value = [
@@ -1535,6 +1539,7 @@ class TestServerList(TestServer):
s.status,
server._format_servers_list_networks(s.networks),
self.image.name,
+ self.flavor.name,
))
self.data_long.append((
s.id,
@@ -1553,6 +1558,14 @@ class TestServerList(TestServer):
getattr(s, 'OS-EXT-SRV-ATTR:host'),
s.Metadata,
))
+ self.data_no_name_lookup.append((
+ s.id,
+ s.name,
+ s.status,
+ server._format_servers_list_networks(s.networks),
+ s.image['id'],
+ s.flavor['id']
+ ))
def test_server_list_no_option(self):
arglist = []
@@ -1585,6 +1598,38 @@ class TestServerList(TestServer):
self.assertEqual(self.columns_long, columns)
self.assertEqual(tuple(self.data_long), tuple(data))
+ def test_server_list_no_name_lookup_option(self):
+ arglist = [
+ '--no-name-lookup',
+ ]
+ verifylist = [
+ ('all_projects', False),
+ ('no_name_lookup', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.list.assert_called_with(**self.kwargs)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data_no_name_lookup), tuple(data))
+
+ def test_server_list_n_option(self):
+ arglist = [
+ '-n',
+ ]
+ verifylist = [
+ ('all_projects', False),
+ ('no_name_lookup', True),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.servers_mock.list.assert_called_with(**self.kwargs)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(tuple(self.data_no_name_lookup), tuple(data))
+
def test_server_list_with_image(self):
arglist = [
diff --git a/openstackclient/tests/unit/identity/v3/test_project.py b/openstackclient/tests/unit/identity/v3/test_project.py
index 7be81153..2ce26c64 100644
--- a/openstackclient/tests/unit/identity/v3/test_project.py
+++ b/openstackclient/tests/unit/identity/v3/test_project.py
@@ -19,6 +19,7 @@ from mock import call
from osc_lib import exceptions
from osc_lib import utils
+from openstackclient.identity import common
from openstackclient.identity.v3 import project
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
@@ -1060,3 +1061,48 @@ class TestProjectShow(TestProject):
['children-id'],
)
self.assertEqual(data, datalist)
+
+ def test_project_show_with_domain(self):
+ project = identity_fakes.FakeProject.create_one_project(
+ {"name": self.project.name})
+
+ self.app.client_manager.identity.tokens.get_token_data.return_value = \
+ {'token':
+ {'project':
+ {'domain': {"id": self.project.domain_id},
+ 'name': self.project.name,
+ 'id': self.project.id
+ }
+ }
+ }
+
+ identity_client = self.app.client_manager.identity
+ arglist = [
+ "--domain", self.domain.id,
+ project.name,
+ ]
+ verifylist = [
+ ('domain', self.domain.id),
+ ('project', project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ project_str = common._get_token_resource(identity_client, 'project',
+ parsed_args.project,
+ parsed_args.domain)
+ self.assertEqual(self.project.id, project_str)
+
+ arglist = [
+ "--domain", project.domain_id,
+ project.name,
+ ]
+ verifylist = [
+ ('domain', project.domain_id),
+ ('project', project.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ project_str = common._get_token_resource(identity_client, 'project',
+ parsed_args.project,
+ parsed_args.domain)
+ self.assertEqual(project.name, project_str)
diff --git a/openstackclient/tests/unit/identity/v3/test_user.py b/openstackclient/tests/unit/identity/v3/test_user.py
index 2ce66e94..96f50766 100644
--- a/openstackclient/tests/unit/identity/v3/test_user.py
+++ b/openstackclient/tests/unit/identity/v3/test_user.py
@@ -19,6 +19,7 @@ import mock
from osc_lib import exceptions
from osc_lib import utils
+from openstackclient.identity import common
from openstackclient.identity.v3 import user
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
@@ -1091,7 +1092,7 @@ class TestUserShow(TestUser):
self.app.client_manager.identity.tokens.get_token_data.return_value = \
{'token':
{'user':
- {'domain': {},
+ {'domain': {'id': self.user.domain_id},
'id': self.user.id,
'name': self.user.name,
}
@@ -1126,3 +1127,38 @@ class TestUserShow(TestUser):
self.user.name,
)
self.assertEqual(datalist, data)
+
+ def test_user_show_with_domain(self):
+ user = identity_fakes.FakeUser.create_one_user(
+ {"name": self.user.name})
+ identity_client = self.app.client_manager.identity
+
+ arglist = [
+ "--domain", self.user.domain_id,
+ user.name,
+ ]
+ verifylist = [
+ ('domain', self.user.domain_id),
+ ('user', user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ user_str = common._get_token_resource(identity_client, 'user',
+ parsed_args.user,
+ parsed_args.domain)
+ self.assertEqual(self.user.id, user_str)
+
+ arglist = [
+ "--domain", user.domain_id,
+ user.name,
+ ]
+ verifylist = [
+ ('domain', user.domain_id),
+ ('user', user.name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ user_str = common._get_token_resource(identity_client, 'user',
+ parsed_args.user,
+ parsed_args.domain)
+ self.assertEqual(user.name, user_str)
diff --git a/openstackclient/tests/unit/network/v2/test_network_agent.py b/openstackclient/tests/unit/network/v2/test_network_agent.py
index 9bb3f090..12e40cdb 100644
--- a/openstackclient/tests/unit/network/v2/test_network_agent.py
+++ b/openstackclient/tests/unit/network/v2/test_network_agent.py
@@ -73,6 +73,46 @@ class TestAddNetworkToAgent(TestNetworkAgent):
self.agent, self.net)
+class TestAddRouterAgent(TestNetworkAgent):
+
+ _router = network_fakes.FakeRouter.create_one_router()
+ _agent = network_fakes.FakeNetworkAgent.create_one_network_agent()
+
+ def setUp(self):
+ super(TestAddRouterAgent, self).setUp()
+ self.network.add_router_to_agent = mock.Mock()
+ self.cmd = network_agent.AddRouterToAgent(self.app, self.namespace)
+ self.network.get_agent = mock.Mock(return_value=self._agent)
+ self.network.find_router = mock.Mock(return_value=self._router)
+
+ def test_add_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Missing agent ID will cause command to bail
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_add_router_required_options(self):
+ arglist = [
+ self._agent.id,
+ self._router.id,
+ '--l3',
+ ]
+ verifylist = [
+ ('l3', True),
+ ('agent_id', self._agent.id),
+ ('router', self._router.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.add_router_to_agent.assert_called_with(
+ self._agent, self._router)
+ self.assertIsNone(result)
+
+
class TestDeleteNetworkAgent(TestNetworkAgent):
network_agents = (
@@ -171,34 +211,16 @@ class TestListNetworkAgent(TestNetworkAgent):
)
data = []
for agent in network_agents:
- agent.agent_type = 'DHCP agent'
data.append((
agent.id,
agent.agent_type,
agent.host,
agent.availability_zone,
- agent.alive,
+ network_agent._format_alive(agent.alive),
network_agent._format_admin_state(agent.admin_state_up),
agent.binary,
))
- network_agent_columns = (
- 'ID',
- 'Host',
- 'Admin State Up',
- 'Alive',
- )
-
- network_agent_data = []
-
- for agent in network_agents:
- network_agent_data.append((
- agent.id,
- agent.host,
- network_agent._format_admin_state(agent.admin_state_up),
- agent.alive,
- ))
-
def setUp(self):
super(TestListNetworkAgent, self).setUp()
self.network.agents = mock.Mock(
@@ -213,6 +235,14 @@ class TestListNetworkAgent(TestNetworkAgent):
self.network.network_hosting_dhcp_agents = mock.Mock(
return_value=self.network_agents)
+ self.network.get_agent = mock.Mock(return_value=_testagent)
+
+ self._testrouter = \
+ network_fakes.FakeRouter.create_one_router()
+ self.network.find_router = mock.Mock(return_value=self._testrouter)
+ self.network.routers_hosting_l3_agents = mock.Mock(
+ return_value=self.network_agents)
+
# Get the command object to test
self.cmd = network_agent.ListNetworkAgent(self.app, self.namespace)
@@ -239,7 +269,7 @@ class TestListNetworkAgent(TestNetworkAgent):
columns, data = self.cmd.take_action(parsed_args)
self.network.agents.assert_called_once_with(**{
- 'agent_type': self.network_agents[0].agent_type,
+ 'agent_type': 'DHCP agent',
})
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
@@ -276,8 +306,53 @@ class TestListNetworkAgent(TestNetworkAgent):
self.network.network_hosting_dhcp_agents.assert_called_once_with(
*attrs)
- self.assertEqual(self.network_agent_columns, columns)
- self.assertEqual(list(self.network_agent_data), list(data))
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_network_agents_list_routers(self):
+ arglist = [
+ '--router', self._testrouter.id,
+ ]
+ verifylist = [
+ ('router', self._testrouter.id),
+ ('long', False)
+ ]
+
+ attrs = {self._testrouter, }
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.routers_hosting_l3_agents.assert_called_once_with(
+ *attrs)
+
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
+ def test_network_agents_list_routers_with_long_option(self):
+ arglist = [
+ '--router', self._testrouter.id,
+ '--long',
+ ]
+ verifylist = [
+ ('router', self._testrouter.id),
+ ('long', True)
+ ]
+
+ attrs = {self._testrouter, }
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.routers_hosting_l3_agents.assert_called_once_with(
+ *attrs)
+
+ # Add a column 'HA State' and corresponding data.
+ router_agent_columns = self.columns + ('HA State',)
+ router_agent_data = [d + ('',) for d in self.data]
+
+ self.assertEqual(router_agent_columns, columns)
+ self.assertEqual(router_agent_data, list(data))
class TestRemoveNetworkFromAgent(TestNetworkAgent):
@@ -303,6 +378,16 @@ class TestRemoveNetworkFromAgent(TestNetworkAgent):
self.assertRaises(tests_utils.ParserException, self.check_parser,
self.cmd, arglist, verifylist)
+ def test_network_agents_list_routers_no_arg(self):
+ arglist = [
+ '--routers',
+ ]
+ verifylist = []
+
+ # Missing required args should bail here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
def test_network_from_dhcp_agent(self):
arglist = [
'--dhcp',
@@ -322,6 +407,46 @@ class TestRemoveNetworkFromAgent(TestNetworkAgent):
self.agent, self.net)
+class TestRemoveRouterAgent(TestNetworkAgent):
+ _router = network_fakes.FakeRouter.create_one_router()
+ _agent = network_fakes.FakeNetworkAgent.create_one_network_agent()
+
+ def setUp(self):
+ super(TestRemoveRouterAgent, self).setUp()
+ self.network.remove_router_from_agent = mock.Mock()
+ self.cmd = network_agent.RemoveRouterFromAgent(self.app,
+ self.namespace)
+ self.network.get_agent = mock.Mock(return_value=self._agent)
+ self.network.find_router = mock.Mock(return_value=self._router)
+
+ def test_remove_no_options(self):
+ arglist = []
+ verifylist = []
+
+ # Missing agent ID will cause command to bail
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_remove_router_required_options(self):
+ arglist = [
+ '--l3',
+ self._agent.id,
+ self._router.id,
+ ]
+ verifylist = [
+ ('l3', True),
+ ('agent_id', self._agent.id),
+ ('router', self._router.id),
+ ]
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ result = self.cmd.take_action(parsed_args)
+
+ self.network.remove_router_from_agent.assert_called_with(
+ self._agent, self._router)
+ self.assertIsNone(result)
+
+
class TestSetNetworkAgent(TestNetworkAgent):
_network_agent = (
@@ -415,9 +540,9 @@ class TestShowNetworkAgent(TestNetworkAgent):
'id',
)
data = (
- network_agent._format_admin_state(_network_agent.admin_state_up),
+ network_agent._format_admin_state(_network_agent.is_admin_state_up),
_network_agent.agent_type,
- _network_agent.alive,
+ network_agent._format_alive(_network_agent.is_alive),
_network_agent.availability_zone,
_network_agent.binary,
utils.format_dict(_network_agent.configurations),
diff --git a/openstackclient/tests/unit/network/v2/test_router.py b/openstackclient/tests/unit/network/v2/test_router.py
index 02e0be94..c153fe4a 100644
--- a/openstackclient/tests/unit/network/v2/test_router.py
+++ b/openstackclient/tests/unit/network/v2/test_router.py
@@ -381,6 +381,21 @@ class TestListRouter(TestRouter):
r.ha,
r.tenant_id,
))
+
+ router_agent_data = []
+ for r in routers:
+ router_agent_data.append((
+ r.id,
+ r.name,
+ r.external_gateway_info,
+ ))
+
+ agents_columns = (
+ 'ID',
+ 'Name',
+ 'External Gateway Info',
+ )
+
data_long = []
for i in range(0, len(routers)):
r = routers[i]
@@ -407,8 +422,15 @@ class TestListRouter(TestRouter):
# Get the command object to test
self.cmd = router.ListRouter(self.app, self.namespace)
+ self.network.agent_hosted_routers = mock.Mock(
+ return_value=self.routers)
self.network.routers = mock.Mock(return_value=self.routers)
self.network.find_extension = mock.Mock(return_value=self._extensions)
+ self.network.find_router = mock.Mock(return_value=self.routers[0])
+ self._testagent = \
+ network_fakes.FakeNetworkAgent.create_one_network_agent()
+ self.network.get_agent = mock.Mock(return_value=self._testagent)
+ self.network.get_router = mock.Mock(return_value=self.routers[0])
def test_router_list_no_options(self):
arglist = []
@@ -556,6 +578,34 @@ class TestListRouter(TestRouter):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
+ def test_router_list_agents_no_args(self):
+ arglist = [
+ '--agents',
+ ]
+ verifylist = []
+
+ # Missing required router ID should bail here
+ self.assertRaises(tests_utils.ParserException, self.check_parser,
+ self.cmd, arglist, verifylist)
+
+ def test_router_list_agents(self):
+ arglist = [
+ '--agent', self._testagent.id,
+ ]
+ verifylist = [
+ ('agent', self._testagent.id),
+ ]
+
+ attrs = {self._testagent.id, }
+
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.network.agent_hosted_routers(
+ *attrs)
+ self.assertEqual(self.columns, columns)
+ self.assertEqual(self.data, list(data))
+
class TestRemovePortFromRouter(TestRouter):
'''Remove port from a Router '''
diff --git a/releasenotes/notes/bp-network-l3-adv-commands-cc1df715a184f1b2.yaml b/releasenotes/notes/bp-network-l3-adv-commands-cc1df715a184f1b2.yaml
new file mode 100644
index 00000000..f978f4d6
--- /dev/null
+++ b/releasenotes/notes/bp-network-l3-adv-commands-cc1df715a184f1b2.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ Add network l3-agent related commands ``network agent add router``,
+ ``network agent remove router`` for adding/removing routers to l3 agents.
+ Add ``network agent list --router``, and ``router list --agent`` for
+ listing agents on routers and routers on specific agents.
+ [Blueprint :oscbp:`network-l3-commands`]
diff --git a/releasenotes/notes/bug-1704097-8ff1ce1444b81b04.yaml b/releasenotes/notes/bug-1704097-8ff1ce1444b81b04.yaml
new file mode 100644
index 00000000..c20d0c99
--- /dev/null
+++ b/releasenotes/notes/bug-1704097-8ff1ce1444b81b04.yaml
@@ -0,0 +1,9 @@
+---
+fixes:
+ - |
+ Fix an issue when run commands `project show`, `user show` and `user set`
+ with `--domain` specific, the domain filter won't work if the login user's
+ project name or user name is same with the resource name user hoping to
+ get.
+
+ [Bug `1704097 <https://bugs.launchpad.net/python-openstackclient/+bug/1704097>`_]
diff --git a/releasenotes/notes/skip-name-lookups-9f499927173c1eee.yaml b/releasenotes/notes/skip-name-lookups-9f499927173c1eee.yaml
new file mode 100644
index 00000000..69ca0f99
--- /dev/null
+++ b/releasenotes/notes/skip-name-lookups-9f499927173c1eee.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add ``--no-name-lookup`` option to ``server list`` command to skip the lookup of
+ flavor and image names. This can save a significant amount of time on clouds with
+ a large number of images. ``-n`` is an alias for this option.
diff --git a/setup.cfg b/setup.cfg
index 73a9c42c..16917e50 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -365,9 +365,11 @@ openstack.network.v2 =
ip_floating_pool_list = openstackclient.network.v2.floating_ip_pool:ListIPFloatingPool
network_agent_add_network = openstackclient.network.v2.network_agent:AddNetworkToAgent
+ network_agent_add_router = openstackclient.network.v2.network_agent:AddRouterToAgent
network_agent_delete = openstackclient.network.v2.network_agent:DeleteNetworkAgent
network_agent_list = openstackclient.network.v2.network_agent:ListNetworkAgent
network_agent_remove_network = openstackclient.network.v2.network_agent:RemoveNetworkFromAgent
+ network_agent_remove_router = openstackclient.network.v2.network_agent:RemoveRouterFromAgent
network_agent_set = openstackclient.network.v2.network_agent:SetNetworkAgent
network_agent_show = openstackclient.network.v2.network_agent:ShowNetworkAgent
diff --git a/test-requirements.txt b/test-requirements.txt
index 411dc877..4ab3250e 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -17,7 +17,7 @@ os-client-config>=1.27.0 # Apache-2.0
os-testr>=0.8.0 # Apache-2.0
testrepository>=0.0.18 # Apache-2.0/BSD
testtools>=1.4.0 # MIT
-tempest>=14.0.0 # Apache-2.0
+tempest>=16.1.0 # Apache-2.0
osprofiler>=1.4.0 # Apache-2.0
bandit>=1.1.0 # Apache-2.0
wrapt>=1.7.0 # BSD License
@@ -29,7 +29,7 @@ python-barbicanclient>=4.0.0 # Apache-2.0
python-congressclient<2000,>=1.3.0 # Apache-2.0
python-designateclient>=1.5.0 # Apache-2.0
python-heatclient>=1.6.1 # Apache-2.0
-python-ironicclient>=1.11.0 # Apache-2.0
+python-ironicclient>=1.14.0 # Apache-2.0
python-ironic-inspector-client>=1.5.0 # Apache-2.0
python-karborclient>=0.2.0 # Apache-2.0
python-mistralclient>=3.1.0 # Apache-2.0