#!/usr/bin/env python3 # -*- coding: utf-8 eval: (blacken-mode 1) -*- # SPDX-License-Identifier: MIT # # February 22 2022, Christian Hopps # # Copyright (c) 2022, LabN Consulting, L.L.C. import argparse import logging import os import sys import tempfile import pytest CWD = os.path.dirname(os.path.realpath(__file__)) try: # Make sure we don't run-into ourselves in parallel operating environment tmpdir = tempfile.mkdtemp(prefix="grpc-client-") # This is painful but works if you have installed grpc and grpc_tools would be *way* # better if we actually built and installed these but ... python packaging. try: import grpc_tools from munet.base import commander import grpc commander.cmd_raises(f"cp {CWD}/../../../grpc/frr-northbound.proto .") commander.cmd_raises( "python3 -m grpc_tools.protoc" f" --python_out={tmpdir} --grpc_python_out={tmpdir}" f" -I {CWD}/../../../grpc frr-northbound.proto" ) except Exception as error: logging.error("can't create proto definition modules %s", error) raise try: sys.path[0:0] = [tmpdir] print(sys.path) import frr_northbound_pb2 import frr_northbound_pb2_grpc sys.path = sys.path[1:] except Exception as error: logging.error("can't import proto definition modules %s", error) raise finally: commander.cmd_nostatus(f"rm -rf {tmpdir}") class GRPCClient: def __init__(self, server, port): self.channel = grpc.insecure_channel("{}:{}".format(server, port)) self.stub = frr_northbound_pb2_grpc.NorthboundStub(self.channel) def get_capabilities(self): request = frr_northbound_pb2.GetCapabilitiesRequest() response = "NONE" try: response = self.stub.GetCapabilities(request) except Exception as error: logging.error("Got exception from stub: %s", error) logging.debug("GRPC Capabilities: %s", response) return response def get(self, xpath, encoding, gtype): request = frr_northbound_pb2.GetRequest() request.path.append(xpath) request.type = gtype request.encoding = encoding result = "" for r in self.stub.Get(request): logging.debug('GRPC Get path: "%s" value: %s', request.path, r) result += str(r.data.data) return result def next_action(action_list=None): "Get next action from list or STDIN" if action_list: for action in action_list: yield action else: while True: try: action = input("") if not action: break yield action.strip() except EOFError: break def main(*args): parser = argparse.ArgumentParser(description="gRPC Client") parser.add_argument( "-s", "--server", default="localhost", help="gRPC Server Address" ) parser.add_argument( "-p", "--port", type=int, default=50051, help="gRPC Server TCP Port" ) parser.add_argument("-v", "--verbose", action="store_true", help="be verbose") parser.add_argument("--check", action="store_true", help="check runable") parser.add_argument("--xml", action="store_true", help="encode XML instead of JSON") parser.add_argument("actions", nargs="*", help="GETCAP|GET,xpath") args = parser.parse_args(*args) level = logging.DEBUG if args.verbose else logging.INFO logging.basicConfig( level=level, format="%(asctime)s %(levelname)s: GRPC-CLI-CLIENT: %(name)s %(message)s", ) if args.check: sys.exit(0) encoding = frr_northbound_pb2.XML if args.xml else frr_northbound_pb2.JSON c = GRPCClient(args.server, args.port) for action in next_action(args.actions): action = action.casefold() logging.debug("GOT ACTION: %s", action) if action == "getcap": caps = c.get_capabilities() print(caps) elif action.startswith("get,"): # Get and print config and state _, xpath = action.split(",", 1) logging.debug("Get XPath: %s", xpath) print(c.get(xpath, encoding, gtype=frr_northbound_pb2.GetRequest.ALL)) elif action.startswith("get-config,"): # Get and print config _, xpath = action.split(",", 1) logging.debug("Get Config XPath: %s", xpath) print(c.get(xpath, encoding, gtype=frr_northbound_pb2.GetRequest.CONFIG)) # for _ in range(0, 1): elif action.startswith("get-state,"): # Get and print state _, xpath = action.split(",", 1) logging.debug("Get State XPath: %s", xpath) print(c.get(xpath, encoding, gtype=frr_northbound_pb2.GetRequest.STATE)) # for _ in range(0, 1): if __name__ == "__main__": main()