From e002496f0e4ae1ab896d19b7e3fa9e4c56d17251 Mon Sep 17 00:00:00 2001 From: James Laska Date: Wed, 2 Oct 2013 11:09:23 -0400 Subject: [PATCH] Add idempotency support to ec2_group --- library/cloud/ec2_group | 140 ++++++++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 55 deletions(-) diff --git a/library/cloud/ec2_group b/library/cloud/ec2_group index 4349374e99d..46f4a3fcebd 100644 --- a/library/cloud/ec2_group +++ b/library/cloud/ec2_group @@ -49,6 +49,14 @@ options: required: false default: null aliases: [] + state: + version_added: "1.4" + description: + - create or delete security group + required: false + default: 'present' + aliases: [] + requirements: [ "boto" ] ''' @@ -105,6 +113,7 @@ def main(): ec2_secret_key=dict(aliases=['EC2_SECRET_KEY'], no_log=True), ec2_access_key=dict(aliases=['EC2_ACCESS_KEY']), region=dict(choices=['eu-west-1', 'sa-east-1', 'us-east-1', 'ap-northeast-1', 'us-west-2', 'us-west-1', 'ap-southeast-1', 'ap-southeast-2']), + state = dict(default='present', choices=['present', 'absent']), ), supports_check_mode=True, ) @@ -116,6 +125,7 @@ def main(): ec2_secret_key = module.params.get('ec2_secret_key') ec2_access_key = module.params.get('ec2_access_key') region = module.params.get('region') + state = module.params.get('state') changed = False @@ -152,74 +162,94 @@ def main(): if curGroup.name == name and curGroup.vpc_id == vpc_id: group = curGroup - # if found, check the group parameters are correct - if group: - group_in_use = False - rs = ec2.get_all_instances() - for r in rs: - for i in r.instances: - group_in_use |= reduce(lambda x, y: x | (y.name == 'public-ssh'), i.groups, False) + # Ensure requested group is absent + if state == 'absent': + if group: + '''found a match, delete it''' + try: + group.delete() + except Exception, e: + module.fail_json(msg="Unable to delete security group '%s' - %s" % (group, e)) + else: + group = None + changed = True + else: + '''no match found, no changes required''' - if group.description != description: - if group_in_use: - module.fail_json(msg="Group description does not match, but it is in use so cannot be changed.") - group.delete() - group = None + # Ensure requested group is present + elif state == 'present': + if group: + '''existing group found''' + # check the group parameters are correct + group_in_use = False + rs = ec2.get_all_instances() + for r in rs: + for i in r.instances: + group_in_use |= reduce(lambda x, y: x | (y.name == 'public-ssh'), i.groups, False) - # if the group doesn't exist, create it now - if not group: - if not module.check_mode: - group = ec2.create_security_group(name, description, vpc_id=vpc_id) - changed = True + if group.description != description: + if group_in_use: + module.fail_json(msg="Group description does not match, but it is in use so cannot be changed.") + + # if the group doesn't exist, create it now + else: + '''no match found, create it''' + if not module.check_mode: + group = ec2.create_security_group(name, description, vpc_id=vpc_id) + changed = True + else: + module.fail_json(msg="Unsupported state requested: %s" % state) # create a lookup for all existing rules on the group - groupRules = {} if group: + groupRules = {} addRulesToLookup(group.rules, 'in', groupRules) - # Now, go through all the defined rules and ensure they are there. - if rules: - for rule in rules: - group_id = None - ip = None - if 'group_id' in rule and 'cidr_ip' in rule: - module.fail_json(msg="Specify group_id OR cidr_ip, not both") - elif 'group_id' in rule: - group_id = rule['group_id'] - elif 'cidr_ip' in rule: - ip = rule['cidr_ip'] + # Now, go through all provided rules and ensure they are there. + if rules: + for rule in rules: + group_id = None + ip = None + if 'group_id' in rule and 'cidr_ip' in rule: + module.fail_json(msg="Specify group_id OR cidr_ip, not both") + elif 'group_id' in rule: + group_id = rule['group_id'] + elif 'cidr_ip' in rule: + ip = rule['cidr_ip'] - if rule['proto'] == 'all': - rule['proto'] = -1 - rule['from_port'] = None - rule['to_port'] = None + if rule['proto'] == 'all': + rule['proto'] = -1 + rule['from_port'] = None + rule['to_port'] = None - ruleId = "%s-%s-%s-%s-%s-%s" % ('in', rule['proto'], rule['from_port'], rule['to_port'], group_id, ip) - if ruleId in groupRules: - del groupRules[ruleId] - continue + # If rule already exists, don't later delete it + ruleId = "%s-%s-%s-%s-%s-%s" % ('in', rule['proto'], rule['from_port'], rule['to_port'], group_id, ip) + if ruleId in groupRules: + del groupRules[ruleId] + # Otherwise, add new rule + else: + grantGroup = None + if group_id: + grantGroup = groups[group_id] - grantGroup = None - if group_id: - grantGroup = groups[group_id] + if not module.check_mode: + group.authorize(rule['proto'], rule['from_port'], rule['to_port'], ip, grantGroup) + changed = True - if not module.check_mode: - group.authorize(rule['proto'], rule['from_port'], rule['to_port'], ip, grantGroup) - changed = True + # Finally, remove anything left in the groupRules -- these will be defunct rules + for rule in groupRules.itervalues(): + for grant in rule.grants: + grantGroup = None + if grant.group_id: + grantGroup = groups[grant.group_id] + if not module.check_mode: + group.revoke(rule.ip_protocol, rule.from_port, rule.to_port, grant.cidr_ip, grantGroup) + changed = True - # Finally, remove anything left in the groupRules -- these will be defunct rules - for rule in groupRules.itervalues(): - for grant in rule.grants: - grantGroup = None - if grant.group_id: - grantGroup = groups[grant.group_id] - if not module.check_mode: - group.revoke(rule.ip_protocol, rule.from_port, rule.to_port, grant.cidr_ip, grantGroup) - changed = True - - if not group: + if group: + module.exit_json(changed=changed, group_id=group.id) + else: module.exit_json(changed=changed, group_id=None) - module.exit_json(changed=changed, group_id=group.id) # this is magic, see lib/ansible/module_common.py #<>