File: //lib/python3.9/site-packages/ansible_collections/community/aws/plugins/modules/lightsail.py
# -*- 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()