From 65130073eec20cdbb701b0f15a5a2e2676c96039 Mon Sep 17 00:00:00 2001
From: Christian Poessinger <christian@poessinger.com>
Date: Fri, 26 Jun 2020 15:59:46 +0200
Subject: ifconfig: T2653: move dummy interface to get_config_dict()

This changes the dummy interface implementation to make use of get_config_dict()
and also implement a new vyos.ifconfig.Interface().update() function to gather
all the scattered calls to update common interface configuration options.

Derived classes of Interface() should extend update() to their needs for their
special interface type - e.g. bond or bridge.
---
 src/conf_mode/interfaces-dummy.py | 120 +++++++++++---------------------------
 1 file changed, 34 insertions(+), 86 deletions(-)

(limited to 'src')

diff --git a/src/conf_mode/interfaces-dummy.py b/src/conf_mode/interfaces-dummy.py
index ec255edd5..749024e84 100755
--- a/src/conf_mode/interfaces-dummy.py
+++ b/src/conf_mode/interfaces-dummy.py
@@ -16,98 +16,66 @@
 
 import os
 
-from copy import deepcopy
-from sys import exit
 from netifaces import interfaces
+from sys import exit
 
-from vyos.ifconfig import DummyIf
-from vyos.configdict import list_diff
 from vyos.config import Config
+from vyos.ifconfig import DummyIf
 from vyos.validate import is_member
-from vyos import ConfigError
-
-from vyos import airbag
+from vyos import ConfigError, airbag
 airbag.enable()
 
-default_config_data = {
-    'address': [],
-    'address_remove': [],
-    'deleted': False,
-    'description': '',
-    'disable': False,
-    'intf': '',
-    'is_bridge_member': False,
-    'vrf': ''
-}
-
 def get_config():
-    dummy = deepcopy(default_config_data)
+    """ Retrive CLI config as dictionary. Dictionary can never be empty,
+        as at least the interface name will be added or a deleted flag """
     conf = Config()
 
     # determine tagNode instance
     if 'VYOS_TAGNODE_VALUE' not in os.environ:
         raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified')
 
-    dummy['intf'] = os.environ['VYOS_TAGNODE_VALUE']
+    ifname = os.environ['VYOS_TAGNODE_VALUE']
+    base = ['interfaces', 'dummy', ifname]
+
+    dummy = conf.get_config_dict(base, key_mangling=('-', '_'))
+    # store interface instance name in dictionary
+    dummy.update({'ifname': ifname})
 
     # check if we are a member of any bridge
-    dummy['is_bridge_member'] = is_member(conf, dummy['intf'], 'bridge')
+    bridge = is_member(conf, ifname, 'bridge')
+    if bridge:
+        tmp = {'is_bridge_member' : bridge}
+        dummy.update(tmp)
 
     # Check if interface has been removed
-    if not conf.exists('interfaces dummy ' + dummy['intf']):
-        dummy['deleted'] = True
-        return dummy
-
-    # set new configuration level
-    conf.set_level('interfaces dummy ' + dummy['intf'])
-
-    # retrieve configured interface addresses
-    if conf.exists('address'):
-        dummy['address'] = conf.return_values('address')
-
-    # retrieve interface description
-    if conf.exists('description'):
-        dummy['description'] = conf.return_value('description')
-
-    # Disable this interface
-    if conf.exists('disable'):
-        dummy['disable'] = True
-
-    # Determine interface addresses (currently effective) - to determine which
-    # address is no longer valid and needs to be removed from the interface
-    eff_addr = conf.return_effective_values('address')
-    act_addr = conf.return_values('address')
-    dummy['address_remove'] = list_diff(eff_addr, act_addr)
-
-    # retrieve VRF instance
-    if conf.exists('vrf'):
-        dummy['vrf'] = conf.return_value('vrf')
+    tmp = {'deleted' : not conf.exists(base)}
+    dummy.update(tmp)
 
     return dummy
 
 def verify(dummy):
     if dummy['deleted']:
-        if dummy['is_bridge_member']:
-            raise ConfigError((
-                f'Interface "{dummy["intf"]}" cannot be deleted as it is a '
-                f'member of bridge "{dummy["is_bridge_member"]}"!'))
+        if 'is_bridge_member' in dummy.keys():
+            raise ConfigError(
+                'Interface "{ifname}" cannot be deleted as it is a '
+                'member of bridge "{is_bridge_member}"!'.format(**dummy))
 
         return None
 
-    if dummy['vrf']:
+    if 'vrf' in dummy.keys():
         if dummy['vrf'] not in interfaces():
-            raise ConfigError(f'VRF "{dummy["vrf"]}" does not exist')
+            raise ConfigError('VRF "{vrf}" does not exist'.format(**dummy))
 
-        if dummy['is_bridge_member']:
-            raise ConfigError((
-                f'Interface "{dummy["intf"]}" cannot be member of VRF '
-                f'"{dummy["vrf"]}" and bridge "{dummy["is_bridge_member"]}" '
-                f'at the same time!'))
+        if 'is_bridge_member' in dummy.keys():
+            raise ConfigError(
+                'Interface "{ifname}" cannot be both a member of VRF "{vrf}" '
+                'and bridge "{is_bridge_member}"!'.format(**dummy))
 
-    if dummy['is_bridge_member'] and dummy['address']:
-        raise ConfigError((
-            f'Cannot assign address to interface "{dummy["intf"]}" '
-            f'as it is a member of bridge "{dummy["is_bridge_member"]}"!'))
+    # check if both keys are part of the dictionary
+    if {'is_bridge_member', 'address'} <= set(dummy):
+        raise ConfigError(
+            f'Cannot assign address to interface "{ifname}" as it is a '
+            f'member of bridge "{is_bridge_member}"!'.format(**dummy))
 
     return None
 
@@ -115,33 +83,13 @@ def generate(dummy):
     return None
 
 def apply(dummy):
-    d = DummyIf(dummy['intf'])
+    d = DummyIf(dummy['ifname'])
 
     # Remove dummy interface
     if dummy['deleted']:
         d.remove()
     else:
-        # update interface description used e.g. within SNMP
-        d.set_alias(dummy['description'])
-
-        # Configure interface address(es)
-        # - not longer required addresses get removed first
-        # - newly addresses will be added second
-        for addr in dummy['address_remove']:
-            d.del_addr(addr)
-        for addr in dummy['address']:
-            d.add_addr(addr)
-
-        # assign/remove VRF (ONLY when not a member of a bridge,
-        # otherwise 'nomaster' removes it from it)
-        if not dummy['is_bridge_member']:
-            d.set_vrf(dummy['vrf'])
-
-        # disable interface on demand
-        if dummy['disable']:
-            d.set_admin_state('down')
-        else:
-            d.set_admin_state('up')
+        d.update(dummy)
 
     return None
 
-- 
cgit v1.2.3