Configure gNOI Services
SUMMARY Configure the remote network management system as a gRPC client that can execute gNOI operations on network devices.
The gRPC Network Operations Interface (gNOI) uses the gRPC Remote Procedure Call (gRPC) framework to perform operations on a network device. The network management system must have the gRPC stack installed.
OpenConfig defines proto definition files for gNOI services. Proto definition files define the operations (RPCs) and the data structures (messages) for a given service. The definitions are language agnostic. gRPC supports using many different languages to execute service operations. You must compile the proto definition files for your language of choice. You then create applications that use the objects (classes, functions, methods, etc) in the compiled files to connect to the gRPC server on the network device and execute the desired operations.
For information about using gRPC with the different supported languages, consult the gRPC documentation. The following sections provide sample commands for setting up a gRPC client and downloading and compiling the gNOI proto definition files for Python. You must use the commands that are appropriate for your operating system, environment, and gRPC language of choice.
Before you configure the gRPC client, configure the gRPC server as defined in Configure gRPC Services.
Set up the gRPC Client
gNOI uses the gRPC framework to perform operations on a network device. gRPC supports using many different languages. Before you can perform gNOI operations using your language of choice, you must install the gRPC stack on the network management system.
For example, to install the gRPC stack for Python on a network management system
running Ubuntu 20.04 LTS (use sudo
where appropriate):
Compile the Proto Definiton Files
gRPC supports using many languages. In order to perform gRPC
operations on network devices, you must compile the respective
proto definition files for your language of choice. OpenConfig provides the
necessary proto definition files in the OpenConfig GitHub repository. You use the protocol buffer compiler
(protoc
or equivalent application) to compile the
.proto
files.
For this setup, we execute a script that copies all the desired
.proto
files into a directory, updates the files to use
relative import statements, and then compiles the files.
To download and compile the gNOI proto definition files for Python:
Create gNOI Applications
After you compile the proto definition files, you create applications that use the objects in the compiled files. The applications connect to the gRPC server on the network device and perform the desired operations. This section provides two sample Python modules, which are described in their respective sections.
grpc_channel.py
The grpc_channel.py
Python module provides sample functions that
create a gRPC channel using the arguments provided for the selected method of
authentication, server-only or mutual.
import grpc from os.path import isfile def grpc_authenticate_channel_mutual(server, port, root_ca_cert="", client_key="", client_cert=""): if not isfile(root_ca_cert): raise Exception("Error: root_ca_cert file does not exist") if (client_key == "") or (not isfile(client_key)): raise Exception( "Error: client_key option is missing or target file does not exist") elif (client_cert == "") or (not isfile(client_cert)): raise Exception( "Error: client_cert option is empty or target file does not exist") print("Creating channel") creds = grpc.ssl_channel_credentials(open(root_ca_cert, 'rb').read(), open(client_key, 'rb').read(), open(client_cert, 'rb').read()) channel = grpc.secure_channel('%s:%s' % (server, port), creds) return channel def grpc_authenticate_channel_server_only(server, port, root_ca_cert=""): if isfile(root_ca_cert): print("Creating channel") creds = grpc.ssl_channel_credentials(open(root_ca_cert, 'rb').read(), None, None) channel = grpc.secure_channel('%s:%s' % (server, port), creds) return channel else: raise Exception("root_ca_cert file does not exist")
gnoi_connect_cert_auth_mutual.py
The gnoi_connect_cert_auth_mutual.py
Python application
establishes a gRPC channel with the given gRPC server and executes a simple gNOI
System
service operation. The user provides the necessary
connection and mutual authentication information as input to the application.
The application invokes the appropriate function in the
grpc_channel.py
module to establish the gRPC channel
between the client and the server. If the application successfully establishes a
gRPC channel, it then executes a simple system service RPC to retrieve the time
from the network device.
"""gRPC gNOI Time request utility.""" from __future__ import print_function import argparse import logging from getpass import getpass import system_pb2 import system_pb2_grpc from grpc_channel import grpc_authenticate_channel_mutual def get_args(parser): parser.add_argument('--server', dest='server', type=str, default='localhost', help='Server IP or name. Default is localhost') parser.add_argument('--port', dest='port', nargs='?', type=int, default=32767, help='The server port. Default is 32767') parser.add_argument('--client_key', dest='client_key', type=str, default='', help='Full path of the client private key. Default ""') parser.add_argument('--client_cert', dest='client_cert', type=str, default='', help='Full path of the client certificate. Default ""') parser.add_argument('--root_ca_cert', dest='root_ca_cert', required=True, type=str, help='Full path of the Root CA certificate.') parser.add_argument('--user_id', dest='user_id', required=True, type=str, help='User ID for RPC call credentials.') args = parser.parse_args() return args def send_rpc(channel, metadata): stub = system_pb2_grpc.SystemStub(channel) print("Executing GNOI::System::Time RPC") req = system_pb2.TimeRequest() try: response = stub.Time(request=req, metadata=metadata, timeout=60) except Exception as e: logging.error('Error executing RPC: %s', e) print(e) else: logging.info('Received message: %s', response) return response def main(): parser = argparse.ArgumentParser() args = get_args(parser) grpc_server_password = getpass("gRPC server password for executing RPCs: ") metadata = [('username', args.user_id), ('password', grpc_server_password)] try: # Establish grpc channel to network device channel = grpc_authenticate_channel_mutual( args.server, args.port, args.root_ca_cert, args.client_key, args.client_cert) response = send_rpc(channel, metadata) print("Response received: time since last epoch in nanoseconds is ", str(response)) except Exception as e: logging.error('Received error: %s', e) print(e) if __name__ == '__main__': logging.basicConfig(filename='gnoi-testing.log', format='%(asctime)s %(levelname)-8s %(message)s', level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S') main()
Execute the Application
After you create applications to perform gNOI service operations, you execute the applications and provide any necessary arguments. The following example uses the scripts provided in the previous section to connect to the gRPC server on the network device and request the time. The gRPC server is configured to require and verify the client's certificate.
-
For mutual authentication, the client provides their own key and X.509 public key certificate in PEM format in addition to the server's IP address, gRPC port, and root CA certificate. The client also provides the credentials for RPC calls: the
user_id
argument supplies the username, and the application prompts for the user password.lab@gnoi-client:~/src/proto$ python3 gnoi_connect_cert_auth_mutual.py --server 10.53.52.169 --port 32767 --root_ca_cert /etc/pki/certs/serverRootCA.crt --client_key /home/lab/certs/client.key --client_cert /home/lab/certs/client.crt --user_id gnoi-user gRPC server password for executing RPCs: Creating channel Executing GNOI::System::Time RPC Response received: time since last epoch in nanoseconds is time: 1650061065769701762