Skip to content

[sonic-py-common] Add gRPC framework with gNOI client#26473

Open
sigabrtv1-ui wants to merge 4 commits into
sonic-net:masterfrom
sigabrtv1-ui:feature/gnoi-py-common
Open

[sonic-py-common] Add gRPC framework with gNOI client#26473
sigabrtv1-ui wants to merge 4 commits into
sonic-net:masterfrom
sigabrtv1-ui:feature/gnoi-py-common

Conversation

@sigabrtv1-ui
Copy link
Copy Markdown

@sigabrtv1-ui sigabrtv1-ui commented Mar 30, 2026

What I did

Added sonic_py_common.gnoi — a reusable gNOI gRPC client framework that any SONiC Python component can use.

Why I did it

Today, gnoi_shutdown_daemon in sonic-host-services shells out to docker exec gnmi gnoi_client which has:

  • Broken completion detection — string-matching "reboot complete" against JSON output that never contains it
  • Suppressed errors — Go panics discarded via suppress_stderr=True
  • Unnecessary container dependency — NPU gnmi container as intermediary to reach DPU
  • Plus this is a CLI disguise as an API which creates subprocess overhead, brittle stdout/stderr parsing and error handling, and make it difficult to maintain.

Other components (pmon, sonic-utilities) may also need gNOI access. A shared framework in sonic-py-common avoids duplicating gRPC boilerplate across repos.

How I did it

sonic_py_common/gnoi/:

  • GnoiClient — thin gRPC channel manager with service stubs as properties (client.system, extensible for client.healthz, client.cert, etc.)
  • Vendored proto stubssystem_pb2, types_pb2, common_pb2 generated from openconfig/gnoi. Vendored because sonic-py-common has no proto compilation infra and gNOI System proto is stable.
  • 9 unit tests covering channel lifecycle, service stub access, RPC calls, error propagation

setup.py: added grpcio/protobuf to deps and sonic_py_common.gnoi to packages.

Usage

from sonic_py_common.gnoi import GnoiClient
from sonic_py_common.gnoi import system_pb2

with GnoiClient('10.0.0.1:8080') as client:
    req = system_pb2.RebootRequest(method=system_pb2.HALT, message='graceful shutdown')
    client.system.Reboot(req, timeout=60)

    status = client.system.RebootStatus(system_pb2.RebootStatusRequest(), timeout=10)
    if not status.active:
        print('Reboot complete')

How to verify

cd src/sonic-py-common
python3 -m pytest tests/test_gnoi_client.py -v

Dependencies

  • grpcio and protobuf — already used by other SONiC components

Related

@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run Azure.sonic-buildimage

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Add sonic_py_common.grpc — a reusable gRPC framework for SONiC Python
components, starting with gNOI support.

Structure:
  sonic_py_common/
    grpc/                    # gRPC framework root
      __init__.py            # future: gnmi, gribi sub-packages
      gnoi/                  # gNOI services
        __init__.py
        client.py            # GnoiClient - channel manager + service stubs
        system_pb2.py        # vendored proto stubs (openconfig/gnoi)
        system_pb2_grpc.py
        types_pb2.py
        types_pb2_grpc.py
        common_pb2.py
        common_pb2_grpc.py

GnoiClient is service-agnostic: stubs accessed via properties
(client.system, with scaffolding for healthz/cert/file/os).
The grpc/ namespace leaves room for gnmi/ and gribi/ sub-packages.

Dependencies: grpcio, protobuf (already used by other SONiC components).

Signed-off-by: sigabrtv1-ui <sig.abrt.v1@gmail.com>

Signed-off-by: Dawei Huang <daweihuang@microsoft.com>
@sigabrtv1-ui sigabrtv1-ui force-pushed the feature/gnoi-py-common branch from 2dc389d to 2585cd8 Compare March 30, 2026 16:56
@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run Azure.sonic-buildimage

@sigabrtv1-ui sigabrtv1-ui changed the title [sonic-py-common] Add gNOI Python gRPC client framework [sonic-py-common] Add gRPC framework with gNOI client Mar 30, 2026
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Add sonic_py_common.grpc.gnoi.testing with:
- FakeSystemStub: controllable System service stub with injectable
  responses, side_effects (including sequences for polling scenarios),
  and call history for assertions
- FakeGnoiClient: drop-in replacement for GnoiClient with no real
  gRPC connections, same context manager protocol

Consumers can write tests like:
    fake = FakeGnoiClient()
    fake.system.set_reboot_status(active=False, status=STATUS_SUCCESS)
    with patch('my_module.GnoiClient', return_value=fake):
        assert my_reboot_function() == True
    assert len(fake.system.reboot_calls) == 1

12 new tests for the fake itself.

Signed-off-by: sigabrtv1-ui <sig.abrt.v1@gmail.com>

Signed-off-by: Dawei Huang <daweihuang@microsoft.com>
@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run Azure.sonic-buildimage

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Replace mock-based testing with a real gRPC fake server:

- FakeGnoiServer: starts a real gRPC server on localhost with
  controllable service implementations. Tests use the real GnoiClient
  connecting over a real channel — no mocking of gRPC internals.

- FakeSystemServicer: configurable System service with:
  - set_reboot_response() / set_reboot_status() for single responses
  - set_reboot_status_sequence() for polling scenarios (active→done)
  - Error injection via grpc.StatusCode
  - Call history for assertions (reboot_calls, etc.)
  - reset() to clear state between tests

- Rewrote all client tests to use FakeGnoiServer (no sys.modules mocking)

19 tests, all using real gRPC. Zero mocks.

Signed-off-by: sigabrtv1-ui <sig.abrt.v1@gmail.com>

Signed-off-by: Dawei Huang <daweihuang@microsoft.com>
@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run Azure.sonic-buildimage

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

The generated protobuf stubs were created with protobuf 6.31.1 which
uses 'runtime_version' import not available in the build image's
protobuf 4.25.9. Regenerated using grpcio-tools 1.60.1 + protobuf
4.25.9 for compatibility with the SONiC build environment.

Signed-off-by: Dawei Huang <daweihuang@microsoft.com>
@mssonicbld
Copy link
Copy Markdown
Collaborator

/azp run Azure.sonic-buildimage

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

@qiluo-msft qiluo-msft requested a review from hdwhdw May 11, 2026 20:22
@judyjoseph judyjoseph requested a review from vaibhavhd May 11, 2026 20:26
@judyjoseph
Copy link
Copy Markdown
Contributor

@vaibhavhd can you review this PR

@hdwhdw
Copy link
Copy Markdown
Contributor

hdwhdw commented May 11, 2026

@qiluo-msft that's my bot so someone else should review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants