[202012] Check config file not empty after modify it in hostcfgd. (#14385)
**What I did** Check /etc/pam.d/sshd integrity after modify it in hostcfgd. **Why I did it** Found some incident that /etc/pam.d/sshd become empty file during OR upgrade. **How I verified it** Pass all UT. Add new UT to cover new code. **Details if related** This is a manually cherry-pick PR for https://github.com/sonic-net/sonic-host-services/pull/36
This commit is contained in:
parent
43aec133da
commit
a20b43e502
@ -210,11 +210,26 @@ class AaaCfg(object):
|
|||||||
if modify_conf:
|
if modify_conf:
|
||||||
self.modify_conf_file()
|
self.modify_conf_file()
|
||||||
|
|
||||||
|
def check_file_not_empty(self, filename):
|
||||||
|
exists = os.path.exists(filename)
|
||||||
|
if not exists:
|
||||||
|
syslog.syslog(syslog.LOG_ERR, "file size check failed: {} is missing".format(filename))
|
||||||
|
return
|
||||||
|
|
||||||
|
size = os.path.getsize(filename)
|
||||||
|
if size == 0:
|
||||||
|
syslog.syslog(syslog.LOG_ERR, "file size check failed: {} is empty, file corrupted".format(filename))
|
||||||
|
return
|
||||||
|
|
||||||
|
syslog.syslog(syslog.LOG_INFO, "file size check pass: {} size is ({}) bytes".format(filename, size))
|
||||||
|
|
||||||
def modify_single_file(self, filename, operations=None):
|
def modify_single_file(self, filename, operations=None):
|
||||||
if operations:
|
if operations:
|
||||||
cmd = "sed -e {0} {1} > {1}.new; mv -f {1} {1}.old; mv -f {1}.new {1}".format(' -e '.join(operations), filename)
|
cmd = "sed -e {0} {1} > {1}.new; mv -f {1} {1}.old; mv -f {1}.new {1}".format(' -e '.join(operations), filename)
|
||||||
os.system(cmd)
|
os.system(cmd)
|
||||||
|
|
||||||
|
self.check_file_not_empty(filename)
|
||||||
|
|
||||||
def modify_conf_file(self):
|
def modify_conf_file(self):
|
||||||
auth = self.auth_default.copy()
|
auth = self.auth_default.copy()
|
||||||
auth.update(self.auth)
|
auth.update(self.auth)
|
||||||
|
@ -225,4 +225,69 @@ class TestHostcfgdDaemon(TestCase):
|
|||||||
expected = [call('sonic-kdump-config --disable', shell=True),
|
expected = [call('sonic-kdump-config --disable', shell=True),
|
||||||
call('sonic-kdump-config --num_dumps 3', shell=True),
|
call('sonic-kdump-config --num_dumps 3', shell=True),
|
||||||
call('sonic-kdump-config --memory 0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M', shell=True)]
|
call('sonic-kdump-config --memory 0M-2G:256M,2G-4G:320M,4G-8G:384M,8G-:448M', shell=True)]
|
||||||
mocked_subprocess.check_call.assert_has_calls(expected, any_order=True)
|
mocked_subprocess.check_call.assert_has_calls(expected, any_order=True)
|
||||||
|
|
||||||
|
class TesAaaCfgd(TestCase):
|
||||||
|
"""
|
||||||
|
Test hostcfd daemon - AaaCfgd
|
||||||
|
"""
|
||||||
|
def setUp(self):
|
||||||
|
MockConfigDb.CONFIG_DB['NTP'] = {'global': {'vrf': 'mgmt', 'src_intf': 'eth0'}}
|
||||||
|
MockConfigDb.CONFIG_DB['NTP_SERVER'] = {'0.debian.pool.ntp.org': {}}
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
MockConfigDb.CONFIG_DB = {}
|
||||||
|
|
||||||
|
def test_aaa_sshd_not_empty(self):
|
||||||
|
with mock.patch('hostcfgd.subprocess') as mocked_subprocess:
|
||||||
|
popen_mock = mock.Mock()
|
||||||
|
attrs = {'communicate.return_value': ('output', 'error')}
|
||||||
|
popen_mock.configure_mock(**attrs)
|
||||||
|
mocked_subprocess.Popen.return_value = popen_mock
|
||||||
|
|
||||||
|
test_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
sample_output_path = os.path.join(test_path, "hostcfgd/sample_output/")
|
||||||
|
|
||||||
|
aaacfgd = hostcfgd.AaaCfg()
|
||||||
|
aaacfgd.modify_single_file(os.path.join(sample_output_path, "sshd_not_empty"))
|
||||||
|
|
||||||
|
# render with empty sshd config file and check error log
|
||||||
|
test_file = os.path.join(sample_output_path, "sshd_empty")
|
||||||
|
original_syslog = hostcfgd.syslog
|
||||||
|
with mock.patch('hostcfgd.syslog.syslog') as mocked_syslog:
|
||||||
|
mocked_syslog.LOG_ERR = original_syslog.LOG_ERR
|
||||||
|
aaacfgd.modify_single_file(test_file)
|
||||||
|
|
||||||
|
# check sys log
|
||||||
|
expected = [
|
||||||
|
mock.call(mocked_syslog.LOG_ERR, "file size check failed: {} is empty, file corrupted".format(test_file))
|
||||||
|
]
|
||||||
|
mocked_syslog.assert_has_calls(expected)
|
||||||
|
|
||||||
|
# check with missing sshd config file and check error log
|
||||||
|
test_file = os.path.join(sample_output_path, "sshd_missing")
|
||||||
|
with mock.patch('hostcfgd.syslog.syslog') as mocked_syslog:
|
||||||
|
mocked_syslog.LOG_ERR = original_syslog.LOG_ERR
|
||||||
|
|
||||||
|
# missing file can't test by render config file,
|
||||||
|
# because missing file case difficult to reproduce: code always generate a empty file.
|
||||||
|
aaacfgd.check_file_not_empty(test_file)
|
||||||
|
|
||||||
|
# check sys log
|
||||||
|
expected = [
|
||||||
|
mock.call(mocked_syslog.LOG_ERR, "file size check failed: {} is missing".format(test_file))
|
||||||
|
]
|
||||||
|
mocked_syslog.assert_has_calls(expected)
|
||||||
|
|
||||||
|
# render with empty sshd config file and check error log
|
||||||
|
test_file = os.path.join(sample_output_path, "sshd_not_empty")
|
||||||
|
original_syslog = hostcfgd.syslog
|
||||||
|
with mock.patch('hostcfgd.syslog.syslog') as mocked_syslog:
|
||||||
|
mocked_syslog.LOG_INFO = original_syslog.LOG_INFO
|
||||||
|
aaacfgd.modify_single_file(test_file)
|
||||||
|
|
||||||
|
# check sys log
|
||||||
|
expected = [
|
||||||
|
mock.call(mocked_syslog.LOG_INFO, "file size check pass: {} size is ({}) bytes".format(test_file, 21))
|
||||||
|
]
|
||||||
|
mocked_syslog.assert_has_calls(expected)
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
#SSHD NOT EMPTY TEST
|
Loading…
Reference in New Issue
Block a user