James Cooper

Modify role.delete to no-op if role missing

If "kappa delete" fails midway then re-running it will fail during
role removal.

This PR modifies `delete` to check if the role exists.  If it does not
then we log a debug line and return early.

I also consolidated various methods that were calling `get_role` so that
error handling is consistent, and removed `_find_all_roles` as
`get_role` is sufficient, and probably faster (particularly for accounts
with many roles).
......@@ -52,28 +52,26 @@ class Role(object):
@property
def arn(self):
if self._arn is None:
try:
response = self._iam_client.call(
'get_role', RoleName=self.name)
LOG.debug(response)
self._arn = response['Role']['Arn']
except Exception:
role = self._get_role()
if role:
self._arn = role['Arn']
else:
LOG.debug('Unable to find ARN for role: %s', self.name)
return self._arn
def _find_all_roles(self):
def _get_role(self):
try:
response = self._iam_client.call('list_roles')
response = self._iam_client.call('get_role', RoleName=self.name)
return response['Role']
except ClientError as e:
if e.response['Error']['Code'] != 'NoSuchEntity':
LOG.exception('Error getting role')
except Exception:
LOG.exception('Error listing roles')
response = {}
return response.get('Roles', list())
LOG.exception('Error getting role')
return None
def exists(self):
for role in self._find_all_roles():
if role['RoleName'] == self.name:
return role
return None
return self._get_role() is not None
def create(self):
LOG.info('creating role %s', self.name)
......@@ -99,6 +97,10 @@ class Role(object):
def delete(self):
response = None
if not self.exists():
LOG.debug('role %s does not exist - skipping delete', self.name)
return response
LOG.debug('deleting role %s', self.name)
try:
LOG.debug('First detach the policy from the role')
......@@ -117,11 +119,7 @@ class Role(object):
def status(self):
LOG.debug('getting status for role %s', self.name)
try:
response = self._iam_client.call(
'get_role', RoleName=self.name)
LOG.debug(response)
except ClientError:
role = self._get_role()
if not role:
LOG.debug('role %s not found', self.name)
response = None
return response
return role
......
......@@ -108,8 +108,8 @@ def status(ctx):
click.echo(click.style('Role', bold=True))
if status['role']:
line = ' {} ({})'.format(
status['role']['Role']['RoleName'],
status['role']['Role']['Arn'])
status['role']['RoleName'],
status['role']['Arn'])
click.echo(click.style(line, fg='green'))
click.echo(click.style('Function', bold=True))
if status['function']:
......