plugins/modules/ali_eip.py (353 lines of code) (raw):
#!/usr/bin/python
# Copyright (c) 2017-present Alibaba Group Holding Limited. <xiaozhu36>
# 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 = '''
---
module: ali_eip
version_added: "2.9"
short_description: Create eip address and bind it to a specified device.
description:
- Create and release an elastic IP address
- Associate/disassociate an EIP with ECS instance id or SLB instance id or Elastic Network Interface (ENI) id.
- Set an EIP name and description
options:
state:
description:
- state for operating elastic IP address
choices: ['present', 'absent']
default: present
type: str
bandwidth:
description:
- Maximum outgoing bandwidth to the EIP, measured in Mbps (Mega bit per second)
default: 5
type: int
internet_charge_type:
description:
- Internet charge type of ECS instance
choices: ['PayByBandwidth', 'PayByTraffic']
default: 'PayByTraffic'
type: str
name:
description:
- The name of the EIP. The name can contain from 2 to 128 characters including "a-z", "A-Z", "0-9", underlines,
and hyphens. The name must start with an English letter, but cannot start with http:// or https://.
type: str
description:
description:
- The description of the EIP. The description can contain from 2 to 256 characters.
The description must start with English letters, but cannot start with http:// or https://.
type: str
ip_address:
description:
- The IP address of a previously allocated EIP and it can used to associate/disassociate with a device or delete itself.
- If present and instance_id is specified, the EIP is associated with the instance.
- If absent and instance_id is specified, the EIP is disassociated from the instance.
aliases: ['ip']
type: str
instance_id:
description:
- The id of the device for the EIP. Can be an ECS instance id or SLB Instance id or Elastic Network Interface (ENI) id.
aliases: ['device_id']
type: str
allocation_id:
description:
- The id of the EIP. It is required when need to operate existing eip.
aliases: ['id']
type: str
release_on_disassociation:
description:
- whether or not to automatically release the EIP when it is disassociated
type: bool
default: False
reuse_existing_ip_allowed:
description:
- Reuse an EIP that is not associated to a instance (when available), instead of allocating a new one.
type: bool
default: False
allow_reassociation:
description:
- Specify this option to allow an Elastic IP address that is already associated with another
ECS or SLB Instance to be re-associated with the specified instance.
type: bool
default: False
tags:
description:
- A hash/dictionaries of eip tags. C({"key":"value"})
type: dict
purge_tags:
description:
- Delete existing tags on the eip that are not specified in the task.
If True, it means you have to specify all the desired tags on each task affecting a eip.
default: False
type: bool
notes:
- A ip address or a instance id which has been associated with EIP can ensure idempotence.
requirements:
- "python >= 3.6"
- "footmark >= 1.13.0"
extends_documentation_fragment:
- alibaba.alicloud.alicloud
author:
- "He Guimin (@xiaozhu36)"
'''
EXAMPLES = '''
# Note: These examples do not set authentication details, see the Alibaba Cloud Guide for details.
- name: Associate an elastic IP with an instance
alibaba.alicloud.ali_eip:
instance_id: i-cqhc3hf4
- name: Associate an elastic IP with a device
alibaba.alicloud.ali_eip:
instance_id: eni-snc3nh438t
- name: Associate an elastic IP with a instance and allow reassociation
alibaba.alicloud.ali_eip:
instance_id: i-cqhc3hf4
allow_reassociation: True
- name: Disassociate an elastic IP from an instance
alibaba.alicloud.ali_eip:
instance_id: i-cqhc3hf4
ip: 93.184.216.119
state: absent
- name: Disassociate an elastic IP with a device
alibaba.alicloud.ali_eip:
instance_id: eni-snc3nh438t
ip: 93.184.216.119
state: absent
- name: Allocate a new elastic IP and associate it with an instance
alibaba.alicloud.ali_eip:
instance_id: i-1212f003
- name: Allocate a new elastic IP without associating it to anything and set name and description
alibaba.alicloud.ali_eip:
name: created-by-ansible
description: "form ansible"
register: eip
- name: Output the IP
debug:
msg: "Allocated IP is {{ eip.public_ip }}"
'''
RETURN = '''
eip:
description: info about the elastic IP address that was created or deleted.
returned: always
type: complex
contains:
allocation_id:
description: The EIP id.
returned: always
type: str
sample: "eip-2zee1nu68juox4"
allocation_time:
description: The time the EIP was created.
returned: always
type: str
sample: "2018-12-31T12:12:52Z"
bandwidth:
description: Maximum bandwidth from the internet network.
returned: always
type: int
sample: 5
charge_type:
description: The eip charge type.
returned: always
type: str
sample: "PostPaid"
description:
description: interface description.
returned: always
type: str
sample: "My new EIP"
id:
description: Allocated EIP id (alias for allocation_id).
returned: always
type: str
sample: "eip-2zee1nu68juox4"
instance_id:
description: Associated instance id.
returned: always
type: str
sample: "i-123456"
instance_region_id:
description: The region id in which the associated instance.
returned: always
type: str
sample: "cn-beijing"
instance_type:
description: Associated instance type.
returned: always
type: str
sample: "EcsInstance"
internet_charge_type:
description: The EIP charge type.
returned: always
type: str
sample: "PayByTraffic"
ip_address:
description: The IP address of the EIP.
returned: always
type: str
sample: "39.96.169.143"
name:
description: The EIP name.
returned: always
type: str
sample: "from-ansible"
status:
description: The EIP status.
returned: always
type: str
sample: "inuse"
tags:
description: Any tags assigned to the EIP.
returned: always
type: dict
sample: {}
'''
import time
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.alibaba.alicloud.plugins.module_utils.alicloud_ecs import ecs_argument_spec, vpc_connect
HAS_FOOTMARK = False
try:
from footmark.exception import VPCResponseError
HAS_FOOTMARK = True
except ImportError:
HAS_FOOTMARK = False
def find_eip(conn, module, ip_address, instance_id, allocation_id):
try:
eip = None
eips = conn.describe_eip_addresses()
if not ip_address and not instance_id and not allocation_id:
return eip, eips
for e in eips:
if instance_id and e.instance_id != instance_id and not module.params['allow_reassociation']:
continue
if ip_address and e.ip_address != ip_address:
continue
if allocation_id and e.allocation_id != allocation_id:
continue
eip = e
return eip, eips
except Exception as e:
module.fail_json(msg="Failed to describe EIPs: {0}".format(e))
def unassociate_eip(eip, module, instance_id):
try:
if eip.get().unassociate(instance_id=instance_id):
return True
except Exception as e:
module.fail_json(msg="Disassociate EIP with instance {0} failed. Error: {1}".format(instance_id, e))
return False
def main():
argument_spec = ecs_argument_spec()
argument_spec.update(
dict(
state=dict(type='str', default='present', choices=['present', 'absent']),
ip_address=dict(type='str', aliases=['ip']),
instance_id=dict(type='str', aliases=['device_id']),
allocation_id=dict(type='str', aliases=['id']),
internet_charge_type=dict(type='str', default='PayByTraffic', choices=['PayByTraffic', 'PayByBandwidth']),
bandwidth=dict(type='int', default=5),
reuse_existing_ip_allowed=dict(type='bool', default=False),
release_on_disassociation=dict(type='bool', default=False),
allow_reassociation=dict(type='bool', default=False),
name=dict(type='str'),
description=dict(type='str'),
tags=dict(type='dict'),
purge_tags=dict(type='bool', default=False)
)
)
module = AnsibleModule(argument_spec=argument_spec)
if not HAS_FOOTMARK:
module.fail_json(msg='footmark is required for the module ali_eip.')
vpc = vpc_connect(module)
# set values
state = module.params['state']
instance_id = module.params['instance_id']
ip_address = module.params['ip_address']
allocation_id = module.params['allocation_id']
eip, eips = find_eip(vpc, module, ip_address, instance_id, allocation_id)
changed = False
if state == 'absent':
if not eip:
module.exit_json(changed=changed, eip={})
if ip_address and instance_id and eip.ip_address != ip_address:
module.exit_json(changed=changed, eip=eip.get.read())
release = module.params['release_on_disassociation']
if instance_id:
try:
if unassociate_eip(eip, module, instance_id):
changed = True
if not release:
module.exit_json(changed=changed, eip=eip.get().read())
except Exception as e:
module.fail_json(msg="Disassociate EIP with instance {0} failed. Error: {1}".format(instance_id, e))
else:
release = True
if release:
try:
changed = eip.release()
module.exit_json(changed=changed, eip={})
except Exception as e:
module.fail_json(msg="{0}".format(e))
# state == present
if not eip:
if module.params['reuse_existing_ip_allowed'] and len(eips) > 0:
for e in eips:
if str(e.status).lower() == "available":
eip = e
break
if not eip:
try:
params = module.params
params['instance_id'] = None
params['client_token'] = "Ansible-Alicloud-%s-%s" % (hash(str(module.params)), str(time.time()))
eip = vpc.allocate_eip_address(**params)
changed = True
except VPCResponseError as e:
module.fail_json(msg='Unable to allocate an eip address, error: {0}'.format(e))
# Modify EIP attribute
name = module.params['name']
description = module.params['description']
bandwidth = module.params['bandwidth']
if not name:
name = eip.name
if not description:
description = eip.description
if not bandwidth:
bandwidth = eip.bandwidth
try:
if eip.modify(bandwidth, name, description):
changed = True
except VPCResponseError as e:
module.fail_json(msg='Modify EIP attribute with an error {0}.'.format(e))
# Associate instance
if instance_id:
if eip.instance_id and eip.instance_id != instance_id:
if not module.params['allow_reassociation']:
module.fail_json(msg='Target EIP {0} has been associated. Please set allow_reassociation to ture to '
'associate the target instance {1}'. format(eip.ip_address, instance_id))
try:
if unassociate_eip(eip, module, instance_id):
changed = True
except Exception as e:
module.fail_json(msg="Unassociate EIP from instance {0} failed. Error: {1}".format(instance_id, e))
try:
if eip.get().associate(instance_id=instance_id):
changed = True
except Exception as e:
module.fail_json(msg="Associate EIP with instance {0} failed. Error: {1}".format(instance_id, e))
tags = module.params['tags']
if module.params['purge_tags']:
if not tags:
tags = eip.tags
try:
if eip.remove_tags(tags):
changed = True
module.exit_json(changed=changed, eip=eip.get().read())
except Exception as e:
module.fail_json(msg="{0}".format(e))
if tags:
try:
if eip.add_tags(tags):
changed = True
except Exception as e:
module.fail_json(msg="{0}".format(e))
module.exit_json(changed=changed, eip=eip.get().read())
if __name__ == "__main__":
main()