This guide explains how to consume the NDK service when developers write the agents using Python1.
Note
This guide provides code snippets for several operations that a typical agent needs to perform according to the NDK Service Operations Flow chapter.
Where applicable, the chapters on this page will refer to the NDK Architecture section to provide more context on the operations.
In addition to the publicly available protobuf files, which define the NDK Service, Nokia also provides generated Python bindings for data access classes of NDK the nokia/srlinux-ndk-py repo. The generated module enables developers of NDK agents to immediately start writing NDK applications without the need to generate the Python package themselves.
Establish gRPC channel with NDK manager and instantiate an NDK client#
Once the gRPC channel is setup, we need to instantiate a client (often called stub) to perform RPCs. The sdk_common_pb2_grpc.SdkMgrServiceStub method returns a SdkMgrService object
Agent must be first registered with SR Linux by calling the AgentRegister method available on the returned SdkMgrService interface. The initial agent state is created during the registration process.
During registration, SR Linux will be expecting a list of tuples with the agent_name item and value of the agent's name as the other item of the tuple. The agent name is defined in the agent's YAML file.
The AgentRegister method takes two named arguments request and metadata. The request argument takes a AgentRegistrationRequest object and the metadata argument uses the previously defined metadata.
fromndk.sdk_service_pb2importAgentRegistrationRequestfromndk.sdk_common_pb2importSdkMgrStatusregister_request=AgentRegistrationRequest()register_request.agent_liveliness=keepalive_interval# Optionalresponse=sdk_mgr_client.AgentRegister(request=register_request,metadata=metadata)ifresponse.status==SdkMgrStatus.kSdkMgrSuccess:# Agent has been registered successfullypasselse:# Agent registration failed error string available as response.error_strpass
The AgentRegister method returns a AgentRegistrationResponse object containing the status of the request as a SdkMgrStatus object, error message (if request failed) as a string and the app id as a integer.
A subscription stream needs to be created first before any of the subscription types can be added. SdkMgrService first creates the subscription stream by executing NotificationRegister method with a NotificationRegisterRequest only field op set to a value of NotificationRegisterRequest.Create. This effectively creates a stream which is identified with a stream_id returned inside the NotificationRegisterResponse.
stream_id must be associated when subscribing/unsubscribing to certain types of router notifications.
fromndk.sdk_service_pb2importNotificationRegisterRequestrequest=NotificationRegisterRequest(op=NotificationRegisterRequest.Create)response=sdk_mgr_client.NotificationRegister(request=request,metadata=metadata)ifresponse.status==sdk_status.kSdkMgrSuccess:# Notification Register successfulstream_id=response.stream_idpasselse:# Notification Register failed, error string available as response.error_strpass
Once the stream_id is acquired, a client can register notifications of a particular type to be delivered over that stream.
Different types of notifications types can be subscribed to by calling the same NotificationRegister method with a NotificationRegisterRequest having op field set to NotificationRegisterRequest.AddSubscription and the correct name argument for the configuration type being added (NotificationRegisterRequest fields for the named arguments).
In the example below we would like to receive notifications from the Config service, hence we specify the config argument with a ConfigSubscriptionRequest object.
fromndk.config_service_pb2importConfigSubscriptionRequestrequest=NotificationRegisterRequest(stream_id=stream_id,op=NotificationRegisterRequest.AddSubscription,config=ConfigSubscriptionRequest(),)response=sdk_mgr_client.NotificationRegister(request=request,metadata=metadata)ifresponse.status==sdk_status.kSdkMgrSuccess:# Successful registrationpasselse:# Registration failed, error string available as response.error_strpass
Info
It is possible to register for multiple different types of notifications at the same time by passing different subscription requests to the same NotificationRegisterRequest.
Actual streaming of notifications is a task for another service - SdkNotificationService. This service requires developers to create its own client, which is done with SdkNotificationServiceStub function.
The returned SdkNotificationService has a single method NotificationStream that is used to start streaming notifications.
NotificationsStream is a server-side streaming RPC which means that SR Linux (server) will send back multiple event notification responses after getting the agent's (client) request.
The stream_id that was returned in the Create subscription stream is used to tell the server to included the notifications that were created between when the SdkNotificationService was created and when its NotificationsStream method is invoked.
Handling notifications starts with reading the incoming notification messages and detecting which type this notification is exactly. When the type is known the client reads the fields of a certain notification. Here is a method that checks for all notification types and delegates handling to helper methods.
fromndk.sdk_service_pb2importNotificationdefhandle_notification(notification:Notification)->None:# Field names are available on the Notification documentation pageifnotification.HasField("config"):handle_ConfigNotification(notification.config)ifnotification.HasField("intf"):handle_InterfaceNotification(notification.intf)ifnotification.HasField("nw_inst"):handle_NetworkInstanceNotification(notification.nw_inst)ifnotification.HasField("lldp_neighbor"):handle_LldpNeighborNotification(notification.lldp_neighbor)ifnotification.HasField("bfd_session"):handle_BfdSessionNotification(notification.bfd_session)ifnotification.HasField("route"):handle_IpRouteNotification(notification.route)ifnotification.HasField("appid"):handle_AppIdentNotification(notification.appid)ifnotification.HasField("nhg"):handle_NextHopGroupNotification(notification.nhg)
A Notification object has a HasField() method that allows to check if the field contains a notification. Once it is confirmed that XXXXX field is present we can access it as attribute of the notification (notification.XXXXX) this will return a notification of the associated type (for example accessing notification.config returns a ConfigNotification).
Note
It is essential to verify if the notification has a given field with the HasField() method as accessing an invalid field will give an empty notification. The value will not be None and the accessing the invalid field will not throw an Exception.
Agent needs to handle SIGTERM signal that is sent when a user invokes stop command via SR Linux CLI. The following is the required steps to cleanly stop the agent:
Remove any agent's state if it was set using TelemetryDelete method of a Telemetry client.
To debug an agent, the developers can analyze the log messages that the agent produced. If the agent's logging facility used stdout/stderr to write log messages, then these messages will be found at /var/log/srlinux/stdout/ directory.
The default SR Linux debug messages are found in the messages directory /var/log/srlinux/buffer/messages; check them when something went wrong within the SR Linux system (agent registration failed, IDB server warning messages, etc.).