HEX
Server: Apache
System: Linux sg241.singhost.net 2.6.32-896.16.1.lve1.4.51.el6.x86_64 #1 SMP Wed Jan 17 13:19:23 EST 2018 x86_64
User: honghock (909)
PHP: 8.0.30
Disabled: passthru,system,shell_exec,show_source,exec,popen,proc_open
Upload Files
File: //usr/lib/python2.7/site-packages/salt/cloud/clouds/tencentcloud.py
# -*- coding: utf-8 -*-

'''
Tencent Cloud Cloud Module
=============================

.. versionadded:: 3000

The Tencent Cloud Cloud Module is used to control access to the Tencent Cloud instance.
https://intl.cloud.tencent.com/

To use this module, set up the cloud configuration at
 ``/etc/salt/cloud.providers`` or ``/etc/salt/cloud.providers.d/*.conf``:

.. code-block:: yaml

    my-tencentcloud-config:
      driver: tencentcloud
      # Tencent Cloud Secret Id
      id: AKIDA64pOio9BMemkApzevX0HS169S4b750A
      # Tencent Cloud Secret Key
      key: 8r2xmPn0C5FDvRAlmcJimiTZKVRsk260
      # Tencent Cloud Region
      location: ap-guangzhou

:depends: tencentcloud-sdk-python
'''

# pylint: disable=invalid-name,redefined-builtin,function-redefined,undefined-variable,broad-except,too-many-locals,too-many-branches

# Import python libs
from __future__ import absolute_import, print_function, unicode_literals
import time
import pprint
import logging

# Import salt cloud libs
import salt.utils.cloud
import salt.utils.data
import salt.utils.json
import salt.config as config
from salt.exceptions import (
    SaltCloudNotFound,
    SaltCloudSystemExit,
    SaltCloudExecutionFailure,
    SaltCloudExecutionTimeout
)

# Import 3rd-party libs
from salt.ext import six
from salt.ext.six.moves import range

try:
    # Try import tencentcloud sdk
    from tencentcloud.common import credential  # pylint: disable=no-name-in-module
    from tencentcloud.common.profile.client_profile import ClientProfile  # pylint: disable=no-name-in-module
    from tencentcloud.cvm.v20170312 import cvm_client  # pylint: disable=no-name-in-module
    from tencentcloud.cvm.v20170312 import models as cvm_models  # pylint: disable=no-name-in-module
    from tencentcloud.vpc.v20170312 import vpc_client  # pylint: disable=no-name-in-module
    from tencentcloud.vpc.v20170312 import models as vpc_models  # pylint: disable=no-name-in-module
    HAS_TENCENTCLOUD_SDK = True
except ImportError:
    HAS_TENCENTCLOUD_SDK = False

# Get logging started
log = logging.getLogger(__name__)

# The default region
DEFAULT_REGION = 'ap-guangzhou'

# The Tencent Cloud
__virtualname__ = 'tencentcloud'


def __virtual__():
    '''
    Only load in this module if the Tencent Cloud configurations are in place
    '''
    if get_configured_provider() is False:
        return False

    if get_dependencies() is False:
        return False

    return __virtualname__


def get_configured_provider():
    '''
    Return the first configured instance.
    '''
    return config.is_provider_configured(
        __opts__,
        __active_provider_name__ or __virtualname__,
        ('id', 'key')
    )


def get_dependencies():
    '''
    Warn if dependencies aren't met.
    '''
    return config.check_driver_dependencies(
        __virtualname__,
        {'tencentcloud-sdk-python': HAS_TENCENTCLOUD_SDK}
    )


def get_provider_client(name=None):
    '''
    Return a new provider client
    '''
    provider = get_configured_provider()

    secretId = provider.get('id')
    secretKey = provider.get('key')
    region = __get_location(None)

    cpf = ClientProfile()
    cpf.language = "en-US"
    crd = credential.Credential(secretId, secretKey)

    if name == "cvm_client":
        client = cvm_client.CvmClient(crd, region, cpf)
    elif name == "vpc_client":
        client = vpc_client.VpcClient(crd, region, cpf)
    else:
        raise SaltCloudSystemExit(
            'Client name {0} is not supported'.format(name)
        )

    return client


def avail_locations(call=None):
    '''
    Return Tencent Cloud available region

    CLI Example:

    .. code-block:: bash

        salt-cloud --list-locations my-tencentcloud-config
        salt-cloud -f avail_locations my-tencentcloud-config
    '''
    if call == 'action':
        raise SaltCloudSystemExit(
            'The avail_locations function must be called with '
            '-f or --function, or with the --list-locations option'
        )

    client = get_provider_client("cvm_client")
    req = cvm_models.DescribeRegionsRequest()
    resp = client.DescribeRegions(req)

    ret = {}
    for region in resp.RegionSet:
        if region.RegionState != "AVAILABLE":
            continue
        ret[region.Region] = region.RegionName

    return ret


def avail_images(call=None):
    '''
    Return Tencent Cloud available image

    CLI Example:

    .. code-block:: bash

        salt-cloud --list-images my-tencentcloud-config
        salt-cloud -f avail_images my-tencentcloud-config
    '''
    if call == 'action':
        raise SaltCloudSystemExit(
            'The avail_images function must be called with '
            '-f or --function, or with the --list-images option'
        )

    return _get_images(["PUBLIC_IMAGE", "PRIVATE_IMAGE", "IMPORT_IMAGE", "SHARED_IMAGE"])


def avail_sizes(call=None):
    '''
    Return Tencent Cloud available instance type

    CLI Example:

    .. code-block:: bash

        salt-cloud --list-sizes my-tencentcloud-config
        salt-cloud -f avail_sizes my-tencentcloud-config
    '''
    if call == 'action':
        raise SaltCloudSystemExit(
            'The avail_sizes function must be called with '
            '-f or --function, or with the --list-sizes option'
        )

    client = get_provider_client("cvm_client")
    req = cvm_models.DescribeInstanceTypeConfigsRequest()
    resp = client.DescribeInstanceTypeConfigs(req)

    ret = {}
    for typeConfig in resp.InstanceTypeConfigSet:
        ret[typeConfig.InstanceType] = {
            "Zone": typeConfig.Zone,
            "InstanceFamily": typeConfig.InstanceFamily,
            "Memory": "{0}GB".format(typeConfig.Memory),
            "CPU": "{0}-Core".format(typeConfig.CPU),
        }
        if typeConfig.GPU:
            ret[typeConfig.InstanceType]["GPU"] = "{0}-Core".format(
                typeConfig.GPU)

    return ret


def list_securitygroups(call=None):
    '''
    Return all Tencent Cloud security groups in current region

    CLI Example:

    .. code-block:: bash

        salt-cloud -f list_securitygroups my-tencentcloud-config
    '''
    if call == 'action':
        raise SaltCloudSystemExit(
            'The list_securitygroups function must be called with -f or --function.'
        )

    client = get_provider_client("vpc_client")
    req = vpc_models.DescribeSecurityGroupsRequest()
    req.Offset = 0
    req.Limit = 100
    resp = client.DescribeSecurityGroups(req)

    ret = {}
    for sg in resp.SecurityGroupSet:
        ret[sg.SecurityGroupId] = {
            "SecurityGroupName": sg.SecurityGroupName,
            "SecurityGroupDesc": sg.SecurityGroupDesc,
            "ProjectId": sg.ProjectId,
            "IsDefault": sg.IsDefault,
            "CreatedTime": sg.CreatedTime,
        }

    return ret


def list_custom_images(call=None):
    '''
    Return all Tencent Cloud images in current region

    CLI Example:

    .. code-block:: bash

        salt-cloud -f list_custom_images my-tencentcloud-config
    '''
    if call == 'action':
        raise SaltCloudSystemExit(
            'The list_custom_images function must be called with -f or --function.'
        )

    return _get_images(["PRIVATE_IMAGE", "IMPORT_IMAGE"])


def list_availability_zones(call=None):
    '''
    Return all Tencent Cloud availability zones in current region

    CLI Example:

    .. code-block:: bash

        salt-cloud -f list_availability_zones my-tencentcloud-config
    '''
    if call == 'action':
        raise SaltCloudSystemExit(
            'The list_availability_zones function must be called with -f or --function.'
        )

    client = get_provider_client("cvm_client")
    req = cvm_models.DescribeZonesRequest()
    resp = client.DescribeZones(req)

    ret = {}
    for zone in resp.ZoneSet:
        if zone.ZoneState != "AVAILABLE":
            continue
        ret[zone.Zone] = zone.ZoneName,

    return ret


def list_nodes(call=None):
    '''
    Return a list of instances that are on the provider

    CLI Examples:

    .. code-block:: bash

        salt-cloud -Q
    '''
    if call == 'action':
        raise SaltCloudSystemExit(
            'The list_nodes function must be called with -f or --function.'
        )

    ret = {}
    nodes = _get_nodes()
    for instance in nodes:
        ret[instance.InstanceId] = {
            "InstanceId": instance.InstanceId,
            "InstanceName": instance.InstanceName,
            "InstanceType": instance.InstanceType,
            "ImageId": instance.ImageId,
            "PublicIpAddresses": instance.PublicIpAddresses,
            "PrivateIpAddresses": instance.PrivateIpAddresses,
            "InstanceState": instance.InstanceState,
        }

    return ret


def list_nodes_full(call=None):
    '''
    Return a list of instances that are on the provider, with full details

    CLI Examples:

    .. code-block:: bash

        salt-cloud -F
    '''
    if call == 'action':
        raise SaltCloudSystemExit(
            'The list_nodes_full function must be called with -f or --function.'
        )

    ret = {}
    nodes = _get_nodes()
    for instance in nodes:
        instanceAttribute = vars(instance)
        ret[instance.InstanceName] = instanceAttribute
        for k in ["DataDisks", "InternetAccessible", "LoginSettings",
                  "Placement", "SystemDisk", "Tags", "VirtualPrivateCloud"]:
            ret[instance.InstanceName][k] = six.text_type(instanceAttribute[k])

    provider = __active_provider_name__ or 'tencentcloud'
    if ':' in provider:
        comps = provider.split(':')
        provider = comps[0]

    __opts__['update_cachedir'] = True
    __utils__['cloud.cache_node_list'](ret, provider, __opts__)

    return ret


def list_nodes_select(call=None):
    '''
    Return a list of instances that are on the provider, with select fields

    CLI Examples:

    .. code-block:: bash

        salt-cloud -S
    '''
    return salt.utils.cloud.list_nodes_select(
        list_nodes_full('function'), __opts__['query.selection'], call,
    )


def list_nodes_min(call=None):
    '''
    Return a list of instances that are on the provider, Only names, and their state, is returned.

    CLI Examples:

    .. code-block:: bash

        salt-cloud -f list_nodes_min my-tencentcloud-config
    '''
    if call == 'action':
        raise SaltCloudSystemExit(
            'The list_nodes_min function must be called with -f or --function.'
        )

    ret = {}
    nodes = _get_nodes()
    for instance in nodes:
        ret[instance.InstanceName] = {
            "InstanceId": instance.InstanceId,
            "InstanceState": instance.InstanceState,
        }

    return ret


def create(vm_):
    '''
    Create a single Tencent Cloud instance from a data dict.

    Tencent Cloud profiles require a ``provider``, ``availability_zone``, ``image`` and ``size``.
    Set up profile at ``/etc/salt/cloud.profiles`` or ``/etc/salt/cloud.profiles.d/*.conf``:

    .. code-block:: yaml

        tencentcloud-guangzhou-s1sm1:
            provider: my-tencentcloud-config
            availability_zone: ap-guangzhou-3
            image: img-31tjrtph
            size: S1.SMALL1
            allocate_public_ip: True
            internet_max_bandwidth_out: 1
            password: '153e41ec96140152'
            securitygroups:
                - sg-5e90804b

    CLI Examples:

    .. code-block:: bash

        salt-cloud -p tencentcloud-guangzhou-s1 myinstance
    '''
    try:
        # Check for required profile parameters before sending any API calls.
        if vm_['profile'] and \
            config.is_profile_configured(__opts__,
                                         __active_provider_name__ or 'tencentcloud',
                                         vm_['profile'],
                                         vm_=vm_) is False:
            return False
    except AttributeError:
        pass

    __utils__['cloud.fire_event'](
        'event',
        'starting create',
        'salt/cloud/{0}/creating'.format(vm_['name']),
        args=__utils__['cloud.filter_event'](
            'creating', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    log.debug('Try creating instance: %s', pprint.pformat(vm_))

    # Init cvm client
    client = get_provider_client("cvm_client")
    req = cvm_models.RunInstancesRequest()
    req.InstanceName = vm_['name']

    # Required parameters
    req.InstanceType = __get_size(vm_)
    req.ImageId = __get_image(vm_)

    zone = __get_availability_zone(vm_)
    projectId = vm_.get("project_id", 0)
    req.Placement = {"Zone": zone, "ProjectId": projectId}

    # Optional parameters

    req.SecurityGroupIds = __get_securitygroups(vm_)
    req.HostName = vm_.get("hostname", vm_['name'])

    req.InstanceChargeType = vm_.get(
        "instance_charge_type", "POSTPAID_BY_HOUR")
    if req.InstanceChargeType == "PREPAID":
        period = vm_.get(
            "instance_charge_type_prepaid_period", 1)
        renewFlag = vm_.get("instance_charge_type_prepaid_renew_flag",
                            "NOTIFY_AND_MANUAL_RENEW")
        req.InstanceChargePrepaid = {"Period": period, "RenewFlag": renewFlag}

    allocate_public_ip = vm_.get("allocate_public_ip", False)
    internet_max_bandwidth_out = vm_.get("internet_max_bandwidth_out", 0)
    if allocate_public_ip and internet_max_bandwidth_out > 0:
        req.InternetAccessible = {"PublicIpAssigned": allocate_public_ip,
                                  "InternetMaxBandwidthOut": internet_max_bandwidth_out}
        internet_charge_type = vm_.get("internet_charge_type", "")
        if internet_charge_type != "":
            req.InternetAccessible["InternetChargeType"] = internet_charge_type

    req.LoginSettings = {}
    req.VirtualPrivateCloud = {}
    req.SystemDisk = {}

    keyId = vm_.get("key_name", "")
    if keyId:
        req.LoginSettings["KeyIds"] = [keyId]

    password = vm_.get("password", "")
    if password:
        req.LoginSettings["Password"] = password

    private_ip = vm_.get("private_ip", "")
    if private_ip:
        req.VirtualPrivateCloud["PrivateIpAddresses"] = private_ip

    vpc_id = vm_.get("vpc_id", "")
    if vpc_id:
        req.VirtualPrivateCloud["VpcId"] = vpc_id

    subnetId = vm_.get("subnet_id", "")
    if subnetId:
        req.VirtualPrivateCloud["SubnetId"] = subnetId

    system_disk_size = vm_.get("system_disk_size", 0)
    if system_disk_size:
        req.SystemDisk["DiskSize"] = system_disk_size

    system_disk_type = vm_.get("system_disk_type", "")
    if system_disk_type:
        req.SystemDisk["DiskType"] = system_disk_type

    __utils__['cloud.fire_event'](
        'event',
        'requesting instance',
        'salt/cloud/{0}/requesting'.format(vm_['name']),
        args=__utils__['cloud.filter_event'](
            'requesting', vm_, list(vm_)),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    try:
        resp = client.RunInstances(req)
        if not resp.InstanceIdSet:
            raise SaltCloudSystemExit(
                "Unexpected error, no instance created"
            )
    except Exception as exc:
        log.error(
            'Error creating %s on tencentcloud\n\n'
            'The following exception was thrown when trying to '
            'run the initial deployment: %s',
            vm_['name'], six.text_type(exc),
            # Show the traceback if the debug logging level is enabled
            exc_info_on_loglevel=logging.DEBUG
        )
        return False

    time.sleep(5)

    def __query_node_data(vm_name):
        data = show_instance(vm_name, call='action')
        if not data:
            return False
        if data["InstanceState"] != "RUNNING":
            return False
        if data["PrivateIpAddresses"]:
            return data

    try:
        data = salt.utils.cloud.wait_for_ip(
            __query_node_data,
            update_args=(vm_['name'],),
            timeout=config.get_cloud_config_value(
                'wait_for_ip_timeout', vm_, __opts__, default=10 * 60),
            interval=config.get_cloud_config_value(
                'wait_for_ip_interval', vm_, __opts__, default=10),
        )
    except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc:
        try:
            destroy(vm_['name'])
        except SaltCloudSystemExit:
            pass
        finally:
            raise SaltCloudSystemExit(six.text_type(exc))

    if data["PublicIpAddresses"]:
        ssh_ip = data["PublicIpAddresses"][0]
    elif data["PrivateIpAddresses"]:
        ssh_ip = data["PrivateIpAddresses"][0]
    else:
        log.error('No available ip: cant connect to salt')
        return False

    log.debug('Instance %s: %s is now running', vm_['name'], ssh_ip)
    vm_['ssh_host'] = ssh_ip

    # The instance is booted and accessible, let's Salt it!
    ret = __utils__['cloud.bootstrap'](vm_, __opts__)
    ret.update(data)

    log.debug('\'%s\' instance creation details:\n%s',
              vm_['name'], pprint.pformat(data))

    __utils__['cloud.fire_event'](
        'event',
        'created instance',
        'salt/cloud/{0}/created'.format(vm_['name']),
        args=__utils__['cloud.filter_event'](
            'created', vm_, ['name', 'profile', 'provider', 'driver']),
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    return ret


def start(name, call=None):
    '''
    Start a Tencent Cloud instance
    Notice: the instance state must be stopped

    CLI Examples:

    .. code-block:: bash

        salt-cloud -a start myinstance
    '''
    if call != 'action':
        raise SaltCloudSystemExit(
            'The stop action must be called with -a or --action.'
        )

    node = _get_node(name)

    client = get_provider_client("cvm_client")
    req = cvm_models.StartInstancesRequest()
    req.InstanceIds = [node.InstanceId]
    resp = client.StartInstances(req)

    return resp


def stop(name, force=False, call=None):
    '''
    Stop a Tencent Cloud running instance
    Note: use `force=True` to make force stop

    CLI Examples:

    .. code-block:: bash

        salt-cloud -a stop myinstance
        salt-cloud -a stop myinstance force=True
    '''
    if call != 'action':
        raise SaltCloudSystemExit(
            'The stop action must be called with -a or --action.'
        )

    node = _get_node(name)

    client = get_provider_client("cvm_client")
    req = cvm_models.StopInstancesRequest()
    req.InstanceIds = [node.InstanceId]
    if force:
        req.ForceStop = "TRUE"
    resp = client.StopInstances(req)

    return resp


def reboot(name, call=None):
    '''
    Reboot a Tencent Cloud instance

    CLI Examples:

    .. code-block:: bash

        salt-cloud -a reboot myinstance
    '''
    if call != 'action':
        raise SaltCloudSystemExit(
            'The stop action must be called with -a or --action.'
        )

    node = _get_node(name)

    client = get_provider_client("cvm_client")
    req = cvm_models.RebootInstancesRequest()
    req.InstanceIds = [node.InstanceId]
    resp = client.RebootInstances(req)

    return resp


def destroy(name, call=None):
    '''
    Destroy a Tencent Cloud instance

    CLI Example:

    .. code-block:: bash

        salt-cloud -a destroy myinstance
        salt-cloud -d myinstance
    '''
    if call == 'function':
        raise SaltCloudSystemExit(
            'The destroy action must be called with -d, --destroy, -a or --action.'
        )

    __utils__['cloud.fire_event'](
        'event',
        'destroying instance',
        'salt/cloud/{0}/destroying'.format(name),
        args={'name': name},
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    node = _get_node(name)

    client = get_provider_client("cvm_client")
    req = cvm_models.TerminateInstancesRequest()
    req.InstanceIds = [node.InstanceId]
    resp = client.TerminateInstances(req)

    __utils__['cloud.fire_event'](
        'event',
        'destroyed instance',
        'salt/cloud/{0}/destroyed'.format(name),
        args={'name': name},
        sock_dir=__opts__['sock_dir'],
        transport=__opts__['transport']
    )

    return resp


def script(vm_):
    '''
    Return the script deployment object
    '''
    return salt.utils.cloud.os_script(
        config.get_cloud_config_value('script', vm_, __opts__),
        vm_,
        __opts__,
        salt.utils.cloud.salt_config_to_yaml(
            salt.utils.cloud.minion_config(__opts__, vm_)
        )
    )


def show_image(kwargs, call=None):
    '''
    Show the details of Tencent Cloud image

    CLI Examples:

    .. code-block:: bash

        salt-cloud -f show_image tencentcloud image=img-31tjrtph
    '''
    if call != 'function':
        raise SaltCloudSystemExit(
            'The show_image function must be called with -f or --function'
        )

    if not isinstance(kwargs, dict):
        kwargs = {}

    if 'image' not in kwargs:
        raise SaltCloudSystemExit('No image specified.')

    image = kwargs['image']

    client = get_provider_client("cvm_client")
    req = cvm_models.DescribeImagesRequest()
    req.ImageIds = [image]
    resp = client.DescribeImages(req)

    if not resp.ImageSet:
        raise SaltCloudNotFound(
            'The specified image \'{0}\' could not be found.'.format(image)
        )

    ret = {}
    for image in resp.ImageSet:
        ret[image.ImageId] = {
            "ImageName": image.ImageName,
            "ImageType": image.ImageType,
            "ImageSource": image.ImageSource,
            "Platform": image.Platform,
            "Architecture": image.Architecture,
            "ImageSize": "{0}GB".format(image.ImageSize),
            "ImageState": image.ImageState,
        }

    return ret


def show_instance(name, call=None):
    '''
    Show the details of Tencent Cloud instance

    CLI Examples:

    .. code-block:: bash

        salt-cloud -a show_instance myinstance
    '''
    if call != 'action':
        raise SaltCloudSystemExit(
            'The show_instance action must be called with -a or --action.'
        )

    node = _get_node(name)
    ret = vars(node)
    for k in ["DataDisks", "InternetAccessible", "LoginSettings",
              "Placement", "SystemDisk", "Tags", "VirtualPrivateCloud"]:
        ret[k] = six.text_type(ret[k])

    return ret


def show_disk(name, call=None):
    '''
    Show the disk details of Tencent Cloud instance

    CLI Examples:

    .. code-block:: bash

        salt-cloud -a show_disk myinstance
    '''
    if call != 'action':
        raise SaltCloudSystemExit(
            'The show_disks action must be called with -a or --action.'
        )

    node = _get_node(name)

    ret = {}
    ret[node.SystemDisk.DiskId] = {
        "SystemDisk": True,
        "DiskSize": node.SystemDisk.DiskSize,
        "DiskType": node.SystemDisk.DiskType,
        "DeleteWithInstance": True,
        "SnapshotId": "",
    }

    if node.DataDisks:
        for disk in node.DataDisks:
            ret[disk.DiskId] = {
                "SystemDisk": False,
                "DiskSize": disk.DiskSize,
                "DiskType": disk.DiskType,
                "DeleteWithInstance": disk.DeleteWithInstance,
                "SnapshotId": disk.SnapshotId,
            }

    return ret


def _get_node(name):
    '''
    Return Tencent Cloud instance detail by name
    '''
    attempts = 5
    while attempts >= 0:
        try:
            client = get_provider_client("cvm_client")
            req = cvm_models.DescribeInstancesRequest()
            req.Filters = [{"Name": "instance-name", "Values": [name]}]
            resp = client.DescribeInstances(req)
            return resp.InstanceSet[0]
        except Exception as ex:
            attempts -= 1
            log.debug(
                'Failed to get data for node \'%s\': %s. Remaining attempts: %d', name, ex, attempts
            )
            time.sleep(0.5)

    raise SaltCloudNotFound(
        'Failed to get instance info {0}'.format(name)
    )


def _get_nodes():
    '''
    Return all list of Tencent Cloud instances
    '''
    ret = []
    offset = 0
    limit = 100

    while True:
        client = get_provider_client("cvm_client")
        req = cvm_models.DescribeInstancesRequest()
        req.Offset = offset
        req.Limit = limit
        resp = client.DescribeInstances(req)
        for v in resp.InstanceSet:
            ret.append(v)
        if len(ret) >= resp.TotalCount:
            break
        offset += len(resp.InstanceSet)

    return ret


def _get_images(image_type):
    '''
    Return all list of Tencent Cloud images
    '''
    client = get_provider_client("cvm_client")
    req = cvm_models.DescribeImagesRequest()
    req.Filters = [{"Name": "image-type", "Values": image_type}]
    req.Offset = 0
    req.Limit = 100
    resp = client.DescribeImages(req)

    ret = {}
    for image in resp.ImageSet:
        if image.ImageState != "NORMAL":
            continue
        ret[image.ImageId] = {
            "ImageName": image.ImageName,
            "ImageType": image.ImageType,
            "ImageSource": image.ImageSource,
            "Platform": image.Platform,
            "Architecture": image.Architecture,
            "ImageSize": "{0}GB".format(image.ImageSize),
        }

    return ret


def __get_image(vm_):
    vm_image = six.text_type(config.get_cloud_config_value(
        'image', vm_, __opts__, search_global=False
    ))

    if not vm_image:
        raise SaltCloudNotFound('No image specified.')

    images = avail_images()
    if vm_image in images:
        return vm_image

    raise SaltCloudNotFound(
        'The specified image \'{0}\' could not be found.'.format(vm_image)
    )


def __get_size(vm_):
    vm_size = six.text_type(config.get_cloud_config_value(
        'size', vm_, __opts__, search_global=False
    ))

    if not vm_size:
        raise SaltCloudNotFound('No size specified.')

    sizes = avail_sizes()
    if vm_size in sizes:
        return vm_size

    raise SaltCloudNotFound(
        'The specified size \'{0}\' could not be found.'.format(vm_size)
    )


def __get_securitygroups(vm_):
    vm_securitygroups = config.get_cloud_config_value(
        'securitygroups', vm_, __opts__, search_global=False
    )

    if not vm_securitygroups:
        return []

    securitygroups = list_securitygroups()
    for i in range(len(vm_securitygroups)):
        vm_securitygroups[i] = six.text_type(vm_securitygroups[i])
        if vm_securitygroups[i] not in securitygroups:
            raise SaltCloudNotFound(
                'The specified securitygroups \'{0}\' could not be found.'.format(
                    vm_securitygroups[i]
                )
            )

    return vm_securitygroups


def __get_availability_zone(vm_):
    vm_availability_zone = six.text_type(config.get_cloud_config_value(
        'availability_zone', vm_, __opts__, search_global=False
    ))

    if not vm_availability_zone:
        raise SaltCloudNotFound('No availability_zone specified.')

    availability_zones = list_availability_zones()
    if vm_availability_zone in availability_zones:
        return vm_availability_zone

    raise SaltCloudNotFound(
        'The specified availability_zone \'{0}\' could not be found.'.format(
            vm_availability_zone
        )
    )


def __get_location(vm_):
    '''
    Return the Tencent Cloud region to use, in this order:
        - CLI parameter
        - VM parameter
        - Cloud profile setting
    '''
    vm_location = six.text_type(__opts__.get(
        'location',
        config.get_cloud_config_value(
            'location',
            vm_ or get_configured_provider(),
            __opts__,
            default=DEFAULT_REGION,
            search_global=False
        )
    ))

    if not vm_location:
        raise SaltCloudNotFound('No location specified.')

    return vm_location