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/softlayer_hw.py |
""" SoftLayer HW Cloud Module ========================= The SoftLayer HW cloud module is used to control access to the SoftLayer hardware cloud system Use of this module only requires the ``apikey`` parameter. Set up the cloud configuration at: ``/etc/salt/cloud.providers`` or ``/etc/salt/cloud.providers.d/softlayer.conf``: .. code-block:: yaml my-softlayer-config: # SoftLayer account api key user: MYLOGIN apikey: JVkbSJDGHSDKUKSDJfhsdklfjgsjdkflhjlsdfffhgdgjkenrtuinv driver: softlayer_hw The SoftLayer Python Library needs to be installed in order to use the SoftLayer salt.cloud modules. See: https://pypi.python.org/pypi/SoftLayer :depends: softlayer """ import decimal import logging import time import salt.config as config import salt.utils.cloud from salt.exceptions import SaltCloudSystemExit # Attempt to import softlayer lib try: import SoftLayer HAS_SLLIBS = True except ImportError: HAS_SLLIBS = False # Get logging started log = logging.getLogger(__name__) __virtualname__ = "softlayer_hw" # Only load in this module if the SoftLayer configurations are in place def __virtual__(): """ Check for SoftLayer configurations. """ 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__, ("apikey",) ) def get_dependencies(): """ Warn if dependencies aren't met. """ return config.check_driver_dependencies(__virtualname__, {"softlayer": HAS_SLLIBS}) def script(vm_): """ Return the script deployment object """ deploy_script = 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_) ), ) return deploy_script def get_conn(service="SoftLayer_Hardware"): """ Return a conn object for the passed VM data """ client = SoftLayer.Client( username=config.get_cloud_config_value( "user", get_configured_provider(), __opts__, search_global=False ), api_key=config.get_cloud_config_value( "apikey", get_configured_provider(), __opts__, search_global=False ), ) return client[service] def avail_locations(call=None): """ List all available locations """ if call == "action": raise SaltCloudSystemExit( "The avail_locations function must be called with " "-f or --function, or with the --list-locations option" ) ret = {} conn = get_conn(service="SoftLayer_Product_Package") locations = conn.getLocations(id=50) for location in locations: ret[location["id"]] = { "id": location["id"], "name": location["name"], "location": location["longName"], } available = conn.getAvailableLocations(id=50) for location in available: if location.get("isAvailable", 0) == 0: continue ret[location["locationId"]]["available"] = True return ret def avail_sizes(call=None): """ Return a dict of all available VM sizes on the cloud provider with relevant data. This data is provided in three dicts. """ if call == "action": raise SaltCloudSystemExit( "The avail_sizes function must be called with " "-f or --function, or with the --list-sizes option" ) ret = {} conn = get_conn(service="SoftLayer_Product_Package") for category in conn.getCategories(id=50): if category["categoryCode"] != "server_core": continue for group in category["groups"]: for price in group["prices"]: ret[price["id"]] = price["item"].copy() del ret[price["id"]]["id"] return ret def avail_images(call=None): """ Return a dict of all available VM images on the cloud provider. """ if call == "action": raise SaltCloudSystemExit( "The avail_images function must be called with " "-f or --function, or with the --list-images option" ) ret = {} conn = get_conn(service="SoftLayer_Product_Package") for category in conn.getCategories(id=50): if category["categoryCode"] != "os": continue for group in category["groups"]: for price in group["prices"]: ret[price["id"]] = price["item"].copy() del ret[price["id"]]["id"] return ret def get_location(vm_=None): """ Return the location to use, in this order: - CLI parameter - VM parameter - Cloud profile setting """ return __opts__.get( "location", config.get_cloud_config_value( "location", vm_ or get_configured_provider(), __opts__, # default=DEFAULT_LOCATION, search_global=False, ), ) 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 "softlayer_hw", vm_["profile"], vm_=vm_, ) is False ): return False except AttributeError: pass name = vm_["name"] hostname = name domain = config.get_cloud_config_value("domain", vm_, __opts__, default=None) if domain is None: raise SaltCloudSystemExit("A domain name is required for the SoftLayer driver.") if vm_.get("use_fqdn"): name = ".".join([name, domain]) vm_["name"] = name __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 Cloud VM %s", name) conn = get_conn(service="SoftLayer_Product_Order") kwargs = { "complexType": "SoftLayer_Container_Product_Order_Hardware_Server", "quantity": 1, "hardware": [{"hostname": hostname, "domain": domain}], # Baremetal Package "packageId": 50, "prices": [ # Size Ex: 1921: 2 x 2.0 GHz Core Bare Metal Instance - 2 GB Ram {"id": vm_["size"]}, # HDD Ex: 19: 250GB SATA II {"id": vm_["hdd"]}, # Image Ex: 13963: CentOS 6.0 - Minimal Install (64 bit) {"id": vm_["image"]}, # The following items are currently required # Reboot / Remote Console {"id": "905"}, # 1 IP Address {"id": "21"}, # Host Ping Monitoring {"id": "55"}, # Email and Ticket Notifications {"id": "57"}, # Automated Notification Response {"id": "58"}, # Unlimited SSL VPN Users & 1 PPTP VPN User per account {"id": "420"}, # Nessus Vulnerability Assessment & Reporting {"id": "418"}, ], } optional_products = config.get_cloud_config_value( "optional_products", vm_, __opts__, default=[] ) for product in optional_products: kwargs["prices"].append({"id": product}) # Default is 273 (100 Mbps Public & Private Networks) port_speed = config.get_cloud_config_value("port_speed", vm_, __opts__, default=273) kwargs["prices"].append({"id": port_speed}) # Default is 1800 (0 GB Bandwidth) bandwidth = config.get_cloud_config_value("bandwidth", vm_, __opts__, default=1800) kwargs["prices"].append({"id": bandwidth}) post_uri = config.get_cloud_config_value("post_uri", vm_, __opts__, default=None) if post_uri: kwargs["prices"].append({"id": post_uri}) vlan_id = config.get_cloud_config_value("vlan", vm_, __opts__, default=False) if vlan_id: kwargs["primaryNetworkComponent"] = {"networkVlan": {"id": vlan_id}} location = get_location(vm_) if location: kwargs["location"] = location __utils__["cloud.fire_event"]( "event", "requesting instance", f"salt/cloud/{name}/requesting", args={ "kwargs": __utils__["cloud.filter_event"]( "requesting", kwargs, list(kwargs) ), }, sock_dir=__opts__["sock_dir"], transport=__opts__["transport"], ) try: response = conn.placeOrder(kwargs) # Leaving the following line in, commented, for easy debugging # response = conn.verifyOrder(kwargs) except Exception as exc: # pylint: disable=broad-except log.error( "Error creating %s on SoftLayer\n\n" "The following exception was thrown when trying to " "run the initial deployment: \n%s", name, exc, # Show the traceback if the debug logging level is enabled exc_info_on_loglevel=logging.DEBUG, ) return False def wait_for_ip(): """ Wait for the IP address to become available """ nodes = list_nodes_full() if "primaryIpAddress" in nodes[hostname]: return nodes[hostname]["primaryIpAddress"] time.sleep(1) return False ip_address = salt.utils.cloud.wait_for_fun( wait_for_ip, timeout=config.get_cloud_config_value( "wait_for_fun_timeout", vm_, __opts__, default=15 * 60 ), ) ssh_connect_timeout = config.get_cloud_config_value( # 15 minutes "ssh_connect_timeout", vm_, __opts__, 900, ) if not salt.utils.cloud.wait_for_port(ip_address, timeout=ssh_connect_timeout): raise SaltCloudSystemExit("Failed to authenticate against remote ssh") pass_conn = get_conn(service="SoftLayer_Account") mask = { "virtualGuests": {"powerState": "", "operatingSystem": {"passwords": ""}}, } def get_passwd(): """ Wait for the password to become available """ node_info = pass_conn.getVirtualGuests(id=response["id"], mask=mask) for node in node_info: if ( node["id"] == response["id"] and "passwords" in node["operatingSystem"] and node["operatingSystem"]["passwords"] ): return node["operatingSystem"]["passwords"][0]["password"] time.sleep(5) return False passwd = salt.utils.cloud.wait_for_fun( get_passwd, timeout=config.get_cloud_config_value( "wait_for_fun_timeout", vm_, __opts__, default=15 * 60 ), ) response["password"] = passwd response["public_ip"] = ip_address ssh_username = config.get_cloud_config_value( "ssh_username", vm_, __opts__, default="root" ) vm_["ssh_host"] = ip_address vm_["password"] = passwd ret = __utils__["cloud.bootstrap"](vm_, __opts__) ret.update(response) __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( mask="mask[id, hostname, primaryIpAddress, primaryBackendIpAddress, processorPhysicalCoreAmount, memoryCount]", 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 = {} conn = get_conn(service="SoftLayer_Account") response = conn.getHardware(mask=mask) for node in response: ret[node["hostname"]] = node __utils__["cloud.cache_node_list"]( ret, _get_active_provider_name().split(":")[0], __opts__ ) 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 = {} nodes = list_nodes_full() if "error" in nodes: raise SaltCloudSystemExit( "An error occurred while listing nodes: {}".format( nodes["error"]["Errors"]["Error"]["Message"] ) ) for node in nodes: ret[node] = { "id": nodes[node]["hostname"], "ram": nodes[node]["memoryCount"], "cpus": nodes[node]["processorPhysicalCoreAmount"], } if "primaryIpAddress" in nodes[node]: ret[node]["public_ips"] = nodes[node]["primaryIpAddress"] if "primaryBackendIpAddress" in nodes[node]: ret[node]["private_ips"] = nodes[node]["primaryBackendIpAddress"] 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 show_instance(name, call=None): """ Show the details from SoftLayer concerning a guest """ if call != "action": raise SaltCloudSystemExit( "The show_instance action must be called with -a or --action." ) nodes = list_nodes_full() __utils__["cloud.cache_node"](nodes[name], _get_active_provider_name(), __opts__) return nodes[name] 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") conn = get_conn(service="SoftLayer_Ticket") response = conn.createCancelServerTicket( { "id": node["id"], "reason": "Salt Cloud Hardware Server Cancellation", "content": "Please cancel this server", "cancelAssociatedItems": True, "attachmentType": "HARDWARE", } ) __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 response def list_vlans(call=None): """ List all VLANs associated with the account """ if call != "function": raise SaltCloudSystemExit( "The list_vlans function must be called with -f or --function." ) conn = get_conn(service="SoftLayer_Account") return conn.getNetworkVlans() def show_pricing(kwargs=None, call=None): """ Show pricing for a particular profile. This is only an estimate, based on unofficial pricing sources. CLI Examples: .. code-block:: bash salt-cloud -f show_pricing my-softlayerhw-config profile=my-profile If pricing sources have not been cached, they will be downloaded. Once they have been cached, they will not be updated automatically. To manually update all prices, use the following command: .. code-block:: bash salt-cloud -f update_pricing <provider> .. versionadded:: 2015.8.0 """ profile = __opts__["profiles"].get(kwargs["profile"], {}) if not profile: return {"Error": "The requested profile was not found"} # Make sure the profile belongs to Softlayer HW provider = profile.get("provider", "0:0") comps = provider.split(":") if len(comps) < 2 or comps[1] != "softlayer_hw": return {"Error": "The requested profile does not belong to Softlayer HW"} raw = {} ret = {} ret["per_hour"] = 0 conn = get_conn(service="SoftLayer_Product_Item_Price") for item in profile: if item in ("profile", "provider", "location"): continue price = conn.getObject(id=profile[item]) raw[item] = price ret["per_hour"] += decimal.Decimal(price.get("hourlyRecurringFee", 0)) ret["per_day"] = ret["per_hour"] * 24 ret["per_week"] = ret["per_day"] * 7 ret["per_month"] = ret["per_day"] * 30 ret["per_year"] = ret["per_week"] * 52 if kwargs.get("raw", False): ret["_raw"] = raw return {profile["profile"]: ret} def show_all_prices(call=None, kwargs=None): """ Return a dict of all prices on the cloud provider. """ if call == "action": raise SaltCloudSystemExit( "The show_all_prices function must be called with -f or --function." ) if kwargs is None: kwargs = {} conn = get_conn(service="SoftLayer_Product_Package") if "code" not in kwargs: return conn.getCategories(id=50) ret = {} for category in conn.getCategories(id=50): if category["categoryCode"] != kwargs["code"]: continue for group in category["groups"]: for price in group["prices"]: ret[price["id"]] = price["item"].copy() del ret[price["id"]]["id"] return ret def show_all_categories(call=None): """ Return a dict of all available categories on the cloud provider. .. versionadded:: 2016.3.0 """ if call == "action": raise SaltCloudSystemExit( "The show_all_categories function must be called with -f or --function." ) conn = get_conn(service="SoftLayer_Product_Package") categories = [] for category in conn.getCategories(id=50): categories.append(category["categoryCode"]) return {"category_codes": categories}