Rebase attempt

No idea if I'm rebasing properly or not.  This is my first attempt.
reviewable/pr18780/r1
Bruce Pennypacker 11 years ago
parent 5e0b083730
commit 11470fea04

@ -43,10 +43,10 @@ options:
aliases: [] aliases: []
region: region:
description: description:
- The AWS region the stack will be launched in - The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used.
required: true required: true
default: null default: null
aliases: [] aliases: ['aws_region', 'ec2_region']
state: state:
description: description:
- If state is "present", stack will be created. If state is "present" and if stack exists and template has changed, it will be updated. - If state is "present", stack will be created. If state is "present" and if stack exists and template has changed, it will be updated.
@ -81,10 +81,24 @@ tasks:
ClusterSize: 3 ClusterSize: 3
''' '''
import boto.cloudformation.connection
import json import json
import time import time
try:
import boto.cloudformation.connection
except ImportError:
print "failed=True msg='boto required for this module'"
sys.exit(1)
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']
class Region: class Region:
def __init__(self, region): def __init__(self, region):
'''connects boto to the region specified in the cloudformation template''' '''connects boto to the region specified in the cloudformation template'''
@ -146,11 +160,7 @@ def main():
argument_spec=dict( argument_spec=dict(
stack_name=dict(required=True), stack_name=dict(required=True),
template_parameters=dict(required=False), template_parameters=dict(required=False),
region=dict(required=True, region=dict(aliases=['aws_region', 'ec2_region'], required=True, choices=AWS_REGIONS),
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']),
state=dict(default='present', choices=['present', 'absent']), state=dict(default='present', choices=['present', 'absent']),
template=dict(default=None, required=True), template=dict(default=None, required=True),
disable_rollback=dict(default=False) disable_rollback=dict(default=False)
@ -159,16 +169,25 @@ def main():
state = module.params['state'] state = module.params['state']
stack_name = module.params['stack_name'] stack_name = module.params['stack_name']
region = Region(module.params['region']) r = module.params['region']
template_body = open(module.params['template'], 'r').read() template_body = open(module.params['template'], 'r').read()
disable_rollback = module.params['disable_rollback'] disable_rollback = module.params['disable_rollback']
template_parameters = module.params['template_parameters'] template_parameters = module.params['template_parameters']
if not r:
if 'AWS_REGION' in os.environ:
r = os.environ['AWS_REGION']
elif 'EC2_REGION' in os.environ:
r = os.environ['EC2_REGION']
# convert the template parameters ansible passes into a tuple for boto # convert the template parameters ansible passes into a tuple for boto
template_parameters_tup = [(k, v) for k, v in template_parameters.items()] template_parameters_tup = [(k, v) for k, v in template_parameters.items()]
stack_outputs = {} stack_outputs = {}
try: try:
region = Region(r)
cfn = boto.cloudformation.connection.CloudFormationConnection( cfn = boto.cloudformation.connection.CloudFormationConnection(
region=region) region=region)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:

@ -50,17 +50,17 @@ options:
region: region:
version_added: "1.2" version_added: "1.2"
description: description:
- the EC2 region to use - The AWS region to use. Must be specified if ec2_url is not used. If not specified then the value of the EC2_REGION environment variable, if any, is used.
required: false required: false
default: null default: null
aliases: [] aliases: [ 'aws_region', 'ec2_region' ]
zone: zone:
version_added: "1.2" version_added: "1.2"
description: description:
- availability zone in which to launch the instance - AWS availability zone in which to launch the instance
required: false required: false
default: null default: null
aliases: [] aliases: [ 'aws_zone', 'ec2_zone' ]
instance_type: instance_type:
description: description:
- instance type to use for the instance - instance type to use for the instance
@ -99,22 +99,22 @@ options:
aliases: [] aliases: []
ec2_url: ec2_url:
description: description:
- url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints) - Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Must be specified if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used
required: false required: false
default: null default: null
aliases: [] aliases: []
ec2_secret_key: aws_secret_key:
description: description:
- EC2 secret key. If not specified then the EC2_SECRET_KEY environment variable is used. - AWS secret key. If not set then the value of the AWS_SECRET_KEY environment variable is used.
required: false required: false
default: null default: null
aliases: [ EC2_SECRET_KEY ] aliases: [ 'ec2_secret_key', 'secret_key' ]
ec2_access_key: aws_access_key:
description: description:
- EC2 access key. If not specified then the EC2_ACCESS_KEY environment variable is used. - AWS access key. If not set then the value of the AWS_ACCESS_KEY environment variable is used.
required: false required: false
default: null default: null
aliases: [ EC2_ACCESS_KEY ] aliases: [ 'ec2_access_key', 'access_key' ]
count: count:
description: description:
- number of instances to launch - number of instances to launch
@ -190,6 +190,9 @@ author: Seth Vidal, Tim Gerla, Lester Wade
''' '''
EXAMPLES = ''' EXAMPLES = '''
# Note: None of these examples set aws_access_key, aws_secret_key, or region.
# It is assumed that their matching environment variables are set.
# Basic provisioning example # Basic provisioning example
- local_action: - local_action:
module: ec2 module: ec2
@ -282,6 +285,15 @@ local_action:
import sys import sys
import time import time
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']
try: try:
import boto.ec2 import boto.ec2
from boto.exception import EC2ResponseError from boto.exception import EC2ResponseError
@ -517,8 +529,8 @@ def main():
id = dict(), id = dict(),
group = dict(type='list'), group = dict(type='list'),
group_id = dict(), group_id = dict(),
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']), region = dict(aliases=['aws_region', 'ec2_region'], choices=AWS_REGIONS),
zone = dict(), zone = dict(aliases=['aws_zone', 'ec2_zone']),
instance_type = dict(aliases=['type']), instance_type = dict(aliases=['type']),
image = dict(), image = dict(),
kernel = dict(), kernel = dict(),
@ -527,9 +539,9 @@ def main():
ramdisk = dict(), ramdisk = dict(),
wait = dict(choices=BOOLEANS, default=False), wait = dict(choices=BOOLEANS, default=False),
wait_timeout = dict(default=300), wait_timeout = dict(default=300),
ec2_url = dict(aliases=['EC2_URL']), ec2_url = dict(),
ec2_secret_key = dict(aliases=['EC2_SECRET_KEY'], no_log=True), aws_secret_key = dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True),
ec2_access_key = dict(aliases=['EC2_ACCESS_KEY']), aws_access_key = dict(aliases=['ec2_access_key', 'access_key']),
placement_group = dict(), placement_group = dict(),
user_data = dict(), user_data = dict(),
instance_tags = dict(), instance_tags = dict(),
@ -542,34 +554,47 @@ def main():
) )
ec2_url = module.params.get('ec2_url') ec2_url = module.params.get('ec2_url')
ec2_secret_key = module.params.get('ec2_secret_key') aws_secret_key = module.params.get('aws_secret_key')
ec2_access_key = module.params.get('ec2_access_key') aws_access_key = module.params.get('aws_access_key')
region = module.params.get('region') region = module.params.get('region')
# allow eucarc environment variables to be used if ansible vars aren't set # allow eucarc environment variables to be used if ansible vars aren't set
if not ec2_url and 'EC2_URL' in os.environ: if not ec2_url and 'EC2_URL' in os.environ:
ec2_url = os.environ['EC2_URL'] ec2_url = os.environ['EC2_URL']
if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ:
ec2_secret_key = os.environ['EC2_SECRET_KEY'] if not aws_secret_key:
if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ: if 'AWS_SECRET_KEY' in os.environ:
ec2_access_key = os.environ['EC2_ACCESS_KEY'] aws_secret_key = os.environ['AWS_SECRET_KEY']
elif 'EC2_SECRET_KEY' in os.environ:
aws_secret_key = os.environ['EC2_SECRET_KEY']
if not aws_access_key:
if 'AWS_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['AWS_ACCESS_KEY']
elif 'EC2_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['EC2_ACCESS_KEY']
if not region:
if 'AWS_REGION' in os.environ:
region = os.environ['AWS_REGION']
elif 'EC2_REGION' in os.environ:
region = os.environ['EC2_REGION']
# If we have a region specified, connect to its endpoint. # If we have a region specified, connect to its endpoint.
if region: if region:
try: try:
ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=ec2_access_key, aws_secret_access_key=ec2_secret_key) ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e)) module.fail_json(msg = str(e))
# Otherwise, no region so we fallback to the old connection method # If we specified an ec2_url then try connecting to it
else: elif ec2_url:
try: try:
if ec2_url: # if we have an URL set, connect to the specified endpoint ec2 = boto.connect_ec2_endpoint(ec2_url, aws_access_key, aws_secret_key)
ec2 = boto.connect_ec2_endpoint(ec2_url, ec2_access_key, ec2_secret_key)
else: # otherwise it's Amazon.
ec2 = boto.connect_ec2(ec2_access_key, ec2_secret_key)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e)) module.fail_json(msg = str(e))
else:
module.fail_json(msg="Either region or ec2_url must be specified")
if module.params.get('state') == 'absent': if module.params.get('state') == 'absent':
instance_ids = module.params.get('instance_ids') instance_ids = module.params.get('instance_ids')

@ -23,22 +23,22 @@ description:
options: options:
ec2_url: ec2_url:
description: description:
- url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints) - Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Must be specified if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used
required: false required: false
default: null default: null
aliases: [] aliases: []
ec2_secret_key: aws_secret_key:
description: description:
- ec2 secret key - AWS secret key. If not set then the value of the AWS_SECRET_KEY environment variable is used.
required: false required: false
default: null default: null
aliases: [] aliases: [ 'ec2_secret_key', 'secret_key' ]
ec2_access_key: aws_access_key:
description: description:
- ec2 access key - AWS access key. If not set then the value of the AWS_ACCESS_KEY environment variable is used.
required: false required: false
default: null default: null
aliases: [] aliases: ['ec2_access_key', 'access_key' ]
instance_id: instance_id:
description: description:
- instance id of the image to create - instance id of the image to create
@ -71,10 +71,10 @@ options:
aliases: [] aliases: []
region: region:
description: description:
- the EC2 region to use - The AWS region to use. Must be specified if ec2_url is not used. If not specified then the value of the EC2_REGION environment variable, if any, is used.
required: false required: false
default: null default: null
aliases: [] aliases: [ 'aws_region', 'ec2_region' ]
description: description:
description: description:
- An optional human-readable string describing the contents and purpose of the AMI. - An optional human-readable string describing the contents and purpose of the AMI.
@ -113,8 +113,8 @@ EXAMPLES = '''
# Basic AMI Creation # Basic AMI Creation
- local_action: - local_action:
module: ec2_ami module: ec2_ami
ec2_access_key: xxxxxxxxxxxxxxxxxxxxxxx aws_access_key: xxxxxxxxxxxxxxxxxxxxxxx
ec2_secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx aws_secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
instance_id: i-xxxxxx instance_id: i-xxxxxx
wait: yes wait: yes
name: newtest name: newtest
@ -123,8 +123,9 @@ EXAMPLES = '''
# Basic AMI Creation, without waiting # Basic AMI Creation, without waiting
- local_action: - local_action:
module: ec2_ami module: ec2_ami
ec2_access_key: xxxxxxxxxxxxxxxxxxxxxxx aws_access_key: xxxxxxxxxxxxxxxxxxxxxxx
ec2_secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx aws_secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
region: xxxxxx
instance_id: i-xxxxxx instance_id: i-xxxxxx
wait: no wait: no
name: newtest name: newtest
@ -133,8 +134,9 @@ EXAMPLES = '''
# Deregister/Delete AMI # Deregister/Delete AMI
- local_action: - local_action:
module: ec2_ami module: ec2_ami
ec2_access_key: xxxxxxxxxxxxxxxxxxxxxxx aws_access_key: xxxxxxxxxxxxxxxxxxxxxxx
ec2_secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx aws_secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
region: xxxxxx
image_id: ${instance.image_id} image_id: ${instance.image_id}
delete_snapshot: True delete_snapshot: True
state: absent state: absent
@ -142,8 +144,9 @@ EXAMPLES = '''
# Deregister AMI # Deregister AMI
- local_action: - local_action:
module: ec2_ami module: ec2_ami
ec2_access_key: xxxxxxxxxxxxxxxxxxxxxxx aws_access_key: xxxxxxxxxxxxxxxxxxxxxxx
ec2_secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx aws_secret_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
region: xxxxxx
image_id: ${instance.image_id} image_id: ${instance.image_id}
delete_snapshot: False delete_snapshot: False
state: absent state: absent
@ -152,6 +155,15 @@ EXAMPLES = '''
import sys import sys
import time import time
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']
try: try:
import boto.ec2 import boto.ec2
except ImportError: except ImportError:
@ -235,9 +247,9 @@ def deregister_image(module, ec2):
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec = dict(
ec2_url = dict(aliases=['EC2_URL']), ec2_url = dict(),
ec2_secret_key = dict(aliases=['EC2_SECRET_KEY'], no_log=True), aws_secret_key = dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True),
ec2_access_key = dict(aliases=['EC2_ACCESS_KEY']), aws_access_key = dict(aliases=['ec2_access_key', 'access_key']),
instance_id = dict(), instance_id = dict(),
image_id = dict(), image_id = dict(),
delete_snapshot = dict(), delete_snapshot = dict(),
@ -247,38 +259,51 @@ def main():
description = dict(default=""), description = dict(default=""),
no_reboot = dict(default=True, type="bool"), no_reboot = dict(default=True, type="bool"),
state = dict(default='present'), state = dict(default='present'),
region = dict() region = dict(aliases=['aws_region', 'ec2_region'], choices=AWS_REGIONS)
) )
) )
ec2_url = module.params.get('ec2_url') ec2_url = module.params.get('ec2_url')
ec2_secret_key = module.params.get('ec2_secret_key') aws_secret_key = module.params.get('aws_secret_key')
ec2_access_key = module.params.get('ec2_access_key') aws_access_key = module.params.get('aws_access_key')
region = module.params.get('region') region = module.params.get('region')
# allow eucarc environment variables to be used if ansible vars aren't set # allow eucarc environment variables to be used if ansible vars aren't set
if not ec2_url and 'EC2_URL' in os.environ: if not ec2_url and 'EC2_URL' in os.environ:
ec2_url = os.environ['EC2_URL'] ec2_url = os.environ['EC2_URL']
if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ:
ec2_secret_key = os.environ['EC2_SECRET_KEY'] if not aws_secret_key:
if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ: if 'AWS_SECRET_KEY' in os.environ:
ec2_access_key = os.environ['EC2_ACCESS_KEY'] aws_secret_key = os.environ['AWS_SECRET_KEY']
elif 'EC2_SECRET_KEY' in os.environ:
aws_secret_key = os.environ['EC2_SECRET_KEY']
if not aws_access_key:
if 'AWS_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['AWS_ACCESS_KEY']
elif 'EC2_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['EC2_ACCESS_KEY']
if not region:
if 'AWS_REGION' in os.environ:
region = os.environ['AWS_REGION']
elif 'EC2_REGION' in os.environ:
region = os.environ['EC2_REGION']
# If we have a region specified, connect to its endpoint. # If we have a region specified, connect to its endpoint.
if region: if region:
try: try:
ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=ec2_access_key, aws_secret_access_key=ec2_secret_key) ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(" %s %s %s " % (region, ec2_access_key, ec2_secret_key))) module.fail_json(msg = str(e))
# Otherwise, no region so we fallback to the old connection method # If we specified an ec2_url then try connecting to it
else: elif ec2_url:
try: try:
if ec2_url: # if we have an URL set, connect to the specified endpoint ec2 = boto.connect_ec2_endpoint(ec2_url, aws_access_key, aws_secret_key)
ec2 = boto.connect_ec2_endpoint(ec2_url, ec2_access_key, ec2_secret_key)
else: # otherwise it's Amazon.
ec2 = boto.connect_ec2(ec2_access_key, ec2_secret_key)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e)) module.fail_json(msg = str(e))
else:
module.fail_json(msg="Either region or ec2_url must be specified")
if module.params.get('state') == 'absent': if module.params.get('state') == 'absent':
if not module.params.get('image_id'): if not module.params.get('image_id'):

@ -25,7 +25,7 @@ description:
if state=absent is passed as an argument. if state=absent is passed as an argument.
- Will be marked changed when called only if there are ELBs found to operate on. - Will be marked changed when called only if there are ELBs found to operate on.
version_added: "1.2" version_added: "1.2"
requirements: [ "boto", "urllib2" ] requirements: [ "boto" ]
author: John Jarvis author: John Jarvis
options: options:
state: state:
@ -43,21 +43,23 @@ options:
- List of ELB names, required for registration. The ec2_elbs fact should be used if there was a previous de-register. - List of ELB names, required for registration. The ec2_elbs fact should be used if there was a previous de-register.
required: false required: false
default: None default: None
ec2_secret_key: aws_secret_key:
description: description:
- AWS Secret API key - AWS secret key. If not set then the value of the AWS_SECRET_KEY environment variable is used.
required: false required: false
default: None def2ault: None
ec2_access_key: aliases: ['ec2_secret_key', 'secret_key' ]
aws_access_key:
description: description:
- AWS Access API key - AWS access key. If not set then the value of the AWS_ACCESS_KEY environment variable is used.
required: false required: false
default: None default: None
ec2_region: aliases: ['ec2_access_key', 'access_key' ]
region:
description: description:
- AWS region of your load balancer. If not set then the region in which - The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used.
this module is running will be used.
required: false required: false
aliases: ['aws_region', 'ec2_region']
""" """
@ -103,22 +105,16 @@ except ImportError:
print "failed=True msg='boto required for this module'" print "failed=True msg='boto required for this module'"
sys.exit(1) sys.exit(1)
try:
import urllib2
except ImportError:
print "failed=True msg='urllib2 required for this module'"
sys.exit(1)
class ElbManager: class ElbManager:
"""Handles EC2 instance ELB registration and de-registration""" """Handles EC2 instance ELB registration and de-registration"""
def __init__(self, module, instance_id=None, ec2_elbs=None, def __init__(self, module, instance_id=None, ec2_elbs=None,
ec2_access_key=None, ec2_secret_key=None, ec2_region=None): aws_access_key=None, aws_secret_key=None, region=None):
self.ec2_access_key = ec2_access_key self.aws_access_key = aws_access_key
self.ec2_secret_key = ec2_secret_key self.aws_secret_key = aws_secret_key
self.module = module self.module = module
self.instance_id = instance_id self.instance_id = instance_id
self.ec2_region = ec2_region self.region = region
self.lbs = self._get_instance_lbs(ec2_elbs) self.lbs = self._get_instance_lbs(ec2_elbs)
# if there are no ELBs to operate on # if there are no ELBs to operate on
@ -174,9 +170,9 @@ class ElbManager:
are attached to self.instance_id""" are attached to self.instance_id"""
try: try:
endpoint="elasticloadbalancing.%s.amazonaws.com" % self.ec2_region endpoint="elasticloadbalancing.%s.amazonaws.com" % self.region
connect_region = RegionInfo(name=self.ec2_region, endpoint=endpoint) connect_region = RegionInfo(name=self.region, endpoint=endpoint)
elb = boto.ec2.elb.ELBConnection(self.ec2_access_key, self.ec2_secret_key, region=connect_region) elb = boto.ec2.elb.ELBConnection(self.aws_access_key, self.aws_secret_key, region=connect_region)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
self.module.fail_json(msg=str(e)) self.module.fail_json(msg=str(e))
@ -201,42 +197,44 @@ def main():
'choices': ['present', 'absent']}, 'choices': ['present', 'absent']},
instance_id={'required': True}, instance_id={'required': True},
ec2_elbs={'default': None, 'required': False}, ec2_elbs={'default': None, 'required': False},
ec2_secret_key={'default': None, 'aliases': ['EC2_SECRET_KEY']}, aws_secret_key={'default': None, 'aliases': ['ec2_secret_key', 'secret_key'], 'no_log': True},
ec2_access_key={'default': None, 'aliases': ['EC2_ACCESS_KEY']}, aws_access_key={'default': None, 'aliases': ['ec2_access_key', 'access_key']},
ec2_region={'default': None, 'required': False, 'choices':AWS_REGIONS} region={'default': None, 'required': False, 'aliases':['aws_region', 'ec2_region'], 'choices':AWS_REGIONS}
) )
) )
ec2_secret_key = module.params['ec2_secret_key'] aws_secret_key = module.params['aws_secret_key']
ec2_access_key = module.params['ec2_access_key'] aws_access_key = module.params['aws_access_key']
ec2_elbs = module.params['ec2_elbs'] ec2_elbs = module.params['ec2_elbs']
ec2_region = module.params['ec2_region'] region = module.params['region']
if module.params['state'] == 'present' and 'ec2_elbs' not in module.params: if module.params['state'] == 'present' and 'ec2_elbs' not in module.params:
module.fail_json(msg="ELBs are required for registration") module.fail_json(msg="ELBs are required for registration")
if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ: if not aws_secret_key:
ec2_secret_key = os.environ['EC2_SECRET_KEY'] if 'AWS_SECRET_KEY' in os.environ:
if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ: aws_secret_key = os.environ['AWS_SECRET_KEY']
ec2_access_key = os.environ['EC2_ACCESS_KEY'] elif 'EC2_SECRET_KEY' in os.environ:
aws_secret_key = os.environ['EC2_SECRET_KEY']
if not ec2_region and 'EC2_REGION' in os.environ: if not aws_access_key:
ec2_region = os.environ['EC2_REGION'] if 'AWS_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['AWS_ACCESS_KEY']
elif 'EC2_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['EC2_ACCESS_KEY']
if not ec2_region: if not region:
response = urllib2.urlopen('http://169.254.169.254/latest/meta-data/placement/availability-zone') if 'AWS_REGION' in os.environ:
az = response.read() region = os.environ['AWS_REGION']
for r in AWS_REGIONS: elif 'EC2_REGION' in os.environ:
if az.startswith(r): region = os.environ['EC2_REGION']
ec2_region = r
break
if not ec2_region: if not region:
module.fail_json(msg = str("ec2_region not specified and unable to determine region from AWS.")) module.fail_json(msg = str("Either region or EC2_REGION environment variable must be set."))
instance_id = module.params['instance_id'] instance_id = module.params['instance_id']
elb_man = ElbManager(module, instance_id, ec2_elbs, ec2_access_key, elb_man = ElbManager(module, instance_id, ec2_elbs, aws_access_key,
ec2_secret_key, ec2_region=ec2_region) aws_secret_key, region=region)
for elb in [ ec2_elbs ]: for elb in [ ec2_elbs ]:
if not elb_man.exists(elb): if not elb_man.exists(elb):

@ -22,6 +22,24 @@ description:
- creates an EBS volume and optionally attaches it to an instance. If both an instance ID and a device name is given and the instance has a device at the device name, then no volume is created and no attachment is made. This module has a dependency on python-boto. - creates an EBS volume and optionally attaches it to an instance. If both an instance ID and a device name is given and the instance has a device at the device name, then no volume is created and no attachment is made. This module has a dependency on python-boto.
version_added: "1.1" version_added: "1.1"
options: options:
aws_secret_key:
description:
- AWS secret key. If not set then the value of the AWS_SECRET_KEY environment variable is used.
required: false
default: None
aliases: ['ec2_secret_key', 'secret_key' ]
aws_access_key:
description:
- AWS access key. If not set then the value of the AWS_ACCESS_KEY environment variable is used.
required: false
default: None
aliases: ['ec2_access_key', 'access_key' ]
ec2_url:
description:
- Url to use to connect to EC2 or your Eucalyptus cloud (by default the module will use EC2 endpoints). Must be specified if region is not used. If not set then the value of the EC2_URL environment variable, if any, is used
required: false
default: null
aliases: []
instance: instance:
description: description:
- instance ID if you wish to attach the volume. - instance ID if you wish to attach the volume.
@ -49,16 +67,16 @@ options:
aliases: [] aliases: []
region: region:
description: description:
- region in which to create the volume - The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used.
required: false required: false
default: null default: null
aliases: [] aliases: ['aws_region', 'ec2_region']
zone: zone:
description: description:
- zone in which to create the volume, if unset uses the zone the instance is in (if set) - zone in which to create the volume, if unset uses the zone the instance is in (if set)
required: false required: false
default: null default: null
aliases: [] aliases: ['aws_zone', 'ec2_zone']
requirements: [ "boto" ] requirements: [ "boto" ]
author: Lester Wade author: Lester Wade
''' '''
@ -109,6 +127,15 @@ except ImportError:
print "failed=True msg='boto required for this module'" print "failed=True msg='boto required for this module'"
sys.exit(1) sys.exit(1)
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 main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec = dict(
@ -116,11 +143,11 @@ def main():
volume_size = dict(required=True), volume_size = dict(required=True),
iops = dict(), iops = dict(),
device_name = dict(), device_name = dict(),
region = dict(), region = dict(aliases=['aws_region', 'ec2_region'], choices=AWS_REGIONS),
zone = dict(), zone = dict(aliases=['availability_zone', 'aws_zone', 'ec2_zone']),
ec2_url = dict(aliases=['EC2_URL']), ec2_url = dict(),
ec2_secret_key = dict(aliases=['EC2_SECRET_KEY']), aws_secret_key = dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True),
ec2_access_key = dict(aliases=['EC2_ACCESS_KEY']), aws_access_key = dict(aliases=['ec2_access_key', 'access_key']),
) )
) )
@ -131,32 +158,45 @@ def main():
region = module.params.get('region') region = module.params.get('region')
zone = module.params.get('zone') zone = module.params.get('zone')
ec2_url = module.params.get('ec2_url') ec2_url = module.params.get('ec2_url')
ec2_secret_key = module.params.get('ec2_secret_key') aws_secret_key = module.params.get('aws_secret_key')
ec2_access_key = module.params.get('ec2_access_key') aws_access_key = module.params.get('aws_access_key')
# allow eucarc environment variables to be used if ansible vars aren't set # allow eucarc environment variables to be used if ansible vars aren't set
if not ec2_url and 'EC2_URL' in os.environ: if not ec2_url and 'EC2_URL' in os.environ:
ec2_url = os.environ['EC2_URL'] ec2_url = os.environ['EC2_URL']
if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ:
ec2_secret_key = os.environ['EC2_SECRET_KEY'] if not aws_secret_key:
if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ: if 'AWS_SECRET_KEY' in os.environ:
ec2_access_key = os.environ['EC2_ACCESS_KEY'] aws_secret_key = os.environ['AWS_SECRET_KEY']
elif 'EC2_SECRET_KEY' in os.environ:
aws_secret_key = os.environ['EC2_SECRET_KEY']
if not aws_access_key:
if 'AWS_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['AWS_ACCESS_KEY']
elif 'EC2_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['EC2_ACCESS_KEY']
if not region:
if 'AWS_REGION' in os.environ:
region = os.environ['AWS_REGION']
elif 'EC2_REGION' in os.environ:
region = os.environ['EC2_REGION']
# If we have a region specified, connect to its endpoint. # If we have a region specified, connect to its endpoint.
if region: if region:
try: try:
ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=ec2_access_key, aws_secret_access_key=ec2_secret_key) ec2 = boto.ec2.connect_to_region(region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e)) module.fail_json(msg = str(e))
# Otherwise, no region so we fallback to the old connection method # Otherwise, no region so we fallback to the old connection method
else: elif ec2_url:
try: try:
if ec2_url: # if we have an URL set, connect to the specified endpoint ec2 = boto.connect_ec2_endpoint(ec2_url, aws_access_key, aws_secret_key)
ec2 = boto.connect_ec2_endpoint(ec2_url, ec2_access_key, ec2_secret_key)
else: # otherwise it's Amazon.
ec2 = boto.connect_ec2(ec2_access_key, ec2_secret_key)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e)) module.fail_json(msg = str(e))
else:
module.fail_json(msg="Either region or ec2_url must be specified")
# Here we need to get the zone info for the instance. This covers situation where # Here we need to get the zone info for the instance. This covers situation where
# instance is specified but zone isn't. # instance is specified but zone isn't.

@ -73,12 +73,12 @@ options:
required: false required: false
default: null default: null
aliases: [] aliases: []
ec2_region: region:
description: description:
- the EC2 region to use. If not specified then the EC2_REGION environment variable is used. If neither exist then the AWS is queried for the region that the host invoking the module is located in. - The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used.
required: true required: true
default: null default: null
aliases: [] aliases: [ 'aws_region', 'ec2_region' ]
db_name: db_name:
description: description:
- Name of a database to create within the instance. If not specified then no database is created. Used only when command=create. - Name of a database to create within the instance. If not specified then no database is created. Used only when command=create.
@ -165,7 +165,7 @@ options:
- availability zone in which to launch the instance. Used only when command=create or command=replicate. - availability zone in which to launch the instance. Used only when command=create or command=replicate.
required: false required: false
default: null default: null
aliases: [] aliases: ['aws_zone', 'ec2_zone']
subnet: subnet:
description: description:
- VPC subnet group. If specified then a VPC instance is created. Used only when command=create. - VPC subnet group. If specified then a VPC instance is created. Used only when command=create.
@ -178,18 +178,18 @@ options:
required: false required: false
default: null default: null
aliases: [] aliases: []
ec2_secret_key: aws_secret_key:
description: description:
- EC2 secret key. If not specified then the EC2_SECRET_KEY environment variable is used. - AWS secret key. If not set then the value of the AWS_SECRET_KEY environment variable is used.
required: false required: false
default: null default: null
aliases: [] aliases: [ 'ec2_secret_key', 'secret_key' ]
ec2_access_key: aws_access_key:
description: description:
- EC2 access key. If not specified then the EC2_ACCESS_KEY environment variable is used. - AWS access key. If not set then the value of the AWS_ACCESS_KEY environment variable is used.
required: false required: false
default: null default: null
aliases: [] aliases: [ 'ec2_access_key', 'access_key' ]
wait: wait:
description: description:
- When command=create, replicate, or modify then wait for the database to enter the 'available' state. When command=delete wait for the database to be terminated. - When command=create, replicate, or modify then wait for the database to enter the 'available' state. When command=delete wait for the database to be terminated.
@ -263,12 +263,6 @@ except ImportError:
print "failed=True msg='boto required for this module'" print "failed=True msg='boto required for this module'"
sys.exit(1) sys.exit(1)
try:
import urllib2
except ImportError:
print "failed=True msg='urllib2 required for this module'"
sys.exit(1)
def main(): def main():
module = AnsibleModule( module = AnsibleModule(
argument_spec = dict( argument_spec = dict(
@ -293,11 +287,11 @@ def main():
maint_window = dict(required=False), maint_window = dict(required=False),
backup_window = dict(required=False), backup_window = dict(required=False),
backup_retention = dict(required=False), backup_retention = dict(required=False),
ec2_region = dict(aliases=['EC2_REGION'], choices=AWS_REGIONS, required=False), region = dict(aliases=['aws_region', 'ec2_region'], choices=AWS_REGIONS, required=False),
zone = dict(required=False), zone = dict(aliases=['aws_zone', 'ec2_zone'], required=False),
subnet = dict(required=False), subnet = dict(required=False),
ec2_secret_key = dict(aliases=['EC2_SECRET_KEY'], no_log=True, required=False), aws_secret_key = dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True, required=False),
ec2_access_key = dict(aliases=['EC2_ACCESS_KEY'], required=False), aws_access_key = dict(aliases=['ec2_access_key', 'access_key'], required=False),
wait = dict(type='bool', default=False), wait = dict(type='bool', default=False),
wait_timeout = dict(default=300), wait_timeout = dict(default=300),
snapshot = dict(required=False), snapshot = dict(required=False),
@ -327,39 +321,40 @@ def main():
subnet = module.params.get('subnet') subnet = module.params.get('subnet')
backup_window = module.params.get('backup_window') backup_window = module.params.get('backup_window')
backup_retention = module.params.get('module_retention') backup_retention = module.params.get('module_retention')
ec2_region = module.params.get('ec2_region') region = module.params.get('region')
zone = module.params.get('zone') zone = module.params.get('zone')
ec2_secret_key = module.params.get('ec2_secret_key') aws_secret_key = module.params.get('aws_secret_key')
ec2_access_key = module.params.get('ec2_access_key') aws_access_key = module.params.get('aws_access_key')
wait = module.params.get('wait') wait = module.params.get('wait')
wait_timeout = int(module.params.get('wait_timeout')) wait_timeout = int(module.params.get('wait_timeout'))
snapshot = module.params.get('snapshot') snapshot = module.params.get('snapshot')
apply_immediately = module.params.get('apply_immediately') apply_immediately = module.params.get('apply_immediately')
# allow environment variables to be used if ansible vars aren't set # allow environment variables to be used if ansible vars aren't set
if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ: if not region:
ec2_secret_key = os.environ['EC2_SECRET_KEY'] if 'AWS_REGION' in os.environ:
if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ: region = os.environ['AWS_REGION']
ec2_access_key = os.environ['EC2_ACCESS_KEY'] elif 'EC2_REGION' in os.environ:
if not ec2_region and 'EC2_REGION' in os.environ: region = os.environ['EC2_REGION']
ec2_region = os.environ['EC2_REGION']
if not aws_secret_key:
# If region isn't set either as a param or environ variable then if 'AWS_SECRET_KEY' in os.environ:
# look up the current region via the AWS URL aws_secret_key = os.environ['AWS_SECRET_KEY']
if not ec2_region: elif 'EC2_SECRET_KEY' in os.environ:
response = urllib2.urlopen('http://169.254.169.254/latest/meta-data/placement/availability-zone') aws_secret_key = os.environ['EC2_SECRET_KEY']
az = response.read()
for r in AWS_REGIONS: if not aws_access_key:
if az.startswith(r): if 'AWS_ACCESS_KEY' in os.environ:
ec2_region = r aws_access_key = os.environ['AWS_ACCESS_KEY']
break elif 'EC2_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['EC2_ACCESS_KEY']
if not ec2_region:
module.fail_json(msg = str("ec2_region not specified and unable to determine region from AWS.")) if not aws_region:
module.fail_json(msg = str("region not specified and unable to determine region from EC2_REGION."))
# connect to the rds endpoint # connect to the rds endpoint
try: try:
conn = boto.rds.connect_to_region(ec2_region, aws_access_key_id=ec2_access_key, aws_secret_access_key=ec2_secret_key) conn = boto.rds.connect_to_region(aws_region, aws_access_key_id=aws_access_key, aws_secret_access_key=aws_secret_key)
except boto.exception.BotoServerError, e: except boto.exception.BotoServerError, e:
module.fail_json(msg = e.error_message) module.fail_json(msg = e.error_message)

@ -60,18 +60,18 @@ options:
required: false required: false
default: null default: null
aliases: [] aliases: []
ec2_secret_key: aws_secret_key:
description: description:
- EC2 secret key. If not specified then the EC2_SECRET_KEY environment variable is used. - AWS secret key.
required: false required: false
default: null default: null
aliases: [] aliases: ['ec2_secret_key', 'secret_key']
ec2_access_key: aws_access_key:
description: description:
- EC2 access key. If not specified then the EC2_ACCESS_KEY environment variable is used. - AWS access key.
required: false required: false
default: null default: null
aliases: [] aliases: ['ec2_access_key', 'access_key']
requirements: [ "boto" ] requirements: [ "boto" ]
author: Bruce Pennypacker author: Bruce Pennypacker
''' '''
@ -98,9 +98,9 @@ EXAMPLES = '''
- route53: > - route53: >
command=delete command=delete
zone=foo.com zone=foo.com
record={{ r.set.record }} record={{ rec.set.record }}
type={{ r.set.type }} type={{ rec.set.type }}
value={{ r.set.value }} value={{ rec.set.value }}
# Add an AAAA record. Note that because there are colons in the value # Add an AAAA record. Note that because there are colons in the value
# that the entire parameter list must be quoted: # that the entire parameter list must be quoted:
@ -132,8 +132,8 @@ def main():
ttl = dict(required=False, default=3600), ttl = dict(required=False, default=3600),
type = dict(choices=['A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'NS'], required=True), type = dict(choices=['A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'NS'], required=True),
value = dict(required=False), value = dict(required=False),
ec2_secret_key = dict(aliases=['EC2_SECRET_KEY'], no_log=True, required=False), aws_secret_key = dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True, required=False),
ec2_access_key = dict(aliases=['EC2_ACCESS_KEY'], required=False) aws_access_key = dict(aliases=['ec2_access_key', 'access_key'], required=False)
) )
) )
@ -143,8 +143,8 @@ def main():
record_in = module.params.get('record') record_in = module.params.get('record')
type_in = module.params.get('type') type_in = module.params.get('type')
value_in = module.params.get('value') value_in = module.params.get('value')
ec2_secret_key = module.params.get('ec2_secret_key') aws_secret_key = module.params.get('aws_secret_key')
ec2_access_key = module.params.get('ec2_access_key') aws_access_key = module.params.get('aws_access_key')
value_list = () value_list = ()
@ -165,14 +165,21 @@ def main():
module.fail_json(msg = "parameter 'value' required for create/delete") module.fail_json(msg = "parameter 'value' required for create/delete")
# allow environment variables to be used if ansible vars aren't set # allow environment variables to be used if ansible vars aren't set
if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ: if not aws_secret_key:
ec2_secret_key = os.environ['EC2_SECRET_KEY'] if 'AWS_SECRET_KEY' in os.environ:
if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ: aws_secret_key = os.environ['AWS_SECRET_KEY']
ec2_access_key = os.environ['EC2_ACCESS_KEY'] elif 'EC2_SECRET_KEY' in os.environ:
aws_secret_key = os.environ['EC2_SECRET_KEY']
if not aws_access_key:
if 'AWS_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['AWS_ACCESS_KEY']
elif 'EC2_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['EC2_ACCESS_KEY']
# connect to the route53 endpoint # connect to the route53 endpoint
try: try:
conn = boto.route53.connection.Route53Connection(ec2_access_key, ec2_secret_key) conn = boto.route53.connection.Route53Connection(aws_access_key, aws_secret_key)
except boto.exception.BotoServerError, e: except boto.exception.BotoServerError, e:
module.fail_json(msg = e.error_message) module.fail_json(msg = e.error_message)

@ -72,18 +72,18 @@ options:
- S3 URL endpoint. If not specified then the S3_URL environment variable is used, if that variable is defined. - S3 URL endpoint. If not specified then the S3_URL environment variable is used, if that variable is defined.
default: null default: null
aliases: [ S3_URL ] aliases: [ S3_URL ]
ec2_access_key: aws_secret_key:
description: description:
- EC2 access key. If not specified then the EC2_ACCESS_KEY environment variable is used. - AWS secret key. If not set then the value of the AWS_SECRET_KEY environment variable is used.
required: false required: false
default: null default: null
aliases: [ EC2_ACCESS_KEY ] aliases: ['ec2_secret_key', 'secret_key']
ec2_secret_key: aws_access_key:
description: description:
- EC2 secret key. If not specified then the EC2_SECRET_KEY environment variable is used. - AWS access key. If not set then the value of the AWS_ACCESS_KEY environment variable is used.
required: false required: false
default: null default: null
aliases: [ EC2_SECRET_KEY ] aliases: [ 'ec2_access_key', 'access_key' ]
requirements: [ "boto" ] requirements: [ "boto" ]
author: Lester Wade, Ralph Tice author: Lester Wade, Ralph Tice
''' '''
@ -252,8 +252,8 @@ def main():
mode = dict(choices=['get', 'put', 'delete', 'create', 'geturl', 'getstr'], required=True), mode = dict(choices=['get', 'put', 'delete', 'create', 'geturl', 'getstr'], required=True),
expiry = dict(default=600, aliases=['expiration']), expiry = dict(default=600, aliases=['expiration']),
s3_url = dict(aliases=['S3_URL']), s3_url = dict(aliases=['S3_URL']),
ec2_secret_key = dict(aliases=['EC2_SECRET_KEY']), aws_secret_key = dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True, required=False),
ec2_access_key = dict(aliases=['EC2_ACCESS_KEY']), aws_access_key = dict(aliases=['ec2_access_key', 'access_key'], required=False),
overwrite = dict(default=False, type='bool'), overwrite = dict(default=False, type='bool'),
), ),
) )
@ -265,8 +265,8 @@ def main():
mode = module.params.get('mode') mode = module.params.get('mode')
expiry = int(module.params['expiry']) expiry = int(module.params['expiry'])
s3_url = module.params.get('s3_url') s3_url = module.params.get('s3_url')
ec2_secret_key = module.params.get('ec2_secret_key') aws_secret_key = module.params.get('aws_secret_key')
ec2_access_key = module.params.get('ec2_access_key') aws_access_key = module.params.get('aws_access_key')
overwrite = module.params.get('overwrite') overwrite = module.params.get('overwrite')
if module.params.get('object'): if module.params.get('object'):
@ -275,21 +275,29 @@ def main():
# allow eucarc environment variables to be used if ansible vars aren't set # allow eucarc environment variables to be used if ansible vars aren't set
if not s3_url and 'S3_URL' in os.environ: if not s3_url and 'S3_URL' in os.environ:
s3_url = os.environ['S3_URL'] s3_url = os.environ['S3_URL']
if not ec2_secret_key and 'EC2_SECRET_KEY' in os.environ:
ec2_secret_key = os.environ['EC2_SECRET_KEY'] if not aws_secret_key:
if not ec2_access_key and 'EC2_ACCESS_KEY' in os.environ: if 'AWS_SECRET_KEY' in os.environ:
ec2_access_key = os.environ['EC2_ACCESS_KEY'] aws_secret_key = os.environ['AWS_SECRET_KEY']
elif 'EC2_SECRET_KEY' in os.environ:
aws_secret_key = os.environ['EC2_SECRET_KEY']
if not aws_access_key:
if 'AWS_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['AWS_ACCESS_KEY']
elif 'EC2_ACCESS_KEY' in os.environ:
aws_access_key = os.environ['EC2_ACCESS_KEY']
# If we have an S3_URL env var set, this is likely to be Walrus, so change connection method # If we have an S3_URL env var set, this is likely to be Walrus, so change connection method
if 'S3_URL' in os.environ: if 'S3_URL' in os.environ:
try: try:
walrus = urlparse.urlparse(s3_url).hostname walrus = urlparse.urlparse(s3_url).hostname
s3 = boto.connect_walrus(walrus, ec2_access_key, ec2_secret_key) s3 = boto.connect_walrus(walrus, aws_access_key, aws_secret_key)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e)) module.fail_json(msg = str(e))
else: else:
try: try:
s3 = boto.connect_s3(ec2_access_key, ec2_secret_key) s3 = boto.connect_s3(aws_access_key, aws_secret_key)
except boto.exception.NoAuthHandlerFound, e: except boto.exception.NoAuthHandlerFound, e:
module.fail_json(msg = str(e)) module.fail_json(msg = str(e))

Loading…
Cancel
Save