From b09773ae75ed138b870b0741dd73a5b038456d8a Mon Sep 17 00:00:00 2001
From: Dave Wallace <dwallacelf@gmail.com>
Date: Tue, 26 Apr 2022 21:04:31 -0400
Subject: [PATCH 1/2] vppcfg: add args to specify location of vpp api files

- refactor to address review comments.

Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
---
 vpp/dumper.py     |  9 ++++++--
 vpp/reconciler.py |  4 ++--
 vpp/vppapi.py     | 22 ++++++++++++------
 vppcfg            | 58 +++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 80 insertions(+), 13 deletions(-)

diff --git a/vpp/dumper.py b/vpp/dumper.py
index 13ced60..476d517 100644
--- a/vpp/dumper.py
+++ b/vpp/dumper.py
@@ -31,8 +31,13 @@ class Dumper(VPPApi):
     Note that not all running VPP configs are "valid" in vppcfg's eyes. It is not
     guaranteed that the output of the Dumper() will stand validation."""
 
-    def __init__(self, address="/run/vpp/api.sock", clientname="vppcfg"):
-        VPPApi.__init__(self, address, clientname)
+    def __init__(
+        self,
+        vpp_api_socket="/run/vpp/api.sock",
+        vpp_json_dir="/usr/share/vpp/api/",
+        clientname="vppcfg",
+    ):
+        VPPApi.__init__(self, vpp_api_socket, vpp_json_dir, clientname)
 
     def write(self, outfile):
         """Emit the configuration to either stdout (outfile=='-') or a filename"""
diff --git a/vpp/reconciler.py b/vpp/reconciler.py
index 8eda3e8..d5c5599 100644
--- a/vpp/reconciler.py
+++ b/vpp/reconciler.py
@@ -38,11 +38,11 @@ class Reconciler:
     but not yet in the dataplane; and finally it syncs the configuration attributes of
     objects that can be changed at runtime."""
 
-    def __init__(self, cfg):
+    def __init__(self, cfg, vpp_api_socket='/run/vpp/api.sock', vpp_json_dir='/usr/share/vpp/api/'):
         self.logger = logging.getLogger("vppcfg.reconciler")
         self.logger.addHandler(logging.NullHandler())
 
-        self.vpp = VPPApi()
+        self.vpp = VPPApi(vpp_api_socket, vpp_json_dir)
         self.cfg = cfg
 
         ## List of CLI calls emitted during the prune, create and sync phases.
diff --git a/vpp/vppapi.py b/vpp/vppapi.py
index 40dbd32..a4caf94 100644
--- a/vpp/vppapi.py
+++ b/vpp/vppapi.py
@@ -28,11 +28,22 @@ from vpp_papi import VPPApiClient
 class VPPApi:
     """The VPPApi class is a base class that abstracts the vpp_papi."""
 
-    def __init__(self, address="/run/vpp/api.sock", clientname="vppcfg"):
+    def __init__(
+        self,
+        vpp_api_socket="/run/vpp/api.sock",
+        vpp_json_dir="/usr/share/vpp/api/",
+        clientname="vppcfg",
+    ):
         self.logger = logging.getLogger("vppcfg.vppapi")
         self.logger.addHandler(logging.NullHandler())
 
-        self.address = address
+        if not os.path.exists(vpp_api_socket):
+            self.logger.error(f"VPP api socket file not found: {vpp_api_socket}")
+        if not os.path.isdir(vpp_json_dir):
+            self.logger.error(f"VPP api json directory not found: {vpp_json_dir}")
+
+        self.vpp_api_socket = vpp_api_socket
+        self.vpp_json_dir = vpp_json_dir
         self.connected = False
         self.clientname = clientname
         self.vpp = None
@@ -45,12 +56,9 @@ class VPPApi:
         if self.connected:
             return True
 
-        vpp_json_dir = "/usr/share/vpp/api/"
-        ## vpp_json_dir = "/home/pim/src/vpp/build-root/build-vpp_debug-native/vpp/CMakeFiles/"
-
         # construct a list of all the json api files
         jsonfiles = []
-        for root, _dirnames, filenames in os.walk(vpp_json_dir):
+        for root, _dirnames, filenames in os.walk(self.vpp_json_dir):
             for filename in fnmatch.filter(filenames, "*.api.json"):
                 jsonfiles.append(os.path.join(root, filename))
 
@@ -58,7 +66,7 @@ class VPPApi:
             self.logger.error("no json api files found")
             return False
 
-        self.vpp = VPPApiClient(apifiles=jsonfiles, server_address=self.address)
+        self.vpp = VPPApiClient(apifiles=jsonfiles, server_address=self.vpp_api_socket)
         try:
             self.logger.debug("Connecting to VPP")
             self.vpp.connect(self.clientname)
diff --git a/vppcfg b/vppcfg
index 7ce9fe6..4075999 100755
--- a/vppcfg
+++ b/vppcfg
@@ -86,6 +86,22 @@ def main():
         type=str,
         help="""Output file for YAML config, default stdout""",
     )
+    dump_p.add_argument(
+        "-j",
+        "--vpp-json-dir",
+        dest="vpp_json_dir",
+        required=False,
+        type=str,
+        help="""Directory where VPP API JSON files are located""",
+    )
+    dump_p.add_argument(
+        "-a",
+        "--vpp-api-socket",
+        dest="vpp_api_socket",
+        required=False,
+        type=str,
+        help="""Pathname of VPP API socket file""",
+    )
 
     plan_p = subparsers.add_parser(
         "plan",
@@ -115,6 +131,22 @@ def main():
         type=str,
         help="""Output file for VPP CLI commands, default stdout""",
     )
+    plan_p.add_argument(
+        "-j",
+        "--vpp-json-dir",
+        dest="vpp_json_dir",
+        required=False,
+        type=str,
+        help="""Directory where VPP API JSON files are located""",
+    )
+    plan_p.add_argument(
+        "-a",
+        "--vpp-api-socket",
+        dest="vpp_api_socket",
+        required=False,
+        type=str,
+        help="""Pathname of VPP API socket file""",
+    )
 
     apply_p = subparsers.add_parser(
         "apply", help="apply changes from current VPP dataplane to target config"
@@ -134,6 +166,22 @@ def main():
         type=str,
         help="""YAML configuration file for vppcfg""",
     )
+    apply_p.add_argument(
+        "-j",
+        "--vpp-json-dir",
+        dest="vpp_json_dir",
+        required=False,
+        type=str,
+        help="""Directory where VPP API JSON files are located""",
+    )
+    apply_p.add_argument(
+        "-a",
+        "--vpp-api-socket",
+        dest="vpp_api_socket",
+        required=False,
+        type=str,
+        help="""Pathname of VPP API socket file""",
+    )
 
     args = parser.parse_args()
     if not args.command:
@@ -150,8 +198,14 @@ def main():
         format="[%(levelname)-8s] %(name)s.%(funcName)s: %(message)s", level=level
     )
 
+    opt_kwargs = {}
+    if args.vpp_json_dir:
+        opt_kwargs["vpp_json_dir"] = args.vpp_json_dir
+    if args.vpp_api_socket:
+        opt_kwargs["vpp_api_socket"] = args.vpp_api_socket
+
     if args.command == "dump":
-        dumper = Dumper()
+        dumper = Dumper(**opt_kwargs)
         if not dumper.readconfig():
             logging.error("Could not retrieve config from VPP")
             sys.exit(-7)
@@ -175,7 +229,7 @@ def main():
     if args.command == "check":
         sys.exit(0)
 
-    reconciler = Reconciler(cfg)
+    reconciler = Reconciler(cfg, **opt_kwargs)
     if not reconciler.vpp.readconfig():
         sys.exit(-3)
 

From a9cff05ca4c7c87f608b156533c007c00cfd7773 Mon Sep 17 00:00:00 2001
From: Dave Wallace <dwallacelf@gmail.com>
Date: Tue, 26 Apr 2022 21:30:06 -0400
Subject: [PATCH 2/2] vpp/reconciler: format diff with black

Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
---
 vpp/reconciler.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/vpp/reconciler.py b/vpp/reconciler.py
index d5c5599..d4cd9e2 100644
--- a/vpp/reconciler.py
+++ b/vpp/reconciler.py
@@ -38,7 +38,12 @@ class Reconciler:
     but not yet in the dataplane; and finally it syncs the configuration attributes of
     objects that can be changed at runtime."""
 
-    def __init__(self, cfg, vpp_api_socket='/run/vpp/api.sock', vpp_json_dir='/usr/share/vpp/api/'):
+    def __init__(
+        self,
+        cfg,
+        vpp_api_socket="/run/vpp/api.sock",
+        vpp_json_dir="/usr/share/vpp/api/",
+    ):
         self.logger = logging.getLogger("vppcfg.reconciler")
         self.logger.addHandler(logging.NullHandler())