ec2_key 7.1 KB
Newer Older
Vincent Viallet committed
1 2 3 4 5 6 7
#!/usr/bin/python
# -*- coding: utf-8 -*-


DOCUMENTATION = '''
---
module: ec2_key
Vincent Viallet committed
8
version_added: "1.5"
Vincent Viallet committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
short_description: maintain an ec2 key pair.
description:
    - maintains ec2 key pairs. This module has a dependency on python-boto >= 2.5
options:
  name:
    description:
      - Name of the key pair.
    required: true
  key_material:
    description:
      - Public key material.
    required: false
  region:
    description:
      - the EC2 region to use
    required: false
    default: null
    aliases: []
  state:
    description:
29
      - create or delete keypair
Vincent Viallet committed
30 31 32
    required: false
    default: 'present'
    aliases: []
33 34 35 36 37 38 39 40 41 42 43 44 45 46
  wait:
    description:
      - Wait for the specified action to complete before returning.
    required: false
    default: false
    aliases: []
    version_added: "1.6"
  wait_timeout:
    description:
      - How long before wait gives up, in seconds
    required: false
    default: 300
    aliases: []
    version_added: "1.6"
Vincent Viallet committed
47

48
extends_documentation_fragment: aws
Vincent Viallet committed
49 50 51 52
author: Vincent Viallet
'''

EXAMPLES = '''
53 54 55
# Note: None of these examples set aws_access_key, aws_secret_key, or region.
# It is assumed that their matching environment variables are set.

Vincent Viallet committed
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
# Creates a new ec2 key pair named `example` if not present, returns generated
# private key
- name: example ec2 key
  local_action:
    module: ec2_key
    name: example

# Creates a new ec2 key pair named `example` if not present using provided key
# material
- name: example2 ec2 key
  local_action:
    module: ec2_key
    name: example2
    key_material: 'ssh-rsa AAAAxyz...== me@example.com'
    state: present

# Creates a new ec2 key pair named `example` if not present using provided key
# material
- name: example3 ec2 key
  local_action:
    module: ec2_key
    name: example3
    key_material: "{{ item }}"
  with_file: /path/to/public_key.id_rsa.pub

# Removes ec2 key pair by name
- name: remove example key
  local_action:
    module: ec2_key
    name: example
    state: absent
'''

try:
    import boto.ec2
except ImportError:
    print "failed=True msg='boto required for this module'"
    sys.exit(1)

95 96 97 98
import random
import string


Vincent Viallet committed
99
def main():
100 101
    argument_spec = ec2_argument_spec()
    argument_spec.update(dict(
Vincent Viallet committed
102 103 104
            name=dict(required=True),
            key_material=dict(required=False),
            state = dict(default='present', choices=['present', 'absent']),
105 106
            wait = dict(type='bool', default=False),
            wait_timeout = dict(default=300),
107 108 109 110
        )
    )
    module = AnsibleModule(
        argument_spec=argument_spec,
Vincent Viallet committed
111 112 113 114 115 116
        supports_check_mode=True,
    )

    name = module.params['name']
    state = module.params.get('state')
    key_material = module.params.get('key_material')
117 118
    wait = module.params.get('wait')
    wait_timeout = int(module.params.get('wait_timeout'))
Vincent Viallet committed
119 120 121

    changed = False

122
    ec2 = ec2_connect(module)
Vincent Viallet committed
123 124 125 126 127 128 129 130 131 132

    # find the key if present
    key = ec2.get_key_pair(name)

    # Ensure requested key is absent
    if state == 'absent':
        if key:
            '''found a match, delete it'''
            try:
                key.delete()
133 134 135 136 137 138 139 140 141 142
                if wait:
                    start = time.time()
                    action_complete = False
                    while (time.time() - start) < wait_timeout:
                        if not ec2.get_key_pair(name):
                            action_complete = True
                            break
                        time.sleep(1)
                    if not action_complete:
                        module.fail_json(msg="timed out while waiting for the key to be removed")
Vincent Viallet committed
143
            except Exception, e:
144
                module.fail_json(msg="Unable to delete key pair '%s' - %s" % (key, e))
Vincent Viallet committed
145 146 147 148 149 150
            else:
                key = None
                changed = True
        else:
            '''no match found, no changes required'''

151
    # Ensure requested key is present
Vincent Viallet committed
152 153
    elif state == 'present':
        if key:
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192
            # existing key found
            if key_material:
                # EC2's fingerprints are non-trivial to generate, so push this key 
                # to a temporary name and make ec2 calculate the fingerprint for us.
                #
                # http://blog.jbrowne.com/?p=23
                # https://forums.aws.amazon.com/thread.jspa?messageID=352828

                # find an unused name
                test = 'empty'
                while test:
                    randomchars = [random.choice(string.ascii_letters + string.digits) for x in range(0,10)]
                    tmpkeyname = "ansible-" + ''.join(randomchars)
                    test = ec2.get_key_pair(tmpkeyname)

                # create tmp key
                tmpkey = ec2.import_key_pair(tmpkeyname, key_material)
                # get tmp key fingerprint
                tmpfingerprint = tmpkey.fingerprint
                # delete tmp key
                tmpkey.delete()

                if key.fingerprint != tmpfingerprint:
                    if not module.check_mode:
                        key.delete()
                        key = ec2.import_key_pair(name, key_material)    

                        if wait:
                            start = time.time()
                            action_complete = False
                            while (time.time() - start) < wait_timeout:
                                if ec2.get_key_pair(name):
                                    action_complete = True
                                    break
                                time.sleep(1)
                            if not action_complete:
                                module.fail_json(msg="timed out while waiting for the key to be re-created")

                    changed = True
Vincent Viallet committed
193 194
            pass

195
        # if the key doesn't exist, create it now
Vincent Viallet committed
196 197 198 199 200 201 202 203 204 205 206 207
        else:
            '''no match found, create it'''
            if not module.check_mode:
                if key_material:
                    '''We are providing the key, need to import'''
                    key = ec2.import_key_pair(name, key_material)
                else:
                    '''
                    No material provided, let AWS handle the key creation and 
                    retrieve the private key
                    '''
                    key = ec2.create_key_pair(name)
208 209 210 211 212 213 214 215 216 217 218 219

                if wait:
                    start = time.time()
                    action_complete = False
                    while (time.time() - start) < wait_timeout:
                        if ec2.get_key_pair(name):
                            action_complete = True
                            break
                        time.sleep(1)
                    if not action_complete:
                        module.fail_json(msg="timed out while waiting for the key to be created")

Vincent Viallet committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
            changed = True

    if key:
        data = {
            'name': key.name,
            'fingerprint': key.fingerprint
        }
        if key.material:
            data.update({'private_key': key.material})

        module.exit_json(changed=changed, key=data)
    else:
        module.exit_json(changed=changed, key=None)

# import module snippets
from ansible.module_utils.basic import *
from ansible.module_utils.ec2 import *

main()