mirror of
https://github.com/valitydev/salt.git
synced 2024-11-09 01:36:48 +00:00
668 lines
21 KiB
Python
668 lines
21 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# Import python libs
|
|
from __future__ import absolute_import, print_function, unicode_literals
|
|
import os
|
|
import uuid
|
|
import hashlib
|
|
import logging
|
|
import psutil
|
|
import shutil
|
|
import signal
|
|
import tempfile
|
|
import textwrap
|
|
|
|
# Import Salt Testing libs
|
|
from tests.support.case import ModuleCase
|
|
from tests.support.helpers import (
|
|
get_unused_localhost_port,
|
|
skip_if_not_root,
|
|
with_tempfile)
|
|
from tests.support.unit import skipIf
|
|
import tests.support.paths as paths
|
|
|
|
# Import salt libs
|
|
import salt.utils.files
|
|
import salt.utils.path
|
|
import salt.utils.platform
|
|
import salt.utils.stringutils
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class CPModuleTest(ModuleCase):
|
|
'''
|
|
Validate the cp module
|
|
'''
|
|
def run_function(self, *args, **kwargs):
|
|
'''
|
|
Ensure that results are decoded
|
|
|
|
TODO: maybe move this behavior to ModuleCase itself?
|
|
'''
|
|
return salt.utils.data.decode(
|
|
super(CPModuleTest, self).run_function(*args, **kwargs)
|
|
)
|
|
|
|
@with_tempfile()
|
|
def test_get_file(self, tgt):
|
|
'''
|
|
cp.get_file
|
|
'''
|
|
self.run_function(
|
|
'cp.get_file',
|
|
[
|
|
'salt://grail/scene33',
|
|
tgt,
|
|
])
|
|
with salt.utils.files.fopen(tgt, 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
def test_get_file_to_dir(self):
|
|
'''
|
|
cp.get_file
|
|
'''
|
|
tgt = os.path.join(paths.TMP, '')
|
|
self.run_function(
|
|
'cp.get_file',
|
|
[
|
|
'salt://grail/scene33',
|
|
tgt,
|
|
])
|
|
with salt.utils.files.fopen(tgt + 'scene33', 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
@with_tempfile()
|
|
def test_get_file_templated_paths(self, tgt):
|
|
'''
|
|
cp.get_file
|
|
'''
|
|
self.run_function(
|
|
'cp.get_file',
|
|
[
|
|
'salt://{{grains.test_grain}}',
|
|
tgt.replace('cheese', '{{grains.test_grain}}')
|
|
],
|
|
template='jinja'
|
|
)
|
|
with salt.utils.files.fopen(tgt, 'r') as cheese:
|
|
data = salt.utils.stringutils.to_unicode(cheese.read())
|
|
self.assertIn('Gromit', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
@with_tempfile()
|
|
def test_get_file_gzipped(self, tgt):
|
|
'''
|
|
cp.get_file
|
|
'''
|
|
src = os.path.join(paths.FILES, 'file', 'base', 'file.big')
|
|
with salt.utils.files.fopen(src, 'rb') as fp_:
|
|
hash_str = hashlib.md5(fp_.read()).hexdigest()
|
|
|
|
self.run_function(
|
|
'cp.get_file',
|
|
[
|
|
'salt://file.big',
|
|
tgt,
|
|
],
|
|
gzip=5
|
|
)
|
|
with salt.utils.files.fopen(tgt, 'rb') as scene:
|
|
data = scene.read()
|
|
self.assertEqual(hash_str, hashlib.md5(data).hexdigest())
|
|
data = salt.utils.stringutils.to_unicode(data)
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
def test_get_file_makedirs(self):
|
|
'''
|
|
cp.get_file
|
|
'''
|
|
tgt = os.path.join(paths.TMP, 'make', 'dirs', 'scene33')
|
|
self.run_function(
|
|
'cp.get_file',
|
|
[
|
|
'salt://grail/scene33',
|
|
tgt,
|
|
],
|
|
makedirs=True
|
|
)
|
|
self.addCleanup(shutil.rmtree, os.path.join(paths.TMP, 'make'), ignore_errors=True)
|
|
with salt.utils.files.fopen(tgt, 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
@with_tempfile()
|
|
def test_get_template(self, tgt):
|
|
'''
|
|
cp.get_template
|
|
'''
|
|
self.run_function(
|
|
'cp.get_template',
|
|
['salt://grail/scene33', tgt],
|
|
spam='bacon')
|
|
with salt.utils.files.fopen(tgt, 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('bacon', data)
|
|
self.assertNotIn('spam', data)
|
|
|
|
def test_get_dir(self):
|
|
'''
|
|
cp.get_dir
|
|
'''
|
|
tgt = os.path.join(paths.TMP, 'many')
|
|
self.run_function(
|
|
'cp.get_dir',
|
|
[
|
|
'salt://grail',
|
|
tgt
|
|
])
|
|
self.assertIn('grail', os.listdir(tgt))
|
|
self.assertIn('36', os.listdir(os.path.join(tgt, 'grail')))
|
|
self.assertIn('empty', os.listdir(os.path.join(tgt, 'grail')))
|
|
self.assertIn('scene', os.listdir(os.path.join(tgt, 'grail', '36')))
|
|
|
|
def test_get_dir_templated_paths(self):
|
|
'''
|
|
cp.get_dir
|
|
'''
|
|
tgt = os.path.join(paths.TMP, 'many')
|
|
self.run_function(
|
|
'cp.get_dir',
|
|
[
|
|
'salt://{{grains.script}}',
|
|
tgt.replace('many', '{{grains.alot}}')
|
|
]
|
|
)
|
|
self.assertIn('grail', os.listdir(tgt))
|
|
self.assertIn('36', os.listdir(os.path.join(tgt, 'grail')))
|
|
self.assertIn('empty', os.listdir(os.path.join(tgt, 'grail')))
|
|
self.assertIn('scene', os.listdir(os.path.join(tgt, 'grail', '36')))
|
|
|
|
# cp.get_url tests
|
|
|
|
@with_tempfile()
|
|
def test_get_url(self, tgt):
|
|
'''
|
|
cp.get_url with salt:// source given
|
|
'''
|
|
self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
'salt://grail/scene33',
|
|
tgt,
|
|
])
|
|
with salt.utils.files.fopen(tgt, 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
def test_get_url_makedirs(self):
|
|
'''
|
|
cp.get_url
|
|
'''
|
|
tgt = os.path.join(paths.TMP, 'make', 'dirs', 'scene33')
|
|
self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
'salt://grail/scene33',
|
|
tgt,
|
|
],
|
|
makedirs=True
|
|
)
|
|
self.addCleanup(shutil.rmtree, os.path.join(paths.TMP, 'make'), ignore_errors=True)
|
|
with salt.utils.files.fopen(tgt, 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
def test_get_url_dest_empty(self):
|
|
'''
|
|
cp.get_url with salt:// source given and destination omitted.
|
|
'''
|
|
ret = self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
'salt://grail/scene33',
|
|
])
|
|
with salt.utils.files.fopen(ret, 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
def test_get_url_no_dest(self):
|
|
'''
|
|
cp.get_url with salt:// source given and destination set as None
|
|
'''
|
|
tgt = None
|
|
ret = self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
'salt://grail/scene33',
|
|
tgt,
|
|
])
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', ret)
|
|
|
|
def test_get_url_nonexistent_source(self):
|
|
'''
|
|
cp.get_url with nonexistent salt:// source given
|
|
'''
|
|
tgt = None
|
|
ret = self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
'salt://grail/nonexistent_scene',
|
|
tgt,
|
|
])
|
|
self.assertEqual(ret, False)
|
|
|
|
def test_get_url_to_dir(self):
|
|
'''
|
|
cp.get_url with salt:// source
|
|
'''
|
|
tgt = os.path.join(paths.TMP, '')
|
|
self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
'salt://grail/scene33',
|
|
tgt,
|
|
])
|
|
with salt.utils.files.fopen(tgt + 'scene33', 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
@with_tempfile()
|
|
def test_get_url_https(self, tgt):
|
|
'''
|
|
cp.get_url with https:// source given
|
|
'''
|
|
self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
'https://repo.saltstack.com/index.html',
|
|
tgt,
|
|
])
|
|
with salt.utils.files.fopen(tgt, 'r') as instructions:
|
|
data = salt.utils.stringutils.to_unicode(instructions.read())
|
|
self.assertIn('Bootstrap', data)
|
|
self.assertIn('Debian', data)
|
|
self.assertIn('Windows', data)
|
|
self.assertNotIn('AYBABTU', data)
|
|
|
|
def test_get_url_https_dest_empty(self):
|
|
'''
|
|
cp.get_url with https:// source given and destination omitted.
|
|
'''
|
|
ret = self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
'https://repo.saltstack.com/index.html',
|
|
])
|
|
with salt.utils.files.fopen(ret, 'r') as instructions:
|
|
data = salt.utils.stringutils.to_unicode(instructions.read())
|
|
self.assertIn('Bootstrap', data)
|
|
self.assertIn('Debian', data)
|
|
self.assertIn('Windows', data)
|
|
self.assertNotIn('AYBABTU', data)
|
|
|
|
def test_get_url_https_no_dest(self):
|
|
'''
|
|
cp.get_url with https:// source given and destination set as None
|
|
'''
|
|
tgt = None
|
|
ret = self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
'https://repo.saltstack.com/index.html',
|
|
tgt,
|
|
])
|
|
self.assertIn('Bootstrap', ret)
|
|
self.assertIn('Debian', ret)
|
|
self.assertIn('Windows', ret)
|
|
self.assertNotIn('AYBABTU', ret)
|
|
|
|
def test_get_url_file(self):
|
|
'''
|
|
cp.get_url with file:// source given
|
|
'''
|
|
tgt = ''
|
|
src = os.path.join('file://', paths.FILES, 'file', 'base', 'file.big')
|
|
ret = self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
src,
|
|
tgt,
|
|
])
|
|
with salt.utils.files.fopen(ret, 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
def test_get_url_file_no_dest(self):
|
|
'''
|
|
cp.get_url with file:// source given and destination set as None
|
|
'''
|
|
tgt = None
|
|
src = os.path.join('file://', paths.FILES, 'file', 'base', 'file.big')
|
|
ret = self.run_function(
|
|
'cp.get_url',
|
|
[
|
|
src,
|
|
tgt,
|
|
])
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', ret)
|
|
self.assertNotIn('bacon', ret)
|
|
|
|
# cp.get_file_str tests
|
|
|
|
def test_get_file_str_salt(self):
|
|
'''
|
|
cp.get_file_str with salt:// source given
|
|
'''
|
|
src = 'salt://grail/scene33'
|
|
ret = self.run_function(
|
|
'cp.get_file_str',
|
|
[
|
|
src,
|
|
])
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', ret)
|
|
|
|
def test_get_file_str_nonexistent_source(self):
|
|
'''
|
|
cp.get_file_str with nonexistent salt:// source given
|
|
'''
|
|
src = 'salt://grail/nonexistent_scene'
|
|
ret = self.run_function(
|
|
'cp.get_file_str',
|
|
[
|
|
src,
|
|
])
|
|
self.assertEqual(ret, False)
|
|
|
|
def test_get_file_str_https(self):
|
|
'''
|
|
cp.get_file_str with https:// source given
|
|
'''
|
|
src = 'https://repo.saltstack.com/index.html'
|
|
ret = self.run_function(
|
|
'cp.get_file_str',
|
|
[
|
|
src,
|
|
])
|
|
self.assertIn('Bootstrap', ret)
|
|
self.assertIn('Debian', ret)
|
|
self.assertIn('Windows', ret)
|
|
self.assertNotIn('AYBABTU', ret)
|
|
|
|
def test_get_file_str_local(self):
|
|
'''
|
|
cp.get_file_str with file:// source given
|
|
'''
|
|
src = os.path.join('file://', paths.FILES, 'file', 'base', 'file.big')
|
|
ret = self.run_function(
|
|
'cp.get_file_str',
|
|
[
|
|
src,
|
|
])
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', ret)
|
|
self.assertNotIn('bacon', ret)
|
|
|
|
# caching tests
|
|
|
|
def test_cache_file(self):
|
|
'''
|
|
cp.cache_file
|
|
'''
|
|
ret = self.run_function(
|
|
'cp.cache_file',
|
|
[
|
|
'salt://grail/scene33',
|
|
])
|
|
with salt.utils.files.fopen(ret, 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('KNIGHT: They\'re nervous, sire.', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
def test_cache_files(self):
|
|
'''
|
|
cp.cache_files
|
|
'''
|
|
ret = self.run_function(
|
|
'cp.cache_files',
|
|
[
|
|
['salt://grail/scene33', 'salt://grail/36/scene'],
|
|
])
|
|
for path in ret:
|
|
with salt.utils.files.fopen(path, 'r') as scene:
|
|
data = salt.utils.stringutils.to_unicode(scene.read())
|
|
self.assertIn('ARTHUR:', data)
|
|
self.assertNotIn('bacon', data)
|
|
|
|
@with_tempfile()
|
|
def test_cache_master(self, tgt):
|
|
'''
|
|
cp.cache_master
|
|
'''
|
|
ret = self.run_function(
|
|
'cp.cache_master',
|
|
[tgt],
|
|
)
|
|
for path in ret:
|
|
self.assertTrue(os.path.exists(path))
|
|
|
|
def test_cache_local_file(self):
|
|
'''
|
|
cp.cache_local_file
|
|
'''
|
|
src = os.path.join(paths.TMP, 'random')
|
|
with salt.utils.files.fopen(src, 'w+') as fn_:
|
|
fn_.write(salt.utils.stringutils.to_str('foo'))
|
|
ret = self.run_function(
|
|
'cp.cache_local_file',
|
|
[src])
|
|
with salt.utils.files.fopen(ret, 'r') as cp_:
|
|
self.assertEqual(
|
|
salt.utils.stringutils.to_unicode(cp_.read()),
|
|
'foo'
|
|
)
|
|
|
|
@skipIf(not salt.utils.path.which('nginx'), 'nginx not installed')
|
|
@skip_if_not_root
|
|
def test_cache_remote_file(self):
|
|
'''
|
|
cp.cache_file
|
|
'''
|
|
nginx_port = get_unused_localhost_port()
|
|
url_prefix = 'http://localhost:{0}/'.format(nginx_port)
|
|
temp_dir = tempfile.mkdtemp(dir=paths.TMP)
|
|
self.addCleanup(shutil.rmtree, temp_dir, ignore_errors=True)
|
|
nginx_root_dir = os.path.join(temp_dir, 'root')
|
|
nginx_conf_dir = os.path.join(temp_dir, 'conf')
|
|
nginx_conf = os.path.join(nginx_conf_dir, 'nginx.conf')
|
|
nginx_pidfile = os.path.join(nginx_conf_dir, 'nginx.pid')
|
|
file_contents = 'Hello world!'
|
|
|
|
for dirname in (nginx_root_dir, nginx_conf_dir):
|
|
os.mkdir(dirname)
|
|
|
|
# Write the temp file
|
|
with salt.utils.files.fopen(os.path.join(nginx_root_dir, 'actual_file'), 'w') as fp_:
|
|
fp_.write(salt.utils.stringutils.to_str(file_contents))
|
|
|
|
# Write the nginx config
|
|
with salt.utils.files.fopen(nginx_conf, 'w') as fp_:
|
|
fp_.write(textwrap.dedent(salt.utils.stringutils.to_str(
|
|
'''\
|
|
user root;
|
|
worker_processes 1;
|
|
error_log {nginx_conf_dir}/server_error.log;
|
|
pid {nginx_pidfile};
|
|
|
|
events {{
|
|
worker_connections 1024;
|
|
}}
|
|
|
|
http {{
|
|
include /etc/nginx/mime.types;
|
|
default_type application/octet-stream;
|
|
|
|
access_log {nginx_conf_dir}/access.log;
|
|
error_log {nginx_conf_dir}/error.log;
|
|
|
|
server {{
|
|
listen {nginx_port} default_server;
|
|
server_name cachefile.local;
|
|
root {nginx_root_dir};
|
|
|
|
location ~ ^/301$ {{
|
|
return 301 /actual_file;
|
|
}}
|
|
|
|
location ~ ^/302$ {{
|
|
return 302 /actual_file;
|
|
}}
|
|
}}
|
|
}}'''.format(**locals())
|
|
)))
|
|
|
|
self.run_function(
|
|
'cmd.run',
|
|
[['nginx', '-c', nginx_conf]],
|
|
python_shell=False
|
|
)
|
|
with salt.utils.files.fopen(nginx_pidfile) as fp_:
|
|
nginx_pid = int(fp_.read().strip())
|
|
nginx_proc = psutil.Process(pid=nginx_pid)
|
|
self.addCleanup(nginx_proc.send_signal, signal.SIGQUIT)
|
|
|
|
for code in ('', '301', '302'):
|
|
url = url_prefix + (code or 'actual_file')
|
|
log.debug('attempting to cache %s', url)
|
|
ret = self.run_function('cp.cache_file', [url])
|
|
self.assertTrue(ret)
|
|
with salt.utils.files.fopen(ret) as fp_:
|
|
cached_contents = salt.utils.stringutils.to_unicode(fp_.read())
|
|
self.assertEqual(cached_contents, file_contents)
|
|
|
|
def test_list_states(self):
|
|
'''
|
|
cp.list_states
|
|
'''
|
|
ret = self.run_function(
|
|
'cp.list_states',
|
|
)
|
|
self.assertIn('core', ret)
|
|
self.assertIn('top', ret)
|
|
|
|
def test_list_minion(self):
|
|
'''
|
|
cp.list_minion
|
|
'''
|
|
self.run_function(
|
|
'cp.cache_file',
|
|
[
|
|
'salt://grail/scene33',
|
|
])
|
|
ret = self.run_function('cp.list_minion')
|
|
found = False
|
|
search = 'grail/scene33'
|
|
if salt.utils.platform.is_windows():
|
|
search = r'grail\scene33'
|
|
for path in ret:
|
|
if search in path:
|
|
found = True
|
|
break
|
|
self.assertTrue(found)
|
|
|
|
def test_is_cached(self):
|
|
'''
|
|
cp.is_cached
|
|
'''
|
|
self.run_function(
|
|
'cp.cache_file',
|
|
[
|
|
'salt://grail/scene33',
|
|
])
|
|
ret1 = self.run_function(
|
|
'cp.is_cached',
|
|
[
|
|
'salt://grail/scene33',
|
|
])
|
|
self.assertTrue(ret1)
|
|
ret2 = self.run_function(
|
|
'cp.is_cached',
|
|
[
|
|
'salt://fasldkgj/poicxzbn',
|
|
])
|
|
self.assertFalse(ret2)
|
|
|
|
def test_hash_file(self):
|
|
'''
|
|
cp.hash_file
|
|
'''
|
|
sha256_hash = self.run_function(
|
|
'cp.hash_file',
|
|
[
|
|
'salt://grail/scene33',
|
|
])
|
|
path = self.run_function(
|
|
'cp.cache_file',
|
|
[
|
|
'salt://grail/scene33',
|
|
])
|
|
with salt.utils.files.fopen(path, 'rb') as fn_:
|
|
data = fn_.read()
|
|
self.assertEqual(
|
|
sha256_hash['hsum'], hashlib.sha256(data).hexdigest())
|
|
|
|
@with_tempfile()
|
|
def test_get_file_from_env_predefined(self, tgt):
|
|
'''
|
|
cp.get_file
|
|
'''
|
|
tgt = os.path.join(paths.TMP, 'cheese')
|
|
try:
|
|
self.run_function('cp.get_file', ['salt://cheese', tgt])
|
|
with salt.utils.files.fopen(tgt, 'r') as cheese:
|
|
data = salt.utils.stringutils.to_unicode(cheese.read())
|
|
self.assertIn('Gromit', data)
|
|
self.assertNotIn('Comte', data)
|
|
finally:
|
|
os.unlink(tgt)
|
|
|
|
@with_tempfile()
|
|
def test_get_file_from_env_in_url(self, tgt):
|
|
tgt = os.path.join(paths.TMP, 'cheese')
|
|
try:
|
|
self.run_function('cp.get_file', ['salt://cheese?saltenv=prod', tgt])
|
|
with salt.utils.files.fopen(tgt, 'r') as cheese:
|
|
data = salt.utils.stringutils.to_unicode(cheese.read())
|
|
self.assertIn('Gromit', data)
|
|
self.assertIn('Comte', data)
|
|
finally:
|
|
os.unlink(tgt)
|
|
|
|
def test_push(self):
|
|
log_to_xfer = os.path.join(paths.TMP, uuid.uuid4().hex)
|
|
open(log_to_xfer, 'w').close() # pylint: disable=resource-leakage
|
|
try:
|
|
self.run_function('cp.push', [log_to_xfer])
|
|
tgt_cache_file = os.path.join(
|
|
paths.TMP,
|
|
'master-minion-root',
|
|
'cache',
|
|
'minions',
|
|
'minion',
|
|
'files',
|
|
paths.TMP,
|
|
log_to_xfer)
|
|
self.assertTrue(os.path.isfile(tgt_cache_file), 'File was not cached on the master')
|
|
finally:
|
|
os.unlink(tgt_cache_file)
|