Skip to content

Commit

Permalink
Add lightsail_static_ip module (#259)
Browse files Browse the repository at this point in the history
Add lightsail_static_ip module

SUMMARY
Adds a module to manage AWS Lightsail Static IP addresses
Fixes #250
ISSUE TYPE

New Module Pull Request

COMPONENT NAME
community.aws.lightsail_static_ip
ADDITIONAL INFORMATION
As per my earlier pull request, this is part of larger work to add functionality to this module in terms of managing AWS Lightsail.
Apologies if there are any issues/I have missed anything. I am new to Ansible development, but have tried to follow the contribution docs as best as I can.
Example playbook:
    - name: create static IP
      community.aws.lightsail_static_ip:
        name: "test_static"
        state: present
        region: ap-southeast-2

Reviewed-by: Jill R <None>
Reviewed-by: Mark Chappell <None>
  • Loading branch information
danielcotton authored Jul 1, 2022
1 parent d7e3617 commit 88f5d0c
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 0 deletions.
1 change: 1 addition & 0 deletions meta/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ action_groups:
- lambda_info
- lambda_policy
- lightsail
- lightsail_static_ip
- networkfirewall
- networkfirewall_info
- networkfirewall_policy
Expand Down
148 changes: 148 additions & 0 deletions plugins/modules/lightsail_static_ip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/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_static_ip
version_added: 4.1.0
short_description: Manage static IP addresses in AWS Lightsail
description:
- Manage static IP addresses in AWS Lightsail.
author:
- "Daniel Cotton (@danielcotton)"
options:
state:
description:
- Describes the desired state.
default: present
choices: ['present', 'absent']
type: str
name:
description: Name of the static IP.
required: true
type: str
extends_documentation_fragment:
- amazon.aws.aws
- amazon.aws.ec2
'''


EXAMPLES = '''
- name: Provision a Lightsail static IP
community.aws.lightsail_static_ip:
state: present
name: my_static_ip
register: my_ip
- name: Remove a static IP
community.aws.lightsail_static_ip:
state: absent
name: my_static_ip
'''

RETURN = '''
static_ip:
description: static_ipinstance data
returned: always
type: dict
sample:
arn: "arn:aws:lightsail:ap-southeast-2:184297340509:StaticIp/d8f47672-c261-4443-a484-4a2ec983db9a"
created_at: "2021-02-28T00:04:05.202000+10:30"
ip_address: "192.0.2.5"
is_attached: false
location:
availability_zone: all
region_name: ap-southeast-2
name: "static_ip"
resource_type: StaticIp
support_code: "677585553206/192.0.2.5"
'''

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_static_ip_info(module, client, static_ip_name, fail_if_not_found=False):

try:
res = client.get_static_ip(staticIpName=static_ip_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['staticIp']


def create_static_ip(module, client, static_ip_name):

inst = find_static_ip_info(module, client, static_ip_name)
if inst:
module.exit_json(changed=False, static_ip=camel_dict_to_snake_dict(inst))
else:
create_params = {'staticIpName': static_ip_name}

try:
client.allocate_static_ip(**create_params)
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)

inst = find_static_ip_info(module, client, static_ip_name, fail_if_not_found=True)

module.exit_json(changed=True, static_ip=camel_dict_to_snake_dict(inst))


def delete_static_ip(module, client, static_ip_name):

inst = find_static_ip_info(module, client, static_ip_name)
if inst is None:
module.exit_json(changed=False, static_ip={})

changed = False
try:
client.release_static_ip(staticIpName=static_ip_name)
changed = True
except botocore.exceptions.ClientError as e:
module.fail_json_aws(e)

module.exit_json(changed=changed, static_ip=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']),
)

module = AnsibleAWSModule(argument_spec=argument_spec)

client = module.client('lightsail')

name = module.params.get('name')
state = module.params.get('state')

if state == 'present':
create_static_ip(module, client, name)
elif state == 'absent':
delete_static_ip(module, client, name)


if __name__ == '__main__':
main()
1 change: 1 addition & 0 deletions tests/integration/targets/lightsail_static_ip/aliases
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cloud/aws
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
static_ip_name: "{{ resource_prefix }}_static_ip"
96 changes: 96 additions & 0 deletions tests/integration/targets/lightsail_static_ip/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---

- module_defaults:
group/aws:
aws_access_key: '{{ aws_access_key | default(omit) }}'
aws_secret_key: '{{ aws_secret_key | default(omit) }}'
security_token: '{{ security_token | default(omit) }}'
region: '{{ aws_region | default(omit) }}'

block:

# ==== Tests ===================================================

- name: Create a new static IP
lightsail_static_ip:
name: "{{ static_ip_name }}"
register: result

- assert:
that:
- result.changed == True
- '"static_ip" in result'
- '"arn" in result.static_ip'
- '"created_at" in result.static_ip'
- '"ip_address" in result.static_ip'
- '"is_attached" in result.static_ip'
- '"location" in result.static_ip'
- '"name" in result.static_ip'
- '"resource_type" in result.static_ip'
- '"support_code" in result.static_ip'
- result.static_ip.arn.startswith("arn:")
- result.static_ip.name == static_ip_name
- result.static_ip.resource_type == 'StaticIp'
- result.static_ip.is_attached == false
- result.static_ip.ip_address | ansible.utils.ipaddr
- '"availability_zone" in result.static_ip.location'
- '"region_name" in result.static_ip.location'

- set_fact:
lightsail_ip_arn: '{{ result.static_ip.arn }}'
lightsail_ip_address: '{{ result.static_ip.ip_address }}'

- name: Make sure create is idempotent
lightsail_static_ip:
name: "{{ static_ip_name }}"
register: result

- assert:
that:
- result.changed == False
- '"static_ip" in result'
- '"arn" in result.static_ip'
- '"created_at" in result.static_ip'
- '"ip_address" in result.static_ip'
- '"is_attached" in result.static_ip'
- '"location" in result.static_ip'
- '"name" in result.static_ip'
- '"resource_type" in result.static_ip'
- '"support_code" in result.static_ip'
- result.static_ip.arn == lightsail_ip_arn
- result.static_ip.name == static_ip_name
- result.static_ip.resource_type == 'StaticIp'
- result.static_ip.is_attached == false
- result.static_ip.ip_address == lightsail_ip_address
- '"availability_zone" in result.static_ip.location'
- '"region_name" in result.static_ip.location'

- name: Delete the static IP
lightsail_static_ip:
name: "{{ static_ip_name }}"
state: absent
register: result

- assert:
that:
- result.changed == True

- name: Make sure deletion is idempotent
lightsail_static_ip:
name: "{{ static_ip_name }}"
state: absent
register: result

- assert:
that:
- result.changed == False

# ==== Cleanup ====================================================

always:

- name: Cleanup - delete static IP
lightsail_static_ip:
name: "{{ static_ip_name }}"
state: absent
ignore_errors: yes

0 comments on commit 88f5d0c

Please sign in to comment.