1# -*- coding: utf-8 -*- 2# This code is part of Ansible, but is an independent component. 3# This particular file snippet, and this file snippet only, is BSD licensed. 4# Modules you write using this snippet, which is embedded dynamically by Ansible 5# still belong to the author of the module, and may assign their own license 6# to the complete work. 7# 8# Copyright (c) 2017-present Alibaba Group Holding Limited. He Guimin <heguimin36@163.com> 9# 10# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause) 11 12from __future__ import (absolute_import, division, print_function) 13__metaclass__ = type 14 15import os 16import json 17from ansible.module_utils.basic import env_fallback 18 19try: 20 import footmark 21 import footmark.ecs 22 import footmark.slb 23 import footmark.vpc 24 import footmark.rds 25 import footmark.ess 26 import footmark.sts 27 import footmark.dns 28 import footmark.ram 29 import footmark.market 30 HAS_FOOTMARK = True 31except ImportError: 32 HAS_FOOTMARK = False 33 34 35class AnsibleACSError(Exception): 36 pass 37 38 39def acs_common_argument_spec(): 40 return dict( 41 alicloud_access_key=dict(aliases=['access_key_id', 'access_key'], no_log=True, 42 fallback=(env_fallback, ['ALICLOUD_ACCESS_KEY', 'ALICLOUD_ACCESS_KEY_ID'])), 43 alicloud_secret_key=dict(aliases=['secret_access_key', 'secret_key'], no_log=True, 44 fallback=(env_fallback, ['ALICLOUD_SECRET_KEY', 'ALICLOUD_SECRET_ACCESS_KEY'])), 45 alicloud_security_token=dict(aliases=['security_token'], no_log=True, 46 fallback=(env_fallback, ['ALICLOUD_SECURITY_TOKEN'])), 47 ecs_role_name=dict(aliases=['role_name'], fallback=(env_fallback, ['ALICLOUD_ECS_ROLE_NAME'])) 48 ) 49 50 51def ecs_argument_spec(): 52 spec = acs_common_argument_spec() 53 spec.update( 54 dict( 55 alicloud_region=dict(required=True, aliases=['region', 'region_id'], 56 fallback=(env_fallback, ['ALICLOUD_REGION', 'ALICLOUD_REGION_ID'])), 57 alicloud_assume_role_arn=dict(fallback=(env_fallback, ['ALICLOUD_ASSUME_ROLE_ARN']), 58 aliases=['assume_role_arn']), 59 alicloud_assume_role_session_name=dict(fallback=(env_fallback, ['ALICLOUD_ASSUME_ROLE_SESSION_NAME']), 60 aliases=['assume_role_session_name']), 61 alicloud_assume_role_session_expiration=dict(type='int', 62 fallback=(env_fallback, 63 ['ALICLOUD_ASSUME_ROLE_SESSION_EXPIRATION']), 64 aliases=['assume_role_session_expiration']), 65 alicloud_assume_role=dict(type='dict', aliases=['assume_role']), 66 profile=dict(fallback=(env_fallback, ['ALICLOUD_PROFILE'])), 67 shared_credentials_file=dict(fallback=(env_fallback, ['ALICLOUD_SHARED_CREDENTIALS_FILE'])) 68 ) 69 ) 70 return spec 71 72 73def get_acs_connection_info(params): 74 75 ecs_params = dict(acs_access_key_id=params.get('alicloud_access_key'), 76 acs_secret_access_key=params.get('alicloud_secret_key'), 77 security_token=params.get('alicloud_security_token'), 78 ecs_role_name=params.get('ecs_role_name'), 79 user_agent='Ansible-Provider-Alicloud') 80 return ecs_params 81 82 83def connect_to_acs(acs_module, region, **params): 84 conn = acs_module.connect_to_region(region, **params) 85 if not conn: 86 if region not in [acs_module_region.id for acs_module_region in acs_module.regions()]: 87 raise AnsibleACSError( 88 "Region %s does not seem to be available for acs module %s." % (region, acs_module.__name__)) 89 else: 90 raise AnsibleACSError( 91 "Unknown problem connecting to region %s for acs module %s." % (region, acs_module.__name__)) 92 return conn 93 94 95def get_assume_role(params): 96 """ Return new params """ 97 sts_params = get_acs_connection_info(params) 98 assume_role = {} 99 if params.get('assume_role'): 100 assume_role['alicloud_assume_role_arn'] = params['assume_role'].get('role_arn') 101 assume_role['alicloud_assume_role_session_name'] = params['assume_role'].get('session_name') 102 assume_role['alicloud_assume_role_session_expiration'] = params['assume_role'].get('session_expiration') 103 assume_role['alicloud_assume_role_policy'] = params['assume_role'].get('policy') 104 105 assume_role_params = { 106 'role_arn': params.get('alicloud_assume_role_arn') if params.get('alicloud_assume_role_arn') else assume_role.get('alicloud_assume_role_arn'), 107 'role_session_name': params.get('alicloud_assume_role_session_name') if params.get('alicloud_assume_role_session_name') 108 else assume_role.get('alicloud_assume_role_session_name'), 109 'duration_seconds': params.get('alicloud_assume_role_session_expiration') if params.get('alicloud_assume_role_session_expiration') 110 else assume_role.get('alicloud_assume_role_session_expiration', 3600), 111 'policy': assume_role.get('alicloud_assume_role_policy', {}) 112 } 113 114 try: 115 sts = connect_to_acs(footmark.sts, params.get('alicloud_region'), **sts_params).assume_role(**assume_role_params).read() 116 sts_params['acs_access_key_id'], sts_params['acs_secret_access_key'], sts_params['security_token'] \ 117 = sts['access_key_id'], sts['access_key_secret'], sts['security_token'] 118 except AnsibleACSError as e: 119 params.fail_json(msg=str(e)) 120 return sts_params 121 122 123def get_profile(params): 124 if not params['alicloud_access_key'] and not params['ecs_role_name'] and params['profile']: 125 path = params['shared_credentials_file'] if params['shared_credentials_file'] else os.getenv('HOME') + '/.aliyun/config.json' 126 auth = {} 127 with open(path, 'r') as f: 128 for pro in json.load(f)['profiles']: 129 if params['profile'] == pro['name']: 130 auth = pro 131 if auth: 132 if auth['mode'] == 'AK' and auth.get('access_key_id') and auth.get('access_key_secret'): 133 params['alicloud_access_key'] = auth.get('access_key_id') 134 params['alicloud_secret_key'] = auth.get('access_key_secret') 135 params['alicloud_region'] = auth.get('region_id') 136 params = get_acs_connection_info(params) 137 elif auth['mode'] == 'StsToken' and auth.get('access_key_id') and auth.get('access_key_secret') and auth.get('sts_token'): 138 params['alicloud_access_key'] = auth.get('access_key_id') 139 params['alicloud_secret_key'] = auth.get('access_key_secret') 140 params['security_token'] = auth.get('sts_token') 141 params['alicloud_region'] = auth.get('region_id') 142 params = get_acs_connection_info(params) 143 elif auth['mode'] == 'EcsRamRole': 144 params['ecs_role_name'] = auth.get('ram_role_name') 145 params['alicloud_region'] = auth.get('region_id') 146 params = get_acs_connection_info(params) 147 elif auth['mode'] == 'RamRoleArn' and auth.get('ram_role_arn'): 148 params['alicloud_access_key'] = auth.get('access_key_id') 149 params['alicloud_secret_key'] = auth.get('access_key_secret') 150 params['security_token'] = auth.get('sts_token') 151 params['ecs_role_name'] = auth.get('ram_role_name') 152 params['alicloud_assume_role_arn'] = auth.get('ram_role_arn') 153 params['alicloud_assume_role_session_name'] = auth.get('ram_session_name') 154 params['alicloud_assume_role_session_expiration'] = auth.get('expired_seconds') 155 params['alicloud_region'] = auth.get('region_id') 156 params = get_assume_role(params) 157 elif params.get('alicloud_assume_role_arn') or params.get('assume_role'): 158 params = get_assume_role(params) 159 else: 160 params = get_acs_connection_info(params) 161 return params 162 163 164def ecs_connect(module): 165 """ Return an ecs connection""" 166 ecs_params = get_profile(module.params) 167 # If we have a region specified, connect to its endpoint. 168 region = module.params.get('alicloud_region') 169 if region: 170 try: 171 ecs = connect_to_acs(footmark.ecs, region, **ecs_params) 172 except AnsibleACSError as e: 173 module.fail_json(msg=str(e)) 174 # Otherwise, no region so we fallback to the old connection method 175 return ecs 176 177 178def slb_connect(module): 179 """ Return an slb connection""" 180 slb_params = get_profile(module.params) 181 # If we have a region specified, connect to its endpoint. 182 region = module.params.get('alicloud_region') 183 if region: 184 try: 185 slb = connect_to_acs(footmark.slb, region, **slb_params) 186 except AnsibleACSError as e: 187 module.fail_json(msg=str(e)) 188 # Otherwise, no region so we fallback to the old connection method 189 return slb 190 191 192def dns_connect(module): 193 """ Return an dns connection""" 194 dns_params = get_profile(module.params) 195 # If we have a region specified, connect to its endpoint. 196 region = module.params.get('alicloud_region') 197 if region: 198 try: 199 dns = connect_to_acs(footmark.dns, region, **dns_params) 200 except AnsibleACSError as e: 201 module.fail_json(msg=str(e)) 202 # Otherwise, no region so we fallback to the old connection method 203 return dns 204 205 206def vpc_connect(module): 207 """ Return an vpc connection""" 208 vpc_params = get_profile(module.params) 209 # If we have a region specified, connect to its endpoint. 210 region = module.params.get('alicloud_region') 211 if region: 212 try: 213 vpc = connect_to_acs(footmark.vpc, region, **vpc_params) 214 except AnsibleACSError as e: 215 module.fail_json(msg=str(e)) 216 # Otherwise, no region so we fallback to the old connection method 217 return vpc 218 219 220def rds_connect(module): 221 """ Return an rds connection""" 222 rds_params = get_profile(module.params) 223 # If we have a region specified, connect to its endpoint. 224 region = module.params.get('alicloud_region') 225 if region: 226 try: 227 rds = connect_to_acs(footmark.rds, region, **rds_params) 228 except AnsibleACSError as e: 229 module.fail_json(msg=str(e)) 230 # Otherwise, no region so we fallback to the old connection method 231 return rds 232 233 234def ess_connect(module): 235 """ Return an ess connection""" 236 ess_params = get_profile(module.params) 237 # If we have a region specified, connect to its endpoint. 238 region = module.params.get('alicloud_region') 239 if region: 240 try: 241 ess = connect_to_acs(footmark.ess, region, **ess_params) 242 except AnsibleACSError as e: 243 module.fail_json(msg=str(e)) 244 # Otherwise, no region so we fallback to the old connection method 245 return ess 246 247 248def sts_connect(module): 249 """ Return an sts connection""" 250 sts_params = get_profile(module.params) 251 # If we have a region specified, connect to its endpoint. 252 region = module.params.get('alicloud_region') 253 if region: 254 try: 255 sts = connect_to_acs(footmark.sts, region, **sts_params) 256 except AnsibleACSError as e: 257 module.fail_json(msg=str(e)) 258 # Otherwise, no region so we fallback to the old connection method 259 return sts 260 261 262def ram_connect(module): 263 """ Return an ram connection""" 264 ram_params = get_profile(module.params) 265 # If we have a region specified, connect to its endpoint. 266 region = module.params.get('alicloud_region') 267 if region: 268 try: 269 ram = connect_to_acs(footmark.ram, region, **ram_params) 270 except AnsibleACSError as e: 271 module.fail_json(msg=str(e)) 272 # Otherwise, no region so we fallback to the old connection method 273 return ram 274 275 276def market_connect(module): 277 """ Return an market connection""" 278 market_params = get_profile(module.params) 279 # If we have a region specified, connect to its endpoint. 280 region = module.params.get('alicloud_region') 281 if region: 282 try: 283 market = connect_to_acs(footmark.market, region, **market_params) 284 except AnsibleACSError as e: 285 module.fail_json(msg=str(e)) 286 # Otherwise, no region so we fallback to the old connection method 287 return market 288