diff --git a/cloud/ec2_elb b/cloud/ec2_elb index a8131c2f48b..7588cd234a9 100644 --- a/cloud/ec2_elb +++ b/cloud/ec2_elb @@ -60,6 +60,12 @@ options: - The AWS region to use. If not specified then the value of the EC2_REGION environment variable, if any, is used. required: false aliases: ['aws_region', 'ec2_region'] + wait: + description: + - Wait for instance registration or deregistration to complete successfully before returning. + required: false + default: yes + choices: [ "yes", "no" ] """ @@ -124,21 +130,23 @@ class ElbManager: else: self.changed = False - def deregister(self): + def deregister(self, wait): """De-register the instance from all ELBs and wait for the ELB to report it out-of-service""" for lb in self.lbs: lb.deregister_instances([self.instance_id]) - self._await_elb_instance_state(lb, 'OutOfService') + if wait: + self._await_elb_instance_state(lb, 'OutOfService') - def register(self): + def register(self, wait): """Register the instance for all ELBs and wait for the ELB to report the instance in-service""" for lb in self.lbs: lb.register_instances([self.instance_id]) - self._await_elb_instance_state(lb, 'InService') + if wait: + self._await_elb_instance_state(lb, 'InService') def exists(self, lbtest): """ Verify that the named ELB actually exists """ @@ -196,10 +204,11 @@ def main(): state={'required': True, 'choices': ['present', 'absent']}, instance_id={'required': True}, - ec2_elbs={'default': None, 'required': False}, + ec2_elbs={'default': None, 'required': False, 'type':'list'}, aws_secret_key={'default': None, 'aliases': ['ec2_secret_key', 'secret_key'], 'no_log': True}, aws_access_key={'default': None, 'aliases': ['ec2_access_key', 'access_key']}, - region={'default': None, 'required': False, 'aliases':['aws_region', 'ec2_region'], 'choices':AWS_REGIONS} + region={'default': None, 'required': False, 'aliases':['aws_region', 'ec2_region'], 'choices':AWS_REGIONS}, + wait={'required': False, 'choices': BOOLEANS, 'default': True} ) ) @@ -207,6 +216,7 @@ def main(): aws_access_key = module.params['aws_access_key'] ec2_elbs = module.params['ec2_elbs'] region = module.params['region'] + wait = module.params['wait'] if module.params['state'] == 'present' and 'ec2_elbs' not in module.params: module.fail_json(msg="ELBs are required for registration") @@ -230,21 +240,21 @@ def main(): region = os.environ['EC2_REGION'] if not region: - module.fail_json(msg = str("Either region or EC2_REGION environment variable must be set.")) + module.fail_json(msg=str("Either region or EC2_REGION environment variable must be set.")) instance_id = module.params['instance_id'] elb_man = ElbManager(module, instance_id, ec2_elbs, aws_access_key, aws_secret_key, region=region) - for elb in [ ec2_elbs ]: + for elb in ec2_elbs: if not elb_man.exists(elb): - str="ELB %s does not exist" % elb - module.fail_json(msg=str) + msg="ELB %s does not exist" % elb + module.fail_json(msg=msg) if module.params['state'] == 'present': - elb_man.register() + elb_man.register(wait) elif module.params['state'] == 'absent': - elb_man.deregister() + elb_man.deregister(wait) ansible_facts = {'ec2_elbs': [lb.name for lb in elb_man.lbs]} ec2_facts_result = dict(changed=elb_man.changed, ansible_facts=ansible_facts) diff --git a/cloud/s3.orig b/cloud/s3.orig deleted file mode 100644 index 57d75d058b0..00000000000 --- a/cloud/s3.orig +++ /dev/null @@ -1,473 +0,0 @@ -#!/usr/bin/python -# 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 . - -DOCUMENTATION = ''' ---- -module: s3 -short_description: idempotent S3 module putting a file into S3. -description: - - This module allows the user to dictate the presence of a given file in an S3 bucket. If or once the key (file) exists in the bucket, it returns a time-expired download URL. This module has a dependency on python-boto. -version_added: "1.1" -options: - bucket: - description: - - Bucket name. - required: true - default: null - aliases: [] - object: - description: - - Keyname of the object inside the bucket. Can be used to create "virtual directories", see examples. - required: false - default: null - aliases: [] - version_added: "1.3" - src: - description: - - The source file path when performing a PUT operation. - required: false - default: null - aliases: [] - version_added: "1.3" - dest: - description: - - The destination file path when downloading an object/key with a GET operation. - required: false - default: 600 - aliases: [] - version_added: "1.3" - overwrite: - description: - - Force overwrite either locally on the filesystem or remotely with the object/key. Used with PUT and GET operations. - required: false - default: false - version_added: "1.2" - mode: - description: - - Switches the module behaviour between put (upload), get (download), geturl (return download url (Ansible 1.3+), getstr (download object as string (1.3+)), create (bucket) and delete (bucket). - required: true - default: null - aliases: [] - expiry: - description: - - Time limit (in seconds) for the URL generated and returned by S3/Walrus when performing a mode=put or mode=geturl operation. - required: false - default: null - aliases: [] - s3_url: - description: - - S3 URL endpoint. If not specified then the S3_URL environment variable is used, if that variable is defined. - default: null - aliases: [ S3_URL ] -<<<<<<< HEAD -======= - ->>>>>>> yet another rebase attempt - 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: null - 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: null - aliases: [ 'ec2_access_key', 'access_key' ] -requirements: [ "boto" ] -author: Lester Wade, Ralph Tice -''' - -EXAMPLES = ''' -# Simple PUT operation -- s3: bucket=mybucket object=/my/desired/key.txt src=/usr/local/myfile.txt mode=put -# Simple GET operation -- s3: bucket=mybucket object=/my/desired/key.txt dest=/usr/local/myfile.txt mode=get -# GET/download and overwrite local file (trust remote) -- s3: bucket=mybucket object=/my/desired/key.txt dest=/usr/local/myfile.txt mode=get overwrite=true -# PUT/upload and overwrite remote file (trust local) -- s3: bucket=mybucket object=/my/desired/key.txt src=/usr/local/myfile.txt mode=put overwrite=true -# Download an object as a string to use else where in your playbook -- s3: bucket=mybucket object=/my/desired/key.txt src=/usr/local/myfile.txt mode=getstr -# Create an empty bucket -- s3: bucket=mybucket mode=create -# Create a bucket with key as directory -- s3: bucket=mybucket object=/my/directory/path mode=create -# Delete a bucket and all contents -- s3: bucket=mybucket mode=delete -''' - -import sys -import os -import urlparse -import hashlib - -try: - import boto -except ImportError: - print "failed=True msg='boto required for this module'" - sys.exit(1) - -def key_check(module, s3, bucket, obj): - try: - bucket = s3.lookup(bucket) - key_check = bucket.get_key(obj) - except s3.provider.storage_response_error, e: - module.fail_json(msg= str(e)) - if key_check: - return True - else: - return False - -def keysum(module, s3, bucket, obj): - bucket = s3.lookup(bucket) - key_check = bucket.get_key(obj) - if key_check: - md5_remote = key_check.etag[1:-1] - etag_multipart = md5_remote.find('-')!=-1 #Check for multipart, etag is not md5 - if etag_multipart is True: - module.fail_json(msg="Files uploaded with multipart of s3 are not supported with checksum, unable to compute checksum.") - sys.exit(0) - return md5_remote - -def bucket_check(module, s3, bucket): - try: - result = s3.lookup(bucket) - except s3.provider.storage_response_error, e: - module.fail_json(msg= str(e)) - if result: - return True - else: - return False - -def create_bucket(module, s3, bucket): - try: - bucket = s3.create_bucket(bucket) - except s3.provider.storage_response_error, e: - module.fail_json(msg= str(e)) - if bucket: - return True - -def delete_bucket(module, s3, bucket): - try: - bucket = s3.lookup(bucket) - bucket_contents = bucket.list() - bucket.delete_keys([key.name for key in bucket_contents]) - bucket.delete() - return True - except s3.provider.storage_response_error, e: - module.fail_json(msg= str(e)) - -def delete_key(module, s3, bucket, obj): - try: - bucket = s3.lookup(bucket) - bucket.delete_key(obj) - module.exit_json(msg="Object deleted from bucket %s"%bucket, changed=True) - except s3.provider.storage_response_error, e: - module.fail_json(msg= str(e)) - -def create_dirkey(module, s3, bucket, obj): - try: - bucket = s3.lookup(bucket) - key = bucket.new_key(obj) - key.set_contents_from_string('') - module.exit_json(msg="Virtual directory %s created in bucket %s" % (obj, bucket.name), changed=True) - except s3.provider.storage_response_error, e: - module.fail_json(msg= str(e)) - -def upload_file_check(src): - if os.path.exists(src): - file_exists is True - else: - file_exists is False - if os.path.isdir(src): - module.fail_json(msg="Specifying a directory is not a valid source for upload.", failed=True) - sys.exit(0) - return file_exists - -def path_check(path): - if os.path.exists(path): - return True - else: - return False - -def upload_s3file(module, s3, bucket, obj, src, expiry): - try: - bucket = s3.lookup(bucket) - key = bucket.new_key(obj) - key.set_contents_from_filename(src) - url = key.generate_url(expiry) - module.exit_json(msg="PUT operation complete", url=url, changed=True) - sys.exit(0) - except s3.provider.storage_copy_error, e: - module.fail_json(msg= str(e)) - -def download_s3file(module, s3, bucket, obj, dest): - try: - bucket = s3.lookup(bucket) - key = bucket.lookup(obj) - key.get_contents_to_filename(dest) - module.exit_json(msg="GET operation complete", changed=True) - sys.exit(0) - except s3.provider.storage_copy_error, e: - module.fail_json(msg= str(e)) - -def download_s3str(module, s3, bucket, obj): - try: - bucket = s3.lookup(bucket) - key = bucket.lookup(obj) - contents = key.get_contents_as_string() - module.exit_json(msg="GET operation complete", contents=contents, changed=True) - sys.exit(0) - except s3.provider.storage_copy_error, e: - module.fail_json(msg= str(e)) - -def get_download_url(module, s3, bucket, obj, expiry): - try: - bucket = s3.lookup(bucket) - key = bucket.lookup(obj) - url = key.generate_url(expiry) - module.exit_json(msg="Download url:", url=url, expiry=expiry, changed=True) - sys.exit(0) - except s3.provider.storage_response_error, e: - module.fail_json(msg= str(e)) - -def main(): - module = AnsibleModule( - argument_spec = dict( - bucket = dict(required=True), - object = dict(), - src = dict(), - dest = dict(), - mode = dict(choices=['get', 'put', 'delete', 'create', 'geturl', 'getstr'], required=True), - expiry = dict(default=600, aliases=['expiration']), - s3_url = dict(aliases=['S3_URL']), - aws_secret_key = dict(aliases=['ec2_secret_key', 'secret_key'], no_log=True, required=False), - aws_access_key = dict(aliases=['ec2_access_key', 'access_key'], required=False), - overwrite = dict(default=False, type='bool'), - ), - ) - - bucket = module.params.get('bucket') - obj = module.params.get('object') - src = module.params.get('src') - dest = module.params.get('dest') - mode = module.params.get('mode') - expiry = int(module.params['expiry']) - s3_url = module.params.get('s3_url') - aws_secret_key = module.params.get('aws_secret_key') - aws_access_key = module.params.get('aws_access_key') - overwrite = module.params.get('overwrite') - - if module.params.get('object'): - obj = os.path.expanduser(module.params['object']) - - # allow eucarc environment variables to be used if ansible vars aren't set - if not s3_url and 'S3_URL' in os.environ: - s3_url = os.environ['S3_URL'] - - if not aws_secret_key: - if 'AWS_SECRET_KEY' in os.environ: - 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 'S3_URL' in os.environ: - try: - walrus = urlparse.urlparse(s3_url).hostname - s3 = boto.connect_walrus(walrus, aws_access_key, aws_secret_key) - except boto.exception.NoAuthHandlerFound, e: - module.fail_json(msg = str(e)) - else: - try: - s3 = boto.connect_s3(aws_access_key, aws_secret_key) - except boto.exception.NoAuthHandlerFound, e: - module.fail_json(msg = str(e)) - - # If our mode is a GET operation (download), go through the procedure as appropriate ... - if mode == 'get': - - # First, we check to see if the bucket exists, we get "bucket" returned. - bucketrtn = bucket_check(module, s3, bucket) - if bucketrtn is False: - module.fail_json(msg="Target bucket cannot be found", failed=True) - sys.exit(0) - - # Next, we check to see if the key in the bucket exists. If it exists, it also returns key_matches md5sum check. - keyrtn = key_check(module, s3, bucket, obj) - if keyrtn is False: - module.fail_json(msg="Target key cannot be found", failed=True) - sys.exit(0) - - # If the destination path doesn't exist, no need to md5um etag check, so just download. - pathrtn = path_check(dest) - if pathrtn is False: - download_s3file(module, s3, bucket, obj, dest) - - # Compare the remote MD5 sum of the object with the local dest md5sum, if it already exists. - if pathrtn is True: - md5_remote = keysum(module, s3, bucket, obj) - md5_local = hashlib.md5(open(dest, 'rb').read()).hexdigest() - if md5_local == md5_remote: - sum_matches = True - if overwrite is True: - download_s3file(module, s3, bucket, obj, dest) - else: - module.exit_json(msg="Local and remote object are identical, ignoring. Use overwrite parameter to force.", changed=False) - else: - sum_matches = False - if overwrite is True: - download_s3file(module, s3, bucket, obj, dest) - else: - module.fail_json(msg="WARNING: Checksums do not match. Use overwrite parameter to force download.", failed=True) - - # If destination file doesn't already exist we can go ahead and download. - if pathrtn is False: - download_s3file(module, s3, bucket, obj, dest) - - # Firstly, if key_matches is TRUE and overwrite is not enabled, we EXIT with a helpful message. - if sum_matches is True and overwrite is False: - module.exit_json(msg="Local and remote object are identical, ignoring. Use overwrite parameter to force.", changed=False) - - # At this point explicitly define the overwrite condition. - if sum_matches is True and pathrtn is True and overwrite is True: - download_s3file(module, s3, bucket, obj, dest) - - # If sum does not match but the destination exists, we - - # if our mode is a PUT operation (upload), go through the procedure as appropriate ... - if mode == 'put': - - # Use this snippet to debug through conditionals: -# module.exit_json(msg="Bucket return %s"%bucketrtn) -# sys.exit(0) - - # Lets check the src path. - pathrtn = path_check(src) - if pathrtn is False: - module.fail_json(msg="Local object for PUT does not exist", failed=True) - sys.exit(0) - - # Lets check to see if bucket exists to get ground truth. - bucketrtn = bucket_check(module, s3, bucket) - keyrtn = key_check(module, s3, bucket, obj) - - # Lets check key state. Does it exist and if it does, compute the etag md5sum. - if bucketrtn is True and keyrtn is True: - md5_remote = keysum(module, s3, bucket, obj) - md5_local = hashlib.md5(open(src, 'rb').read()).hexdigest() - if md5_local == md5_remote: - sum_matches = True - if overwrite is True: - upload_s3file(module, s3, bucket, obj, src, expiry) - else: - module.exit_json(msg="Local and remote object are identical, ignoring. Use overwrite parameter to force.", changed=False) - else: - sum_matches = False - if overwrite is True: - upload_s3file(module, s3, bucket, obj, src, expiry) - else: - module.exit_json(msg="WARNING: Checksums do not match. Use overwrite parameter to force upload.", failed=True) - - # If neither exist (based on bucket existence), we can create both. - if bucketrtn is False and pathrtn is True: - create_bucket(module, s3, bucket) - upload_s3file(module, s3, bucket, obj, src, expiry) - - # If bucket exists but key doesn't, just upload. - if bucketrtn is True and pathrtn is True and keyrtn is False: - upload_s3file(module, s3, bucket, obj, src, expiry) - - # Support for deleting an object if we have both params. - if mode == 'delete': - if bucket: - bucketrtn = bucket_check(module, s3, bucket) - if bucketrtn is True: - deletertn = delete_bucket(module, s3, bucket) - if deletertn is True: - module.exit_json(msg="Bucket %s and all keys have been deleted."%bucket, changed=True) - else: - module.fail_json(msg="Bucket does not exist.", failed=True) - else: - module.fail_json(msg="Bucket parameter is required.", failed=True) - - # Need to research how to create directories without "populating" a key, so this should just do bucket creation for now. - # WE SHOULD ENABLE SOME WAY OF CREATING AN EMPTY KEY TO CREATE "DIRECTORY" STRUCTURE, AWS CONSOLE DOES THIS. - if mode == 'create': - if bucket and not obj: - bucketrtn = bucket_check(module, s3, bucket) - if bucketrtn is True: - module.exit_json(msg="Bucket already exists.", changed=False) - else: - created = create_bucket(module, s3, bucket) - if bucket and obj: - bucketrtn = bucket_check(module, s3, bucket) - if obj.endswith('/'): - dirobj = obj - else: - dirobj = obj + "/" - if bucketrtn is True: - keyrtn = key_check(module, s3, bucket, dirobj) - if keyrtn is True: - module.exit_json(msg="Bucket %s and key %s already exists."% (bucket, obj), changed=False) - else: - create_dirkey(module, s3, bucket, dirobj) - if bucketrtn is False: - created = create_bucket(module, s3, bucket) - create_dirkey(module, s3, bucket, dirobj) - - # Support for grabbing the time-expired URL for an object in S3/Walrus. - if mode == 'geturl': - if bucket and obj: - bucketrtn = bucket_check(module, s3, bucket) - if bucketrtn is False: - module.fail_json(msg="Bucket %s does not exist."%bucket, failed=True) - else: - keyrtn = key_check(module, s3, bucket, obj) - if keyrtn is True: - get_download_url(module, s3, bucket, obj, expiry) - else: - module.fail_json(msg="Key %s does not exist."%obj, failed=True) - else: - module.fail_json(msg="Bucket and Object parameters must be set", failed=True) - sys.exit(0) - - if mode == 'getstr': - if bucket and obj: - bucketrtn = bucket_check(module, s3, bucket) - if bucketrtn is False: - module.fail_json(msg="Bucket %s does not exist."%bucket, failed=True) - else: - keyrtn = key_check(module, s3, bucket, obj) - if keyrtn is True: - download_s3str(module, s3, bucket, obj) - else: - module.fail_json(msg="Key %s does not exist."%obj, failed=True) - - sys.exit(0) - -# this is magic, see lib/ansible/module_common.py -#<> - -main()