-
Notifications
You must be signed in to change notification settings - Fork 23.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding module to manage AWS Storage gateways #40494
Changes from all commits
d5c4120
67da0e7
53ce6b0
2f857a0
9edc27c
b5ff3b7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
#!/usr/bin/python | ||
|
||
# Copyright: (c) 2018, Aaron Smith <ajsmith10381@gmail.com> | ||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) | ||
|
||
from __future__ import absolute_import, division, print_function | ||
__metaclass__ = type | ||
|
||
|
||
ANSIBLE_METADATA = {'metadata_version': '1.1', | ||
'status': ['preview'], | ||
'supported_by': 'community'} | ||
|
||
|
||
DOCUMENTATION = r''' | ||
--- | ||
module: storage_gateway | ||
short_description: Manage AWS Storage Gateway instances | ||
description: | ||
- Activate or deactivate AWS Storage Gateway instances. | ||
version_added: "2.7" | ||
requirements: [ 'botocore', 'boto3' ] | ||
author: | ||
- "Aaron Smith (@slapula)" | ||
options: | ||
name: | ||
description: | ||
- The name you configured for your gateway. | ||
required: true | ||
state: | ||
description: | ||
- Whether the resource should be present or absent. | ||
default: present | ||
choices: ['present', 'absent'] | ||
activation_key: | ||
description: | ||
- Your gateway activation key. See AWS documentation on how to acquire this key. | ||
required: true | ||
timezone: | ||
description: | ||
- A value that indicates the time zone you want to set for the gateway. | ||
required: true | ||
gateway_region: | ||
description: | ||
- A value that indicates the region where you want to store your data. | ||
required: true | ||
gateway_type: | ||
description: | ||
- A value that defines the type of gateway to activate. | ||
- The type specified is critical to all later functions of the gateway and cannot be changed after activation. | ||
default: 'STORED' | ||
choices: ['STORED', 'CACHED', 'VTL', 'FILE_S3'] | ||
tape_drive_type: | ||
description: | ||
- The value that indicates the type of tape drive to use for tape gateway. | ||
choices: ['IBM-ULT3580-TD5'] | ||
medium_changer_type: | ||
description: | ||
- The value that indicates the type of medium changer to use for tape gateway. | ||
choices: ['STK-L700', 'AWS-Gateway-VTL'] | ||
extends_documentation_fragment: | ||
- aws | ||
- ec2 | ||
''' | ||
|
||
EXAMPLES = r''' | ||
- name: Activate file gateway | ||
storage_gateway: | ||
name: "example-file-gateway" | ||
state: present | ||
activation_key: "{{ activation_code.stdout }}" | ||
timezone: 'GMT-6:00' | ||
gateway_region: "{{ aws_region }}" | ||
gateway_type: 'FILE_S3' | ||
''' | ||
|
||
RETURN = r''' | ||
gateway_arn: | ||
description: The ARN of the gateway you just created or updated. | ||
returned: always | ||
type: string | ||
''' | ||
|
||
import time | ||
import ast | ||
|
||
try: | ||
import botocore | ||
from botocore.exceptions import BotoCoreError, ClientError | ||
except ImportError: | ||
pass # handled by AnsibleAWSModule | ||
|
||
from ansible.module_utils.aws.core import AnsibleAWSModule | ||
from ansible.module_utils.ec2 import boto3_conn, get_aws_connection_info, AWSRetry | ||
from ansible.module_utils.ec2 import camel_dict_to_snake_dict, boto3_tag_list_to_ansible_dict | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line 94 and 95 are also unused imports. |
||
|
||
|
||
def gateway_exists(client, module, params, result): | ||
try: | ||
gateway_list = client.list_gateways() | ||
for i in gateway_list['Gateways']: | ||
if i['GatewayName'] == params['GatewayName']: | ||
disks_response = client.list_local_disks( | ||
GatewayARN=i['GatewayARN'] | ||
) | ||
result['GatewayARN'] = i['GatewayARN'] | ||
result['Disks'] = disks_response['Disks'] | ||
return True | ||
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError): | ||
return False | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It looks like list_gateways() returns an empty list rather than failing if no gateways exist, so I think fail_json_aws should probably be used here. Right now valid ClientError and BotoCoreError exceptions are masked. If there's a specific boto3 exception that needs to be handled, use |
||
|
||
return False | ||
|
||
|
||
def create_gateway(client, module, params, result): | ||
try: | ||
gw_response = client.activate_gateway(**params) | ||
time.sleep(15) # Need a waiter here but it doesn't exist yet in the StorageGateway API | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you verify that the gateway is active here before moving on? Maybe with https://boto3.readthedocs.io/en/latest/reference/services/storagegateway.html#StorageGateway.Client.describe_gateway_information. We've been adding waiters for things here https://github.com/ansible/ansible/blob/devel/lib/ansible/module_utils/aws/waiters.py and at a glance looks like this could use that. |
||
disks_response = client.list_local_disks( | ||
GatewayARN=gw_response['GatewayARN'] | ||
) | ||
if disks_response['Disks']: | ||
if params['GatewayType'] == 'FILE_S3': | ||
vol_response = client.add_cache( | ||
GatewayARN=gw_response['GatewayARN'], | ||
DiskIds=[disks_response['Disks'][0]['DiskId']] | ||
) | ||
if params['GatewayType'] == 'CACHED' or params['GatewayType'] == 'VTL': | ||
vol_response = client.add_cache( | ||
GatewayARN=gw_response['GatewayARN'], | ||
DiskIds=[disks_response['Disks'][0]['DiskId']] | ||
) | ||
vol_response = client.add_upload_buffer( | ||
GatewayARN=gw_response['GatewayARN'], | ||
DiskIds=[disks_response['Disks'][1]['DiskId']] | ||
) | ||
if params['GatewayType'] == 'STORED': | ||
vol_response = client.add_upload_buffer( | ||
GatewayARN=gw_response['GatewayARN'], | ||
DiskIds=[disks_response['Disks'][0]['DiskId']] | ||
) | ||
result['gateway_arn'] = gw_response['GatewayARN'] | ||
result['Disks'] = disks_response['Disks'] | ||
result['changed'] = True | ||
return result | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused return here and on line 149. |
||
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: | ||
module.fail_json_aws(e, msg="Couldn't activate storage gateway instance") | ||
|
||
return result | ||
|
||
|
||
def update_gateway(client, module, params, result): | ||
current_params = client.describe_gateway_information( | ||
GatewayARN=result['GatewayARN'] | ||
) | ||
|
||
if params['GatewayName'] != current_params['GatewayName'] or params['GatewayTimezone'] != current_params['GatewayTimezone']: | ||
try: | ||
response = client.update_gateway_information( | ||
GatewayARN=result['GatewayARN'], | ||
GatewayName=params['GatewayName'], | ||
GatewayTimezone=params['GatewayTimezone'] | ||
) | ||
disks_response = client.list_local_disks( | ||
GatewayARN=result['GatewayARN'] | ||
) | ||
result['gateway_arn'] = response['GatewayARN'] | ||
result['Disks'] = disks_response['Disks'] | ||
result['changed'] = True | ||
return result | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This return and the one on line 174 don't do anything (same for returns in delete_gateway()) |
||
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: | ||
module.fail_json_aws(e, msg="Couldn't update storage gateway") | ||
|
||
return result | ||
|
||
|
||
def delete_gateway(client, module, result): | ||
try: | ||
response = client.delete_gateway( | ||
GatewayARN=result['GatewayARN'] | ||
) | ||
result['changed'] = True | ||
return result | ||
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: | ||
module.fail_json_aws(e, msg="Couldn't delete storage gateway") | ||
|
||
return result | ||
|
||
|
||
def main(): | ||
module = AnsibleAWSModule( | ||
argument_spec={ | ||
'name': dict(type='str', required=True), | ||
'state': dict(type='str', choices=['present', 'absent'], default='present'), | ||
'activation_key': dict(type='str', required=True), | ||
'timezone': dict(type='str', required=True), | ||
'gateway_region': dict(type='str', required=True), | ||
'gateway_type': dict(type='str', default='STORED', choices=['STORED', 'CACHED', 'VTL', 'FILE_S3']), | ||
'tape_drive_type': dict(type='str', choices=['IBM-ULT3580-TD5']), | ||
'medium_changer_type': dict(type='str', choices=['STK-L700', 'AWS-Gateway-VTL']), | ||
}, | ||
supports_check_mode=False, | ||
) | ||
|
||
result = { | ||
'changed': False, | ||
'gateway_arn': '' | ||
} | ||
|
||
desired_state = module.params.get('state') | ||
|
||
params = {} | ||
params['GatewayName'] = module.params.get('name') | ||
params['ActivationKey'] = module.params.get('activation_key') | ||
params['GatewayTimezone'] = module.params.get('timezone') | ||
params['GatewayRegion'] = module.params.get('gateway_region') | ||
params['GatewayType'] = module.params.get('gateway_type') | ||
if module.params.get('tape_drive_type'): | ||
params['TapeDriveType'] = module.params.get('tape_drive_type') | ||
if module.params.get('medium_changer_type'): | ||
params['MediumChangerType'] = module.params.get('medium_changer_type') | ||
|
||
client = module.client('storagegateway') | ||
|
||
gateway_status = gateway_exists(client, module, params, result) | ||
|
||
if desired_state == 'present': | ||
if not gateway_status: | ||
create_gateway(client, module, params, result) | ||
if gateway_status: | ||
update_gateway(client, module, params, result) | ||
|
||
if desired_state == 'absent': | ||
if gateway_status: | ||
delete_gateway(client, module, result) | ||
|
||
module.exit_json(changed=result['changed'], gateway_arn=result['gateway_arn']) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a blocker, but it seems like returning tuples could be an alternative to passing around a reference to a result dictionary that gets modified and not returned. |
||
|
||
|
||
if __name__ == '__main__': | ||
main() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
cloud/aws | ||
posix/ci/cloud/group4/aws |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
--- | ||
# defaults file for ec2_instance | ||
ec2_instance_name: '{{resource_prefix}}-node' | ||
ec2_instance_owner: 'integration-run-{{resource_prefix}}' | ||
ec2_file_ami_image: | ||
# amazon/aws-storage-gateway-file-2018-03-21 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If there's a way to filter for these you could use ec2_ami_facts so we always get the latest ones. |
||
ap-northeast-1: ami-798cdc1f | ||
ap-northeast-2: ami-d10ca0bf | ||
ap-south-1: ami-e238638d | ||
ap-southeast-1: ami-48114d34 | ||
ap-southeast-2: ami-47d41925 | ||
ca-central-1: ami-edd95f89 | ||
eu-central-1: ami-9aa9f971 | ||
eu-west-1: ami-10f1a569 | ||
eu-west-2: ami-4c34d22b | ||
eu-west-3: ami-38388e45 | ||
sa-east-1: ami-0f481c63 | ||
us-east-1: ami-6e14c313 | ||
us-east-2: ami-7845741d | ||
us-west-1: ami-ba9483da | ||
us-west-2: ami-be21bdc6 | ||
ec2_vol_vtl_ami_image: | ||
# amazon/aws-storage-gateway-2.0.9.2 | ||
ap-northeast-1: ami-0a8bcd6c | ||
ap-northeast-2: ami-6667ca08 | ||
ap-south-1: ami-c04718af | ||
ap-southeast-1: ami-37175c4b | ||
ap-southeast-2: ami-95d91ff7 | ||
ca-central-1: ami-7e880f1a | ||
eu-central-1: ami-71ec811e | ||
eu-west-1: ami-dc82c7a5 | ||
eu-west-2: ami-4d64802a | ||
eu-west-3: ami-2b66d056 | ||
sa-east-1: ami-ec165d80 | ||
us-east-1: ami-571ff42a | ||
us-east-2: ami-a7facdc2 | ||
us-west-1: ami-68e7ec08 | ||
us-west-2: ami-989119e0 | ||
us-gov-west-1: ami-9ce277fd |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
dependencies: | ||
- prepare_tests | ||
- setup_ec2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These imports are unused.