Page MenuHomeVyOS Platform

host_name.py
No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None

host_name.py

#!/usr/bin/env python3
#
# Copyright (C) 2018 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
"""
conf-mode script for 'system host-name' and 'system domain-name'.
"""
import os
import re
import sys
import subprocess
import copy
import jinja2
import glob
from vyos.config import Config
from vyos import ConfigError
config_file_hosts = '/etc/hosts'
config_file_resolv = '/etc/resolv.conf'
config_tmpl_hosts = """
### Autogenerated by host_name.py ###
127.0.0.1 localhost {{ hostname }}{% if domain_name %}.{{ domain_name }}{% endif %}
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
### modifications from other scripts should be added below
"""
config_tmpl_resolv = """
### Autogenerated by host_name.py ###
{% for ns in nameserver -%}
nameserver {{ ns }}
{% endfor -%}
{%- if domain_name %}
domain {{ domain_name }}
{%- endif %}
{%- if domain_search %}
search {{ domain_search | join(" ") }}
{%- endif %}
"""
# borrowed from: https://github.com/donjajo/py-world/blob/master/resolvconfReader.py, THX!
def get_resolvers(file):
resolvers = []
try:
with open(file, 'r') as resolvconf:
for line in resolvconf.readlines():
line = line.split('#',1)[0];
line = line.rstrip();
if 'nameserver' in line:
resolvers.append(line.split()[1])
return resolvers
except IOError:
return []
default_config_data = {
'hostname': 'vyos',
'domain_name': '',
'domain_search': [],
'nameserver': [],
'no_dhcp_ns': False
}
def get_config():
conf = Config()
hosts = copy.deepcopy(default_config_data)
hosts['hostname'] = conf.return_value("system host-name")
hosts['domain_name'] = conf.return_value("system domain-name")
if hosts['domain_name']:
hosts['domain_search'].append(hosts['domain_name'])
for search in conf.return_values("system domain-search domain"):
hosts['domain_search'].append(search)
hosts['nameserver'] = conf.return_values("system name-server")
hosts['no_dhcp_ns'] = conf.exists('system disable-dhcp-nameservers')
return hosts
def verify(config):
if config is None:
return None
# pattern $VAR(@) "^[[:alnum:]][-.[:alnum:]]*[[:alnum:]]$" ; "invalid host name $VAR(@)"
hostname_regex = re.compile("^[A-Za-z0-9][-.A-Za-z0-9]*[A-Za-z0-9]$")
if not hostname_regex.match(config['hostname']):
raise ConfigError('Invalid host name ' + config["hostname"])
# pattern $VAR(@) "^.{1,63}$" ; "invalid host-name length"
length = len(config['hostname'])
if length < 1 or length > 63:
raise ConfigError(
'Invalid host-name length, must be less than 63 characters')
# The search list is currently limited to six domains with a total of 256 characters.
# https://linux.die.net/man/5/resolv.conf
if len(config['domain_search']) > 6:
raise ConfigError('The search list is currently limited to six domains')
tmp = ' '.join(config['domain_search'])
if len(tmp) > 256:
raise ConfigError('The search list is currently limited to 256 characters')
return None
def generate(config):
if config is None:
return None
# If "system disable-dhcp-nameservers" is __configured__ all DNS resolvers
# received via dhclient should not be added into the final 'resolv.conf'.
#
# We iterate over every resolver file and retrieve the received nameservers
# for later adjustment of the system nameservers
dhcp_ns = []
for file in glob.glob('/etc/resolv.conf.dhclient-new*'):
for r in get_resolvers(file):
dhcp_ns.append(r)
if not config['no_dhcp_ns']:
config['nameserver'] += dhcp_ns
# We have third party scripts altering /etc/hosts, too.
# One example are the DHCP hostname update scripts thus we need to cache in
# every modification first - so changing domain-name, domain-search or hostname
# during runtime works
old_hosts = ""
with open(config_file_hosts, 'r') as f:
# Skips text before the beginning of our marker.
# NOTE: Marker __MUST__ match the one specified in config_tmpl_hosts
for line in f:
if line.strip() == '### modifications from other scripts should be added below':
break
for line in f:
# This additional line.strip() filters empty lines
if line.strip():
old_hosts += line
# Add an additional newline
old_hosts += '\n'
tmpl = jinja2.Template(config_tmpl_hosts)
config_text = tmpl.render(config)
with open(config_file_hosts, 'w') as f:
f.write(config_text)
f.write(old_hosts)
tmpl = jinja2.Template(config_tmpl_resolv)
config_text = tmpl.render(config)
with open(config_file_resolv, 'w') as f:
f.write(config_text)
return None
def apply(config):
if config is None:
return None
fqdn = config['hostname']
if config['domain_name']:
fqdn += '.' + config['domain_name']
os.system("hostnamectl set-hostname --static {0}".format(fqdn))
# Restart services that use the hostname
os.system("systemctl restart rsyslog.service")
# If SNMP is running, restart it too
if os.system("pgrep snmpd > /dev/null") == 0:
os.system("systemctl restart snmpd.service")
return None
if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
sys.exit(1)

File Metadata

Mime Type
text/x-script.python
Expires
Sat, Oct 17, 12:49 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4347351
Default Alt Text
host_name.py (6 KB)

Event Timeline