summaryrefslogtreecommitdiff
path: root/openstackclient/network
diff options
context:
space:
mode:
authorAkihiro Motoki <amotoki@gmail.com>2017-04-29 00:32:32 +0000
committerAkihiro Motoki <amotoki@gmail.com>2017-07-23 21:54:32 +0000
commit57e5840710c3b2b74d31bfd6a0da739e0fc747ed (patch)
tree93fbb66cdc78f93062c4be7bddd8c8d8e45ff365 /openstackclient/network
parente889ba1524c7e48a86ef41361a17cdb93b9942c2 (diff)
downloadpython-openstackclient-57e5840710c3b2b74d31bfd6a0da739e0fc747ed.tar.gz
Network tag support
Neutron tag mechanism now supports network, subnet, port, subnetpool and router. Tag support for more resources is planned. This commit introduces a common mixin class to implement tag operation and individual resource consumes it. To support tag remove, network unset command is added. Implements blueprint neutron-client-tag Change-Id: Iad59d052f46896d27d73c22d6d4bb3df889f2352
Diffstat (limited to 'openstackclient/network')
-rw-r--r--openstackclient/network/v2/_tag.py134
-rw-r--r--openstackclient/network/v2/network.py43
-rw-r--r--openstackclient/network/v2/port.py24
-rw-r--r--openstackclient/network/v2/router.py19
-rw-r--r--openstackclient/network/v2/subnet.py21
-rw-r--r--openstackclient/network/v2/subnet_pool.py21
6 files changed, 250 insertions, 12 deletions
diff --git a/openstackclient/network/v2/_tag.py b/openstackclient/network/v2/_tag.py
new file mode 100644
index 00000000..d1e59937
--- /dev/null
+++ b/openstackclient/network/v2/_tag.py
@@ -0,0 +1,134 @@
+# 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.
+#
+
+import argparse
+
+from openstackclient.i18n import _
+
+
+class _CommaListAction(argparse.Action):
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ setattr(namespace, self.dest, values.split(','))
+
+
+def add_tag_filtering_option_to_parser(parser, collection_name):
+ parser.add_argument(
+ '--tags',
+ metavar='<tag>[,<tag>,...]',
+ action=_CommaListAction,
+ help=_('List %s which have all given tag(s) '
+ '(Comma-separated list of tags)') % collection_name
+ )
+ parser.add_argument(
+ '--any-tags',
+ metavar='<tag>[,<tag>,...]',
+ action=_CommaListAction,
+ help=_('List %s which have any given tag(s) '
+ '(Comma-separated list of tags)') % collection_name
+ )
+ parser.add_argument(
+ '--not-tags',
+ metavar='<tag>[,<tag>,...]',
+ action=_CommaListAction,
+ help=_('Exclude %s which have all given tag(s) '
+ '(Comma-separated list of tags)') % collection_name
+ )
+ parser.add_argument(
+ '--not-any-tags',
+ metavar='<tag>[,<tag>,...]',
+ action=_CommaListAction,
+ help=_('Exclude %s which have any given tag(s) '
+ '(Comma-separated list of tags)') % collection_name
+ )
+
+
+def get_tag_filtering_args(parsed_args, args):
+ if parsed_args.tags:
+ args['tags'] = ','.join(parsed_args.tags)
+ if parsed_args.any_tags:
+ args['any_tags'] = ','.join(parsed_args.any_tags)
+ if parsed_args.not_tags:
+ args['not_tags'] = ','.join(parsed_args.not_tags)
+ if parsed_args.not_any_tags:
+ args['not_any_tags'] = ','.join(parsed_args.not_any_tags)
+
+
+def add_tag_option_to_parser_for_create(parser, resource_name):
+ tag_group = parser.add_mutually_exclusive_group()
+ tag_group.add_argument(
+ '--tag',
+ action='append',
+ dest='tags',
+ metavar='<tag>',
+ help=_("Tag to be added to the %s "
+ "(repeat option to set multiple tags)") % resource_name
+ )
+ tag_group.add_argument(
+ '--no-tag',
+ action='store_true',
+ help=_("No tags associated with the %s") % resource_name
+ )
+
+
+def add_tag_option_to_parser_for_set(parser, resource_name):
+ parser.add_argument(
+ '--tag',
+ action='append',
+ dest='tags',
+ metavar='<tag>',
+ help=_("Tag to be added to the %s "
+ "(repeat option to set multiple tags)") % resource_name
+ )
+ parser.add_argument(
+ '--no-tag',
+ action='store_true',
+ help=_("Clear tags associated with the %s. Specify both "
+ "--tag and --no-tag to overwrite current tags") % resource_name
+ )
+
+
+def update_tags_for_set(client, obj, parsed_args):
+ if parsed_args.no_tag:
+ tags = set()
+ else:
+ tags = set(obj.tags)
+ if parsed_args.tags:
+ tags |= set(parsed_args.tags)
+ if set(obj.tags) != tags:
+ client.set_tags(obj, list(tags))
+
+
+def add_tag_option_to_parser_for_unset(parser, resource_name):
+ tag_group = parser.add_mutually_exclusive_group()
+ tag_group.add_argument(
+ '--tag',
+ action='append',
+ dest='tags',
+ metavar='<tag>',
+ help=_("Tag to be removed from the %s "
+ "(repeat option to remove multiple tags)") % resource_name)
+ tag_group.add_argument(
+ '--all-tag',
+ action='store_true',
+ help=_("Clear all tags associated with the %s") % resource_name)
+
+
+def update_tags_for_unset(client, obj, parsed_args):
+ tags = set(obj.tags)
+ if parsed_args.all_tag:
+ tags = set()
+ if parsed_args.tags:
+ tags -= set(parsed_args.tags)
+ if set(obj.tags) != tags:
+ client.set_tags(obj, list(tags))
diff --git a/openstackclient/network/v2/network.py b/openstackclient/network/v2/network.py
index 33decd82..4c1725c5 100644
--- a/openstackclient/network/v2/network.py
+++ b/openstackclient/network/v2/network.py
@@ -20,6 +20,7 @@ from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
from openstackclient.network import common
from openstackclient.network import sdk_utils
+from openstackclient.network.v2 import _tag
def _format_admin_state(item):
@@ -280,6 +281,7 @@ class CreateNetwork(common.NetworkAndComputeShowOne):
help=_("Do not make the network VLAN transparent"))
_add_additional_network_options(parser)
+ _tag.add_tag_option_to_parser_for_create(parser, _('network'))
return parser
def update_parser_compute(self, parser):
@@ -299,6 +301,8 @@ class CreateNetwork(common.NetworkAndComputeShowOne):
attrs['vlan_transparent'] = False
obj = client.create_network(**attrs)
+ # tags cannot be set when created, so tags need to be set later.
+ _tag.update_tags_for_set(client, obj, parsed_args)
display_columns, columns = _get_columns_network(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
return (display_columns, data)
@@ -424,7 +428,9 @@ class ListNetwork(common.NetworkAndComputeLister):
'--agent',
metavar='<agent-id>',
dest='agent_id',
- help=_('List networks hosted by agent (ID only)'))
+ help=_('List networks hosted by agent (ID only)')
+ )
+ _tag.add_tag_filtering_option_to_parser(parser, _('networks'))
return parser
def take_action_network(self, client, parsed_args):
@@ -441,6 +447,7 @@ class ListNetwork(common.NetworkAndComputeLister):
'provider_network_type',
'is_router_external',
'availability_zones',
+ 'tags',
)
column_headers = (
'ID',
@@ -453,6 +460,7 @@ class ListNetwork(common.NetworkAndComputeLister):
'Network Type',
'Router Type',
'Availability Zones',
+ 'Tags',
)
elif parsed_args.agent_id:
columns = (
@@ -534,6 +542,8 @@ class ListNetwork(common.NetworkAndComputeLister):
args['provider:segmentation_id'] = parsed_args.segmentation_id
args['provider_segmentation_id'] = parsed_args.segmentation_id
+ _tag.get_tag_filtering_args(parsed_args, args)
+
data = client.networks(**args)
return (column_headers,
@@ -656,6 +666,7 @@ class SetNetwork(command.Command):
action='store_true',
help=_("Remove the QoS policy attached to this network")
)
+ _tag.add_tag_option_to_parser_for_set(parser, _('network'))
_add_additional_network_options(parser)
return parser
@@ -664,7 +675,11 @@ class SetNetwork(command.Command):
obj = client.find_network(parsed_args.network, ignore_missing=False)
attrs = _get_attrs_network(self.app.client_manager, parsed_args)
- client.update_network(obj, **attrs)
+ if attrs:
+ client.update_network(obj, **attrs)
+
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_set(client, obj, parsed_args)
class ShowNetwork(common.NetworkAndComputeShowOne):
@@ -689,3 +704,27 @@ class ShowNetwork(common.NetworkAndComputeShowOne):
display_columns, columns = _get_columns_compute(obj)
data = utils.get_dict_properties(obj, columns)
return (display_columns, data)
+
+
+class UnsetNetwork(command.Command):
+ _description = _("Unset network properties")
+
+ def get_parser(self, prog_name):
+ parser = super(UnsetNetwork, self).get_parser(prog_name)
+ parser.add_argument(
+ 'network',
+ metavar="<network>",
+ help=_("Network to modify (name or ID)")
+ )
+ _tag.add_tag_option_to_parser_for_unset(parser, _('network'))
+ return parser
+
+ def take_action(self, parsed_args):
+ client = self.app.client_manager.network
+ obj = client.find_network(parsed_args.network, ignore_missing=False)
+
+ # NOTE: As of now, UnsetNetwork has no attributes which need
+ # to be updated by update_network().
+
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_unset(client, obj, parsed_args)
diff --git a/openstackclient/network/v2/port.py b/openstackclient/network/v2/port.py
index d7f197e0..9536fe86 100644
--- a/openstackclient/network/v2/port.py
+++ b/openstackclient/network/v2/port.py
@@ -26,6 +26,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
from openstackclient.network import sdk_utils
+from openstackclient.network.v2 import _tag
LOG = logging.getLogger(__name__)
@@ -47,6 +48,7 @@ _formatters = {
'extra_dhcp_opts': utils.format_list_of_dicts,
'fixed_ips': utils.format_list_of_dicts,
'security_group_ids': utils.format_list,
+ 'tags': utils.format_list,
}
@@ -384,6 +386,7 @@ class CreatePort(command.ShowOne):
"ip-address=<ip-address>[,mac-address=<mac-address>] "
"(repeat option to set multiple allowed-address pairs)")
)
+ _tag.add_tag_option_to_parser_for_create(parser, _('port'))
return parser
def take_action(self, parsed_args):
@@ -416,6 +419,8 @@ class CreatePort(command.ShowOne):
attrs['qos_policy_id'] = client.find_qos_policy(
parsed_args.qos_policy, ignore_missing=False).id
obj = client.create_port(**attrs)
+ # tags cannot be set when created, so tags need to be set later.
+ _tag.update_tags_for_set(client, obj, parsed_args)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
@@ -512,6 +517,7 @@ class ListPort(command.Lister):
"(name or ID): subnet=<subnet>,ip-address=<ip-address> "
"(repeat option to set multiple fixed IP addresses)"),
)
+ _tag.add_tag_filtering_option_to_parser(parser, _('ports'))
return parser
def take_action(self, parsed_args):
@@ -535,8 +541,8 @@ class ListPort(command.Lister):
filters = {}
if parsed_args.long:
- columns += ('security_group_ids', 'device_owner',)
- column_headers += ('Security Groups', 'Device Owner',)
+ columns += ('security_group_ids', 'device_owner', 'tags')
+ column_headers += ('Security Groups', 'Device Owner', 'Tags')
if parsed_args.device_owner is not None:
filters['device_owner'] = parsed_args.device_owner
if parsed_args.router:
@@ -566,6 +572,8 @@ class ListPort(command.Lister):
filters['fixed_ips'] = _prepare_filter_fixed_ips(
self.app.client_manager, parsed_args)
+ _tag.get_tag_filtering_args(parsed_args, filters)
+
data = network_client.ports(**filters)
return (column_headers,
@@ -694,6 +702,7 @@ class SetPort(command.Command):
"Unset it to None with the 'port unset' command "
"(requires data plane status extension)")
)
+ _tag.add_tag_option_to_parser_for_set(parser, _('port'))
return parser
@@ -750,7 +759,11 @@ class SetPort(command.Command):
if parsed_args.data_plane_status:
attrs['data_plane_status'] = parsed_args.data_plane_status
- client.update_port(obj, **attrs)
+ if attrs:
+ client.update_port(obj, **attrs)
+
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_set(client, obj, parsed_args)
class ShowPort(command.ShowOne):
@@ -834,6 +847,8 @@ class UnsetPort(command.Command):
help=_("Clear existing information of data plane status")
)
+ _tag.add_tag_option_to_parser_for_unset(parser, _('port'))
+
return parser
def take_action(self, parsed_args):
@@ -889,3 +904,6 @@ class UnsetPort(command.Command):
if attrs:
client.update_port(obj, **attrs)
+
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_unset(client, obj, parsed_args)
diff --git a/openstackclient/network/v2/router.py b/openstackclient/network/v2/router.py
index 8db0c439..4f908537 100644
--- a/openstackclient/network/v2/router.py
+++ b/openstackclient/network/v2/router.py
@@ -26,6 +26,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
from openstackclient.network import sdk_utils
+from openstackclient.network.v2 import _tag
LOG = logging.getLogger(__name__)
@@ -57,6 +58,7 @@ _formatters = {
'availability_zones': utils.format_list,
'availability_zone_hints': utils.format_list,
'routes': _format_routes,
+ 'tags': utils.format_list,
}
@@ -217,6 +219,7 @@ class CreateRouter(command.ShowOne):
"(Router Availability Zone extension required, "
"repeat option to set multiple availability zones)")
)
+ _tag.add_tag_option_to_parser_for_create(parser, _('router'))
return parser
@@ -229,6 +232,8 @@ class CreateRouter(command.ShowOne):
if parsed_args.no_ha:
attrs['ha'] = False
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)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
@@ -310,6 +315,7 @@ class ListRouter(command.Lister):
metavar='<agent-id>',
help=_("List routers hosted by an agent (ID only)")
)
+ _tag.add_tag_filtering_option_to_parser(parser, _('routers'))
return parser
@@ -357,6 +363,8 @@ class ListRouter(command.Lister):
args['tenant_id'] = project_id
args['project_id'] = project_id
+ _tag.get_tag_filtering_args(parsed_args, args)
+
if parsed_args.agent is not None:
agent = client.get_agent(parsed_args.agent)
data = client.agent_hosted_routers(agent)
@@ -384,6 +392,8 @@ class ListRouter(command.Lister):
column_headers = column_headers + (
'Availability zones',
)
+ columns = columns + ('tags',)
+ column_headers = column_headers + ('Tags',)
return (column_headers,
(utils.get_item_properties(
@@ -567,6 +577,7 @@ class SetRouter(command.Command):
action='store_true',
help=_("Disable Source NAT on external gateway")
)
+ _tag.add_tag_option_to_parser_for_set(parser, _('router'))
return parser
def take_action(self, parsed_args):
@@ -625,7 +636,10 @@ class SetRouter(command.Command):
ips.append(ip_spec)
gateway_info['external_fixed_ips'] = ips
attrs['external_gateway_info'] = gateway_info
- client.update_router(obj, **attrs)
+ if attrs:
+ client.update_router(obj, **attrs)
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_set(client, obj, parsed_args)
class ShowRouter(command.ShowOne):
@@ -675,6 +689,7 @@ class UnsetRouter(command.Command):
metavar="<router>",
help=_("Router to modify (name or ID)")
)
+ _tag.add_tag_option_to_parser_for_unset(parser, _('router'))
return parser
def take_action(self, parsed_args):
@@ -695,3 +710,5 @@ class UnsetRouter(command.Command):
attrs['external_gateway_info'] = {}
if attrs:
client.update_router(obj, **attrs)
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_unset(client, obj, parsed_args)
diff --git a/openstackclient/network/v2/subnet.py b/openstackclient/network/v2/subnet.py
index 2fdd11f0..b96dff7f 100644
--- a/openstackclient/network/v2/subnet.py
+++ b/openstackclient/network/v2/subnet.py
@@ -24,6 +24,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
from openstackclient.network import sdk_utils
+from openstackclient.network.v2 import _tag
LOG = logging.getLogger(__name__)
@@ -55,6 +56,7 @@ _formatters = {
'dns_nameservers': utils.format_list,
'host_routes': _format_host_routes,
'service_types': utils.format_list,
+ 'tags': utils.format_list,
}
@@ -336,12 +338,15 @@ class CreateSubnet(command.ShowOne):
help=_("Set subnet description")
)
_get_common_parse_arguments(parser)
+ _tag.add_tag_option_to_parser_for_create(parser, _('subnet'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.network
attrs = _get_attrs(self.app.client_manager, parsed_args)
obj = client.create_subnet(**attrs)
+ # tags cannot be set when created, so tags need to be set later.
+ _tag.update_tags_for_set(client, obj, parsed_args)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
return (display_columns, data)
@@ -454,6 +459,7 @@ class ListSubnet(command.Lister):
"(in CIDR notation) in output "
"e.g.: --subnet-range 10.10.0.0/16")
)
+ _tag.add_tag_filtering_option_to_parser(parser, _('subnets'))
return parser
def take_action(self, parsed_args):
@@ -488,6 +494,7 @@ class ListSubnet(command.Lister):
filters['name'] = parsed_args.name
if parsed_args.subnet_range:
filters['cidr'] = parsed_args.subnet_range
+ _tag.get_tag_filtering_args(parsed_args, filters)
data = network_client.subnets(**filters)
headers = ('ID', 'Name', 'Network', 'Subnet')
@@ -495,10 +502,10 @@ class ListSubnet(command.Lister):
if parsed_args.long:
headers += ('Project', 'DHCP', 'Name Servers',
'Allocation Pools', 'Host Routes', 'IP Version',
- 'Gateway', 'Service Types')
+ 'Gateway', 'Service Types', 'Tags')
columns += ('project_id', 'is_dhcp_enabled', 'dns_nameservers',
'allocation_pools', 'host_routes', 'ip_version',
- 'gateway_ip', 'service_types')
+ 'gateway_ip', 'service_types', 'tags')
return (headers,
(utils.get_item_properties(
@@ -549,6 +556,7 @@ class SetSubnet(command.Command):
metavar='<description>',
help=_("Set subnet description")
)
+ _tag.add_tag_option_to_parser_for_set(parser, _('subnet'))
_get_common_parse_arguments(parser, is_create=False)
return parser
@@ -574,7 +582,10 @@ class SetSubnet(command.Command):
attrs['allocation_pools'] = []
if 'service_types' in attrs:
attrs['service_types'] += obj.service_types
- client.update_subnet(obj, **attrs)
+ if attrs:
+ client.update_subnet(obj, **attrs)
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_set(client, obj, parsed_args)
return
@@ -643,6 +654,7 @@ class UnsetSubnet(command.Command):
'Must be a valid device owner value for a network port '
'(repeat option to unset multiple service types)')
)
+ _tag.add_tag_option_to_parser_for_unset(parser, _('subnet'))
parser.add_argument(
'subnet',
metavar="<subnet>",
@@ -678,3 +690,6 @@ class UnsetSubnet(command.Command):
attrs['service_types'] = tmp_obj.service_types
if attrs:
client.update_subnet(obj, **attrs)
+
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_unset(client, obj, parsed_args)
diff --git a/openstackclient/network/v2/subnet_pool.py b/openstackclient/network/v2/subnet_pool.py
index b72a74fc..a5839868 100644
--- a/openstackclient/network/v2/subnet_pool.py
+++ b/openstackclient/network/v2/subnet_pool.py
@@ -24,6 +24,7 @@ from osc_lib import utils
from openstackclient.i18n import _
from openstackclient.identity import common as identity_common
from openstackclient.network import sdk_utils
+from openstackclient.network.v2 import _tag
LOG = logging.getLogger(__name__)
@@ -42,6 +43,7 @@ def _get_columns(item):
_formatters = {
'prefixes': utils.format_list,
+ 'tags': utils.format_list,
}
@@ -191,6 +193,7 @@ class CreateSubnetPool(command.ShowOne):
metavar='<num-ip-addresses>',
help=_("Set default quota for subnet pool as the number of"
"IP addresses allowed in a subnet")),
+ _tag.add_tag_option_to_parser_for_create(parser, _('subnet pool'))
return parser
def take_action(self, parsed_args):
@@ -200,6 +203,8 @@ class CreateSubnetPool(command.ShowOne):
if "prefixes" not in attrs:
attrs['prefixes'] = []
obj = client.create_subnet_pool(**attrs)
+ # tags cannot be set when created, so tags need to be set later.
+ _tag.update_tags_for_set(client, obj, parsed_args)
display_columns, columns = _get_columns(obj)
data = utils.get_item_properties(obj, columns, formatters=_formatters)
return (display_columns, data)
@@ -293,6 +298,7 @@ class ListSubnetPool(command.Lister):
help=_("List only subnet pools of given address scope "
"in output (name or ID)")
)
+ _tag.add_tag_filtering_option_to_parser(parser, _('subnet pools'))
return parser
def take_action(self, parsed_args):
@@ -324,15 +330,16 @@ class ListSubnetPool(command.Lister):
parsed_args.address_scope,
ignore_missing=False)
filters['address_scope_id'] = address_scope.id
+ _tag.get_tag_filtering_args(parsed_args, filters)
data = network_client.subnet_pools(**filters)
headers = ('ID', 'Name', 'Prefixes')
columns = ('id', 'name', 'prefixes')
if parsed_args.long:
headers += ('Default Prefix Length', 'Address Scope',
- 'Default Subnet Pool', 'Shared')
+ 'Default Subnet Pool', 'Shared', 'Tags')
columns += ('default_prefix_length', 'address_scope_id',
- 'is_default', 'is_shared')
+ 'is_default', 'is_shared', 'tags')
return (headers,
(utils.get_item_properties(
@@ -384,6 +391,8 @@ class SetSubnetPool(command.Command):
metavar='<num-ip-addresses>',
help=_("Set default quota for subnet pool as the number of"
"IP addresses allowed in a subnet")),
+ _tag.add_tag_option_to_parser_for_set(parser, _('subnet pool'))
+
return parser
def take_action(self, parsed_args):
@@ -397,7 +406,10 @@ class SetSubnetPool(command.Command):
if 'prefixes' in attrs:
attrs['prefixes'].extend(obj.prefixes)
- client.update_subnet_pool(obj, **attrs)
+ if attrs:
+ client.update_subnet_pool(obj, **attrs)
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_set(client, obj, parsed_args)
class ShowSubnetPool(command.ShowOne):
@@ -441,6 +453,7 @@ class UnsetSubnetPool(command.Command):
metavar="<subnet-pool>",
help=_("Subnet pool to modify (name or ID)")
)
+ _tag.add_tag_option_to_parser_for_unset(parser, _('subnet pool'))
return parser
def take_action(self, parsed_args):
@@ -461,3 +474,5 @@ class UnsetSubnetPool(command.Command):
attrs['prefixes'] = tmp_prefixes
if attrs:
client.update_subnet_pool(obj, **attrs)
+ # tags is a subresource and it needs to be updated separately.
+ _tag.update_tags_for_unset(client, obj, parsed_args)