HIGUCHI Yuta
Committed by Gerrit Code Review

ONOS-3323 gRPC implementation of Remote Service

- Start modelling Device related service (ONOS-3306)
- exclude machine generated code from doc

Change-Id: Idffbcd883f813de79c6f05fedc9475f308efcc31
...@@ -46,11 +46,13 @@ ...@@ -46,11 +46,13 @@
46 <plugin> 46 <plugin>
47 <groupId>org.apache.maven.plugins</groupId> 47 <groupId>org.apache.maven.plugins</groupId>
48 <artifactId>maven-javadoc-plugin</artifactId> 48 <artifactId>maven-javadoc-plugin</artifactId>
49 - <version>2.10.1</version> 49 + <version>2.10.3</version>
50 <configuration> 50 <configuration>
51 <show>package</show> 51 <show>package</show>
52 - <excludePackageNames>@external-excludes 52 + <excludePackageNames>@external-excludes</excludePackageNames>
53 - </excludePackageNames> 53 + <sourceFileExcludes>
54 + <sourceFileExclude>**/generated-sources/**</sourceFileExclude>
55 + </sourceFileExcludes>
54 <docfilessubdirs>true</docfilessubdirs> 56 <docfilessubdirs>true</docfilessubdirs>
55 <doctitle>ONOS Java API (1.4.0-SNAPSHOT)</doctitle> 57 <doctitle>ONOS Java API (1.4.0-SNAPSHOT)</doctitle>
56 <groups> 58 <groups>
......
...@@ -51,8 +51,11 @@ ...@@ -51,8 +51,11 @@
51 <show>package</show> 51 <show>package</show>
52 <docfilessubdirs>true</docfilessubdirs> 52 <docfilessubdirs>true</docfilessubdirs>
53 <doctitle>ONOS Java API (1.4.0-SNAPSHOT)</doctitle> 53 <doctitle>ONOS Java API (1.4.0-SNAPSHOT)</doctitle>
54 - <excludePackageNames>@internal-excludes 54 + <excludePackageNames>@internal-excludes</excludePackageNames>
55 - </excludePackageNames> 55 + <sourceFileExcludes>
56 + <sourceFileExclude>**/generated-sources/**</sourceFileExclude>
57 + </sourceFileExcludes>
58 +
56 <groups> 59 <groups>
57 <group> 60 <group>
58 <title>Network Model &amp; Services</title> 61 <title>Network Model &amp; Services</title>
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
36 <module>net</module> 36 <module>net</module>
37 <module>store</module> 37 <module>store</module>
38 <module>rpc</module> 38 <module>rpc</module>
39 + <module>rpc-grpc</module>
39 </modules> 40 </modules>
40 41
41 <dependencies> 42 <dependencies>
......
1 +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<features xmlns="http://karaf.apache.org/xmlns/features/v1.2.0" name="${project.artifactId}-${project.version}">
18 + <feature name="${project.artifactId}" version="${project.version}"
19 + description="${project.description}">
20 + <feature>onos-api</feature>
21 + <bundle>mvn:com.google.protobuf/protobuf-java/3.0.0-beta-1</bundle>
22 + <bundle>mvn:io.netty/netty-common/4.1.0.Beta6</bundle>
23 + <bundle>mvn:io.netty/netty-buffer/4.1.0.Beta6</bundle>
24 + <bundle>mvn:io.netty/netty-transport/4.1.0.Beta6</bundle>
25 + <bundle>mvn:io.netty/netty-handler/4.1.0.Beta6</bundle>
26 + <bundle>mvn:io.netty/netty-codec/4.1.0.Beta6</bundle>
27 + <bundle>mvn:io.netty/netty-codec-http/4.1.0.Beta6</bundle>
28 + <bundle>mvn:io.netty/netty-codec-http2/4.1.0.Beta6</bundle>
29 + <bundle>mvn:io.netty/netty-resolver/4.1.0.Beta6</bundle>
30 + <bundle>mvn:com.twitter/hpack/0.11.0</bundle>
31 + <!-- TODO: Create shaded jar for these. -->
32 + <bundle>wrap:mvn:com.google.auth/google-auth-library-credentials/0.3.0$Bundle-SymbolicName=com.google.auth.google-auth-library-credentials&amp;Bundle-Version=0.3.0</bundle>
33 + <bundle>wrap:mvn:com.google.auth/google-auth-library-oauth2-http/0.3.0$Bundle-SymbolicName=com.google.auth.google-auth-library-oauth2-http&amp;Bundle-Version=0.3.0</bundle>
34 + <bundle>wrap:mvn:io.grpc/grpc-all/0.9.0$Bundle-SymbolicName=io.grpc.grpc-all&amp;Bundle-Version=0.9.0&amp;Import-Package=io.netty.*;version=4.1.0.Beta6,javax.net.ssl,com.google.protobuf.nano;resolution:=optional,okio;resolution:=optional,*</bundle>
35 + <bundle>mvn:${project.groupId}/${project.artifactId}/${project.version}</bundle>
36 + </feature>
37 +</features>
1 +<?xml version="1.0" encoding="UTF-8"?>
2 +<!--
3 + ~ Copyright 2015 Open Networking Laboratory
4 + ~
5 + ~ Licensed under the Apache License, Version 2.0 (the "License");
6 + ~ you may not use this file except in compliance with the License.
7 + ~ You may obtain a copy of the License at
8 + ~
9 + ~ http://www.apache.org/licenses/LICENSE-2.0
10 + ~
11 + ~ Unless required by applicable law or agreed to in writing, software
12 + ~ distributed under the License is distributed on an "AS IS" BASIS,
13 + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 + ~ See the License for the specific language governing permissions and
15 + ~ limitations under the License.
16 + -->
17 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
18 + <modelVersion>4.0.0</modelVersion>
19 + <parent>
20 + <artifactId>onos-incubator</artifactId>
21 + <groupId>org.onosproject</groupId>
22 + <version>1.4.0-SNAPSHOT</version>
23 + </parent>
24 +
25 + <artifactId>onos-incubator-rpc-grpc</artifactId>
26 + <packaging>bundle</packaging>
27 +
28 + <description>ONOS inter-cluster RPC based on gRPC</description>
29 + <url>http://onosproject.org</url>
30 +
31 + <properties>
32 + <onos.app.name>org.onosproject.incubator.rpc.grpc</onos.app.name>
33 + <onos.app.requires>org.onosproject.incubator.rpc</onos.app.requires>
34 + <!-- Note: update feature.xml when updating -->
35 + <grpc.version>0.9.0</grpc.version>
36 + <grpc.netty.version>4.1.0.Beta6</grpc.netty.version>
37 + </properties>
38 +
39 + <pluginRepositories>
40 + <pluginRepository>
41 + <id>protoc-plugin</id>
42 + <url>https://dl.bintray.com/sergei-ivanov/maven/</url>
43 + </pluginRepository>
44 + </pluginRepositories>
45 +
46 +
47 + <dependencies>
48 + <dependency>
49 + <groupId>org.onosproject</groupId>
50 + <artifactId>onos-api</artifactId>
51 + </dependency>
52 +
53 + <dependency>
54 + <groupId>org.onosproject</groupId>
55 + <artifactId>onos-incubator-api</artifactId>
56 + </dependency>
57 +
58 + <dependency>
59 + <groupId>org.onosproject</groupId>
60 + <artifactId>onlab-osgi</artifactId>
61 + </dependency>
62 +<!--
63 + <dependency>
64 + <groupId>io.grpc</groupId>
65 + <artifactId>grpc-all</artifactId>
66 + <version>${grpc.version}</version>
67 + </dependency>
68 +-->
69 + <dependency>
70 + <groupId>io.grpc</groupId>
71 + <artifactId>grpc-core</artifactId>
72 + <version>${grpc.version}</version>
73 + </dependency>
74 + <dependency>
75 + <groupId>io.grpc</groupId>
76 + <artifactId>grpc-protobuf</artifactId>
77 + <version>${grpc.version}</version>
78 + </dependency>
79 + <dependency>
80 + <groupId>io.grpc</groupId>
81 + <artifactId>grpc-stub</artifactId>
82 + <version>${grpc.version}</version>
83 + </dependency>
84 + <dependency>
85 + <groupId>io.grpc</groupId>
86 + <artifactId>grpc-netty</artifactId>
87 + <version>${grpc.version}</version>
88 + </dependency>
89 + <dependency>
90 + <groupId>io.grpc</groupId>
91 + <artifactId>grpc-auth</artifactId>
92 + <version>${grpc.version}</version>
93 + </dependency>
94 +
95 + <dependency>
96 + <groupId>junit</groupId>
97 + <artifactId>junit</artifactId>
98 + <scope>test</scope>
99 + </dependency>
100 +
101 + <dependency>
102 + <groupId>org.onosproject</groupId>
103 + <artifactId>onos-api</artifactId>
104 + <scope>test</scope>
105 + <classifier>tests</classifier>
106 + </dependency>
107 +
108 + <dependency>
109 + <groupId>org.apache.felix</groupId>
110 + <artifactId>org.apache.felix.scr.annotations</artifactId>
111 + <scope>provided</scope>
112 + </dependency>
113 + </dependencies>
114 +
115 + <build>
116 + <extensions>
117 + <extension>
118 + <groupId>kr.motd.maven</groupId>
119 + <artifactId>os-maven-plugin</artifactId>
120 + <version>1.4.0.Final</version>
121 + </extension>
122 + </extensions>
123 +
124 + <plugins>
125 + <plugin>
126 + <groupId>org.apache.felix</groupId>
127 + <artifactId>maven-bundle-plugin</artifactId>
128 + <extensions>true</extensions>
129 + </plugin>
130 + <plugin>
131 + <groupId>org.apache.maven.plugins</groupId>
132 + <artifactId>maven-compiler-plugin</artifactId>
133 + <configuration>
134 + <source>1.8</source>
135 + <target>1.8</target>
136 + </configuration>
137 + </plugin>
138 + <plugin>
139 + <groupId>org.apache.felix</groupId>
140 + <artifactId>maven-scr-plugin</artifactId>
141 + <executions>
142 + <execution>
143 + <id>generate-scr-srcdescriptor</id>
144 + <goals>
145 + <goal>scr</goal>
146 + </goals>
147 + </execution>
148 + </executions>
149 + <configuration>
150 + <!-- avoid searching into wrong source path -->
151 + <scanClasses>true</scanClasses>
152 + <supportedProjectTypes>
153 + <supportedProjectType>bundle</supportedProjectType>
154 + <supportedProjectType>war</supportedProjectType>
155 + </supportedProjectTypes>
156 + </configuration>
157 + </plugin>
158 + <plugin>
159 + <groupId>org.onosproject</groupId>
160 + <artifactId>onos-maven-plugin</artifactId>
161 + <executions>
162 + <execution>
163 + <id>cfg</id>
164 + <phase>generate-resources</phase>
165 + <goals>
166 + <goal>cfg</goal>
167 + </goals>
168 + </execution>
169 + <execution>
170 + <id>swagger</id>
171 + <phase>generate-sources</phase>
172 + <goals>
173 + <goal>swagger</goal>
174 + </goals>
175 + </execution>
176 + <execution>
177 + <id>app</id>
178 + <phase>package</phase>
179 + <goals>
180 + <goal>app</goal>
181 + </goals>
182 + </execution>
183 + </executions>
184 + </plugin>
185 +
186 + <plugin>
187 + <groupId>com.google.protobuf.tools</groupId>
188 + <artifactId>maven-protoc-plugin</artifactId>
189 + <version>0.4.2</version>
190 + <configuration>
191 + <!-- The version of protoc must match protobuf-java. If you don't
192 + depend on protobuf-java directly, you will be transitively depending on the
193 + protobuf-java version that grpc depends on. -->
194 + <protocArtifact>com.google.protobuf:protoc:3.0.0-beta-1:exe:${os.detected.classifier}</protocArtifact>
195 + <pluginId>grpc-java</pluginId>
196 + <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
197 + </configuration>
198 + <executions>
199 + <execution>
200 + <goals>
201 + <goal>compile</goal>
202 + <goal>compile-custom</goal>
203 + </goals>
204 + </execution>
205 + </executions>
206 + </plugin>
207 +
208 + <plugin>
209 + <groupId>org.codehaus.mojo</groupId>
210 + <artifactId>build-helper-maven-plugin</artifactId>
211 + <version>1.9.1</version>
212 + <executions>
213 + <execution>
214 + <id>add-source</id>
215 + <phase>generate-sources</phase>
216 + <goals>
217 + <goal>add-source</goal>
218 + </goals>
219 + <configuration>
220 + <sources>
221 + <source>${project.build.directory}/generated-sources/protobuf/java</source>
222 + <source>${project.build.directory}/generated-sources/protobuf/grpc-java</source>
223 + </sources>
224 + </configuration>
225 + </execution>
226 + </executions>
227 + </plugin>
228 +
229 + </plugins>
230 + </build>
231 +
232 + <!-- gRPC requires more recent version of netty -->
233 + <dependencyManagement>
234 + <dependencies>
235 + <dependency>
236 + <groupId>io.netty</groupId>
237 + <artifactId>netty-codec</artifactId>
238 + <version>${grpc.netty.version}</version>
239 + </dependency>
240 + <dependency>
241 + <groupId>io.netty</groupId>
242 + <artifactId>netty-transport</artifactId>
243 + <version>${grpc.netty.version}</version>
244 + </dependency>
245 + <dependency>
246 + <groupId>io.netty</groupId>
247 + <artifactId>netty-handler</artifactId>
248 + <version>${grpc.netty.version}</version>
249 + </dependency>
250 + <dependency>
251 + <groupId>io.netty</groupId>
252 + <artifactId>netty-buffer</artifactId>
253 + <version>${grpc.netty.version}</version>
254 + </dependency>
255 + <dependency>
256 + <groupId>io.netty</groupId>
257 + <artifactId>netty-common</artifactId>
258 + <version>${grpc.netty.version}</version>
259 + </dependency>
260 + <dependency>
261 + <groupId>com.twitter</groupId>
262 + <artifactId>hpack</artifactId>
263 + <!-- 0.11.0 and later are published as a bundle -->
264 + <version>0.11.0</version>
265 + </dependency>
266 + </dependencies>
267 + </dependencyManagement>
268 +
269 +</project>
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
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 + */
16 +package org.onosproject.incubator.rpc.grpc;
17 +
18 +import java.util.Map;
19 +
20 +import org.onosproject.net.device.DeviceProvider;
21 +import org.onosproject.net.device.DeviceProviderRegistry;
22 +import org.onosproject.net.device.DeviceProviderService;
23 +import org.onosproject.net.provider.AbstractProviderRegistry;
24 +import org.slf4j.Logger;
25 +import org.slf4j.LoggerFactory;
26 +
27 +import com.google.common.collect.Maps;
28 +
29 +import io.grpc.Channel;
30 +import io.grpc.ManagedChannel;
31 +
32 +// gRPC Client side
33 +/**
34 + * Proxy object to handle DeviceProviderRegistry calls.
35 + *
36 + * RPC wise, this will start/stop bidirectional streaming service sessions.
37 + */
38 +final class DeviceProviderRegistryClientProxy
39 + extends AbstractProviderRegistry<DeviceProvider, DeviceProviderService>
40 + implements DeviceProviderRegistry {
41 +
42 + private final Logger log = LoggerFactory.getLogger(getClass());
43 +
44 + private final Channel channel;
45 +
46 + private final Map<DeviceProvider, DeviceProviderServiceClientProxy> pServices;
47 +
48 + DeviceProviderRegistryClientProxy(ManagedChannel channel) {
49 + this.channel = channel;
50 + pServices = Maps.newIdentityHashMap();
51 + }
52 +
53 + @Override
54 + protected synchronized DeviceProviderService createProviderService(DeviceProvider provider) {
55 +
56 + // Create session
57 + DeviceProviderServiceClientProxy pService = new DeviceProviderServiceClientProxy(provider, channel);
58 + log.debug("Created DeviceProviderServiceClientProxy", pService);
59 +
60 + DeviceProviderServiceClientProxy old = pServices.put(provider, pService);
61 + if (old != null) {
62 + // sanity check, can go away
63 + log.warn("Duplicate registration detected for {}", provider.id());
64 + }
65 + return pService;
66 + }
67 +
68 + @Override
69 + public synchronized void unregister(DeviceProvider provider) {
70 + DeviceProviderServiceClientProxy pService = pServices.remove(provider);
71 + log.debug("Unregistering DeviceProviderServiceClientProxy", pService);
72 + super.unregister(provider);
73 + if (pService != null) {
74 + pService.shutdown();
75 + }
76 + }
77 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
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 + */
16 +package org.onosproject.incubator.rpc.grpc;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +import static java.util.stream.Collectors.toList;
20 +import static org.onosproject.incubator.rpc.grpc.GrpcDeviceUtils.translate;
21 +import static org.onosproject.net.DeviceId.deviceId;
22 +
23 +import java.util.Collection;
24 +import java.util.List;
25 +import java.util.concurrent.atomic.AtomicBoolean;
26 +
27 +import org.onosproject.grpc.Device.DeviceProviderMsg;
28 +import org.onosproject.grpc.Device.DeviceProviderServiceMsg;
29 +import org.onosproject.grpc.Device.IsReachableRequest;
30 +import org.onosproject.grpc.Device.RoleChanged;
31 +import org.onosproject.grpc.Device.TriggerProbe;
32 +import org.onosproject.grpc.DeviceProviderRegistryRpcGrpc;
33 +import org.onosproject.grpc.DeviceProviderRegistryRpcGrpc.DeviceProviderRegistryRpcStub;
34 +import org.onosproject.net.DeviceId;
35 +import org.onosproject.net.MastershipRole;
36 +import org.onosproject.net.device.DeviceDescription;
37 +import org.onosproject.net.device.DeviceProvider;
38 +import org.onosproject.net.device.DeviceProviderService;
39 +import org.onosproject.net.device.PortDescription;
40 +import org.onosproject.net.device.PortStatistics;
41 +import org.onosproject.net.provider.AbstractProviderService;
42 +import org.slf4j.Logger;
43 +import org.slf4j.LoggerFactory;
44 +
45 +import com.google.common.base.MoreObjects;
46 +
47 +import io.grpc.Channel;
48 +import io.grpc.stub.StreamObserver;
49 +
50 +// gRPC Client side
51 +// gRPC wise, this object represents bidirectional streaming service session
52 +// and deals with outgoing message stream
53 +/**
54 + * DeviceProviderService instance associated with given DeviceProvider.
55 + */
56 +final class DeviceProviderServiceClientProxy
57 + extends AbstractProviderService<DeviceProvider>
58 + implements DeviceProviderService {
59 +
60 + private final Logger log = LoggerFactory.getLogger(getClass());
61 +
62 + private final StreamObserver<DeviceProviderServiceMsg> devProvService;
63 + private final AtomicBoolean hasShutdown = new AtomicBoolean(false);
64 +
65 + private final Channel channel;
66 +
67 + DeviceProviderServiceClientProxy(DeviceProvider provider, Channel channel) {
68 + super(provider);
69 + this.channel = channel;
70 +
71 + DeviceProviderRegistryRpcStub stub = DeviceProviderRegistryRpcGrpc.newStub(channel);
72 + log.debug("Calling RPC register({}) against {}", provider.id(), channel.authority());
73 + devProvService = stub.register(new DeviceProviderClientProxy(provider));
74 +
75 + // send initialize message
76 + DeviceProviderServiceMsg.Builder builder = DeviceProviderServiceMsg.newBuilder();
77 + builder.setRegisterProvider(builder.getRegisterProviderBuilder()
78 + .setProviderScheme(provider.id().scheme())
79 + .build());
80 + devProvService.onNext(builder.build());
81 + }
82 +
83 + @Override
84 + public void deviceConnected(DeviceId deviceId,
85 + DeviceDescription deviceDescription) {
86 + checkValidity();
87 +
88 + DeviceProviderServiceMsg.Builder builder = DeviceProviderServiceMsg.newBuilder();
89 + builder.setDeviceConnected(builder.getDeviceConnectedBuilder()
90 + .setDeviceId(deviceId.toString())
91 + .setDeviceDescription(translate(deviceDescription))
92 + .build());
93 +
94 + devProvService.onNext(builder.build());
95 + }
96 +
97 + @Override
98 + public void deviceDisconnected(DeviceId deviceId) {
99 + checkValidity();
100 +
101 + DeviceProviderServiceMsg.Builder builder = DeviceProviderServiceMsg.newBuilder();
102 + builder.setDeviceDisconnected(builder.getDeviceDisconnectedBuilder()
103 + .setDeviceId(deviceId.toString())
104 + .build());
105 +
106 + devProvService.onNext(builder.build());
107 + }
108 +
109 + @Override
110 + public void updatePorts(DeviceId deviceId,
111 + List<PortDescription> portDescriptions) {
112 + checkValidity();
113 +
114 + DeviceProviderServiceMsg.Builder builder = DeviceProviderServiceMsg.newBuilder();
115 + List<org.onosproject.grpc.Port.PortDescription> portDescs =
116 + portDescriptions.stream()
117 + .map(GrpcDeviceUtils::translate)
118 + .collect(toList());
119 +
120 + builder.setUpdatePorts(builder.getUpdatePortsBuilder()
121 + .setDeviceId(deviceId.toString())
122 + .addAllPortDescriptions(portDescs)
123 + .build());
124 +
125 + devProvService.onNext(builder.build());
126 + }
127 +
128 + @Override
129 + public void portStatusChanged(DeviceId deviceId,
130 + PortDescription portDescription) {
131 + checkValidity();
132 +
133 + DeviceProviderServiceMsg.Builder builder = DeviceProviderServiceMsg.newBuilder();
134 + builder.setPortStatusChanged(builder.getPortStatusChangedBuilder()
135 + .setDeviceId(deviceId.toString())
136 + .setPortDescription(translate(portDescription))
137 + .build());
138 +
139 + devProvService.onNext(builder.build());
140 + }
141 +
142 + @Override
143 + public void receivedRoleReply(DeviceId deviceId, MastershipRole requested,
144 + MastershipRole response) {
145 + checkValidity();
146 +
147 + DeviceProviderServiceMsg.Builder builder = DeviceProviderServiceMsg.newBuilder();
148 + builder.setReceivedRoleReply(builder.getReceivedRoleReplyBuilder()
149 + .setDeviceId(deviceId.toString())
150 + .setRequested(translate(requested))
151 + .setResponse(translate(response))
152 + .build());
153 +
154 + devProvService.onNext(builder.build());
155 + }
156 +
157 + @Override
158 + public void updatePortStatistics(DeviceId deviceId,
159 + Collection<PortStatistics> portStatistics) {
160 + checkValidity();
161 +
162 + DeviceProviderServiceMsg.Builder builder = DeviceProviderServiceMsg.newBuilder();
163 + List<org.onosproject.grpc.Port.PortStatistics> portStats =
164 + portStatistics.stream()
165 + .map(GrpcDeviceUtils::translate)
166 + .collect(toList());
167 + builder.setUpdatePortStatistics(builder.getUpdatePortStatisticsBuilder()
168 + .setDeviceId(deviceId.toString())
169 + .addAllPortStatistics(portStats)
170 + .build());
171 +
172 + devProvService.onNext(builder.build());
173 + }
174 +
175 + /**
176 + * Shutdown this session.
177 + */
178 + public void shutdown() {
179 + if (hasShutdown.compareAndSet(false, true)) {
180 + log.info("Shutting down session over {}", channel.authority());
181 + // initiate clean shutdown from client
182 + devProvService.onCompleted();
183 + invalidate();
184 + }
185 + }
186 +
187 + /**
188 + * Abnormally terminate this session.
189 + * @param t error details
190 + */
191 + public void shutdown(Throwable t) {
192 + if (hasShutdown.compareAndSet(false, true)) {
193 + log.error("Shutting down session over {}", channel.authority());
194 + // initiate abnormal termination from client
195 + devProvService.onError(t);
196 + invalidate();
197 + }
198 + }
199 +
200 + @Override
201 + public String toString() {
202 + return MoreObjects.toStringHelper(this)
203 + .add("channel", channel.authority())
204 + .add("hasShutdown", hasShutdown.get())
205 + .toString();
206 + }
207 +
208 + // gRPC wise, this object handles incoming message stream
209 + /**
210 + * Translates DeviceProvider instructions received from RPC to Java calls.
211 + */
212 + private final class DeviceProviderClientProxy
213 + implements StreamObserver<DeviceProviderMsg> {
214 +
215 + private final DeviceProvider provider;
216 +
217 + DeviceProviderClientProxy(DeviceProvider provider) {
218 + this.provider = checkNotNull(provider);
219 + }
220 +
221 + @Override
222 + public void onNext(DeviceProviderMsg msg) {
223 + try {
224 + log.trace("DeviceProviderClientProxy received: {}", msg);
225 + onMethod(msg);
226 + } catch (Exception e) {
227 + log.error("Exception caught handling {} at DeviceProviderClientProxy", msg, e);
228 + // initiate shutdown from client
229 + shutdown(e);
230 + }
231 + }
232 +
233 + /**
234 + * Translates received RPC message to {@link DeviceProvider} method calls.
235 + * @param msg DeviceProvider message
236 + */
237 + private void onMethod(DeviceProviderMsg msg) {
238 + switch (msg.getMethodCase()) {
239 + case TRIGGER_PROBE:
240 + TriggerProbe triggerProbe = msg.getTriggerProbe();
241 + provider.triggerProbe(deviceId(triggerProbe.getDeviceId()));
242 + break;
243 + case ROLE_CHANGED:
244 + RoleChanged roleChanged = msg.getRoleChanged();
245 + provider.roleChanged(deviceId(roleChanged.getDeviceId()),
246 + translate(roleChanged.getNewRole()));
247 + break;
248 + case IS_REACHABLE_REQUEST:
249 + IsReachableRequest isReachableRequest = msg.getIsReachableRequest();
250 + // check if reachable
251 + boolean reachable = provider.isReachable(deviceId(isReachableRequest.getDeviceId()));
252 +
253 + int xid = isReachableRequest.getXid();
254 + // send response back DeviceProviderService channel
255 + DeviceProviderServiceMsg.Builder builder = DeviceProviderServiceMsg.newBuilder();
256 + builder.setIsReachableResponse(builder.getIsReachableResponseBuilder()
257 + .setXid(xid)
258 + .setIsReachable(reachable)
259 + .build());
260 + devProvService.onNext(builder.build());
261 + break;
262 +
263 + case METHOD_NOT_SET:
264 + default:
265 + log.warn("Unexpected method, ignoring", msg);
266 + break;
267 + }
268 + }
269 +
270 + @Override
271 + public void onCompleted() {
272 + log.info("DeviceProviderClientProxy completed");
273 + // session terminated from remote
274 + // TODO unregister...? how?
275 +
276 + //devProvService.onCompleted();
277 + }
278 +
279 + @Override
280 + public void onError(Throwable t) {
281 + log.error("DeviceProviderClientProxy#onError", t);
282 + // session terminated from remote
283 + // TODO unregister...? how?
284 + //devProvService.onError(t);
285 + }
286 +
287 + @Override
288 + public String toString() {
289 + return MoreObjects.toStringHelper(this)
290 + .add("channel", channel.authority())
291 + .toString();
292 + }
293 + }
294 +}
295 +
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
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 + */
16 +package org.onosproject.incubator.rpc.grpc;
17 +
18 +import java.net.URI;
19 +import java.util.HashMap;
20 +import java.util.Map;
21 +
22 +import org.onlab.packet.ChassisId;
23 +import org.onosproject.grpc.Device.DeviceType;
24 +import org.onosproject.grpc.Port.PortType;
25 +import org.onosproject.net.Annotations;
26 +import org.onosproject.net.DefaultAnnotations;
27 +import org.onosproject.net.Device;
28 +import org.onosproject.net.MastershipRole;
29 +import org.onosproject.net.Port;
30 +import org.onosproject.net.Port.Type;
31 +import org.onosproject.net.PortNumber;
32 +import org.onosproject.net.SparseAnnotations;
33 +import org.onosproject.net.device.DefaultDeviceDescription;
34 +import org.onosproject.net.device.DefaultPortDescription;
35 +import org.onosproject.net.device.DefaultPortStatistics;
36 +import org.onosproject.net.device.DeviceDescription;
37 +import org.onosproject.net.device.PortDescription;
38 +import org.onosproject.net.device.PortStatistics;
39 +import org.slf4j.Logger;
40 +import org.slf4j.LoggerFactory;
41 +
42 +import com.google.api.client.repackaged.com.google.common.annotations.Beta;
43 +
44 +/**
45 + * gRPC message conversion related utilities.
46 + */
47 +@Beta
48 +public final class GrpcDeviceUtils {
49 +
50 + private static final Logger log = LoggerFactory.getLogger(GrpcDeviceUtils.class);
51 +
52 + /**
53 + * Translates gRPC enum MastershipRole to ONOS enum.
54 + *
55 + * @param role mastership role in gRPC enum
56 + * @return equivalent in ONOS enum
57 + */
58 + public static MastershipRole translate(org.onosproject.grpc.Device.MastershipRole role) {
59 + switch (role) {
60 + case NONE:
61 + return MastershipRole.NONE;
62 + case MASTER:
63 + return MastershipRole.MASTER;
64 + case STANDBY:
65 + return MastershipRole.STANDBY;
66 + case UNRECOGNIZED:
67 + log.warn("Unrecognized MastershipRole gRPC message: {}", role);
68 + default:
69 + return MastershipRole.NONE;
70 + }
71 + }
72 +
73 + /**
74 + * Translates ONOS enum MastershipRole to gRPC enum.
75 + *
76 + * @param newRole ONOS' mastership role
77 + * @return equivalent in gRPC message enum
78 + */
79 + public static org.onosproject.grpc.Device.MastershipRole translate(MastershipRole newRole) {
80 + switch (newRole) {
81 + case MASTER:
82 + return org.onosproject.grpc.Device.MastershipRole.MASTER;
83 + case STANDBY:
84 + return org.onosproject.grpc.Device.MastershipRole.STANDBY;
85 + case NONE:
86 + default:
87 + return org.onosproject.grpc.Device.MastershipRole.NONE;
88 + }
89 + }
90 +
91 +
92 + /**
93 + * Translates gRPC DeviceDescription to {@link DeviceDescription}.
94 + *
95 + * @param deviceDescription gRPC message
96 + * @return {@link DeviceDescription}
97 + */
98 + public static DeviceDescription translate(org.onosproject.grpc.Device.DeviceDescription deviceDescription) {
99 + URI uri = URI.create(deviceDescription.getDeviceUri());
100 + Device.Type type = translate(deviceDescription.getType());
101 + String manufacturer = deviceDescription.getManufacturer();
102 + String hwVersion = deviceDescription.getHwVersion();
103 + String swVersion = deviceDescription.getSwVersion();
104 + String serialNumber = deviceDescription.getSerialNumber();
105 + ChassisId chassis = new ChassisId(deviceDescription.getChassisId());
106 + return new DefaultDeviceDescription(uri, type, manufacturer,
107 + hwVersion, swVersion, serialNumber,
108 + chassis,
109 + asAnnotations(deviceDescription.getAnnotations()));
110 + }
111 +
112 + /**
113 + * Translates {@link DeviceDescription} to gRPC DeviceDescription message.
114 + *
115 + * @param deviceDescription {@link DeviceDescription}
116 + * @return gRPC DeviceDescription message
117 + */
118 + public static org.onosproject.grpc.Device.DeviceDescription translate(DeviceDescription deviceDescription) {
119 +
120 + return org.onosproject.grpc.Device.DeviceDescription.newBuilder()
121 + .setDeviceUri(deviceDescription.deviceUri().toString())
122 + .setType(translate(deviceDescription.type()))
123 + .setManufacturer(deviceDescription.manufacturer())
124 + .setHwVersion(deviceDescription.hwVersion())
125 + .setSwVersion(deviceDescription.swVersion())
126 + .setSerialNumber(deviceDescription.serialNumber())
127 + .setChassisId(deviceDescription.chassisId().toString())
128 + .putAllAnnotations(asMap(deviceDescription.annotations()))
129 + .build();
130 + }
131 +
132 +
133 + /**
134 + * Translates gRPC DeviceType to {@link Device.Type}.
135 + *
136 + * @param type gRPC message
137 + * @return {@link Device.Type}
138 + */
139 + public static Device.Type translate(org.onosproject.grpc.Device.DeviceType type) {
140 + switch (type) {
141 + case BALANCER:
142 + return Device.Type.BALANCER;
143 + case CONTROLLER:
144 + return Device.Type.CONTROLLER;
145 + case FIBER_SWITCH:
146 + return Device.Type.FIBER_SWITCH;
147 + case FIREWALL:
148 + return Device.Type.FIREWALL;
149 + case IDS:
150 + return Device.Type.IDS;
151 + case IPS:
152 + return Device.Type.IPS;
153 + case MICROWAVE:
154 + return Device.Type.MICROWAVE;
155 + case OTHER:
156 + return Device.Type.OTHER;
157 + case OTN:
158 + return Device.Type.OTN;
159 + case ROADM:
160 + return Device.Type.ROADM;
161 + case ROADM_OTN:
162 + return Device.Type.ROADM_OTN;
163 + case ROUTER:
164 + return Device.Type.ROUTER;
165 + case SWITCH:
166 + return Device.Type.SWITCH;
167 + case VIRTUAL:
168 + return Device.Type.VIRTUAL;
169 +
170 + case UNRECOGNIZED:
171 + default:
172 + log.warn("Unexpected DeviceType: {}", type);
173 + return Device.Type.OTHER;
174 + }
175 + }
176 +
177 + /**
178 + * Translates {@link Type} to gRPC DeviceType.
179 + *
180 + * @param type {@link Type}
181 + * @return gRPC message
182 + */
183 + public static DeviceType translate(Device.Type type) {
184 + switch (type) {
185 + case BALANCER:
186 + return DeviceType.BALANCER;
187 + case CONTROLLER:
188 + return DeviceType.CONTROLLER;
189 + case FIBER_SWITCH:
190 + return DeviceType.FIBER_SWITCH;
191 + case FIREWALL:
192 + return DeviceType.FIREWALL;
193 + case IDS:
194 + return DeviceType.IDS;
195 + case IPS:
196 + return DeviceType.IPS;
197 + case MICROWAVE:
198 + return DeviceType.MICROWAVE;
199 + case OTHER:
200 + return DeviceType.OTHER;
201 + case OTN:
202 + return DeviceType.OTN;
203 + case ROADM:
204 + return DeviceType.ROADM;
205 + case ROADM_OTN:
206 + return DeviceType.ROADM_OTN;
207 + case ROUTER:
208 + return DeviceType.ROUTER;
209 + case SWITCH:
210 + return DeviceType.SWITCH;
211 + case VIRTUAL:
212 + return DeviceType.VIRTUAL;
213 +
214 + default:
215 + log.warn("Unexpected Device.Type: {}", type);
216 + return DeviceType.OTHER;
217 + }
218 + }
219 +
220 + /**
221 + * Translates gRPC PortDescription message to {@link PortDescription}.
222 + *
223 + * @param portDescription gRPC message
224 + * @return {@link PortDescription}
225 + */
226 + public static PortDescription translate(org.onosproject.grpc.Port.PortDescription portDescription) {
227 + PortNumber number = PortNumber.fromString(portDescription.getPortNumber());
228 + boolean isEnabled = portDescription.getIsEnabled();
229 + Port.Type type = translate(portDescription.getType());
230 + long portSpeed = portDescription.getPortSpeed();
231 + SparseAnnotations annotations = asAnnotations(portDescription.getAnnotations());
232 + // TODO How to deal with more specific Port...
233 + return new DefaultPortDescription(number, isEnabled, type, portSpeed, annotations);
234 + }
235 +
236 + /**
237 + * Translates {@link PortDescription} to gRPC PortDescription message.
238 + *
239 + * @param portDescription {@link PortDescription}
240 + * @return gRPC PortDescription message
241 + */
242 + public static org.onosproject.grpc.Port.PortDescription translate(PortDescription portDescription) {
243 + // TODO How to deal with more specific Port...
244 + return org.onosproject.grpc.Port.PortDescription.newBuilder()
245 + .setPortNumber(portDescription.portNumber().toString())
246 + .setIsEnabled(portDescription.isEnabled())
247 + .setType(translate(portDescription.type()))
248 + .setPortSpeed(portDescription.portSpeed())
249 + .putAllAnnotations(asMap(portDescription.annotations()))
250 + .build();
251 + }
252 +
253 + /**
254 + * Translates gRPC PortType to {@link Port.Type}.
255 + *
256 + * @param type gRPC message
257 + * @return {@link Port.Type}
258 + */
259 + public static Port.Type translate(PortType type) {
260 + switch (type) {
261 + case COPPER:
262 + return Type.COPPER;
263 + case FIBER:
264 + return Type.FIBER;
265 + case OCH:
266 + return Type.OCH;
267 + case ODUCLT:
268 + return Type.ODUCLT;
269 + case OMS:
270 + return Type.OMS;
271 + case PACKET:
272 + return Type.PACKET;
273 + case VIRTUAL:
274 + return Type.VIRTUAL;
275 +
276 + case UNRECOGNIZED:
277 + default:
278 + log.warn("Unexpected PortType: {}", type);
279 + return Type.COPPER;
280 + }
281 + }
282 +
283 + /**
284 + * Translates {@link Port.Type} to gRPC PortType.
285 + *
286 + * @param type {@link Port.Type}
287 + * @return gRPC message
288 + */
289 + public static PortType translate(Port.Type type) {
290 + switch (type) {
291 + case COPPER:
292 + return PortType.COPPER;
293 + case FIBER:
294 + return PortType.FIBER;
295 + case OCH:
296 + return PortType.OCH;
297 + case ODUCLT:
298 + return PortType.ODUCLT;
299 + case OMS:
300 + return PortType.OMS;
301 + case PACKET:
302 + return PortType.PACKET;
303 + case VIRTUAL:
304 + return PortType.VIRTUAL;
305 +
306 + default:
307 + log.warn("Unexpected Port.Type: {}", type);
308 + return PortType.COPPER;
309 + }
310 + }
311 +
312 + /**
313 + * Translates gRPC PortStatistics message to {@link PortStatistics}.
314 + *
315 + * @param portStatistics gRPC PortStatistics message
316 + * @return {@link PortStatistics}
317 + */
318 + public static PortStatistics translate(org.onosproject.grpc.Port.PortStatistics portStatistics) {
319 + // TODO implement adding missing fields
320 + return DefaultPortStatistics.builder()
321 + .setPort(portStatistics.getPort())
322 + .setPacketsReceived(portStatistics.getPacketsReceived())
323 + .setPacketsSent(portStatistics.getPacketsSent())
324 + .build();
325 + }
326 +
327 + /**
328 + * Translates {@link PortStatistics} to gRPC PortStatistics message.
329 + *
330 + * @param portStatistics {@link PortStatistics}
331 + * @return gRPC PortStatistics message
332 + */
333 + public static org.onosproject.grpc.Port.PortStatistics translate(PortStatistics portStatistics) {
334 + // TODO implement adding missing fields
335 + return org.onosproject.grpc.Port.PortStatistics.newBuilder()
336 + .setPort(portStatistics.port())
337 + .setPacketsReceived(portStatistics.packetsReceived())
338 + .setPacketsSent(portStatistics.packetsSent())
339 + .build();
340 + }
341 +
342 + // may be this can be moved to Annotation itself or AnnotationsUtils
343 + /**
344 + * Converts Annotations to Map of Strings.
345 + *
346 + * @param annotations {@link Annotations}
347 + * @return Map of annotation key and values
348 + */
349 + public static Map<String, String> asMap(Annotations annotations) {
350 + if (annotations instanceof DefaultAnnotations) {
351 + return ((DefaultAnnotations) annotations).asMap();
352 + }
353 + Map<String, String> map = new HashMap<>();
354 + annotations.keys()
355 + .forEach(k -> map.put(k, annotations.value(k)));
356 +
357 + return map;
358 + }
359 +
360 + // may be this can be moved to Annotation itself or AnnotationsUtils
361 + /**
362 + * Converts Map of Strings to {@link SparseAnnotations}.
363 + *
364 + * @param annotations Map of annotation key and values
365 + * @return {@link SparseAnnotations}
366 + */
367 + public static SparseAnnotations asAnnotations(Map<String, String> annotations) {
368 + DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
369 + annotations.entrySet().forEach(e -> {
370 + if (e.getValue() != null) {
371 + builder.set(e.getKey(), e.getValue());
372 + } else {
373 + builder.remove(e.getKey());
374 + }
375 + });
376 + return builder.build();
377 + }
378 +
379 + // Utility class not intended for instantiation.
380 + private GrpcDeviceUtils() {}
381 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
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 + */
16 +package org.onosproject.incubator.rpc.grpc;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +
20 +import java.util.Map;
21 +import java.util.NoSuchElementException;
22 +import java.util.concurrent.ConcurrentHashMap;
23 +
24 +import org.onosproject.incubator.rpc.RemoteServiceContext;
25 +import org.onosproject.net.device.DeviceProviderRegistry;
26 +import org.slf4j.Logger;
27 +import org.slf4j.LoggerFactory;
28 +
29 +import com.google.common.base.MoreObjects;
30 +
31 +import io.grpc.ManagedChannel;
32 +
33 +// gRPC Client side
34 +// Probably there should be plug-in mechanism in the future.
35 +/**
36 + * RemoteServiceContext based on gRPC.
37 + *
38 + * <p>
39 + * Currently it supports {@link DeviceProviderRegistry}.
40 + */
41 +public class GrpcRemoteServiceContext implements RemoteServiceContext {
42 +
43 + private final Logger log = LoggerFactory.getLogger(getClass());
44 +
45 + private final Map<Class<? extends Object>, Object> services = new ConcurrentHashMap<>();
46 +
47 + private final ManagedChannel channel;
48 +
49 + public GrpcRemoteServiceContext(ManagedChannel channel) {
50 + this.channel = checkNotNull(channel);
51 + services.put(DeviceProviderRegistry.class, new DeviceProviderRegistryClientProxy(channel));
52 + }
53 +
54 +
55 + @Override
56 + public <T> T get(Class<T> serviceClass) {
57 + @SuppressWarnings("unchecked")
58 + T service = (T) services.get(serviceClass);
59 + if (service != null) {
60 + return service;
61 + }
62 + log.error("{} not supported", serviceClass);
63 + throw new NoSuchElementException(serviceClass.getTypeName() + " not supported");
64 + }
65 +
66 +
67 + @Override
68 + public String toString() {
69 + return MoreObjects.toStringHelper(this)
70 + .add("services", services.keySet())
71 + .add("channel", channel.authority())
72 + .toString();
73 + }
74 +
75 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
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 + */
16 +package org.onosproject.incubator.rpc.grpc;
17 +
18 +import static com.google.common.base.Preconditions.checkArgument;
19 +
20 +import java.net.URI;
21 +import java.util.Map;
22 +import java.util.Objects;
23 +import java.util.concurrent.ConcurrentHashMap;
24 +
25 +import org.apache.felix.scr.annotations.Activate;
26 +import org.apache.felix.scr.annotations.Component;
27 +import org.apache.felix.scr.annotations.Deactivate;
28 +import org.apache.felix.scr.annotations.Reference;
29 +import org.apache.felix.scr.annotations.ReferenceCardinality;
30 +import org.onosproject.incubator.rpc.RemoteServiceContext;
31 +import org.onosproject.incubator.rpc.RemoteServiceContextProvider;
32 +import org.onosproject.incubator.rpc.RemoteServiceContextProviderService;
33 +import org.onosproject.incubator.rpc.RemoteServiceProviderRegistry;
34 +import org.onosproject.net.provider.ProviderId;
35 +import org.slf4j.Logger;
36 +import org.slf4j.LoggerFactory;
37 +
38 +import io.grpc.ManagedChannel;
39 +import io.grpc.netty.NegotiationType;
40 +import io.grpc.netty.NettyChannelBuilder;
41 +
42 +
43 +// gRPC Client side
44 +/**
45 + * RemoteServiceContextProvider based on gRPC.
46 + */
47 +@Component(immediate = true)
48 +public class GrpcRemoteServiceProvider implements RemoteServiceContextProvider {
49 +
50 + public static final String GRPC_SCHEME = "grpc";
51 +
52 + public static final String RPC_PROVIDER_NAME = "org.onosproject.rpc.provider.grpc";
53 +
54 + private static final ProviderId PID = new ProviderId(GRPC_SCHEME, RPC_PROVIDER_NAME);
55 +
56 + private final Logger log = LoggerFactory.getLogger(getClass());
57 +
58 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
59 + protected RemoteServiceProviderRegistry rpcRegistry;
60 +
61 + private Map<URI, ManagedChannel> channels = new ConcurrentHashMap<>();
62 +
63 + private RemoteServiceContextProviderService providerService;
64 +
65 +
66 + @Activate
67 + protected void activate() {
68 + providerService = rpcRegistry.register(this);
69 +
70 + // FIXME remove me. test code to see if gRPC loads in karaf
71 + //getChannel(URI.create("grpc://localhost:8080"));
72 +
73 + log.info("Started");
74 + }
75 +
76 + @Deactivate
77 + protected void deactivate() {
78 + rpcRegistry.unregister(this);
79 +
80 + // shutdown all channels
81 + channels.values().stream()
82 + .forEach(ManagedChannel::shutdown);
83 + // Should we wait for shutdown? How?
84 + channels.clear();
85 + log.info("Stopped");
86 + }
87 +
88 + @Override
89 + public ProviderId id() {
90 + return PID;
91 + }
92 +
93 + @Override
94 + public RemoteServiceContext get(URI uri) {
95 + // Create gRPC client
96 + return new GrpcRemoteServiceContext(getChannel(uri));
97 + }
98 +
99 + private ManagedChannel getChannel(URI uri) {
100 + checkArgument(Objects.equals(GRPC_SCHEME, uri.getScheme()),
101 + "Invalid URI scheme: %s", uri.getScheme());
102 +
103 + return channels.compute(uri, (u, ch) -> {
104 + if (ch != null && !ch.isShutdown()) {
105 + return ch;
106 + } else {
107 + return createChannel(u);
108 + }
109 + });
110 + }
111 +
112 + private ManagedChannel createChannel(URI uri) {
113 + log.debug("Creating channel for {}", uri);
114 + return NettyChannelBuilder.forAddress(uri.getHost(), uri.getPort())
115 + .negotiationType(NegotiationType.PLAINTEXT)
116 + .build();
117 + }
118 +
119 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
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 + */
16 +package org.onosproject.incubator.rpc.grpc;
17 +
18 +import static com.google.common.base.Preconditions.checkNotNull;
19 +import static java.util.stream.Collectors.toList;
20 +import static org.onosproject.incubator.rpc.grpc.GrpcDeviceUtils.translate;
21 +import static org.onosproject.net.DeviceId.deviceId;
22 +
23 +import java.io.IOException;
24 +import java.util.Set;
25 +import java.util.concurrent.CompletableFuture;
26 +import java.util.concurrent.ExecutionException;
27 +import java.util.concurrent.TimeUnit;
28 +import java.util.concurrent.TimeoutException;
29 +import java.util.concurrent.atomic.AtomicInteger;
30 +
31 +import org.apache.felix.scr.annotations.Activate;
32 +import org.apache.felix.scr.annotations.Component;
33 +import org.apache.felix.scr.annotations.Deactivate;
34 +import org.apache.felix.scr.annotations.Modified;
35 +import org.apache.felix.scr.annotations.Property;
36 +import org.apache.felix.scr.annotations.Reference;
37 +import org.apache.felix.scr.annotations.ReferenceCardinality;
38 +import org.onosproject.grpc.Device.DeviceConnected;
39 +import org.onosproject.grpc.Device.DeviceDisconnected;
40 +import org.onosproject.grpc.Device.DeviceProviderMsg;
41 +import org.onosproject.grpc.Device.DeviceProviderServiceMsg;
42 +import org.onosproject.grpc.Device.IsReachableResponse;
43 +import org.onosproject.grpc.Device.PortStatusChanged;
44 +import org.onosproject.grpc.Device.ReceivedRoleReply;
45 +import org.onosproject.grpc.Device.RegisterProvider;
46 +import org.onosproject.grpc.Device.UpdatePortStatistics;
47 +import org.onosproject.grpc.Device.UpdatePorts;
48 +import org.onosproject.grpc.DeviceProviderRegistryRpcGrpc;
49 +import org.onosproject.grpc.DeviceProviderRegistryRpcGrpc.DeviceProviderRegistryRpc;
50 +import org.onosproject.net.DeviceId;
51 +import org.onosproject.net.MastershipRole;
52 +import org.onosproject.net.device.DeviceProvider;
53 +import org.onosproject.net.device.DeviceProviderRegistry;
54 +import org.onosproject.net.device.DeviceProviderService;
55 +import org.onosproject.net.provider.ProviderId;
56 +import org.osgi.service.component.ComponentContext;
57 +import org.slf4j.Logger;
58 +import org.slf4j.LoggerFactory;
59 +
60 +import com.google.common.cache.Cache;
61 +import com.google.common.cache.CacheBuilder;
62 +import com.google.common.collect.Sets;
63 +
64 +import io.grpc.Server;
65 +import io.grpc.netty.NettyServerBuilder;
66 +import io.grpc.stub.StreamObserver;
67 +
68 +// gRPC Server on Metro-side
69 +// Translates request received on RPC channel, and calls corresponding Service on
70 +// Metro-ONOS cluster.
71 +/**
72 + * Server side implementation of gRPC based RemoteService.
73 + */
74 +@Component(immediate = true)
75 +public class GrpcRemoteServiceServer {
76 +
77 + private static final String RPC_PROVIDER_NAME = "org.onosproject.rpc.provider.grpc";
78 +
79 + // TODO pick a number
80 + public static final int DEFAULT_LISTEN_PORT = 11984;
81 +
82 + private final Logger log = LoggerFactory.getLogger(getClass());
83 +
84 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 + protected DeviceProviderRegistry deviceProviderRegistry;
86 +
87 +
88 + @Property(name = "listenPort", intValue = DEFAULT_LISTEN_PORT,
89 + label = "Port to listen on")
90 + protected int listenPort = DEFAULT_LISTEN_PORT;
91 +
92 + private Server server;
93 + private final Set<DeviceProviderServerProxy> registeredProviders = Sets.newConcurrentHashSet();
94 +
95 + @Activate
96 + protected void activate(ComponentContext context) throws IOException {
97 + modified(context);
98 +
99 + log.debug("Server starting on {}", listenPort);
100 + try {
101 + server = NettyServerBuilder.forPort(listenPort)
102 + .addService(DeviceProviderRegistryRpcGrpc.bindService(new DeviceProviderRegistryServerProxy()))
103 + .build().start();
104 + } catch (IOException e) {
105 + log.error("Failed to start gRPC server", e);
106 + throw e;
107 + }
108 +
109 + log.info("Started on {}", listenPort);
110 + }
111 +
112 + @Deactivate
113 + protected void deactivate() {
114 +
115 + registeredProviders.stream()
116 + .forEach(deviceProviderRegistry::unregister);
117 +
118 + server.shutdown();
119 + // Should we wait for shutdown?
120 + log.info("Stopped");
121 + }
122 +
123 + @Modified
124 + public void modified(ComponentContext context) {
125 + // TODO support dynamic reconfiguration and restarting server?
126 + }
127 +
128 + // RPC Server-side code
129 + // RPC session Factory
130 + /**
131 + * Relays DeviceProviderRegistry calls from RPC client.
132 + */
133 + class DeviceProviderRegistryServerProxy implements DeviceProviderRegistryRpc {
134 +
135 + @Override
136 + public StreamObserver<DeviceProviderServiceMsg> register(StreamObserver<DeviceProviderMsg> toDeviceProvider) {
137 + log.trace("DeviceProviderRegistryServerProxy#register called!");
138 +
139 + DeviceProviderServerProxy provider = new DeviceProviderServerProxy(toDeviceProvider);
140 +
141 + return new DeviceProviderServiceServerProxy(provider, toDeviceProvider);
142 + }
143 + }
144 +
145 + // Lower -> Upper Controller message
146 + // RPC Server-side code
147 + // RPC session handler
148 + private final class DeviceProviderServiceServerProxy
149 + implements StreamObserver<DeviceProviderServiceMsg> {
150 +
151 + // intentionally shadowing
152 + private final Logger log = LoggerFactory.getLogger(getClass());
153 +
154 + private final DeviceProviderServerProxy pairedProvider;
155 + private final StreamObserver<DeviceProviderMsg> toDeviceProvider;
156 +
157 + private final Cache<Integer, CompletableFuture<Boolean>> outstandingIsReachable;
158 +
159 + // wrapped providerService
160 + private DeviceProviderService deviceProviderService;
161 +
162 +
163 + DeviceProviderServiceServerProxy(DeviceProviderServerProxy provider,
164 + StreamObserver<DeviceProviderMsg> toDeviceProvider) {
165 + this.pairedProvider = provider;
166 + this.toDeviceProvider = toDeviceProvider;
167 + outstandingIsReachable = CacheBuilder.newBuilder()
168 + .expireAfterWrite(1, TimeUnit.MINUTES)
169 + .build();
170 +
171 + // pair RPC session in other direction
172 + provider.pair(this);
173 + }
174 +
175 + @Override
176 + public void onNext(DeviceProviderServiceMsg msg) {
177 + try {
178 + log.trace("DeviceProviderServiceServerProxy received: {}", msg);
179 + onMethod(msg);
180 + } catch (Exception e) {
181 + log.error("Exception thrown handling {}", msg, e);
182 + onError(e);
183 + throw e;
184 + }
185 + }
186 +
187 + /**
188 + * Translates received RPC message to {@link DeviceProviderService} method calls.
189 + * @param msg DeviceProviderService message
190 + */
191 + private void onMethod(DeviceProviderServiceMsg msg) {
192 + switch (msg.getMethodCase()) {
193 + case REGISTER_PROVIDER:
194 + RegisterProvider registerProvider = msg.getRegisterProvider();
195 + // TODO Do we care about provider name?
196 + pairedProvider.setProviderId(new ProviderId(registerProvider.getProviderScheme(), RPC_PROVIDER_NAME));
197 + registeredProviders.add(pairedProvider);
198 + deviceProviderService = deviceProviderRegistry.register(pairedProvider);
199 + break;
200 +
201 + case DEVICE_CONNECTED:
202 + DeviceConnected deviceConnected = msg.getDeviceConnected();
203 + deviceProviderService.deviceConnected(deviceId(deviceConnected.getDeviceId()),
204 + translate(deviceConnected.getDeviceDescription()));
205 + break;
206 + case DEVICE_DISCONNECTED:
207 + DeviceDisconnected deviceDisconnected = msg.getDeviceDisconnected();
208 + deviceProviderService.deviceDisconnected(deviceId(deviceDisconnected.getDeviceId()));
209 + break;
210 + case UPDATE_PORTS:
211 + UpdatePorts updatePorts = msg.getUpdatePorts();
212 + deviceProviderService.updatePorts(deviceId(updatePorts.getDeviceId()),
213 + updatePorts.getPortDescriptionsList()
214 + .stream()
215 + .map(GrpcDeviceUtils::translate)
216 + .collect(toList()));
217 + break;
218 + case PORT_STATUS_CHANGED:
219 + PortStatusChanged portStatusChanged = msg.getPortStatusChanged();
220 + deviceProviderService.portStatusChanged(deviceId(portStatusChanged.getDeviceId()),
221 + translate(portStatusChanged.getPortDescription()));
222 + break;
223 + case RECEIVED_ROLE_REPLY:
224 + ReceivedRoleReply receivedRoleReply = msg.getReceivedRoleReply();
225 + deviceProviderService.receivedRoleReply(deviceId(receivedRoleReply.getDeviceId()),
226 + translate(receivedRoleReply.getRequested()),
227 + translate(receivedRoleReply.getResponse()));
228 + break;
229 + case UPDATE_PORT_STATISTICS:
230 + UpdatePortStatistics updatePortStatistics = msg.getUpdatePortStatistics();
231 + deviceProviderService.updatePortStatistics(deviceId(updatePortStatistics.getDeviceId()),
232 + updatePortStatistics.getPortStatisticsList()
233 + .stream()
234 + .map(GrpcDeviceUtils::translate)
235 + .collect(toList()));
236 + break;
237 +
238 + // return value of DeviceProvider#isReachable
239 + case IS_REACHABLE_RESPONSE:
240 + IsReachableResponse isReachableResponse = msg.getIsReachableResponse();
241 + int xid = isReachableResponse.getXid();
242 + boolean isReachable = isReachableResponse.getIsReachable();
243 + CompletableFuture<Boolean> result = outstandingIsReachable.asMap().remove(xid);
244 + if (result != null) {
245 + result.complete(isReachable);
246 + }
247 + break;
248 +
249 + case METHOD_NOT_SET:
250 + default:
251 + log.warn("Unexpected message received {}", msg);
252 + break;
253 + }
254 + }
255 +
256 + @Override
257 + public void onCompleted() {
258 + log.info("DeviceProviderServiceServerProxy completed");
259 + deviceProviderRegistry.unregister(pairedProvider);
260 + registeredProviders.remove(pairedProvider);
261 + toDeviceProvider.onCompleted();
262 + }
263 +
264 + @Override
265 + public void onError(Throwable e) {
266 + log.error("DeviceProviderServiceServerProxy#onError", e);
267 + deviceProviderRegistry.unregister(pairedProvider);
268 + registeredProviders.remove(pairedProvider);
269 + // TODO What is the proper clean up for bi-di stream on error?
270 + // sample suggests no-op
271 + toDeviceProvider.onError(e);
272 + }
273 +
274 +
275 + /**
276 + * Registers Future for {@link DeviceProvider#isReachable(DeviceId)} return value.
277 + * @param xid IsReachable call ID.
278 + * @param reply Future to
279 + */
280 + void register(int xid, CompletableFuture<Boolean> reply) {
281 + outstandingIsReachable.put(xid, reply);
282 + }
283 +
284 + }
285 +
286 + // Upper -> Lower Controller message
287 + /**
288 + * Relay DeviceProvider calls to RPC client.
289 + */
290 + private final class DeviceProviderServerProxy
291 + implements DeviceProvider {
292 +
293 + private final Logger log = LoggerFactory.getLogger(getClass());
294 +
295 + // xid for isReachable calls
296 + private final AtomicInteger xidPool = new AtomicInteger();
297 + private final StreamObserver<DeviceProviderMsg> toDeviceProvider;
298 +
299 + private DeviceProviderServiceServerProxy deviceProviderServiceProxy = null;
300 + private ProviderId providerId;
301 +
302 + DeviceProviderServerProxy(StreamObserver<DeviceProviderMsg> toDeviceProvider) {
303 + this.toDeviceProvider = toDeviceProvider;
304 + }
305 +
306 + void setProviderId(ProviderId pid) {
307 + this.providerId = pid;
308 + }
309 +
310 + /**
311 + * Registers RPC stream in other direction.
312 + * @param deviceProviderServiceProxy {@link DeviceProviderServiceServerProxy}
313 + */
314 + void pair(DeviceProviderServiceServerProxy deviceProviderServiceProxy) {
315 + this.deviceProviderServiceProxy = deviceProviderServiceProxy;
316 + }
317 +
318 + @Override
319 + public void triggerProbe(DeviceId deviceId) {
320 + log.trace("triggerProbe({})", deviceId);
321 + DeviceProviderMsg.Builder msgBuilder = DeviceProviderMsg.newBuilder();
322 + msgBuilder.setTriggerProbe(msgBuilder.getTriggerProbeBuilder()
323 + .setDeviceId(deviceId.toString())
324 + .build());
325 + DeviceProviderMsg triggerProbeMsg = msgBuilder.build();
326 + toDeviceProvider.onNext(triggerProbeMsg);
327 + // TODO Catch Exceptions and call onError()
328 + }
329 +
330 + @Override
331 + public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
332 + log.trace("roleChanged({}, {})", deviceId, newRole);
333 + DeviceProviderMsg.Builder msgBuilder = DeviceProviderMsg.newBuilder();
334 + msgBuilder.setRoleChanged(msgBuilder.getRoleChangedBuilder()
335 + .setDeviceId(deviceId.toString())
336 + .setNewRole(translate(newRole))
337 + .build());
338 + toDeviceProvider.onNext(msgBuilder.build());
339 + // TODO Catch Exceptions and call onError()
340 + }
341 +
342 + @Override
343 + public boolean isReachable(DeviceId deviceId) {
344 + log.trace("isReachable({})", deviceId);
345 + CompletableFuture<Boolean> result = new CompletableFuture<>();
346 + final int xid = xidPool.incrementAndGet();
347 +
348 + DeviceProviderMsg.Builder msgBuilder = DeviceProviderMsg.newBuilder();
349 + msgBuilder.setIsReachableRequest(msgBuilder.getIsReachableRequestBuilder()
350 + .setXid(xid)
351 + .setDeviceId(deviceId.toString())
352 + .build());
353 +
354 + // Associate xid and register above future some where
355 + // in DeviceProviderService channel to receive reply
356 + if (deviceProviderServiceProxy != null) {
357 + deviceProviderServiceProxy.register(xid, result);
358 + }
359 +
360 + // send message down RPC
361 + toDeviceProvider.onNext(msgBuilder.build());
362 +
363 + // wait for reply
364 + try {
365 + return result.get(10, TimeUnit.SECONDS);
366 + } catch (InterruptedException e) {
367 + log.debug("isReachable({}) was Interrupted", deviceId, e);
368 + Thread.currentThread().interrupt();
369 + } catch (TimeoutException e) {
370 + log.warn("isReachable({}) Timed out", deviceId, e);
371 + } catch (ExecutionException e) {
372 + log.error("isReachable({}) Execution failed", deviceId, e);
373 + // close session?
374 + }
375 + return false;
376 + // TODO Catch Exceptions and call onError()
377 + }
378 +
379 + @Override
380 + public ProviderId id() {
381 + return checkNotNull(providerId, "not initialized yet");
382 + }
383 +
384 + }
385 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
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 + */
16 +
17 +/**
18 + * gRPC based RemoteServiceProvider implementation.
19 + */
20 +package org.onosproject.incubator.rpc.grpc;
1 +syntax = "proto3";
2 +option java_package = "org.onosproject.grpc";
3 +
4 +import "Port.proto";
5 +package Device;
6 +
7 +enum DeviceType {
8 + OTHER = 0;
9 + SWITCH = 1;
10 + ROUTER = 2;
11 + ROADM = 3;
12 + OTN = 4;
13 + ROADM_OTN = 5;
14 + FIREWALL = 6;
15 + BALANCER = 7;
16 + IPS = 8;
17 + IDS = 9;
18 + CONTROLLER = 10;
19 + VIRTUAL = 11;
20 + FIBER_SWITCH = 12;
21 + MICROWAVE = 13;
22 +}
23 +
24 +message DeviceDescription {
25 + string device_Uri = 1;
26 + DeviceType type = 2;
27 + string manufacturer = 3;
28 + string hw_version = 4;
29 + string sw_version = 5;
30 + string serial_number = 6;
31 + string chassis_id = 7;
32 + map<string, string> annotations = 8;
33 +}
34 +
35 +enum MastershipRole {
36 + NONE = 0;
37 + MASTER = 1;
38 + STANDBY = 2;
39 +}
40 +
41 +message DeviceConnected {
42 + // DeviceID as String DeviceId#toString
43 + string device_id = 1;
44 + DeviceDescription device_description = 2;
45 +}
46 +
47 +message DeviceDisconnected {
48 + // DeviceID as String DeviceId#toString
49 + string device_id = 1;
50 +}
51 +
52 +message UpdatePorts {
53 + // DeviceID as String DeviceId#toString
54 + string device_id = 1;
55 + repeated Port.PortDescription port_descriptions= 2;
56 +}
57 +
58 +message PortStatusChanged {
59 + // DeviceID as String DeviceId#toString
60 + string device_id = 1;
61 + Port.PortDescription port_description= 2;
62 +}
63 +
64 +message ReceivedRoleReply {
65 + // DeviceID as String DeviceId#toString
66 + string device_id = 1;
67 + MastershipRole requested = 2;
68 + MastershipRole response = 3;
69 +}
70 +
71 +message UpdatePortStatistics {
72 + // DeviceID as String DeviceId#toString
73 + string device_id = 1;
74 + repeated Port.PortStatistics port_statistics = 2;
75 +}
76 +
77 +message RegisterProvider {
78 + // DeviceProvider's ProviderId scheme
79 + string provider_scheme = 1;
80 +}
81 +
82 +message DeviceProviderServiceMsg {
83 + oneof method {
84 + DeviceConnected device_connected= 1;
85 + DeviceDisconnected device_disconnected = 2;
86 + UpdatePorts update_ports= 3;
87 + PortStatusChanged port_status_changed = 4;
88 + ReceivedRoleReply received_role_reply = 5;
89 + UpdatePortStatistics update_port_statistics = 6;
90 +
91 + // This message is for return value of DeviceProvider#isReachable
92 + IsReachableResponse is_reachable_response = 7;
93 +
94 + // This MUST be the 1st message over the stream
95 + RegisterProvider register_provider = 8;
96 + }
97 +}
98 +
99 +message TriggerProbe {
100 + // DeviceID as String DeviceId#toString
101 + string device_id = 1;
102 +}
103 +
104 +message RoleChanged {
105 + // DeviceID as String DeviceId#toString
106 + string device_id = 1;
107 + MastershipRole new_role = 2;
108 +}
109 +
110 +message IsReachableRequest {
111 + int32 xid = 1;
112 + // DeviceID as String DeviceId#toString
113 + string device_id = 2;
114 +}
115 +
116 +message IsReachableResponse {
117 + int32 xid = 1;
118 + bool is_reachable = 2;
119 +}
120 +
121 +message DeviceProviderMsg {
122 + oneof method {
123 + TriggerProbe trigger_probe = 1;
124 + RoleChanged role_changed = 2;
125 + IsReachableRequest is_reachable_request= 3;
126 + }
127 +}
128 +
129 +service DeviceProviderRegistryRpc {
130 + rpc Register(stream DeviceProviderServiceMsg) returns (stream DeviceProviderMsg);
131 +}
1 +syntax = "proto3";
2 +option java_package = "org.onosproject.grpc";
3 +
4 +package Port;
5 +
6 +enum PortType {
7 + // Signifies copper-based connectivity.
8 + COPPER = 0;
9 + // Signifies optical fiber-based connectivity.
10 + FIBER = 1;
11 + // Signifies optical fiber-based packet port.
12 + PACKET = 2;
13 + // Signifies optical fiber-based optical tributary port (called T-port).
14 + //The signal from the client side will be formed into a ITU G.709 (OTN) frame.
15 + ODUCLT = 3;
16 + // Signifies optical fiber-based Line-side port (called L-port).
17 + OCH = 4;
18 + // Signifies optical fiber-based WDM port (called W-port).
19 + //Optical Multiplexing Section (See ITU G.709).
20 + OMS = 5;
21 + // Signifies virtual port.
22 + VIRTUAL = 6;
23 +}
24 +
25 +// TODO What are we going to do with more specific PortDescription ...
26 +message PortDescription {
27 + // PortNumber as String PortNumber#toString
28 + string port_number = 1;
29 + bool is_enabled = 2;
30 + PortType type = 3;
31 + int64 port_speed = 4;
32 + map<string, string> annotations = 8;
33 +}
34 +
35 +message PortStatistics {
36 + int32 port = 1;
37 + int64 packets_received = 2;
38 + int64 packets_sent = 3;
39 + // TODO add all other fields
40 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
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 + */
16 +package org.onosproject.incubator.rpc.grpc;
17 +
18 +import static org.junit.Assert.*;
19 +import static org.onosproject.net.DeviceId.deviceId;
20 +
21 +import java.io.IOException;
22 +import java.net.ServerSocket;
23 +import java.net.URI;
24 +import java.util.Collection;
25 +import java.util.Collections;
26 +import java.util.List;
27 +import java.util.Set;
28 +import java.util.concurrent.CountDownLatch;
29 +import java.util.concurrent.TimeUnit;
30 +
31 +import org.apache.commons.lang3.RandomUtils;
32 +import org.junit.After;
33 +import org.junit.Before;
34 +import org.junit.Test;
35 +import org.onlab.packet.ChassisId;
36 +import org.onosproject.incubator.rpc.RemoteServiceContext;
37 +import org.onosproject.incubator.rpc.RemoteServiceContextProvider;
38 +import org.onosproject.incubator.rpc.RemoteServiceContextProviderService;
39 +import org.onosproject.incubator.rpc.RemoteServiceProviderRegistry;
40 +import org.onosproject.net.DefaultAnnotations;
41 +import org.onosproject.net.Device.Type;
42 +import org.onosproject.net.DeviceId;
43 +import org.onosproject.net.MastershipRole;
44 +import org.onosproject.net.PortNumber;
45 +import org.onosproject.net.SparseAnnotations;
46 +import org.onosproject.net.device.DefaultDeviceDescription;
47 +import org.onosproject.net.device.DefaultPortDescription;
48 +import org.onosproject.net.device.DeviceDescription;
49 +import org.onosproject.net.device.DeviceProvider;
50 +import org.onosproject.net.device.DeviceProviderRegistry;
51 +import org.onosproject.net.device.DeviceProviderService;
52 +import org.onosproject.net.device.PortDescription;
53 +import org.onosproject.net.device.PortStatistics;
54 +import org.onosproject.net.provider.AbstractProviderRegistry;
55 +import org.onosproject.net.provider.AbstractProviderService;
56 +import org.onosproject.net.provider.ProviderId;
57 +import org.slf4j.Logger;
58 +import org.slf4j.LoggerFactory;
59 +
60 +import com.google.common.collect.ImmutableList;
61 +
62 +/**
63 + * Set of tests of the gRPC RemoteService components.
64 + */
65 +public class GrpcRemoteServiceTest {
66 +
67 + private static final DeviceId DEVICE_ID = deviceId("dev:000001");
68 +
69 + private final Logger log = LoggerFactory.getLogger(getClass());
70 +
71 + private static final ProviderId PID = new ProviderId("test", "com.exmaple.test");
72 +
73 + private static final URI DURI = URI.create("dev:000001");
74 +
75 + private static final String MFR = "mfr";
76 +
77 + private static final String HW = "hw";
78 +
79 + private static final String SW = "sw";
80 +
81 + private static final String SN = "serial";
82 +
83 + private static final ChassisId CHASSIS = new ChassisId(42);
84 +
85 + private static final SparseAnnotations ANON = DefaultAnnotations.builder()
86 + .set("foo", "var")
87 + .build();
88 +
89 + private static final PortNumber PORT = PortNumber.portNumber(99);
90 +
91 + private static final DeviceDescription DDESC
92 + = new DefaultDeviceDescription(DURI, Type.SWITCH, MFR, HW, SW, SN,
93 + CHASSIS, ANON);
94 +
95 + private GrpcRemoteServiceServer server;
96 + private GrpcRemoteServiceProvider client;
97 +
98 + private DeviceProvider svSideDeviceProvider;
99 +
100 + private MTestDeviceProviderService svDeviceProviderService;
101 +
102 + private CountDownLatch serverReady;
103 +
104 + private URI uri;
105 +
106 + public static int pickListenPort() {
107 + try {
108 + // pick unused port
109 + ServerSocket socket = new ServerSocket(0);
110 + int port = socket.getLocalPort();
111 + socket.close();
112 + return port;
113 + } catch (IOException e) {
114 + // something went wrong, try picking randomly
115 + return RandomUtils.nextInt(49152, 0xFFFF + 1);
116 + }
117 + }
118 +
119 + @Before
120 + public void setUp() throws Exception {
121 + serverReady = new CountDownLatch(1);
122 + server = new GrpcRemoteServiceServer();
123 + server.deviceProviderRegistry = new MTestDeviceProviderRegistry();
124 + // todo: pass proper ComponentContext
125 + server.listenPort = pickListenPort();
126 + uri = URI.create("grpc://localhost:" + server.listenPort);
127 + server.activate(null);
128 +
129 + client = new GrpcRemoteServiceProvider();
130 + client.rpcRegistry = new NoOpRemoteServiceProviderRegistry();
131 + client.activate();
132 + }
133 +
134 + @After
135 + public void tearDown() {
136 + client.deactivate();
137 + server.deactivate();
138 + }
139 +
140 + private static void assertEqualsButNotSame(Object expected, Object actual) {
141 + assertEquals(expected, actual);
142 + assertNotSame("Cannot be same instance if it properly went through gRPC",
143 + expected, actual);
144 + }
145 +
146 + @Test
147 + public void basics() throws InterruptedException {
148 + RemoteServiceContext remoteServiceContext = client.get(uri);
149 + assertNotNull(remoteServiceContext);
150 +
151 + DeviceProviderRegistry deviceProviderRegistry = remoteServiceContext.get(DeviceProviderRegistry.class);
152 + assertNotNull(deviceProviderRegistry);
153 +
154 + CTestDeviceProvider clDeviceProvider = new CTestDeviceProvider();
155 + DeviceProviderService clDeviceProviderService = deviceProviderRegistry.register(clDeviceProvider);
156 +
157 + assertTrue(serverReady.await(10, TimeUnit.SECONDS));
158 +
159 + // client to server communication
160 + clDeviceProviderService.deviceConnected(DEVICE_ID, DDESC);
161 + assertTrue(svDeviceProviderService.deviceConnected.await(10, TimeUnit.SECONDS));
162 + assertEqualsButNotSame(DEVICE_ID, svDeviceProviderService.deviceConnectedDid);
163 + assertEqualsButNotSame(DDESC, svDeviceProviderService.deviceConnectedDesc);
164 +
165 + PortDescription portDescription = new DefaultPortDescription(PORT, true, ANON);
166 + List<PortDescription> portDescriptions = ImmutableList.of(portDescription);
167 + clDeviceProviderService.updatePorts(DEVICE_ID, portDescriptions);
168 + assertTrue(svDeviceProviderService.updatePorts.await(10, TimeUnit.SECONDS));
169 + assertEqualsButNotSame(DEVICE_ID, svDeviceProviderService.updatePortsDid);
170 + assertEqualsButNotSame(portDescriptions, svDeviceProviderService.updatePortsDescs);
171 +
172 + MastershipRole cRole = MastershipRole.MASTER;
173 + MastershipRole dRole = MastershipRole.STANDBY;
174 + clDeviceProviderService.receivedRoleReply(DEVICE_ID, cRole, dRole);
175 + assertTrue(svDeviceProviderService.receivedRoleReply.await(10, TimeUnit.SECONDS));
176 + assertEqualsButNotSame(DEVICE_ID, svDeviceProviderService.receivedRoleReplyDid);
177 + assertEquals(cRole, svDeviceProviderService.receivedRoleReplyRequested);
178 + assertEquals(dRole, svDeviceProviderService.receivedRoleReplyResponse);
179 +
180 + clDeviceProviderService.portStatusChanged(DEVICE_ID, portDescription);
181 + assertTrue(svDeviceProviderService.portStatusChanged.await(10, TimeUnit.SECONDS));
182 + assertEqualsButNotSame(DEVICE_ID, svDeviceProviderService.portStatusChangedDid);
183 + assertEqualsButNotSame(portDescription, svDeviceProviderService.portStatusChangedDesc);
184 +
185 + Collection<PortStatistics> portStatistics = Collections.emptyList();
186 + clDeviceProviderService.updatePortStatistics(DEVICE_ID, portStatistics);
187 + assertTrue(svDeviceProviderService.updatePortStatistics.await(10, TimeUnit.SECONDS));
188 + assertEqualsButNotSame(DEVICE_ID, svDeviceProviderService.updatePortStatisticsDid);
189 + assertEqualsButNotSame(portStatistics, svDeviceProviderService.updatePortStatisticsStats);
190 +
191 + clDeviceProviderService.deviceDisconnected(DEVICE_ID);
192 + assertTrue(svDeviceProviderService.deviceDisconnected.await(10, TimeUnit.SECONDS));
193 + assertEqualsButNotSame(DEVICE_ID, svDeviceProviderService.deviceDisconnectedDid);
194 +
195 +
196 +
197 + // server to client communication
198 + svSideDeviceProvider.triggerProbe(DEVICE_ID);
199 + assertTrue(clDeviceProvider.triggerProbe.await(10, TimeUnit.SECONDS));
200 + assertEquals(DEVICE_ID, clDeviceProvider.triggerProbeDid);
201 + assertNotSame("Cannot be same instance if it properly went through gRPC",
202 + DEVICE_ID, clDeviceProvider.triggerProbeDid);
203 +
204 + svSideDeviceProvider.roleChanged(DEVICE_ID, MastershipRole.STANDBY);
205 + assertTrue(clDeviceProvider.roleChanged.await(10, TimeUnit.SECONDS));
206 + assertEquals(DEVICE_ID, clDeviceProvider.roleChangedDid);
207 + assertNotSame("Cannot be same instance if it properly went through gRPC",
208 + DEVICE_ID, clDeviceProvider.roleChangedDid);
209 + assertEquals(MastershipRole.STANDBY, clDeviceProvider.roleChangedNewRole);
210 +
211 + clDeviceProvider.isReachableReply = false;
212 + assertEquals(clDeviceProvider.isReachableReply,
213 + svSideDeviceProvider.isReachable(DEVICE_ID));
214 + assertTrue(clDeviceProvider.isReachable.await(10, TimeUnit.SECONDS));
215 + assertEquals(DEVICE_ID, clDeviceProvider.isReachableDid);
216 + assertNotSame("Cannot be same instance if it properly went through gRPC",
217 + DEVICE_ID, clDeviceProvider.isReachableDid);
218 + }
219 +
220 + /**
221 + * Device Provider on CO side.
222 + */
223 + public class CTestDeviceProvider implements DeviceProvider {
224 +
225 + final CountDownLatch triggerProbe = new CountDownLatch(1);
226 + DeviceId triggerProbeDid;
227 +
228 + final CountDownLatch roleChanged = new CountDownLatch(1);
229 + DeviceId roleChangedDid;
230 + MastershipRole roleChangedNewRole;
231 +
232 + final CountDownLatch isReachable = new CountDownLatch(1);
233 + DeviceId isReachableDid;
234 + boolean isReachableReply = false;
235 +
236 + @Override
237 + public ProviderId id() {
238 + return PID;
239 + }
240 +
241 + @Override
242 + public void triggerProbe(DeviceId deviceId) {
243 + log.info("triggerProbe({}) on Client called", deviceId);
244 + triggerProbeDid = deviceId;
245 + triggerProbe.countDown();
246 + }
247 +
248 + @Override
249 + public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
250 + log.info("roleChanged({},{}) on Client called", deviceId, newRole);
251 + roleChangedDid = deviceId;
252 + roleChangedNewRole = newRole;
253 + roleChanged.countDown();
254 + }
255 +
256 + @Override
257 + public boolean isReachable(DeviceId deviceId) {
258 + log.info("isReachable({}) on Client called", deviceId);
259 + isReachableDid = deviceId;
260 + isReachable.countDown();
261 + return isReachableReply;
262 + }
263 +
264 + }
265 +
266 + class NoOpRemoteServiceProviderRegistry
267 + implements RemoteServiceProviderRegistry {
268 +
269 + @Override
270 + public RemoteServiceContextProviderService register(RemoteServiceContextProvider provider) {
271 + return new RemoteServiceContextProviderService() {
272 +
273 + @Override
274 + public RemoteServiceContextProvider provider() {
275 + return provider;
276 + }
277 + };
278 + }
279 +
280 + @Override
281 + public void unregister(RemoteServiceContextProvider provider) {
282 + }
283 +
284 + @Override
285 + public Set<ProviderId> getProviders() {
286 + return Collections.emptySet();
287 + }
288 + }
289 +
290 + /**
291 + * DeviceProvider on Metro side.
292 + */
293 + public class MTestDeviceProviderRegistry
294 + extends AbstractProviderRegistry<DeviceProvider, DeviceProviderService>
295 + implements DeviceProviderRegistry {
296 +
297 + @Override
298 + protected DeviceProviderService createProviderService(DeviceProvider provider) {
299 + log.info("createProviderService({})", provider);
300 + svSideDeviceProvider = provider;
301 + svDeviceProviderService = new MTestDeviceProviderService(provider);
302 + serverReady.countDown();
303 + return svDeviceProviderService;
304 + }
305 +
306 + }
307 +
308 + private final class MTestDeviceProviderService
309 + extends AbstractProviderService<DeviceProvider>
310 + implements DeviceProviderService {
311 +
312 + public MTestDeviceProviderService(DeviceProvider provider) {
313 + super(provider);
314 + }
315 +
316 +
317 + final CountDownLatch deviceConnected = new CountDownLatch(1);
318 + DeviceId deviceConnectedDid;
319 + DeviceDescription deviceConnectedDesc;
320 +
321 + @Override
322 + public void deviceConnected(DeviceId deviceId,
323 + DeviceDescription deviceDescription) {
324 + log.info("deviceConnected({}, {}) on Server called", deviceId, deviceDescription);
325 + deviceConnectedDid = deviceId;
326 + deviceConnectedDesc = deviceDescription;
327 + deviceConnected.countDown();
328 + }
329 +
330 +
331 + final CountDownLatch updatePorts = new CountDownLatch(1);
332 + DeviceId updatePortsDid;
333 + List<PortDescription> updatePortsDescs;
334 +
335 + @Override
336 + public void updatePorts(DeviceId deviceId,
337 + List<PortDescription> portDescriptions) {
338 + log.info("updatePorts({}, {}) on Server called", deviceId, portDescriptions);
339 + updatePortsDid = deviceId;
340 + updatePortsDescs = portDescriptions;
341 + updatePorts.countDown();
342 + }
343 +
344 + final CountDownLatch receivedRoleReply = new CountDownLatch(1);
345 + DeviceId receivedRoleReplyDid;
346 + MastershipRole receivedRoleReplyRequested;
347 + MastershipRole receivedRoleReplyResponse;
348 +
349 + @Override
350 + public void receivedRoleReply(DeviceId deviceId, MastershipRole requested,
351 + MastershipRole response) {
352 + log.info("receivedRoleReply({}, {}, {}) on Server called", deviceId, requested, response);
353 + receivedRoleReplyDid = deviceId;
354 + receivedRoleReplyRequested = requested;
355 + receivedRoleReplyResponse = response;
356 + receivedRoleReply.countDown();
357 + }
358 +
359 + final CountDownLatch portStatusChanged = new CountDownLatch(1);
360 + DeviceId portStatusChangedDid;
361 + PortDescription portStatusChangedDesc;
362 +
363 +
364 + @Override
365 + public void portStatusChanged(DeviceId deviceId,
366 + PortDescription portDescription) {
367 + log.info("portStatusChanged({}, {}) on Server called", deviceId, portDescription);
368 + portStatusChangedDid = deviceId;
369 + portStatusChangedDesc = portDescription;
370 + portStatusChanged.countDown();
371 + }
372 +
373 + final CountDownLatch updatePortStatistics = new CountDownLatch(1);
374 + DeviceId updatePortStatisticsDid;
375 + Collection<PortStatistics> updatePortStatisticsStats;
376 +
377 +
378 + @Override
379 + public void updatePortStatistics(DeviceId deviceId,
380 + Collection<PortStatistics> portStatistics) {
381 + log.info("updatePortStatistics({}, {}) on Server called", deviceId, portStatistics);
382 + updatePortStatisticsDid = deviceId;
383 + updatePortStatisticsStats = portStatistics;
384 + updatePortStatistics.countDown();
385 + }
386 +
387 + final CountDownLatch deviceDisconnected = new CountDownLatch(1);
388 + DeviceId deviceDisconnectedDid;
389 +
390 + @Override
391 + public void deviceDisconnected(DeviceId deviceId) {
392 + log.info("deviceDisconnected({}) on Server called", deviceId);
393 + deviceDisconnectedDid = deviceId;
394 + deviceDisconnected.countDown();
395 + }
396 + }
397 +
398 +}