Merge "Implement network rbac create and delete commands" · madorn/python-openstackclient@fe650e2 · GitHub
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

8 files changed

Lines changed: 528 additions & 5 deletions

File tree

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

Lines changed: 62 additions & 0 deletions

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

0 commit comments

Comments
 (0)