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