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/packet.py |
""" Packet Cloud Module Using Packet's Python API Client ==================================================== The Packet cloud module is used to control access to the Packet VPS system. Use of this module only requires the ``token`` parameter. Set up the cloud configuration at ``/etc/salt/cloud.providers`` or ``/etc/salt/cloud.providers.d/packet.conf``: The Packet profile requires ``size``, ``image``, ``location``, ``project_id`` Optional profile parameters: - ``storage_size`` - min value is 10, defines Gigabytes of storage that will be attached to device. - ``storage_tier`` - storage_1 - Standard Plan, storage_2 - Performance Plan - ``snapshot_count`` - int - ``snapshot_frequency`` - string - possible values: - 1min - 15min - 1hour - 1day - 1week - 1month - 1year This driver requires Packet's client library: https://pypi.python.org/pypi/packet-python .. code-block:: yaml packet-provider: minion: master: 192.168.50.10 driver: packet token: ewr23rdf35wC8oNjJrhmHa87rjSXzJyi private_key: /root/.ssh/id_rsa packet-profile: provider: packet-provider size: baremetal_0 image: ubuntu_16_04_image location: ewr1 project_id: a64d000b-d47c-4d26-9870-46aac43010a6 storage_size: 10 storage_tier: storage_1 storage_snapshot_count: 1 storage_snapshot_frequency: 15min """ import logging import pprint import time import salt.config as config import salt.utils.cloud from salt.cloud.libcloudfuncs import get_image, get_size, script, show_instance from salt.exceptions import SaltCloudException, SaltCloudSystemExit from salt.utils.functools import namespaced_function try: import packet HAS_PACKET = True except ImportError: HAS_PACKET = False get_size = namespaced_function(get_size, globals()) get_image = namespaced_function(get_image, globals()) script = namespaced_function(script, globals()) show_instance = namespaced_function(show_instance, globals()) # Get logging started log = logging.getLogger(__name__) __virtualname__ = "packet" # Only load this module if the Packet configuration is in place. def __virtual__(): """ Check for Packet configs. """ if HAS_PACKET is False: return False, "The packet python library is not installed" if get_configured_provider() 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__, ("token",) ) def avail_images(call=None): """ Return available Packet os images. CLI Example: .. code-block:: bash salt-cloud --list-images packet-provider salt-cloud -f avail_images packet-provider """ if call == "action": raise SaltCloudException( "The avail_images function must be called with -f or --function." ) ret = {} vm_ = get_configured_provider() manager = packet.Manager(auth_token=vm_["token"]) ret = {} for os_system in manager.list_operating_systems(): ret[os_system.name] = os_system.__dict__ return ret def avail_locations(call=None): """ Return available Packet datacenter locations. CLI Example: .. code-block:: bash salt-cloud --list-locations packet-provider salt-cloud -f avail_locations packet-provider """ if call == "action": raise SaltCloudException( "The avail_locations function must be called with -f or --function." ) vm_ = get_configured_provider() manager = packet.Manager(auth_token=vm_["token"]) ret = {} for facility in manager.list_facilities(): ret[facility.name] = facility.__dict__ return ret def avail_sizes(call=None): """ Return available Packet sizes. CLI Example: .. code-block:: bash salt-cloud --list-sizes packet-provider salt-cloud -f avail_sizes packet-provider """ if call == "action": raise SaltCloudException( "The avail_locations function must be called with -f or --function." ) vm_ = get_configured_provider() manager = packet.Manager(auth_token=vm_["token"]) ret = {} for plan in manager.list_plans(): ret[plan.name] = plan.__dict__ return ret def avail_projects(call=None): """ Return available Packet projects. CLI Example: .. code-block:: bash salt-cloud -f avail_projects packet-provider """ if call == "action": raise SaltCloudException( "The avail_projects function must be called with -f or --function." ) vm_ = get_configured_provider() manager = packet.Manager(auth_token=vm_["token"]) ret = {} for project in manager.list_projects(): ret[project.name] = project.__dict__ return ret def _wait_for_status(status_type, object_id, status=None, timeout=500, quiet=True): """ Wait for a certain status from Packet. status_type device or volume object_id The ID of the Packet device or volume to wait on. Required. status The status to wait for. timeout The amount of time to wait for a status to update. quiet Log status updates to debug logs when False. Otherwise, logs to info. """ if status is None: status = "ok" interval = 5 iterations = int(timeout / interval) vm_ = get_configured_provider() manager = packet.Manager(auth_token=vm_["token"]) for i in range(0, iterations): get_object = getattr(manager, f"get_{status_type}") obj = get_object(object_id) if obj.state == status: return obj time.sleep(interval) log.log( logging.INFO if not quiet else logging.DEBUG, "Status for Packet %s is '%s', waiting for '%s'.", object_id, obj.state, status, ) return obj def is_profile_configured(vm_): 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 __virtualname__, vm_["profile"], vm_=vm_, ) is False ): return False alias, driver = _get_active_provider_name().split(":") profile_data = __opts__["providers"][alias][driver]["profiles"][vm_["profile"]] if profile_data.get("storage_size") or profile_data.get("storage_tier"): required_keys = ["storage_size", "storage_tier"] for key in required_keys: if profile_data.get(key) is None: log.error( "both storage_size and storage_tier required for " "profile %s. Please check your profile configuration", vm_["profile"], ) return False locations = avail_locations() for location in locations.values(): if location["code"] == profile_data["location"]: if "storage" not in location["features"]: log.error( "Chosen location %s for profile %s does not " "support storage feature. Please check your " "profile configuration", location["code"], vm_["profile"], ) return False if profile_data.get("storage_snapshot_count") or profile_data.get( "storage_snapshot_frequency" ): required_keys = ["storage_size", "storage_tier"] for key in required_keys: if profile_data.get(key) is None: log.error( "both storage_snapshot_count and " "storage_snapshot_frequency required for profile " "%s. Please check your profile configuration", vm_["profile"], ) return False except AttributeError: pass return True def create(vm_): """ Create a single Packet VM. """ name = vm_["name"] if not is_profile_configured(vm_): return False __utils__["cloud.fire_event"]( "event", "starting create", f"salt/cloud/{name}/creating", args=__utils__["cloud.filter_event"]( "creating", vm_, ["name", "profile", "provider", "driver"] ), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) log.info("Creating Packet VM %s", name) manager = packet.Manager(auth_token=vm_["token"]) __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{}/requesting".format(vm_["name"]), args=__utils__["cloud.filter_event"]( "requesting", vm_, ["name", "profile", "provider", "driver"] ), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) device = manager.create_device( project_id=vm_["project_id"], hostname=name, plan=vm_["size"], facility=vm_["location"], operating_system=vm_["image"], ) device = _wait_for_status("device", device.id, status="active") if device.state != "active": log.error( "Error creating %s on PACKET\n\nwhile waiting for initial ready status", name, exc_info_on_loglevel=logging.DEBUG, ) # Define which ssh_interface to use ssh_interface = _get_ssh_interface(vm_) # Pass the correct IP address to the bootstrap ssh_host key if ssh_interface == "private_ips": for ip in device.ip_addresses: if ip["public"] is False: vm_["ssh_host"] = ip["address"] break else: for ip in device.ip_addresses: if ip["public"] is True: vm_["ssh_host"] = ip["address"] break key_filename = config.get_cloud_config_value( "private_key", vm_, __opts__, search_global=False, default=None ) vm_["key_filename"] = key_filename vm_["private_key"] = key_filename # Bootstrap! ret = __utils__["cloud.bootstrap"](vm_, __opts__) ret.update({"device": device.__dict__}) if vm_.get("storage_tier") and vm_.get("storage_size"): # create storage and attach it to device volume = manager.create_volume( vm_["project_id"], f"{name}_storage", vm_.get("storage_tier"), vm_.get("storage_size"), vm_.get("location"), snapshot_count=vm_.get("storage_snapshot_count", 0), snapshot_frequency=vm_.get("storage_snapshot_frequency"), ) volume.attach(device.id) volume = _wait_for_status("volume", volume.id, status="active") if volume.state != "active": log.error( "Error creating %s on PACKET\n\nwhile waiting for initial ready status", name, exc_info_on_loglevel=logging.DEBUG, ) ret.update({"volume": volume.__dict__}) log.info("Created Cloud VM '%s'", name) log.debug("'%s' VM creation details:\n%s", name, pprint.pformat(device.__dict__)) __utils__["cloud.fire_event"]( "event", "created instance", f"salt/cloud/{name}/created", args=__utils__["cloud.filter_event"]( "created", vm_, ["name", "profile", "provider", "driver"] ), sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) return ret def list_nodes_full(call=None): """ List devices, with all available information. CLI Example: .. code-block:: bash salt-cloud -F salt-cloud --full-query salt-cloud -f list_nodes_full packet-provider .. """ if call == "action": raise SaltCloudException( "The list_nodes_full function must be called with -f or --function." ) ret = {} for device in get_devices_by_token(): ret[device.hostname] = device.__dict__ return ret def list_nodes_min(call=None): """ Return a list of the VMs that are on the provider. Only a list of VM names and their state is returned. This is the minimum amount of information needed to check for existing VMs. .. versionadded:: 2015.8.0 CLI Example: .. code-block:: bash salt-cloud -f list_nodes_min packet-provider salt-cloud --function list_nodes_min packet-provider """ if call == "action": raise SaltCloudSystemExit( "The list_nodes_min function must be called with -f or --function." ) ret = {} for device in get_devices_by_token(): ret[device.hostname] = {"id": device.id, "state": device.state} return ret def list_nodes_select(call=None): """ Return a list of the VMs that are on the provider, with select fields. """ return salt.utils.cloud.list_nodes_select( list_nodes_full(), __opts__["query.selection"], call, ) def get_devices_by_token(): vm_ = get_configured_provider() manager = packet.Manager(auth_token=vm_["token"]) devices = [] for profile_name in vm_["profiles"]: profile = vm_["profiles"][profile_name] devices.extend(manager.list_devices(profile["project_id"])) return devices def list_nodes(call=None): """ Returns a list of devices, keeping only a brief listing. CLI Example: .. code-block:: bash salt-cloud -Q salt-cloud --query salt-cloud -f list_nodes packet-provider .. """ if call == "action": raise SaltCloudException( "The list_nodes function must be called with -f or --function." ) ret = {} for device in get_devices_by_token(): ret[device.hostname] = device.__dict__ return ret def destroy(name, call=None): """ Destroys a Packet device by name. name The hostname of VM to be be destroyed. CLI Example: .. code-block:: bash salt-cloud -d name """ if call == "function": raise SaltCloudException( "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"], ) vm_ = get_configured_provider() manager = packet.Manager(auth_token=vm_["token"]) nodes = list_nodes_min() node = nodes[name] for project in manager.list_projects(): for volume in manager.list_volumes(project.id): if volume.attached_to == node["id"]: volume.detach() volume.delete() break manager.call_api("devices/{id}".format(id=node["id"]), type="DELETE") __utils__["cloud.fire_event"]( "event", "destroyed instance", f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) return {} def _get_ssh_interface(vm_): """ Return the ssh_interface type to connect to. Either 'public_ips' (default) or 'private_ips'. """ return config.get_cloud_config_value( "ssh_interface", vm_, __opts__, default="public_ips", search_global=False )