diff options
Diffstat (limited to 'openstackclient/network/v2')
25 files changed, 828 insertions, 40 deletions
diff --git a/openstackclient/network/v2/floating_ip.py b/openstackclient/network/v2/floating_ip.py index 4c03074d..22096bc4 100644 --- a/openstackclient/network/v2/floating_ip.py +++ b/openstackclient/network/v2/floating_ip.py @@ -28,7 +28,7 @@ _formatters = { def _get_network_columns(item): column_map = {} - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/floating_ip_port_forwarding.py b/openstackclient/network/v2/floating_ip_port_forwarding.py index cd71c05a..0156af8e 100644 --- a/openstackclient/network/v2/floating_ip_port_forwarding.py +++ b/openstackclient/network/v2/floating_ip_port_forwarding.py @@ -82,7 +82,7 @@ def validate_port(port): def _get_columns(item): column_map = {} - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/l3_conntrack_helper.py b/openstackclient/network/v2/l3_conntrack_helper.py index 1de5b785..df153dd8 100644 --- a/openstackclient/network/v2/l3_conntrack_helper.py +++ b/openstackclient/network/v2/l3_conntrack_helper.py @@ -26,7 +26,7 @@ LOG = logging.getLogger(__name__) def _get_columns(item): column_map = {} - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/local_ip.py b/openstackclient/network/v2/local_ip.py index 08735553..e8fb5f8a 100644 --- a/openstackclient/network/v2/local_ip.py +++ b/openstackclient/network/v2/local_ip.py @@ -29,7 +29,7 @@ LOG = logging.getLogger(__name__) def _get_columns(item): column_map = {} - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, hidden_columns) diff --git a/openstackclient/network/v2/local_ip_association.py b/openstackclient/network/v2/local_ip_association.py index 9e123f05..4cd7707a 100644 --- a/openstackclient/network/v2/local_ip_association.py +++ b/openstackclient/network/v2/local_ip_association.py @@ -29,7 +29,7 @@ LOG = logging.getLogger(__name__) def _get_columns(item): column_map = {} - hidden_columns = ['location', 'name', 'id'] + hidden_columns = ['location', 'name', 'id', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, hidden_columns) diff --git a/openstackclient/network/v2/ndp_proxy.py b/openstackclient/network/v2/ndp_proxy.py new file mode 100644 index 00000000..25b287f3 --- /dev/null +++ b/openstackclient/network/v2/ndp_proxy.py @@ -0,0 +1,269 @@ +# Copyright (c) 2020 Troila. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +"""Router NDP proxy action implementations""" +import logging + +from osc_lib.command import command +from osc_lib import exceptions +from osc_lib import utils + +from openstackclient.i18n import _ +from openstackclient.identity import common as identity_common + + +LOG = logging.getLogger(__name__) + + +def _get_columns(item): + column_map = {} + hidden_columns = ['location'] + return utils.get_osc_show_columns_for_sdk_resource( + item, column_map, hidden_columns) + + +class CreateNDPProxy(command.ShowOne): + _description = _("Create NDP proxy") + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + 'router', + metavar='<router>', + help=_("The name or ID of a router")) + parser.add_argument( + '--name', + metavar='<name>', + help=_("New NDP proxy name") + ) + parser.add_argument( + '--port', + metavar='<port>', + required=True, + help=_("The name or ID of the network port associated " + "to the NDP proxy")) + parser.add_argument( + '--ip-address', + metavar='<ip-address>', + help=_("The IPv6 address that is to be proxied. In case the port " + "has multiple addresses assigned, use this option to " + "select which address is to be used.")) + parser.add_argument( + '--description', + metavar='<description>', + help=_("A text to describe/contextualize the use of the " + "NDP proxy configuration") + ) + + return parser + + def take_action(self, parsed_args): + attrs = {'name': parsed_args.name} + client = self.app.client_manager.network + router = client.find_router( + parsed_args.router, + ignore_missing=False, + ) + attrs['router_id'] = router.id + + if parsed_args.ip_address: + attrs['ip_address'] = parsed_args.ip_address + + port = client.find_port(parsed_args.port, + ignore_missing=False) + attrs['port_id'] = port.id + + if parsed_args.description is not None: + attrs['description'] = parsed_args.description + + obj = client.create_ndp_proxy(**attrs) + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + return (display_columns, data) + + +class DeleteNDPProxy(command.Command): + _description = _("Delete NDP proxy") + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + 'ndp_proxy', + nargs="+", + metavar="<ndp-proxy>", + help=_("NDP proxy(s) to delete (name or ID)") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + result = 0 + + for ndp_proxy in parsed_args.ndp_proxy: + try: + obj = client.find_ndp_proxy(ndp_proxy, ignore_missing=False) + client.delete_ndp_proxy(obj) + except Exception as e: + result += 1 + LOG.error(_("Failed to delete NDP proxy " + "'%(ndp_proxy)s': %(e)s"), + {'ndp_proxy': ndp_proxy, 'e': e}) + if result > 0: + total = len(parsed_args.ndp_proxy) + msg = (_("%(result)s of %(total)s NDP Proxy failed " + "to delete.") % {'result': result, 'total': total}) + raise exceptions.CommandError(msg) + + +class ListNDPProxy(command.Lister): + _description = _("List NDP proxies") + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + '--router', + metavar='<router>', + help=_("List only NDP proxies belong to this router (name or ID)") + ) + parser.add_argument( + '--port', + metavar='<port>', + help=_("List only NDP proxies assocate to this port (name or ID)") + ) + parser.add_argument( + '--ip-address', + metavar='ip-address', + help=_("List only NDP proxies according to their IPv6 address") + ) + parser.add_argument( + '--project', + metavar='<project>', + help=_("List NDP proxies according to their project (name or ID)") + ) + parser.add_argument( + '--name', + metavar='<name>', + help=_("List NDP proxies according to their name") + ) + + identity_common.add_project_domain_option_to_parser(parser) + + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + identity_client = self.app.client_manager.identity + + columns = ( + 'id', + 'name', + 'router_id', + 'ip_address', + 'project_id', + ) + headers = ( + 'ID', + 'Name', + 'Router ID', + 'IP Address', + 'Project', + ) + + query = {} + + if parsed_args.router: + router = client.find_router(parsed_args.router, + ignore_missing=False) + query['router_id'] = router.id + if parsed_args.port: + port = client.find_port(parsed_args.port, + ignore_missing=False) + query['port_id'] = port.id + if parsed_args.ip_address is not None: + query['ip_address'] = parsed_args.ip_address + if parsed_args.project: + project_id = identity_common.find_project( + identity_client, + parsed_args.project, + parsed_args.project_domain, + ).id + query['project_id'] = project_id + if parsed_args.name: + query['name'] = parsed_args.name + + data = client.ndp_proxies(**query) + + return (headers, + (utils.get_item_properties( + s, columns, + formatters={}, + ) for s in data)) + + +class SetNDPProxy(command.Command): + _description = _("Set NDP proxy properties") + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + 'ndp_proxy', + metavar='<ndp-proxy>', + help=_("The ID or name of the NDP proxy to update") + ) + parser.add_argument( + '--name', + metavar='<name>', + help=_("Set NDP proxy name") + ) + parser.add_argument( + '--description', + metavar='<description>', + help=_("A text to describe/contextualize the use of " + "the NDP proxy configuration") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + attrs = {} + if parsed_args.description is not None: + attrs['description'] = parsed_args.description + if parsed_args.name is not None: + attrs['name'] = parsed_args.name + + obj = client.find_ndp_proxy( + parsed_args.ndp_proxy, ignore_missing=False) + client.update_ndp_proxy(obj, **attrs) + + +class ShowNDPProxy(command.ShowOne): + _description = _("Display NDP proxy details") + + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + parser.add_argument( + 'ndp_proxy', + metavar="<ndp-proxy>", + help=_("The ID or name of the NDP proxy") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + obj = client.find_ndp_proxy(parsed_args.ndp_proxy, + ignore_missing=False) + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + return (display_columns, data) diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py index a239e0fe..54e2821c 100644 --- a/openstackclient/network/v2/network.py +++ b/openstackclient/network/v2/network.py @@ -60,6 +60,7 @@ def _get_columns_network(item): 'ipv6_address_scope_id': 'ipv6_address_scope', 'tags': 'tags', } + hidden_columns = ['location', 'tenant_id'] hidden_columns = ['location'] return utils.get_osc_show_columns_for_sdk_resource( item, @@ -270,14 +271,16 @@ class CreateNetwork(common.NetworkAndComputeShowOne, '--external', action='store_true', help=self.enhance_help_neutron( - _("Set this network as an external network " + _("The network has an external routing facility that's not " + "managed by Neutron and can be used as in: " + "openstack router set --external-gateway NETWORK " "(external-net extension required)")) ) external_router_grp.add_argument( '--internal', action='store_true', help=self.enhance_help_neutron( - _("Set this network as an internal network (default)")) + _("Opposite of '--external' (default)")) ) default_router_grp = parser.add_mutually_exclusive_group() default_router_grp.add_argument( @@ -664,12 +667,12 @@ class SetNetwork(common.NeutronCommandWithExtraArgs): ) parser.add_argument( '--description', - metavar="<description", + metavar="<description>", help=_("Set network description") ) parser.add_argument( '--mtu', - metavar="<mtu", + metavar="<mtu>", help=_("Set network mtu") ) port_security_group = parser.add_mutually_exclusive_group() @@ -689,13 +692,15 @@ class SetNetwork(common.NeutronCommandWithExtraArgs): external_router_grp.add_argument( '--external', action='store_true', - help=_("Set this network as an external network " + help=_("The network has an external routing facility that's not " + "managed by Neutron and can be used as in: " + "openstack router set --external-gateway NETWORK " "(external-net extension required)") ) external_router_grp.add_argument( '--internal', action='store_true', - help=_("Set this network as an internal network") + help=_("Opposite of '--external'") ) default_router_grp = parser.add_mutually_exclusive_group() default_router_grp.add_argument( diff --git a/openstackclient/network/v2/network_agent.py b/openstackclient/network/v2/network_agent.py index 3024d026..f67f67bd 100644 --- a/openstackclient/network/v2/network_agent.py +++ b/openstackclient/network/v2/network_agent.py @@ -50,7 +50,7 @@ def _get_network_columns(item): 'is_admin_state_up': 'admin_state_up', 'is_alive': 'alive', } - hidden_columns = ['location'] + hidden_columns = ['location', 'name', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, @@ -168,11 +168,11 @@ class ListNetworkAgent(command.Lister): metavar='<agent-type>', choices=["bgp", "dhcp", "open-vswitch", "linux-bridge", "ofa", "l3", "loadbalancer", "metering", "metadata", "macvtap", - "nic"], + "nic", "baremetal"], help=_("List only agents with the specified agent type. " "The supported agent types are: bgp, dhcp, open-vswitch, " "linux-bridge, ofa, l3, loadbalancer, metering, " - "metadata, macvtap, nic.") + "metadata, macvtap, nic, baremetal.") ) parser.add_argument( '--host', @@ -231,7 +231,8 @@ class ListNetworkAgent(command.Lister): 'metering': 'Metering agent', 'metadata': 'Metadata agent', 'macvtap': 'Macvtap agent', - 'nic': 'NIC Switch agent' + 'nic': 'NIC Switch agent', + 'baremetal': 'Baremetal Node' } filters = {} diff --git a/openstackclient/network/v2/network_flavor.py b/openstackclient/network/v2/network_flavor.py index 862155ce..864184c0 100644 --- a/openstackclient/network/v2/network_flavor.py +++ b/openstackclient/network/v2/network_flavor.py @@ -31,7 +31,7 @@ def _get_columns(item): 'is_enabled': 'enabled', } - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/network_flavor_profile.py b/openstackclient/network/v2/network_flavor_profile.py index 719f955c..66c6dcff 100644 --- a/openstackclient/network/v2/network_flavor_profile.py +++ b/openstackclient/network/v2/network_flavor_profile.py @@ -29,7 +29,7 @@ def _get_columns(item): 'is_enabled': 'enabled', } - hidden_columns = ['location'] + hidden_columns = ['location', 'name', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, @@ -166,7 +166,7 @@ class ListNetworkFlavorProfile(command.Lister): 'id', 'driver', 'is_enabled', - 'metainfo', + 'meta_info', 'description', ) column_headers = ( diff --git a/openstackclient/network/v2/network_meter.py b/openstackclient/network/v2/network_meter.py index b7b77fb1..99b0bdd4 100644 --- a/openstackclient/network/v2/network_meter.py +++ b/openstackclient/network/v2/network_meter.py @@ -30,7 +30,7 @@ def _get_columns(item): column_map = { 'is_shared': 'shared', } - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/network_meter_rule.py b/openstackclient/network/v2/network_meter_rule.py index 0f427275..2c50e5a6 100644 --- a/openstackclient/network/v2/network_meter_rule.py +++ b/openstackclient/network/v2/network_meter_rule.py @@ -28,7 +28,7 @@ LOG = logging.getLogger(__name__) def _get_columns(item): column_map = {} - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/network_qos_policy.py b/openstackclient/network/v2/network_qos_policy.py index bc257901..d77e5db9 100644 --- a/openstackclient/network/v2/network_qos_policy.py +++ b/openstackclient/network/v2/network_qos_policy.py @@ -30,7 +30,7 @@ def _get_columns(item): column_map = { 'is_shared': 'shared', } - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/network_qos_rule.py b/openstackclient/network/v2/network_qos_rule.py index a4129b83..cb2d2339 100644 --- a/openstackclient/network/v2/network_qos_rule.py +++ b/openstackclient/network/v2/network_qos_rule.py @@ -25,16 +25,20 @@ from openstackclient.network import common RULE_TYPE_BANDWIDTH_LIMIT = 'bandwidth-limit' RULE_TYPE_DSCP_MARKING = 'dscp-marking' RULE_TYPE_MINIMUM_BANDWIDTH = 'minimum-bandwidth' +RULE_TYPE_MINIMUM_PACKET_RATE = 'minimum-packet-rate' MANDATORY_PARAMETERS = { RULE_TYPE_MINIMUM_BANDWIDTH: {'min_kbps', 'direction'}, + RULE_TYPE_MINIMUM_PACKET_RATE: {'min_kpps', 'direction'}, RULE_TYPE_DSCP_MARKING: {'dscp_mark'}, RULE_TYPE_BANDWIDTH_LIMIT: {'max_kbps'}} OPTIONAL_PARAMETERS = { RULE_TYPE_MINIMUM_BANDWIDTH: set(), + RULE_TYPE_MINIMUM_PACKET_RATE: set(), RULE_TYPE_DSCP_MARKING: set(), RULE_TYPE_BANDWIDTH_LIMIT: {'direction', 'max_burst_kbps'}} DIRECTION_EGRESS = 'egress' DIRECTION_INGRESS = 'ingress' +DIRECTION_ANY = 'any' DSCP_VALID_MARKS = [0, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 46, 48, 56] @@ -47,7 +51,7 @@ ACTION_SHOW = 'get' def _get_columns(item): column_map = {} - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, @@ -98,10 +102,20 @@ def _get_attrs(network_client, parsed_args, is_create=False): attrs['dscp_mark'] = parsed_args.dscp_mark if parsed_args.min_kbps is not None: attrs['min_kbps'] = parsed_args.min_kbps + if parsed_args.min_kpps is not None: + attrs['min_kpps'] = parsed_args.min_kpps if parsed_args.ingress: - attrs['direction'] = 'ingress' + attrs['direction'] = DIRECTION_INGRESS if parsed_args.egress: - attrs['direction'] = 'egress' + attrs['direction'] = DIRECTION_EGRESS + if parsed_args.any: + if rule_type == RULE_TYPE_MINIMUM_PACKET_RATE: + attrs['direction'] = DIRECTION_ANY + else: + msg = (_('Direction "any" can only be used with ' + '%(rule_type_min_pps)s rule type') % + {'rule_type_min_pps': RULE_TYPE_MINIMUM_PACKET_RATE}) + raise exceptions.CommandError(msg) _check_type_parameters(attrs, rule_type, is_create) return attrs @@ -160,6 +174,13 @@ def _add_rule_arguments(parser): type=int, help=_('Minimum guaranteed bandwidth in kbps') ) + parser.add_argument( + '--min-kpps', + dest='min_kpps', + metavar='<min-kpps>', + type=int, + help=_('Minimum guaranteed packet rate in kpps') + ) direction_group = parser.add_mutually_exclusive_group() direction_group.add_argument( '--ingress', @@ -171,6 +192,12 @@ def _add_rule_arguments(parser): action='store_true', help=_("Egress traffic direction from the project point of view") ) + direction_group.add_argument( + '--any', + action='store_true', + help=_("Any traffic direction from the project point of view. Can be " + "used only with minimum packet rate rule.") + ) class CreateNetworkQosRule(command.ShowOne, @@ -190,6 +217,7 @@ class CreateNetworkQosRule(command.ShowOne, metavar='<type>', required=True, choices=[RULE_TYPE_MINIMUM_BANDWIDTH, + RULE_TYPE_MINIMUM_PACKET_RATE, RULE_TYPE_DSCP_MARKING, RULE_TYPE_BANDWIDTH_LIMIT], help=(_('QoS rule type (%s)') % @@ -200,10 +228,10 @@ class CreateNetworkQosRule(command.ShowOne, def take_action(self, parsed_args): network_client = self.app.client_manager.network - attrs = _get_attrs(network_client, parsed_args, is_create=True) - attrs.update( - self._parse_extra_properties(parsed_args.extra_properties)) try: + attrs = _get_attrs(network_client, parsed_args, is_create=True) + attrs.update( + self._parse_extra_properties(parsed_args.extra_properties)) obj = _rule_action_call( network_client, ACTION_CREATE, parsed_args.type)( attrs.pop('qos_policy_id'), **attrs) @@ -270,6 +298,7 @@ class ListNetworkQosRule(command.Lister): 'max_kbps', 'max_burst_kbps', 'min_kbps', + 'min_kpps', 'dscp_mark', 'direction', ) @@ -280,6 +309,7 @@ class ListNetworkQosRule(command.Lister): 'Max Kbps', 'Max Burst Kbits', 'Min Kbps', + 'Min Kpps', 'DSCP mark', 'Direction', ) diff --git a/openstackclient/network/v2/network_qos_rule_type.py b/openstackclient/network/v2/network_qos_rule_type.py index 1bcfda82..3f4f6a19 100644 --- a/openstackclient/network/v2/network_qos_rule_type.py +++ b/openstackclient/network/v2/network_qos_rule_type.py @@ -24,14 +24,31 @@ def _get_columns(item): "type": "rule_type_name", "drivers": "drivers", } - invisible_columns = ["id", "location", "name"] + hidden_columns = ["id", "location", "name", 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( - item, column_map, invisible_columns) + item, column_map, hidden_columns) class ListNetworkQosRuleType(command.Lister): _description = _("List QoS rule types") + def get_parser(self, prog_name): + parser = super().get_parser(prog_name) + supported = parser.add_mutually_exclusive_group() + supported.add_argument( + '--all-supported', + action='store_true', + help=_("List all the QoS rule types supported by any loaded " + "mechanism drivers (the union of all sets of supported " + "rules)") + ) + supported.add_argument( + '--all-rules', + action='store_true', + help=_("List all QoS rule types implemented in Neutron QoS driver") + ) + return parser + def take_action(self, parsed_args): client = self.app.client_manager.network columns = ( @@ -40,7 +57,13 @@ class ListNetworkQosRuleType(command.Lister): column_headers = ( 'Type', ) - data = client.qos_rule_types() + + args = {} + if parsed_args.all_supported: + args['all_supported'] = True + elif parsed_args.all_rules: + args['all_rules'] = True + data = client.qos_rule_types(**args) return (column_headers, (utils.get_item_properties( diff --git a/openstackclient/network/v2/network_rbac.py b/openstackclient/network/v2/network_rbac.py index 00667395..fa4fca7c 100644 --- a/openstackclient/network/v2/network_rbac.py +++ b/openstackclient/network/v2/network_rbac.py @@ -30,7 +30,7 @@ def _get_columns(item): column_map = { 'target_tenant': 'target_project_id', } - hidden_columns = ['location'] + hidden_columns = ['location', 'name', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, @@ -218,6 +218,11 @@ class ListNetworkRBAC(command.Lister): 'action ("access_as_external" or "access_as_shared")') ) parser.add_argument( + '--target-project', + metavar='<target-project>', + help=_('List network RBAC policies for a specific target project') + ) + parser.add_argument( '--long', action='store_true', default=False, @@ -247,6 +252,16 @@ class ListNetworkRBAC(command.Lister): query['object_type'] = parsed_args.type if parsed_args.action is not None: query['action'] = parsed_args.action + if parsed_args.target_project is not None: + project_id = "*" + + if parsed_args.target_project != "*": + identity_client = self.app.client_manager.identity + project_id = identity_common.find_project( + identity_client, + parsed_args.target_project, + ).id + query['target_project_id'] = project_id data = client.rbac_policies(**query) diff --git a/openstackclient/network/v2/network_segment.py b/openstackclient/network/v2/network_segment.py index 0f64bd86..c6c88e30 100644 --- a/openstackclient/network/v2/network_segment.py +++ b/openstackclient/network/v2/network_segment.py @@ -27,7 +27,7 @@ LOG = logging.getLogger(__name__) def _get_columns(item): column_map = {} - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/network_segment_range.py b/openstackclient/network/v2/network_segment_range.py index a95adb0a..1291d9d8 100644 --- a/openstackclient/network/v2/network_segment_range.py +++ b/openstackclient/network/v2/network_segment_range.py @@ -33,7 +33,7 @@ LOG = logging.getLogger(__name__) def _get_columns(item): column_map = {} - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/network_trunk.py b/openstackclient/network/v2/network_trunk.py new file mode 100644 index 00000000..c5f62901 --- /dev/null +++ b/openstackclient/network/v2/network_trunk.py @@ -0,0 +1,402 @@ +# Copyright 2016 ZTE Corporation. +# All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +"""Network trunk and subports action implementations""" +import logging + +from cliff import columns as cliff_columns +from osc_lib.cli import format_columns +from osc_lib.cli import identity as identity_utils +from osc_lib.cli import parseractions +from osc_lib.command import command +from osc_lib import exceptions +from osc_lib import utils as osc_utils + +from openstackclient.i18n import _ + +LOG = logging.getLogger(__name__) + +TRUNK = 'trunk' +TRUNKS = 'trunks' +SUB_PORTS = 'sub_ports' + + +class AdminStateColumn(cliff_columns.FormattableColumn): + def human_readable(self): + return 'UP' if self._value else 'DOWN' + + +class CreateNetworkTrunk(command.ShowOne): + """Create a network trunk for a given project""" + + def get_parser(self, prog_name): + parser = super(CreateNetworkTrunk, self).get_parser(prog_name) + parser.add_argument( + 'name', + metavar='<name>', + 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, + help=_("Parent port belonging to this trunk (name or ID)") + ) + parser.add_argument( + '--subport', + metavar='<port=,segmentation-type=,segmentation-id=>', + action=parseractions.MultiKeyValueAction, dest='add_subports', + optional_keys=['segmentation-id', 'segmentation-type'], + required_keys=['port'], + help=_("Subport to add. Subport is of form " + "\'port=<name or ID>,segmentation-type=<segmentation-type>," + "segmentation-id=<segmentation-ID>\' (--subport) option " + "can be repeated") + ) + admin_group = parser.add_mutually_exclusive_group() + admin_group.add_argument( + '--enable', + action='store_true', + default=True, + help=_("Enable trunk (default)") + ) + admin_group.add_argument( + '--disable', + action='store_true', + help=_("Disable trunk") + ) + identity_utils.add_project_owner_option_to_parser(parser) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + attrs = _get_attrs_for_trunk(self.app.client_manager, + parsed_args) + obj = client.create_trunk(**attrs) + display_columns, columns = _get_columns(obj) + data = osc_utils.get_dict_properties(obj, columns, + formatters=_formatters) + return display_columns, data + + +class DeleteNetworkTrunk(command.Command): + """Delete a given network trunk""" + + def get_parser(self, prog_name): + parser = super(DeleteNetworkTrunk, self).get_parser(prog_name) + parser.add_argument( + 'trunk', + metavar="<trunk>", + nargs="+", + help=_("Trunk(s) to delete (name or ID)") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + result = 0 + for trunk in parsed_args.trunk: + try: + trunk_id = client.find_trunk(trunk).id + client.delete_trunk(trunk_id) + except Exception as e: + result += 1 + LOG.error(_("Failed to delete trunk with name " + "or ID '%(trunk)s': %(e)s"), + {'trunk': trunk, 'e': e}) + if result > 0: + total = len(parsed_args.trunk) + msg = (_("%(result)s of %(total)s trunks failed " + "to delete.") % {'result': result, 'total': total}) + raise exceptions.CommandError(msg) + + +class ListNetworkTrunk(command.Lister): + """List all network trunks""" + + def get_parser(self, prog_name): + parser = super(ListNetworkTrunk, self).get_parser(prog_name) + parser.add_argument( + '--long', + action='store_true', + default=False, + help=_("List additional fields in output") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + data = client.trunks() + headers = ( + 'ID', + 'Name', + 'Parent Port', + 'Description' + ) + columns = ( + 'id', + 'name', + '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, + (osc_utils.get_item_properties( + s, columns, + formatters=_formatters, + ) for s in data)) + + +class SetNetworkTrunk(command.Command): + """Set network trunk properties""" + + def get_parser(self, prog_name): + parser = super(SetNetworkTrunk, self).get_parser(prog_name) + parser.add_argument( + 'trunk', + metavar="<trunk>", + help=_("Trunk to modify (name or ID)") + ) + parser.add_argument( + '--name', + metavar="<name>", + 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', + optional_keys=['segmentation-id', 'segmentation-type'], + required_keys=['port'], + help=_("Subport to add. Subport is of form " + "\'port=<name or ID>,segmentation-type=<segmentation-type>" + ",segmentation-id=<segmentation-ID>\' (--subport) option " + "can be repeated") + ) + admin_group = parser.add_mutually_exclusive_group() + admin_group.add_argument( + '--enable', + action='store_true', + help=_("Enable trunk") + ) + admin_group.add_argument( + '--disable', + action='store_true', + help=_("Disable trunk") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + trunk_id = client.find_trunk(parsed_args.trunk) + attrs = _get_attrs_for_trunk(self.app.client_manager, parsed_args) + try: + client.update_trunk(trunk_id, **attrs) + except Exception as e: + msg = (_("Failed to set trunk '%(t)s': %(e)s") + % {'t': parsed_args.trunk, 'e': e}) + raise exceptions.CommandError(msg) + if parsed_args.set_subports: + subport_attrs = _get_attrs_for_subports(self.app.client_manager, + parsed_args) + try: + client.add_trunk_subports(trunk_id, subport_attrs) + except Exception as e: + msg = (_("Failed to add subports to trunk '%(t)s': %(e)s") + % {'t': parsed_args.trunk, 'e': e}) + raise exceptions.CommandError(msg) + + +class ShowNetworkTrunk(command.ShowOne): + """Show information of a given network trunk""" + def get_parser(self, prog_name): + parser = super(ShowNetworkTrunk, self).get_parser(prog_name) + parser.add_argument( + 'trunk', + metavar="<trunk>", + help=_("Trunk to display (name or ID)") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + trunk_id = client.find_trunk(parsed_args.trunk).id + obj = client.get_trunk(trunk_id) + display_columns, columns = _get_columns(obj) + data = osc_utils.get_dict_properties(obj, columns, + formatters=_formatters) + return display_columns, data + + +class ListNetworkSubport(command.Lister): + """List all subports for a given network trunk""" + + def get_parser(self, prog_name): + parser = super(ListNetworkSubport, self).get_parser(prog_name) + parser.add_argument( + '--trunk', + required=True, + metavar="<trunk>", + help=_("List subports belonging to this trunk (name or ID)") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + trunk_id = client.find_trunk(parsed_args.trunk) + data = client.get_trunk_subports(trunk_id) + headers = ('Port', 'Segmentation Type', 'Segmentation ID') + columns = ('port_id', 'segmentation_type', 'segmentation_id') + return (headers, + (osc_utils.get_dict_properties( + s, columns, + ) for s in data[SUB_PORTS])) + + +class UnsetNetworkTrunk(command.Command): + """Unset subports from a given network trunk""" + + def get_parser(self, prog_name): + parser = super(UnsetNetworkTrunk, self).get_parser(prog_name) + parser.add_argument( + 'trunk', + metavar="<trunk>", + help=_("Unset subports from this trunk (name or ID)") + ) + parser.add_argument( + '--subport', + metavar="<subport>", + required=True, + action='append', dest='unset_subports', + help=_("Subport to delete (name or ID of the port) " + "(--subport) option can be repeated") + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.network + attrs = _get_attrs_for_subports(self.app.client_manager, parsed_args) + trunk_id = client.find_trunk(parsed_args.trunk) + client.delete_trunk_subports(trunk_id, attrs) + + +_formatters = { + 'admin_state_up': AdminStateColumn, + 'sub_ports': format_columns.ListDictColumn, +} + + +def _get_columns(item): + column_map = {} + hidden_columns = ['location', 'tenant_id'] + return osc_utils.get_osc_show_columns_for_sdk_resource( + item, + column_map, + hidden_columns + ) + + +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: + attrs['admin_state_up'] = False + if 'parent_port' in parsed_args and parsed_args.parent_port is not None: + port_id = client_manager.network.find_port( + parsed_args.parent_port)['id'] + attrs['port_id'] = port_id + if 'add_subports' in parsed_args and parsed_args.add_subports is not None: + attrs[SUB_PORTS] = _format_subports(client_manager, + parsed_args.add_subports) + + # "trunk set" command doesn't support setting project. + if 'project' in parsed_args and parsed_args.project is not None: + identity_client = client_manager.identity + project_id = identity_utils.find_project( + identity_client, + parsed_args.project, + parsed_args.project_domain, + ).id + attrs['tenant_id'] = project_id + + return attrs + + +def _format_subports(client_manager, subports): + attrs = [] + for subport in subports: + subport_attrs = {} + if subport.get('port'): + port_id = client_manager.network.find_port(subport['port'])['id'] + subport_attrs['port_id'] = port_id + if subport.get('segmentation-id'): + try: + subport_attrs['segmentation_id'] = int( + subport['segmentation-id']) + except ValueError: + msg = (_("Segmentation-id '%s' is not an integer") % + subport['segmentation-id']) + raise exceptions.CommandError(msg) + if subport.get('segmentation-type'): + subport_attrs['segmentation_type'] = subport['segmentation-type'] + attrs.append(subport_attrs) + return attrs + + +def _get_attrs_for_subports(client_manager, parsed_args): + attrs = {} + if 'set_subports' in parsed_args and parsed_args.set_subports is not None: + attrs = _format_subports(client_manager, + parsed_args.set_subports) + if ('unset_subports' in parsed_args and + parsed_args.unset_subports is not None): + subports_list = [] + for subport in parsed_args.unset_subports: + port_id = client_manager.network.find_port(subport)['id'] + subports_list.append({'port_id': port_id}) + attrs = subports_list + return attrs + + +def _get_id(client, id_or_name, resource): + return client.find_resource(resource, str(id_or_name))['id'] diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py index 16072bc0..8bf14d6a 100644 --- a/openstackclient/network/v2/port.py +++ b/openstackclient/network/v2/port.py @@ -64,7 +64,7 @@ def _get_columns(item): 'is_admin_state_up': 'admin_state_up', 'is_port_security_enabled': 'port_security_enabled', } - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py index f1fce298..8302ee01 100644 --- a/openstackclient/network/v2/router.py +++ b/openstackclient/network/v2/router.py @@ -369,6 +369,21 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs): action='store_true', help=_("Disable Source NAT on external gateway") ) + ndp_proxy_group = parser.add_mutually_exclusive_group() + ndp_proxy_group.add_argument( + '--enable-ndp-proxy', + dest='enable_ndp_proxy', + default=None, + action='store_true', + help=_("Enable IPv6 NDP proxy on external gateway") + ) + ndp_proxy_group.add_argument( + '--disable-ndp-proxy', + dest='enable_ndp_proxy', + default=None, + action='store_false', + help=_("Disable IPv6 NDP proxy on external gateway") + ) return parser @@ -383,6 +398,14 @@ class CreateRouter(command.ShowOne, common.NeutronCommandWithExtraArgs): attrs.update( self._parse_extra_properties(parsed_args.extra_properties)) + if parsed_args.enable_ndp_proxy and not parsed_args.external_gateway: + msg = (_("You must specify '--external-gateway' in order " + "to enable router's NDP proxy")) + raise exceptions.CommandError(msg) + + if parsed_args.enable_ndp_proxy is not None: + attrs['enable_ndp_proxy'] = parsed_args.enable_ndp_proxy + obj = client.create_router(**attrs) # tags cannot be set when created, so tags need to be set later. _tag.update_tags_for_set(client, obj, parsed_args) @@ -737,6 +760,21 @@ class SetRouter(common.NeutronCommandWithExtraArgs): action='store_true', help=_("Disable Source NAT on external gateway") ) + ndp_proxy_group = parser.add_mutually_exclusive_group() + ndp_proxy_group.add_argument( + '--enable-ndp-proxy', + dest='enable_ndp_proxy', + default=None, + action='store_true', + help=_("Enable IPv6 NDP proxy on external gateway") + ) + ndp_proxy_group.add_argument( + '--disable-ndp-proxy', + dest='enable_ndp_proxy', + default=None, + action='store_false', + help=_("Disable IPv6 NDP proxy on external gateway") + ) qos_policy_group = parser.add_mutually_exclusive_group() qos_policy_group.add_argument( '--qos-policy', @@ -804,6 +842,9 @@ class SetRouter(common.NeutronCommandWithExtraArgs): attrs.update( self._parse_extra_properties(parsed_args.extra_properties)) + if parsed_args.enable_ndp_proxy is not None: + attrs['enable_ndp_proxy'] = parsed_args.enable_ndp_proxy + if attrs: client.update_router(obj, **attrs) # tags is a subresource and it needs to be updated separately. diff --git a/openstackclient/network/v2/security_group.py b/openstackclient/network/v2/security_group.py index d8c38f45..ffad9988 100644 --- a/openstackclient/network/v2/security_group.py +++ b/openstackclient/network/v2/security_group.py @@ -35,6 +35,7 @@ def _format_network_security_group_rules(sg_rules): for key in empty_keys: sg_rule.pop(key) sg_rule.pop('security_group_id', None) + sg_rule.pop('tenant_id', None) sg_rule.pop('project_id', None) return utils.format_list_of_dicts(sg_rules) diff --git a/openstackclient/network/v2/security_group_rule.py b/openstackclient/network/v2/security_group_rule.py index a1122616..2179f33d 100644 --- a/openstackclient/network/v2/security_group_rule.py +++ b/openstackclient/network/v2/security_group_rule.py @@ -72,7 +72,7 @@ def _format_remote_ip_prefix(rule): def _get_columns(item): column_map = {} - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py index bf6a46d4..8e3a877f 100644 --- a/openstackclient/network/v2/subnet.py +++ b/openstackclient/network/v2/subnet.py @@ -138,16 +138,17 @@ def _get_columns(item): 'is_dhcp_enabled': 'enable_dhcp', 'subnet_pool_id': 'subnetpool_id', } - # Do not show this column when displaying a subnet - invisible_columns = [ + # Do not show these columns when displaying a subnet + hidden_columns = [ 'location', 'use_default_subnet_pool', - 'prefix_length' + 'prefix_length', + 'tenant_id', ] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, - invisible_columns + hidden_columns ) diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py index b4142f37..2369960e 100644 --- a/openstackclient/network/v2/subnet_pool.py +++ b/openstackclient/network/v2/subnet_pool.py @@ -37,7 +37,7 @@ def _get_columns(item): 'maximum_prefix_length': 'max_prefixlen', 'minimum_prefix_length': 'min_prefixlen', } - hidden_columns = ['location'] + hidden_columns = ['location', 'tenant_id'] return utils.get_osc_show_columns_for_sdk_resource( item, column_map, |