PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/cloud/clouds/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : //proc/self/root/opt/saltstack/salt/lib/python3.10/site-packages/salt/cloud/clouds/tencentcloud.py |
""" 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