mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
New module: AWS storage gateway facts (#39491)
* Add a module to get storage gateway facts * Review fixes * Last review fixes * Add filtering gathering & some fixes * doc fix * API error handling * Remove ec2_argument_spec import Use imported BotoCoreError and ClientError rather than botocore.exceptions
This commit is contained in:
parent
f872b70449
commit
88df583af7
1 changed files with 354 additions and 0 deletions
354
lib/ansible/modules/cloud/amazon/aws_sgw_facts.py
Normal file
354
lib/ansible/modules/cloud/amazon/aws_sgw_facts.py
Normal file
|
@ -0,0 +1,354 @@
|
|||
#!/usr/bin/python
|
||||
# Copyright (c) 2018 Loic BLOT <loic.blot@unix-experience.fr>
|
||||
# This module is sponsored by E.T.A.I. (www.etai.fr)
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'}
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: aws_sgw_facts
|
||||
short_description: Fetch AWS Storage Gateway facts
|
||||
description:
|
||||
- Fetch AWS Storage Gateway facts
|
||||
version_added: "2.6"
|
||||
requirements: [ boto3 ]
|
||||
author: "Loic Blot <loic.blot@unix-experience.fr>"
|
||||
options:
|
||||
gather_local_disks:
|
||||
description:
|
||||
- Gather local disks attached to the storage gateway.
|
||||
type: bool
|
||||
required: false
|
||||
default: true
|
||||
gather_tapes:
|
||||
description:
|
||||
- Gather tape information for storage gateways in tape mode.
|
||||
type: bool
|
||||
required: false
|
||||
default: true
|
||||
gather_file_shares:
|
||||
description:
|
||||
- Gather file share information for storage gateways in s3 mode.
|
||||
type: bool
|
||||
required: false
|
||||
default: true
|
||||
gather_volumes:
|
||||
description:
|
||||
- Gather volume information for storage gateways in iSCSI (cached & stored) modes.
|
||||
type: bool
|
||||
required: false
|
||||
default: true
|
||||
extends_documentation_fragment:
|
||||
- aws
|
||||
- ec2
|
||||
'''
|
||||
|
||||
RETURN = '''
|
||||
gateways:
|
||||
description: list of gateway objects
|
||||
returned: always
|
||||
type: complex
|
||||
contains:
|
||||
gateway_arn:
|
||||
description: "Storage Gateway ARN"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "arn:aws:storagegateway:eu-west-1:367709993819:gateway/sgw-9999F888"
|
||||
gateway_id:
|
||||
description: "Storage Gateway ID"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "sgw-9999F888"
|
||||
gateway_name:
|
||||
description: "Storage Gateway friendly name"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "my-sgw-01"
|
||||
gateway_operational_state:
|
||||
description: "Storage Gateway operational state"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "ACTIVE"
|
||||
gateway_type:
|
||||
description: "Storage Gateway type"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "FILE_S3"
|
||||
file_shares:
|
||||
description: "Storage gateway file shares"
|
||||
returned: when gateway_type == "FILE_S3"
|
||||
type: complex
|
||||
contains:
|
||||
file_share_arn:
|
||||
description: "File share ARN"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "arn:aws:storagegateway:eu-west-1:399805793479:share/share-AF999C88"
|
||||
file_share_id:
|
||||
description: "File share ID"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "share-AF999C88"
|
||||
file_share_status:
|
||||
description: "File share status"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "AVAILABLE"
|
||||
tapes:
|
||||
description: "Storage Gateway tapes"
|
||||
returned: when gateway_type == "VTL"
|
||||
type: complex
|
||||
contains:
|
||||
tape_arn:
|
||||
description: "Tape ARN"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "arn:aws:storagegateway:eu-west-1:399805793479:tape/tape-AF999C88"
|
||||
tape_barcode:
|
||||
description: "Tape ARN"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "tape-AF999C88"
|
||||
tape_size_in_bytes:
|
||||
description: "Tape ARN"
|
||||
returned: always
|
||||
type: integer
|
||||
sample: 555887569
|
||||
tape_status:
|
||||
description: "Tape ARN"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "AVAILABLE"
|
||||
local_disks:
|
||||
description: "Storage gateway local disks"
|
||||
returned: always
|
||||
type: complex
|
||||
contains:
|
||||
disk_allocation_type:
|
||||
description: "Disk allocation type"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "CACHE STORAGE"
|
||||
disk_id:
|
||||
description: "Disk ID on the system"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "pci-0000:00:1f.0"
|
||||
disk_node:
|
||||
description: "Disk parent block device"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "/dev/sdb"
|
||||
disk_path:
|
||||
description: "Disk path used for the cache"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "/dev/nvme1n1"
|
||||
disk_size_in_bytes:
|
||||
description: "Disk size in bytes"
|
||||
returned: always
|
||||
type: integer
|
||||
sample: 107374182400
|
||||
disk_status:
|
||||
description: "Disk status"
|
||||
returned: always
|
||||
type: string
|
||||
sample: "present"
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
# Note: These examples do not set authentication details, see the AWS Guide for details.
|
||||
|
||||
- name: "Get AWS storage gateway facts"
|
||||
aws_sgw_facts:
|
||||
|
||||
- name: "Get AWS storage gateway facts for region eu-west-3"
|
||||
aws_sgw_facts:
|
||||
region: eu-west-3
|
||||
'''
|
||||
|
||||
from ansible.module_utils.aws.core import AnsibleAWSModule
|
||||
from ansible.module_utils.ec2 import camel_dict_to_snake_dict
|
||||
|
||||
try:
|
||||
from botocore.exceptions import BotoCoreError, ClientError
|
||||
except ImportError:
|
||||
pass # caught by imported HAS_BOTO3
|
||||
|
||||
|
||||
class SGWFactsManager(object):
|
||||
def __init__(self, client, module):
|
||||
self.client = client
|
||||
self.module = module
|
||||
self.name = self.module.params.get('name')
|
||||
|
||||
def fetch(self):
|
||||
gateways = self.list_gateways()
|
||||
for gateway in gateways:
|
||||
if self.module.params.get('gather_local_disks'):
|
||||
self.list_local_disks(gateway)
|
||||
# File share gateway
|
||||
if gateway["gateway_type"] == "FILE_S3" and self.module.params.get('gather_file_shares'):
|
||||
self.list_gateway_file_shares(gateway)
|
||||
# Volume tape gateway
|
||||
elif gateway["gateway_type"] == "VTL" and self.module.params.get('gather_tapes'):
|
||||
self.list_gateway_vtl(gateway)
|
||||
# iSCSI gateway
|
||||
elif gateway["gateway_type"] in ["CACHED", "STORED"] and self.module.params.get('gather_volumes'):
|
||||
self.list_gateway_volumes(gateway)
|
||||
|
||||
self.module.exit_json(gateways=gateways)
|
||||
|
||||
"""
|
||||
List all storage gateways for the AWS endpoint.
|
||||
"""
|
||||
def list_gateways(self):
|
||||
try:
|
||||
paginator = self.client.get_paginator('list_gateways')
|
||||
response = paginator.paginate(
|
||||
PaginationConfig={
|
||||
'PageSize': 100,
|
||||
}
|
||||
).build_full_result()
|
||||
|
||||
gateways = []
|
||||
for gw in response["Gateways"]:
|
||||
gateways.append(camel_dict_to_snake_dict(gw))
|
||||
|
||||
return gateways
|
||||
|
||||
except (BotoCoreError, ClientError) as e:
|
||||
self.module.fail_json_aws(e, msg="Couldn't list storage gateways")
|
||||
|
||||
"""
|
||||
Read file share objects from AWS API response.
|
||||
Drop the gateway_arn attribute from response, as it will be duplicate with parent object.
|
||||
"""
|
||||
@staticmethod
|
||||
def _read_gateway_fileshare_response(fileshares, aws_reponse):
|
||||
for share in aws_reponse["FileShareInfoList"]:
|
||||
share_obj = camel_dict_to_snake_dict(share)
|
||||
if "gateway_arn" in share_obj:
|
||||
del share_obj["gateway_arn"]
|
||||
fileshares.append(share_obj)
|
||||
|
||||
return aws_reponse["NextMarker"] if "NextMarker" in aws_reponse else None
|
||||
|
||||
"""
|
||||
List file shares attached to AWS storage gateway when in S3 mode.
|
||||
"""
|
||||
def list_gateway_file_shares(self, gateway):
|
||||
try:
|
||||
response = self.client.list_file_shares(
|
||||
GatewayARN=gateway["gateway_arn"],
|
||||
Limit=100
|
||||
)
|
||||
|
||||
gateway["file_shares"] = []
|
||||
marker = self._read_gateway_fileshare_response(gateway["file_shares"], response)
|
||||
|
||||
while marker is not None:
|
||||
response = self.client.list_file_shares(
|
||||
GatewayARN=gateway["gateway_arn"],
|
||||
Marker=marker,
|
||||
Limit=100
|
||||
)
|
||||
|
||||
marker = self._read_gateway_fileshare_response(gateway["file_shares"], response)
|
||||
except (BotoCoreError, ClientError) as e:
|
||||
self.module.fail_json_aws(e, msg="Couldn't list gateway file shares")
|
||||
|
||||
"""
|
||||
List storage gateway local disks
|
||||
"""
|
||||
def list_local_disks(self, gateway):
|
||||
try:
|
||||
gateway['local_disks'] = [camel_dict_to_snake_dict(disk) for disk in
|
||||
self.client.list_local_disks(GatewayARN=gateway["gateway_arn"])['Disks']]
|
||||
except (BotoCoreError, ClientError) as e:
|
||||
self.module.fail_json_aws(e, msg="Couldn't list storage gateway local disks")
|
||||
|
||||
"""
|
||||
Read tape objects from AWS API response.
|
||||
Drop the gateway_arn attribute from response, as it will be duplicate with parent object.
|
||||
"""
|
||||
@staticmethod
|
||||
def _read_gateway_tape_response(tapes, aws_response):
|
||||
for tape in aws_response["TapeInfos"]:
|
||||
tape_obj = camel_dict_to_snake_dict(tape)
|
||||
if "gateway_arn" in tape_obj:
|
||||
del tape_obj["gateway_arn"]
|
||||
tapes.append(tape_obj)
|
||||
|
||||
return aws_response["Marker"] if "Marker" in aws_response else None
|
||||
|
||||
"""
|
||||
List VTL & VTS attached to AWS storage gateway in VTL mode
|
||||
"""
|
||||
def list_gateway_vtl(self, gateway):
|
||||
try:
|
||||
response = self.client.list_tapes(
|
||||
Limit=100
|
||||
)
|
||||
|
||||
gateway["tapes"] = []
|
||||
marker = self._read_gateway_tape_response(gateway["tapes"], response)
|
||||
|
||||
while marker is not None:
|
||||
response = self.client.list_tapes(
|
||||
Marker=marker,
|
||||
Limit=100
|
||||
)
|
||||
|
||||
marker = self._read_gateway_tape_response(gateway["tapes"], response)
|
||||
except (BotoCoreError, ClientError) as e:
|
||||
self.module.fail_json_aws(e, msg="Couldn't list storage gateway tapes")
|
||||
|
||||
"""
|
||||
List volumes attached to AWS storage gateway in CACHED or STORAGE mode
|
||||
"""
|
||||
def list_gateway_volumes(self, gateway):
|
||||
try:
|
||||
paginator = self.client.get_paginator('list_volumes')
|
||||
response = paginator.paginate(
|
||||
GatewayARN=gateway["gateway_arn"],
|
||||
PaginationConfig={
|
||||
'PageSize': 100,
|
||||
}
|
||||
).build_full_result()
|
||||
|
||||
gateway["volumes"] = []
|
||||
for volume in response["VolumeInfos"]:
|
||||
volume_obj = camel_dict_to_snake_dict(volume)
|
||||
if "gateway_arn" in volume_obj:
|
||||
del volume_obj["gateway_arn"]
|
||||
if "gateway_id" in volume_obj:
|
||||
del volume_obj["gateway_id"]
|
||||
|
||||
gateway["volumes"].append(volume_obj)
|
||||
except (BotoCoreError, ClientError) as e:
|
||||
self.module.fail_json_aws(e, msg="Couldn't list storage gateway volumes")
|
||||
|
||||
|
||||
def main():
|
||||
argument_spec = dict(
|
||||
gather_local_disks=dict(type='bool', default=True),
|
||||
gather_tapes=dict(type='bool', default=True),
|
||||
gather_file_shares=dict(type='bool', default=True),
|
||||
gather_volumes=dict(type='bool', default=True)
|
||||
)
|
||||
|
||||
module = AnsibleAWSModule(argument_spec=argument_spec)
|
||||
client = module.client('storagegateway')
|
||||
|
||||
if client is None: # this should never happen
|
||||
module.fail_json(msg='Unknown error, failed to create storagegateway client, no information from boto.')
|
||||
|
||||
SGWFactsManager(client, module).fetch()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in a new issue