salt/tests/unit/modules/test_cron.py
rallytime 68aabff0cf
Merge branch '2017.7' into '2018.3'
Conflicts:
  - pkg/windows/req.txt
  - salt/netapi/rest_tornado/saltnado.py
  - salt/utils/versions.py
  - tests/integration/states/test_file.py
2018-07-09 10:27:58 -04:00

1022 lines
49 KiB
Python

# -*- coding: utf-8 -*-
'''
:codeauthor: Mike Place <mp@saltstack.com>
'''
# Import python libs
from __future__ import absolute_import, unicode_literals, print_function
# Import Salt Testing libs
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.unit import TestCase, skipIf
from tests.support.mock import NO_MOCK, NO_MOCK_REASON, MagicMock, patch, call
# Import Salt libs
import salt.modules.cron as cron
from salt.ext.six.moves import builtins, range, StringIO
STUB_USER = 'root'
STUB_PATH = '/tmp'
STUB_CRON_TIMESTAMP = {'minute': '1',
'hour': '2',
'daymonth': '3',
'month': '4',
'dayweek': '5'}
STUB_SIMPLE_RAW_CRON = '5 0 * * * /tmp/no_script.sh'
STUB_SIMPLE_CRON_DICT = {'pre': ['5 0 * * * /tmp/no_script.sh'], 'crons': [], 'env': [], 'special': []}
STUB_CRON_SPACES = """
# Lines below here are managed by Salt, do not edit
TEST_VAR="a string with plenty of spaces"
# SALT_CRON_IDENTIFIER:echo "must be double spaced"
11 * * * * echo "must be double spaced"
"""
STUB_AT_SIGN = """
# Lines below here are managed by Salt, do not edit
# SALT_CRON_IDENTIFIER:echo "cron with @ sign"
@daily echo "cron with @ sign"
@daily
"""
L = '# Lines below here are managed by Salt, do not edit\n'
CRONTAB = StringIO()
def get_crontab(*args, **kw):
return CRONTAB.getvalue()
def set_crontab(val):
CRONTAB.seek(0)
CRONTAB.truncate(0)
CRONTAB.write(val)
def write_crontab(*args, **kw):
set_crontab('\n'.join(
[a.strip() for a in args[1]]))
return MagicMock()
@skipIf(NO_MOCK, NO_MOCK_REASON)
class CronTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {cron: {}}
def test__need_changes_new(self):
'''
New behavior, identifier will get track of the managed lines!
'''
with patch('salt.modules.cron.raw_cron',
new=MagicMock(side_effect=get_crontab)), \
patch('salt.modules.cron._write_cron_lines',
new=MagicMock(side_effect=write_crontab)):
# when there are no identifiers,
# we do not touch it
set_crontab(
L + '# SALT_CRON_IDENTIFIER:booh\n'
'* * * * * ls\n')
cron.set_job(
user='root',
minute='*',
hour='*',
daymonth='*',
month='*',
dayweek='*',
cmd='ls',
comment=None,
identifier=None,
)
c1 = get_crontab()
set_crontab(L + '* * * * * ls\n')
self.assertEqual(
c1,
'# Lines below here are managed by Salt, do not edit\n'
'# SALT_CRON_IDENTIFIER:booh\n'
'* * * * * ls\n'
'* * * * * ls'
)
# whenever we have an identifier, hourray even without comment
# we can match and edit the crontab in place
# without cluttering the crontab with new cmds
set_crontab(
L + '# SALT_CRON_IDENTIFIER:bar\n'
'* * * * * ls\n')
cron.set_job(
user='root',
minute='*',
hour='*',
daymonth='*',
month='*',
dayweek='*',
cmd='ls',
comment=None,
identifier='bar',
)
c5 = get_crontab()
set_crontab(L + '* * * * * ls\n')
self.assertEqual(
c5,
'# Lines below here are managed by Salt, do not edit\n'
'# SALT_CRON_IDENTIFIER:bar\n'
'* * * * * ls\n'
)
# we can even change the other parameters as well
# thx to the id
set_crontab(
L + '# SALT_CRON_IDENTIFIER:bar\n* * * * * ls\n')
cron.set_job(
user='root',
minute='1',
hour='2',
daymonth='3',
month='4',
dayweek='5',
cmd='foo',
comment='moo',
identifier='bar',
)
c6 = get_crontab()
self.assertEqual(
c6,
'# Lines below here are managed by Salt, do not edit\n'
'# moo SALT_CRON_IDENTIFIER:bar\n'
'1 2 3 4 5 foo'
)
def test__unicode_match(self):
with patch.object(builtins, '__salt_system_encoding__', 'utf-8'):
self.assertTrue(cron._cron_matched({'identifier': '1'}, 'foo', 1))
self.assertTrue(cron._cron_matched({'identifier': 'é'}, 'foo', 'é'))
self.assertTrue(cron._cron_matched({'identifier': u'é'}, 'foo', 'é'))
self.assertTrue(cron._cron_matched({'identifier': 'é'}, 'foo', u'é'))
self.assertTrue(cron._cron_matched({'identifier': u'é'}, 'foo', u'é'))
def test__need_changes_old(self):
'''
old behavior; ID has no special action
- If an id is found, it will be added as a new crontab
even if there is a cmd that looks like this one
- no comment, delete the cmd and readd it
- comment: idem
'''
with patch('salt.modules.cron.raw_cron',
new=MagicMock(side_effect=get_crontab)), \
patch('salt.modules.cron._write_cron_lines',
new=MagicMock(side_effect=write_crontab)):
set_crontab(L + '* * * * * ls\n\n')
cron.set_job(
user='root',
minute='*',
hour='*',
daymonth='*',
month='*',
dayweek='*',
cmd='ls',
comment=None,
identifier=cron.SALT_CRON_NO_IDENTIFIER,
)
c1 = get_crontab()
set_crontab(L + '* * * * * ls\n')
self.assertEqual(
c1,
'# Lines below here are managed by Salt, do not edit\n'
'* * * * * ls\n'
'\n'
)
cron.set_job(
user='root',
minute='*',
hour='*',
daymonth='*',
month='*',
dayweek='*',
cmd='ls',
comment='foo',
identifier=cron.SALT_CRON_NO_IDENTIFIER,
)
c2 = get_crontab()
self.assertEqual(
c2,
'# Lines below here are managed by Salt, do not edit\n'
'# foo\n* * * * * ls'
)
set_crontab(L + '* * * * * ls\n')
cron.set_job(
user='root',
minute='*',
hour='*',
daymonth='*',
month='*',
dayweek='*',
cmd='lsa',
comment='foo',
identifier='bar',
)
c3 = get_crontab()
self.assertEqual(
c3,
'# Lines below here are managed by Salt, do not edit\n'
'* * * * * ls\n'
'# foo SALT_CRON_IDENTIFIER:bar\n'
'* * * * * lsa'
)
set_crontab(L + '* * * * * ls\n')
cron.set_job(
user='root',
minute='*',
hour='*',
daymonth='*',
month='*',
dayweek='*',
cmd='foo',
comment='foo',
identifier='bar',
)
c4 = get_crontab()
self.assertEqual(
c4,
'# Lines below here are managed by Salt, do not edit\n'
'* * * * * ls\n'
'# foo SALT_CRON_IDENTIFIER:bar\n'
'* * * * * foo'
)
set_crontab(L + '* * * * * ls\n')
cron.set_job(
user='root',
minute='*',
hour='*',
daymonth='*',
month='*',
dayweek='*',
cmd='ls',
comment='foo',
identifier='bbar',
)
c4 = get_crontab()
self.assertEqual(
c4,
'# Lines below here are managed by Salt, do not edit\n'
'# foo SALT_CRON_IDENTIFIER:bbar\n'
'* * * * * ls'
)
def test__issue10959(self):
'''
handle multi old style crontabs
https://github.com/saltstack/salt/issues/10959
'''
with patch('salt.modules.cron.raw_cron',
new=MagicMock(side_effect=get_crontab)), \
patch('salt.modules.cron._write_cron_lines',
new=MagicMock(side_effect=write_crontab)):
set_crontab(
'# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
# as managed per salt, the last lines will be merged together !
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd\n'
'* * * * * samecmd\n'
'* * * * * otheridcmd\n'
'* * * * * otheridcmd\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n0 * * * * samecmd1\n'
'1 * * * * samecmd1\n'
'0 * * * * otheridcmd1\n'
'1 * * * * otheridcmd1\n'
# special case here, none id managed line with same command
# as a later id managed line will become managed
'# SALT_CRON_IDENTIFIER:1\n0 * * * * otheridcmd1\n'
'# SALT_CRON_IDENTIFIER:2\n0 * * * * otheridcmd1\n'
)
crons1 = cron.list_tab('root')
# the filtering is done on save, we reflect in listing
# the same that we have in a file, no matter what we
# have
self.assertEqual(crons1, {
'crons': [
{'cmd': 'ls', 'comment': 'uoo', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'NO ID SET',
'minute': '*', 'month': '*', 'commented': False},
{'cmd': 'too', 'comment': 'uuoo', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'NO ID SET',
'minute': '*', 'month': '*', 'commented': False},
{'cmd': 'zoo', 'comment': 'uuuoo', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'NO ID SET',
'minute': '*', 'month': '*', 'commented': False},
{'cmd': 'yoo', 'comment': '', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'NO ID SET',
'minute': '*', 'month': '*', 'commented': False},
{'cmd': 'xoo', 'comment': '', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'NO ID SET',
'minute': '*', 'month': '*', 'commented': False},
{'cmd': 'samecmd', 'comment': '', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'NO ID SET',
'minute': '*', 'month': '*', 'commented': False},
{'cmd': 'samecmd', 'comment': None, 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': None,
'minute': '*', 'month': '*', 'commented': False},
{'cmd': 'otheridcmd', 'comment': None, 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': None,
'minute': '*', 'month': '*', 'commented': False},
{'cmd': 'otheridcmd', 'comment': None, 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': None,
'minute': '*', 'month': '*', 'commented': False},
{'cmd': 'samecmd1', 'comment': '', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'NO ID SET',
'minute': '0', 'month': '*', 'commented': False},
{'cmd': 'samecmd1', 'comment': None, 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': None,
'minute': '1', 'month': '*', 'commented': False},
{'cmd': 'otheridcmd1', 'comment': None, 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': None,
'minute': '0', 'month': '*', 'commented': False},
{'cmd': 'otheridcmd1', 'comment': None, 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': None,
'minute': '1', 'month': '*', 'commented': False},
{'cmd': 'otheridcmd1', 'comment': '', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': '1',
'minute': '0', 'month': '*', 'commented': False},
{'cmd': 'otheridcmd1',
'comment': '', 'daymonth': '*', 'dayweek': '*',
'hour': '*', 'identifier': '2', 'minute': '0',
'month': '*', 'commented': False}
],
'env': [],
'pre': [],
'special': []})
# so yood so far, no problem for now, trying to save the
# multilines without id crons now
inc_tests = [
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd\n'
'* * * * * otheridcmd'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd\n'
'* * * * * otheridcmd'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd\n'
'* * * * * otheridcmd\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n'
'0 * * * * samecmd1'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd\n'
'* * * * * otheridcmd\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n1 * * * * samecmd1'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd\n'
'* * * * * otheridcmd\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n1 * * * * samecmd1\n'
'0 * * * * otheridcmd1'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd\n'
'* * * * * otheridcmd\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n1 * * * * samecmd1\n'
'1 * * * * otheridcmd1'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd\n'
'* * * * * otheridcmd\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n1 * * * * samecmd1\n'
'# SALT_CRON_IDENTIFIER:1\n0 * * * * otheridcmd1'),
#
('# Lines below here are managed by Salt, do not edit\n'
'# uoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * ls\n'
'# uuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * too\n'
'# uuuoo SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * zoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * yoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * xoo\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n* * * * * samecmd\n'
'* * * * * otheridcmd\n'
'# SALT_CRON_IDENTIFIER:NO ID SET\n1 * * * * samecmd1\n'
'# SALT_CRON_IDENTIFIER:1\n0 * * * * otheridcmd1\n'
'# SALT_CRON_IDENTIFIER:2\n0 * * * * otheridcmd1')
]
set_crontab('')
for idx, cr in enumerate(crons1['crons']):
cron.set_job('root', **cr)
self.assertEqual(
get_crontab(),
inc_tests[idx], (
"idx {0}\n'{1}'\n != \n'{2}'\n\n\n"
"\'{1}\' != \'{2}\'"
).format(
idx, get_crontab(), inc_tests[idx]))
def test_list_tab_commented_cron_jobs(self):
'''
handle commented cron jobs
https://github.com/saltstack/salt/issues/29082
'''
with patch('salt.modules.cron.raw_cron', MagicMock(side_effect=get_crontab)), \
patch('salt.modules.cron._write_cron_lines',
MagicMock(side_effect=write_crontab)):
set_crontab(
'# An unmanaged commented cron job\n'
'#0 * * * * /bin/true\n'
'# Lines below here are managed by Salt, do not edit\n'
'# cron_1 SALT_CRON_IDENTIFIER:cron_1\n#DISABLED#0 * * * * my_cmd_1\n'
'# cron_2 SALT_CRON_IDENTIFIER:cron_2\n#DISABLED#* * * * * my_cmd_2\n'
'# cron_3 SALT_CRON_IDENTIFIER:cron_3\n'
'#DISABLED#but it is a comment line'
'#DISABLED#0 * * * * my_cmd_3\n'
'# cron_4 SALT_CRON_IDENTIFIER:cron_4\n0 * * * * my_cmd_4\n'
)
crons1 = cron.list_tab('root')
self.assertEqual(crons1, {
'crons': [
{'cmd': 'my_cmd_1', 'comment': 'cron_1', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'cron_1',
'minute': '0', 'month': '*', 'commented': True},
{'cmd': 'my_cmd_2', 'comment': 'cron_2', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'cron_2',
'minute': '*', 'month': '*', 'commented': True},
{'cmd': 'line#DISABLED#0 * * * * my_cmd_3',
'comment': 'cron_3', 'daymonth': 'is',
'dayweek': 'comment', 'hour': 'it', 'identifier': 'cron_3',
'minute': 'but', 'month': 'a', 'commented': True},
{'cmd': 'my_cmd_4', 'comment': 'cron_4', 'daymonth': '*',
'dayweek': '*', 'hour': '*', 'identifier': 'cron_4',
'minute': '0', 'month': '*', 'commented': False},
],
'env': [],
'pre': ['# An unmanaged commented cron job', '#0 * * * * /bin/true'],
'special': []})
def test_cron_extra_spaces(self):
'''
Issue #38449
'''
with patch.dict(cron.__grains__, {'os': None}), \
patch('salt.modules.cron.raw_cron',
MagicMock(return_value=STUB_CRON_SPACES)):
ret = cron.list_tab('root')
eret = {'crons': [{'cmd': 'echo "must be double spaced"',
'comment': '',
'commented': False,
'daymonth': '*',
'dayweek': '*',
'hour': '*',
'identifier': 'echo "must be double spaced"',
'minute': '11',
'month': '*'}],
'env': [{'name': 'TEST_VAR', 'value': '"a string with plenty of spaces"'}],
'pre': [''],
'special': []}
self.assertEqual(eret, ret)
def test_cron_at_sign(self):
with patch.dict(cron.__grains__, {'os': None}), \
patch('salt.modules.cron.raw_cron',
MagicMock(return_value=STUB_AT_SIGN)):
ret = cron.list_tab('root')
eret = {'crons': [],
'env': [],
'pre': [''],
'special': [{u'cmd': u'echo "cron with @ sign"',
u'comment': u'',
u'commented': False,
u'identifier': u'echo "cron with @ sign"',
u'spec': u'@daily'}]}
self.assertDictEqual(eret, ret)
def test__load_tab(self):
with patch.dict(cron.__grains__, {'os_family': 'Solaris'}), \
patch('salt.modules.cron.raw_cron',
new=MagicMock(side_effect=[
(L + '\n'),
(L + '* * * * * ls\nn'),
(L + '# commented\n'
'#DISABLED#* * * * * ls\n'),
(L + '# foo\n'
'* * * * * ls\n'),
(L + '# foo {0}:blah\n'.format(
cron.SALT_CRON_IDENTIFIER) +
'* * * * * ls\n')])):
crons1 = cron.list_tab('root')
crons2 = cron.list_tab('root')
crons3 = cron.list_tab('root')
crons4 = cron.list_tab('root')
crons5 = cron.list_tab('root')
self.assertEqual(
crons1,
{'pre': [], 'crons': [], 'env': [], 'special': []})
self.assertEqual(
crons2['crons'][0],
{'comment': None,
'commented': False,
'dayweek': '*',
'hour': '*',
'identifier': None,
'cmd': 'ls',
'daymonth': '*',
'minute': '*',
'month': '*'})
self.assertEqual(
crons3['crons'][0],
{'comment': 'commented',
'commented': True,
'dayweek': '*',
'hour': '*',
'identifier': None,
'cmd': 'ls',
'daymonth': '*',
'minute': '*',
'month': '*'})
self.assertEqual(
crons4['crons'][0],
{'comment': 'foo',
'commented': False,
'dayweek': '*',
'hour': '*',
'identifier': None,
'cmd': 'ls',
'daymonth': '*',
'minute': '*',
'month': '*'})
self.assertEqual(
crons5['crons'][0],
{'comment': 'foo',
'commented': False,
'dayweek': '*',
'hour': '*',
'identifier': 'blah',
'cmd': 'ls',
'daymonth': '*',
'minute': '*',
'month': '*'})
def test_write_cron_file_root_rh(self):
'''
Assert that write_cron_file() is called with the correct cron command and user: RedHat
- If instance running uid matches crontab user uid, runas STUB_USER without -u flag.
'''
with patch.dict(cron.__grains__, {'os_family': 'RedHat'}), \
patch.dict(cron.__salt__, {'cmd.retcode': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
new=MagicMock(return_value=True)):
cron.write_cron_file(STUB_USER, STUB_PATH)
cron.__salt__['cmd.retcode'].assert_called_with("crontab /tmp",
runas=STUB_USER,
python_shell=False)
def test_write_cron_file_foo_rh(self):
'''
Assert that write_cron_file() is called with the correct cron command and user: RedHat
- If instance running with uid that doesn't match crontab user uid, run with -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'RedHat'}), \
patch.dict(cron.__salt__, {'cmd.retcode': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=False)):
cron.write_cron_file('foo', STUB_PATH)
cron.__salt__['cmd.retcode'].assert_called_with("crontab -u foo /tmp",
python_shell=False)
def test_write_cron_file_root_sol(self):
'''
Assert that write_cron_file() is called with the correct cron command and user: Solaris
- Solaris should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'RedHat'}), \
patch.dict(cron.__salt__, {'cmd.retcode': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=True)):
cron.write_cron_file(STUB_USER, STUB_PATH)
cron.__salt__['cmd.retcode'].assert_called_with("crontab /tmp",
runas=STUB_USER,
python_shell=False)
def test_write_cron_file_foo_sol(self):
'''
Assert that write_cron_file() is called with the correct cron command and user: Solaris
- Solaris should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'Solaris'}), \
patch.dict(cron.__salt__, {'cmd.retcode': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=False)):
cron.write_cron_file('foo', STUB_PATH)
cron.__salt__['cmd.retcode'].assert_called_with("crontab /tmp",
runas='foo',
python_shell=False)
def test_write_cron_file_root_aix(self):
'''
Assert that write_cron_file() is called with the correct cron command and user: AIX
- AIX should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'AIX'}), \
patch.dict(cron.__salt__, {'cmd.retcode': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=True)):
cron.write_cron_file(STUB_USER, STUB_PATH)
cron.__salt__['cmd.retcode'].assert_called_with("crontab /tmp",
runas=STUB_USER,
python_shell=False)
def test_write_cron_file_foo_aix(self):
'''
Assert that write_cron_file() is called with the correct cron command and user: AIX
- AIX should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'AIX'}), \
patch.dict(cron.__salt__, {'cmd.retcode': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=False)):
cron.write_cron_file('foo', STUB_PATH)
cron.__salt__['cmd.retcode'].assert_called_with("crontab /tmp",
runas='foo',
python_shell=False)
def test_write_cr_file_v_root_rh(self):
'''
Assert that write_cron_file_verbose() is called with the correct cron command and user: RedHat
- If instance running uid matches crontab user uid, runas STUB_USER without -u flag.
'''
with patch.dict(cron.__grains__, {'os_family': 'Redhat'}), \
patch.dict(cron.__salt__, {'cmd.run_all': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=True)):
cron.write_cron_file_verbose(STUB_USER, STUB_PATH)
cron.__salt__['cmd.run_all'].assert_called_with("crontab /tmp",
runas=STUB_USER,
python_shell=False)
def test_write_cr_file_v_foo_rh(self):
'''
Assert that write_cron_file_verbose() is called with the correct cron command and user: RedHat
- If instance running with uid that doesn't match crontab user uid, run with -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'Redhat'}), \
patch.dict(cron.__salt__, {'cmd.run_all': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=False)):
cron.write_cron_file_verbose('foo', STUB_PATH)
cron.__salt__['cmd.run_all'].assert_called_with("crontab -u foo /tmp",
python_shell=False)
def test_write_cr_file_v_root_sol(self):
'''
Assert that write_cron_file_verbose() is called with the correct cron command and user: Solaris
- Solaris should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'Solaris'}), \
patch.dict(cron.__salt__, {'cmd.run_all': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=True)):
cron.write_cron_file_verbose(STUB_USER, STUB_PATH)
cron.__salt__['cmd.run_all'].assert_called_with("crontab /tmp",
runas=STUB_USER,
python_shell=False)
def test_write_cr_file_v_foo_sol(self):
'''
Assert that write_cron_file_verbose() is called with the correct cron command and user: Solaris
- Solaris should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'Solaris'}), \
patch.dict(cron.__salt__, {'cmd.run_all': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=False)):
cron.write_cron_file_verbose('foo', STUB_PATH)
cron.__salt__['cmd.run_all'].assert_called_with("crontab /tmp",
runas='foo',
python_shell=False)
def test_write_cr_file_v_root_aix(self):
'''
Assert that write_cron_file_verbose() is called with the correct cron command and user: AIX
- AIX should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'AIX'}), \
patch.dict(cron.__salt__, {'cmd.run_all': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=True)):
cron.write_cron_file_verbose(STUB_USER, STUB_PATH)
cron.__salt__['cmd.run_all'].assert_called_with("crontab /tmp",
runas=STUB_USER,
python_shell=False)
def test_write_cr_file_v_foo_aix(self):
'''
Assert that write_cron_file_verbose() is called with the correct cron command and user: AIX
- AIX should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'AIX'}), \
patch.dict(cron.__salt__, {'cmd.run_all': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=False)):
cron.write_cron_file_verbose('foo', STUB_PATH)
cron.__salt__['cmd.run_all'].assert_called_with("crontab /tmp",
runas='foo',
python_shell=False)
def test_raw_cron_root_redhat(self):
'''
Assert that raw_cron() is called with the correct cron command and user: RedHat
- If instance running uid matches crontab user uid, runas STUB_USER without -u flag.
'''
with patch.dict(cron.__grains__, {'os_family': 'Redhat'}), \
patch.dict(cron.__salt__, {'cmd.run_stdout': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=True)):
cron.raw_cron(STUB_USER)
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
runas=STUB_USER,
ignore_retcode=True,
rstrip=False,
python_shell=False)
def test_raw_cron_foo_redhat(self):
'''
Assert that raw_cron() is called with the correct cron command and user: RedHat
- If instance running with uid that doesn't match crontab user uid, run with -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'Redhat'}), \
patch.dict(cron.__salt__, {'cmd.run_stdout': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=False)):
cron.raw_cron(STUB_USER)
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -u root -l",
ignore_retcode=True,
rstrip=False,
python_shell=False)
def test_raw_cron_root_solaris(self):
'''
Assert that raw_cron() is called with the correct cron command and user: Solaris
- Solaris should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'Solaris'}), \
patch.dict(cron.__salt__, {'cmd.run_stdout': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=True)):
cron.raw_cron(STUB_USER)
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
runas=STUB_USER,
ignore_retcode=True,
rstrip=False,
python_shell=False)
def test_raw_cron_foo_solaris(self):
'''
Assert that raw_cron() is called with the correct cron command and user: Solaris
- Solaris should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'Solaris'}), \
patch.dict(cron.__salt__, {'cmd.run_stdout': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=False)):
cron.raw_cron(STUB_USER)
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
runas=STUB_USER,
ignore_retcode=True,
rstrip=False,
python_shell=False)
def test_raw_cron_root_aix(self):
'''
Assert that raw_cron() is called with the correct cron command and user: AIX
- AIX should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'AIX'}), \
patch.dict(cron.__salt__, {'cmd.run_stdout': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=True)):
cron.raw_cron(STUB_USER)
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
runas=STUB_USER,
ignore_retcode=True,
rstrip=False,
python_shell=False)
def test_raw_cron_foo_aix(self):
'''
Assert that raw_cron() is called with the correct cron command and user: AIX
- AIX should always run without a -u flag
'''
with patch.dict(cron.__grains__, {'os_family': 'AIX'}), \
patch.dict(cron.__salt__, {'cmd.run_stdout': MagicMock()}), \
patch('salt.modules.cron._check_instance_uid_match',
MagicMock(return_value=False)):
cron.raw_cron(STUB_USER)
cron.__salt__['cmd.run_stdout'].assert_called_with("crontab -l",
runas=STUB_USER,
ignore_retcode=True,
rstrip=False,
python_shell=False)
@skipIf(NO_MOCK, NO_MOCK_REASON)
class PsTestCase(TestCase, LoaderModuleMockMixin):
def setup_loader_modules(self):
return {cron: {}}
def test__needs_change(self):
self.assertTrue(cron._needs_change(True, False))
def test__needs_change_random(self):
'''
Assert that if the new var is 'random' and old is '* that we return True
'''
self.assertTrue(cron._needs_change('*', 'random'))
## Still trying to figure this one out.
# def test__render_tab(self):
# pass
def test__get_cron_cmdstr(self):
self.assertEqual('crontab /tmp', cron._get_cron_cmdstr(STUB_PATH))
# Test get_cron_cmdstr() when user is added
def test__get_cron_cmdstr_user(self):
'''
Passes if a user is added to crontab command
'''
self.assertEqual('crontab -u root /tmp', cron._get_cron_cmdstr(STUB_PATH, STUB_USER))
def test__date_time_match(self):
'''
Passes if a match is found on all elements. Note the conversions to strings here!
:return:
'''
self.assertTrue(cron._date_time_match(STUB_CRON_TIMESTAMP,
minute=STUB_CRON_TIMESTAMP['minute'],
hour=STUB_CRON_TIMESTAMP['hour'],
daymonth=STUB_CRON_TIMESTAMP['daymonth'],
dayweek=STUB_CRON_TIMESTAMP['dayweek']
))
def test_list_tab(self):
with patch('salt.modules.cron.raw_cron', new=MagicMock(return_value=STUB_SIMPLE_RAW_CRON)):
self.assertDictEqual(STUB_SIMPLE_CRON_DICT, cron.list_tab('DUMMY_USER'))
def test_set_special(self):
with patch('salt.modules.cron._write_cron_lines') as write_cron_lines_mock, \
patch('salt.modules.cron.list_tab', new=MagicMock(return_value=STUB_SIMPLE_CRON_DICT)):
expected_write_call = call('DUMMY_USER',
['5 0 * * * /tmp/no_script.sh\n',
'# Lines below here are managed by Salt, do not edit\n',
'@hourly echo Hi!\n'])
ret = cron.set_special('DUMMY_USER', '@hourly', 'echo Hi!')
write_cron_lines_mock.assert_has_calls((expected_write_call,), any_order=True)
def test__get_cron_date_time(self):
ret = cron._get_cron_date_time(minute=STUB_CRON_TIMESTAMP['minute'],
hour=STUB_CRON_TIMESTAMP['hour'],
daymonth=STUB_CRON_TIMESTAMP['daymonth'],
dayweek=STUB_CRON_TIMESTAMP['dayweek'],
month=STUB_CRON_TIMESTAMP['month'])
self.assertDictEqual(ret, STUB_CRON_TIMESTAMP)
def test__get_cron_date_time_daymonth_max(self):
ret = cron._get_cron_date_time(minute='random',
hour='random',
daymonth='random',
dayweek='random',
month='random')
self.assertTrue(int(ret['minute']) in range(0, 60))
self.assertTrue(int(ret['hour']) in range(0, 24))
self.assertTrue(int(ret['daymonth']) in range(1, 32))
self.assertTrue(int(ret['dayweek']) in range(0, 8))
self.assertTrue(int(ret['month']) in range(1, 13))
def test_set_job(self):
with patch.dict(cron.__grains__, {'os': None}), \
patch('salt.modules.cron._write_cron_lines',
new=MagicMock(return_value={'retcode': False})), \
patch('salt.modules.cron.raw_cron',
new=MagicMock(return_value=STUB_SIMPLE_RAW_CRON)):
cron.set_job('DUMMY_USER', 1, 2, 3, 4, 5,
'/bin/echo NOT A DROID',
'WERE YOU LOOKING FOR ME?')
expected_call = call('DUMMY_USER',
['5 0 * * * /tmp/no_script.sh\n',
'# Lines below here are managed by Salt, do not edit\n',
'# WERE YOU LOOKING FOR ME?\n',
'1 2 3 4 5 /bin/echo NOT A DROID\n'])
cron._write_cron_lines.call_args.assert_called_with(expected_call)
def test_rm_special(self):
with patch.dict(cron.__grains__, {'os': None}), \
patch('salt.modules.cron._write_cron_lines',
new=MagicMock(return_value={'retcode': False})), \
patch('salt.modules.cron.raw_cron',
new=MagicMock(return_value=STUB_AT_SIGN)):
ret = cron.rm_special('root', 'echo "cron with @ sign"', special='@daily', identifier='echo "cron with @ sign"')
self.assertEqual('removed', ret)
def test_rm_special_default_special(self):
with patch.dict(cron.__grains__, {'os': None}), \
patch('salt.modules.cron._write_cron_lines',
new=MagicMock(return_value={'retcode': False})), \
patch('salt.modules.cron.raw_cron',
new=MagicMock(return_value=STUB_AT_SIGN)):
ret = cron.rm_special('root', 'echo "cron with @ sign"', identifier='echo "cron with @ sign"')
self.assertEqual('removed', ret)
def test_rm_special_absent(self):
with patch.dict(cron.__grains__, {'os': None}), \
patch('salt.modules.cron._write_cron_lines',
new=MagicMock(return_value={'retcode': False})), \
patch('salt.modules.cron.raw_cron',
new=MagicMock(return_value=STUB_AT_SIGN)):
ret = cron.rm_special('root', 'echo "there is no job"', identifier='echo "there is no job"')
self.assertEqual('absent', ret)
def test_rm_job_is_absent(self):
with patch.dict(cron.__grains__, {'os': None}), \
patch('salt.modules.cron._write_cron_lines',
new=MagicMock(return_value={'retcode': False})), \
patch('salt.modules.cron.raw_cron',
new=MagicMock(return_value=STUB_SIMPLE_RAW_CRON)):
ret = cron.rm_job('DUMMY_USER', '/bin/echo NOT A DROID', 1, 2, 3, 4, 5)
self.assertEqual('absent', ret)