lib/ansible/modules/cloud/alicloud/ali_rds_instance.py (576 lines of code) (raw):

#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright (c) 2017-present Alibaba Group Holding Limited. He Guimin <heguimin36@163.com.com> # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) # # This file is part of Ansible # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see http://www.gnu.org/licenses/. from __future__ import (absolute_import, division, print_function) __metaclass__ = type ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'} DOCUMENTATION = ''' --- module: ali_rds_instance short_description: Create, Restart or Delete an RDS Instance in Alibaba Cloud. description: - Create, Restart, Delete and Modify connection_string, spec for RDS Instance. - An unique ali_rds_instance module is determined by parameters db_instance_name. options: state: description: - If I(state=present), instance will be created. - If I(state=present) and instance exists, it will be updated. - If I(state=absent), instance will be removed. - If I(state=restart), instance will be restarted. choices: ['present', 'restart', 'absent'] default: 'present' type: str zone_id: description: - Aliyun availability zone ID in which to launch the instance. If it is not specified, it will be allocated by system automatically. aliases: ['alicloud_zone'] type: str engine: description: - The engine type of the database. Required when C(state=present). choices: ['MySQL', 'SQLServer', 'PostgreSQL', 'PPAS', 'MariaDB'] type: str engine_version: description: - The version of the database. Required when C(state=present). - MySQL (5.5 | 5.6 | 5.7 | 8.0). - SQL Server (2008r2 | 2012 | 2012_ent_ha | 2012_std_ha | 2012_web | 2016_ent_ha | 2016_std_ha | 2016_web | 2017_ent). - PostgreSQL (9.4 | 10.0). - PPAS (9.3 | 10.0). - MariaDB (10.3). - see more (https://www.alibabacloud.com/help/doc-detail/26228.htm). type: str db_instance_class: description: - The instance type (specifications). For more information, see(https://www.alibabacloud.com/help/doc-detail/26312.htm). Required when C(state=present). aliases: ['instance_class'] type: str db_instance_storage: description: - The storage capacity of the instance. Unit(GB). This value must be a multiple of 5. For more information see(https://www.alibabacloud.com/help/doc-detail/26312.htm). Required when C(state=present). aliases: ['instance_storage'] type: int db_instance_net_type: description: - Instance of the network connection type (Internet on behalf of the public network, Intranet on behalf of the private network) Required when C(state=present). aliases: ['instance_net_type'] choices: ["Internet", "Intranet"] type: str db_instance_name: description: - The instance name. It starts with a letter and contains 2 to 255 characters, including letters, digits, underscores (_), and hyphens (-). It cannot start with http:// or https://. - One of I(db_instance_id) and I(db_instance_name) must be specified when operate existing instance. aliases: ['description', 'name'] type: str db_instance_id: description: - The instance id. - One of I(db_instance_id) and I(db_instance_name) must be specified when operate existing instance. aliases: ['id'] type: str security_ip_list: description: - The IP address whitelist of the instance. Separate multiple IP addresses with commas (,). It can include up to 1,000 IP addresses. The IP addresses support two formats. IP address format. For example, 10.23.12.24. Classless Inter-Domain Routing (CIDR) format. For example, 10.23.12.24/24 (where /24 indicates the number of bits for the prefix of the IP address, in the range of 1 to 32). Required when C(state=present). aliases: ['security_ips'] type: str pay_type: description: - The billing method of the instance. Required when C(state=present). choices: ["PostPaid", "PrePaid"] type: str period: description: - The duration of the instance. Required when C(pay_type=PrePaid). choices: [1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36] default: 1 type: int connection_mode: description: - The access mode of the instance. choices: ["Standard", "Safe"] type: str vswitch_id: description: - The ID of the VSwitch. Required when C(engine=MariaDB) type: str private_ip_address: description: - The intranet IP address of the instance. It must be within the IP address range provided by the switch. By default, the system automatically assigns an IP address based on the VPCId and VSwitchId. type: str auto_renew: description: - Indicates whether the instance is automatically renewed type: bool default: False aliases: ['auto_renew'] port: description: - The target port. type: str auto_pay: description: - Auto renew or not. type: bool default: False current_connection_string: description: - The current connection address of an instance. It can be an internal network address, a public network address, or a classic network address in the hybrid access mode. type: str connection_string_prefix: description: - The prefix of the target connection address. Only the prefix of CurrentConnectionString can be modified. type: str tags: description: - A hash/dictionaries of rds tags. C({"key":"value"}) type: dict purge_tags: description: - Delete existing tags on the rds that are not specified in the task. If True, it means you have to specify all the desired tags on each task affecting a rds. default: False type: bool author: - "He Guimin (@xiaozhu36)" - "Li Xue (@lixue323)" requirements: - "python >= 3.6" - "footmark >= 1.16.0" extends_documentation_fragment: - alicloud ''' EXAMPLES = ''' - name: Changed. Add Tags. ali_rds_instance: db_instance_description: '{{ name }}' tags: TAG: "add1" TAG2: "add2" - name: Changed. Removing tags. ali_rds_instance: db_instance_description: '{{ name }}' purge_tags: True tags: TAG: "add1" - name: Changed. allocate instance public connection string ali_rds_instance: db_instance_description: '{{ name }}' connection_string_prefix: publicave-89asd port: 3165 - name: release instance public connection string ali_rds_instance: state: absent db_instance_description: '{{ name }}' current_connection_string: publicave-89asd.mysql.rds.aliyuncs.com - name: restart rds instance ali_rds_instance: db_instance_description: '{{ name }}' state: restart - name: Changed. modify instance spec ali_rds_instance: db_instance_description: '{{ name }}' db_instance_class: rds.mysql.c2.xlarge db_instance_storage: 40 - name: Changed. modify instance current connection string ali_rds_instance: current_connection_string: '{{ rds.instances.0.id }}.mysql.rds.aliyuncs.com' db_instance_description: '{{ name }}' connection_string_prefix: private-ansible port: 3307 - name: Changed. Deleting rds ali_rds_instance: state: absent db_instance_description: '{{ name }}' ''' RETURN = ''' instances: description: Describe the info after operating rds instance. returned: always type: complex contains: db_instance_class: description: The type of the instance. returned: always type: str sample: rds.mysql.t1.small db_instance_description: description: The description of the instance. returned: always type: str sample: ansible_test_rds db_instance_id: description: The ID of the instance. returned: always type: str sample: rm-uf6wjk5xxxxxxxxxx db_instance_net_type: description: The network type of the instance. returned: always type: str sample: Internet db_instance_status: description: The status of the instance. returned: always type: str sample: Running db_instance_type: description: The type of the instance role. returned: always type: str sample: Primary engine: description: The type of the database. returned: always type: str sample: MySQL engine_version: description: The version of the database. returned: always type: str sample: 5.6 id: description: alias of 'db_instance_id'. returned: always type: str sample: rm-uf6wjk5xxxxxxxxxx type: description: alias of 'db_instance_type'. returned: always type: str sample: Primary instance_network_type: description: The network type of the instance. returned: always type: str sample: VPC name: description: alias of 'db_instance_description'. returned: always type: str sample: ansible_test_rds pay_type: description: The billing method of the instance. returned: always type: str sample: Postpaid resource_group_id: description: The ID of the resource group. returned: always type: str sample: rg-acfmyxxxxxxx status: description: alias of 'db_instance_status' returned: always type: str sample: Running vpc_cloud_instance_id: description: The ID of the VPC instance returned: always type: str sample: rm-uf6wjk5xxxxxxx vpc_id: description: The ID of the VPC. returned: always type: str sample: vpc-uf6f7l4fg90xxxxxxx vswitch_id: description: The ID of the VSwitch. returned: always type: str sample: vsw-uf6adz52c2pxxxxxxx lock_mode: description: The lock mode of the instance. returned: always type: str sample: Unlock connection_mode: description: The access mode of the instance. returned: always type: str sample: Standard account_max_quantity: description: The maximum number of accounts that can be created in an instance. returned: always type: int sample: 50 account_type: description: The type of the account. returned: always type: str sample: Mix auto_upgrade_minor_version: description: The method of upgrading an instance to a minor version. returned: always type: str sample: Auto availability_value: description: The availability of the instance. returned: always type: str sample: 100.0% category: description: The edition (series) of the instance. returned: always type: str sample: Basic connection_string: description: The private IP address of the instance. returned: always type: str sample: rm-uf6wjk5xxxxxxxxxx.mysql.rds.aliyuncs.com creation_time: description: The time when the instance is created returned: always type: str sample: '2011-05-30T12:11:04Z' current_kernel_version: description: The current kernel version. returned: always type: str sample: rds_20181010 db_instance_class_type: description: The instance type (specifications). returned: always type: str sample: rds.mys2.small db_instance_cpu: description: The count of the instance cpu. returned: always type: int sample: 2 db_instance_memory: description: The memory of the instance. returned: always type: int sample: 4096 db_instance_storage: description: The type of the instance. returned: always type: str sample: rds.mysql.t1.small db_instance_storage_type: description: The storage capacity of the instance. returned: always type: int sample: 10 db_max_quantity: description: The maximum number of databases that can be created in an instance. returned: always type: int sample: 200 dispense_mode: description: The allocation mode. returned: always type: str sample: ClassicDispenseMode expire_time: description: The expiration time. returned: always type: str sample: '2019-03-27T16:00:00Z' maintain_time: description: The maintenance period of the instance. returned: always type: str sample: '00:00Z-02:00Z' max_connections: description: The maximum number of concurrent connections. returned: always type: int sample: 60 max_iops: description: The maximum number of I/O requests per second. returned: always type: int sample: 60 origin_configuration: description: The type of the instance. returned: always type: str sample: rds.mysql.t1.small port: description: The private port of the instance. returned: always type: str sample: 3306 read_only_dbinstance_ids: description: The IDs of read-only instances attached to the master instance. returned: always type: complex contains: read_only_dbinstance_id: description: The ID of a read-only instance. returned: always type: list sample: ['rr-bpxxxxxxxxx'] security_ipmode: description: The IP whitelist mode. returned: always type: complex sample: normal ''' import time from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.alicloud_ecs import ecs_argument_spec, rds_connect, vpc_connect HAS_FOOTMARK = False try: from footmark.exception import ECSResponseError HAS_FOOTMARK = True except ImportError: HAS_FOOTMARK = False def get_instance(db_instance_id, name, modules, rds): try: instances = rds.describe_db_instances() res = None for ins in instances: if name and ins.name != name: continue if db_instance_id and ins.id != db_instance_id: continue res = ins return res except Exception as e: modules.fail_json(msg="Failed to describe rds: {0}".format(e)) def main(): argument_spec = ecs_argument_spec() argument_spec.update(dict( state=dict(default="present", choices=["present", "absent", "restart"]), zone_id=dict(type='str', aliases=['alicloud_zone']), engine=dict(type='str', choices=['MySQL', 'SQLServer', 'PostgreSQL', 'PPAS', 'MariaDB']), engine_version=dict(type='str'), db_instance_net_type=dict(type='str', choices=["Internet", "Intranet"], aliases=['instance_net_type']), db_instance_name=dict(type='str', aliases=['description', 'name']), db_instance_id=dict(type='str', aliases=['id']), security_ip_list=dict(type='str', aliases=['security_ips']), pay_type=dict(type='str', choices=["PostPaid", "PrePaid"]), period=dict(type='int', choices=[1, 2, 3, 4, 5, 6, 7, 8, 9, 12, 24, 36], default=1), connection_mode=dict(type='str', choices=["Standard", "Safe"]), vswitch_id=dict(type='str'), private_ip_address=dict(type='str'), tags=dict(type='dict'), purge_tags=dict(type='bool', default=False), auto_pay=dict(type='bool', aliases=['auto_renew']), connection_string_prefix=dict(type='str'), port=dict(type='str'), current_connection_string=dict(type='str'), db_instance_class=dict(type='str', aliases=['instance_class']), db_instance_storage=dict(type='int', aliases=['instance_storage']) )) modules = AnsibleModule(argument_spec=argument_spec) if HAS_FOOTMARK is False: modules.fail_json(msg="Package 'footmark' required for the module ali_rds_instance.") rds = rds_connect(modules) vpc = vpc_connect(modules) state = modules.params['state'] vswitch_id = modules.params['vswitch_id'] connection_string_prefix = modules.params['connection_string_prefix'] port = modules.params['port'] tags = modules.params['tags'] current_connection_string = modules.params['current_connection_string'] db_instance_description = modules.params['db_instance_name'] modules.params['db_instance_description'] = db_instance_description db_instance_class = modules.params['db_instance_class'] db_instance_storage = modules.params['db_instance_storage'] db_instance_id = modules.params['db_instance_id'] pay_type = modules.params['pay_type'] used_time = modules.params['period'] modules.params['period'] = 'Month' modules.params['used_time'] = str(used_time) if used_time > 9: modules.params['period'] = 'Year' if used_time == 12: modules.params['used_time'] = '1' elif used_time == 24: modules.params['used_time'] = '2' else: modules.params['used_time'] = '3' if pay_type: modules.params['pay_type'] = pay_type.capitalize() current_instance = None changed = False if vswitch_id: modules.params['instance_network_type'] = 'VPC' try: vswitch_obj = vpc.describe_vswitch_attributes(vswitch_id=vswitch_id) if vswitch_obj: modules.params['vpc_id'] = vswitch_obj.vpc_id except Exception as e: modules.fail_json(msg=str("Unable to get vswitch, error:{0}".format(e))) try: current_instance = get_instance(db_instance_id, db_instance_description, modules, rds) except Exception as e: modules.fail_json(msg=str("Unable to describe instance, error:{0}".format(e))) if state == 'absent': if current_instance: if current_connection_string: try: changed = rds.release_instance_public_connection(current_connection_string=current_connection_string, db_instance_id=current_instance.id) modules.exit_json(changed=changed, instances=current_instance.get().read()) except Exception as e: modules.fail_json(msg=str("Unable to release public connection string error: {0}".format(e))) try: current_instance.delete() modules.exit_json(changed=True, instances={}) except Exception as e: modules.fail_json(msg=str("Unable to release instance error: {0}".format(e))) modules.fail_json(msg=str("Unable to operate your instance, please check your instance_id and try again!")) if state == 'restart': if current_instance: try: changed = current_instance.restart() modules.exit_json(changed=changed, instances=current_instance.get().read()) except Exception as e: modules.fail_json(msg=str("Unable to restart instance error: {0}".format(e))) modules.fail_json(msg=str("Unable to restart your instance, please check your instance_id and try again!")) if not current_instance: try: modules.params['client_token'] = "Ansible-Alicloud-%s-%s" % (hash(str(modules.params)), str(time.time())) current_instance = rds.create_db_instance(**modules.params) modules.exit_json(changed=True, instances=current_instance.get().read()) except Exception as e: modules.fail_json(msg=str("Unable to create rds instance error: {0}".format(e))) if connection_string_prefix and port: if current_connection_string: try: changed = current_instance.modify_db_instance_connection_string(current_connection_string=current_connection_string, connection_string_prefix=connection_string_prefix, port=port) modules.exit_json(changed=changed, instances=current_instance.get().read()) except Exception as e: modules.fail_json(msg=str("Unable to modify current string error: {0}".format(e))) else: try: changed = current_instance.allocate_public_connection_string(connection_string_prefix=connection_string_prefix, port=port) modules.exit_json(changed=changed, instances=current_instance.get().read()) except Exception as e: modules.fail_json(msg=str("Unable to allocate public connection error: {0}".format(e))) if db_instance_class or db_instance_storage: try: changed = current_instance.modify_instance_spec(db_instance_class=db_instance_class, db_instance_storage=db_instance_storage) except Exception as e: modules.fail_json(msg=str("Unable to modify instance spec: {0}".format(e))) if modules.params['purge_tags']: if not tags: tags = current_instance.tags try: if current_instance.remove_tags(tags): changed = True modules.exit_json(changed=changed, instances=current_instance.get().read()) except Exception as e: modules.fail_json(msg="{0}".format(e)) if tags: try: if current_instance.add_tags(tags): changed = True except Exception as e: modules.fail_json(msg="{0}".format(e)) modules.exit_json(changed=changed, instances=current_instance.get().read()) if __name__ == '__main__': main()