Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 94 additions & 1 deletion scripts/hostcfgd
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import re
import jinja2
from sonic_py_common import device_info
from swsscommon.swsscommon import ConfigDBConnector, DBConnector, Table
from swsscommon import swsscommon

# FILE
PAM_AUTH_CONF = "/etc/pam.d/common-auth-sonic"
Expand Down Expand Up @@ -1253,6 +1254,79 @@ class PamLimitsCfg(object):
"modify pam_limits config file failed with exception: {}"
.format(e))

class LoginCfg(object):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need in python3:

Suggested change
class LoginCfg(object):
class LoginCfg:

"""
LoginCfg Config Daemon

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Daemon word confuses since it is not a deamon

Handles changes in LOGIN_MESSAGE table.
1) Handle change for pre-login and post-login messages.
Comment on lines +1260 to +1261

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Handles changes in LOGIN_MESSAGE table.
1) Handle change for pre-login and post-login messages.
Handles changes in LOGIN_MESSAGE table for pre-login and post-login messages.

"""
class cmds:
"""Run commands for actions"""
login_message_pre = '''sudo bash -c "echo -e{} '{}' > /etc/issue.net"'''
login_message_appl = "sudo sed -iE 's/\(#\|\)Banner.*$/Banner "\
"\/etc\/issue.net/' /etc/ssh/sshd_config"
login_message_rest_ssh = "sudo service ssh restart"
login_message_post = '''sudo bash -c "echo -e{} '{}' > /etc/motd"'''

def __init__(self):
self.cache = {}

def load(self, login_msgs={}):
# Get initial login messages
self.cache['pre-login'] = login_msgs.get('pre-login',{}
).get('message', '')
self.cache['post-login'] = login_msgs.get('post-login', {}
).get('message', '')
Comment on lines +1276 to +1279

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.cache['pre-login'] = login_msgs.get('pre-login',{}
).get('message', '')
self.cache['post-login'] = login_msgs.get('post-login', {}
).get('message', '')
self.cache['pre-login'] = login_msgs.get('pre-login', {}).get('message', '')
self.cache['post-login'] = login_msgs.get('post-login', {}).get('message', '')

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The total line width will exceed 80 chars. Which will break python code style

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are lines longer then 80 chars in this file. We don't follow that guideline and a newline in the middle hurts readability.

syslog.syslog(syslog.LOG_DEBUG, f'Initial login message: {self.cache}')

def set_login_message(self, key, data):
"""
Apply login message handler.

Args:
cache: Cache to compare/save data.
db: DB instance.
table: DB table that was changed.
key: DB table's key that was triggered change.
data: Read table data.
Comment on lines +1287 to +1291

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cache: Cache to compare/save data.
db: DB instance.
table: DB table that was changed.
key: DB table's key that was triggered change.
data: Read table data.
key: DB table's key that was triggered change.
data: Read table data.

"""
# Handling pre/post login messages. Data should be a dict
msg = None if not isinstance(data, dict) else data.get('message')
if type(msg) != str:
# Nothing to handle
return
Comment on lines +1294 to +1297

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
msg = None if not isinstance(data, dict) else data.get('message')
if type(msg) != str:
# Nothing to handle
return
msg = data.get('message')
if not msg:
# Nothing to handle
return


# Check with cache
if msg == self.cache.get(key):
# Nothing to handle
return

# Don't print newline when message is empty
not_newline = '' if msg else 'n'

try:
# Check which key was changed
if key == 'pre_login':
# Write pre-login to /etc/issue file
run_cmd(self.cmds.login_message_pre.format(not_newline, msg),
True, True)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add log_err and raise_exception as you do on next lines for readability

run_cmd(self.cmds.login_message_appl, log_err=True,
raise_exception=True)
run_cmd(self.cmds.login_message_rest_ssh, log_err=True,
raise_exception=True)
elif key == 'post_login':
# Write post-login to /etc/motd file
run_cmd(self.cmds.login_message_post.format(not_newline, msg),
True, True)
except Exception:
syslog.syslog(syslog.LOG_ERR, f'Failed to update {key} message')
return

# Update cache
syslog.syslog(f'Set new {key} message: {msg}')
self.cache[key] = msg


class HostConfigDaemon:
def __init__(self):
# Just a sanity check to verify if the CONFIG_DB has been initialized
Expand Down Expand Up @@ -1294,6 +1368,9 @@ class HostConfigDaemon:
self.pamLimitsCfg = PamLimitsCfg(self.config_db)
self.pamLimitsCfg.update_config_file()

# Initialize LoginCfg
self.loginmsgcfg = LoginCfg()

def load(self, init_data):
features = init_data['FEATURE']
aaa = init_data['AAA']
Expand All @@ -1306,13 +1383,15 @@ class HostConfigDaemon:
ntp_global = init_data['NTP']
kdump = init_data['KDUMP']
passwh = init_data['PASSW_HARDENING']
login_msgs = init_data.get(swsscommon.CFG_LOGIN_MESSAGE_TABLE_NAME, {})

self.feature_handler.sync_state_field(features)
self.aaacfg.load(aaa, tacacs_global, tacacs_server, radius_global, radius_server)
self.iptables.load(lpbk_table)
self.ntpcfg.load(ntp_global, ntp_server)
self.kdumpCfg.load(kdump)
self.passwcfg.load(passwh)
self.loginmsgcfg.load(login_msgs)

dev_meta = self.config_db.get_table('DEVICE_METADATA')
if 'localhost' in dev_meta:
Expand All @@ -1322,6 +1401,12 @@ class HostConfigDaemon:
# Update AAA with the hostname
self.aaacfg.hostname_update(self.hostname_cache)

# Update Login messages
login_msgs = self.config_db.get_table(
swsscommon.CFG_LOGIN_MESSAGE_TABLE_NAME)
for key in login_msgs:
self.loginmsgcfg.set_login_message(key, login_msgs[key])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

load will save configuration into the cache, so this call to set_login_message will not set anything because it is the same as in the cache?


def __get_intf_name(self, key):
if isinstance(key, tuple) and key:
intf = key[0]
Expand Down Expand Up @@ -1409,6 +1494,10 @@ class HostConfigDaemon:
syslog.syslog(syslog.LOG_INFO, 'Kdump handler...')
self.kdumpCfg.kdump_update(key, data)

def login_handler(self, key, op, data):
syslog.syslog(syslog.LOG_INFO, 'LOGIN_MESSAGE table handler...')
self.loginmsgcfg.set_login_message(key, data)

def wait_till_system_init_done(self):
# No need to print the output in the log file so using the "--quiet"
# flag
Expand Down Expand Up @@ -1447,7 +1536,11 @@ class HostConfigDaemon:
self.config_db.subscribe('VLAN_SUB_INTERFACE', make_callback(self.vlan_sub_intf_handler))
self.config_db.subscribe('PORTCHANNEL_INTERFACE', make_callback(self.portchannel_intf_handler))
self.config_db.subscribe('INTERFACE', make_callback(self.phy_intf_handler))


# Handle LOGIN_MESSAGE changes
self.config_db.subscribe(swsscommon.CFG_LOGIN_MESSAGE_TABLE_NAME,
make_callback(self.login_handler))

syslog.syslog(syslog.LOG_INFO,
"Waiting for systemctl to finish initialization")
self.wait_till_system_init_done()
Expand Down