summaryrefslogtreecommitdiffstats
path: root/ansible_collections/community/aws/plugins/modules/lightsail.py
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 16:03:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 16:03:42 +0000
commit66cec45960ce1d9c794e9399de15c138acb18aed (patch)
tree59cd19d69e9d56b7989b080da7c20ef1a3fe2a5a /ansible_collections/community/aws/plugins/modules/lightsail.py
parentInitial commit. (diff)
downloadansible-upstream.tar.xz
ansible-upstream.zip
Adding upstream version 7.3.0+dfsg.upstream/7.3.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/community/aws/plugins/modules/lightsail.py')
-rw-r--r--ansible_collections/community/aws/plugins/modules/lightsail.py340
1 files changed, 340 insertions, 0 deletions
diff --git a/ansible_collections/community/aws/plugins/modules/lightsail.py b/ansible_collections/community/aws/plugins/modules/lightsail.py
new file mode 100644
index 00000000..5e403515
--- /dev/null
+++ b/ansible_collections/community/aws/plugins/modules/lightsail.py
@@ -0,0 +1,340 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+# Copyright: Ansible Project
+# 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
+
+
+DOCUMENTATION = '''
+---
+module: lightsail
+version_added: 1.0.0
+short_description: Manage instances in AWS Lightsail
+description:
+ - Manage instances in AWS Lightsail.
+ - Instance tagging is not yet supported in this module.
+author:
+ - "Nick Ball (@nickball)"
+ - "Prasad Katti (@prasadkatti)"
+options:
+ state:
+ description:
+ - Indicate desired state of the target.
+ - I(rebooted) and I(restarted) are aliases.
+ default: present
+ choices: ['present', 'absent', 'running', 'restarted', 'rebooted', 'stopped']
+ type: str
+ name:
+ description: Name of the instance.
+ required: true
+ type: str
+ zone:
+ description:
+ - AWS availability zone in which to launch the instance.
+ - Required when I(state=present)
+ type: str
+ blueprint_id:
+ description:
+ - ID of the instance blueprint image.
+ - Required when I(state=present)
+ type: str
+ bundle_id:
+ description:
+ - Bundle of specification info for the instance.
+ - Required when I(state=present).
+ type: str
+ user_data:
+ description:
+ - Launch script that can configure the instance with additional data.
+ type: str
+ default: ''
+ key_pair_name:
+ description:
+ - Name of the key pair to use with the instance.
+ - If I(state=present) and a key_pair_name is not provided, the default keypair from the region will be used.
+ type: str
+ wait:
+ description:
+ - Wait for the instance to be in state 'running' before returning.
+ - If I(wait=false) an ip_address may not be returned.
+ - Has no effect when I(state=rebooted) or I(state=absent).
+ type: bool
+ default: true
+ wait_timeout:
+ description:
+ - How long before I(wait) gives up, in seconds.
+ default: 300
+ type: int
+
+extends_documentation_fragment:
+- amazon.aws.aws
+- amazon.aws.ec2
+- amazon.aws.boto3
+
+'''
+
+
+EXAMPLES = '''
+- name: Create a new Lightsail instance
+ community.aws.lightsail:
+ state: present
+ name: my_instance
+ region: us-east-1
+ zone: us-east-1a
+ blueprint_id: ubuntu_16_04
+ bundle_id: nano_1_0
+ key_pair_name: id_rsa
+ user_data: " echo 'hello world' > /home/ubuntu/test.txt"
+ register: my_instance
+
+- name: Delete an instance
+ community.aws.lightsail:
+ state: absent
+ region: us-east-1
+ name: my_instance
+
+'''
+
+RETURN = '''
+changed:
+ description: if a snapshot has been modified/created
+ returned: always
+ type: bool
+ sample:
+ changed: true
+instance:
+ description: instance data
+ returned: always
+ type: dict
+ sample:
+ arn: "arn:aws:lightsail:us-east-1:123456789012:Instance/1fef0175-d6c8-480e-84fa-214f969cda87"
+ blueprint_id: "ubuntu_16_04"
+ blueprint_name: "Ubuntu"
+ bundle_id: "nano_1_0"
+ created_at: "2017-03-27T08:38:59.714000-04:00"
+ hardware:
+ cpu_count: 1
+ ram_size_in_gb: 0.5
+ is_static_ip: false
+ location:
+ availability_zone: "us-east-1a"
+ region_name: "us-east-1"
+ name: "my_instance"
+ networking:
+ monthly_transfer:
+ gb_per_month_allocated: 1024
+ ports:
+ - access_direction: "inbound"
+ access_from: "Anywhere (0.0.0.0/0)"
+ access_type: "public"
+ common_name: ""
+ from_port: 80
+ protocol: tcp
+ to_port: 80
+ - access_direction: "inbound"
+ access_from: "Anywhere (0.0.0.0/0)"
+ access_type: "public"
+ common_name: ""
+ from_port: 22
+ protocol: tcp
+ to_port: 22
+ private_ip_address: "172.26.8.14"
+ public_ip_address: "34.207.152.202"
+ resource_type: "Instance"
+ ssh_key_name: "keypair"
+ state:
+ code: 16
+ name: running
+ support_code: "123456789012/i-0997c97831ee21e33"
+ username: "ubuntu"
+'''
+
+import time
+
+try:
+ import botocore
+except ImportError:
+ # will be caught by AnsibleAWSModule
+ pass
+
+from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict
+
+from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
+from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code
+
+
+def find_instance_info(module, client, instance_name, fail_if_not_found=False):
+
+ try:
+ res = client.get_instance(instanceName=instance_name)
+ except is_boto3_error_code('NotFoundException') as e:
+ if fail_if_not_found:
+ module.fail_json_aws(e)
+ return None
+ except botocore.exceptions.ClientError as e: # pylint: disable=duplicate-except
+ module.fail_json_aws(e)
+ return res['instance']
+
+
+def wait_for_instance_state(module, client, instance_name, states):
+ """
+ `states` is a list of instance states that we are waiting for.
+ """
+
+ wait_timeout = module.params.get('wait_timeout')
+ wait_max = time.time() + wait_timeout
+ while wait_max > time.time():
+ try:
+ instance = find_instance_info(module, client, instance_name)
+ if instance['state']['name'] in states:
+ break
+ time.sleep(5)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+ else:
+ module.fail_json(msg='Timed out waiting for instance "{0}" to get to one of the following states -'
+ ' {1}'.format(instance_name, states))
+
+
+def create_instance(module, client, instance_name):
+
+ inst = find_instance_info(module, client, instance_name)
+ if inst:
+ module.exit_json(changed=False, instance=camel_dict_to_snake_dict(inst))
+ else:
+ create_params = {'instanceNames': [instance_name],
+ 'availabilityZone': module.params.get('zone'),
+ 'blueprintId': module.params.get('blueprint_id'),
+ 'bundleId': module.params.get('bundle_id'),
+ 'userData': module.params.get('user_data')}
+
+ key_pair_name = module.params.get('key_pair_name')
+ if key_pair_name:
+ create_params['keyPairName'] = key_pair_name
+
+ try:
+ client.create_instances(**create_params)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+ wait = module.params.get('wait')
+ if wait:
+ desired_states = ['running']
+ wait_for_instance_state(module, client, instance_name, desired_states)
+ inst = find_instance_info(module, client, instance_name, fail_if_not_found=True)
+
+ module.exit_json(changed=True, instance=camel_dict_to_snake_dict(inst))
+
+
+def delete_instance(module, client, instance_name):
+
+ changed = False
+
+ inst = find_instance_info(module, client, instance_name)
+ if inst is None:
+ module.exit_json(changed=changed, instance={})
+
+ # Wait for instance to exit transition state before deleting
+ desired_states = ['running', 'stopped']
+ wait_for_instance_state(module, client, instance_name, desired_states)
+
+ try:
+ client.delete_instance(instanceName=instance_name)
+ changed = True
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+ module.exit_json(changed=changed, instance=camel_dict_to_snake_dict(inst))
+
+
+def restart_instance(module, client, instance_name):
+ """
+ Reboot an existing instance
+ Wait will not apply here as this is an OS-level operation
+ """
+
+ changed = False
+
+ inst = find_instance_info(module, client, instance_name, fail_if_not_found=True)
+
+ try:
+ client.reboot_instance(instanceName=instance_name)
+ changed = True
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+
+ module.exit_json(changed=changed, instance=camel_dict_to_snake_dict(inst))
+
+
+def start_or_stop_instance(module, client, instance_name, state):
+ """
+ Start or stop an existing instance
+ """
+
+ changed = False
+
+ inst = find_instance_info(module, client, instance_name, fail_if_not_found=True)
+
+ # Wait for instance to exit transition state before state change
+ desired_states = ['running', 'stopped']
+ wait_for_instance_state(module, client, instance_name, desired_states)
+
+ # Try state change
+ if inst and inst['state']['name'] != state:
+ try:
+ if state == 'running':
+ client.start_instance(instanceName=instance_name)
+ else:
+ client.stop_instance(instanceName=instance_name)
+ except botocore.exceptions.ClientError as e:
+ module.fail_json_aws(e)
+ changed = True
+ # Grab current instance info
+ inst = find_instance_info(module, client, instance_name)
+
+ wait = module.params.get('wait')
+ if wait:
+ desired_states = [state]
+ wait_for_instance_state(module, client, instance_name, desired_states)
+ inst = find_instance_info(module, client, instance_name, fail_if_not_found=True)
+
+ module.exit_json(changed=changed, instance=camel_dict_to_snake_dict(inst))
+
+
+def main():
+
+ argument_spec = dict(
+ name=dict(type='str', required=True),
+ state=dict(type='str', default='present', choices=['present', 'absent', 'stopped', 'running', 'restarted',
+ 'rebooted']),
+ zone=dict(type='str'),
+ blueprint_id=dict(type='str'),
+ bundle_id=dict(type='str'),
+ key_pair_name=dict(type='str'),
+ user_data=dict(type='str', default=''),
+ wait=dict(type='bool', default=True),
+ wait_timeout=dict(default=300, type='int'),
+ )
+
+ module = AnsibleAWSModule(argument_spec=argument_spec,
+ required_if=[['state', 'present', ('zone', 'blueprint_id', 'bundle_id')]])
+
+ client = module.client('lightsail')
+
+ name = module.params.get('name')
+ state = module.params.get('state')
+
+ if state == 'present':
+ create_instance(module, client, name)
+ elif state == 'absent':
+ delete_instance(module, client, name)
+ elif state in ('running', 'stopped'):
+ start_or_stop_instance(module, client, name, state)
+ elif state in ('restarted', 'rebooted'):
+ restart_instance(module, client, name)
+
+
+if __name__ == '__main__':
+ main()