mirror of
https://github.com/saltstack/salt.git
synced 2025-04-10 23:01:39 +00:00
1042 lines
27 KiB
Python
1042 lines
27 KiB
Python
"""
|
|
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
|
|
"""
|
|
|
|
import logging
|
|
import pprint
|
|
import time
|
|
|
|
import salt.config as config
|
|
import salt.utils.cloud
|
|
import salt.utils.data
|
|
import salt.utils.json
|
|
from salt.exceptions import (
|
|
SaltCloudExecutionFailure,
|
|
SaltCloudExecutionTimeout,
|
|
SaltCloudNotFound,
|
|
SaltCloudSystemExit,
|
|
)
|
|
|
|
try:
|
|
# Try import tencentcloud sdk
|
|
from tencentcloud.common import credential # pylint: disable=no-name-in-module
|
|
|
|
# pylint: disable=no-name-in-module
|
|
from tencentcloud.common.profile.client_profile import ClientProfile
|
|
from tencentcloud.cvm.v20170312 import cvm_client
|
|
from tencentcloud.cvm.v20170312 import models as cvm_models
|
|
from tencentcloud.vpc.v20170312 import models as vpc_models
|
|
from tencentcloud.vpc.v20170312 import vpc_client
|
|
|
|
# pylint: enable=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_active_provider_name():
|
|
try:
|
|
return __active_provider_name__.value()
|
|
except AttributeError:
|
|
return __active_provider_name__
|
|
|
|
|
|
def get_configured_provider():
|
|
"""
|
|
Return the first configured instance.
|
|
"""
|
|
return config.is_provider_configured(
|
|
__opts__, _get_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(f"Client name {name} is not supported")
|
|
|
|
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": f"{typeConfig.Memory}GB",
|
|
"CPU": f"{typeConfig.CPU}-Core",
|
|
}
|
|
if typeConfig.GPU:
|
|
ret[typeConfig.InstanceType]["GPU"] = f"{typeConfig.GPU}-Core"
|
|
|
|
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] = str(instanceAttribute[k])
|
|
|
|
provider = _get_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__,
|
|
_get_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/{}/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/{}/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: # pylint: disable=broad-except
|
|
log.error(
|
|
"Error creating %s on tencentcloud\n\n"
|
|
"The following exception was thrown when trying to "
|
|
"run the initial deployment: %s",
|
|
vm_["name"],
|
|
str(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(str(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/{}/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",
|
|
f"salt/cloud/{name}/destroying",
|
|
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",
|
|
f"salt/cloud/{name}/destroyed",
|
|
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(f"The specified image '{image}' could not be found.")
|
|
|
|
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": f"{image.ImageSize}GB",
|
|
"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] = str(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: # pylint: disable=broad-except
|
|
attempts -= 1
|
|
log.debug(
|
|
"Failed to get data for node '%s': %s. Remaining attempts: %d",
|
|
name,
|
|
ex,
|
|
attempts,
|
|
)
|
|
time.sleep(0.5)
|
|
|
|
raise SaltCloudNotFound(f"Failed to get instance info {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": f"{image.ImageSize}GB",
|
|
}
|
|
|
|
return ret
|
|
|
|
|
|
def __get_image(vm_):
|
|
vm_image = str(
|
|
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(f"The specified image '{vm_image}' could not be found.")
|
|
|
|
|
|
def __get_size(vm_):
|
|
vm_size = str(
|
|
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(f"The specified size '{vm_size}' could not be found.")
|
|
|
|
|
|
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 idx, value in enumerate(vm_securitygroups):
|
|
vm_securitygroups[idx] = str(value)
|
|
if vm_securitygroups[idx] not in securitygroups:
|
|
raise SaltCloudNotFound(
|
|
"The specified securitygroups '{}' could not be found.".format(
|
|
vm_securitygroups[idx]
|
|
)
|
|
)
|
|
|
|
return vm_securitygroups
|
|
|
|
|
|
def __get_availability_zone(vm_):
|
|
vm_availability_zone = str(
|
|
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 '{}' 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 = str(
|
|
__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
|