#!/usr/bin/python # Copyright (c) Ansible Project # GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) # SPDX-License-Identifier: GPL-3.0-or-later from __future__ import annotations DOCUMENTATION = r""" module: oneandone_public_ip short_description: Configure 1&1 public IPs description: - Create, update, and remove public IPs. This module has a dependency on 1and1 >= 1.0. deprecated: removed_in: 13.0.0 why: DNS fails to resolve the API endpoint used by the module. alternative: There is none. extends_documentation_fragment: - community.general.attributes attributes: check_mode: support: full diff_mode: support: none options: state: description: - Define a public IP state to create, remove, or update. type: str default: 'present' choices: ["present", "absent", "update"] auth_token: description: - Authenticating API token provided by 1&1. type: str api_url: description: - Custom API URL. Overrides the E(ONEANDONE_API_URL) environment variable. type: str reverse_dns: description: - Reverse DNS name. maxLength=256. type: str datacenter: description: - ID of the datacenter where the IP is created (only for unassigned IPs). type: str choices: [US, ES, DE, GB] default: US type: description: - Type of IP. Currently, only IPV4 is available. type: str choices: ["IPV4", "IPV6"] default: 'IPV4' public_ip_id: description: - The ID of the public IP used with update and delete states. type: str wait: description: - Wait for the instance to be in state 'running' before returning. default: true type: bool wait_timeout: description: - How long before wait gives up, in seconds. type: int default: 600 wait_interval: description: - Defines the number of seconds to wait when using the _wait_for methods. type: int default: 5 requirements: - "1and1" author: - Amel Ajdinovic (@aajdinov) - Ethan Devenport (@edevenport) """ EXAMPLES = r""" - name: Create a public IP community.general.oneandone_public_ip: auth_token: oneandone_private_api_key reverse_dns: example.com datacenter: US type: IPV4 - name: Update a public IP community.general.oneandone_public_ip: auth_token: oneandone_private_api_key public_ip_id: public ip id reverse_dns: secondexample.com state: update - name: Delete a public IP community.general.oneandone_public_ip: auth_token: oneandone_private_api_key public_ip_id: public ip id state: absent """ RETURN = r""" public_ip: description: Information about the public IP that was processed. type: dict sample: {"id": "F77CC589EBC120905B4F4719217BFF6D", "ip": "10.5.132.106"} returned: always """ import os from ansible.module_utils.basic import AnsibleModule from ansible_collections.community.general.plugins.module_utils.oneandone import ( get_datacenter, get_public_ip, OneAndOneResources, wait_for_resource_creation_completion, ) HAS_ONEANDONE_SDK = True try: import oneandone.client except ImportError: HAS_ONEANDONE_SDK = False DATACENTERS = ["US", "ES", "DE", "GB"] TYPES = ["IPV4", "IPV6"] def _check_mode(module, result): if module.check_mode: module.exit_json(changed=result) def create_public_ip(module, oneandone_conn): """ Create new public IP module : AnsibleModule object oneandone_conn: authenticated oneandone object Returns a dictionary containing a 'changed' attribute indicating whether any public IP was added. """ reverse_dns = module.params.get("reverse_dns") datacenter = module.params.get("datacenter") ip_type = module.params.get("type") wait = module.params.get("wait") wait_timeout = module.params.get("wait_timeout") wait_interval = module.params.get("wait_interval") if datacenter is not None: datacenter_id = get_datacenter(oneandone_conn, datacenter) if datacenter_id is None: _check_mode(module, False) module.fail_json(msg=f"datacenter {datacenter} not found.") try: _check_mode(module, True) public_ip = oneandone_conn.create_public_ip( reverse_dns=reverse_dns, ip_type=ip_type, datacenter_id=datacenter_id ) if wait: wait_for_resource_creation_completion( oneandone_conn, OneAndOneResources.public_ip, public_ip["id"], wait_timeout, wait_interval ) public_ip = oneandone_conn.get_public_ip(public_ip["id"]) changed = True if public_ip else False return (changed, public_ip) except Exception as e: module.fail_json(msg=str(e)) def update_public_ip(module, oneandone_conn): """ Update a public IP module : AnsibleModule object oneandone_conn: authenticated oneandone object Returns a dictionary containing a 'changed' attribute indicating whether any public IP was changed. """ reverse_dns = module.params.get("reverse_dns") public_ip_id = module.params.get("public_ip_id") wait = module.params.get("wait") wait_timeout = module.params.get("wait_timeout") wait_interval = module.params.get("wait_interval") public_ip = get_public_ip(oneandone_conn, public_ip_id, True) if public_ip is None: _check_mode(module, False) module.fail_json(msg=f"public IP {public_ip_id} not found.") try: _check_mode(module, True) public_ip = oneandone_conn.modify_public_ip(ip_id=public_ip["id"], reverse_dns=reverse_dns) if wait: wait_for_resource_creation_completion( oneandone_conn, OneAndOneResources.public_ip, public_ip["id"], wait_timeout, wait_interval ) public_ip = oneandone_conn.get_public_ip(public_ip["id"]) changed = True if public_ip else False return (changed, public_ip) except Exception as e: module.fail_json(msg=str(e)) def delete_public_ip(module, oneandone_conn): """ Delete a public IP module : AnsibleModule object oneandone_conn: authenticated oneandone object Returns a dictionary containing a 'changed' attribute indicating whether any public IP was deleted. """ public_ip_id = module.params.get("public_ip_id") public_ip = get_public_ip(oneandone_conn, public_ip_id, True) if public_ip is None: _check_mode(module, False) module.fail_json(msg=f"public IP {public_ip_id} not found.") try: _check_mode(module, True) deleted_public_ip = oneandone_conn.delete_public_ip(ip_id=public_ip["id"]) changed = True if deleted_public_ip else False return (changed, {"id": public_ip["id"]}) except Exception as e: module.fail_json(msg=str(e)) def main(): module = AnsibleModule( argument_spec=dict( auth_token=dict(type="str", no_log=True, default=os.environ.get("ONEANDONE_AUTH_TOKEN")), api_url=dict(type="str", default=os.environ.get("ONEANDONE_API_URL")), public_ip_id=dict(type="str"), reverse_dns=dict(type="str"), datacenter=dict(choices=DATACENTERS, default="US"), type=dict(choices=TYPES, default="IPV4"), wait=dict(type="bool", default=True), wait_timeout=dict(type="int", default=600), wait_interval=dict(type="int", default=5), state=dict(type="str", default="present", choices=["present", "absent", "update"]), ), supports_check_mode=True, ) if not HAS_ONEANDONE_SDK: module.fail_json(msg="1and1 required for this module") if not module.params.get("auth_token"): module.fail_json(msg="auth_token parameter is required.") if not module.params.get("api_url"): oneandone_conn = oneandone.client.OneAndOneService(api_token=module.params.get("auth_token")) else: oneandone_conn = oneandone.client.OneAndOneService( api_token=module.params.get("auth_token"), api_url=module.params.get("api_url") ) state = module.params.get("state") if state == "absent": if not module.params.get("public_ip_id"): module.fail_json(msg="'public_ip_id' parameter is required to delete a public ip.") try: (changed, public_ip) = delete_public_ip(module, oneandone_conn) except Exception as e: module.fail_json(msg=str(e)) elif state == "update": if not module.params.get("public_ip_id"): module.fail_json(msg="'public_ip_id' parameter is required to update a public ip.") try: (changed, public_ip) = update_public_ip(module, oneandone_conn) except Exception as e: module.fail_json(msg=str(e)) elif state == "present": try: (changed, public_ip) = create_public_ip(module, oneandone_conn) except Exception as e: module.fail_json(msg=str(e)) module.exit_json(changed=changed, public_ip=public_ip) if __name__ == "__main__": main()