summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog6
-rw-r--r--interface-definitions/dns-domain-name.xml47
-rwxr-xr-xsrc/conf_mode/host_name.py249
3 files changed, 193 insertions, 109 deletions
diff --git a/debian/changelog b/debian/changelog
index 77b0aae2a..29dfa5512 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+vyos-1x (1.3.0-2) unstable; urgency=low
+
+ fixes T1257 - implement 'set system static-host-mapping' in host_name.py and remove old function calls
+
+ -- hagbard <vyosdev@derith.de> Thu, 21 Feb 2019 15:53:30 -0800
+
vyos-1x (1.3.0-1) unstable; urgency=medium
* Changing version for the new branch.
diff --git a/interface-definitions/dns-domain-name.xml b/interface-definitions/dns-domain-name.xml
index 7b8497c09..a2c66495f 100644
--- a/interface-definitions/dns-domain-name.xml
+++ b/interface-definitions/dns-domain-name.xml
@@ -63,6 +63,53 @@
<valueless/>
</properties>
</leafNode>
+ <node name="static-host-mapping" owner="${vyos_conf_scripts_dir}/host_name.py">
+ <properties>
+ <help>Map host names to addresses</help>
+ <priority>400</priority>
+ </properties>
+ <children>
+
+ <tagNode name="host-name">
+ <properties>
+ <help>Host name for static address mapping</help>
+ <constraint>
+ <regex>^[A-Za-z0-9][-.A-Za-z0-9]*[A-Za-z0-9]$</regex>
+ </constraint>
+ <constraintErrorMessage>invalid hostname</constraintErrorMessage>
+ </properties>
+ <children>
+ <leafNode name="alias">
+ <properties>
+ <help>Alias for this address</help>
+ <constraint>
+ <regex>^.{1,63}$</regex>
+ </constraint>
+ <constraintErrorMessage>invalid alias hostname, needs to be between 1 and 63 charactes</constraintErrorMessage>
+ <multi />
+ </properties>
+ </leafNode>
+ <leafNode name="inet">
+ <properties>
+ <help>IP Address [REQUIRED]</help>
+ <valueHelp>
+ <format>ipv4</format>
+ <description>IPv4 address</description>
+ </valueHelp>
+ <valueHelp>
+ <format>ipv6</format>
+ <description>IPv6 address</description>
+ </valueHelp>
+ <constraint>
+ <validator name="ip-address"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </tagNode>
+
+ </children>
+ </node>
</children>
</node>
</interfaceDefinition>
diff --git a/src/conf_mode/host_name.py b/src/conf_mode/host_name.py
index 3ffc7829f..bdb99a7a4 100755
--- a/src/conf_mode/host_name.py
+++ b/src/conf_mode/host_name.py
@@ -45,8 +45,14 @@ ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
-### modifications from other scripts should be added below
+# static hostname mappings
+{%- if static_host_mapping['hostnames'] %}
+{% for hn in static_host_mapping['hostnames'] -%}
+{{static_host_mapping['hostnames'][hn]['ipaddr']}}\t{{static_host_mapping['hostnames'][hn]['alias']}}\t{{hn}}
+{% endfor -%}
+{%- endif %}
+### modifications from other scripts should be added below
"""
@@ -68,17 +74,17 @@ search {{ domain_search | join(" ") }}
# 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 []
+ 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',
@@ -89,124 +95,149 @@ default_config_data = {
}
def get_config():
- conf = Config()
- hosts = copy.deepcopy(default_config_data)
+ 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")
+ 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'])
+ 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)
+ 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')
+ hosts['nameserver'] = conf.return_values("system name-server")
+ hosts['no_dhcp_ns'] = conf.exists('system disable-dhcp-nameservers')
- return hosts
+ ## system static-host-mapping
+ hosts['static_host_mapping'] = { 'hostnames' : {}}
+
+ if conf.exists('system static-host-mapping host-name'):
+ for hn in conf.list_nodes('system static-host-mapping host-name'):
+ hosts['static_host_mapping']['hostnames'][hn] = {
+ 'ipaddr' : conf.return_value('system static-host-mapping host-name ' + hn + ' inet'),
+ 'alias' : ''
+ }
+
+ if conf.exists('system static-host-mapping host-name ' + hn + ' alias'):
+ a = conf.return_values('system static-host-mapping host-name ' + hn + ' alias')
+ hosts['static_host_mapping']['hostnames'][hn]['alias'] = " ".join( conf.return_values('system static-host-mapping host-name ' + hn + ' alias') )
+
+ return hosts
def verify(config):
- if config is None:
- return None
+ 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(@) "^[[: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')
+ # 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')
+ # 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')
+ tmp = ' '.join(config['domain_search'])
+ if len(tmp) > 256:
+ raise ConfigError('The search list is currently limited to 256 characters')
- return None
+ # static mappings alias hostname
+ if config['static_host_mapping']['hostnames']:
+ for hn in config['static_host_mapping']['hostnames']:
+ for hn_alias in config['static_host_mapping']['hostnames'][hn]['alias'].split(' '):
+ if not hostname_regex.match(hn_alias):
+ raise ConfigError('Invalid hostname alias ' + hn_alias)
-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 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
+ if config is None:
+ return None
- fqdn = config['hostname']
- if config['domain_name']:
- fqdn += '.' + config['domain_name']
+ fqdn = config['hostname']
+ if config['domain_name']:
+ fqdn += '.' + config['domain_name']
- os.system("hostnamectl set-hostname --static {0}".format(fqdn))
+ os.system("hostnamectl set-hostname --static {0}".format(fqdn))
- # Restart services that use the hostname
- os.system("systemctl restart rsyslog.service")
+ # 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")
+ # If SNMP is running, restart it too
+ if os.system("pgrep snmpd > /dev/null") == 0:
+ os.system("systemctl restart snmpd.service")
+
+ # restart pdns if it is used
+ if os.system("/usr/bin/rec_control ping >/dev/null") == 0:
+ os.system("/etc/init.d/pdns-recursor restart >/dev/null")
- return None
+ return None
if __name__ == '__main__':
- try:
- c = get_config()
- verify(c)
- generate(c)
- apply(c)
- except ConfigError as e:
- print(e)
- sys.exit(1)
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ sys.exit(1)