From 3480d92a8c4d84e8c1f94a9362bac2be0cc77921 Mon Sep 17 00:00:00 2001
From: Nataliia Solomko <natalirs1985@gmail.com>
Date: Wed, 28 Feb 2024 11:42:58 +0200
Subject: T5504 Keepalived VRRP ability to set more than one peer-address

---
 src/conf_mode/high-availability.py | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

(limited to 'src')

diff --git a/src/conf_mode/high-availability.py b/src/conf_mode/high-availability.py
index b3b27b14e..59d49ea67 100755
--- a/src/conf_mode/high-availability.py
+++ b/src/conf_mode/high-availability.py
@@ -125,8 +125,9 @@ def verify(ha):
                         raise ConfigError(f'VRRP group "{group}" uses IPv4 but hello-source-address is IPv6!')
 
                 if 'peer_address' in group_config:
-                    if is_ipv6(group_config['peer_address']):
-                        raise ConfigError(f'VRRP group "{group}" uses IPv4 but peer-address is IPv6!')
+                    for peer_address in group_config['peer_address']:
+                        if is_ipv6(peer_address):
+                            raise ConfigError(f'VRRP group "{group}" uses IPv4 but peer-address is IPv6!')
 
             if vaddrs6:
                 tmp = {'interface': interface, 'vrid': vrid, 'ipver': 'IPv6'}
@@ -139,8 +140,9 @@ def verify(ha):
                         raise ConfigError(f'VRRP group "{group}" uses IPv6 but hello-source-address is IPv4!')
 
                 if 'peer_address' in group_config:
-                    if is_ipv4(group_config['peer_address']):
-                        raise ConfigError(f'VRRP group "{group}" uses IPv6 but peer-address is IPv4!')
+                    for peer_address in group_config['peer_address']:
+                        if is_ipv4(peer_address):
+                            raise ConfigError(f'VRRP group "{group}" uses IPv6 but peer-address is IPv4!')
     # Check sync groups
     if 'vrrp' in ha and 'sync_group' in ha['vrrp']:
         for sync_group, sync_config in ha['vrrp']['sync_group'].items():
-- 
cgit v1.2.3


From 0ea3a454cf560171d3eb9d4d1b97b172c06360fe Mon Sep 17 00:00:00 2001
From: Christian Breunig <christian@breunig.cc>
Date: Wed, 28 Feb 2024 20:47:10 +0100
Subject: banner: T6077: implement ASCII contest winner default logo

Implement VyOS ASCII art contest winners logo as the default for our MOTD
---
 data/templates/login/default_motd.j2 | 14 ++++++++++++++
 src/conf_mode/system_login_banner.py | 22 +++++++++++-----------
 2 files changed, 25 insertions(+), 11 deletions(-)
 create mode 100644 data/templates/login/default_motd.j2

(limited to 'src')

diff --git a/data/templates/login/default_motd.j2 b/data/templates/login/default_motd.j2
new file mode 100644
index 000000000..8584d261a
--- /dev/null
+++ b/data/templates/login/default_motd.j2
@@ -0,0 +1,14 @@
+Welcome to VyOS!
+
+   ┌── ┐
+   . VyOS {{ version_data.version }}
+   └ ──┘  {{ version_data.release_train }}
+
+ * Documentation:  https://docs.vyos.io/en/{{ version_data.release_train | replace('current', 'latest') }}
+ * Project news:   https://blog.vyos.io
+ * Bug reports:    https://vyos.dev
+
+You can change this banner using "set system login banner post-login" command.
+
+VyOS is a free software distribution that includes multiple components,
+you can check individual component licenses under /usr/share/doc/*/copyright
diff --git a/src/conf_mode/system_login_banner.py b/src/conf_mode/system_login_banner.py
index 65fa04417..923e1bf57 100755
--- a/src/conf_mode/system_login_banner.py
+++ b/src/conf_mode/system_login_banner.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2020-2021 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -18,30 +18,26 @@ from sys import exit
 from copy import deepcopy
 
 from vyos.config import Config
+from vyos.template import render
 from vyos.utils.file import write_file
+from vyos.version import get_version_data
 from vyos import ConfigError
 from vyos import airbag
 airbag.enable()
 
-try:
-    with open('/usr/share/vyos/default_motd') as f:
-        motd = f.read()
-except:
-    # Use an empty banner if the default banner file cannot be read
-    motd = "\n"
-
 PRELOGIN_FILE = r'/etc/issue'
 PRELOGIN_NET_FILE = r'/etc/issue.net'
 POSTLOGIN_FILE = r'/etc/motd'
 
 default_config_data = {
     'issue': 'Welcome to VyOS - \\n \\l\n\n',
-    'issue_net': '',
-    'motd': motd
+    'issue_net': ''
 }
 
 def get_config(config=None):
     banner = deepcopy(default_config_data)
+    banner['version_data'] = get_version_data()
+
     if config:
         conf = config
     else:
@@ -92,7 +88,11 @@ def generate(banner):
 def apply(banner):
     write_file(PRELOGIN_FILE, banner['issue'])
     write_file(PRELOGIN_NET_FILE, banner['issue_net'])
-    write_file(POSTLOGIN_FILE, banner['motd'])
+    if 'motd' in banner:
+        write_file(POSTLOGIN_FILE, banner['motd'])
+    else:
+        render(POSTLOGIN_FILE, 'login/default_motd.j2', banner,
+            permission=0o644, user='root', group='root')
 
     return None
 
-- 
cgit v1.2.3


From 70e1df1b5fcb3b1791cca320ed45b71e01e1ffda Mon Sep 17 00:00:00 2001
From: John Estabrook <jestabro@vyos.io>
Date: Tue, 27 Feb 2024 14:54:50 -0600
Subject: configdep: T5660: remove global redundancies under vyos-configd

---
 python/vyos/configdep.py  | 18 ++++++++++++++----
 src/services/vyos-configd | 19 ++++++++++++++++---
 src/shim/vyshim.c         | 12 ++++++++++--
 3 files changed, 40 insertions(+), 9 deletions(-)

(limited to 'src')

diff --git a/python/vyos/configdep.py b/python/vyos/configdep.py
index 41252d8f5..73bd9ea96 100644
--- a/python/vyos/configdep.py
+++ b/python/vyos/configdep.py
@@ -33,9 +33,10 @@ if typing.TYPE_CHECKING:
 dependency_dir = os.path.join(directories['data'],
                               'config-mode-dependencies')
 
-dependent_func: dict[str, list[typing.Callable]] = {}
+local_dependent_func: dict[str, list[typing.Callable]] = {}
 
 DEBUG = False
+FORCE_LOCAL = False
 
 def debug_print(s: str):
     if DEBUG:
@@ -122,16 +123,25 @@ def set_dependents(case: str, config: 'Config',
     d = get_dependency_dict(config)
     k = canon_name_of_path(caller_name())
     tag_ext = f'_{tagnode}' if tagnode is not None else ''
-    l = dependent_func.setdefault(k, [])
+    if hasattr(config, 'dependent_func') and not FORCE_LOCAL:
+        dependent_func = getattr(config, 'dependent_func')
+        l = dependent_func.setdefault('vyos_configd', [])
+    else:
+        dependent_func = local_dependent_func
+        l = dependent_func.setdefault(k, [])
     for target in d[k][case]:
         func = def_closure(target, config, tagnode)
         func.__name__ = f'{target}{tag_ext}'
         append_uniq(l, func)
     debug_print(f'set_dependents: caller {k}, dependents {names_of(l)}')
 
-def call_dependents():
+def call_dependents(dependent_func: dict = None):
     k = canon_name_of_path(caller_name())
-    l = dependent_func.get(k, [])
+    if dependent_func is None or FORCE_LOCAL:
+        dependent_func = local_dependent_func
+        l = dependent_func.get(k, [])
+    else:
+        l = dependent_func.get('vyos_configd', [])
     debug_print(f'call_dependents: caller {k}, dependents {names_of(l)}')
     while l:
         f = l.pop(0)
diff --git a/src/services/vyos-configd b/src/services/vyos-configd
index 355182b26..648a017d5 100755
--- a/src/services/vyos-configd
+++ b/src/services/vyos-configd
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 #
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -19,6 +19,7 @@ import sys
 import grp
 import re
 import json
+import typing
 import logging
 import signal
 import importlib.util
@@ -29,6 +30,7 @@ from vyos.defaults import directories
 from vyos.utils.boot import boot_configuration_complete
 from vyos.configsource import ConfigSourceString
 from vyos.configsource import ConfigSourceError
+from vyos.configdep import call_dependents
 from vyos.config import Config
 from vyos import ConfigError
 
@@ -198,10 +200,12 @@ def initialization(socket):
         return None
 
     config = Config(config_source=configsource)
+    dependent_func: dict[str, list[typing.Callable]] = {}
+    setattr(config, 'dependent_func', dependent_func)
 
     return config
 
-def process_node_data(config, data) -> int:
+def process_node_data(config, data, last: bool = False) -> int:
     if not config:
         logger.critical(f"Empty config")
         return R_ERROR_DAEMON
@@ -223,11 +227,18 @@ def process_node_data(config, data) -> int:
     args.insert(0, f'{script_name}.py')
 
     if script_name not in include_set:
+        # call dependents now if last element of prio queue is run
+        # independent of configd
+        if last:
+            call_dependents(dependent_func=config.dependent_func)
         return R_PASS
 
     with stdout_redirected(session_out, session_mode):
         result = run_script(conf_mode_scripts[script_name], config, args)
 
+    if last:
+        call_dependents(dependent_func=config.dependent_func)
+
     return result
 
 def remove_if_file(f: str):
@@ -281,7 +292,9 @@ if __name__ == '__main__':
             socket.send(resp.encode())
             config = initialization(socket)
         elif message["type"] == "node":
-            res = process_node_data(config, message["data"])
+            if message["last"]:
+                logger.debug(f'final element of priority queue')
+            res = process_node_data(config, message["data"], message["last"])
             response = res.to_bytes(1, byteorder=sys.byteorder)
             logger.debug(f"Sending response {res}")
             socket.send(response)
diff --git a/src/shim/vyshim.c b/src/shim/vyshim.c
index cae8b6152..41723e7a4 100644
--- a/src/shim/vyshim.c
+++ b/src/shim/vyshim.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 VyOS maintainers and contributors
+ * Copyright (C) 2020-2024 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
@@ -49,6 +49,7 @@
 #define GET_SESSION "cli-shell-api --show-working-only --show-show-defaults --show-ignore-edit showConfig"
 
 #define COMMIT_MARKER "/var/tmp/initial_in_commit"
+#define QUEUE_MARKER "/var/tmp/last_in_queue"
 
 enum {
     SUCCESS =      1 << 0,
@@ -77,6 +78,7 @@ int main(int argc, char* argv[])
 
     int ex_index;
     int init_timeout = 0;
+    int last = 0;
 
     debug_print("Connecting to vyos-configd ...\n");
     zmq_connect(requester, SOCKET_PATH);
@@ -101,10 +103,16 @@ int main(int argc, char* argv[])
         return ret;
     }
 
+    if (access(QUEUE_MARKER, F_OK) != -1) {
+        last = 1;
+        remove(QUEUE_MARKER);
+    }
+
     char error_code[1];
     debug_print("Sending node data ...\n");
-    char *string_node_data_msg = mkjson(MKJSON_OBJ, 2,
+    char *string_node_data_msg = mkjson(MKJSON_OBJ, 3,
                                         MKJSON_STRING, "type", "node",
+                                        MKJSON_BOOL, "last", last,
                                         MKJSON_STRING, "data", &string_node_data[0]);
 
     zmq_send(requester, string_node_data_msg, strlen(string_node_data_msg), 0);
-- 
cgit v1.2.3