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/parallels.py |
""" Parallels Cloud Module ====================== The Parallels cloud module is used to control access to cloud providers using the Parallels VPS system. Set up the cloud configuration at ``/etc/salt/cloud.providers`` or ``/etc/salt/cloud.providers.d/parallels.conf``: .. code-block:: yaml my-parallels-config: # Parallels account information user: myuser password: mypassword url: https://api.cloud.xmission.com:4465/paci/v1.0/ driver: parallels """ import logging import pprint import time import urllib.parse import urllib.request import xml.etree.ElementTree as ET from urllib.error import URLError import salt.config as config import salt.utils.cloud from salt.exceptions import ( SaltCloudExecutionFailure, SaltCloudExecutionTimeout, SaltCloudNotFound, SaltCloudSystemExit, ) log = logging.getLogger(__name__) __virtualname__ = "parallels" # Only load in this module if the PARALLELS configurations are in place def __virtual__(): """ Check for PARALLELS configurations """ 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__, ( "user", "password", "url", ), ) def avail_images(call=None): """ Return a list of the images that are on the provider """ if call == "action": raise SaltCloudSystemExit( "The avail_images function must be called with " "-f or --function, or with the --list-images option" ) items = query(action="template") ret = {} for item in items: ret[item.attrib["name"]] = item.attrib return ret def list_nodes(call=None): """ Return a list of the VMs that are on the provider """ if call == "action": raise SaltCloudSystemExit( "The list_nodes function must be called with -f or --function." ) ret = {} items = query(action="ve") for item in items: name = item.attrib["name"] node = show_instance(name, call="action") ret[name] = { "id": node["id"], "image": node["platform"]["template-info"]["name"], "state": node["state"], } if "private-ip" in node["network"]: ret[name]["private_ips"] = [node["network"]["private-ip"]] if "public-ip" in node["network"]: ret[name]["public_ips"] = [node["network"]["public-ip"]] return ret def list_nodes_full(call=None): """ Return a list of the VMs that are on the provider """ if call == "action": raise SaltCloudSystemExit( "The list_nodes_full function must be called with -f or --function." ) ret = {} items = query(action="ve") for item in items: name = item.attrib["name"] node = show_instance(name, call="action") ret[name] = node ret[name]["image"] = node["platform"]["template-info"]["name"] if "private-ip" in node["network"]: ret[name]["private_ips"] = [node["network"]["private-ip"]["address"]] if "public-ip" in node["network"]: ret[name]["public_ips"] = [node["network"]["public-ip"]["address"]] 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_image(vm_): """ Return the image object to use """ images = avail_images() vm_image = config.get_cloud_config_value( "image", vm_, __opts__, search_global=False ) for image in images: if str(vm_image) in (images[image]["name"], images[image]["id"]): return images[image]["id"] raise SaltCloudNotFound("The specified image could not be found.") def create_node(vm_): """ Build and submit the XML to create a node """ # Start the tree content = ET.Element("ve") # Name of the instance name = ET.SubElement(content, "name") name.text = vm_["name"] # Description, defaults to name desc = ET.SubElement(content, "description") desc.text = config.get_cloud_config_value( "desc", vm_, __opts__, default=vm_["name"], search_global=False ) # How many CPU cores, and how fast they are cpu = ET.SubElement(content, "cpu") cpu.attrib["number"] = config.get_cloud_config_value( "cpu_number", vm_, __opts__, default="1", search_global=False ) cpu.attrib["power"] = config.get_cloud_config_value( "cpu_power", vm_, __opts__, default="1000", search_global=False ) # How many megabytes of RAM ram = ET.SubElement(content, "ram-size") ram.text = config.get_cloud_config_value( "ram", vm_, __opts__, default="256", search_global=False ) # Bandwidth available, in kbps bandwidth = ET.SubElement(content, "bandwidth") bandwidth.text = config.get_cloud_config_value( "bandwidth", vm_, __opts__, default="100", search_global=False ) # How many public IPs will be assigned to this instance ip_num = ET.SubElement(content, "no-of-public-ip") ip_num.text = config.get_cloud_config_value( "ip_num", vm_, __opts__, default="1", search_global=False ) # Size of the instance disk disk = ET.SubElement(content, "ve-disk") disk.attrib["local"] = "true" disk.attrib["size"] = config.get_cloud_config_value( "disk_size", vm_, __opts__, default="10", search_global=False ) # Attributes for the image vm_image = config.get_cloud_config_value( "image", vm_, __opts__, search_global=False ) image = show_image({"image": vm_image}, call="function") platform = ET.SubElement(content, "platform") template = ET.SubElement(platform, "template-info") template.attrib["name"] = vm_image os_info = ET.SubElement(platform, "os-info") os_info.attrib["technology"] = image[vm_image]["technology"] os_info.attrib["type"] = image[vm_image]["osType"] # Username and password admin = ET.SubElement(content, "admin") admin.attrib["login"] = config.get_cloud_config_value( "ssh_username", vm_, __opts__, default="root" ) admin.attrib["password"] = config.get_cloud_config_value( "password", vm_, __opts__, search_global=False ) data = ET.tostring(content, encoding="UTF-8") __utils__["cloud.fire_event"]( "event", "requesting instance", "salt/cloud/{}/requesting".format(vm_["name"]), args={ "kwargs": __utils__["cloud.filter_event"]("requesting", data, list(data)), }, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) node = query(action="ve", method="POST", data=data) return node def create(vm_): """ Create a single VM from a data dict """ 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 "parallels", 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.info("Creating Cloud VM %s", vm_["name"]) try: data = create_node(vm_) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating %s on PARALLELS\n\n" "The following exception was thrown when trying to " "run the initial deployment: \n%s", vm_["name"], exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) return False name = vm_["name"] if not wait_until(name, "CREATED"): return {"Error": f"Unable to start {name}, command timed out"} start(vm_["name"], call="action") if not wait_until(name, "STARTED"): return {"Error": f"Unable to start {name}, command timed out"} def __query_node_data(vm_name): data = show_instance(vm_name, call="action") if "public-ip" not in data["network"]: # Trigger another iteration return 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=5 * 60 ), interval=config.get_cloud_config_value( "wait_for_ip_interval", vm_, __opts__, default=5 ), ) except (SaltCloudExecutionTimeout, SaltCloudExecutionFailure) as exc: try: # It might be already up, let's destroy it! destroy(vm_["name"]) except SaltCloudSystemExit: pass finally: raise SaltCloudSystemExit(str(exc)) comps = data["network"]["public-ip"]["address"].split("/") public_ip = comps[0] vm_["ssh_host"] = public_ip ret = __utils__["cloud.bootstrap"](vm_, __opts__) log.info("Created Cloud VM '%s'", vm_["name"]) log.debug("'%s' VM 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 data def query(action=None, command=None, args=None, method="GET", data=None): """ Make a web call to a Parallels provider """ path = config.get_cloud_config_value( "url", get_configured_provider(), __opts__, search_global=False ) auth_handler = urllib.request.HTTPBasicAuthHandler() auth_handler.add_password( realm="Parallels Instance Manager", uri=path, user=config.get_cloud_config_value( "user", get_configured_provider(), __opts__, search_global=False ), passwd=config.get_cloud_config_value( "password", get_configured_provider(), __opts__, search_global=False ), ) opener = urllib.request.build_opener(auth_handler) urllib.request.install_opener(opener) if action: path += action if command: path += f"/{command}" if not type(args, dict): args = {} kwargs = {"data": data} if isinstance(data, str) and "<?xml" in data: kwargs["headers"] = { "Content-type": "application/xml", } if args: params = urllib.parse.urlencode(args) req = urllib.request.Request(url=f"{path}?{params}", **kwargs) else: req = urllib.request.Request(url=path, **kwargs) req.get_method = lambda: method log.debug("%s %s", method, req.get_full_url()) if data: log.debug(data) try: result = urllib.request.urlopen(req) log.debug("PARALLELS Response Status Code: %s", result.getcode()) if "content-length" in result.headers: content = result.read() result.close() items = ET.fromstring(content) return items return {} except URLError as exc: root = ET.fromstring(exc.read()) log.error("PARALLELS Response Status Code: %s %s\n%s", exc.code, exc.msg, root) return {"error": root} 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 from Parallels concerning an image """ if call != "function": raise SaltCloudSystemExit( "The show_image function must be called with -f or --function." ) items = query(action="template", command=kwargs["image"]) if "error" in items: return items["error"] ret = {} for item in items: ret.update({item.attrib["name"]: item.attrib}) return ret def show_instance(name, call=None): """ Show the details from Parallels concerning an instance """ if call != "action": raise SaltCloudSystemExit( "The show_instance action must be called with -a or --action." ) items = query(action="ve", command=name) ret = {} for item in items: if "text" in item.__dict__: ret[item.tag] = item.text else: ret[item.tag] = item.attrib if item._children: ret[item.tag] = {} children = item._children for child in children: ret[item.tag][child.tag] = child.attrib __utils__["cloud.cache_node"](ret, _get_active_provider_name(), __opts__) return ret def wait_until(name, state, timeout=300): """ Wait until a specific state has been reached on a node """ start_time = time.time() node = show_instance(name, call="action") while True: if node["state"] == state: return True time.sleep(1) if time.time() - start_time > timeout: return False node = show_instance(name, call="action") def destroy(name, call=None): """ Destroy a node. CLI Example: .. code-block:: bash salt-cloud --destroy mymachine """ 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 = show_instance(name, call="action") if node["state"] == "STARTED": stop(name, call="action") if not wait_until(name, "STOPPED"): return {"Error": f"Unable to destroy {name}, command timed out"} data = query(action="ve", command=name, method="DELETE") if "error" in data: return data["error"] __utils__["cloud.fire_event"]( "event", "destroyed instance", f"salt/cloud/{name}/destroyed", args={"name": name}, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) if __opts__.get("update_cachedir", False) is True: __utils__["cloud.delete_minion_cachedir"]( name, _get_active_provider_name().split(":")[0], __opts__ ) return {"Destroyed": f"{name} was destroyed."} def start(name, call=None): """ Start a node. CLI Example: .. code-block:: bash salt-cloud -a start mymachine """ if call != "action": raise SaltCloudSystemExit( "The show_instance action must be called with -a or --action." ) data = query(action="ve", command=f"{name}/start", method="PUT") if "error" in data: return data["error"] return {"Started": f"{name} was started."} def stop(name, call=None): """ Stop a node. CLI Example: .. code-block:: bash salt-cloud -a stop mymachine """ if call != "action": raise SaltCloudSystemExit( "The show_instance action must be called with -a or --action." ) data = query(action="ve", command=f"{name}/stop", method="PUT") if "error" in data: return data["error"] return {"Stopped": f"{name} was stopped."}