mirror of
https://github.com/valitydev/salt.git
synced 2024-11-08 09:23:56 +00:00
Merge pull request #1315 from imankulov/ssh_known_hosts
Support for ssh_known_hosts in modules and states
This commit is contained in:
commit
99ea439ab6
@ -1,9 +1,10 @@
|
||||
'''
|
||||
Manage client ssh components
|
||||
'''
|
||||
|
||||
import os
|
||||
import re
|
||||
import binascii
|
||||
import hashlib
|
||||
|
||||
|
||||
def _refine_enc(enc):
|
||||
@ -119,16 +120,38 @@ def _validate_keys(key_file):
|
||||
enc = comps[0]
|
||||
key = comps[1]
|
||||
comment = ' '.join(comps[2:])
|
||||
fingerprint = _fingerprint(key)
|
||||
if fingerprint is None:
|
||||
continue
|
||||
|
||||
ret[key] = {'enc': enc,
|
||||
'comment': comment,
|
||||
'options': options}
|
||||
'options': options,
|
||||
'fingerprint': fingerprint}
|
||||
except IOError:
|
||||
return {}
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _fingerprint(public_key):
|
||||
"""
|
||||
Return a public key fingerprint based on its base64-encoded representation
|
||||
|
||||
The fingerprint string is formatted according to RFC 4716 (ch.4), that is,
|
||||
in the form "xx:xx:...:xx"
|
||||
|
||||
If the key is invalid (incorrect base64 string), return None
|
||||
"""
|
||||
try:
|
||||
raw_key = public_key.decode('base64')
|
||||
except binascii.Error:
|
||||
return None
|
||||
ret = hashlib.md5(raw_key).hexdigest()
|
||||
chunks = [ret[i:i+2] for i in range(0, len(ret), 2)]
|
||||
return ':'.join(chunks)
|
||||
|
||||
|
||||
def host_keys(keydir=None):
|
||||
'''
|
||||
Return the minion's host keys
|
||||
@ -368,3 +391,167 @@ def set_auth_key(
|
||||
else:
|
||||
open(fconfig, 'a+').write('{0}'.format(auth_line))
|
||||
return 'new'
|
||||
|
||||
|
||||
def _parse_openssh_output(lines):
|
||||
'''
|
||||
Helper function which parses ssh-keygen -F and ssh-keyscan function output
|
||||
and yield dict with keys information, one by one.
|
||||
'''
|
||||
for line in lines:
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
try:
|
||||
hostname, enc, key = line.split()
|
||||
except ValueError: # incorrect format
|
||||
continue
|
||||
fingerprint = _fingerprint(key)
|
||||
if not fingerprint:
|
||||
continue
|
||||
yield {'hostname': hostname, 'key': key, 'enc': enc,
|
||||
'fingerprint': fingerprint}
|
||||
|
||||
|
||||
def get_known_host(user, hostname, config='.ssh/known_hosts'):
|
||||
'''
|
||||
Return information about known host from the configfile, if any.
|
||||
If there is no such key, return None.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' ssh.get_known_host <user> <hostname>
|
||||
'''
|
||||
uinfo = __salt__['user.info'](user)
|
||||
full = os.path.join(uinfo['home'], config)
|
||||
if not os.path.isfile(full):
|
||||
return None
|
||||
cmd = 'ssh-keygen -F "{0}" -f "{1}"'.format(hostname, full)
|
||||
lines = __salt__['cmd.run'](cmd).splitlines()
|
||||
known_hosts = list(_parse_openssh_output(lines))
|
||||
return known_hosts[0] if known_hosts else None
|
||||
|
||||
|
||||
def recv_known_host(user, hostname, enc=None, port=None, hash_hostname=False):
|
||||
'''
|
||||
Retreive information about host public key from remote server
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' ssh.recv_known_host <user> <hostname> enc=<enc> port=<port>
|
||||
'''
|
||||
chunks = ['ssh-keyscan', ]
|
||||
if port:
|
||||
chunks += ['-p', str(port)]
|
||||
if enc:
|
||||
chunks += ['-t', str(enc)]
|
||||
if hash_hostname:
|
||||
chunks.append('-H')
|
||||
chunks.append(str(hostname))
|
||||
cmd = ' '.join(chunks)
|
||||
lines = __salt__['cmd.run'](cmd).splitlines()
|
||||
known_hosts = list(_parse_openssh_output(lines))
|
||||
return known_hosts[0] if known_hosts else None
|
||||
|
||||
|
||||
def check_known_host(user, hostname, key=None, fingerprint=None,
|
||||
config='.ssh/known_hosts'):
|
||||
'''
|
||||
Check the record in known_hosts file, either by its value or by fingerprint
|
||||
(it's enough to set up either key or fingerprint, you don't need to set up
|
||||
both).
|
||||
|
||||
If provided key or fingerprint doesn't match with stored value, return
|
||||
"update", if no value is found for a given host, return "add", otherwise
|
||||
return "exists".
|
||||
|
||||
If neither key, nor fingerprint is defined, then additional validation is
|
||||
not performed.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' ssh.check_known_host <user> <hostname> key='AAAA...FAaQ=='
|
||||
'''
|
||||
known_host = get_known_host(user, hostname, config=config)
|
||||
if not known_host:
|
||||
return 'add'
|
||||
if key:
|
||||
return 'exists' if key == known_host['key'] else 'update'
|
||||
elif fingerprint:
|
||||
return 'exists' if fingerprint == known_host['fingerprint'] else 'update'
|
||||
else:
|
||||
return 'exists'
|
||||
|
||||
|
||||
def rm_known_host(user, hostname, config='.ssh/known_hosts'):
|
||||
'''
|
||||
Remove all keys belonging to hostname from a known_hosts file.
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' ssh.rm_known_host <user> <hostname>
|
||||
'''
|
||||
uinfo = __salt__['user.info'](user)
|
||||
full = os.path.join(uinfo['home'], config)
|
||||
if not os.path.isfile(full):
|
||||
return {'status': 'error',
|
||||
'error': 'Known hosts file {0} does not exist'.format(full)}
|
||||
cmd = 'ssh-keygen -R "{0}" -f "{1}"'.format(hostname, full)
|
||||
cmd_result = __salt__['cmd.run'](cmd).strip()
|
||||
return {'status': 'removed', 'comment': cmd_result}
|
||||
|
||||
|
||||
def set_known_host(user, hostname,
|
||||
fingerprint=None,
|
||||
port=None,
|
||||
enc=None,
|
||||
hash_hostname=True,
|
||||
config='.ssh/known_hosts'):
|
||||
'''
|
||||
Download SSH public key from remote host "hostname", optionally validate
|
||||
its fingerprint against "fingerprint" variable and save the record in the
|
||||
known_hosts file.
|
||||
|
||||
If such a record does already exists in there, do nothing.
|
||||
|
||||
|
||||
CLI Example::
|
||||
|
||||
salt '*' ssh.set_known_host <user> fingerprint='xx:xx:..:xx' enc='ssh-rsa'\
|
||||
config='.ssh/known_hosts'
|
||||
'''
|
||||
update_required = False
|
||||
stored_host = get_known_host(user, hostname, config)
|
||||
|
||||
if not stored_host:
|
||||
update_required = True
|
||||
elif fingerprint and fingerprint != stored_host['fingerprint']:
|
||||
update_required = True
|
||||
|
||||
if not update_required:
|
||||
return {'status': 'exists', 'key': stored_host}
|
||||
|
||||
remote_host = recv_known_host(user, hostname, enc=enc, port=port,
|
||||
hash_hostname=True)
|
||||
if not remote_host:
|
||||
return {'status': 'error',
|
||||
'error': 'Unable to receive remote host key'}
|
||||
|
||||
if fingerprint and fingerprint != remote_host['fingerprint']:
|
||||
return {'status': 'error',
|
||||
'error': ('Remote host public key found but its fingerprint '
|
||||
'does not match one you have provided')}
|
||||
|
||||
# remove everything we had in the config so far
|
||||
rm_known_host(user, hostname, config=config)
|
||||
# set up new value
|
||||
uinfo = __salt__['user.info'](user)
|
||||
full = os.path.join(uinfo['home'], config)
|
||||
line = '{hostname} {enc} {key}\n'.format(**remote_host)
|
||||
with open(full, 'w') as fd:
|
||||
fd.write(line)
|
||||
return {'status': 'updated', 'old': stored_host, 'new': remote_host}
|
||||
|
||||
status = check_known_host(user, hostname, fingerprint=fingerprint,
|
||||
config=config)
|
||||
if status == 'exists':
|
||||
return None
|
||||
|
104
salt/states/ssh_known_hosts.py
Normal file
104
salt/states/ssh_known_hosts.py
Normal file
@ -0,0 +1,104 @@
|
||||
'''
|
||||
SSH known hosts management
|
||||
==========================
|
||||
|
||||
Manage the information stored in the known_hosts files
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
github.com:
|
||||
ssh_known_hosts:
|
||||
- present
|
||||
- user: root
|
||||
- fingerprint: 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48
|
||||
|
||||
example.com:
|
||||
ssh_known_hosts:
|
||||
- absent
|
||||
- user: root
|
||||
'''
|
||||
|
||||
def present(
|
||||
name,
|
||||
user,
|
||||
fingerprint=None,
|
||||
port=None,
|
||||
enc=None,
|
||||
config='.ssh/known_hosts'):
|
||||
'''
|
||||
Verifies that the specified host is known by the specified user
|
||||
|
||||
name
|
||||
The name of the remote host (i.e. "github.com")
|
||||
|
||||
user
|
||||
The user who owns the ssh authorized keys file to modify
|
||||
|
||||
enc
|
||||
Defines what type of key is being used, can be ssh-rsa or ssh-dss
|
||||
|
||||
fingerprint
|
||||
The fingerprint of the key which must be presented in the known_hosts
|
||||
file
|
||||
|
||||
port
|
||||
optional parameter, denoting the port of the remote host, which will be
|
||||
used in case, if the public key will be requested from it. By default
|
||||
the port 22 is used.
|
||||
|
||||
config
|
||||
The location of the authorized keys file relative to the user's home
|
||||
directory, defaults to ".ssh/known_hosts"
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': ''}
|
||||
|
||||
result = __salt__['ssh.set_known_host'](user, name,
|
||||
fingerprint=fingerprint,
|
||||
port=port,
|
||||
enc=enc,
|
||||
config=config)
|
||||
if result['status'] == 'exists':
|
||||
return {'name': name,
|
||||
'result': None,
|
||||
'comment': '{0} already exists in {1}'.format(name, config)}
|
||||
elif result['status'] == 'error':
|
||||
return {'name': name,
|
||||
'result': False,
|
||||
'comment': result['error']}
|
||||
else: # 'updated'
|
||||
return {'name': name,
|
||||
'result': True,
|
||||
'changes': {'old': result['old'], 'new': result['new']},
|
||||
'comment': '{0}\'s key saved to {1} (fingerprint: {2})'.format(
|
||||
name, config, result['new']['fingerprint'])}
|
||||
|
||||
|
||||
def absent(name, user, config='.ssh/known_hosts'):
|
||||
'''
|
||||
Verifies that the specified host is not known by the given user
|
||||
|
||||
name
|
||||
The host name
|
||||
|
||||
user
|
||||
The user who owns the ssh authorized keys file to modify
|
||||
|
||||
config
|
||||
The location of the authorized keys file relative to the user's home
|
||||
directory, defaults to ".ssh/known_hosts"
|
||||
'''
|
||||
ret = {'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': ''}
|
||||
known_host = __salt__['ssh.get_known_host'](user, name, config=config)
|
||||
if not known_host:
|
||||
return dict(ret, result=None, comment='Host is already absent')
|
||||
rm_result = __salt__['ssh.rm_known_host'](user, name, config=config)
|
||||
if rm_result['status'] == 'error':
|
||||
return dict(ret, result=False, comment=rm_result['error'])
|
||||
else:
|
||||
return dict(ret, result=True, comment=rm_result['comment'])
|
1
tests/integration/files/ssh/authorized_keys
Normal file
1
tests/integration/files/ssh/authorized_keys
Normal file
@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== github.com
|
1
tests/integration/files/ssh/known_hosts
Normal file
1
tests/integration/files/ssh/known_hosts
Normal file
@ -0,0 +1 @@
|
||||
|1|muzcBqgq7+ByUY7aLICytOff8UI=|rZ1JBNlIOqRnwwsJl9yP+xMxgf8= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
1
tests/integration/files/ssh/raw
Normal file
1
tests/integration/files/ssh/raw
Normal file
@ -0,0 +1 @@
|
||||
AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
|
148
tests/integration/modules/ssh.py
Normal file
148
tests/integration/modules/ssh.py
Normal file
@ -0,0 +1,148 @@
|
||||
'''
|
||||
Test the ssh module
|
||||
'''
|
||||
# Import python libs
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
# Import Salt libs
|
||||
from saltunittest import TestLoader, TextTestRunner
|
||||
import integration
|
||||
from integration import TestDaemon
|
||||
|
||||
|
||||
AUTHORIZED_KEYS = os.path.join(integration.TMP, 'authorized_keys')
|
||||
KNOWN_HOSTS = os.path.join(integration.TMP, 'known_hosts')
|
||||
GITHUB_FINGERPRINT = '16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48'
|
||||
|
||||
|
||||
class SSHModuleTest(integration.ModuleCase):
|
||||
'''
|
||||
Test the ssh module
|
||||
'''
|
||||
def setUp(self):
|
||||
super(SSHModuleTest, self).setUp()
|
||||
with open(os.path.join(integration.FILES, 'ssh', 'raw')) as fd:
|
||||
self.key = fd.read().strip()
|
||||
|
||||
def tearDown(self):
|
||||
if os.path.isfile(AUTHORIZED_KEYS):
|
||||
os.remove(AUTHORIZED_KEYS)
|
||||
if os.path.isfile(KNOWN_HOSTS):
|
||||
os.remove(KNOWN_HOSTS)
|
||||
super(SSHModuleTest, self).tearDown()
|
||||
|
||||
def test_auth_keys(self):
|
||||
shutil.copyfile(
|
||||
os.path.join(integration.FILES, 'ssh', 'authorized_keys'),
|
||||
AUTHORIZED_KEYS)
|
||||
ret = self.run_function('ssh.auth_keys', ['root', AUTHORIZED_KEYS])
|
||||
self.assertEqual(len(ret.items()), 1) # exactply one key is found
|
||||
key_data = ret.items()[0][1]
|
||||
self.assertEqual(key_data['comment'], 'github.com')
|
||||
self.assertEqual(key_data['enc'], 'ssh-rsa')
|
||||
self.assertEqual(key_data['options'], [])
|
||||
self.assertEqual(key_data['fingerprint'], GITHUB_FINGERPRINT)
|
||||
|
||||
def test_get_known_host(self):
|
||||
"""
|
||||
Check that known host information is returned from ~/.ssh/config
|
||||
"""
|
||||
shutil.copyfile(
|
||||
os.path.join(integration.FILES, 'ssh', 'known_hosts'),
|
||||
KNOWN_HOSTS)
|
||||
arg = ['root', 'github.com']
|
||||
kwargs = {'config': KNOWN_HOSTS}
|
||||
ret = self.run_function('ssh.get_known_host', arg, **kwargs)
|
||||
self.assertEqual(ret['enc'], 'ssh-rsa')
|
||||
self.assertEqual(ret['key'], self.key)
|
||||
self.assertEqual(ret['fingerprint'], GITHUB_FINGERPRINT)
|
||||
|
||||
def test_recv_known_host(self):
|
||||
"""
|
||||
Check that known host information is returned from remote host
|
||||
"""
|
||||
ret = self.run_function('ssh.recv_known_host', ['root', 'github.com'])
|
||||
self.assertEqual(ret['enc'], 'ssh-rsa')
|
||||
self.assertEqual(ret['key'], self.key)
|
||||
self.assertEqual(ret['fingerprint'], GITHUB_FINGERPRINT)
|
||||
|
||||
def test_check_known_host_add(self):
|
||||
"""
|
||||
Check known hosts by its fingerprint. File needs to be updated
|
||||
"""
|
||||
arg = ['root', 'github.com']
|
||||
kwargs = {'fingerprint': GITHUB_FINGERPRINT, 'config': KNOWN_HOSTS}
|
||||
ret = self.run_function('ssh.check_known_host', arg, **kwargs)
|
||||
self.assertEqual(ret, 'add')
|
||||
|
||||
|
||||
def test_check_known_host_update(self):
|
||||
shutil.copyfile(
|
||||
os.path.join(integration.FILES, 'ssh', 'known_hosts'),
|
||||
KNOWN_HOSTS)
|
||||
arg = ['root', 'github.com']
|
||||
kwargs = {'config': KNOWN_HOSTS}
|
||||
# wrong fingerprint
|
||||
ret = self.run_function('ssh.check_known_host', arg,
|
||||
**dict(kwargs, fingerprint='aa:bb:cc:dd'))
|
||||
self.assertEqual(ret, 'update')
|
||||
# wrong keyfile
|
||||
ret = self.run_function('ssh.check_known_host', arg,
|
||||
**dict(kwargs, key='YQ=='))
|
||||
self.assertEqual(ret, 'update')
|
||||
|
||||
def test_check_known_host_exists(self):
|
||||
shutil.copyfile(
|
||||
os.path.join(integration.FILES, 'ssh', 'known_hosts'),
|
||||
KNOWN_HOSTS)
|
||||
arg = ['root', 'github.com']
|
||||
kwargs = {'config': KNOWN_HOSTS}
|
||||
# wrong fingerprint
|
||||
ret = self.run_function('ssh.check_known_host', arg,
|
||||
**dict(kwargs, fingerprint=GITHUB_FINGERPRINT))
|
||||
self.assertEqual(ret, 'exists')
|
||||
# wrong keyfile
|
||||
ret = self.run_function('ssh.check_known_host', arg,
|
||||
**dict(kwargs, key=self.key))
|
||||
self.assertEqual(ret, 'exists')
|
||||
|
||||
def test_rm_known_host(self):
|
||||
shutil.copyfile(
|
||||
os.path.join(integration.FILES, 'ssh', 'known_hosts'),
|
||||
KNOWN_HOSTS)
|
||||
arg = ['root', 'github.com']
|
||||
kwargs = {'config': KNOWN_HOSTS, 'key': self.key}
|
||||
# before removal
|
||||
ret = self.run_function('ssh.check_known_host', arg, **kwargs)
|
||||
self.assertEqual(ret, 'exists')
|
||||
# remove
|
||||
self.run_function('ssh.rm_known_host', arg, config=KNOWN_HOSTS)
|
||||
# after removal
|
||||
ret = self.run_function('ssh.check_known_host', arg, **kwargs)
|
||||
self.assertEqual(ret, 'add')
|
||||
|
||||
def test_set_known_host(self):
|
||||
# add item
|
||||
ret = self.run_function('ssh.set_known_host', ['root', 'github.com'],
|
||||
config=KNOWN_HOSTS)
|
||||
self.assertEqual(ret['status'], 'updated')
|
||||
self.assertEqual(ret['old'], None)
|
||||
self.assertEqual(ret['new']['fingerprint'], GITHUB_FINGERPRINT)
|
||||
# check that item does exist
|
||||
ret = self.run_function('ssh.get_known_host', ['root', 'github.com'],
|
||||
config=KNOWN_HOSTS)
|
||||
self.assertEqual(ret['fingerprint'], GITHUB_FINGERPRINT)
|
||||
# add the same item once again
|
||||
ret = self.run_function('ssh.set_known_host', ['root', 'github.com'],
|
||||
config=KNOWN_HOSTS)
|
||||
self.assertEqual(ret['status'], 'exists')
|
||||
|
||||
if __name__ == "__main__":
|
||||
loader = TestLoader()
|
||||
tests = loader.loadTestsFromTestCase(SSHModuleTest)
|
||||
print('Setting up Salt daemons to execute tests')
|
||||
with TestDaemon():
|
||||
runner = TextTestRunner(verbosity=1).run(tests)
|
||||
sys.exit(runner.wasSuccessful())
|
73
tests/integration/states/ssh.py
Normal file
73
tests/integration/states/ssh.py
Normal file
@ -0,0 +1,73 @@
|
||||
'''
|
||||
Test the ssh_known_hosts state
|
||||
'''
|
||||
import os
|
||||
import shutil
|
||||
import integration
|
||||
|
||||
|
||||
KNOWN_HOSTS = os.path.join(integration.TMP, 'known_hosts')
|
||||
GITHUB_FINGERPRINT = '16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48'
|
||||
|
||||
|
||||
class SSHKnownHostsStateTest(integration.ModuleCase):
|
||||
'''
|
||||
Validate the ssh state
|
||||
'''
|
||||
def tearDown(self):
|
||||
if os.path.isfile(KNOWN_HOSTS):
|
||||
os.remove(KNOWN_HOSTS)
|
||||
super(SSHKnownHostsStateTest, self).tearDown()
|
||||
|
||||
def test_present(self):
|
||||
'''
|
||||
ssh_known_hosts.present
|
||||
'''
|
||||
# save once
|
||||
_ret = self.run_state('ssh_known_hosts.present',
|
||||
name='github.com',
|
||||
user='root',
|
||||
fingerprint=GITHUB_FINGERPRINT,
|
||||
config=KNOWN_HOSTS)
|
||||
ret = _ret.values()[0]
|
||||
self.assertTrue(ret['result'], ret)
|
||||
# save twice
|
||||
_ret = self.run_state('ssh_known_hosts.present',
|
||||
name='github.com',
|
||||
user='root',
|
||||
fingerprint=GITHUB_FINGERPRINT,
|
||||
config=KNOWN_HOSTS)
|
||||
ret = _ret.values()[0]
|
||||
self.assertEqual(ret['result'], None, ret)
|
||||
|
||||
def test_present_fail(self):
|
||||
# save something wrong
|
||||
_ret = self.run_state('ssh_known_hosts.present',
|
||||
name='github.com',
|
||||
user='root',
|
||||
fingerprint='aa:bb:cc:dd',
|
||||
config=KNOWN_HOSTS)
|
||||
ret = _ret.values()[0]
|
||||
self.assertFalse(ret['result'], ret)
|
||||
|
||||
def test_absent(self):
|
||||
'''
|
||||
ssh_known_hosts.absent
|
||||
'''
|
||||
shutil.copyfile(
|
||||
os.path.join(integration.FILES, 'ssh', 'known_hosts'),
|
||||
KNOWN_HOSTS)
|
||||
# remove once
|
||||
_ret = self.run_state('ssh_known_hosts.absent',
|
||||
name='github.com',
|
||||
user='root',
|
||||
config=KNOWN_HOSTS)
|
||||
ret = _ret.values()[0]
|
||||
self.assertTrue(ret['result'], ret)
|
||||
# remove twice
|
||||
_ret = self.run_state('ssh_known_hosts.absent',
|
||||
name='github.com',
|
||||
user='root',
|
||||
config=KNOWN_HOSTS)
|
||||
ret = _ret.values()[0]
|
||||
self.assertEqual(ret['result'], None, ret)
|
Loading…
Reference in New Issue
Block a user