Skip to content

Commit 96578cb

Browse files
author
Huanxuan Ao
committed
Error handling for delete commands in identity
Add missing multi deletion error handling for identity delete commands. All delete commands in identity support error handling now. Change-Id: I05626dcb5e516a423d610906347b02236ba7eeaf
1 parent f020a9f commit 96578cb

16 files changed

Lines changed: 392 additions & 45 deletions

File tree

openstackclient/identity/v2_0/project.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from keystoneauth1 import exceptions as ks_exc
2121
from osc_lib.cli import parseractions
2222
from osc_lib.command import command
23+
from osc_lib import exceptions
2324
from osc_lib import utils
2425
import six
2526

@@ -117,12 +118,25 @@ def get_parser(self, prog_name):
117118
def take_action(self, parsed_args):
118119
identity_client = self.app.client_manager.identity
119120

121+
errors = 0
120122
for project in parsed_args.projects:
121-
project_obj = utils.find_resource(
122-
identity_client.tenants,
123-
project,
124-
)
125-
identity_client.tenants.delete(project_obj.id)
123+
try:
124+
project_obj = utils.find_resource(
125+
identity_client.tenants,
126+
project,
127+
)
128+
identity_client.tenants.delete(project_obj.id)
129+
except Exception as e:
130+
errors += 1
131+
LOG.error(_("Failed to delete project with "
132+
"name or ID '%(project)s': %(e)s"),
133+
{'project': project, 'e': e})
134+
135+
if errors > 0:
136+
total = len(parsed_args.projects)
137+
msg = (_("%(errors)s of %(total)s projects failed "
138+
"to delete.") % {'errors': errors, 'total': total})
139+
raise exceptions.CommandError(msg)
126140

127141

128142
class ListProject(command.Lister):

openstackclient/identity/v2_0/role.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,25 @@ def get_parser(self, prog_name):
124124
def take_action(self, parsed_args):
125125
identity_client = self.app.client_manager.identity
126126

127+
errors = 0
127128
for role in parsed_args.roles:
128-
role_obj = utils.find_resource(
129-
identity_client.roles,
130-
role,
131-
)
132-
identity_client.roles.delete(role_obj.id)
129+
try:
130+
role_obj = utils.find_resource(
131+
identity_client.roles,
132+
role,
133+
)
134+
identity_client.roles.delete(role_obj.id)
135+
except Exception as e:
136+
errors += 1
137+
LOG.error(_("Failed to delete role with "
138+
"name or ID '%(role)s': %(e)s"),
139+
{'role': role, 'e': e})
140+
141+
if errors > 0:
142+
total = len(parsed_args.roles)
143+
msg = (_("%(errors)s of %(total)s roles failed "
144+
"to delete.") % {'errors': errors, 'total': total})
145+
raise exceptions.CommandError(msg)
133146

134147

135148
class ListRole(command.Lister):

openstackclient/identity/v2_0/user.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from keystoneauth1 import exceptions as ks_exc
2121
from osc_lib.command import command
22+
from osc_lib import exceptions
2223
from osc_lib import utils
2324
import six
2425

@@ -145,12 +146,25 @@ def get_parser(self, prog_name):
145146
def take_action(self, parsed_args):
146147
identity_client = self.app.client_manager.identity
147148

149+
errors = 0
148150
for user in parsed_args.users:
149-
user_obj = utils.find_resource(
150-
identity_client.users,
151-
user,
152-
)
153-
identity_client.users.delete(user_obj.id)
151+
try:
152+
user_obj = utils.find_resource(
153+
identity_client.users,
154+
user,
155+
)
156+
identity_client.users.delete(user_obj.id)
157+
except Exception as e:
158+
errors += 1
159+
LOG.error(_("Failed to delete user with "
160+
"name or ID '%(user)s': %(e)s"),
161+
{'user': user, 'e': e})
162+
163+
if errors > 0:
164+
total = len(parsed_args.users)
165+
msg = (_("%(errors)s of %(total)s users failed "
166+
"to delete.") % {'errors': errors, 'total': total})
167+
raise exceptions.CommandError(msg)
154168

155169

156170
class ListUser(command.Lister):

openstackclient/identity/v3/group.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
from keystoneauth1 import exceptions as ks_exc
2222
from osc_lib.command import command
23+
from osc_lib import exceptions
2324
from osc_lib import utils
2425
import six
2526

@@ -194,11 +195,24 @@ def get_parser(self, prog_name):
194195
def take_action(self, parsed_args):
195196
identity_client = self.app.client_manager.identity
196197

198+
errors = 0
197199
for group in parsed_args.groups:
198-
group_obj = common.find_group(identity_client,
199-
group,
200-
parsed_args.domain)
201-
identity_client.groups.delete(group_obj.id)
200+
try:
201+
group_obj = common.find_group(identity_client,
202+
group,
203+
parsed_args.domain)
204+
identity_client.groups.delete(group_obj.id)
205+
except Exception as e:
206+
errors += 1
207+
LOG.error(_("Failed to delete group with "
208+
"name or ID '%(group)s': %(e)s"),
209+
{'group': group, 'e': e})
210+
211+
if errors > 0:
212+
total = len(parsed_args.groups)
213+
msg = (_("%(errors)s of %(total)s groups failed "
214+
"to delete.") % {'errors': errors, 'total': total})
215+
raise exceptions.CommandError(msg)
202216

203217

204218
class ListGroup(command.Lister):

openstackclient/identity/v3/project.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from keystoneauth1 import exceptions as ks_exc
2121
from osc_lib.cli import parseractions
2222
from osc_lib.command import command
23+
from osc_lib import exceptions
2324
from osc_lib import utils
2425
import six
2526

@@ -148,15 +149,28 @@ def take_action(self, parsed_args):
148149
domain = None
149150
if parsed_args.domain:
150151
domain = common.find_domain(identity_client, parsed_args.domain)
152+
errors = 0
151153
for project in parsed_args.projects:
152-
if domain is not None:
153-
project_obj = utils.find_resource(identity_client.projects,
154-
project,
155-
domain_id=domain.id)
156-
else:
157-
project_obj = utils.find_resource(identity_client.projects,
158-
project)
159-
identity_client.projects.delete(project_obj.id)
154+
try:
155+
if domain is not None:
156+
project_obj = utils.find_resource(identity_client.projects,
157+
project,
158+
domain_id=domain.id)
159+
else:
160+
project_obj = utils.find_resource(identity_client.projects,
161+
project)
162+
identity_client.projects.delete(project_obj.id)
163+
except Exception as e:
164+
errors += 1
165+
LOG.error(_("Failed to delete project with "
166+
"name or ID '%(project)s': %(e)s"),
167+
{'project': project, 'e': e})
168+
169+
if errors > 0:
170+
total = len(parsed_args.projects)
171+
msg = (_("%(errors)s of %(total)s projects failed "
172+
"to delete.") % {'errors': errors, 'total': total})
173+
raise exceptions.CommandError(msg)
160174

161175

162176
class ListProject(command.Lister):

openstackclient/identity/v3/role.py

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
from keystoneauth1 import exceptions as ks_exc
2222
from osc_lib.command import command
23+
from osc_lib import exceptions
2324
from osc_lib import utils
2425
import six
2526

@@ -223,14 +224,26 @@ def take_action(self, parsed_args):
223224
if parsed_args.domain:
224225
domain_id = common.find_domain(identity_client,
225226
parsed_args.domain).id
226-
227+
errors = 0
227228
for role in parsed_args.roles:
228-
role_obj = utils.find_resource(
229-
identity_client.roles,
230-
role,
231-
domain_id=domain_id
232-
)
233-
identity_client.roles.delete(role_obj.id)
229+
try:
230+
role_obj = utils.find_resource(
231+
identity_client.roles,
232+
role,
233+
domain_id=domain_id
234+
)
235+
identity_client.roles.delete(role_obj.id)
236+
except Exception as e:
237+
errors += 1
238+
LOG.error(_("Failed to delete role with "
239+
"name or ID '%(role)s': %(e)s"),
240+
{'role': role, 'e': e})
241+
242+
if errors > 0:
243+
total = len(parsed_args.roles)
244+
msg = (_("%(errors)s of %(total)s roles failed "
245+
"to delete.") % {'errors': errors, 'total': total})
246+
raise exceptions.CommandError(msg)
234247

235248

236249
class ListRole(command.Lister):

openstackclient/identity/v3/trust.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,20 @@
1414
"""Identity v3 Trust action implementations"""
1515

1616
import datetime
17+
import logging
1718

1819
from osc_lib.command import command
20+
from osc_lib import exceptions
1921
from osc_lib import utils
2022
import six
2123

2224
from openstackclient.i18n import _
2325
from openstackclient.identity import common
2426

2527

28+
LOG = logging.getLogger(__name__)
29+
30+
2631
class CreateTrust(command.ShowOne):
2732
_description = _("Create new trust")
2833

@@ -145,9 +150,24 @@ def get_parser(self, prog_name):
145150

146151
def take_action(self, parsed_args):
147152
identity_client = self.app.client_manager.identity
148-
for t in parsed_args.trust:
149-
trust_obj = utils.find_resource(identity_client.trusts, t)
150-
identity_client.trusts.delete(trust_obj.id)
153+
154+
errors = 0
155+
for trust in parsed_args.trust:
156+
try:
157+
trust_obj = utils.find_resource(identity_client.trusts,
158+
trust)
159+
identity_client.trusts.delete(trust_obj.id)
160+
except Exception as e:
161+
errors += 1
162+
LOG.error(_("Failed to delete trust with "
163+
"name or ID '%(trust)s': %(e)s"),
164+
{'trust': trust, 'e': e})
165+
166+
if errors > 0:
167+
total = len(parsed_args.trust)
168+
msg = (_("%(errors)s of %(total)s trusts failed "
169+
"to delete.") % {'errors': errors, 'total': total})
170+
raise exceptions.CommandError(msg)
151171

152172

153173
class ListTrust(command.Lister):

openstackclient/identity/v3/user.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
from keystoneauth1 import exceptions as ks_exc
2222
from osc_lib.command import command
23+
from osc_lib import exceptions
2324
from osc_lib import utils
2425
import six
2526

@@ -161,15 +162,28 @@ def take_action(self, parsed_args):
161162
domain = None
162163
if parsed_args.domain:
163164
domain = common.find_domain(identity_client, parsed_args.domain)
165+
errors = 0
164166
for user in parsed_args.users:
165-
if domain is not None:
166-
user_obj = utils.find_resource(identity_client.users,
167-
user,
168-
domain_id=domain.id)
169-
else:
170-
user_obj = utils.find_resource(identity_client.users,
171-
user)
172-
identity_client.users.delete(user_obj.id)
167+
try:
168+
if domain is not None:
169+
user_obj = utils.find_resource(identity_client.users,
170+
user,
171+
domain_id=domain.id)
172+
else:
173+
user_obj = utils.find_resource(identity_client.users,
174+
user)
175+
identity_client.users.delete(user_obj.id)
176+
except Exception as e:
177+
errors += 1
178+
LOG.error(_("Failed to delete user with "
179+
"name or ID '%(user)s': %(e)s"),
180+
{'user': user, 'e': e})
181+
182+
if errors > 0:
183+
total = len(parsed_args.users)
184+
msg = (_("%(errors)s of %(total)s users failed "
185+
"to delete.") % {'errors': errors, 'total': total})
186+
raise exceptions.CommandError(msg)
173187

174188

175189
class ListUser(command.Lister):

openstackclient/tests/unit/identity/v2_0/test_project.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313
# under the License.
1414
#
1515

16+
import mock
17+
1618
from keystoneauth1 import exceptions as ks_exc
1719
from osc_lib import exceptions
20+
from osc_lib import utils
1821

1922
from openstackclient.identity.v2_0 import project
2023
from openstackclient.tests.unit.identity.v2_0 import fakes as identity_fakes
@@ -302,6 +305,32 @@ def test_project_delete_no_options(self):
302305
)
303306
self.assertIsNone(result)
304307

308+
@mock.patch.object(utils, 'find_resource')
309+
def test_delete_multi_projects_with_exception(self, find_mock):
310+
find_mock.side_effect = [self.fake_project,
311+
exceptions.CommandError]
312+
arglist = [
313+
self.fake_project.id,
314+
'unexist_project',
315+
]
316+
verifylist = [
317+
('projects', arglist),
318+
]
319+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
320+
321+
try:
322+
self.cmd.take_action(parsed_args)
323+
self.fail('CommandError should be raised.')
324+
except exceptions.CommandError as e:
325+
self.assertEqual('1 of 2 projects failed to delete.',
326+
str(e))
327+
328+
find_mock.assert_any_call(self.projects_mock, self.fake_project.id)
329+
find_mock.assert_any_call(self.projects_mock, 'unexist_project')
330+
331+
self.assertEqual(2, find_mock.call_count)
332+
self.projects_mock.delete.assert_called_once_with(self.fake_project.id)
333+
305334

306335
class TestProjectList(TestProject):
307336

0 commit comments

Comments
 (0)