Network: Add tag support for security group

Change-Id: Icccb23429913724c6a8bd15d4737672b47a5f13a
Closes-Bug: #1750983
This commit is contained in:
Dongcan Ye 2018-02-24 09:13:48 +00:00
parent 7505831e81
commit aaed4b315f
6 changed files with 295 additions and 6 deletions

View File

@ -19,6 +19,7 @@ Create a new security group
openstack security group create
[--description <description>]
[--project <project> [--project-domain <project-domain>]]
[--tag <tag> | --no-tag]
<name>
.. option:: --description <description>
@ -38,6 +39,18 @@ Create a new security group
*Network version 2 only*
.. option:: --tag <tag>
Tag to be added to the security group (repeat option to set multiple tags)
*Network version 2 only*
.. option:: --no-tag
No tags associated with the security group
*Network version 2 only*
.. describe:: <name>
New security group name
@ -68,6 +81,8 @@ List security groups
openstack security group list
[--all-projects]
[--project <project> [--project-domain <project-domain>]]
[--tags <tag>[,<tag>,...]] [--any-tags <tag>[,<tag>,...]]
[--not-tags <tag>[,<tag>,...]] [--not-any-tags <tag>[,<tag>,...]]
.. option:: --all-projects
@ -89,6 +104,30 @@ List security groups
*Network version 2 only*
.. option:: --tags <tag>[,<tag>,...]
List security groups which have all given tag(s)
*Network version 2 only*
.. option:: --any-tags <tag>[,<tag>,...]
List security groups which have any given tag(s)
*Network version 2 only*
.. option:: --not-tags <tag>[,<tag>,...]
Exclude security groups which have all given tag(s)
*Network version 2 only*
.. option:: --not-any-tags <tag>[,<tag>,...]
Exclude security groups which have any given tag(s)
*Network version 2 only*
security group set
------------------
@ -100,6 +139,7 @@ Set security group properties
openstack security group set
[--name <new-name>]
[--description <description>]
[--tag <tag>] [--no-tag]
<group>
.. option:: --name <new-name>
@ -110,6 +150,15 @@ Set security group properties
New security group description
.. option:: --tag <tag>
Tag to be added to the security group (repeat option to set multiple tags)
.. option:: --no-tag
Clear tags associated with the security group. Specify both --tag
and --no-tag to overwrite current tags
.. describe:: <group>
Security group to modify (name or ID)
@ -128,3 +177,28 @@ Display security group details
.. describe:: <group>
Security group to display (name or ID)
security group unset
--------------------
Unset security group properties
.. program:: security group unset
.. code:: bash
openstack security group unset
[--tag <tag> | --all-tag]
<group>
.. option:: --tag <tag>
Tag to be removed from the security group
(repeat option to remove multiple tags)
.. option:: --all-tag
Clear all tags associated with the security group
.. describe:: <group>
Security group to modify (name or ID)

View File

@ -15,6 +15,7 @@
import argparse
from osc_lib.command import command
from osc_lib import utils
import six
@ -23,6 +24,7 @@ from openstackclient.identity import common as identity_common
from openstackclient.network import common
from openstackclient.network import sdk_utils
from openstackclient.network import utils as network_utils
from openstackclient.network.v2 import _tag
def _format_network_security_group_rules(sg_rules):
@ -106,6 +108,7 @@ class CreateSecurityGroup(common.NetworkAndComputeShowOne):
help=_("Owner's project (name or ID)")
)
identity_common.add_project_domain_option_to_parser(parser)
_tag.add_tag_option_to_parser_for_create(parser, _('security group'))
return parser
def _get_description(self, parsed_args):
@ -130,6 +133,8 @@ class CreateSecurityGroup(common.NetworkAndComputeShowOne):
# Create the security group and display the results.
obj = client.create_security_group(**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, property_columns = _get_columns(obj)
data = utils.get_item_properties(
obj,
@ -198,6 +203,7 @@ class ListSecurityGroup(common.NetworkAndComputeLister):
"(name or ID)")
)
identity_common.add_project_domain_option_to_parser(parser)
_tag.add_tag_filtering_option_to_parser(parser, _('security group'))
return parser
def update_parser_compute(self, parser):
@ -220,19 +226,23 @@ class ListSecurityGroup(common.NetworkAndComputeLister):
).id
filters['tenant_id'] = project_id
filters['project_id'] = project_id
_tag.get_tag_filtering_args(parsed_args, filters)
data = client.security_groups(**filters)
columns = (
"ID",
"Name",
"Description",
"Project ID"
"Project ID",
"tags"
)
column_headers = (
"ID",
"Name",
"Description",
"Project"
"Project",
"Tags"
)
return (column_headers,
(utils.get_item_properties(
@ -282,6 +292,10 @@ class SetSecurityGroup(common.NetworkAndComputeCommand):
)
return parser
def update_parser_network(self, parser):
_tag.add_tag_option_to_parser_for_set(parser, _('security group'))
return parser
def take_action_network(self, client, parsed_args):
obj = client.find_security_group(parsed_args.group,
ignore_missing=False)
@ -295,6 +309,9 @@ class SetSecurityGroup(common.NetworkAndComputeCommand):
# the update.
client.update_security_group(obj, **attrs)
# tags is a subresource and it needs to be updated separately.
_tag.update_tags_for_set(client, obj, parsed_args)
def take_action_compute(self, client, parsed_args):
data = client.api.security_group_find(parsed_args.group)
@ -344,3 +361,25 @@ class ShowSecurityGroup(common.NetworkAndComputeShowOne):
formatters=_formatters_compute
)
return (display_columns, data)
class UnsetSecurityGroup(command.Command):
_description = _("Unset security group properties")
def get_parser(self, prog_name):
parser = super(UnsetSecurityGroup, self).get_parser(prog_name)
parser.add_argument(
'group',
metavar="<group>",
help=_("Security group to modify (name or ID)")
)
_tag.add_tag_option_to_parser_for_unset(parser, _('security group'))
return parser
def take_action(self, parsed_args):
client = self.app.client_manager.network
obj = client.find_security_group(parsed_args.group,
ignore_missing=False)
# tags is a subresource and it needs to be updated separately.
_tag.update_tags_for_unset(client, obj, parsed_args)

View File

@ -1131,6 +1131,7 @@ class FakeSecurityGroup(object):
'description': 'security-group-description-' + uuid.uuid4().hex,
'project_id': 'project-id-' + uuid.uuid4().hex,
'security_group_rules': [],
'tags': []
}
# Overwrite default attributes.

View File

@ -40,8 +40,8 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
project = identity_fakes.FakeProject.create_one_project()
domain = identity_fakes.FakeDomain.create_one_domain()
# The security group to be created.
_security_group = \
network_fakes.FakeSecurityGroup.create_one_security_group()
_security_group = (
network_fakes.FakeSecurityGroup.create_one_security_group())
columns = (
'description',
@ -49,6 +49,7 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
'name',
'project_id',
'rules',
'tags',
)
data = (
@ -57,6 +58,7 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
_security_group.name,
_security_group.project_id,
'',
_security_group.tags,
)
def setUp(self):
@ -67,6 +69,7 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
self.projects_mock.get.return_value = self.project
self.domains_mock.get.return_value = self.domain
self.network.set_tags = mock.Mock(return_value=None)
# Get the command object to test
self.cmd = security_group.CreateSecurityGroup(self.app, self.namespace)
@ -118,6 +121,43 @@ class TestCreateSecurityGroupNetwork(TestSecurityGroupNetwork):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
def _test_create_with_tag(self, add_tags=True):
arglist = [self._security_group.name]
if add_tags:
arglist += ['--tag', 'red', '--tag', 'blue']
else:
arglist += ['--no-tag']
verifylist = [
('name', self._security_group.name),
]
if add_tags:
verifylist.append(('tags', ['red', 'blue']))
else:
verifylist.append(('no_tag', True))
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = (self.cmd.take_action(parsed_args))
self.network.create_security_group.assert_called_once_with(**{
'description': self._security_group.name,
'name': self._security_group.name,
})
if add_tags:
self.network.set_tags.assert_called_once_with(
self._security_group,
tests_utils.CompareBySet(['red', 'blue']))
else:
self.assertFalse(self.network.set_tags.called)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
def test_create_with_tags(self):
self._test_create_with_tag(add_tags=True)
def test_create_with_no_tag(self):
self._test_create_with_tag(add_tags=False)
class TestDeleteSecurityGroupNetwork(TestSecurityGroupNetwork):
@ -214,6 +254,7 @@ class TestListSecurityGroupNetwork(TestSecurityGroupNetwork):
'Name',
'Description',
'Project',
'Tags',
)
data = []
@ -223,6 +264,7 @@ class TestListSecurityGroupNetwork(TestSecurityGroupNetwork):
grp.name,
grp.description,
grp.project_id,
grp.tags,
))
def setUp(self):
@ -300,12 +342,38 @@ class TestListSecurityGroupNetwork(TestSecurityGroupNetwork):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
def test_list_with_tag_options(self):
arglist = [
'--tags', 'red,blue',
'--any-tags', 'red,green',
'--not-tags', 'orange,yellow',
'--not-any-tags', 'black,white',
]
verifylist = [
('tags', ['red', 'blue']),
('any_tags', ['red', 'green']),
('not_tags', ['orange', 'yellow']),
('not_any_tags', ['black', 'white']),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.network.security_groups.assert_called_once_with(
**{'tags': 'red,blue',
'any_tags': 'red,green',
'not_tags': 'orange,yellow',
'not_any_tags': 'black,white'}
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, list(data))
class TestSetSecurityGroupNetwork(TestSecurityGroupNetwork):
# The security group to be set.
_security_group = \
network_fakes.FakeSecurityGroup.create_one_security_group()
_security_group = (
network_fakes.FakeSecurityGroup.create_one_security_group(
attrs={'tags': ['green', 'red']}))
def setUp(self):
super(TestSetSecurityGroupNetwork, self).setUp()
@ -314,6 +382,7 @@ class TestSetSecurityGroupNetwork(TestSecurityGroupNetwork):
self.network.find_security_group = mock.Mock(
return_value=self._security_group)
self.network.set_tags = mock.Mock(return_value=None)
# Get the command object to test
self.cmd = security_group.SetSecurityGroup(self.app, self.namespace)
@ -366,6 +435,34 @@ class TestSetSecurityGroupNetwork(TestSecurityGroupNetwork):
)
self.assertIsNone(result)
def _test_set_tags(self, with_tags=True):
if with_tags:
arglist = ['--tag', 'red', '--tag', 'blue']
verifylist = [('tags', ['red', 'blue'])]
expected_args = ['red', 'blue', 'green']
else:
arglist = ['--no-tag']
verifylist = [('no_tag', True)]
expected_args = []
arglist.append(self._security_group.name)
verifylist.append(
('group', self._security_group.name))
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.assertTrue(self.network.update_security_group.called)
self.network.set_tags.assert_called_once_with(
self._security_group,
tests_utils.CompareBySet(expected_args))
self.assertIsNone(result)
def test_set_with_tags(self):
self._test_set_tags(with_tags=True)
def test_set_with_no_tag(self):
self._test_set_tags(with_tags=False)
class TestShowSecurityGroupNetwork(TestSecurityGroupNetwork):
@ -385,6 +482,7 @@ class TestShowSecurityGroupNetwork(TestSecurityGroupNetwork):
'name',
'project_id',
'rules',
'tags',
)
data = (
@ -394,6 +492,7 @@ class TestShowSecurityGroupNetwork(TestSecurityGroupNetwork):
_security_group.project_id,
security_group._format_network_security_group_rules(
[_security_group_rule._info]),
_security_group.tags,
)
def setUp(self):
@ -424,3 +523,70 @@ class TestShowSecurityGroupNetwork(TestSecurityGroupNetwork):
self._security_group.id, ignore_missing=False)
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
class TestUnsetSecurityGroupNetwork(TestSecurityGroupNetwork):
# The security group to be unset.
_security_group = (
network_fakes.FakeSecurityGroup.create_one_security_group(
attrs={'tags': ['green', 'red']}))
def setUp(self):
super(TestUnsetSecurityGroupNetwork, self).setUp()
self.network.update_security_group = mock.Mock(return_value=None)
self.network.find_security_group = mock.Mock(
return_value=self._security_group)
self.network.set_tags = mock.Mock(return_value=None)
# Get the command object to test
self.cmd = security_group.UnsetSecurityGroup(self.app, self.namespace)
def test_set_no_options(self):
self.assertRaises(tests_utils.ParserException,
self.check_parser, self.cmd, [], [])
def test_set_no_updates(self):
arglist = [
self._security_group.name,
]
verifylist = [
('group', self._security_group.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.assertFalse(self.network.update_security_group.called)
self.assertFalse(self.network.set_tags.called)
self.assertIsNone(result)
def _test_unset_tags(self, with_tags=True):
if with_tags:
arglist = ['--tag', 'red', '--tag', 'blue']
verifylist = [('tags', ['red', 'blue'])]
expected_args = ['green']
else:
arglist = ['--all-tag']
verifylist = [('all_tag', True)]
expected_args = []
arglist.append(self._security_group.name)
verifylist.append(
('group', self._security_group.name))
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
self.assertFalse(self.network.update_security_group.called)
self.network.set_tags.assert_called_once_with(
self._security_group,
tests_utils.CompareBySet(expected_args))
self.assertIsNone(result)
def test_unset_with_tags(self):
self._test_unset_tags(with_tags=True)
def test_unset_with_all_tag(self):
self._test_unset_tags(with_tags=False)

View File

@ -0,0 +1,8 @@
---
fixes:
- |
Add supports tagging for Network security group.
Add ``tag``, ``no-tag`` to ``security group create`` and ``security group set`` commands.
Add ``tags``, ``any-tags``, ``not-tags``, ``not-any-tags`` to ``security group list`` command.
Add ``tag`` and ``all-tag`` to ``security group unset`` command.
[Bug `1750983 <https://bugs.launchpad.net/python-openstackclient/+bug/1750983>`_]

View File

@ -467,6 +467,7 @@ openstack.network.v2 =
security_group_list = openstackclient.network.v2.security_group:ListSecurityGroup
security_group_set = openstackclient.network.v2.security_group:SetSecurityGroup
security_group_show = openstackclient.network.v2.security_group:ShowSecurityGroup
security_group_unset = openstackclient.network.v2.security_group:UnsetSecurityGroup
security_group_rule_create = openstackclient.network.v2.security_group_rule:CreateSecurityGroupRule
security_group_rule_delete = openstackclient.network.v2.security_group_rule:DeleteSecurityGroupRule