From 1405cd2e8ee559ec75205b9eed1686bf31c29ba0 Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Wed, 8 Jan 2025 18:30:10 +0000 Subject: [PATCH 1/4] format and naming clean up for gnoi_client.go. --- gnoi_client/gnoi_client.go | 205 +++++++++++++++++++------------------ 1 file changed, 105 insertions(+), 100 deletions(-) diff --git a/gnoi_client/gnoi_client.go b/gnoi_client/gnoi_client.go index 7d480e2b..8a9f7f8e 100644 --- a/gnoi_client/gnoi_client.go +++ b/gnoi_client/gnoi_client.go @@ -1,51 +1,53 @@ package main import ( - "google.golang.org/grpc" - gnoi_system_pb "github.com/openconfig/gnoi/system" + "context" + "encoding/json" + "flag" + "fmt" + "github.com/google/gnxi/utils/credentials" gnoi_file_pb "github.com/openconfig/gnoi/file" + gnoi_system_pb "github.com/openconfig/gnoi/system" spb "github.com/sonic-net/sonic-gnmi/proto/gnoi" spb_jwt "github.com/sonic-net/sonic-gnmi/proto/gnoi/jwt" - "context" + "google.golang.org/grpc" + "google.golang.org/grpc/metadata" "os" "os/signal" - "fmt" - "flag" - "google.golang.org/grpc/metadata" - "github.com/google/gnxi/utils/credentials" - "encoding/json" ) var ( - module = flag.String("module", "System", "gNOI Module") - rpc = flag.String("rpc", "Time", "rpc call in specified module to call") - target = flag.String("target", "localhost:8080", "Address:port of gNOI Server") - args = flag.String("jsonin", "", "RPC Arguments in json format") - jwtToken = flag.String("jwt_token", "", "JWT Token if required") + module = flag.String("module", "System", "gNOI Module") + rpc = flag.String("rpc", "Time", "rpc call in specified module to call") + target = flag.String("target", "localhost:8080", "Address:port of gNOI Server") + args = flag.String("jsonin", "", "RPC Arguments in json format") + jwtToken = flag.String("jwt_token", "", "JWT Token if required") targetName = flag.String("target_name", "hostname.com", "The target name use to verify the hostname returned by TLS handshake") ) + func setUserCreds(ctx context.Context) context.Context { if len(*jwtToken) > 0 { ctx = metadata.AppendToOutgoingContext(ctx, "access_token", *jwtToken) } return ctx } + func main() { flag.Parse() opts := credentials.ClientCredentials(*targetName) - ctx, cancel := context.WithCancel(context.Background()) - go func() { - c := make(chan os.Signal, 1) - signal.Notify(c, os.Interrupt) - <-c - cancel() - }() + ctx, cancel := context.WithCancel(context.Background()) + go func() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt) + <-c + cancel() + }() conn, err := grpc.Dial(*target, opts...) if err != nil { panic(err.Error()) } - + switch *module { case "System": sc := gnoi_system_pb.NewSystemClient(conn) @@ -59,7 +61,7 @@ func main() { case "RebootStatus": systemRebootStatus(sc, ctx) case "KillProcess": - killProcess(sc, ctx) + systemKillProcess(sc, ctx) default: panic("Invalid RPC Name") } @@ -78,25 +80,25 @@ func main() { sonicShowTechSupport(sc, ctx) case "copyConfig": sc := spb.NewSonicServiceClient(conn) - copyConfig(sc, ctx) + sonicCopyConfig(sc, ctx) case "authenticate": sc := spb_jwt.NewSonicJwtServiceClient(conn) - authenticate(sc, ctx) + sonicAuthenticate(sc, ctx) case "imageInstall": sc := spb.NewSonicServiceClient(conn) - imageInstall(sc, ctx) + sonicImageInstall(sc, ctx) case "imageDefault": sc := spb.NewSonicServiceClient(conn) - imageDefault(sc, ctx) + sonicImageDefault(sc, ctx) case "imageRemove": sc := spb.NewSonicServiceClient(conn) - imageRemove(sc, ctx) + sonicImageRemove(sc, ctx) case "refresh": sc := spb_jwt.NewSonicJwtServiceClient(conn) - refresh(sc, ctx) + sonicRefresh(sc, ctx) case "clearNeighbors": sc := spb.NewSonicServiceClient(conn) - clearNeighbors(sc, ctx) + sonicClearNeighbors(sc, ctx) default: panic("Invalid RPC Name") } @@ -106,10 +108,11 @@ func main() { } +// RPC for System Services func systemTime(sc gnoi_system_pb.SystemClient, ctx context.Context) { fmt.Println("System Time") ctx = setUserCreds(ctx) - resp,err := sc.Time(ctx, new(gnoi_system_pb.TimeRequest)) + resp, err := sc.Time(ctx, new(gnoi_system_pb.TimeRequest)) if err != nil { panic(err.Error()) } @@ -120,45 +123,26 @@ func systemTime(sc gnoi_system_pb.SystemClient, ctx context.Context) { fmt.Println(string(respstr)) } -func killProcess(sc gnoi_system_pb.SystemClient, ctx context.Context) { +func systemKillProcess(sc gnoi_system_pb.SystemClient, ctx context.Context) { fmt.Println("Kill Process with optional restart") ctx = setUserCreds(ctx) - req := &gnoi_system_pb.KillProcessRequest {} + req := &gnoi_system_pb.KillProcessRequest{} err := json.Unmarshal([]byte(*args), req) if err != nil { panic(err.Error()) } - _,err = sc.KillProcess(ctx, req) + _, err = sc.KillProcess(ctx, req) if err != nil { panic(err.Error()) } } -func fileStat(fc gnoi_file_pb.FileClient, ctx context.Context) { - fmt.Println("File Stat") - ctx = setUserCreds(ctx) - req := &gnoi_file_pb.StatRequest {} - err := json.Unmarshal([]byte(*args), req) - if err != nil { - panic(err.Error()) - } - resp,err := fc.Stat(ctx, req) - if err != nil { - panic(err.Error()) - } - respstr, err := json.Marshal(resp) - if err != nil { - panic(err.Error()) - } - fmt.Println(string(respstr)) -} - func systemReboot(sc gnoi_system_pb.SystemClient, ctx context.Context) { fmt.Println("System Reboot") ctx = setUserCreds(ctx) - req := &gnoi_system_pb.RebootRequest {} + req := &gnoi_system_pb.RebootRequest{} json.Unmarshal([]byte(*args), req) - _,err := sc.Reboot(ctx, req) + _, err := sc.Reboot(ctx, req) if err != nil { panic(err.Error()) } @@ -167,9 +151,9 @@ func systemReboot(sc gnoi_system_pb.SystemClient, ctx context.Context) { func systemCancelReboot(sc gnoi_system_pb.SystemClient, ctx context.Context) { fmt.Println("System CancelReboot") ctx = setUserCreds(ctx) - req := &gnoi_system_pb.CancelRebootRequest {} + req := &gnoi_system_pb.CancelRebootRequest{} json.Unmarshal([]byte(*args), req) - resp,err := sc.CancelReboot(ctx, req) + resp, err := sc.CancelReboot(ctx, req) if err != nil { panic(err.Error()) } @@ -183,8 +167,8 @@ func systemCancelReboot(sc gnoi_system_pb.SystemClient, ctx context.Context) { func systemRebootStatus(sc gnoi_system_pb.SystemClient, ctx context.Context) { fmt.Println("System RebootStatus") ctx = setUserCreds(ctx) - req := &gnoi_system_pb.RebootStatusRequest {} - resp,err := sc.RebootStatus(ctx, req) + req := &gnoi_system_pb.RebootStatusRequest{} + resp, err := sc.RebootStatus(ctx, req) if err != nil { panic(err.Error()) } @@ -195,18 +179,37 @@ func systemRebootStatus(sc gnoi_system_pb.SystemClient, ctx context.Context) { fmt.Println(string(respstr)) } +// RPC for File Services +func fileStat(fc gnoi_file_pb.FileClient, ctx context.Context) { + fmt.Println("File Stat") + ctx = setUserCreds(ctx) + req := &gnoi_file_pb.StatRequest{} + err := json.Unmarshal([]byte(*args), req) + if err != nil { + panic(err.Error()) + } + resp, err := fc.Stat(ctx, req) + if err != nil { + panic(err.Error()) + } + respstr, err := json.Marshal(resp) + if err != nil { + panic(err.Error()) + } + fmt.Println(string(respstr)) +} + +// RPC for Sonic Services func sonicShowTechSupport(sc spb.SonicServiceClient, ctx context.Context) { fmt.Println("Sonic ShowTechsupport") ctx = setUserCreds(ctx) - req := &spb.TechsupportRequest { - Input: &spb.TechsupportRequest_Input{ - - }, + req := &spb.TechsupportRequest{ + Input: &spb.TechsupportRequest_Input{}, } json.Unmarshal([]byte(*args), req) - - resp,err := sc.ShowTechsupport(ctx, req) + + resp, err := sc.ShowTechsupport(ctx, req) if err != nil { panic(err.Error()) } @@ -217,7 +220,7 @@ func sonicShowTechSupport(sc spb.SonicServiceClient, ctx context.Context) { fmt.Println(string(respstr)) } -func copyConfig(sc spb.SonicServiceClient, ctx context.Context) { +func sonicCopyConfig(sc spb.SonicServiceClient, ctx context.Context) { fmt.Println("Sonic CopyConfig") ctx = setUserCreds(ctx) req := &spb.CopyConfigRequest{ @@ -225,7 +228,7 @@ func copyConfig(sc spb.SonicServiceClient, ctx context.Context) { } json.Unmarshal([]byte(*args), req) - resp,err := sc.CopyConfig(ctx, req) + resp, err := sc.CopyConfig(ctx, req) if err != nil { panic(err.Error()) @@ -236,7 +239,8 @@ func copyConfig(sc spb.SonicServiceClient, ctx context.Context) { } fmt.Println(string(respstr)) } -func imageInstall(sc spb.SonicServiceClient, ctx context.Context) { + +func sonicImageInstall(sc spb.SonicServiceClient, ctx context.Context) { fmt.Println("Sonic ImageInstall") ctx = setUserCreds(ctx) req := &spb.ImageInstallRequest{ @@ -244,7 +248,7 @@ func imageInstall(sc spb.SonicServiceClient, ctx context.Context) { } json.Unmarshal([]byte(*args), req) - resp,err := sc.ImageInstall(ctx, req) + resp, err := sc.ImageInstall(ctx, req) if err != nil { panic(err.Error()) @@ -255,7 +259,8 @@ func imageInstall(sc spb.SonicServiceClient, ctx context.Context) { } fmt.Println(string(respstr)) } -func imageRemove(sc spb.SonicServiceClient, ctx context.Context) { + +func sonicImageRemove(sc spb.SonicServiceClient, ctx context.Context) { fmt.Println("Sonic ImageRemove") ctx = setUserCreds(ctx) req := &spb.ImageRemoveRequest{ @@ -263,7 +268,7 @@ func imageRemove(sc spb.SonicServiceClient, ctx context.Context) { } json.Unmarshal([]byte(*args), req) - resp,err := sc.ImageRemove(ctx, req) + resp, err := sc.ImageRemove(ctx, req) if err != nil { panic(err.Error()) @@ -275,7 +280,7 @@ func imageRemove(sc spb.SonicServiceClient, ctx context.Context) { fmt.Println(string(respstr)) } -func imageDefault(sc spb.SonicServiceClient, ctx context.Context) { +func sonicImageDefault(sc spb.SonicServiceClient, ctx context.Context) { fmt.Println("Sonic ImageDefault") ctx = setUserCreds(ctx) req := &spb.ImageDefaultRequest{ @@ -283,7 +288,7 @@ func imageDefault(sc spb.SonicServiceClient, ctx context.Context) { } json.Unmarshal([]byte(*args), req) - resp,err := sc.ImageDefault(ctx, req) + resp, err := sc.ImageDefault(ctx, req) if err != nil { panic(err.Error()) @@ -295,14 +300,14 @@ func imageDefault(sc spb.SonicServiceClient, ctx context.Context) { fmt.Println(string(respstr)) } -func authenticate(sc spb_jwt.SonicJwtServiceClient, ctx context.Context) { +func sonicAuthenticate(sc spb_jwt.SonicJwtServiceClient, ctx context.Context) { fmt.Println("Sonic Authenticate") ctx = setUserCreds(ctx) - req := &spb_jwt.AuthenticateRequest {} - + req := &spb_jwt.AuthenticateRequest{} + json.Unmarshal([]byte(*args), req) - - resp,err := sc.Authenticate(ctx, req) + + resp, err := sc.Authenticate(ctx, req) if err != nil { panic(err.Error()) } @@ -313,14 +318,14 @@ func authenticate(sc spb_jwt.SonicJwtServiceClient, ctx context.Context) { fmt.Println(string(respstr)) } -func refresh(sc spb_jwt.SonicJwtServiceClient, ctx context.Context) { +func sonicRefresh(sc spb_jwt.SonicJwtServiceClient, ctx context.Context) { fmt.Println("Sonic Refresh") ctx = setUserCreds(ctx) - req := &spb_jwt.RefreshRequest {} - + req := &spb_jwt.RefreshRequest{} + json.Unmarshal([]byte(*args), req) - resp,err := sc.Refresh(ctx, req) + resp, err := sc.Refresh(ctx, req) if err != nil { panic(err.Error()) } @@ -331,22 +336,22 @@ func refresh(sc spb_jwt.SonicJwtServiceClient, ctx context.Context) { fmt.Println(string(respstr)) } -func clearNeighbors(sc spb.SonicServiceClient, ctx context.Context) { - fmt.Println("Sonic ClearNeighbors") - ctx = setUserCreds(ctx) - req := &spb.ClearNeighborsRequest{ - Input: &spb.ClearNeighborsRequest_Input{}, - } - json.Unmarshal([]byte(*args), req) - - resp,err := sc.ClearNeighbors(ctx, req) - - if err != nil { - panic(err.Error()) - } - respstr, err := json.Marshal(resp) - if err != nil { - panic(err.Error()) - } - fmt.Println(string(respstr)) -} \ No newline at end of file +func sonicClearNeighbors(sc spb.SonicServiceClient, ctx context.Context) { + fmt.Println("Sonic ClearNeighbors") + ctx = setUserCreds(ctx) + req := &spb.ClearNeighborsRequest{ + Input: &spb.ClearNeighborsRequest_Input{}, + } + json.Unmarshal([]byte(*args), req) + + resp, err := sc.ClearNeighbors(ctx, req) + + if err != nil { + panic(err.Error()) + } + respstr, err := json.Marshal(resp) + if err != nil { + panic(err.Error()) + } + fmt.Println(string(respstr)) +} From 452d1a6ca77078aad21fcbc78d943c64d46dfd4d Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Fri, 3 Jan 2025 18:55:48 +0000 Subject: [PATCH 2/4] Unit test for System.SetPackaget --- test/test_gnoi_system.py | 29 ++++++++++++++++++++++++ test/utils.py | 49 +++++++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 test/test_gnoi_system.py diff --git a/test/test_gnoi_system.py b/test/test_gnoi_system.py new file mode 100644 index 00000000..f10f9653 --- /dev/null +++ b/test/test_gnoi_system.py @@ -0,0 +1,29 @@ +""" +This module contains unit tests for GNOI system API. +See https://github.com/openconfig/gnoi/blob/main/system/system.proto. +""" +import pytest +from utils import gnmi_dump, gnoi_setpackage + +class TestGNOISystem: + """ + Test GNOI system API. + """ + def test_system_setpackage_from_remote_url_success(self): + """ + Test GNOI system set package success. + """ + SONIC_VS_IMAGE_URL = "https://sonic-build.azurewebsites.net/api/sonic/artifacts?branchName=master&platform=vs&target=target/sonic-vs.bin" + + ret, download_start = gnmi_dump("DBUS image download") + ret, install_start = gnmi_dump("DBUS image install") + assert ret == 0, "Fail to read counter" + + ret, msg = gnoi_setpackage() + assert ret == 0, msg + + ret, download_end = gnmi_dump("DBUS image download") + ret, install_end = gnmi_dump("DBUS image install") + assert ret == 0, "Fail to read counter" + assert download_end == download_start + 1, "DBUS image download is not invoked" + assert install_end == install_start + 1, "DBUS image install is not invoked" \ No newline at end of file diff --git a/test/utils.py b/test/utils.py index ffb9fd4d..5f3c9a82 100644 --- a/test/utils.py +++ b/test/utils.py @@ -1,6 +1,7 @@ import os import re import subprocess +import json def run_cmd(cmd): res = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -283,14 +284,6 @@ def gnoi_traceroute(dst): ret, msg = run_cmd(cmd) return ret, msg -def gnoi_setpackage(): - path = os.getcwd() - cmd = path + '/build/bin/gnoi_client ' - cmd += '-insecure -target 127.0.0.1:8080 ' - cmd += '-rpc SetPackage ' - ret, msg = run_cmd(cmd) - return ret, msg - def gnoi_switchcontrolprocessor(): path = os.getcwd() cmd = path + '/build/bin/gnoi_client ' @@ -315,4 +308,44 @@ def gnoi_refresh_with_jwt(token): cmd += '-jwt_token ' + token + ' ' cmd += '-module Sonic -rpc refresh ' ret, msg = run_cmd(cmd) + return ret, msg + +def create_gnoi_client_command(module, rpc, **kwargs): + """ + Constructs a command string to execute the gNOI client with specified parameters. + + Args: + module (str): The gNOI module (System, Sonic, Containerz) to be used. + rpc (str): The RPC method to be invoked. + **kwargs: Additional keyword arguments to be passed as JSON input to the gNOI client. + + Returns: + str: The constructed command string to execute the gNOI client. + """ + path = os.getcwd() + cmd = [ + path + '/build/bin/gnoi_client', + '-insecure', + '-target 127.0.0.1:8080', + '-module %s' % module, + '-rpc %s' % rpc + ] + if kwargs: + jsonin = json.dumps(kwargs) + cmd.append('-jsonin \'%s\'' % jsonin) + return ' '.join(cmd) + +def gnoi_setpackage(): + """ + Invoke gNOI System.SetPackage RPC to download and install a package from a remote URL. + """ + cmd = create_gnoi_client_command( + 'System', + 'SetPackage', + filename='/tmp/sonic-vs.bin', + version='1.0', + activate='false', + url='https://sonic-build.azurewebsites.net/api/sonic/artifacts?branchName=master&platform=vs&target=target/sonic-vs.bin' + ) + ret, msg = run_cmd(cmd) return ret, msg \ No newline at end of file From 93d08e8567c29be2e000b7427f653695917dc123 Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Thu, 9 Jan 2025 00:32:14 +0000 Subject: [PATCH 3/4] initial client code for setpackage. --- gnoi_client/gnoi_client.go | 43 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/gnoi_client/gnoi_client.go b/gnoi_client/gnoi_client.go index 8a9f7f8e..3df71481 100644 --- a/gnoi_client/gnoi_client.go +++ b/gnoi_client/gnoi_client.go @@ -179,6 +179,49 @@ func systemRebootStatus(sc gnoi_system_pb.SystemClient, ctx context.Context) { fmt.Println(string(respstr)) } +func systemSetPackage(sc gnoi_system_pb.SystemClient, ctx context.Context) { + fmt.Println("System SetPackage") + ctx = setUserCreds(ctx) + stream, err := sc.SetPackage(ctx) + if err != nil { + panic(err.Error()) + } + // SetPackage uses a streaming API. The input parameter jsonin is used to specify + // the first message, which is the package metadata, as well as the last message, + // which contains the hash. The package itself is not streamed. + init_req := &gnoi_system_pb.SetPackageRequest{ + Request: &gnoi_system_pb.SetPackageRequest_Package{}, + } + err = json.Unmarshal([]byte(*args), init_req) + if err != nil { + panic(err.Error()) + } + err = stream.Send(init_req) + if err != nil { + panic(err.Error()) + } + // For this version of the client and server, the server will download the package. + // Skip directly to hash. + // TODO: Add support for streaming the package. + final_req := &gnoi_system_pb.SetPackageRequest{ + Request: &gnoi_system_pb.SetPackageRequest_Hash{}, + } + err = json.Unmarshal([]byte(*args), final_req) + if err != nil { + panic(err.Error()) + } + err = stream.Send(final_req) + if err != nil { + panic(err.Error()) + } + resp, err := stream.CloseAndRecv() + if err != nil { + panic(err.Error()) + } + // SetPackageResponse is always empty. + fmt.Println(resp) +} + // RPC for File Services func fileStat(fc gnoi_file_pb.FileClient, ctx context.Context) { fmt.Println("File Stat") From 1c9ebcb8eaaf701a5be00de3715758c22e9f13f3 Mon Sep 17 00:00:00 2001 From: Dawei Huang Date: Thu, 9 Jan 2025 18:09:38 +0000 Subject: [PATCH 4/4] add placeholder server implementation for setpackage. --- gnmi_server/gnoi.go | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/gnmi_server/gnoi.go b/gnmi_server/gnoi.go index 4c3aad6c..a59f0779 100644 --- a/gnmi_server/gnoi.go +++ b/gnmi_server/gnoi.go @@ -228,6 +228,17 @@ func (srv *SystemServer) Ping(req *gnoi_system_pb.PingRequest, rs gnoi_system_pb log.V(1).Info("gNOI: Ping") return status.Errorf(codes.Unimplemented, "") } + +func (src *SystemServer) SetPackage(rs gnoi_system_pb.System_SetPackageServer) error { + ctx := rs.Context() + _, err := authenticate(srv.config, ctx) + if err != nil { + return err + } + log.V(1).Info("gNOI: SetPackage") + return status.Errorf(codes.Unimplemented, "") +} + func (srv *SystemServer) Traceroute(req *gnoi_system_pb.TracerouteRequest, rs gnoi_system_pb.System_TracerouteServer) error { ctx := rs.Context() _, err := authenticate(srv.config, ctx) @@ -286,7 +297,7 @@ func (srv *Server) Authenticate(ctx context.Context, req *spb_jwt.AuthenticateRe return &spb_jwt.AuthenticateResponse{Token: tokenResp(req.Username, roles)}, nil } } - + } return nil, status.Errorf(codes.PermissionDenied, "Invalid Username or Password") @@ -314,7 +325,7 @@ func (srv *Server) Refresh(ctx context.Context, req *spb_jwt.RefreshRequest) (*s if time.Unix(claims.ExpiresAt, 0).Sub(time.Now()) > JwtRefreshInt { return nil, status.Errorf(codes.InvalidArgument, "Invalid JWT Token") } - + return &spb_jwt.RefreshResponse{Token: tokenResp(claims.Username, claims.Roles)}, nil } @@ -357,13 +368,13 @@ func (srv *Server) CopyConfig(ctx context.Context, req *spb.CopyConfigRequest) ( return nil, err } log.V(1).Info("gNOI: Sonic CopyConfig") - + resp := &spb.CopyConfigResponse{ Output: &spb.SonicOutput { }, } - + reqstr, err := json.Marshal(req) if err != nil { return nil, status.Error(codes.Unknown, err.Error()) @@ -373,12 +384,12 @@ func (srv *Server) CopyConfig(ctx context.Context, req *spb.CopyConfigRequest) ( if err != nil { return nil, status.Error(codes.Unknown, err.Error()) } - + err = json.Unmarshal(jsresp, resp) if err != nil { return nil, status.Error(codes.Unknown, err.Error()) } - + return resp, nil } @@ -388,7 +399,7 @@ func (srv *Server) ShowTechsupport(ctx context.Context, req *spb.TechsupportRequ return nil, err } log.V(1).Info("gNOI: Sonic ShowTechsupport") - + resp := &spb.TechsupportResponse{ Output: &spb.TechsupportResponse_Output { @@ -404,13 +415,13 @@ func (srv *Server) ShowTechsupport(ctx context.Context, req *spb.TechsupportRequ if err != nil { return nil, status.Error(codes.Unknown, err.Error()) } - + err = json.Unmarshal(jsresp, resp) if err != nil { return nil, status.Error(codes.Unknown, err.Error()) } - - + + return resp, nil } @@ -420,7 +431,7 @@ func (srv *Server) ImageInstall(ctx context.Context, req *spb.ImageInstallReques return nil, err } log.V(1).Info("gNOI: Sonic ImageInstall") - + resp := &spb.ImageInstallResponse{ Output: &spb.SonicOutput { @@ -436,13 +447,13 @@ func (srv *Server) ImageInstall(ctx context.Context, req *spb.ImageInstallReques if err != nil { return nil, status.Error(codes.Unknown, err.Error()) } - + err = json.Unmarshal(jsresp, resp) if err != nil { return nil, status.Error(codes.Unknown, err.Error()) } - + return resp, nil } @@ -452,7 +463,7 @@ func (srv *Server) ImageRemove(ctx context.Context, req *spb.ImageRemoveRequest) return nil, err } log.V(1).Info("gNOI: Sonic ImageRemove") - + resp := &spb.ImageRemoveResponse{ Output: &spb.SonicOutput { @@ -468,7 +479,7 @@ func (srv *Server) ImageRemove(ctx context.Context, req *spb.ImageRemoveRequest) if err != nil { return nil, status.Error(codes.Unknown, err.Error()) } - + err = json.Unmarshal(jsresp, resp) if err != nil { return nil, status.Error(codes.Unknown, err.Error()) @@ -482,7 +493,7 @@ func (srv *Server) ImageDefault(ctx context.Context, req *spb.ImageDefaultReques return nil, err } log.V(1).Info("gNOI: Sonic ImageDefault") - + resp := &spb.ImageDefaultResponse{ Output: &spb.SonicOutput { @@ -504,6 +515,6 @@ func (srv *Server) ImageDefault(ctx context.Context, req *spb.ImageDefaultReques return nil, status.Error(codes.Unknown, err.Error()) } - + return resp, nil }