From b6dcb0a887a4fab89ca870d6142d6856cccc181f Mon Sep 17 00:00:00 2001
From: Christian Poessinger <christian@poessinger.com>
Date: Mon, 3 Aug 2020 13:51:48 +0200
Subject: ifconfig: T2653: unify DHCPv4 configuration

Pass the interface dictionary transparently to the DHCP module and render the
DHCP client config template directly from the same source instead of transcoding
it once more.
---
 python/vyos/ifconfig/dhcp.py      | 48 +++++++++++++++++++--------------------
 python/vyos/ifconfig/interface.py | 10 +-------
 2 files changed, 25 insertions(+), 33 deletions(-)

(limited to 'python')

diff --git a/python/vyos/ifconfig/dhcp.py b/python/vyos/ifconfig/dhcp.py
index bd37970a2..5f99a0b7e 100644
--- a/python/vyos/ifconfig/dhcp.py
+++ b/python/vyos/ifconfig/dhcp.py
@@ -14,26 +14,22 @@
 # License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 
 import os
+import jmespath
 
+from vyos.configdict import dict_merge
 from vyos.configverify import verify_dhcpv6
-from vyos.dicts import FixedDict
 from vyos.ifconfig.control import Control
 from vyos.template import render
 
 class _DHCPv4 (Control):
     def __init__(self, ifname):
         super().__init__()
-        config_base = r'/var/lib/dhcp/dhclient_'
-        self.options = FixedDict(**{
-            'ifname': ifname,
-            'hostname': '',
-            'client_id': '',
-            'vendor_class_id': '',
-            'conf_file': config_base + f'{ifname}.conf',
-            'options_file': config_base + f'{ifname}.options',
-            'pid_file': config_base + f'{ifname}.pid',
-            'lease_file': config_base + f'{ifname}.leases',
-        })
+        config_base = r'/var/lib/dhcp/dhclient'
+        self._conf_file = f'{config_base}_{ifname}.conf'
+        self._options_file = f'{config_base}_{ifname}.options'
+        self._pid_file = f'{config_base}_{ifname}.pid'
+        self._lease_file = f'{config_base}_{ifname}.leases'
+        self.options = {'ifname' : ifname}
 
     # replace dhcpv4/v6 with systemd.networkd?
     def set(self):
@@ -42,19 +38,24 @@ class _DHCPv4 (Control):
         started in background!
 
         Example:
-
         >>> from vyos.ifconfig import Interface
         >>> j = Interface('eth0')
         >>> j.dhcp.v4.set()
         """
-        if not self.options['hostname']:
+
+        if jmespath.search('dhcp_options.host_name', self.options) == None:
             # read configured system hostname.
             # maybe change to vyos hostd client ???
+            hostname = 'vyos'
             with open('/etc/hostname', 'r') as f:
-                self.options['hostname'] = f.read().rstrip('\n')
+                hostname = f.read().rstrip('\n')
+                tmp = {'dhcp_options' : { 'host_name' : hostname}}
+                self.options = dict_merge(tmp, self.options)
 
-        render(self.options['options_file'], 'dhcp-client/daemon-options.tmpl', self.options)
-        render(self.options['conf_file'], 'dhcp-client/ipv4.tmpl', self.options)
+        render(self._options_file, 'dhcp-client/daemon-options.tmpl',
+               self.options, trim_blocks=True)
+        render(self._conf_file, 'dhcp-client/ipv4.tmpl',
+               self.options, trim_blocks=True)
 
         return self._cmd('systemctl restart dhclient@{ifname}.service'.format(**self.options))
 
@@ -64,21 +65,20 @@ class _DHCPv4 (Control):
         pid, config and lease will be removed.
 
         Example:
-
         >>> from vyos.ifconfig import Interface
         >>> j = Interface('eth0')
         >>> j.dhcp.v4.delete()
         """
-        if not os.path.isfile(self.options['pid_file']):
+        if not os.path.isfile(self._pid_file):
             self._debug_msg('No DHCP client PID found')
             return None
 
         self._cmd('systemctl stop dhclient@{ifname}.service'.format(**self.options))
 
         # cleanup old config files
-        for name in ('conf_file', 'options_file', 'pid_file', 'lease_file'):
-            if os.path.isfile(self.options[name]):
-                os.remove(self.options[name])
+        for file in [self._conf_file, self._options_file, self._pid_file, self._lease_file]:
+            if os.path.isfile(file):
+                os.remove(file)
 
 class _DHCPv6 (Control):
     def __init__(self, ifname):
@@ -101,7 +101,8 @@ class _DHCPv6 (Control):
         # missed it we are safe!
         verify_dhcpv6(self.options)
 
-        render(self._config, 'dhcp-client/ipv6.tmpl', self.options, trim_blocks=True)
+        render(self._config, 'dhcp-client/ipv6.tmpl',
+               self.options, trim_blocks=True)
         return self._cmd('systemctl restart dhcp6c@{ifname}.service'.format(
             **self.options))
 
@@ -111,7 +112,6 @@ class _DHCPv6 (Control):
         pid, config and lease will be removed.
 
         Example:
-
         >>> from vyos.ifconfig import Interface
         >>> j = Interface('eth0')
         >>> j.dhcp.v6.delete()
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index f5e43e172..214ece8cd 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -824,15 +824,7 @@ class Interface(Control):
 
         # DHCP options
         if 'dhcp_options' in config:
-            dhcp_options = config.get('dhcp_options')
-            if 'client_id' in dhcp_options:
-                self.dhcp.v4.options['client_id'] = dhcp_options.get('client_id')
-
-            if 'host_name' in dhcp_options:
-                self.dhcp.v4.options['hostname'] = dhcp_options.get('host_name')
-
-            if 'vendor_class_id' in dhcp_options:
-                self.dhcp.v4.options['vendor_class_id'] = dhcp_options.get('vendor_class_id')
+            self.dhcp.v4.options = config
 
         # DHCPv6 options
         if 'dhcpv6_options' in config:
-- 
cgit v1.2.3