1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Add param for doc/fragments/alicloud (#108)

This commit is contained in:
lx 2020-04-13 14:23:38 +08:00 committed by GitHub
parent 6d7f66539c
commit 4ebb65e6f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 791 additions and 378 deletions

View file

@ -0,0 +1,6 @@
changes:
- "alicloud modules - now only support Python 3.6, not support Python 2.x"
- "ali_instance and ali_instance_info - the required package footmark needs a version higher than 1.19.0"
- "ali_instance - Add params ``unique_suffix``, ``tags``, ``purge_tags``, ``ram_role_name``, ``spot_price_limit``, ``spot_strategy``, ``period_unit``, ``dry_run``, ``include_data_disks``"
- "ali_instance_info - Add params ``name_prefix``, ``filters``"
- "alicloud modules - Add authentication params to all modules"

View file

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2017 Alibaba Group Holding Limited. He Guimin <heguimin36@163.com>
# Copyright (c) 2017-present Alibaba Group Holding Limited. He Guimin <heguimin36@163.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
@ -11,46 +11,95 @@ class ModuleDocFragment(object):
options:
alicloud_access_key:
description:
- Aliyun Cloud access key.
- If not set then the value of environment variable C(ALICLOUD_ACCESS_KEY),
C(ALICLOUD_ACCESS_KEY_ID) will be used instead.
- Alibaba Cloud access key. If not set then the value of environment variable C(ALICLOUD_ACCESS_KEY),
C(ALICLOUD_ACCESS_KEY_ID) will be used instead.
aliases: ['access_key_id', 'access_key']
type: str
aliases: [ access_key_id, access_key ]
alicloud_secret_key:
description:
- Aliyun Cloud secret key.
- If not set then the value of environment variable C(ALICLOUD_SECRET_KEY),
C(ALICLOUD_SECRET_ACCESS_KEY) will be used instead.
- Alibaba Cloud secret key. If not set then the value of environment variable C(ALICLOUD_SECRET_KEY),
C(ALICLOUD_SECRET_ACCESS_KEY) will be used instead.
aliases: ['secret_access_key', 'secret_key']
type: str
aliases: [ secret_access_key, secret_key ]
alicloud_region:
description:
- The Aliyun Cloud region to use.
- If not specified then the value of environment variable
C(ALICLOUD_REGION), C(ALICLOUD_REGION_ID) will be used instead.
- The Alibaba Cloud region to use. If not specified then the value of environment variable
C(ALICLOUD_REGION), C(ALICLOUD_REGION_ID) will be used instead.
aliases: ['region', 'region_id']
required: true
type: str
aliases: [ region, region_id ]
alicloud_security_token:
description:
- The Aliyun Cloud security token.
- If not specified then the value of environment variable
C(ALICLOUD_SECURITY_TOKEN) will be used instead.
- The Alibaba Cloud security token. If not specified then the value of environment variable
C(ALICLOUD_SECURITY_TOKEN) will be used instead.
aliases: ['security_token']
type: str
alicloud_assume_role:
description:
- If provided with a role ARN, Ansible will attempt to assume this role using the supplied credentials.
- The nested assume_role block supports I(alicloud_assume_role_arn), I(alicloud_assume_role_session_name),
I(alicloud_assume_role_session_expiration) and I(alicloud_assume_role_policy)
type: dict
aliases: ['assume_role']
alicloud_assume_role_arn:
description:
- The Alibaba Cloud role_arn. The ARN of the role to assume. If ARN is set to an empty string,
it does not perform role switching. It supports environment variable ALICLOUD_ASSUME_ROLE_ARN.
ansible will execute with provided credentials.
aliases: ['assume_role_arn']
type: str
alicloud_assume_role_session_name:
description:
- The Alibaba Cloud session_name. The session name to use when assuming the role. If omitted,
'ansible' is passed to the AssumeRole call as session name. It supports environment variable
ALICLOUD_ASSUME_ROLE_SESSION_NAME
aliases: ['assume_role_session_name']
type: str
alicloud_assume_role_session_expiration:
description:
- The Alibaba Cloud session_expiration. The time after which the established session for assuming
role expires. Valid value range 900-3600 seconds. Default to 3600 (in this case Alicloud use own default
value). It supports environment variable ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION
aliases: ['assume_role_session_expiration']
type: int
ecs_role_name:
description:
- The RAM Role Name attached on a ECS instance for API operations. You can retrieve this from the 'Access Control'
section of the Alibaba Cloud console.
- If you're running Ansible from an ECS instance with RAM Instance using RAM Role, Ansible will just access the
metadata U(http://100.100.100.200/latest/meta-data/ram/security-credentials/<ecs_role_name>) to obtain the STS
credential. This is a preferred approach over any other when running in ECS as you can avoid hard coding
credentials. Instead these are leased on-the-fly by Ansible which reduces the chance of leakage.
aliases: ['role_name']
type: str
profile:
description:
- This is the Alicloud profile name as set in the shared credentials file. It can also be sourced from the
ALICLOUD_PROFILE environment variable.
type: str
shared_credentials_file:
description:
- This is the path to the shared credentials file. It can also be sourced from the ALICLOUD_SHARED_CREDENTIALS_FILE
environment variable.
- If this is not set and a profile is specified, ~/.aliyun/config.json will be used.
type: str
aliases: [ security_token ]
author:
- He Guimin (@xiaozhu36)
- "He Guimin (@xiaozhu36)"
requirements:
- python >= 2.6
extends_documentation_fragment:
- community.general.alicloud
- "python >= 3.6"
notes:
- If parameters are not set within the module, the following
environment variables can be used in decreasing order of precedence
C(ALICLOUD_ACCESS_KEY) or C(ALICLOUD_ACCESS_KEY_ID),
C(ALICLOUD_SECRET_KEY) or C(ALICLOUD_SECRET_ACCESS_KEY),
C(ALICLOUD_REGION) or C(ALICLOUD_REGION_ID),
C(ALICLOUD_SECURITY_TOKEN)
C(ALICLOUD_SECURITY_TOKEN),
C(ALICLOUD_ECS_ROLE_NAME),
C(ALICLOUD_SHARED_CREDENTIALS_FILE),
C(ALICLOUD_PROFILE),
C(ALICLOUD_ASSUME_ROLE_ARN),
C(ALICLOUD_ASSUME_ROLE_SESSION_NAME),
C(ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION),
- C(ALICLOUD_REGION) or C(ALICLOUD_REGION_ID) can be typically be used to specify the
ALICLOUD region, when required, but this can also be configured in the footmark config file
'''

View file

@ -4,7 +4,7 @@
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# Copyright (c) 2017 Alibaba Group Holding Limited. He Guimin <heguimin36@163.com>
# Copyright (c) 2017-present Alibaba Group Holding Limited. He Guimin <heguimin36@163.com>
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
@ -26,6 +26,8 @@
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
import os
import json
from ansible.module_utils.basic import env_fallback
try:
@ -35,6 +37,10 @@ try:
import footmark.vpc
import footmark.rds
import footmark.ess
import footmark.sts
import footmark.dns
import footmark.ram
import footmark.market
HAS_FOOTMARK = True
except ImportError:
HAS_FOOTMARK = False
@ -46,12 +52,13 @@ class AnsibleACSError(Exception):
def acs_common_argument_spec():
return dict(
alicloud_access_key=dict(required=True, aliases=['access_key_id', 'access_key'], no_log=True,
alicloud_access_key=dict(aliases=['access_key_id', 'access_key'], no_log=True,
fallback=(env_fallback, ['ALICLOUD_ACCESS_KEY', 'ALICLOUD_ACCESS_KEY_ID'])),
alicloud_secret_key=dict(required=True, aliases=['secret_access_key', 'secret_key'], no_log=True,
alicloud_secret_key=dict(aliases=['secret_access_key', 'secret_key'], no_log=True,
fallback=(env_fallback, ['ALICLOUD_SECRET_KEY', 'ALICLOUD_SECRET_ACCESS_KEY'])),
alicloud_security_token=dict(aliases=['security_token'], no_log=True,
fallback=(env_fallback, ['ALICLOUD_SECURITY_TOKEN'])),
ecs_role_name=dict(aliases=['role_name'], fallback=(env_fallback, ['ALICLOUD_ECS_ROLE_NAME']))
)
@ -61,19 +68,30 @@ def ecs_argument_spec():
dict(
alicloud_region=dict(required=True, aliases=['region', 'region_id'],
fallback=(env_fallback, ['ALICLOUD_REGION', 'ALICLOUD_REGION_ID'])),
alicloud_assume_role_arn=dict(fallback=(env_fallback, ['ALICLOUD_ASSUME_ROLE_ARN']),
aliases=['assume_role_arn']),
alicloud_assume_role_session_name=dict(fallback=(env_fallback, ['ALICLOUD_ASSUME_ROLE_SESSION_NAME']),
aliases=['assume_role_session_name']),
alicloud_assume_role_session_expiration=dict(type='int',
fallback=(env_fallback,
['ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION']),
aliases=['assume_role_session_expiration']),
alicloud_assume_role=dict(type='dict', aliases=['assume_role']),
profile=dict(fallback=(env_fallback, ['ALICLOUD_PROFILE'])),
shared_credentials_file=dict(fallback=(env_fallback, ['ALICLOUD_SHARED_CREDENTIALS_FILE']))
)
)
return spec
def get_acs_connection_info(module):
def get_acs_connection_info(params):
ecs_params = dict(acs_access_key_id=module.params.get('alicloud_access_key'),
acs_secret_access_key=module.params.get('alicloud_secret_key'),
security_token=module.params.get('alicloud_security_token'),
ecs_params = dict(acs_access_key_id=params.get('alicloud_access_key'),
acs_secret_access_key=params.get('alicloud_secret_key'),
security_token=params.get('alicloud_security_token'),
ecs_role_name=params.get('ecs_role_name'),
user_agent='Ansible-Provider-Alicloud')
return module.params.get('alicloud_region'), ecs_params
return ecs_params
def connect_to_acs(acs_module, region, **params):
@ -88,11 +106,80 @@ def connect_to_acs(acs_module, region, **params):
return conn
def get_assume_role(params):
""" Return new params """
sts_params = get_acs_connection_info(params)
assume_role = {}
if params.get('assume_role'):
assume_role['alicloud_assume_role_arn'] = params['assume_role'].get('role_arn')
assume_role['alicloud_assume_role_session_name'] = params['assume_role'].get('session_name')
assume_role['alicloud_assume_role_session_expiration'] = params['assume_role'].get('session_expiration')
assume_role['alicloud_assume_role_policy'] = params['assume_role'].get('policy')
assume_role_params = {
'role_arn': params.get('alicloud_assume_role_arn') if params.get('alicloud_assume_role_arn') else assume_role.get('alicloud_assume_role_arn'),
'role_session_name': params.get('alicloud_assume_role_session_name') if params.get('alicloud_assume_role_session_name')
else assume_role.get('alicloud_assume_role_session_name'),
'duration_seconds': params.get('alicloud_assume_role_session_expiration') if params.get('alicloud_assume_role_session_expiration')
else assume_role.get('alicloud_assume_role_session_expiration', 3600),
'policy': assume_role.get('alicloud_assume_role_policy', {})
}
try:
sts = connect_to_acs(footmark.sts, params.get('alicloud_region'), **sts_params).assume_role(**assume_role_params).read()
sts_params['acs_access_key_id'], sts_params['acs_secret_access_key'], sts_params['security_token'] \
= sts['access_key_id'], sts['access_key_secret'], sts['security_token']
except AnsibleACSError as e:
params.fail_json(msg=str(e))
return sts_params
def get_profile(params):
if not params['alicloud_access_key'] and not params['ecs_role_name'] and params['profile']:
path = params['shared_credentials_file'] if params['shared_credentials_file'] else os.getenv('HOME') + '/.aliyun/config.json'
auth = {}
with open(path, 'r') as f:
for pro in json.load(f)['profiles']:
if params['profile'] == pro['name']:
auth = pro
if auth:
if auth['mode'] == 'AK' and auth.get('access_key_id') and auth.get('access_key_secret'):
params['alicloud_access_key'] = auth.get('access_key_id')
params['alicloud_secret_key'] = auth.get('access_key_secret')
params['alicloud_region'] = auth.get('region_id')
params = get_acs_connection_info(params)
elif auth['mode'] == 'StsToken' and auth.get('access_key_id') and auth.get('access_key_secret') and auth.get('sts_token'):
params['alicloud_access_key'] = auth.get('access_key_id')
params['alicloud_secret_key'] = auth.get('access_key_secret')
params['security_token'] = auth.get('sts_token')
params['alicloud_region'] = auth.get('region_id')
params = get_acs_connection_info(params)
elif auth['mode'] == 'EcsRamRole':
params['ecs_role_name'] = auth.get('ram_role_name')
params['alicloud_region'] = auth.get('region_id')
params = get_acs_connection_info(params)
elif auth['mode'] == 'RamRoleArn' and auth.get('ram_role_arn'):
params['alicloud_access_key'] = auth.get('access_key_id')
params['alicloud_secret_key'] = auth.get('access_key_secret')
params['security_token'] = auth.get('sts_token')
params['ecs_role_name'] = auth.get('ram_role_name')
params['alicloud_assume_role_arn'] = auth.get('ram_role_arn')
params['alicloud_assume_role_session_name'] = auth.get('ram_session_name')
params['alicloud_assume_role_session_expiration'] = auth.get('expired_seconds')
params['alicloud_region'] = auth.get('region_id')
params = get_assume_role(params)
elif params.get('alicloud_assume_role_arn') or params.get('assume_role'):
params = get_assume_role(params)
else:
params = get_acs_connection_info(params)
return params
def ecs_connect(module):
""" Return an ecs connection"""
region, ecs_params = get_acs_connection_info(module)
ecs_params = get_profile(module.params)
# If we have a region specified, connect to its endpoint.
region = module.params.get('alicloud_region')
if region:
try:
ecs = connect_to_acs(footmark.ecs, region, **ecs_params)
@ -104,9 +191,9 @@ def ecs_connect(module):
def slb_connect(module):
""" Return an slb connection"""
region, slb_params = get_acs_connection_info(module)
slb_params = get_profile(module.params)
# If we have a region specified, connect to its endpoint.
region = module.params.get('alicloud_region')
if region:
try:
slb = connect_to_acs(footmark.slb, region, **slb_params)
@ -116,11 +203,25 @@ def slb_connect(module):
return slb
def dns_connect(module):
""" Return an dns connection"""
dns_params = get_profile(module.params)
# If we have a region specified, connect to its endpoint.
region = module.params.get('alicloud_region')
if region:
try:
dns = connect_to_acs(footmark.dns, region, **dns_params)
except AnsibleACSError as e:
module.fail_json(msg=str(e))
# Otherwise, no region so we fallback to the old connection method
return dns
def vpc_connect(module):
""" Return an vpc connection"""
region, vpc_params = get_acs_connection_info(module)
vpc_params = get_profile(module.params)
# If we have a region specified, connect to its endpoint.
region = module.params.get('alicloud_region')
if region:
try:
vpc = connect_to_acs(footmark.vpc, region, **vpc_params)
@ -132,9 +233,9 @@ def vpc_connect(module):
def rds_connect(module):
""" Return an rds connection"""
region, rds_params = get_acs_connection_info(module)
rds_params = get_profile(module.params)
# If we have a region specified, connect to its endpoint.
region = module.params.get('alicloud_region')
if region:
try:
rds = connect_to_acs(footmark.rds, region, **rds_params)
@ -146,9 +247,9 @@ def rds_connect(module):
def ess_connect(module):
""" Return an ess connection"""
region, ess_params = get_acs_connection_info(module)
ess_params = get_profile(module.params)
# If we have a region specified, connect to its endpoint.
region = module.params.get('alicloud_region')
if region:
try:
ess = connect_to_acs(footmark.ess, region, **ess_params)
@ -156,3 +257,45 @@ def ess_connect(module):
module.fail_json(msg=str(e))
# Otherwise, no region so we fallback to the old connection method
return ess
def sts_connect(module):
""" Return an sts connection"""
sts_params = get_profile(module.params)
# If we have a region specified, connect to its endpoint.
region = module.params.get('alicloud_region')
if region:
try:
sts = connect_to_acs(footmark.sts, region, **sts_params)
except AnsibleACSError as e:
module.fail_json(msg=str(e))
# Otherwise, no region so we fallback to the old connection method
return sts
def ram_connect(module):
""" Return an ram connection"""
ram_params = get_profile(module.params)
# If we have a region specified, connect to its endpoint.
region = module.params.get('alicloud_region')
if region:
try:
ram = connect_to_acs(footmark.ram, region, **ram_params)
except AnsibleACSError as e:
module.fail_json(msg=str(e))
# Otherwise, no region so we fallback to the old connection method
return ram
def market_connect(module):
""" Return an market connection"""
market_params = get_profile(module.params)
# If we have a region specified, connect to its endpoint.
region = module.params.get('alicloud_region')
if region:
try:
market = connect_to_acs(footmark.market, region, **market_params)
except AnsibleACSError as e:
module.fail_json(msg=str(e))
# Otherwise, no region so we fallback to the old connection method
return market

View file

@ -1,5 +1,7 @@
#!/usr/bin/python
# Copyright (c) 2017 Alibaba Group Holding Limited. He Guimin <heguimin36@163.com>
# -*- coding: utf-8 -*-
# Copyright (c) 2017-present Alibaba Group Holding Limited. He Guimin <heguimin36@163.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
@ -17,196 +19,236 @@
# 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
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
DOCUMENTATION = '''
---
module: ali_instance
short_description: Create, start, stop, restart or terminate an instance in ECS, add or remove an instance to/from a security group
short_description: Create, Start, Stop, Restart or Terminate an Instance in ECS. Add or Remove Instance to/from a Security Group.
description:
- Create, start, stop, restart, modify or terminate ecs instances.
- Add or remove ecs instances to/from security group.
- Create, start, stop, restart, modify or terminate ecs instances.
- Add or remove ecs instances to/from security group.
options:
state:
state:
description:
- The state of the instance after operating.
default: 'present'
choices: ['present', 'running', 'stopped', 'restarted', 'absent']
type: str
availability_zone:
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', 'zone_id']
type: str
image_id:
description:
- Image ID used to launch instances. Required when C(state=present) and creating new ECS instances.
aliases: ['image']
type: str
instance_type:
description:
- Instance type used to launch instances. Required when C(state=present) and creating new ECS instances.
aliases: ['type']
type: str
security_groups:
description:
- A list of security group IDs.
aliases: ['group_ids']
type: list
elements: str
vswitch_id:
description:
- The subnet ID in which to launch the instances (VPC).
aliases: ['subnet_id']
type: str
instance_name:
description:
- The name of ECS instance, which is a string of 2 to 128 Chinese or English characters. It must begin with an
uppercase/lowercase letter or a Chinese character and can contain numerals, ".", "_" or "-".
It cannot begin with http:// or https://.
aliases: ['name']
type: str
description:
- The state of the instance after operating.
type: str
default: 'present'
choices: ['absent', 'present', 'restarted', 'running', 'stopped']
availability_zone:
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
image_id:
description:
- Image ID used to launch instances.
- Required when I(state=present) and creating new ECS instances.
aliases: ['image']
type: str
instance_type:
description:
- Instance type used to launch instances.
- Required when I(state=present) and creating new ECS instances.
aliases: ['type']
type: str
security_groups:
description:
- A list of security group IDs.
type: list
vswitch_id:
description:
- The subnet ID in which to launch the instances (VPC).
aliases: ['subnet_id']
type: str
instance_name:
description:
- The name of ECS instance, which is a string of 2 to 128 Chinese or English characters.
- It must begin with an uppercase/lowercase letter or a Chinese character and
can contain numerals, ".", "_" or "-". It cannot begin with http:// or https://.
aliases: ['name']
type: str
description:
description:
- The description of ECS instance, which is a string of 2 to 256 characters.
- It cannot begin with http:// or https://.
type: str
internet_charge_type:
description:
- Internet charge type of ECS instance.
type: str
default: 'PayByBandwidth'
choices: ['PayByBandwidth', 'PayByTraffic']
max_bandwidth_in:
description:
- Maximum incoming bandwidth from the public network,
measured in Mbps (Megabits per second).
default: 200
type: int
max_bandwidth_out:
description:
- Maximum outgoing bandwidth to the public network, measured in Mbps (Megabits per second).
type: int
default: 0
host_name:
description:
- Instance host name.
type: str
password:
description:
- The password to login instance.
- After rebooting instances, modified password will take effect.
type: str
system_disk_category:
description:
- Category of the system disk.
type: str
default: 'cloud_efficiency'
choices: ['cloud_efficiency', 'cloud_ssd']
system_disk_size:
description:
- Size of the system disk, in GB. The valid values are 40~500.
type: int
default: 40
system_disk_name:
description:
- Name of the system disk.
type: str
system_disk_description:
description:
- Description of the system disk.
type: str
count:
description:
- The number of the new instance.
- Indicates how many instances that match I(count_tag) should be running.
- Instances are either created or terminated based on this value.
type: int
default: 1
count_tag:
description:
- Determines how many instances based on a specific tag criteria should be present.
- This can be expressed in multiple ways and is shown in the EXAMPLES section.
- The specified count_tag must already exist or be passed in as the I(instance_tags) option.
- If it is not specified, it will be replaced by I(instance_name).
type: str
allocate_public_ip:
description:
- Whether allocate a public ip for the new instance.
default: False
aliases: ['assign_public_ip']
type: bool
instance_charge_type:
description:
- The charge type of the instance.
type: str
choices: ['PrePaid', 'PostPaid']
default: 'PostPaid'
period:
description:
- The charge duration of the instance, in month.
- Required when I(instance_charge_type=PrePaid).
- The valid value are [1-9, 12, 24, 36].
type: int
default: 1
auto_renew:
description:
- Whether automate renew the charge of the instance.
type: bool
default: False
auto_renew_period:
description:
- The duration of the automatic renew the charge of the instance.
- Required when I(auto_renew=True).
type: int
choices: [1, 2, 3, 6, 12]
instance_ids:
description:
- A list of instance ids. It is required when need to operate existing instances.
- If it is specified, I(count) will lose efficacy.
type: list
force:
description:
- Whether the current operation needs to be execute forcibly.
default: False
type: bool
instance_tags:
description:
- A hash/dictionaries of instance tags, to add to the new instance or
for starting/stopping instance by tag (C({"key":"value"})).
aliases: ['tags']
type: dict
key_name:
description:
- The name of key pair which is used to access ECS instance in SSH.
type: str
required: false
aliases: ['keypair']
user_data:
description:
- User-defined data to customize the startup behaviors of an ECS instance and to pass data into an ECS instance.
It only will take effect when launching the new ECS instances.
required: false
type: str
description:
- The description of ECS instance, which is a string of 2 to 256 characters. It cannot begin with http:// or https://.
type: str
internet_charge_type:
description:
- Internet charge type of ECS instance.
default: 'PayByBandwidth'
choices: ['PayByBandwidth', 'PayByTraffic']
type: str
max_bandwidth_in:
description:
- Maximum incoming bandwidth from the public network, measured in Mbps (Megabits per second).
default: 200
type: int
max_bandwidth_out:
description:
- Maximum outgoing bandwidth to the public network, measured in Mbps (Megabits per second).
Required when C(allocate_public_ip=True). Ignored when C(allocate_public_ip=False).
default: 0
type: int
host_name:
description:
- Instance host name. Ordered hostname is not supported.
type: str
unique_suffix:
description:
- Specifies whether to add sequential suffixes to the host_name.
The sequential suffix ranges from 001 to 999.
default: False
type: bool
password:
description:
- The password to login instance. After rebooting instances, modified password will take effect.
type: str
system_disk_category:
description:
- Category of the system disk.
default: 'cloud_efficiency'
choices: ['cloud_efficiency', 'cloud_ssd']
type: str
system_disk_size:
description:
- Size of the system disk, in GB. The valid values are 40~500.
default: 40
type: int
system_disk_name:
description:
- Name of the system disk.
type: str
system_disk_description:
description:
- Description of the system disk.
type: str
count:
description:
- The number of the new instance. An integer value which indicates how many instances that match I(count_tag)
should be running. Instances are either created or terminated based on this value.
default: 1
type: int
count_tag:
description:
- I(count) determines how many instances based on a specific tag criteria should be present.
This can be expressed in multiple ways and is shown in the EXAMPLES section.
The specified count_tag must already exist or be passed in as the I(tags) option.
If it is not specified, it will be replaced by I(instance_name).
type: str
allocate_public_ip:
description:
- Whether allocate a public ip for the new instance.
default: False
aliases: [ 'assign_public_ip' ]
type: bool
instance_charge_type:
description:
- The charge type of the instance.
choices: ['PrePaid', 'PostPaid']
default: 'PostPaid'
type: str
period:
description:
- The charge duration of the instance, in month. Required when C(instance_charge_type=PrePaid).
- The valid value are [1-9, 12, 24, 36].
default: 1
type: int
auto_renew:
description:
- Whether automate renew the charge of the instance.
type: bool
default: False
auto_renew_period:
description:
- The duration of the automatic renew the charge of the instance. Required when C(auto_renew=True).
choices: [1, 2, 3, 6, 12]
type: int
instance_ids:
description:
- A list of instance ids. It is required when need to operate existing instances.
If it is specified, I(count) will lose efficacy.
type: list
elements: str
force:
description:
- Whether the current operation needs to be execute forcibly.
default: False
type: bool
tags:
description:
- A hash/dictionaries of instance tags, to add to the new instance or for starting/stopping instance by tag. C({"key":"value"})
aliases: ["instance_tags"]
type: dict
purge_tags:
description:
- Delete any tags not specified in the task that are on the instance.
If True, it means you have to specify all the desired tags on each task affecting an instance.
default: False
type: bool
key_name:
description:
- The name of key pair which is used to access ECS instance in SSH.
required: false
type: str
aliases: ['keypair']
user_data:
description:
- User-defined data to customize the startup behaviors of an ECS instance and to pass data into an ECS instance.
It only will take effect when launching the new ECS instances.
required: false
type: str
ram_role_name:
description:
- The name of the instance RAM role.
type: str
spot_price_limit:
description:
- The maximum hourly price for the preemptible instance. This parameter supports a maximum of three decimal
places and takes effect when the SpotStrategy parameter is set to SpotWithPriceLimit.
type: float
spot_strategy:
description:
- The bidding mode of the pay-as-you-go instance. This parameter is valid when InstanceChargeType is set to PostPaid.
choices: ['NoSpot', 'SpotWithPriceLimit', 'SpotAsPriceGo']
default: 'NoSpot'
type: str
period_unit:
description:
- The duration unit that you will buy the resource. It is valid when C(instance_charge_type=PrePaid)
choices: ['Month', 'Week']
default: 'Month'
type: str
dry_run:
description:
- Specifies whether to send a dry-run request.
- If I(dry_run=True), Only a dry-run request is sent and no instance is created. The system checks whether the
required parameters are set, and validates the request format, service permissions, and available ECS instances.
If the validation fails, the corresponding error code is returned. If the validation succeeds, the DryRunOperation error code is returned.
- If I(dry_run=False), A request is sent. If the validation succeeds, the instance is created.
default: False
type: bool
include_data_disks:
description:
- Whether to change instance disks charge type when changing instance charge type.
default: True
type: bool
author:
- "He Guimin (@xiaozhu36)"
- "He Guimin (@xiaozhu36)"
requirements:
- "python >= 2.6"
- "footmark >= 1.1.16"
- "python >= 3.6"
- "footmark >= 1.19.0"
extends_documentation_fragment:
- community.general.alicloud
- community.general.alicloud
'''
EXAMPLES = r'''
EXAMPLES = '''
# basic provisioning example vpc network
- name: basic provisioning example
hosts: localhost
@ -243,7 +285,7 @@ EXAMPLES = r'''
assign_public_ip: '{{ assign_public_ip }}'
internet_charge_type: '{{ internet_charge_type }}'
max_bandwidth_out: '{{ max_bandwidth_out }}'
instance_tags:
tags:
Name: created_one
host_name: '{{ host_name }}'
password: '{{ password }}'
@ -261,7 +303,7 @@ EXAMPLES = r'''
security_groups: '{{ security_groups }}'
internet_charge_type: '{{ internet_charge_type }}'
max_bandwidth_out: '{{ max_bandwidth_out }}'
instance_tags:
tags:
Name: created_one
Version: 0.1
count: 2
@ -296,9 +338,9 @@ EXAMPLES = r'''
security_groups: '{{ security_groups }}'
'''
RETURN = r'''
RETURN = '''
instances:
description: List of ECS instances.
description: List of ECS instances
returned: always
type: complex
contains:
@ -432,6 +474,11 @@ instances:
returned: always
type: str
sample: ecs.sn1ne.xlarge
instance_type_family:
description: The instance type family of the instance belongs.
returned: always
type: str
sample: ecs.sn1ne
internet_charge_type:
description: The billing method of the network bandwidth.
returned: always
@ -493,7 +540,7 @@ instances:
type: str
sample: 10.0.0.1
public_ip_address:
description: The public IPv4 address assigned to the instance.
description: The public IPv4 address assigned to the instance or eip address
returned: always
type: str
sample: 43.0.0.1
@ -509,15 +556,15 @@ instances:
elements: dict
contains:
group_id:
description: The ID of the security group.
returned: always
type: str
sample: sg-0123456
description: The ID of the security group.
returned: always
type: str
sample: sg-0123456
group_name:
description: The name of the security group.
returned: always
type: str
sample: my-security-group
description: The name of the security group.
returned: always
type: str
sample: my-security-group
status:
description: The current status of the instance.
returned: always
@ -528,6 +575,11 @@ instances:
returned: always
type: dict
sample:
user_data:
description: User-defined data.
returned: always
type: dict
sample:
vswitch_id:
description: The ID of the vswitch in which the instance is running.
returned: always
@ -536,15 +588,28 @@ instances:
vpc_id:
description: The ID of the VPC the instance is in.
returned: always
type: dict
type: str
sample: vpc-0011223344
spot_price_limit:
description:
- The maximum hourly price for the preemptible instance.
returned: always
type: float
sample: 0.97
spot_strategy:
description:
- The bidding mode of the pay-as-you-go instance.
returned: always
type: str
sample: NoSpot
ids:
description: List of ECS instance IDs.
description: List of ECS instance IDs
returned: always
type: list
sample: [i-12345er, i-3245fs]
'''
import re
import time
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
@ -562,14 +627,17 @@ except ImportError:
def get_instances_info(connection, ids):
result = []
instances = connection.get_all_instances(instance_ids=ids)
instances = connection.describe_instances(instance_ids=ids)
if len(instances) > 0:
for inst in instances:
volumes = connection.describe_disks(instance_id=inst.id)
setattr(inst, 'block_device_mappings', volumes)
setattr(inst, 'user_data', inst.describe_user_data())
result.append(inst.read())
return result
def create_instance(module, ecs, exact_count):
def run_instance(module, ecs, exact_count):
if exact_count <= 0:
return None
zone_id = module.params['availability_zone']
@ -581,7 +649,7 @@ def create_instance(module, ecs, exact_count):
description = module.params['description']
internet_charge_type = module.params['internet_charge_type']
max_bandwidth_out = module.params['max_bandwidth_out']
max_bandwidth_in = module.params['max_bandwidth_out']
max_bandwidth_in = module.params['max_bandwidth_in']
host_name = module.params['host_name']
password = module.params['password']
system_disk_category = module.params['system_disk_category']
@ -589,14 +657,16 @@ def create_instance(module, ecs, exact_count):
system_disk_name = module.params['system_disk_name']
system_disk_description = module.params['system_disk_description']
allocate_public_ip = module.params['allocate_public_ip']
instance_tags = module.params['instance_tags']
period = module.params['period']
auto_renew = module.params['auto_renew']
instance_charge_type = module.params['instance_charge_type']
auto_renew_period = module.params['auto_renew_period']
user_data = module.params['user_data']
key_name = module.params['key_name']
ram_role_name = module.params['ram_role_name']
spot_price_limit = module.params['spot_price_limit']
spot_strategy = module.params['spot_strategy']
unique_suffix = module.params['unique_suffix']
# check whether the required parameter passed or not
if not image_id:
module.fail_json(msg='image_id is required for new instance')
@ -611,17 +681,17 @@ def create_instance(module, ecs, exact_count):
try:
# call to create_instance method from footmark
instances = ecs.create_instance(image_id=image_id, instance_type=instance_type, security_group_id=security_groups[0],
zone_id=zone_id, instance_name=instance_name, description=description,
internet_charge_type=internet_charge_type, max_bandwidth_out=max_bandwidth_out,
max_bandwidth_in=max_bandwidth_in, host_name=host_name, password=password,
io_optimized='optimized', system_disk_category=system_disk_category,
system_disk_size=system_disk_size, system_disk_name=system_disk_name,
system_disk_description=system_disk_description,
vswitch_id=vswitch_id, count=exact_count, allocate_public_ip=allocate_public_ip,
instance_charge_type=instance_charge_type, period=period, auto_renew=auto_renew,
auto_renew_period=auto_renew_period, instance_tags=instance_tags,
key_pair_name=key_name, user_data=user_data, client_token=client_token)
instances = ecs.run_instances(image_id=image_id, instance_type=instance_type, security_group_id=security_groups[0],
zone_id=zone_id, instance_name=instance_name, description=description,
internet_charge_type=internet_charge_type, internet_max_bandwidth_out=max_bandwidth_out,
internet_max_bandwidth_in=max_bandwidth_in, host_name=host_name, password=password,
io_optimized='optimized', system_disk_category=system_disk_category,
system_disk_size=system_disk_size, system_disk_disk_name=system_disk_name,
system_disk_description=system_disk_description, vswitch_id=vswitch_id,
amount=exact_count, instance_charge_type=instance_charge_type, period=period, period_unit="Month",
auto_renew=auto_renew, auto_renew_period=auto_renew_period, key_pair_name=key_name,
user_data=user_data, client_token=client_token, ram_role_name=ram_role_name,
spot_price_limit=spot_price_limit, spot_strategy=spot_strategy, unique_suffix=unique_suffix)
except Exception as e:
module.fail_json(msg='Unable to create instance, error: {0}'.format(e))
@ -629,11 +699,69 @@ def create_instance(module, ecs, exact_count):
return instances
def modify_instance(module, instance):
# According to state to modify instance's some special attribute
state = module.params["state"]
name = module.params['instance_name']
unique_suffix = module.params['unique_suffix']
if not name:
name = instance.name
description = module.params['description']
if not description:
description = instance.description
host_name = module.params['host_name']
if unique_suffix and host_name:
suffix = instance.host_name[-3:]
host_name = host_name + suffix
if not host_name:
host_name = instance.host_name
# password can be modified only when restart instance
password = ""
if state == "restarted":
password = module.params['password']
# userdata can be modified only when instance is stopped
setattr(instance, "user_data", instance.describe_user_data())
user_data = instance.user_data
if state == "stopped":
user_data = module.params['user_data'].encode()
try:
return instance.modify(name=name, description=description, host_name=host_name, password=password, user_data=user_data)
except Exception as e:
module.fail_json(msg="Modify instance {0} attribute got an error: {1}".format(instance.id, e))
def wait_for_instance_modify_charge(ecs, instance_ids, charge_type, delay=10, timeout=300):
"""
To verify instance charge type has become expected after modify instance charge type
"""
try:
while True:
instances = ecs.describe_instances(instance_ids=instance_ids)
flag = True
for inst in instances:
if inst and inst.instance_charge_type != charge_type:
flag = False
if flag:
return
timeout -= delay
time.sleep(delay)
if timeout <= 0:
raise Exception("Timeout Error: Waiting for instance to {0}. ".format(charge_type))
except Exception as e:
raise e
def main():
argument_spec = ecs_argument_spec()
argument_spec.update(dict(
security_groups=dict(type='list'),
availability_zone=dict(type='str', aliases=['alicloud_zone']),
security_groups=dict(type='list', elements='str', aliases=['group_ids']),
availability_zone=dict(type='str', aliases=['alicloud_zone', 'zone_id']),
instance_type=dict(type='str', aliases=['type']),
image_id=dict(type='str', aliases=['image']),
count=dict(type='int', default=1),
@ -650,17 +778,25 @@ def main():
system_disk_name=dict(type='str'),
system_disk_description=dict(type='str'),
force=dict(type='bool', default=False),
instance_tags=dict(type='dict', aliases=['tags']),
tags=dict(type='dict', aliases=['instance_tags']),
purge_tags=dict(type='bool', default=False),
state=dict(default='present', choices=['present', 'running', 'stopped', 'restarted', 'absent']),
description=dict(type='str'),
allocate_public_ip=dict(type='bool', aliases=['assign_public_ip'], default=False),
instance_charge_type=dict(type='str', default='PostPaid', choices=['PrePaid', 'PostPaid']),
period=dict(type='int', default=1),
auto_renew=dict(type='bool', default=False),
instance_ids=dict(type='list'),
instance_ids=dict(type='list', elements='str'),
auto_renew_period=dict(type='int', choices=[1, 2, 3, 6, 12]),
key_name=dict(type='str', aliases=['keypair']),
user_data=dict(type='str')
user_data=dict(type='str'),
ram_role_name=dict(type='str'),
spot_price_limit=dict(type='float'),
spot_strategy=dict(type='str', default='NoSpot', choices=['NoSpot', 'SpotWithPriceLimit', 'SpotAsPriceGo']),
unique_suffix=dict(type='bool', default=False),
period_unit=dict(type='str', default='Month', choices=['Month', 'Week']),
dry_run=dict(type='bool', default=False),
include_data_disks=dict(type='bool', default=True)
)
)
module = AnsibleModule(argument_spec=argument_spec)
@ -669,6 +805,7 @@ def main():
module.fail_json(msg=missing_required_lib('footmark'), exception=FOOTMARK_IMP_ERR)
ecs = ecs_connect(module)
host_name = module.params['host_name']
state = module.params['state']
instance_ids = module.params['instance_ids']
count_tag = module.params['count_tag']
@ -677,22 +814,50 @@ def main():
force = module.params['force']
zone_id = module.params['availability_zone']
key_name = module.params['key_name']
tags = module.params['tags']
max_bandwidth_out = module.params['max_bandwidth_out']
instance_charge_type = module.params['instance_charge_type']
if instance_charge_type == "PrePaid":
module.params['spot_strategy'] = ''
changed = False
instances = []
if instance_ids:
if not isinstance(instance_ids, list):
module.fail_json(msg='The parameter instance_ids should be a list, aborting')
instances = ecs.get_all_instances(zone_id=zone_id, instance_ids=instance_ids)
instances = ecs.describe_instances(zone_id=zone_id, instance_ids=instance_ids)
if not instances:
module.fail_json(msg="There are no instances in our record based on instance_ids {0}. "
"Please check it and try again.".format(instance_ids))
elif count_tag:
instances = ecs.get_all_instances(zone_id=zone_id, instance_tags=eval(count_tag))
instances = ecs.describe_instances(zone_id=zone_id, tags=eval(count_tag))
elif instance_name:
instances = ecs.get_all_instances(zone_id=zone_id, instance_name=instance_name)
instances = ecs.describe_instances(zone_id=zone_id, instance_name=instance_name)
ids = []
if state == 'absent':
if len(instances) < 1:
module.fail_json(msg='Please specify ECS instances that you want to operate by using '
'parameters instance_ids, tags or instance_name, aborting')
try:
targets = []
for inst in instances:
if inst.status != 'stopped' and not force:
module.fail_json(msg="Instance is running, and please stop it or set 'force' as True.")
targets.append(inst.id)
if ecs.delete_instances(instance_ids=targets, force=force):
changed = True
ids.extend(targets)
module.exit_json(changed=changed, ids=ids, instances=[])
except Exception as e:
module.fail_json(msg='Delete instance got an error: {0}'.format(e))
if module.params['allocate_public_ip'] and max_bandwidth_out < 0:
module.fail_json(msg="'max_bandwidth_out' should be greater than 0 when 'allocate_public_ip' is True.")
if not module.params['allocate_public_ip']:
module.params['max_bandwidth_out'] = 0
if state == 'present':
if not instance_ids:
if len(instances) > count:
@ -702,13 +867,17 @@ def main():
module.fail_json(msg="That to delete instance {0} is failed results from it is running, "
"and please stop it or set 'force' as True.".format(inst.id))
try:
changed = inst.terminate(force=force)
if inst.terminate(force=force):
changed = True
except Exception as e:
module.fail_json(msg="Delete instance {0} got an error: {1}".format(inst.id, e))
instances.pop(len(instances) - 1)
else:
try:
new_instances = create_instance(module, ecs, count - len(instances))
if re.search(r"-\[\d+,\d+\]-", host_name):
module.fail_json(msg='Ordered hostname is not supported, If you want to add an ordered '
'suffix to the hostname, you can set unique_suffix to True')
new_instances = run_instance(module, ecs, count - len(instances))
if new_instances:
changed = True
instances.extend(new_instances)
@ -717,9 +886,9 @@ def main():
# Security Group join/leave begin
security_groups = module.params['security_groups']
if not isinstance(security_groups, list):
module.fail_json(msg='The parameter security_groups should be a list, aborting')
if len(security_groups) > 0:
if security_groups:
if not isinstance(security_groups, list):
module.fail_json(msg='The parameter security_groups should be a list, aborting')
for inst in instances:
existing = inst.security_group_ids['security_group_id']
remove = list(set(existing).difference(set(security_groups)))
@ -737,80 +906,102 @@ def main():
for inst in instances:
if key_name is not None and key_name != inst.key_name:
if key_name == "":
changed = inst.detach_key_pair()
if inst.detach_key_pair():
changed = True
else:
inst_ids.append(inst.id)
if inst_ids:
changed = ecs.attach_key_pair(instance_ids=inst_ids, key_pair_name=key_name)
# Modify instance attribute
description = module.params['description']
host_name = module.params['host_name']
password = module.params['password']
for inst in instances:
if not instance_name:
instance_name = inst.name
if not description:
description = inst.description
if not host_name:
host_name = inst.host_name
try:
if inst.modify(name=instance_name, description=description, host_name=host_name, password=password):
changed = True
except Exception as e:
module.fail_json(msg="Modify instance attribute {0} got an error: {1}".format(inst.id, e))
if modify_instance(module, inst):
changed = True
if inst.id not in ids:
ids.append(inst.id)
module.exit_json(changed=changed, ids=ids, instances=get_instances_info(ecs, ids))
# Modify instance charge type
ids = []
for inst in instances:
if inst.instance_charge_type != instance_charge_type:
ids.append(inst.id)
if ids:
params = {"instance_ids": ids, "instance_charge_type": instance_charge_type,
"include_data_disks": module.params['include_data_disks'], "dry_run": module.params['dry_run'],
"auto_pay": True}
if instance_charge_type == 'PrePaid':
params['period'] = module.params['period']
params['period_unit'] = module.params['period_unit']
if ecs.modify_instance_charge_type(**params):
changed = True
wait_for_instance_modify_charge(ecs, ids, instance_charge_type)
else:
if len(instances) < 1:
module.fail_json(msg='Please specify ECS instances that you want to operate by using '
'parameters instance_ids, instance_tags or instance_name, aborting')
force = module.params['force']
'parameters instance_ids, tags or instance_name, aborting')
if state == 'running':
try:
targets = []
for inst in instances:
if inst.start():
if modify_instance(module, inst):
changed = True
ids.append(inst.id)
module.exit_json(changed=changed, ids=ids, instances=get_instances_info(ecs, ids))
if inst.status != "running":
targets.append(inst.id)
ids.append(inst.id)
if targets and ecs.start_instances(instance_ids=targets):
changed = True
ids.extend(targets)
except Exception as e:
module.fail_json(msg='Start instances got an error: {0}'.format(e))
elif state == 'stopped':
try:
targets = []
for inst in instances:
if inst.stop(force=force):
if inst.status != "stopped":
targets.append(inst.id)
if targets and ecs.stop_instances(instance_ids=targets, force_stop=force):
changed = True
ids.extend(targets)
for inst in instances:
if modify_instance(module, inst):
changed = True
ids.append(inst.id)
module.exit_json(changed=changed, ids=ids, instances=get_instances_info(ecs, ids))
except Exception as e:
module.fail_json(msg='Stop instances got an error: {0}'.format(e))
elif state == 'restarted':
try:
targets = []
for inst in instances:
if inst.reboot(force=module.params['force']):
if modify_instance(module, inst):
changed = True
ids.append(inst.id)
module.exit_json(changed=changed, ids=ids, instances=get_instances_info(ecs, ids))
targets.append(inst.id)
if ecs.reboot_instances(instance_ids=targets, force_stop=module.params['force']):
changed = True
ids.extend(targets)
except Exception as e:
module.fail_json(msg='Reboot instances got an error: {0}'.format(e))
else:
try:
for inst in instances:
if inst.status != 'stopped' and not force:
module.fail_json(msg="Instance is running, and please stop it or set 'force' as True.")
if inst.terminate(force=module.params['force']):
changed = True
module.exit_json(changed=changed, ids=[], instances=[])
tags = module.params['tags']
if module.params['purge_tags']:
for inst in instances:
if not tags:
tags = inst.tags
try:
if inst.remove_tags(tags):
changed = True
except Exception as e:
module.fail_json(msg='Delete instance got an error: {0}'.format(e))
module.fail_json(msg="{0}".format(e))
module.exit_json(changed=changed, instances=get_instances_info(ecs, ids))
if tags:
for inst in instances:
try:
if inst.add_tags(tags):
changed = True
except Exception as e:
module.fail_json(msg="{0}".format(e))
module.exit_json(changed=changed, instances=get_instances_info(ecs, ids))
if __name__ == '__main__':

View file

@ -1,5 +1,7 @@
#!/usr/bin/python
# Copyright (c) 2017 Alibaba Group Holding Limited. He Guimin <heguimin36@163.com>
# -*- coding: utf-8 -*-
# Copyright (c) 2017-present Alibaba Group Holding Limited. He Guimin <heguimin36@163.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
@ -17,7 +19,8 @@
# 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
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
@ -36,68 +39,70 @@ description:
options:
availability_zone:
description:
- Aliyun availability zone ID in which to launch the instance
- (Deprecated) Aliyun availability zone ID in which to launch the instance. Please use filter item 'zone_id' instead.
aliases: ['alicloud_zone']
type: str
instance_names:
description:
- A list of ECS instance names.
aliases: [ "names"]
- (Deprecated) A list of ECS instance names. Please use filter item 'instance_name' instead.
aliases: ["names"]
type: list
elements: str
instance_ids:
description:
- A list of ECS instance ids.
aliases: ["ids"]
instance_tags:
type: list
elements: str
name_prefix:
description:
- Use a instance name prefix to filter ecs instances.
type: str
tags:
description:
- A hash/dictionaries of instance tags. C({"key":"value"})
aliases: ["tags"]
aliases: ["instance_tags"]
type: dict
filters:
description:
- A dict of filters to apply. Each dict item consists of a filter key and a filter value. The filter keys can be
all of request parameters. See U(https://www.alibabacloud.com/help/doc-detail/25506.htm) for parameter details.
Filter keys can be same as request parameter name or be lower case and use underscore ("_") or dash ("-") to
connect different words in one parameter. 'InstanceIds' should be a list and it will be appended to
I(instance_ids) automatically. 'Tag.n.Key' and 'Tag.n.Value' should be a dict and using I(tags) instead.
type: dict
author:
- "He Guimin (@xiaozhu36)"
requirements:
- "python >= 2.6"
- "footmark >= 1.1.16"
- "python >= 3.6"
- "footmark >= 1.13.0"
extends_documentation_fragment:
- community.general.alicloud
- community.general.alicloud
'''
EXAMPLES = '''
# Fetch instances details according to setting different filters
- name: fetch instances details example
hosts: localhost
vars:
alicloud_access_key: <your-alicloud-access-key>
alicloud_secret_key: <your-alicloud-secret-key>
alicloud_region: cn-beijing
availability_zone: cn-beijing-a
tasks:
- name: Find all instances in the specified region
ali_instance_info:
alicloud_access_key: '{{ alicloud_access_key }}'
alicloud_secret_key: '{{ alicloud_secret_key }}'
alicloud_region: '{{ alicloud_region }}'
register: all_instances
- name: Find all instances in the specified region
ali_instance_info:
register: all_instances
- name: Find all instances based on the specified ids
ali_instance_info:
alicloud_access_key: '{{ alicloud_access_key }}'
alicloud_secret_key: '{{ alicloud_secret_key }}'
alicloud_region: '{{ alicloud_region }}'
instance_ids:
- "i-35b333d9"
- "i-ddav43kd"
register: instances_by_ids
- name: Find all instances based on the specified ids
ali_instance_info:
instance_ids:
- "i-35b333d9"
- "i-ddav43kd"
register: instances_by_ids
- name: Find all instances based on the specified names/name-prefixes
ali_instance_info:
alicloud_access_key: '{{ alicloud_access_key }}'
alicloud_secret_key: '{{ alicloud_secret_key }}'
alicloud_region: '{{ alicloud_region }}'
instance_names:
- "ecs_instance-1"
- "ecs_instance_2"
register: instances_by_ids
- name: Find all instances based on the specified name_prefix
ali_instance_info:
name_prefix: "ecs_instance_"
register: instances_by_name_prefix
- name: Find instances based on tags
ali_instance_info:
tags:
Test: "add"
'''
RETURN = '''
@ -231,6 +236,11 @@ instances:
returned: always
type: str
sample: my-ecs
instance_type_family:
description: The instance type family of the instance belongs.
returned: always
type: str
sample: ecs.sn1ne
instance_type:
description: The instance type of the running instance.
returned: always
@ -297,7 +307,7 @@ instances:
type: str
sample: 10.0.0.1
public_ip_address:
description: The public IPv4 address assigned to the instance
description: The public IPv4 address assigned to the instance or eip address
returned: always
type: str
sample: 43.0.0.1
@ -313,15 +323,15 @@ instances:
elements: dict
contains:
group_id:
description: The ID of the security group.
returned: always
type: str
sample: sg-0123456
description: The ID of the security group.
returned: always
type: str
sample: sg-0123456
group_name:
description: The name of the security group.
returned: always
type: str
sample: my-security-group
description: The name of the security group.
returned: always
type: str
sample: my-security-group
status:
description: The current status of the instance.
returned: always
@ -340,7 +350,7 @@ instances:
vpc_id:
description: The ID of the VPC the instance is in.
returned: always
type: dict
type: str
sample: vpc-0011223344
ids:
description: List of ECS instance IDs
@ -349,11 +359,9 @@ ids:
sample: [i-12345er, i-3245fs]
'''
# import time
# import sys
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
from ansible_collections.community.general.plugins.module_utils.alicloud_ecs import get_acs_connection_info, ecs_argument_spec, ecs_connect
from ansible_collections.community.general.plugins.module_utils.alicloud_ecs import ecs_argument_spec, ecs_connect
HAS_FOOTMARK = False
FOOTMARK_IMP_ERR = None
@ -369,9 +377,11 @@ def main():
argument_spec = ecs_argument_spec()
argument_spec.update(dict(
availability_zone=dict(aliases=['alicloud_zone']),
instance_ids=dict(type='list', aliases=['ids']),
instance_names=dict(type='list', aliases=['names']),
instance_tags=dict(type='list', aliases=['tags']),
instance_ids=dict(type='list', elements='str', aliases=['ids']),
instance_names=dict(type='list', elements='str', aliases=['names']),
name_prefix=dict(type='str'),
tags=dict(type='dict', aliases=['instance_tags']),
filters=dict(type='dict')
)
)
module = AnsibleModule(argument_spec=argument_spec)
@ -386,23 +396,43 @@ def main():
instances = []
instance_ids = []
ids = module.params['instance_ids']
name_prefix = module.params['name_prefix']
names = module.params['instance_names']
zone_id = module.params['availability_zone']
if ids and (not isinstance(ids, list) or len(ids) < 1):
module.fail_json(msg='instance_ids should be a list of instances, aborting')
if names and (not isinstance(names, list) or len(names) < 1):
module.fail_json(msg='instance_ids should be a list of instances, aborting')
module.fail_json(msg='instance_names should be a list of instances, aborting')
filters = module.params['filters']
if not filters:
filters = {}
if not ids:
ids = []
for key, value in list(filters.items()):
if key in ["InstanceIds", "instance_ids", "instance-ids"] and isinstance(ids, list):
for id in value:
if id not in ids:
ids.append(value)
if ids:
filters['instance_ids'] = ids
if module.params['tags']:
filters['tags'] = module.params['tags']
if zone_id:
filters['zone_id'] = zone_id
if names:
for name in names:
for inst in ecs.get_all_instances(zone_id=zone_id, instance_ids=ids, instance_name=name):
instances.append(inst.read())
instance_ids.append(inst.id)
else:
for inst in ecs.get_all_instances(zone_id=zone_id, instance_ids=ids):
instances.append(inst.read())
instance_ids.append(inst.id)
filters['instance_name'] = names[0]
for inst in ecs.describe_instances(**filters):
if name_prefix:
if not str(inst.instance_name).startswith(name_prefix):
continue
volumes = ecs.describe_disks(instance_id=inst.id)
setattr(inst, 'block_device_mappings', volumes)
setattr(inst, 'user_data', inst.describe_user_data())
instances.append(inst.read())
instance_ids.append(inst.id)
module.exit_json(changed=False, ids=instance_ids, instances=instances)

View file

@ -152,12 +152,6 @@ plugins/module_utils/univention_umc.py future-import-boilerplate
plugins/module_utils/univention_umc.py metaclass-boilerplate
plugins/module_utils/vexata.py future-import-boilerplate
plugins/module_utils/vexata.py metaclass-boilerplate
plugins/modules/cloud/alicloud/ali_instance.py validate-modules:doc-required-mismatch
plugins/modules/cloud/alicloud/ali_instance.py validate-modules:parameter-list-no-elements
plugins/modules/cloud/alicloud/ali_instance_info.py validate-modules:doc-missing-type
plugins/modules/cloud/alicloud/ali_instance_info.py validate-modules:doc-required-mismatch
plugins/modules/cloud/alicloud/ali_instance_info.py validate-modules:parameter-list-no-elements
plugins/modules/cloud/alicloud/ali_instance_info.py validate-modules:parameter-type-not-in-doc
plugins/modules/cloud/atomic/atomic_container.py validate-modules:doc-missing-type
plugins/modules/cloud/atomic/atomic_container.py validate-modules:doc-required-mismatch
plugins/modules/cloud/atomic/atomic_container.py validate-modules:no-default-for-required-parameter