196 lines
6 KiB
Python
196 lines
6 KiB
Python
#!/usr/bin/python
|
|
#
|
|
# (c) 2013, Nimbis Services
|
|
#
|
|
# This file is part of Ansible
|
|
#
|
|
# Ansible is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Ansible is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
|
DOCUMENTATION = '''
|
|
---
|
|
module: ec2_ami_search
|
|
short_description: Retrieve AWS AMI for a given operating system.
|
|
version_added: "1.6"
|
|
description:
|
|
- Look up the most recent AMI on AWS for a given operating system.
|
|
- Returns C(ami), C(aki), C(ari), C(serial), C(tag)
|
|
- If there is no AKI or ARI associated with an image, these will be C(null).
|
|
- Only supports images from cloud-images.ubuntu.com
|
|
- 'Example output: C({"ami": "ami-69f5a900", "changed": false, "aki": "aki-88aa75e1", "tag": "release", "ari": null, "serial": "20131024"})'
|
|
version_added: "1.6"
|
|
options:
|
|
distro:
|
|
description: Linux distribution (e.g., C(ubuntu))
|
|
required: true
|
|
choices: ["ubuntu"]
|
|
release:
|
|
description: short name of the release (e.g., C(precise))
|
|
required: true
|
|
stream:
|
|
description: Type of release.
|
|
required: false
|
|
default: "server"
|
|
choices: ["server", "desktop"]
|
|
store:
|
|
description: Back-end store for instance
|
|
required: false
|
|
default: "ebs"
|
|
choices: ["ebs", "instance-store"]
|
|
arch:
|
|
description: CPU architecture
|
|
required: false
|
|
default: "amd64"
|
|
choices: ["i386", "amd64"]
|
|
region:
|
|
description: EC2 region
|
|
required: false
|
|
default: us-east-1
|
|
choices: ["ap-northeast-1", "ap-southeast-1", "ap-southeast-2",
|
|
"eu-west-1", "sa-east-1", "us-east-1", "us-west-1", "us-west-2"]
|
|
virt:
|
|
description: virutalization type
|
|
required: false
|
|
default: paravirtual
|
|
choices: ["paravirtual", "hvm"]
|
|
|
|
author: Lorin Hochstein
|
|
'''
|
|
|
|
EXAMPLES = '''
|
|
- name: Launch an Ubuntu 12.04 (Precise Pangolin) EC2 instance
|
|
hosts: 127.0.0.1
|
|
connection: local
|
|
tasks:
|
|
- name: Get the Ubuntu precise AMI
|
|
ec2_ami_search: distro=ubuntu release=precise region=us-west-1 store=instance-store
|
|
register: ubuntu_image
|
|
- name: Start the EC2 instance
|
|
ec2: image={{ ubuntu_image.ami }} instance_type=m1.small key_name=mykey
|
|
'''
|
|
|
|
import csv
|
|
import json
|
|
import urllib2
|
|
import urlparse
|
|
|
|
SUPPORTED_DISTROS = ['ubuntu']
|
|
|
|
AWS_REGIONS = ['ap-northeast-1',
|
|
'ap-southeast-1',
|
|
'ap-southeast-2',
|
|
'eu-west-1',
|
|
'sa-east-1',
|
|
'us-east-1',
|
|
'us-west-1',
|
|
'us-west-2']
|
|
|
|
|
|
def get_url(module, url):
|
|
""" Get url and return response """
|
|
try:
|
|
r = urllib2.urlopen(url)
|
|
except (urllib2.HTTPError, urllib2.URLError), e:
|
|
code = getattr(e, 'code', -1)
|
|
module.fail_json(msg="Request failed: %s" % str(e), status_code=code)
|
|
return r
|
|
|
|
|
|
def ubuntu(module):
|
|
""" Get the ami for ubuntu """
|
|
|
|
release = module.params['release']
|
|
stream = module.params['stream']
|
|
store = module.params['store']
|
|
arch = module.params['arch']
|
|
region = module.params['region']
|
|
virt = module.params['virt']
|
|
|
|
url = get_ubuntu_url(release, stream)
|
|
|
|
req = get_url(module, url)
|
|
reader = csv.reader(req, delimiter='\t')
|
|
try:
|
|
ami, aki, ari, tag, serial = lookup_ubuntu_ami(reader, release, stream,
|
|
store, arch, region, virt)
|
|
module.exit_json(changed=False, ami=ami, aki=aki, ari=ari, tag=tag,
|
|
serial=serial)
|
|
except KeyError:
|
|
module.fail_json(msg="No matching AMI found")
|
|
|
|
|
|
def lookup_ubuntu_ami(table, release, stream, store, arch, region, virt):
|
|
""" Look up the Ubuntu AMI that matches query given a table of AMIs
|
|
|
|
table: an iterable that returns a row of
|
|
(release, stream, tag, serial, region, ami, aki, ari, virt)
|
|
release: ubuntu release name
|
|
stream: 'server' or 'desktop'
|
|
store: 'ebs' or 'instance-store'
|
|
arch: 'i386' or 'amd64'
|
|
region: EC2 region
|
|
virt: 'paravirtual' or 'hvm'
|
|
|
|
Returns (ami, aki, ari, tag, serial)"""
|
|
expected = (release, stream, store, arch, region, virt)
|
|
|
|
for row in table:
|
|
(actual_release, actual_stream, tag, serial,
|
|
actual_store, actual_arch, actual_region, ami, aki, ari,
|
|
actual_virt) = row
|
|
actual = (actual_release, actual_stream, actual_store, actual_arch,
|
|
actual_region, actual_virt)
|
|
if actual == expected:
|
|
# aki and ari are sometimes blank
|
|
if aki == '':
|
|
aki = None
|
|
if ari == '':
|
|
ari = None
|
|
return (ami, aki, ari, tag, serial)
|
|
|
|
raise KeyError()
|
|
|
|
|
|
def get_ubuntu_url(release, stream):
|
|
url = "https://cloud-images.ubuntu.com/query/%s/%s/released.current.txt"
|
|
return url % (release, stream)
|
|
|
|
|
|
def main():
|
|
arg_spec = dict(
|
|
distro=dict(required=True, choices=SUPPORTED_DISTROS),
|
|
release=dict(required=True),
|
|
stream=dict(required=False, default='server',
|
|
choices=['desktop', 'server']),
|
|
store=dict(required=False, default='ebs',
|
|
choices=['ebs', 'instance-store']),
|
|
arch=dict(required=False, default='amd64',
|
|
choices=['i386', 'amd64']),
|
|
region=dict(required=False, default='us-east-1', choices=AWS_REGIONS),
|
|
virt=dict(required=False, default='paravirtual',
|
|
choices=['paravirtual', 'hvm'])
|
|
)
|
|
module = AnsibleModule(argument_spec=arg_spec)
|
|
distro = module.params['distro']
|
|
|
|
if distro == 'ubuntu':
|
|
ubuntu(module)
|
|
else:
|
|
module.fail_json(msg="Unsupported distro: %s" % distro)
|
|
|
|
|
|
|
|
# this is magic, see lib/ansible/module_common.py
|
|
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
|
|
|
if __name__ == '__main__':
|
|
main()
|