gNOI 文件服务
使用 gNOI File 服务管理网络设备上的文件。
使用 File 服务 RPC 传输和删除文件或检索有关文件的信息。原型定义文件位于 https://github.com/openconfig/gnoi/blob/master/file/file.proto。
支持的 RPC
| RPC | 描述 | 在版本中引入 |
|---|---|---|
Get() |
从目标读取和流式传输文件的内容。 该文件由顺序消息流式传输,每条消息最多包含 64KB 的数据。在关闭包含发送数据哈希的流之前,会发送最后一条消息。如果文件不存在或读取文件时出错,则该操作将返回错误。 |
Junos OS 演化版 22.2R1 |
Put() |
将数据流式传输到目标上的文件。 该文件以顺序消息形式发送,每条消息最多包含 64KB 的数据。必须发送包含数据哈希的最终消息。 如果位置不存在或写入数据时出错,则该操作将返回错误。如果未收到校验和,目标将移除部分传输的文件。失败不会更改任何同名的现有文件。 |
Junos OS 演化版 22.2R1 |
Remove() |
从目标中删除指定的文件。如果文件不存在、文件路径解析为目录或删除操作遇到错误,则该操作将返回错误。 |
Junos OS 演化版 22.2R1 |
Stat() |
返回有关目标设备上文件的元数据。如果文件不存在或访问元数据时出错,则该操作将返回错误。 |
Junos OS 演化版 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=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.') 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=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 --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=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.') 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=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 --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