diff options
-rw-r--r-- | interface-definitions/host-name.xml | 24 | ||||
-rw-r--r-- | schema/interface_definition.rnc | 154 | ||||
-rw-r--r-- | schema/interface_definition.rng | 7 | ||||
-rwxr-xr-x[-rw-r--r--] | src/conf-mode/vyos-config-host-name.py | 74 |
4 files changed, 214 insertions, 45 deletions
diff --git a/interface-definitions/host-name.xml b/interface-definitions/host-name.xml index 1452a956a..4ab244f6a 100644 --- a/interface-definitions/host-name.xml +++ b/interface-definitions/host-name.xml @@ -5,18 +5,22 @@ <interfaceDefinition> <node name="system"> <children> - <node name="host-name" owner="${vyos_sbindir}/vyos-config-host-name.py"> + <leafNode name="host-name" owner="${vyos_sbindir}/vyos-config-host-name.py"> <properties> <help>System host name (default: vyos)</help> + <constraint> + <regex>[A-Za-z0-9][-.A-Za-z0-9]*[A-Za-z0-9]</regex> + </constraint> </properties> - <children> - <leafNode name="hostname"> - <properties> - <help>System host name (default: vyos)</help> - </properties> - </leafNode> - </children> - </node> + </leafNode> + <leafNode name="domain-name" owner="${vyos_sbindir}/vyos-config-host-name.py"> + <properties> + <help>System domain name</help> + <constraint> + <regex>[A-Za-z0-9][-.A-Za-z0-9]*</regex> + </constraint> + </properties> + </leafNode> </children> </node> -</interfaceDefinition>
\ No newline at end of file +</interfaceDefinition> diff --git a/schema/interface_definition.rnc b/schema/interface_definition.rnc new file mode 100644 index 000000000..02175fec8 --- /dev/null +++ b/schema/interface_definition.rnc @@ -0,0 +1,154 @@ +# interface_definition.rnc: VyConf reference tree XML grammar +# +# Copyright (C) 2014. 2017 VyOS maintainers and contributors <maintainers@vyos.net> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 +# USA + +# The language of this file is compact form RELAX-NG +# http://relaxng.org/compact-tutorial-20030326.htm +# (unless converted to XML, then just RELAX-NG :) + +# Interface definition starts with interfaceDefinition tag that may contain node tags +start = element interfaceDefinition +{ + node* +} + +# node tag may contain node, leafNode, or tagNode tags +# Those are intermediate configuration nodes that may only contain +# other nodes and must not have values +node = element node +{ + (ownerAttr? & nodeNameAttr), + (properties? & children? ) +} + +# Tag nodes are containers for nodes without predefined names, like network interfaces +# or user names (e.g. "interfaces ethernet eth0" or "user jrandomhacker") +# Tag nodes may contain node and leafNode elements, and also nameConstraint tags +# They must not contain other tag nodes +tagNode = element tagNode +{ + (ownerAttr? & nodeNameAttr), + (properties? & children ) +} + +# Leaf nodes are terminal configuration nodes that can't have children, +# but can have values. +# Leaf node may contain one or more valueConstraint tags +# If multiple valueConstraint tags are used, they work a logical OR +# Leaf nodes can have "multi" attribute that indicated that it can have +# more than one value +leafNode = element leafNode +{ + (ownerAttr? & nodeNameAttr), + properties +} + +# Normal and tag nodes may have children +children = element children +{ + (node | tagNode | leafNode)+ +} + +# Nodes may have properties +# For simplicity, any property is allowed in any node, +# but whether they are used or not is implementation-defined +# +# Leaf nodes may differ in number of values that can be +# associated with them. +# By default, a leaf node can have only one value. +# "multi" tag means a node can have one or more values, +# "valueless" means it can have no values at all. +# "hidden" means node visibility can be toggled, eg 'dangerous' commands, +# "secret" allows a node to hide its value from unprivileged users. +# +# "priority" is used to influence node processing order for nodes +# with exact same dependencies and in compatibility modes. +properties = element properties +{ + help? & + constraint? & + valueHelp* & + (element constraintErrorMessage { text })? & + completionHelp* & + + # These are meaningful only for leaf nodes + (element valueless { empty })? & + (element multi { empty })? & + (element hidden { empty })? & + (element secret { empty })? & + (element priority { text })? & + + # These are meaningful only for tag nodes + (element keepChildOrder { empty })? +} + +# All nodes must have "name" attribute +nodeNameAttr = attribute name +{ + text +} + +# Ordinary nodes and tag nodes can have "owner" attribute. +# Owner is the component that is notified when node changes. +ownerAttr = attribute owner +{ + text +} + +# Tag and leaf nodes may have constraints on their names and values +# (respectively). +# When multiple constraints are listed, they work as logical OR +constraint = element constraint +{ + ( (element regex { text }) | + validator )+ +} + +# A constraint may also use an external validator rather than regex +validator = element validator +{ + ( (attribute name { text }) & + (attribute argument { text })? ), + empty +} + +# help tags contains brief description of the purpose of the node +help = element help +{ + text +} + +# valueHelp tags contain information about acceptable value format +valueHelp = element valueHelp +{ + element format { text } & + element description { text } +} + +# completionHelp tags contain information about allowed values of a node that is used for generating +# tab completion in the CLI frontend and drop-down lists in GUI frontends +# It is only meaninful for leaf nodes +# Allowed values can be given as a fixed list of values (e.g. <list>foo bar baz</list>), +# as a configuration path (e.g. <path>interfaces ethernet</path>), +# or as a path to a script file that generates the list (e.g. <script>/usr/lib/foo/list-things</script> +completionHelp = element completionHelp +{ + (element list { text })* & + (element path { text })* & + (element script { text })* +} diff --git a/schema/interface_definition.rng b/schema/interface_definition.rng index d1bd9a708..195ef27f4 100644 --- a/schema/interface_definition.rng +++ b/schema/interface_definition.rng @@ -88,7 +88,12 @@ --> <define name="leafNode"> <element name="leafNode"> - <ref name="nodeNameAttr"/> + <interleave> + <optional> + <ref name="ownerAttr"/> + </optional> + <ref name="nodeNameAttr"/> + </interleave> <ref name="properties"/> </element> </define> diff --git a/src/conf-mode/vyos-config-host-name.py b/src/conf-mode/vyos-config-host-name.py index da053d9f6..2a245b211 100644..100755 --- a/src/conf-mode/vyos-config-host-name.py +++ b/src/conf-mode/vyos-config-host-name.py @@ -19,64 +19,70 @@ import os import re import sys +import subprocess from vyos.config import Config from vyos.util import ConfigError -hostname_config = "/etc/hostname" -mailname_config = "/etc/mailname" hostname_regex = re.compile("^[A-Za-z0-9][-.A-Za-z0-9]*[A-Za-z0-9]$") def get_config(): conf = Config() - conf.set_level("system") - - hostname = conf.return_value("host-name") - domain = conf.return_value("domain-name") - return { - "hostname": hostname, - "domain": domain - } + hostname = conf.return_value("system host-name") + domain = conf.return_value("system domain-name") + + # No one likes fixups, but we really don't want VyOS fail to boot + # if hostname is not in the config + if not hostname: + hostname = "vyos" + + if domain: + fqdn = "{0}.{1}".format(hostname, domain) + else: + fqdn = hostname + + return {"hostname": hostname, "domain": domain, "fqdn": fqdn} def verify(config): - # check for invalid host + # check for invalid host - # pattern $VAR(@) "^[[:alnum:]][-.[:alnum:]]*[[:alnum:]]$" ; "invalid host name $VAR(@)" - valid = hostname_regex.match(config.hostname) - if (!valid): - raise ConfigError('invalid host name' + config.hostname) + # pattern $VAR(@) "^[[:alnum:]][-.[:alnum:]]*[[:alnum:]]$" ; "invalid host name $VAR(@)" + 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') + # 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') - return None + return None def generate(config): - mailname = config.hostname - if config.domain != "": - mailname += '.' + config.domain + # read the hosts file + with open('/etc/hosts', 'r') as f: + hosts = f.read() - # update /etc/hostname - with open(hostname_config, 'w') as f: - f.write(config.hostname) + # get the current hostname + old_hostname = subprocess.check_output(['hostname']).decode().strip() - # update /etc/mailname - with open(mailname_config, 'w') as f: - f.write(mailname) + # replace the local host line + hosts = re.sub(r"(127.0.1.1\s+{0}.*)".format(old_hostname), r"127.0.1.1\t{0} # VyOS entry\n".format(config["fqdn"]), hosts) - return None + with open('/etc/hosts', 'w') as f: + f.write(hosts) + + return None def apply(config): - # set hostname for the current session - cmd = "hostname " + config.hostname - os.system(cmd) + os.system("hostnamectl set-hostname {0}".format(config["fqdn"])) + + # restart services that use the hostname + os.system("systemctl restart rsyslog.service") - return None + return None if __name__ == '__main__': |