Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

juniper modules/states docstring, parameter name fixes #57281

Merged
merged 20 commits into from
May 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 107 additions & 58 deletions salt/modules/junos.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
# Import Python libraries
from __future__ import absolute_import, print_function, unicode_literals

import copy
import glob
import json
import logging
Expand Down Expand Up @@ -51,6 +52,7 @@
import jnpr.junos.cfg
import jxmlease
from jnpr.junos.factory.optable import OpTable
from jnpr.junos.factory.cfgtable import CfgTable
import jnpr.junos.op as tables_dir
from jnpr.junos.factory.factory_loader import FactoryLoader
import yamlordereddictloader
Expand Down Expand Up @@ -200,11 +202,6 @@ def rpc(cmd=None, dest=None, **kwargs):
ret = {}
ret["out"] = True

if cmd is None:
ret["message"] = "Please provide the rpc to execute."
ret["out"] = False
return ret

op = dict()
if "__pub_arg" in kwargs:
if kwargs["__pub_arg"]:
Expand All @@ -216,6 +213,12 @@ def rpc(cmd=None, dest=None, **kwargs):
op[key] = value
else:
op.update(kwargs)

if cmd is None:
ret["message"] = "Please provide the rpc to execute."
ret["out"] = False
return ret

format_ = op.pop("format", "xml")
# when called from state, dest becomes part of op via __pub_arg
dest = dest or op.pop("dest", None)
Expand Down Expand Up @@ -250,13 +253,10 @@ def rpc(cmd=None, dest=None, **kwargs):
return ret

if format_ == "text":
# Earlier it was ret['message']
ret["rpc_reply"] = reply.text
elif format_ == "json":
# Earlier it was ret['message']
ret["rpc_reply"] = reply
else:
# Earlier it was ret['message']
ret["rpc_reply"] = jxmlease.parse(etree.tostring(reply))

if dest:
Expand Down Expand Up @@ -786,20 +786,21 @@ def install_config(path=None, **kwargs):

mode : exclusive
The mode in which the configuration is locked. Can be one of
``private``, ``dynamic``, ``batch``, ``exclusive``.
``private``, ``dynamic``, ``batch``, ``exclusive``, ``ephemeral``

dev_timeout : 30
Set NETCONF RPC timeout. Can be used for commands which take a while to
execute.

overwrite : False
Set to ``True`` if you want this file is to completely replace the
configuration file.
configuration file. Sets action to override

replace : False
Specify whether the configuration file uses ``replace:`` statements. If
``True``, only those statements under the ``replace`` tag will be
changed.
.. note:: This option cannot be used if **format** is "set".

merge : False
If set to ``True`` will set the load-config action to merge.
the default load-config action is 'replace' for xml/json/text config

format
Determines the format of the contents
Expand Down Expand Up @@ -867,15 +868,14 @@ def install_config(path=None, **kwargs):
op.update(kwargs)

test = op.pop("test", False)
template_vars = {}

kwargs = {}
if "template_vars" in op:
template_vars = op["template_vars"]
kwargs = op["template_vars"]

try:
template_cached_path = salt.utils.files.mkstemp()
__salt__["cp.get_template"](
path, template_cached_path, template_vars=template_vars
)
__salt__["cp.get_template"](path, template_cached_path, **kwargs)
except Exception as ex: # pylint: disable=broad-except
ret["message"] = (
"Salt failed to render the template, please check file path and syntax."
Expand Down Expand Up @@ -906,6 +906,8 @@ def install_config(path=None, **kwargs):
template_format = "set"
elif path.endswith("xml"):
template_format = "xml"
elif path.endswith("json"):
template_format = "json"
else:
template_format = "text"

Expand All @@ -921,13 +923,18 @@ def install_config(path=None, **kwargs):
del op["overwrite"]

db_mode = op.pop("mode", "exclusive")
if write_diff and db_mode == "dynamic":
ret["message"] = "Write diff is not supported with dynamic configuration mode"
if write_diff and db_mode in ["dynamic", "ephemeral"]:
ret[
"message"
] = "Write diff is not supported with dynamic/ephemeral configuration mode"
ret["out"] = False
return ret

config_params = {}
if "ephemeral_instance" in op:
config_params["ephemeral_instance"] = op.pop("ephemeral_instance")
try:
with Config(conn, mode=db_mode) as cu:
with Config(conn, mode=db_mode, **config_params) as cu:
try:
cu.load(**op)
except Exception as exception: # pylint: disable=broad-except
Expand All @@ -940,7 +947,10 @@ def install_config(path=None, **kwargs):
finally:
salt.utils.files.safe_rm(template_cached_path)

if db_mode != "dynamic":
config_diff = None
if db_mode in ["dynamic", "ephemeral"]:
log.warning("diff is not supported for dynamic and ephemeral")
else:
config_diff = cu.diff()
if config_diff is None:
ret["message"] = "Configuration already applied!"
Expand All @@ -955,7 +965,9 @@ def install_config(path=None, **kwargs):

# Assume commit_check succeeds and initialize variable check
check = True
if db_mode != "dynamic":
if db_mode in ["dynamic", "ephemeral"]:
log.warning("commit check not supported for dynamic and ephemeral")
else:
try:
check = cu.commit_check()
except Exception as exception: # pylint: disable=broad-except
Expand Down Expand Up @@ -1000,10 +1012,10 @@ def install_config(path=None, **kwargs):
exception
)
ret["out"] = False
except ValueError:
ret[
"message"
] = "Invalid mode. Modes supported: private, dynamic, batch, exclusive"
except ValueError as ex:
message = "install_config failed due to: {0}".format(str(ex))
log.error(message)
ret["message"] = message
ret["out"] = False
except LockError as ex:
log.error("Configuration database is locked")
Expand Down Expand Up @@ -1059,12 +1071,14 @@ def install_os(path=None, **kwargs):
device. The default is ``/var/tmp``. If the value of :path: or
is a URL, then the value of :remote_path: is unused.

dev_timeout : 30
dev_timeout : 1800
The NETCONF RPC timeout (in seconds). This argument was added since most of
the time the "package add" RPC takes a significant amount of time. The default
RPC timeout is 30 seconds. So this :timeout: value will be
used in the context of the SW installation process. Defaults to
30 minutes (30*60=1800)
the time the "package add" RPC takes a significant amount of time.
So this :timeout: value will be used in the context of the SW installation
process. Defaults to 30 minutes (30*60=1800 seconds)

timeout : 1800
Alias to dev_timeout for backward compatibility

reboot : False
Whether to reboot after installation
Expand Down Expand Up @@ -1122,8 +1136,8 @@ def install_os(path=None, **kwargs):
# timeout value is not honoured by sw.install if not passed as argument
# currently, timeout is set to be maximum of default 1800 and user passed timeout value
# For info: https://github.com/Juniper/salt/issues/116
op.pop("dev_timeout", None)
timeout = max(1800, conn.timeout)
dev_timeout = max(op.pop("dev_timeout", 0), op.pop("timeout", 0))
timeout = max(1800, conn.timeout, dev_timeout)
# Reboot should not be passed as a keyword argument to install(),
# Please refer to https://github.com/Juniper/salt/issues/115 for more details
reboot = op.pop("reboot", False)
Expand Down Expand Up @@ -1158,9 +1172,9 @@ def install_os(path=None, **kwargs):
return ret

# install() should not reboot the device, reboot is handled in the next block
install_status = False
try:
conn.sw.install(path, progress=True, timeout=timeout, **op)
ret["message"] = "Installed the os."
install_status = conn.sw.install(path, progress=True, timeout=timeout, **op)
except Exception as exception: # pylint: disable=broad-except
ret["message"] = 'Installation failed due to: "{0}"'.format(exception)
ret["out"] = False
Expand All @@ -1169,10 +1183,22 @@ def install_os(path=None, **kwargs):
if not no_copy_:
salt.utils.files.safe_rm(image_cached_path)

if install_status is True:
ret["message"] = "Installed the os."
else:
ret["message"] = "Installation failed."
ret["out"] = False
return ret

# Handle reboot, after the install has finished
if reboot is True:
reboot_kwargs = {}
if "vmhost" in op and op.get("vmhost") is True:
reboot_kwargs["vmhost"] = True
if "all_re" in op:
reboot_kwargs["all_re"] = op.get("all_re")
try:
conn.sw.reboot()
conn.sw.reboot(**reboot_kwargs)
except Exception as exception: # pylint: disable=broad-except
ret[
"message"
Expand Down Expand Up @@ -1299,18 +1325,13 @@ def load(path=None, **kwargs):

overwrite : False
Set to ``True`` if you want this file is to completely replace the
configuration file.
configuration file. Sets action to override

replace : False
Specify whether the configuration file uses ``replace:`` statements. If
``True``, only those statements under the ``replace`` tag will be
changed.
.. note:: This option cannot be used if **format** is "set".

merge : False
If set to ``True`` will set the load-config action to merge.

format
Determines the format of the contents
the default load-config action is 'replace' for xml/json/text config

update : False
Compare a complete loaded configuration against the candidate
Expand All @@ -1321,6 +1342,9 @@ def load(path=None, **kwargs):
affected by the changed configuration elements parse the new
configuration. This action is supported from PyEZ 2.1.

format
Determines the format of the contents

template_vars
Variables to be passed into the template processing engine in addition to
those present in pillar, the minion configuration, grains, etc. You may
Expand Down Expand Up @@ -1393,6 +1417,8 @@ def load(path=None, **kwargs):
template_format = "set"
elif path.endswith("xml"):
template_format = "xml"
elif path.endswith("json"):
template_format = "json"
else:
template_format = "text"

Expand Down Expand Up @@ -1468,7 +1494,7 @@ def get_table(
key=None,
key_items=None,
filters=None,
template_args=None,
table_args=None,
):
"""
.. versionadded:: Sodium
Expand Down Expand Up @@ -1497,15 +1523,17 @@ def get_table(
filters:
To select only filter for the dictionary from columns

template_args:
table_args:
key/value pair which should render Jinja template command
or are passed as args to rpc call in op table

CLI Example:

.. code-block:: bash

salt 'device_name' junos.get_table
salt 'device_name' junos.get_table RouteTable routes.yml
"""

conn = __proxy__["junos.conn"]()
ret = {}
ret["out"] = True
Expand All @@ -1520,20 +1548,28 @@ def get_table(
get_kvargs["key_items"] = key_items
if filters is not None:
get_kvargs["filters"] = filters
if template_args is not None and isinstance(template_args, dict):
get_kvargs["args"] = template_args
if table_args is not None and isinstance(table_args, dict):
get_kvargs["args"] = table_args
pyez_tables_path = os.path.dirname(os.path.abspath(tables_dir.__file__))
try:
if path is not None:
file_loc = glob.glob(os.path.join(path, "{}".format(table_file)))
file_loc = glob.glob(os.path.join(path, "{0}".format(table_file)))
else:
file_loc = glob.glob(
os.path.join(pyez_tables_path, "{}".format(table_file))
os.path.join(pyez_tables_path, "{0}".format(table_file))
)
if len(file_loc) == 1:
file_name = file_loc[0]
else:
ret["message"] = "Given table file {} cannot be located".format(table_file)
elif len(file_loc) > 1:
ret[
"message"
] = "Given table file {0} is located at multiple location".format(
table_file
)
ret["out"] = False
return ret
elif len(file_loc) == 0:
ret["message"] = "Given table file {0} cannot be located".format(table_file)
ret["out"] = False
return ret
try:
Expand Down Expand Up @@ -1566,23 +1602,36 @@ def get_table(
ret["out"] = False
return ret
ret["reply"] = json.loads(data.to_json())
if data.__class__.__bases__[0] == OpTable:
if data.__class__.__bases__[0] in [OpTable, CfgTable]:
# Sets key value if not present in YAML. To be used by returner
if ret["table"][table].get("key") is None:
ret["table"][table]["key"] = data.ITEM_NAME_XPATH
# If key is provided from salt state file.
if key is not None:
ret["table"][table]["key"] = data.KEY
if table_args is not None:
args = copy.copy(data.GET_ARGS)
args.update(table_args)
ret["table"][table]["args"] = args
else:
if target is not None:
ret["table"][table]["target"] = data.TARGET
if key is not None:
ret["table"][table]["key"] = data.KEY
if key_items is not None:
ret["table"][table]["key_items"] = data.KEY_ITEMS
if template_args is not None:
ret["table"][table]["args"] = data.CMD_ARGS
if table_args is not None:
args = copy.copy(data.CMD_ARGS)
args.update(table_args)
ret["table"][table]["args"] = args
ret["table"][table]["command"] = data.GET_CMD
except ConnectClosedError:
ret["message"] = (
"Got ConnectClosedError exception. Connection lost "
"with {0}".format(str(conn))
)
ret["out"] = False
return ret
except Exception as err: # pylint: disable=broad-except
ret["message"] = "Uncaught exception - please report: {0}".format(str(err))
traceback.print_exc()
Expand Down
Loading