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/proxy/ |
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/proxy/cimc.py |
""" Proxy Minion interface module for managing Cisco Integrated Management Controller devices ========================================================================================= .. versionadded:: 2018.3.0 :codeauthor: ``Spencer Ervin <spencer_ervin@hotmail.com>`` :maturity: new :depends: none :platform: unix This proxy minion enables Cisco Integrated Management Controller devices (hereafter referred to as simply 'cimc' devices to be treated individually like a Salt Minion. The cimc proxy leverages the XML API functionality on the Cisco Integrated Management Controller. The Salt proxy must have access to the cimc on HTTPS (tcp/443). More in-depth conceptual reading on Proxy Minions can be found in the :ref:`Proxy Minion <proxy-minion>` section of Salt's documentation. Configuration ============= To use this integration proxy module, please configure the following: Pillar ------ Proxy minions get their configuration from Salt's Pillar. Every proxy must have a stanza in Pillar and a reference in the Pillar top-file that matches the ID. .. code-block:: yaml proxy: proxytype: cimc host: <ip or dns name of cimc host> username: <cimc username> password: <cimc password> verify_ssl: True proxytype ^^^^^^^^^ The ``proxytype`` key and value pair is critical, as it tells Salt which interface to load from the ``proxy`` directory in Salt's install hierarchy, or from ``/srv/salt/_proxy`` on the Salt Master (if you have created your own proxy module, for example). To use this cimc Proxy Module, set this to ``cimc``. host ^^^^ The location, or ip/dns, of the cimc host. Required. username ^^^^^^^^ The username used to login to the cimc host. Required. password ^^^^^^^^ The password used to login to the cimc host. Required. """ import logging import re import xml.etree.ElementTree as ET import salt.exceptions # This must be present or the Salt loader won't load this module. __proxyenabled__ = ["cimc"] # Variables are scoped to this module so we can have persistent data. GRAINS_CACHE = {"vendor": "Cisco"} DETAILS = {} # Set up logging log = logging.getLogger(__file__) # Define the module's virtual name __virtualname__ = "cimc" def __virtual__(): """ Only return if all the modules are available. """ return __virtualname__ def _validate_response_code(response_code_to_check, cookie_to_logout=None): formatted_response_code = str(response_code_to_check) if formatted_response_code not in ["200", "201", "202", "204"]: if cookie_to_logout: logout(cookie_to_logout) log.error("Received error HTTP status code: %s", formatted_response_code) raise salt.exceptions.CommandExecutionError( "Did not receive a valid response from host." ) def init(opts): """ This function gets called when the proxy starts up. """ log.debug("=== opts %s ===", opts) if "host" not in opts["proxy"]: log.critical("No 'host' key found in pillar for this proxy.") return False if "username" not in opts["proxy"]: log.critical("No 'username' key found in pillar for this proxy.") return False if "password" not in opts["proxy"]: log.critical("No 'passwords' key found in pillar for this proxy.") return False DETAILS["url"] = "https://{}/nuova".format(opts["proxy"]["host"]) DETAILS["headers"] = { "Content-Type": "application/x-www-form-urlencoded", "Content-Length": 62, "USER-Agent": "lwp-request/2.06", } # Set configuration details DETAILS["host"] = opts["proxy"]["host"] DETAILS["username"] = opts["proxy"].get("username") DETAILS["password"] = opts["proxy"].get("password") verify_ssl = opts["proxy"].get("verify_ssl") if verify_ssl is None: verify_ssl = True DETAILS["verify_ssl"] = verify_ssl # Ensure connectivity to the device log.debug("Attempting to connect to cimc proxy host.") get_config_resolver_class("computeRackUnit") log.debug("Successfully connected to cimc proxy host.") DETAILS["initialized"] = True def set_config_modify(dn=None, inconfig=None, hierarchical=False): """ The configConfMo method configures the specified managed object in a single subtree (for example, DN). """ ret = {} cookie = logon() # Declare if the search contains hierarchical results. h = "false" if hierarchical is True: h = "true" payload = ( '<configConfMo cookie="{}" inHierarchical="{}" dn="{}">' "<inConfig>{}</inConfig></configConfMo>".format(cookie, h, dn, inconfig) ) r = __utils__["http.query"]( DETAILS["url"], data=payload, method="POST", decode_type="plain", decode=True, verify_ssl=DETAILS["verify_ssl"], raise_error=True, status=True, headers=DETAILS["headers"], ) _validate_response_code(r["status"], cookie) answer = re.findall(r"(<[\s\S.]*>)", r["text"])[0] items = ET.fromstring(answer) logout(cookie) for item in items: ret[item.tag] = prepare_return(item) return ret def get_config_resolver_class(cid=None, hierarchical=False): """ The configResolveClass method returns requested managed object in a given class. """ ret = {} cookie = logon() # Declare if the search contains hierarchical results. h = "false" if hierarchical is True: h = "true" payload = ( '<configResolveClass cookie="{}" inHierarchical="{}" classId="{}"/>'.format( cookie, h, cid ) ) r = __utils__["http.query"]( DETAILS["url"], data=payload, method="POST", decode_type="plain", decode=True, verify_ssl=DETAILS["verify_ssl"], raise_error=True, status=True, headers=DETAILS["headers"], ) _validate_response_code(r["status"], cookie) answer = re.findall(r"(<[\s\S.]*>)", r["text"])[0] items = ET.fromstring(answer) logout(cookie) for item in items: ret[item.tag] = prepare_return(item) return ret def logon(): """ Logs into the cimc device and returns the session cookie. """ content = {} payload = "<aaaLogin inName='{}' inPassword='{}'></aaaLogin>".format( DETAILS["username"], DETAILS["password"] ) r = __utils__["http.query"]( DETAILS["url"], data=payload, method="POST", decode_type="plain", decode=True, verify_ssl=DETAILS["verify_ssl"], raise_error=False, status=True, headers=DETAILS["headers"], ) _validate_response_code(r["status"]) answer = re.findall(r"(<[\s\S.]*>)", r["text"])[0] items = ET.fromstring(answer) for item in items.attrib: content[item] = items.attrib[item] if "outCookie" not in content: raise salt.exceptions.CommandExecutionError("Unable to log into proxy device.") return content["outCookie"] def logout(cookie=None): """ Closes the session with the device. """ payload = '<aaaLogout cookie="{0}" inCookie="{0}"></aaaLogout>'.format(cookie) __utils__["http.query"]( DETAILS["url"], data=payload, method="POST", decode_type="plain", decode=True, verify_ssl=DETAILS["verify_ssl"], raise_error=True, headers=DETAILS["headers"], ) return def prepare_return(x): """ Converts the etree to dict """ ret = {} for a in list(x): if a.tag not in ret: ret[a.tag] = [] ret[a.tag].append(prepare_return(a)) for a in x.attrib: ret[a] = x.attrib[a] return ret def initialized(): """ Since grains are loaded in many different places and some of those places occur before the proxy can be initialized, return whether our init() function has been called """ return DETAILS.get("initialized", False) def grains(): """ Get the grains from the proxied device """ if not DETAILS.get("grains_cache", {}): DETAILS["grains_cache"] = GRAINS_CACHE try: compute_rack = get_config_resolver_class("computeRackUnit", False) DETAILS["grains_cache"] = compute_rack["outConfigs"]["computeRackUnit"] except salt.exceptions.CommandExecutionError: pass except Exception as err: # pylint: disable=broad-except log.error(err) return DETAILS["grains_cache"] def grains_refresh(): """ Refresh the grains from the proxied device """ DETAILS["grains_cache"] = None return grains() def ping(): """ Returns true if the device is reachable, else false. """ try: cookie = logon() logout(cookie) except salt.exceptions.CommandExecutionError: return False except Exception as err: # pylint: disable=broad-except log.debug(err) return False return True def shutdown(): """ Shutdown the connection to the proxy device. For this proxy, shutdown is a no-op. """ log.debug("CIMC proxy shutdown() called.")