mirror of
https://github.com/saltstack/salt.git
synced 2025-04-17 10:10:20 +00:00
Do not lookup reverse dns with salt-ssh
This commit is contained in:
parent
b3127f7648
commit
b321137374
3 changed files with 286 additions and 88 deletions
1
changelog/49840.fixed
Normal file
1
changelog/49840.fixed
Normal file
|
@ -0,0 +1 @@
|
|||
Do not use reverse DNS of the target used in salt-ssh. Use the target the user provides.
|
|
@ -1,9 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Create ssh executor system
|
||||
"""
|
||||
# Import python libs
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import base64
|
||||
import binascii
|
||||
|
@ -208,7 +206,7 @@ if not is_windows():
|
|||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SSH(object):
|
||||
class SSH:
|
||||
"""
|
||||
Create an SSH execution system
|
||||
"""
|
||||
|
@ -306,7 +304,7 @@ class SSH(object):
|
|||
}
|
||||
if self.opts.get("rand_thin_dir"):
|
||||
self.defaults["thin_dir"] = os.path.join(
|
||||
"/var/tmp", ".{0}".format(uuid.uuid4().hex[:6])
|
||||
"/var/tmp", ".{}".format(uuid.uuid4().hex[:6])
|
||||
)
|
||||
self.opts["ssh_wipe"] = "True"
|
||||
self.serial = salt.payload.Serial(opts)
|
||||
|
@ -322,6 +320,22 @@ class SSH(object):
|
|||
)
|
||||
self.mods = mod_data(self.fsclient)
|
||||
|
||||
@property
|
||||
def parse_tgt(self):
|
||||
"""
|
||||
Method to determine the hostname and user
|
||||
when bypassing the roster and using
|
||||
ssh syntax (ex. root@localhost)
|
||||
"""
|
||||
if not self.opts.get("ssh_cli_tgt"):
|
||||
self.opts["ssh_cli_tgt"] = self.opts.get("tgt", "")
|
||||
hostname = self.opts.get("ssh_cli_tgt", "")
|
||||
if "@" in hostname:
|
||||
user, hostname = hostname.split("@", 1)
|
||||
else:
|
||||
user = self.opts.get("ssh_user")
|
||||
return {"hostname": hostname, "user": user}
|
||||
|
||||
def _get_roster(self):
|
||||
"""
|
||||
Read roster filename as a key to the data.
|
||||
|
@ -345,18 +359,14 @@ class SSH(object):
|
|||
:return:
|
||||
"""
|
||||
# TODO: Support -L
|
||||
target = self.opts["tgt"]
|
||||
if isinstance(target, list):
|
||||
hostname = self.parse_tgt["hostname"]
|
||||
if isinstance(hostname, list):
|
||||
return
|
||||
|
||||
hostname = self.opts["tgt"].split("@")[-1]
|
||||
needs_expansion = (
|
||||
"*" not in hostname
|
||||
and salt.utils.network.is_reachable_host(hostname)
|
||||
and salt.utils.network.is_ip(hostname)
|
||||
needs_expansion = "*" not in hostname and salt.utils.network.is_reachable_host(
|
||||
hostname
|
||||
)
|
||||
if needs_expansion:
|
||||
hostname = salt.utils.network.ip_to_host(hostname)
|
||||
if hostname is None:
|
||||
# Reverse lookup failed
|
||||
return
|
||||
|
@ -365,7 +375,7 @@ class SSH(object):
|
|||
roster_data = self.__parsed_rosters[roster_filename]
|
||||
if not isinstance(roster_data, bool):
|
||||
for host_id in roster_data:
|
||||
if hostname in [host_id, roster_data.get("host")]:
|
||||
if hostname in [host_id, roster_data[host_id].get("host")]:
|
||||
if hostname != self.opts["tgt"]:
|
||||
self.opts["tgt"] = hostname
|
||||
self.__parsed_rosters[self.ROSTER_UPDATE_FLAG] = False
|
||||
|
@ -392,29 +402,24 @@ class SSH(object):
|
|||
)
|
||||
)
|
||||
log.info(
|
||||
"The host {0} has been added to the roster {1}".format(
|
||||
"The host {} has been added to the roster {}".format(
|
||||
self.opts.get("tgt", ""), roster_file
|
||||
)
|
||||
)
|
||||
else:
|
||||
log.error("Unable to update roster {0}: access denied".format(roster_file))
|
||||
log.error("Unable to update roster {}: access denied".format(roster_file))
|
||||
|
||||
def _update_targets(self):
|
||||
"""
|
||||
Uptade targets in case hostname was directly passed without the roster.
|
||||
:return:
|
||||
"""
|
||||
|
||||
hostname = self.opts.get("tgt", "")
|
||||
if "@" in hostname:
|
||||
user, hostname = hostname.split("@", 1)
|
||||
else:
|
||||
user = self.opts.get("ssh_user")
|
||||
hostname = self.parse_tgt["hostname"]
|
||||
user = self.parse_tgt["user"]
|
||||
if hostname == "*":
|
||||
hostname = ""
|
||||
|
||||
if salt.utils.network.is_reachable_host(hostname):
|
||||
hostname = salt.utils.network.ip_to_host(hostname)
|
||||
self.opts["tgt"] = hostname
|
||||
self.targets[hostname] = {
|
||||
"passwd": self.opts.get("ssh_passwd", ""),
|
||||
|
@ -438,9 +443,9 @@ class SSH(object):
|
|||
priv = self.opts.get(
|
||||
"ssh_priv", os.path.join(self.opts["pki_dir"], "ssh", "salt-ssh.rsa")
|
||||
)
|
||||
pub = "{0}.pub".format(priv)
|
||||
pub = "{}.pub".format(priv)
|
||||
with salt.utils.files.fopen(pub, "r") as fp_:
|
||||
return "{0} rsa root@master".format(fp_.read().split()[1])
|
||||
return "{} rsa root@master".format(fp_.read().split()[1])
|
||||
|
||||
def key_deploy(self, host, ret):
|
||||
"""
|
||||
|
@ -456,7 +461,7 @@ class SSH(object):
|
|||
# permission denied, attempt to auto deploy ssh key
|
||||
print(
|
||||
(
|
||||
"Permission denied for host {0}, do you want to deploy "
|
||||
"Permission denied for host {}, do you want to deploy "
|
||||
"the salt-ssh key? (password required):"
|
||||
).format(host)
|
||||
)
|
||||
|
@ -464,7 +469,7 @@ class SSH(object):
|
|||
if deploy.startswith(("n", "N")):
|
||||
return ret
|
||||
target["passwd"] = getpass.getpass(
|
||||
"Password for {0}@{1}: ".format(target["user"], host)
|
||||
"Password for {}@{}: ".format(target["user"], host)
|
||||
)
|
||||
return self._key_deploy_run(host, target, True)
|
||||
return ret
|
||||
|
@ -632,7 +637,7 @@ class SSH(object):
|
|||
|
||||
if host not in returned:
|
||||
error = (
|
||||
"Target '{0}' did not return any data, "
|
||||
"Target '{}' did not return any data, "
|
||||
"probably due to an error."
|
||||
).format(host)
|
||||
ret = {"id": host, "ret": error}
|
||||
|
@ -660,7 +665,7 @@ class SSH(object):
|
|||
pillar, or master config (they will be checked in that order) and
|
||||
will modify the argv with the arguments from mine_functions
|
||||
"""
|
||||
fstr = "{0}.prep_jid".format(self.opts["master_job_cache"])
|
||||
fstr = "{}.prep_jid".format(self.opts["master_job_cache"])
|
||||
jid = self.returners[fstr](passed_jid=jid or self.opts.get("jid", None))
|
||||
|
||||
# Save the invocation information
|
||||
|
@ -684,20 +689,20 @@ class SSH(object):
|
|||
|
||||
# save load to the master job cache
|
||||
if self.opts["master_job_cache"] == "local_cache":
|
||||
self.returners["{0}.save_load".format(self.opts["master_job_cache"])](
|
||||
self.returners["{}.save_load".format(self.opts["master_job_cache"])](
|
||||
jid, job_load, minions=self.targets.keys()
|
||||
)
|
||||
else:
|
||||
self.returners["{0}.save_load".format(self.opts["master_job_cache"])](
|
||||
self.returners["{}.save_load".format(self.opts["master_job_cache"])](
|
||||
jid, job_load
|
||||
)
|
||||
|
||||
for ret in self.handle_ssh(mine=mine):
|
||||
host = next(six.iterkeys(ret))
|
||||
host = next(iter(ret.keys()))
|
||||
self.cache_job(jid, host, ret[host], fun)
|
||||
if self.event:
|
||||
id_, data = next(six.iteritems(ret))
|
||||
if isinstance(data, six.text_type):
|
||||
id_, data = next(iter(ret.items()))
|
||||
if isinstance(data, str):
|
||||
data = {"return": data}
|
||||
if "id" not in data:
|
||||
data["id"] = id_
|
||||
|
@ -713,7 +718,7 @@ class SSH(object):
|
|||
"""
|
||||
Cache the job information
|
||||
"""
|
||||
self.returners["{0}.returner".format(self.opts["master_job_cache"])](
|
||||
self.returners["{}.returner".format(self.opts["master_job_cache"])](
|
||||
{"jid": jid, "id": id_, "return": ret, "fun": fun}
|
||||
)
|
||||
|
||||
|
@ -734,7 +739,7 @@ class SSH(object):
|
|||
salt.output.display_output(ret, "nested", self.opts)
|
||||
sys.exit()
|
||||
|
||||
fstr = "{0}.prep_jid".format(self.opts["master_job_cache"])
|
||||
fstr = "{}.prep_jid".format(self.opts["master_job_cache"])
|
||||
jid = self.returners[fstr](passed_jid=jid or self.opts.get("jid", None))
|
||||
|
||||
# Save the invocation information
|
||||
|
@ -761,11 +766,11 @@ class SSH(object):
|
|||
if isinstance(jid, bytes):
|
||||
jid = jid.decode("utf-8")
|
||||
if self.opts["master_job_cache"] == "local_cache":
|
||||
self.returners["{0}.save_load".format(self.opts["master_job_cache"])](
|
||||
self.returners["{}.save_load".format(self.opts["master_job_cache"])](
|
||||
jid, job_load, minions=self.targets.keys()
|
||||
)
|
||||
else:
|
||||
self.returners["{0}.save_load".format(self.opts["master_job_cache"])](
|
||||
self.returners["{}.save_load".format(self.opts["master_job_cache"])](
|
||||
jid, job_load
|
||||
)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
|
@ -777,7 +782,7 @@ class SSH(object):
|
|||
)
|
||||
|
||||
if self.opts.get("verbose"):
|
||||
msg = "Executing job with jid {0}".format(jid)
|
||||
msg = "Executing job with jid {}".format(jid)
|
||||
print(msg)
|
||||
print("-" * len(msg) + "\n")
|
||||
print("")
|
||||
|
@ -785,7 +790,7 @@ class SSH(object):
|
|||
outputter = self.opts.get("output", "nested")
|
||||
final_exit = 0
|
||||
for ret in self.handle_ssh():
|
||||
host = next(six.iterkeys(ret))
|
||||
host = next(iter(ret.keys()))
|
||||
if isinstance(ret[host], dict):
|
||||
host_ret = ret[host].get("retcode", 0)
|
||||
if host_ret != 0:
|
||||
|
@ -814,8 +819,8 @@ class SSH(object):
|
|||
else:
|
||||
salt.output.display_output(p_data, outputter, self.opts)
|
||||
if self.event:
|
||||
id_, data = next(six.iteritems(ret))
|
||||
if isinstance(data, six.text_type):
|
||||
id_, data = next(iter(ret.items()))
|
||||
if isinstance(data, str):
|
||||
data = {"return": data}
|
||||
if "id" not in data:
|
||||
data["id"] = id_
|
||||
|
@ -831,7 +836,7 @@ class SSH(object):
|
|||
sys.exit(salt.defaults.exitcodes.EX_AGGREGATE)
|
||||
|
||||
|
||||
class Single(object):
|
||||
class Single:
|
||||
"""
|
||||
Hold onto a single ssh execution
|
||||
"""
|
||||
|
@ -904,7 +909,7 @@ class Single(object):
|
|||
if self.ssh_pre_flight:
|
||||
self.ssh_pre_file = os.path.basename(self.ssh_pre_flight)
|
||||
|
||||
if isinstance(argv, six.string_types):
|
||||
if isinstance(argv, str):
|
||||
self.argv = [argv]
|
||||
else:
|
||||
self.argv = argv
|
||||
|
@ -999,7 +1004,7 @@ class Single(object):
|
|||
check if the thindir exists on the remote machine
|
||||
"""
|
||||
stdout, stderr, retcode = self.shell.exec_cmd(
|
||||
"test -d {0}".format(self.thin_dir)
|
||||
"test -d {}".format(self.thin_dir)
|
||||
)
|
||||
if retcode != 0:
|
||||
return False
|
||||
|
@ -1042,13 +1047,13 @@ class Single(object):
|
|||
if self.ssh_pre_flight:
|
||||
if not self.opts.get("ssh_run_pre_flight", False) and self.check_thin_dir():
|
||||
log.info(
|
||||
"{0} thin dir already exists. Not running ssh_pre_flight script".format(
|
||||
"{} thin dir already exists. Not running ssh_pre_flight script".format(
|
||||
self.thin_dir
|
||||
)
|
||||
)
|
||||
elif not os.path.exists(self.ssh_pre_flight):
|
||||
log.error(
|
||||
"The ssh_pre_flight script {0} does not exist".format(
|
||||
"The ssh_pre_flight script {} does not exist".format(
|
||||
self.ssh_pre_flight
|
||||
)
|
||||
)
|
||||
|
@ -1056,13 +1061,13 @@ class Single(object):
|
|||
stdout, stderr, retcode = self.run_ssh_pre_flight()
|
||||
if stderr:
|
||||
log.error(
|
||||
"Error running ssh_pre_flight script {0}".format(
|
||||
"Error running ssh_pre_flight script {}".format(
|
||||
self.ssh_pre_file
|
||||
)
|
||||
)
|
||||
return stdout, stderr, retcode
|
||||
log.info(
|
||||
"Successfully ran the ssh_pre_flight script: {0}".format(
|
||||
"Successfully ran the ssh_pre_flight script: {}".format(
|
||||
self.ssh_pre_file
|
||||
)
|
||||
)
|
||||
|
@ -1239,11 +1244,11 @@ class Single(object):
|
|||
else:
|
||||
result = self.wfuncs[self.fun](*self.args, **self.kwargs)
|
||||
except TypeError as exc:
|
||||
result = "TypeError encountered executing {0}: {1}".format(self.fun, exc)
|
||||
result = "TypeError encountered executing {}: {}".format(self.fun, exc)
|
||||
log.error(result, exc_info_on_loglevel=logging.DEBUG)
|
||||
retcode = 1
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
result = "An Exception occurred while executing {0}: {1}".format(
|
||||
result = "An Exception occurred while executing {}: {}".format(
|
||||
self.fun, exc
|
||||
)
|
||||
log.error(result, exc_info_on_loglevel=logging.DEBUG)
|
||||
|
@ -1305,10 +1310,7 @@ ARGS = {arguments}\n'''.format(
|
|||
arguments=self.argv,
|
||||
)
|
||||
py_code = SSH_PY_SHIM.replace("#%%OPTS", arg_str)
|
||||
if six.PY2:
|
||||
py_code_enc = py_code.encode("base64")
|
||||
else:
|
||||
py_code_enc = base64.encodebytes(py_code.encode("utf-8")).decode("utf-8")
|
||||
py_code_enc = base64.encodebytes(py_code.encode("utf-8")).decode("utf-8")
|
||||
if not self.winrm:
|
||||
cmd = SSH_SH_SHIM.format(
|
||||
DEBUG=debug,
|
||||
|
@ -1328,18 +1330,18 @@ ARGS = {arguments}\n'''.format(
|
|||
execute a script on the minion then delete
|
||||
"""
|
||||
if extension == "ps1":
|
||||
ret = self.shell.exec_cmd('"powershell {0}"'.format(script))
|
||||
ret = self.shell.exec_cmd('"powershell {}"'.format(script))
|
||||
else:
|
||||
if not self.winrm:
|
||||
ret = self.shell.exec_cmd("/bin/sh '{0}{1}'".format(pre_dir, script))
|
||||
ret = self.shell.exec_cmd("/bin/sh '{}{}'".format(pre_dir, script))
|
||||
else:
|
||||
ret = saltwinshell.call_python(self, script)
|
||||
|
||||
# Remove file from target system
|
||||
if not self.winrm:
|
||||
self.shell.exec_cmd("rm '{0}{1}'".format(pre_dir, script))
|
||||
self.shell.exec_cmd("rm '{}{}'".format(pre_dir, script))
|
||||
else:
|
||||
self.shell.exec_cmd("del {0}".format(script))
|
||||
self.shell.exec_cmd("del {}".format(script))
|
||||
|
||||
return ret
|
||||
|
||||
|
@ -1360,7 +1362,7 @@ ARGS = {arguments}\n'''.format(
|
|||
shim_tmp_file.write(salt.utils.stringutils.to_bytes(cmd_str))
|
||||
|
||||
# Copy shim to target system, under $HOME/.<randomized name>
|
||||
target_shim_file = ".{0}.{1}".format(
|
||||
target_shim_file = ".{}.{}".format(
|
||||
binascii.hexlify(os.urandom(6)).decode("ascii"), extension
|
||||
)
|
||||
if self.winrm:
|
||||
|
@ -1370,7 +1372,7 @@ ARGS = {arguments}\n'''.format(
|
|||
# Remove our shim file
|
||||
try:
|
||||
os.remove(shim_tmp_file.name)
|
||||
except IOError:
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
ret = self.execute_script(
|
||||
|
@ -1393,7 +1395,7 @@ ARGS = {arguments}\n'''.format(
|
|||
self.argv = _convert_args(self.argv)
|
||||
log.debug(
|
||||
"Performing shimmed, blocking command as follows:\n%s",
|
||||
" ".join([six.text_type(arg) for arg in self.argv]),
|
||||
" ".join([str(arg) for arg in self.argv]),
|
||||
)
|
||||
cmd_str = self._cmd_str()
|
||||
stdout, stderr, retcode = self.shim_cmd(cmd_str)
|
||||
|
@ -1418,7 +1420,7 @@ ARGS = {arguments}\n'''.format(
|
|||
# If RSTR is not seen in both stdout and stderr then there
|
||||
# was a thin deployment problem.
|
||||
return (
|
||||
"ERROR: Failure deploying thin, undefined state: {0}".format(
|
||||
"ERROR: Failure deploying thin, undefined state: {}".format(
|
||||
stdout
|
||||
),
|
||||
stderr,
|
||||
|
@ -1429,7 +1431,7 @@ ARGS = {arguments}\n'''.format(
|
|||
while re.search(RSTR_RE, stderr):
|
||||
stderr = re.split(RSTR_RE, stderr, 1)[1].strip()
|
||||
else:
|
||||
return "ERROR: {0}".format(error), stderr, retcode
|
||||
return "ERROR: {}".format(error), stderr, retcode
|
||||
|
||||
# FIXME: this discards output from ssh_shim if the shim succeeds. It should
|
||||
# always save the shim output regardless of shim success or failure.
|
||||
|
@ -1489,7 +1491,7 @@ ARGS = {arguments}\n'''.format(
|
|||
# If RSTR is not seen in both stdout and stderr then there
|
||||
# was a thin deployment problem.
|
||||
return (
|
||||
"ERROR: Failure deploying ext_mods: {0}".format(stdout),
|
||||
"ERROR: Failure deploying ext_mods: {}".format(stdout),
|
||||
stderr,
|
||||
retcode,
|
||||
)
|
||||
|
@ -1648,12 +1650,12 @@ def salt_refs(data):
|
|||
"""
|
||||
proto = "salt://"
|
||||
ret = []
|
||||
if isinstance(data, six.string_types):
|
||||
if isinstance(data, str):
|
||||
if data.startswith(proto):
|
||||
return [data]
|
||||
if isinstance(data, list):
|
||||
for comp in data:
|
||||
if isinstance(comp, six.string_types):
|
||||
if isinstance(comp, str):
|
||||
if comp.startswith(proto):
|
||||
ret.append(comp)
|
||||
return ret
|
||||
|
@ -1678,7 +1680,7 @@ def mod_data(fsclient):
|
|||
files = fsclient.file_list(env)
|
||||
for ref in sync_refs:
|
||||
mods_data = {}
|
||||
pref = "_{0}".format(ref)
|
||||
pref = "_{}".format(ref)
|
||||
for fn_ in sorted(files):
|
||||
if fn_.startswith(pref):
|
||||
if fn_.endswith((".py", ".so", ".pyx")):
|
||||
|
@ -1697,12 +1699,11 @@ def mod_data(fsclient):
|
|||
if not ret:
|
||||
return {}
|
||||
|
||||
if six.PY3:
|
||||
ver_base = salt.utils.stringutils.to_bytes(ver_base)
|
||||
ver_base = salt.utils.stringutils.to_bytes(ver_base)
|
||||
|
||||
ver = hashlib.sha1(ver_base).hexdigest()
|
||||
ext_tar_path = os.path.join(
|
||||
fsclient.opts["cachedir"], "ext_mods.{0}.tgz".format(ver)
|
||||
fsclient.opts["cachedir"], "ext_mods.{}.tgz".format(ver)
|
||||
)
|
||||
mods = {"version": ver, "file": ext_tar_path}
|
||||
if os.path.isfile(ext_tar_path):
|
||||
|
@ -1752,7 +1753,7 @@ def _convert_args(args):
|
|||
for key in list(arg.keys()):
|
||||
if key == "__kwarg__":
|
||||
continue
|
||||
converted.append("{0}={1}".format(key, arg[key]))
|
||||
converted.append("{}={}".format(key, arg[key]))
|
||||
else:
|
||||
converted.append(arg)
|
||||
return converted
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
:codeauthor: :email:`Daniel Wallace <dwallace@saltstack.com`
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import, print_function, unicode_literals
|
||||
|
||||
import os
|
||||
import re
|
||||
|
@ -23,15 +21,6 @@ from tests.support.mock import MagicMock, call, patch
|
|||
from tests.support.runtests import RUNTIME_VARS
|
||||
from tests.support.unit import TestCase, skipIf
|
||||
|
||||
ROSTER = """
|
||||
localhost:
|
||||
host: 127.0.0.1
|
||||
port: 2827
|
||||
self:
|
||||
host: 0.0.0.0
|
||||
port: 42
|
||||
"""
|
||||
|
||||
|
||||
@skipIf(not salt.utils.path.which("ssh"), "No ssh binary found in path")
|
||||
class SSHPasswordTests(ShellCase):
|
||||
|
@ -76,6 +65,16 @@ class SSHPasswordTests(ShellCase):
|
|||
|
||||
|
||||
class SSHRosterDefaults(TestCase):
|
||||
def setUp(self):
|
||||
self.roster = """
|
||||
localhost:
|
||||
host: 127.0.0.1
|
||||
port: 2827
|
||||
self:
|
||||
host: 0.0.0.0
|
||||
port: 42
|
||||
"""
|
||||
|
||||
def test_roster_defaults_flat(self):
|
||||
"""
|
||||
Test Roster Defaults on the flat roster
|
||||
|
@ -97,10 +96,12 @@ class SSHRosterDefaults(TestCase):
|
|||
"""
|
||||
)
|
||||
opts = salt.config.master_config(fpath)
|
||||
with patch("salt.roster.get_roster_file", MagicMock(return_value=ROSTER)):
|
||||
with patch(
|
||||
"salt.roster.get_roster_file", MagicMock(return_value=self.roster)
|
||||
):
|
||||
with patch(
|
||||
"salt.template.compile_template",
|
||||
MagicMock(return_value=salt.utils.yaml.safe_load(ROSTER)),
|
||||
MagicMock(return_value=salt.utils.yaml.safe_load(self.roster)),
|
||||
):
|
||||
roster = salt.roster.Roster(opts=opts)
|
||||
self.assertEqual(roster.targets("*", "glob"), expected)
|
||||
|
@ -322,8 +323,8 @@ class SSHSingleTests(TestCase):
|
|||
assert ret == exp_ret
|
||||
assert mock_cmd.call_count == 2
|
||||
assert [
|
||||
call("/bin/sh '{0}'".format(script)),
|
||||
call("rm '{0}'".format(script)),
|
||||
call("/bin/sh '{}'".format(script)),
|
||||
call("rm '{}'".format(script)),
|
||||
] == mock_cmd.call_args_list
|
||||
|
||||
def test_shim_cmd(self):
|
||||
|
@ -388,8 +389,8 @@ class SSHSingleTests(TestCase):
|
|||
ret = single.run_ssh_pre_flight()
|
||||
assert ret == exp_ret
|
||||
assert [
|
||||
call("/bin/sh '{0}'".format(exp_tmp)),
|
||||
call("rm '{0}'".format(exp_tmp)),
|
||||
call("/bin/sh '{}'".format(exp_tmp)),
|
||||
call("rm '{}'".format(exp_tmp)),
|
||||
] == mock_cmd.call_args_list
|
||||
|
||||
@skipIf(salt.utils.platform.is_windows(), "SSH_PY_SHIM not set on windows")
|
||||
|
@ -432,3 +433,198 @@ class SSHSingleTests(TestCase):
|
|||
|
||||
ret = single._cmd_str()
|
||||
assert re.search('SET_PATH=""', ret)
|
||||
|
||||
|
||||
class SSHTests(ShellCase):
|
||||
def setUp(self):
|
||||
self.roster = """
|
||||
localhost:
|
||||
host: 127.0.0.1
|
||||
port: 2827
|
||||
"""
|
||||
self.opts = salt.config.client_config(self.get_config_file_path("master"))
|
||||
self.opts["selected_target_option"] = "glob"
|
||||
|
||||
def test_expand_target_ip_address(self):
|
||||
"""
|
||||
test expand_target when target is root@<ip address>
|
||||
"""
|
||||
host = "127.0.0.1"
|
||||
user = "test-user@"
|
||||
opts = self.opts
|
||||
opts["tgt"] = user + host
|
||||
|
||||
with patch(
|
||||
"salt.utils.network.is_reachable_host", MagicMock(return_value=False)
|
||||
):
|
||||
client = ssh.SSH(opts)
|
||||
assert opts["tgt"] == user + host
|
||||
with patch(
|
||||
"salt.roster.get_roster_file", MagicMock(return_value="/etc/salt/roster")
|
||||
), patch(
|
||||
"salt.client.ssh.compile_template",
|
||||
MagicMock(return_value=salt.utils.yaml.safe_load(self.roster)),
|
||||
):
|
||||
client._expand_target()
|
||||
assert opts["tgt"] == host
|
||||
|
||||
def test_expand_target_dns(self):
|
||||
"""
|
||||
test expand_target when target is root@<dns>
|
||||
"""
|
||||
host = "localhost"
|
||||
user = "test-user@"
|
||||
opts = self.opts
|
||||
opts["tgt"] = user + host
|
||||
|
||||
with patch(
|
||||
"salt.utils.network.is_reachable_host", MagicMock(return_value=False)
|
||||
):
|
||||
client = ssh.SSH(opts)
|
||||
assert opts["tgt"] == user + host
|
||||
with patch(
|
||||
"salt.roster.get_roster_file", MagicMock(return_value="/etc/salt/roster")
|
||||
), patch(
|
||||
"salt.client.ssh.compile_template",
|
||||
MagicMock(return_value=salt.utils.yaml.safe_load(self.roster)),
|
||||
):
|
||||
client._expand_target()
|
||||
assert opts["tgt"] == host
|
||||
|
||||
def test_expand_target_no_user(self):
|
||||
"""
|
||||
test expand_target when no user defined
|
||||
"""
|
||||
host = "127.0.0.1"
|
||||
opts = self.opts
|
||||
opts["tgt"] = host
|
||||
|
||||
with patch(
|
||||
"salt.utils.network.is_reachable_host", MagicMock(return_value=False)
|
||||
):
|
||||
client = ssh.SSH(opts)
|
||||
assert opts["tgt"] == host
|
||||
|
||||
with patch(
|
||||
"salt.roster.get_roster_file", MagicMock(return_value="/etc/salt/roster")
|
||||
), patch(
|
||||
"salt.client.ssh.compile_template",
|
||||
MagicMock(return_value=salt.utils.yaml.safe_load(self.roster)),
|
||||
):
|
||||
client._expand_target()
|
||||
assert opts["tgt"] == host
|
||||
|
||||
def test_update_targets_ip_address(self):
|
||||
"""
|
||||
test update_targets when host is ip address
|
||||
"""
|
||||
host = "127.0.0.1"
|
||||
user = "test-user@"
|
||||
opts = self.opts
|
||||
opts["tgt"] = user + host
|
||||
|
||||
with patch(
|
||||
"salt.utils.network.is_reachable_host", MagicMock(return_value=False)
|
||||
):
|
||||
client = ssh.SSH(opts)
|
||||
assert opts["tgt"] == user + host
|
||||
client._update_targets()
|
||||
assert opts["tgt"] == host
|
||||
assert client.targets[host]["user"] == user.split("@")[0]
|
||||
|
||||
def test_update_targets_dns(self):
|
||||
"""
|
||||
test update_targets when host is dns
|
||||
"""
|
||||
host = "localhost"
|
||||
user = "test-user@"
|
||||
opts = self.opts
|
||||
opts["tgt"] = user + host
|
||||
|
||||
with patch(
|
||||
"salt.utils.network.is_reachable_host", MagicMock(return_value=False)
|
||||
):
|
||||
client = ssh.SSH(opts)
|
||||
assert opts["tgt"] == user + host
|
||||
client._update_targets()
|
||||
assert opts["tgt"] == host
|
||||
assert client.targets[host]["user"] == user.split("@")[0]
|
||||
|
||||
def test_update_targets_no_user(self):
|
||||
"""
|
||||
test update_targets when no user defined
|
||||
"""
|
||||
host = "127.0.0.1"
|
||||
opts = self.opts
|
||||
opts["tgt"] = host
|
||||
|
||||
with patch(
|
||||
"salt.utils.network.is_reachable_host", MagicMock(return_value=False)
|
||||
):
|
||||
client = ssh.SSH(opts)
|
||||
assert opts["tgt"] == host
|
||||
client._update_targets()
|
||||
assert opts["tgt"] == host
|
||||
|
||||
def test_update_expand_target_dns(self):
|
||||
"""
|
||||
test update_targets and expand_target when host is dns
|
||||
"""
|
||||
host = "localhost"
|
||||
user = "test-user@"
|
||||
opts = self.opts
|
||||
opts["tgt"] = user + host
|
||||
|
||||
with patch(
|
||||
"salt.utils.network.is_reachable_host", MagicMock(return_value=False)
|
||||
):
|
||||
client = ssh.SSH(opts)
|
||||
assert opts["tgt"] == user + host
|
||||
with patch(
|
||||
"salt.roster.get_roster_file", MagicMock(return_value="/etc/salt/roster")
|
||||
), patch(
|
||||
"salt.client.ssh.compile_template",
|
||||
MagicMock(return_value=salt.utils.yaml.safe_load(self.roster)),
|
||||
):
|
||||
client._expand_target()
|
||||
client._update_targets()
|
||||
assert opts["tgt"] == host
|
||||
assert client.targets[host]["user"] == user.split("@")[0]
|
||||
|
||||
def test_parse_tgt(self):
|
||||
"""
|
||||
test parse_tgt when user and host set on
|
||||
the ssh cli tgt
|
||||
"""
|
||||
host = "localhost"
|
||||
user = "test-user@"
|
||||
opts = self.opts
|
||||
opts["tgt"] = user + host
|
||||
|
||||
with patch(
|
||||
"salt.utils.network.is_reachable_host", MagicMock(return_value=False)
|
||||
):
|
||||
assert not self.opts.get("ssh_cli_tgt")
|
||||
client = ssh.SSH(opts)
|
||||
assert client.parse_tgt["hostname"] == host
|
||||
assert client.parse_tgt["user"] == user.split("@")[0]
|
||||
assert self.opts.get("ssh_cli_tgt") == user + host
|
||||
|
||||
def test_parse_tgt_no_user(self):
|
||||
"""
|
||||
test parse_tgt when only the host set on
|
||||
the ssh cli tgt
|
||||
"""
|
||||
host = "localhost"
|
||||
opts = self.opts
|
||||
opts["ssh_user"] = "ssh-usr"
|
||||
opts["tgt"] = host
|
||||
|
||||
with patch(
|
||||
"salt.utils.network.is_reachable_host", MagicMock(return_value=False)
|
||||
):
|
||||
assert not self.opts.get("ssh_cli_tgt")
|
||||
client = ssh.SSH(opts)
|
||||
assert client.parse_tgt["hostname"] == host
|
||||
assert client.parse_tgt["user"] == opts["ssh_user"]
|
||||
assert self.opts.get("ssh_cli_tgt") == host
|
||||
|
|
Loading…
Add table
Reference in a new issue