]>
Commit | Line | Data |
---|---|---|
e00241ad CH |
1 | #!/usr/bin/env python3 |
2 | # -*- coding: utf-8 eval: (blacken-mode 1) -*- | |
acddc0ed | 3 | # SPDX-License-Identifier: MIT |
e00241ad CH |
4 | # |
5 | # February 22 2022, Christian Hopps <chopps@labn.net> | |
6 | # | |
7 | # Copyright (c) 2022, LabN Consulting, L.L.C. | |
e00241ad CH |
8 | |
9 | import argparse | |
10 | import logging | |
11 | import os | |
12 | import sys | |
13 | ||
14 | import pytest | |
15 | ||
16 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
17 | ||
18 | # This is painful but works if you have installed grpc and grpc_tools would be *way* | |
19 | # better if we actually built and installed these but ... python packaging. | |
20 | try: | |
21 | import grpc | |
22 | import grpc_tools | |
23 | ||
60e03778 CH |
24 | sys.path.append(os.path.dirname(CWD)) |
25 | from munet.base import commander | |
e00241ad CH |
26 | |
27 | commander.cmd_raises(f"cp {CWD}/../../../grpc/frr-northbound.proto .") | |
28 | commander.cmd_raises( | |
29 | f"python -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I . frr-northbound.proto" | |
30 | ) | |
31 | except Exception as error: | |
32 | logging.error("can't create proto definition modules %s", error) | |
33 | raise | |
34 | ||
35 | try: | |
36 | sys.path[0:0] = "." | |
37 | import frr_northbound_pb2 | |
38 | import frr_northbound_pb2_grpc | |
39 | ||
40 | # Would be nice if compiling the modules internally from the source worked | |
41 | # # import grpc_tools.protoc | |
42 | # # proto_include = pkg_resources.resource_filename("grpc_tools", "_proto") | |
43 | # from grpc_tools.protoc import _proto_file_to_module_name, _protos_and_services | |
44 | # try: | |
45 | # frr_northbound_pb2, frr_northbound_pb2_grpc = _protos_and_services( | |
46 | # "frr_northbound.proto" | |
47 | # ) | |
48 | # finally: | |
49 | # os.chdir(CWD) | |
50 | except Exception as error: | |
51 | logging.error("can't import proto definition modules %s", error) | |
52 | raise | |
53 | ||
54 | ||
55 | class GRPCClient: | |
56 | def __init__(self, server, port): | |
57 | self.channel = grpc.insecure_channel("{}:{}".format(server, port)) | |
58 | self.stub = frr_northbound_pb2_grpc.NorthboundStub(self.channel) | |
59 | ||
60 | def get_capabilities(self): | |
61 | request = frr_northbound_pb2.GetCapabilitiesRequest() | |
62 | response = "NONE" | |
63 | try: | |
64 | response = self.stub.GetCapabilities(request) | |
65 | except Exception as error: | |
66 | logging.error("Got exception from stub: %s", error) | |
67 | ||
68 | logging.debug("GRPC Capabilities: %s", response) | |
69 | return response | |
70 | ||
71 | def get(self, xpath): | |
72 | request = frr_northbound_pb2.GetRequest() | |
73 | request.path.append(xpath) | |
74 | request.type = frr_northbound_pb2.GetRequest.ALL | |
75 | request.encoding = frr_northbound_pb2.XML | |
76 | xml = "" | |
77 | for r in self.stub.Get(request): | |
78 | logging.info('GRPC Get path: "%s" value: %s', request.path, r) | |
79 | xml += str(r.data.data) | |
80 | return xml | |
81 | ||
82 | ||
83 | def next_action(action_list=None): | |
84 | "Get next action from list or STDIN" | |
85 | if action_list: | |
86 | for action in action_list: | |
87 | yield action | |
88 | else: | |
89 | while True: | |
90 | try: | |
91 | action = input("") | |
92 | if not action: | |
93 | break | |
94 | yield action.strip() | |
95 | except EOFError: | |
96 | break | |
97 | ||
98 | ||
99 | def main(*args): | |
100 | parser = argparse.ArgumentParser(description="gRPC Client") | |
101 | parser.add_argument( | |
102 | "-s", "--server", default="localhost", help="gRPC Server Address" | |
103 | ) | |
104 | parser.add_argument( | |
105 | "-p", "--port", type=int, default=50051, help="gRPC Server TCP Port" | |
106 | ) | |
107 | parser.add_argument("-v", "--verbose", action="store_true", help="be verbose") | |
108 | parser.add_argument("--check", action="store_true", help="check runable") | |
109 | parser.add_argument("actions", nargs="*", help="GETCAP|GET,xpath") | |
110 | args = parser.parse_args(*args) | |
111 | ||
112 | level = logging.DEBUG if args.verbose else logging.INFO | |
113 | logging.basicConfig( | |
114 | level=level, | |
115 | format="%(asctime)s %(levelname)s: GRPC-CLI-CLIENT: %(name)s %(message)s", | |
116 | ) | |
117 | ||
118 | if args.check: | |
119 | sys.exit(0) | |
120 | ||
121 | c = GRPCClient(args.server, args.port) | |
122 | ||
123 | for action in next_action(args.actions): | |
124 | action = action.casefold() | |
125 | logging.info("GOT ACTION: %s", action) | |
126 | if action == "getcap": | |
127 | caps = c.get_capabilities() | |
128 | print("Capabilities:", caps) | |
129 | elif action.startswith("get,"): | |
130 | # Print Interface State and Config | |
131 | _, xpath = action.split(",", 1) | |
132 | print("Get XPath: ", xpath) | |
133 | xml = c.get(xpath) | |
134 | print("{}: {}".format(xpath, xml)) | |
135 | # for _ in range(0, 1): | |
136 | ||
137 | ||
138 | if __name__ == "__main__": | |
139 | main() |