[build_templates] [hostcfgd] Keep containers hostname up to date (#2924)
* Add updateHostName function to docker_image_ctl.j2 * Add hostname specification on container creating step * Add listener for hostname changes in hostcfgd Signed-off-by: Myron Sosyak <msosyak@barefootnetworks.com>
This commit is contained in:
parent
4f85c7cd5f
commit
3ec95e17c8
@ -5,6 +5,32 @@ function getMountPoint()
|
|||||||
echo $1 | python -c "import sys, json, os; mnts = [x for x in json.load(sys.stdin)[0]['Mounts'] if x['Destination'] == '/usr/share/sonic/hwsku']; print '' if len(mnts) == 0 else os.path.basename(mnts[0]['Source'])" 2>/dev/null
|
echo $1 | python -c "import sys, json, os; mnts = [x for x in json.load(sys.stdin)[0]['Mounts'] if x['Destination'] == '/usr/share/sonic/hwsku']; print '' if len(mnts) == 0 else os.path.basename(mnts[0]['Source'])" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateHostName()
|
||||||
|
{
|
||||||
|
HOSTS=/etc/hosts
|
||||||
|
HOSTS_TMP=/etc/hosts.tmp
|
||||||
|
|
||||||
|
EXEC="docker exec -i {{docker_container_name}} bash -c"
|
||||||
|
|
||||||
|
NEW_HOSTNAME="$1"
|
||||||
|
HOSTNAME=`$EXEC "hostname"`
|
||||||
|
if ! [[ $HOSTNAME =~ ^[a-zA-Z0-9.\-]*$ ]]; then
|
||||||
|
HOSTNAME=`hostname`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# copy HOSTS to HOSTS_TMP
|
||||||
|
$EXEC "cp $HOSTS $HOSTS_TMP"
|
||||||
|
# remove entry with hostname
|
||||||
|
$EXEC "sed -i \"/$HOSTNAME$/d\" $HOSTS_TMP"
|
||||||
|
# add entry with new hostname
|
||||||
|
$EXEC "echo -e \"127.0.0.1\t$NEW_HOSTNAME\" >> $HOSTS_TMP"
|
||||||
|
|
||||||
|
echo "Set hostname in {{docker_container_name}} container"
|
||||||
|
$EXEC "hostname '$NEW_HOSTNAME'"
|
||||||
|
$EXEC "cat $HOSTS_TMP > $HOSTS"
|
||||||
|
$EXEC "rm -f $HOSTS_TMP"
|
||||||
|
}
|
||||||
|
|
||||||
function getBootType()
|
function getBootType()
|
||||||
{
|
{
|
||||||
local BOOT_TYPE
|
local BOOT_TYPE
|
||||||
@ -105,6 +131,10 @@ start() {
|
|||||||
# Obtain our HWSKU as we will mount directories with these names in each docker
|
# Obtain our HWSKU as we will mount directories with these names in each docker
|
||||||
HWSKU=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["hwsku"]'`
|
HWSKU=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["hwsku"]'`
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
HOSTNAME=`sonic-cfggen -m -v 'DEVICE_METADATA["localhost"]["hostname"]'`
|
||||||
|
if [ -z "$HOSTNAME" ] || ! [[ $HOSTNAME =~ ^[a-zA-Z0-9.\-]*$ ]]; then
|
||||||
|
HOSTNAME=`hostname`
|
||||||
|
fi
|
||||||
|
|
||||||
DOCKERCHECK=`docker inspect --type container {{docker_container_name}} 2>/dev/null`
|
DOCKERCHECK=`docker inspect --type container {{docker_container_name}} 2>/dev/null`
|
||||||
if [ "$?" -eq "0" ]; then
|
if [ "$?" -eq "0" ]; then
|
||||||
@ -121,6 +151,7 @@ start() {
|
|||||||
{%- endif %}
|
{%- endif %}
|
||||||
preStartAction
|
preStartAction
|
||||||
docker start {{docker_container_name}}
|
docker start {{docker_container_name}}
|
||||||
|
updateHostName "$HOSTNAME"
|
||||||
postStartAction
|
postStartAction
|
||||||
exit $?
|
exit $?
|
||||||
fi
|
fi
|
||||||
@ -167,6 +198,7 @@ start() {
|
|||||||
--tmpfs /tmp \
|
--tmpfs /tmp \
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
--tmpfs /var/tmp \
|
--tmpfs /var/tmp \
|
||||||
|
--hostname "$HOSTNAME" \
|
||||||
--name={{docker_container_name}} {{docker_image_name}}:latest || {
|
--name={{docker_container_name}} {{docker_image_name}}:latest || {
|
||||||
echo "Failed to docker run" >&1
|
echo "Failed to docker run" >&1
|
||||||
exit 4
|
exit 4
|
||||||
@ -186,11 +218,13 @@ stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
start|wait|stop)
|
start|wait|stop|updateHostName)
|
||||||
$1
|
cmd=$1
|
||||||
|
shift
|
||||||
|
$cmd $@
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {start|wait|stop}"
|
echo "Usage: $0 {start|wait|stop|updateHostName new_hostname}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
import syslog
|
import syslog
|
||||||
@ -22,6 +23,15 @@ TACPLUS_SERVER_TIMEOUT_DEFAULT = "5"
|
|||||||
TACPLUS_SERVER_AUTH_TYPE_DEFAULT = "pap"
|
TACPLUS_SERVER_AUTH_TYPE_DEFAULT = "pap"
|
||||||
|
|
||||||
|
|
||||||
|
def is_valid_hostname(name):
|
||||||
|
if hostname[-1] == ".":
|
||||||
|
hostname = hostname[:-1] # strip exactly one dot from the right, if present
|
||||||
|
if len(hostname) > 253:
|
||||||
|
return False
|
||||||
|
allowed = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
|
||||||
|
return all(allowed.match(x) for x in hostname.split("."))
|
||||||
|
|
||||||
|
|
||||||
def is_true(val):
|
def is_true(val):
|
||||||
if val == 'True' or val == 'true':
|
if val == 'True' or val == 'true':
|
||||||
return True
|
return True
|
||||||
@ -148,6 +158,7 @@ class HostConfigDaemon:
|
|||||||
tacacs_server = self.config_db.get_table('TACPLUS_SERVER')
|
tacacs_server = self.config_db.get_table('TACPLUS_SERVER')
|
||||||
self.aaacfg = AaaCfg()
|
self.aaacfg = AaaCfg()
|
||||||
self.aaacfg.load(aaa, tacacs_global, tacacs_server)
|
self.aaacfg.load(aaa, tacacs_global, tacacs_server)
|
||||||
|
self.hostname_cache=""
|
||||||
|
|
||||||
def aaa_handler(self, key, data):
|
def aaa_handler(self, key, data):
|
||||||
self.aaacfg.aaa_update(key, data)
|
self.aaacfg.aaa_update(key, data)
|
||||||
@ -166,10 +177,49 @@ class HostConfigDaemon:
|
|||||||
log_data['passkey'] = obfuscate(log_data['passkey'])
|
log_data['passkey'] = obfuscate(log_data['passkey'])
|
||||||
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, log_data))
|
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, log_data))
|
||||||
|
|
||||||
|
def hostname_handler(self, key, data):
|
||||||
|
if key != "localhost":
|
||||||
|
return
|
||||||
|
|
||||||
|
hostname = data.get("hostname")
|
||||||
|
|
||||||
|
if not hostname:
|
||||||
|
syslog.syslog(syslog.LOG_WARNING, "hostname key is missing")
|
||||||
|
return
|
||||||
|
if not is_valid_hostname(hostname):
|
||||||
|
return
|
||||||
|
if hostname == self.hostname_cache:
|
||||||
|
return
|
||||||
|
|
||||||
|
syslog.syslog(syslog.LOG_INFO, "Get all running containers")
|
||||||
|
cmd = 'docker ps --format "{{.Names}}"'
|
||||||
|
try:
|
||||||
|
containers = subprocess.check_output(cmd, shell=True).split("\n")[:-1]
|
||||||
|
except subprocess.CalledProcessError as err:
|
||||||
|
syslog.syslog(syslog.LOG_ERR, "{} - failed: return code - {}, output:\n{}"
|
||||||
|
.format(err.cmd, err.returncode, err.output))
|
||||||
|
|
||||||
|
for name in containers:
|
||||||
|
script = '/usr/bin/{}.sh'.format(name)
|
||||||
|
exists = os.path.isfile(script)
|
||||||
|
if not exists:
|
||||||
|
syslog.syslog(syslog.LOG_ERR, "Can't find control script for {}".format(name))
|
||||||
|
continue
|
||||||
|
|
||||||
|
cmd = "{} updateHostName {}".format(script, hostname)
|
||||||
|
try:
|
||||||
|
subprocess.check_call(cmd, shell=True)
|
||||||
|
except subprocess.CalledProcessError as err:
|
||||||
|
syslog.syslog(syslog.LOG_ERR, "{} - failed: return code - {}, output:\n{}"
|
||||||
|
.format(err.cmd, err.returncode, err.output))
|
||||||
|
|
||||||
|
self.hostname_cache = hostname
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.config_db.subscribe('AAA', lambda table, key, data: self.aaa_handler(key, data))
|
self.config_db.subscribe('AAA', lambda table, key, data: self.aaa_handler(key, data))
|
||||||
self.config_db.subscribe('TACPLUS_SERVER', lambda table, key, data: self.tacacs_server_handler(key, data))
|
self.config_db.subscribe('TACPLUS_SERVER', lambda table, key, data: self.tacacs_server_handler(key, data))
|
||||||
self.config_db.subscribe('TACPLUS', lambda table, key, data: self.tacacs_global_handler(key, data))
|
self.config_db.subscribe('TACPLUS', lambda table, key, data: self.tacacs_global_handler(key, data))
|
||||||
|
self.config_db.subscribe('DEVICE_METADATA', lambda table, key, data: self.hostname_handler(key, data))
|
||||||
self.config_db.listen()
|
self.config_db.listen()
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user