1"""
2Util functions for the NXOS API modules.
3"""
4
5import json
6import logging
7
8import salt.utils.http
9from salt.exceptions import SaltException
10from salt.utils.args import clean_kwargs
11
12log = logging.getLogger(__name__)
13
14RPC_INIT_KWARGS = [
15    "transport",
16    "host",
17    "username",
18    "password",
19    "port",
20    "timeout",
21    "verify",
22    "rpc_version",
23]
24
25
26def _prepare_connection(**nxos_api_kwargs):
27    """
28    Prepare the connection with the remote network device, and clean up the key
29    value pairs, removing the args used for the connection init.
30    """
31    nxos_api_kwargs = clean_kwargs(**nxos_api_kwargs)
32    init_kwargs = {}
33    # Clean up any arguments that are not required
34    for karg, warg in nxos_api_kwargs.items():
35        if karg in RPC_INIT_KWARGS:
36            init_kwargs[karg] = warg
37    if "host" not in init_kwargs:
38        init_kwargs["host"] = "localhost"
39    if "transport" not in init_kwargs:
40        init_kwargs["transport"] = "https"
41    if "port" not in init_kwargs:
42        init_kwargs["port"] = 80 if init_kwargs["transport"] == "http" else 443
43    verify = init_kwargs.get("verify", True)
44    if isinstance(verify, bool):
45        init_kwargs["verify_ssl"] = verify
46    else:
47        init_kwargs["ca_bundle"] = verify
48    if "rpc_version" not in init_kwargs:
49        init_kwargs["rpc_version"] = "2.0"
50    if "timeout" not in init_kwargs:
51        init_kwargs["timeout"] = 60
52    return init_kwargs
53
54
55def rpc(commands, method="cli", **kwargs):
56    """
57    Execute an arbitrary RPC request via the Nexus API.
58
59    commands
60        The commands to be executed.
61
62    method: ``cli``
63        The type of the response, i.e., raw text (``cli_ascii``) or structured
64        document (``cli``). Defaults to ``cli`` (structured data).
65
66    transport: ``https``
67        Specifies the type of connection transport to use. Valid values for the
68        connection are ``http``, and  ``https``.
69
70    host: ``localhost``
71        The IP address or DNS host name of the connection device.
72
73    username: ``admin``
74        The username to pass to the device to authenticate the NX-API connection.
75
76    password
77        The password to pass to the device to authenticate the NX-API connection.
78
79    port
80        The TCP port of the endpoint for the NX-API connection. If this keyword is
81        not specified, the default value is automatically determined by the
82        transport type (``80`` for ``http``, or ``443`` for ``https``).
83
84    timeout: ``60``
85        Time in seconds to wait for the device to respond. Default: 60 seconds.
86
87    verify: ``True``
88        Either a boolean, in which case it controls whether we verify the NX-API
89        TLS certificate, or a string, in which case it must be a path to a CA bundle
90        to use. Defaults to ``True``.
91    """
92    init_args = _prepare_connection(**kwargs)
93    log.error("These are the init args:")
94    log.error(init_args)
95    url = "{transport}://{host}:{port}/ins".format(
96        transport=init_args["transport"], host=init_args["host"], port=init_args["port"]
97    )
98    headers = {"content-type": "application/json-rpc"}
99    payload = []
100    if not isinstance(commands, (list, tuple)):
101        commands = [commands]
102    for index, command in enumerate(commands):
103        payload.append(
104            {
105                "jsonrpc": init_args["rpc_version"],
106                "method": method,
107                "params": {"cmd": command, "version": 1},
108                "id": index + 1,
109            }
110        )
111    opts = {"http_request_timeout": init_args["timeout"]}
112    response = salt.utils.http.query(
113        url,
114        method="POST",
115        opts=opts,
116        data=json.dumps(payload),
117        header_dict=headers,
118        decode=True,
119        decode_type="json",
120        **init_args
121    )
122    if "error" in response:
123        raise SaltException(response["error"])
124    response_list = response["dict"]
125    if isinstance(response_list, dict):
126        response_list = [response_list]
127    for index, command in enumerate(commands):
128        response_list[index]["command"] = command
129    return response_list
130