gNOI 文件服务
总结 使用 gNOI File
服务管理网络设备上的文件。
使用 File
服务 RPC 传输和删除文件或检索有关文件的信息。proto 定义文件位于 https://github.com/openconfig/gnoi/blob/master/file/file.proto。
支持的 RPC
版本中引入的 | RPC | 说明 |
---|---|---|
Get() |
从目标读取和流传输文件的内容。 该文件由连续消息流传输,每条消息包含多达 64KB 的数据。在关闭包含已发送数据的散列流之前发送最后一条消息。如果文件不存在或读取文件时出错,操作将返回错误。 |
Junos OS Evolved 22.2R1 |
Put() |
将数据流式传输到目标上的文件。 该文件以顺序消息发送,每条消息包含多达 64KB 的数据。必须发送包含数据散列的最终消息。 如果位置不存在或写入数据时出错,则操作将返回错误。如果未收到任何校验和,目标将移除部分传输的文件。故障不会改变任何同名现有文件。 |
Junos OS Evolved 22.2R1 |
Remove() |
从目标中移除指定的文件。如果文件不存在、文件路径解析到某个目录,或者删除操作遇到错误,则操作将返回错误。 |
Junos OS Evolved 22.2R1 |
Stat() |
返回有关目标设备上的文件的元数据。如果文件不存在,或者访问元数据时出错,则操作将返回错误。 |
Junos OS Evolved 22.2R1 |
网络设备配置
开始之前:
- 按照配置 gRPC 服务中的说明,在网络设备上 配置 gRPC 服务。
- 按照配置 gNOI 服务中的说明,配置网络管理系统以支持 gNOI 操作。
示例:获取文件
此示例提供了一个简单的 Python 应用程序, gnoi_file_get.py
用于将文件从目标设备下载到本地网络管理系统。
应用程序会导入模块grpc_channel
以建立通道。配置 gNOI 服务中介绍了该grpc_channel
模块。应用程序参数存储在文件中args_file_get.txt
。此处显示应用程序和参数文件。
gnoi_file_get.py
"""gNOI Get File utility.""" from __future__ import print_function import argparse import hashlib import logging from getpass import getpass import file_pb2 import file_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=50051, help='The server port. Default is 50051') 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.') parser.add_argument('--dest_file', dest='dest_file', type=str, default='', help='Full path for destination file. Default ""') parser.add_argument('--source_file', dest='source_file', type=str, default='', help='Full path of source file to retrieve. Default ""') args = parser.parse_args() return args def send_rpc(channel, metadata, args): stub = file_pb2_grpc.FileStub(channel) print("Executing GNOI::File::Get") # Prepare hash generator gen_hash = hashlib.sha256() # Get File req = file_pb2.GetRequest() req.remote_file = args.source_file hashvalue = None hm = None count = 1 with open(args.dest_file, "wb") as file: # Read data in 64 KB chunks and calculate checksum and data messages print("Retrieving file") try: for msg in stub.Get(req, metadata=metadata, timeout=120): if msg.WhichOneof('response') == "contents": count = count + 1 file.write(msg.contents) gen_hash.update(msg.contents) else: hashvalue = msg.hash.hash hm = msg.hash.method print("File transfer complete: ", args.dest_file) except Exception as e: logging.error("Get() operation error. %s", e) print(e) else: file.close() ehashvalue = gen_hash.hexdigest().encode() if (ehashvalue != hashvalue): raise ValueError( 'Hash value mismatch. Expected "%s", got "%s"' % (ehashvalue, hashvalue)) if (hm != 1): raise ValueError( 'Hash method mismatch. Expected "1", got "%s"' % (hm)) logging.info("Downloaded file: %s", args.dest_file) def main(): parser = argparse.ArgumentParser(fromfile_prefix_chars='@') 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) send_rpc(channel, metadata, args) 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()
args_file_get.txt
--server=10.53.52.169 --port=50051 --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 --source_file=/var/log/messages --dest_file=downloads/10.53.52.169-messages
执行应用程序
客户端执行应用程序时,会将指定文件从目标设备传输到本地设备。
lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_file_get.py @args_file_get.txt gRPC server password for executing RPCs: Creating channel Executing GNOI::File::Get Retrieving file File transfer complete: downloads/10.53.52.169-messages
示例:放置文件
此示例提供了一个简单的 Python 应用程序, gnoi_file_put.py
用于将文件从本地网络管理系统上传到目标设备。
应用程序会导入模块grpc_channel
以建立通道。配置 gNOI 服务中介绍了该grpc_channel
模块。应用程序参数存储在文件中args_file_put.txt
。此处显示应用程序和参数文件。
gnoi_file_put.py
"""gNOI Put File utility.""" from __future__ import print_function import argparse import hashlib import logging import sys from functools import partial from getpass import getpass import file_pb2 import file_pb2_grpc from grpc_channel import grpc_authenticate_channel_mutual MAX_BYTES = 65536 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=50051, help='The server port. Default is 50051') 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.') parser.add_argument('--dest_file', dest='dest_file', type=str, default='', help='Full path for destination file. Default ""') parser.add_argument('--dest_file_mode', dest='dest_file_mode', type=int, default=600, help='Destination file mode (file permissions in octal). Default 600') parser.add_argument('--hash_method', dest='hash_method', type=str, default='unspecified', help='Hash method. Valid values are md5, sha256, sha512, or unspecified. Default: unspecified') parser.add_argument('--source_file', dest='source_file', type=str, default='', help='Full path of source file to transfer. Default ""') args = parser.parse_args() return args def send_rpc(channel, metadata, args): stub = file_pb2_grpc.FileStub(channel) print("Executing GNOI::File::Put") # Prepare hash generator if args.hash_method == "sha256": gen_hash = hashlib.sha256() hm = 1 elif args.hash_method == "sha512": gen_hash = hashlib.sha512() hm = 2 elif args.hash_method == "md5": gen_hash = hashlib.md5() hm = 3 else: print("Unsupported hash method:", args.hash_method) sys.exit(1) # Put File req = file_pb2.PutRequest() req.open.remote_file = args.dest_file req.open.permissions = args.dest_file_mode it = [] it.append(req) # Read source file and add to request with open(args.source_file, "rb") as file: # Read data in 64 KB chunks and calculate checksum and data messages for data in iter(partial(file.read, MAX_BYTES), b''): req = file_pb2.PutRequest() req.contents = data it.append(req) gen_hash.update(data) # Checksum message req = file_pb2.PutRequest() req.hash.hash = gen_hash.hexdigest().encode() req.hash.method = hm it.append(req) # Send PutRequest try: print("Sending file.") response = stub.Put(iter(it), metadata=metadata, timeout=120) except Exception as e: logging.error("Error uploading source file %s to %s. Error: %s", args.source_file, args.dest_file, e) print(e) else: print("File transfer complete: ", args.dest_file) logging.info("Uploaded file: %s", args.dest_file) def main(): parser = argparse.ArgumentParser(fromfile_prefix_chars='@') 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) send_rpc(channel, metadata, args) 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()
args_file_put.txt
--server=10.53.52.169 --port=50051 --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 --source_file=scripts/op/ospf-summary.slax --dest_file=/var/db/scripts/op/ospf-summary.slax --dest_file_mode=644 --hash_method=sha256
执行应用程序
客户端执行应用程序时,会将指定文件从本地设备传输到目标设备,并根据该值设置文件权限 dest_file_mode
。
lab@gnoi-client:~/src/gnoi/proto$ python3 gnoi_file_put.py @args_file_put.txt gRPC server password for executing RPCs: Creating channel Executing GNOI::File::Put Sending file. File transfer complete: /var/db/scripts/op/ospf-summary.slax