[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:
Hua Liu 2023-03-27 00:30:05 -07:00 committed by GitHub
parent 43aec133da
commit a20b43e502
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 82 additions and 1 deletions

View File

@ -210,11 +210,26 @@ class AaaCfg(object):
if modify_conf:
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):
if operations:
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)
self.check_file_not_empty(filename)
def modify_conf_file(self):
auth = self.auth_default.copy()
auth.update(self.auth)

View File

@ -225,4 +225,69 @@ class TestHostcfgdDaemon(TestCase):
expected = [call('sonic-kdump-config --disable', 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)]
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)

View File

@ -0,0 +1 @@
#SSHD NOT EMPTY TEST