Skip to content

Commit fe650e2

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Implement network rbac create and delete commands"
2 parents b7b140d + 13bc379 commit fe650e2

File tree

8 files changed

+528
-5
lines changed

8 files changed

+528
-5
lines changed

doc/source/command-objects/network-rbac.rst

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,68 @@ to network resources for specific projects.
88

99
Network v2
1010

11+
network rbac create
12+
-------------------
13+
14+
Create network RBAC policy
15+
16+
.. program:: network rbac create
17+
.. code:: bash
18+
19+
os network rbac create
20+
--type <type>
21+
--action <action>
22+
--target-project <target-project> [--target-project-domain <target-project-domain>]
23+
[--project <project> [--project-domain <project-domain>]]
24+
<rbac-policy>
25+
26+
.. option:: --type <type>
27+
28+
Type of the object that RBAC policy affects ("qos_policy" or "network") (required)
29+
30+
.. option:: --action <action>
31+
32+
Action for the RBAC policy ("access_as_external" or "access_as_shared") (required)
33+
34+
.. option:: --target-project <target-project>
35+
36+
The project to which the RBAC policy will be enforced (name or ID) (required)
37+
38+
.. option:: --target-project-domain <target-project-domain>
39+
40+
Domain the target project belongs to (name or ID).
41+
This can be used in case collisions between project names exist.
42+
43+
.. option:: --project <project>
44+
45+
The owner project (name or ID)
46+
47+
.. option:: --project-domain <project-domain>
48+
49+
Domain the project belongs to (name or ID).
50+
This can be used in case collisions between project names exist.
51+
52+
.. _network_rbac_create-rbac-policy:
53+
.. describe:: <rbac-object>
54+
55+
The object to which this RBAC policy affects (name or ID for network objects, ID only for QoS policy objects)
56+
57+
network rbac delete
58+
-------------------
59+
60+
Delete network RBAC policy(s)
61+
62+
.. program:: network rbac delete
63+
.. code:: bash
64+
65+
os network rbac delete
66+
<rbac-policy> [<rbac-policy> ...]
67+
68+
.. _network_rbac_delete-rbac-policy:
69+
.. describe:: <rbac-policy>
70+
71+
RBAC policy(s) to delete (ID only)
72+
1173
network rbac list
1274
-----------------
1375

doc/source/specs/command-objects/example.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Delete example(s)
3838
3939
.. describe:: <example>
4040

41-
Example to delete (name or ID)
41+
Example(s) to delete (name or ID)
4242

4343
example list
4444
------------
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
2+
# not use this file except in compliance with the License. You may obtain
3+
# a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10+
# License for the specific language governing permissions and limitations
11+
# under the License.
12+
13+
import uuid
14+
15+
from functional.common import test
16+
17+
18+
class NetworkRBACTests(test.TestCase):
19+
"""Functional tests for network rbac. """
20+
NET_NAME = uuid.uuid4().hex
21+
OBJECT_ID = None
22+
ID = None
23+
HEADERS = ['ID']
24+
FIELDS = ['id']
25+
26+
@classmethod
27+
def setUpClass(cls):
28+
opts = cls.get_opts(cls.FIELDS)
29+
raw_output = cls.openstack('network create ' + cls.NET_NAME + opts)
30+
cls.OBJECT_ID = raw_output.strip('\n')
31+
opts = cls.get_opts(['id', 'object_id'])
32+
raw_output = cls.openstack('network rbac create ' +
33+
cls.OBJECT_ID +
34+
' --action access_as_shared' +
35+
' --target-project admin' +
36+
' --type network' + opts)
37+
cls.ID, object_id, rol = tuple(raw_output.split('\n'))
38+
cls.assertOutput(cls.OBJECT_ID, object_id)
39+
40+
@classmethod
41+
def tearDownClass(cls):
42+
raw_output = cls.openstack('network rbac delete ' + cls.ID)
43+
cls.assertOutput('', raw_output)
44+
raw_output = cls.openstack('network delete ' + cls.OBJECT_ID)
45+
cls.assertOutput('', raw_output)
46+
47+
def test_network_rbac_list(self):
48+
opts = self.get_opts(self.HEADERS)
49+
raw_output = self.openstack('network rbac list' + opts)
50+
self.assertIn(self.ID, raw_output)
51+
52+
def test_network_rbac_show(self):
53+
opts = self.get_opts(self.FIELDS)
54+
raw_output = self.openstack('network rbac show ' + self.ID + opts)
55+
self.assertEqual(self.ID + "\n", raw_output)

openstackclient/network/v2/network_rbac.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,17 @@
1313

1414
"""RBAC action implementations"""
1515

16+
import logging
17+
1618
from osc_lib.command import command
19+
from osc_lib import exceptions
1720
from osc_lib import utils
1821

1922
from openstackclient.i18n import _
23+
from openstackclient.identity import common as identity_common
24+
25+
26+
LOG = logging.getLogger(__name__)
2027

2128

2229
def _get_columns(item):
@@ -30,6 +37,131 @@ def _get_columns(item):
3037
return tuple(sorted(columns))
3138

3239

40+
def _get_attrs(client_manager, parsed_args):
41+
attrs = {}
42+
attrs['object_type'] = parsed_args.type
43+
attrs['action'] = parsed_args.action
44+
45+
network_client = client_manager.network
46+
if parsed_args.type == 'network':
47+
object_id = network_client.find_network(
48+
parsed_args.rbac_object, ignore_missing=False).id
49+
if parsed_args.type == 'qos_policy':
50+
# TODO(Huanxuan Ao): Support finding a object ID by obejct name
51+
# after qos policy finding supported in SDK.
52+
object_id = parsed_args.rbac_object
53+
attrs['object_id'] = object_id
54+
55+
identity_client = client_manager.identity
56+
project_id = identity_common.find_project(
57+
identity_client,
58+
parsed_args.target_project,
59+
parsed_args.target_project_domain,
60+
).id
61+
attrs['target_tenant'] = project_id
62+
if parsed_args.project is not None:
63+
project_id = identity_common.find_project(
64+
identity_client,
65+
parsed_args.project,
66+
parsed_args.project_domain,
67+
).id
68+
attrs['tenant_id'] = project_id
69+
70+
return attrs
71+
72+
73+
class CreateNetworkRBAC(command.ShowOne):
74+
"""Create network RBAC policy"""
75+
76+
def get_parser(self, prog_name):
77+
parser = super(CreateNetworkRBAC, self).get_parser(prog_name)
78+
parser.add_argument(
79+
'rbac_object',
80+
metavar="<rbac-object>",
81+
help=_("The object to which this RBAC policy affects (name or "
82+
"ID for network objects, ID only for QoS policy objects)")
83+
)
84+
parser.add_argument(
85+
'--type',
86+
metavar="<type>",
87+
required=True,
88+
choices=['qos_policy', 'network'],
89+
help=_('Type of the object that RBAC policy '
90+
'affects ("qos_policy" or "network")')
91+
)
92+
parser.add_argument(
93+
'--action',
94+
metavar="<action>",
95+
required=True,
96+
choices=['access_as_external', 'access_as_shared'],
97+
help=_('Action for the RBAC policy '
98+
'("access_as_external" or "access_as_shared")')
99+
)
100+
parser.add_argument(
101+
'--target-project',
102+
required=True,
103+
metavar="<target-project>",
104+
help=_('The project to which the RBAC policy '
105+
'will be enforced (name or ID)')
106+
)
107+
parser.add_argument(
108+
'--target-project-domain',
109+
metavar='<target-project-domain>',
110+
help=_('Domain the target project belongs to (name or ID). '
111+
'This can be used in case collisions between project names '
112+
'exist.'),
113+
)
114+
parser.add_argument(
115+
'--project',
116+
metavar="<project>",
117+
help=_('The owner project (name or ID)')
118+
)
119+
identity_common.add_project_domain_option_to_parser(parser)
120+
return parser
121+
122+
def take_action(self, parsed_args):
123+
client = self.app.client_manager.network
124+
attrs = _get_attrs(self.app.client_manager, parsed_args)
125+
obj = client.create_rbac_policy(**attrs)
126+
columns = _get_columns(obj)
127+
data = utils.get_item_properties(obj, columns)
128+
return columns, data
129+
130+
131+
class DeleteNetworkRBAC(command.Command):
132+
"""Delete network RBAC policy(s)"""
133+
134+
def get_parser(self, prog_name):
135+
parser = super(DeleteNetworkRBAC, self).get_parser(prog_name)
136+
parser.add_argument(
137+
'rbac_policy',
138+
metavar="<rbac-policy>",
139+
nargs='+',
140+
help=_("RBAC policy(s) to delete (ID only)")
141+
)
142+
return parser
143+
144+
def take_action(self, parsed_args):
145+
client = self.app.client_manager.network
146+
result = 0
147+
148+
for rbac in parsed_args.rbac_policy:
149+
try:
150+
obj = client.find_rbac_policy(rbac, ignore_missing=False)
151+
client.delete_rbac_policy(obj)
152+
except Exception as e:
153+
result += 1
154+
LOG.error(_("Failed to delete RBAC policy with "
155+
"ID '%(rbac)s': %(e)s"),
156+
{'rbac': rbac, 'e': e})
157+
158+
if result > 0:
159+
total = len(parsed_args.rbac_policy)
160+
msg = (_("%(result)s of %(total)s RBAC policies failed "
161+
"to delete.") % {'result': result, 'total': total})
162+
raise exceptions.CommandError(msg)
163+
164+
33165
class ListNetworkRBAC(command.Lister):
34166
"""List network RBAC policies"""
35167

openstackclient/tests/network/v2/fakes.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,25 @@ def create_network_rbacs(attrs=None, count=2):
541541

542542
return rbac_policies
543543

544+
@staticmethod
545+
def get_network_rbacs(rbac_policies=None, count=2):
546+
"""Get an iterable MagicMock object with a list of faked rbac policies.
547+
548+
If rbac policies list is provided, then initialize the Mock object
549+
with the list. Otherwise create one.
550+
551+
:param List rbac_policies:
552+
A list of FakeResource objects faking rbac policies
553+
:param int count:
554+
The number of rbac policies to fake
555+
:return:
556+
An iterable Mock object with side_effect set to a list of faked
557+
rbac policies
558+
"""
559+
if rbac_policies is None:
560+
rbac_policies = FakeNetworkRBAC.create_network_rbacs(count)
561+
return mock.MagicMock(side_effect=rbac_policies)
562+
544563

545564
class FakeRouter(object):
546565
"""Fake one or more routers."""

0 commit comments

Comments
 (0)