blob: 47daa83d56b890ea99c00cfe9d4e5554964046b6 [file] [log] [blame]
Yi Tseng890dc3f2018-11-01 13:23:11 -07001/*
2 * Copyright 2018-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Carmelo Cascone3370c962019-02-07 18:24:19 -080016
17package org.onosproject.gnmi.ctl;
Yi Tseng890dc3f2018-11-01 13:23:11 -070018
19import gnmi.Gnmi.CapabilityRequest;
20import gnmi.Gnmi.CapabilityResponse;
21import gnmi.Gnmi.GetRequest;
22import gnmi.Gnmi.GetResponse;
Yi Tseng5f7fef52018-11-05 11:30:47 -080023import gnmi.Gnmi.Path;
24import gnmi.Gnmi.PathElem;
Yi Tseng890dc3f2018-11-01 13:23:11 -070025import gnmi.Gnmi.SetRequest;
26import gnmi.Gnmi.SetResponse;
Yi Tsenge616d752018-11-27 10:53:27 -080027import gnmi.Gnmi.SubscribeRequest;
Yi Tseng890dc3f2018-11-01 13:23:11 -070028import gnmi.gNMIGrpc;
29import io.grpc.ManagedChannel;
Yi Tseng5f7fef52018-11-05 11:30:47 -080030import io.grpc.Status;
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080031import io.grpc.stub.StreamObserver;
Yi Tsengd7716482018-10-31 15:34:30 -070032import org.onosproject.gnmi.api.GnmiClient;
Yi Tseng890dc3f2018-11-01 13:23:11 -070033import org.onosproject.grpc.ctl.AbstractGrpcClient;
Carmelo Casconec2be50a2019-04-10 00:15:39 -070034import org.onosproject.net.DeviceId;
Yi Tseng890dc3f2018-11-01 13:23:11 -070035
36import java.util.concurrent.CompletableFuture;
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080037import java.util.concurrent.TimeUnit;
38import java.util.function.Consumer;
Yi Tseng890dc3f2018-11-01 13:23:11 -070039
40/**
41 * Implementation of gNMI client.
42 */
43public class GnmiClientImpl extends AbstractGrpcClient implements GnmiClient {
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080044
45 private static final int RPC_TIMEOUT_SECONDS = 10;
46
47 private static final GetRequest PING_REQUEST = GetRequest.newBuilder().addPath(
48 Path.newBuilder().addElem(
49 PathElem.newBuilder().setName("onos-gnmi-ping").build()
50 ).build()).build();
51
52 private GnmiSubscriptionManager subscribeManager;
Yi Tseng890dc3f2018-11-01 13:23:11 -070053
Carmelo Casconec2be50a2019-04-10 00:15:39 -070054 GnmiClientImpl(DeviceId deviceId, ManagedChannel managedChannel,
55 GnmiControllerImpl controller) {
56 super(deviceId, managedChannel, false, controller);
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080057 this.subscribeManager =
58 new GnmiSubscriptionManager(this, deviceId, controller);
Yi Tseng890dc3f2018-11-01 13:23:11 -070059 }
60
61 @Override
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080062 public CompletableFuture<CapabilityResponse> capabilities() {
63 final CompletableFuture<CapabilityResponse> future = new CompletableFuture<>();
64 execRpc(s -> s.capabilities(
65 CapabilityRequest.getDefaultInstance(),
66 unaryObserver(future, CapabilityResponse.getDefaultInstance(),
67 "capabilities request"))
68 );
69 return future;
Yi Tseng890dc3f2018-11-01 13:23:11 -070070 }
71
72 @Override
73 public CompletableFuture<GetResponse> get(GetRequest request) {
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080074 final CompletableFuture<GetResponse> future = new CompletableFuture<>();
75 execRpc(s -> s.get(request, unaryObserver(
76 future, GetResponse.getDefaultInstance(), "GET"))
77 );
78 return future;
Yi Tseng890dc3f2018-11-01 13:23:11 -070079 }
80
81 @Override
82 public CompletableFuture<SetResponse> set(SetRequest request) {
Carmelo Casconeab5d41e2019-03-06 18:02:34 -080083 final CompletableFuture<SetResponse> future = new CompletableFuture<>();
84 execRpc(s -> s.set(request, unaryObserver(
85 future, SetResponse.getDefaultInstance(), "SET"))
86 );
87 return future;
88 }
89
90 private <RES> StreamObserver<RES> unaryObserver(
91 final CompletableFuture<RES> future,
92 final RES defaultResponse,
93 final String opDescription) {
94 return new StreamObserver<RES>() {
95 @Override
96 public void onNext(RES value) {
97 future.complete(value);
98 }
99
100 @Override
101 public void onError(Throwable t) {
102 handleRpcError(t, opDescription);
103 future.complete(defaultResponse);
104 }
105
106 @Override
107 public void onCompleted() {
108 // Ignore. Unary call.
109 }
110 };
Yi Tseng890dc3f2018-11-01 13:23:11 -0700111 }
112
Yi Tseng5f7fef52018-11-05 11:30:47 -0800113 @Override
Carmelo Casconeab5d41e2019-03-06 18:02:34 -0800114 public void subscribe(SubscribeRequest request) {
115 subscribeManager.subscribe(request);
Yi Tsenge616d752018-11-27 10:53:27 -0800116 }
117
118 @Override
Carmelo Casconeab5d41e2019-03-06 18:02:34 -0800119 public void unsubscribe() {
120 subscribeManager.unsubscribe();
Yi Tsenge616d752018-11-27 10:53:27 -0800121 }
122
123 @Override
Carmelo Cascone3977ea42019-02-28 13:43:42 -0800124 public CompletableFuture<Boolean> probeService() {
Carmelo Casconeab5d41e2019-03-06 18:02:34 -0800125 final CompletableFuture<Boolean> future = new CompletableFuture<>();
126 final StreamObserver<GetResponse> responseObserver = new StreamObserver<GetResponse>() {
127 @Override
128 public void onNext(GetResponse value) {
129 future.complete(true);
130 }
131
132 @Override
133 public void onError(Throwable t) {
134 // This gRPC call should throw INVALID_ARGUMENT status exception
135 // since "/onos-gnmi-ping" path does not exists in any config
136 // model For other status code such as UNIMPLEMENT, means the
137 // gNMI service is not available on the device.
138 future.complete(Status.fromThrowable(t).getCode()
139 == Status.Code.INVALID_ARGUMENT);
140 }
141
142 @Override
143 public void onCompleted() {
144 // Ignore. Unary call.
145 }
146 };
147 execRpc(s -> s.get(PING_REQUEST, responseObserver));
148 return future;
Yi Tseng5f7fef52018-11-05 11:30:47 -0800149 }
150
Yi Tsenge616d752018-11-27 10:53:27 -0800151 @Override
Carmelo Casconeab5d41e2019-03-06 18:02:34 -0800152 public void shutdown() {
153 subscribeManager.shutdown();
154 super.shutdown();
Yi Tsenge616d752018-11-27 10:53:27 -0800155 }
156
Carmelo Casconeab5d41e2019-03-06 18:02:34 -0800157 /**
158 * Forces execution of an RPC in a cancellable context with a timeout.
159 *
160 * @param stubConsumer P4Runtime stub consumer
161 */
162 private void execRpc(Consumer<gNMIGrpc.gNMIStub> stubConsumer) {
163 if (log.isTraceEnabled()) {
164 log.trace("Executing RPC with timeout {} seconds (context deadline {})...",
165 RPC_TIMEOUT_SECONDS, context().getDeadline());
Yi Tseng890dc3f2018-11-01 13:23:11 -0700166 }
Carmelo Casconeab5d41e2019-03-06 18:02:34 -0800167 runInCancellableContext(() -> stubConsumer.accept(
168 gNMIGrpc.newStub(channel)
169 .withDeadlineAfter(RPC_TIMEOUT_SECONDS, TimeUnit.SECONDS)));
Yi Tseng890dc3f2018-11-01 13:23:11 -0700170 }
171
Carmelo Casconeab5d41e2019-03-06 18:02:34 -0800172 /**
173 * Forces execution of an RPC in a cancellable context with no timeout.
174 *
175 * @param stubConsumer P4Runtime stub consumer
176 */
177 void execRpcNoTimeout(Consumer<gNMIGrpc.gNMIStub> stubConsumer) {
178 if (log.isTraceEnabled()) {
179 log.trace("Executing RPC with no timeout (context deadline {})...",
180 context().getDeadline());
Yi Tseng890dc3f2018-11-01 13:23:11 -0700181 }
Carmelo Casconeab5d41e2019-03-06 18:02:34 -0800182 runInCancellableContext(() -> stubConsumer.accept(
183 gNMIGrpc.newStub(channel)));
Yi Tseng5f7fef52018-11-05 11:30:47 -0800184 }
Yi Tseng890dc3f2018-11-01 13:23:11 -0700185}