Thomas Vachuska

Added a REST command to upload topology configuration.

...@@ -88,7 +88,6 @@ ...@@ -88,7 +88,6 @@
88 <version>18.0</version> 88 <version>18.0</version>
89 </dependency> 89 </dependency>
90 90
91 -
92 <dependency> 91 <dependency>
93 <groupId>io.netty</groupId> 92 <groupId>io.netty</groupId>
94 <artifactId>netty</artifactId> 93 <artifactId>netty</artifactId>
......
...@@ -7,4 +7,4 @@ export OC1="192.168.56.101" ...@@ -7,4 +7,4 @@ export OC1="192.168.56.101"
7 export OCN="192.168.56.103" 7 export OCN="192.168.56.103"
8 export OCI="${OC1}" 8 export OCI="${OC1}"
9 9
10 -export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core-trivial,onos-cli,onos-openflow,onos-app-fwd,onos-app-proxyarp,onos-app-tvue}" 10 +export ONOS_FEATURES="${ONOS_FEATURES:-webconsole,onos-api,onos-core-trivial,onos-cli,onos-rest,onos-openflow,onos-app-fwd,onos-app-proxyarp,onos-app-tvue}"
......
1 +{
2 + "devices" : [
3 + {
4 + "uri": "of:0000ffffffffff01", "mac": "ffffffffffff01", "type": "ROADM",
5 + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
6 + "annotations": { "latitude": 37.6, "longitude": 122.3, "optical.regens": 0 }
7 + },
8 + {
9 + "uri": "of:0000ffffffffff02", "mac": "ffffffffffff02", "type": "ROADM",
10 + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
11 + "annotations": { "latitude": 37.3, "longitude": 121.9, "optical.regens": 0 }
12 + },
13 + {
14 + "uri": "of:0000ffffffffff03", "mac": "ffffffffffff03", "type": "ROADM",
15 + "mfr": "Linc", "hw": "OE", "sw": "?", "serial": "?",
16 + "annotations": { "latitude": 33.9, "longitude": 118.4, "optical.regens": 2 }
17 + },
18 +
19 + {
20 + "uri": "of:0000ffffffff0001", "mac": "ffffffffff0003", "type": "SWITCH",
21 + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?",
22 + "annotations": { "latitude": 37.6, "longitude": 122.3 }
23 + },
24 + {
25 + "uri": "of:0000ffffffff0002", "mac": "ffffffffff0002", "type": "SWITCH",
26 + "mfr": "Linc", "hw": "PK", "sw": "?", "serial": "?",
27 + "annotations": { "latitude": 37.3, "longitude": 121.9 }
28 + }
29 + ],
30 +
31 + "links" : [
32 + { "src": "of:0000ffffffffff01/10", "dst": "of:0000ffffffffff03/30", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM" } },
33 + { "src": "of:0000ffffffffff02/20", "dst": "of:0000ffffffffff03/31", "type": "OPTICAL", "annotations": { "optical.waves": 80, "optical.type": "WDM" } },
34 +
35 + { "src": "of:0000ffffffff0001/10", "dst": "of:0000ffffffffff01/11", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } },
36 + { "src": "of:0000ffffffff0002/10", "dst": "of:0000ffffffffff02/21", "type": "OPTICAL", "annotations": { "bandwidth": 100000, "optical.type": "cross-connect" } }
37 + ],
38 +
39 + "hosts" : [
40 + { "mac": "a0:00:00:00:00:11", "vlan": -1, "location": "of:0000ffffffff0001/11", "ip": "1.2.3.4" },
41 + { "mac": "a0:00:00:00:00:12", "vlan": -1, "location": "of:0000ffffffff0001/12", "ip": "1.2.3.5" },
42 + { "mac": "a0:00:00:00:00:21", "vlan": -1, "location": "of:0000ffffffff0002/11", "ip": "2.2.3.4" },
43 + { "mac": "a0:00:00:00:00:22", "vlan": -1, "location": "of:0000ffffffff0002/12", "ip": "2.2.3.5" }
44 + ]
45 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -32,7 +32,7 @@ public final class ChassisId { ...@@ -32,7 +32,7 @@ public final class ChassisId {
32 * @param value the value to use. 32 * @param value the value to use.
33 */ 33 */
34 public ChassisId(String value) { 34 public ChassisId(String value) {
35 - this.value = Long.valueOf(value); 35 + this.value = Long.valueOf(value, 16);
36 } 36 }
37 37
38 /** 38 /**
......
...@@ -23,12 +23,6 @@ ...@@ -23,12 +23,6 @@
23 <version>1.0.0-SNAPSHOT</version> 23 <version>1.0.0-SNAPSHOT</version>
24 <scope>test</scope> 24 <scope>test</scope>
25 </dependency> 25 </dependency>
26 - <dependency>
27 - <groupId>com.google.guava</groupId>
28 - <artifactId>guava</artifactId>
29 - <scope>test</scope>
30 - </dependency>
31 -
32 </dependencies> 26 </dependencies>
33 27
34 <properties> 28 <properties>
......
1 +/*
2 + * Licensed to the Apache Software Foundation (ASF) under one
3 + * or more contributor license agreements. See the NOTICE file
4 + * distributed with this work for additional information
5 + * regarding copyright ownership. The ASF licenses this file
6 + * to you under the Apache License, Version 2.0 (the
7 + * "License"); you may not use this file except in compliance
8 + * with the License. You may obtain a copy of the License at
9 + *
10 + * http://www.apache.org/licenses/LICENSE-2.0
11 + *
12 + * Unless required by applicable law or agreed to in writing,
13 + * software distributed under the License is distributed on an
14 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 + * KIND, either express or implied. See the License for the
16 + * specific language governing permissions and limitations
17 + * under the License.
18 + */
19 +package org.onlab.onos.rest;
20 +
21 +import com.fasterxml.jackson.databind.JsonNode;
22 +import org.onlab.onos.net.ConnectPoint;
23 +import org.onlab.onos.net.DefaultAnnotations;
24 +import org.onlab.onos.net.Device;
25 +import org.onlab.onos.net.Host;
26 +import org.onlab.onos.net.HostId;
27 +import org.onlab.onos.net.HostLocation;
28 +import org.onlab.onos.net.Link;
29 +import org.onlab.onos.net.MastershipRole;
30 +import org.onlab.onos.net.SparseAnnotations;
31 +import org.onlab.onos.net.device.DefaultDeviceDescription;
32 +import org.onlab.onos.net.device.DeviceDescription;
33 +import org.onlab.onos.net.device.DeviceProvider;
34 +import org.onlab.onos.net.device.DeviceProviderRegistry;
35 +import org.onlab.onos.net.device.DeviceProviderService;
36 +import org.onlab.onos.net.host.DefaultHostDescription;
37 +import org.onlab.onos.net.host.HostProvider;
38 +import org.onlab.onos.net.host.HostProviderRegistry;
39 +import org.onlab.onos.net.host.HostProviderService;
40 +import org.onlab.onos.net.link.DefaultLinkDescription;
41 +import org.onlab.onos.net.link.LinkProvider;
42 +import org.onlab.onos.net.link.LinkProviderRegistry;
43 +import org.onlab.onos.net.link.LinkProviderService;
44 +import org.onlab.onos.net.provider.ProviderId;
45 +import org.onlab.packet.ChassisId;
46 +import org.onlab.packet.IpPrefix;
47 +import org.onlab.packet.MacAddress;
48 +import org.onlab.packet.VlanId;
49 +
50 +import java.net.URI;
51 +import java.util.Iterator;
52 +
53 +import static com.google.common.base.Preconditions.checkNotNull;
54 +import static org.onlab.onos.net.DeviceId.deviceId;
55 +import static org.onlab.onos.net.PortNumber.portNumber;
56 +
57 +/**
58 + * Provider of devices and links parsed from a JSON configuration structure.
59 + */
60 +class ConfigProvider implements DeviceProvider, LinkProvider, HostProvider {
61 +
62 + private static final ProviderId PID =
63 + new ProviderId("cfg", "org.onlab.onos.rest", true);
64 +
65 + private final JsonNode cfg;
66 + private final DeviceProviderRegistry deviceProviderRegistry;
67 + private final LinkProviderRegistry linkProviderRegistry;
68 + private final HostProviderRegistry hostProviderRegistry;
69 +
70 + /**
71 + * Creates a new configuration provider.
72 + *
73 + * @param cfg JSON configuration
74 + * @param deviceProviderRegistry device provider registry
75 + * @param linkProviderRegistry link provider registry
76 + * @param hostProviderRegistry host provider registry
77 + */
78 + ConfigProvider(JsonNode cfg,
79 + DeviceProviderRegistry deviceProviderRegistry,
80 + LinkProviderRegistry linkProviderRegistry,
81 + HostProviderRegistry hostProviderRegistry) {
82 + this.cfg = checkNotNull(cfg, "Configuration cannot be null");
83 + this.deviceProviderRegistry = checkNotNull(deviceProviderRegistry, "Device provider registry cannot be null");
84 + this.linkProviderRegistry = checkNotNull(linkProviderRegistry, "Link provider registry cannot be null");
85 + this.hostProviderRegistry = checkNotNull(hostProviderRegistry, "Host provider registry cannot be null");
86 + }
87 +
88 + /**
89 + * Parses the given JSON and provides links as configured.
90 + */
91 + void parse() {
92 + parseDevices();
93 + parseLinks();
94 + parseHosts();
95 + }
96 +
97 + // Parses the given JSON and provides devices.
98 + private void parseDevices() {
99 + try {
100 + DeviceProviderService dps = deviceProviderRegistry.register(this);
101 + JsonNode nodes = cfg.get("devices");
102 + if (nodes != null) {
103 + for (JsonNode node : nodes) {
104 + parseDevice(dps, node);
105 + }
106 + }
107 + } finally {
108 + deviceProviderRegistry.unregister(this);
109 + }
110 + }
111 +
112 + // Parses the given node with device data and supplies the device.
113 + private void parseDevice(DeviceProviderService dps, JsonNode node) {
114 + URI uri = URI.create(get(node, "uri"));
115 + Device.Type type = Device.Type.valueOf(get(node, "type"));
116 + String mfr = get(node, "mfr");
117 + String hw = get(node, "hw");
118 + String sw = get(node, "sw");
119 + String serial = get(node, "serial");
120 + ChassisId cid = new ChassisId(get(node, "mac"));
121 + SparseAnnotations annotations = annotations(node.get("annotations"));
122 +
123 + DeviceDescription desc =
124 + new DefaultDeviceDescription(uri, type, mfr, hw, sw, serial,
125 + cid, annotations);
126 + dps.deviceConnected(deviceId(uri), desc);
127 + }
128 +
129 + // Parses the given JSON and provides links as configured.
130 + private void parseLinks() {
131 + try {
132 + LinkProviderService lps = linkProviderRegistry.register(this);
133 + JsonNode nodes = cfg.get("links");
134 + if (nodes != null) {
135 + for (JsonNode node : nodes) {
136 + parseLink(lps, node, false);
137 + if (!node.has("halfplex")) {
138 + parseLink(lps, node, true);
139 + }
140 + }
141 + }
142 + } finally {
143 + linkProviderRegistry.unregister(this);
144 + }
145 + }
146 +
147 + // Parses the given node with link data and supplies the link.
148 + private void parseLink(LinkProviderService lps, JsonNode node, boolean reverse) {
149 + ConnectPoint src = connectPoint(get(node, "src"));
150 + ConnectPoint dst = connectPoint(get(node, "dst"));
151 + Link.Type type = Link.Type.valueOf(get(node, "type"));
152 + SparseAnnotations annotations = annotations(node.get("annotations"));
153 +
154 + DefaultLinkDescription desc = reverse ?
155 + new DefaultLinkDescription(dst, src, type, annotations) :
156 + new DefaultLinkDescription(src, dst, type, annotations);
157 + lps.linkDetected(desc);
158 + }
159 +
160 + // Parses the given JSON and provides hosts as configured.
161 + private void parseHosts() {
162 + try {
163 + HostProviderService hps = hostProviderRegistry.register(this);
164 + JsonNode nodes = cfg.get("hosts");
165 + if (nodes != null) {
166 + for (JsonNode node : nodes) {
167 + parseHost(hps, node);
168 + }
169 + }
170 + } finally {
171 + hostProviderRegistry.unregister(this);
172 + }
173 + }
174 +
175 + // Parses the given node with host data and supplies the host.
176 + private void parseHost(HostProviderService hps, JsonNode node) {
177 + MacAddress mac = MacAddress.valueOf(get(node, "mac"));
178 + VlanId vlanId = VlanId.vlanId(node.get("vlan").shortValue());
179 + HostId hostId = HostId.hostId(mac, vlanId);
180 + SparseAnnotations annotations = annotations(node.get("annotations"));
181 + HostLocation location = new HostLocation(connectPoint(get(node, "location")), 0);
182 + IpPrefix ip = IpPrefix.valueOf(get(node, "ip"));
183 +
184 + DefaultHostDescription desc =
185 + new DefaultHostDescription(mac, vlanId, location, ip, annotations);
186 + hps.hostDetected(hostId, desc);
187 + }
188 +
189 + // Produces set of annotations from the given JSON node.
190 + private SparseAnnotations annotations(JsonNode node) {
191 + if (node == null) {
192 + return null;
193 + }
194 +
195 + DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
196 + Iterator<String> it = node.fieldNames();
197 + while (it.hasNext()) {
198 + String k = it.next();
199 + builder.set(k, node.get(k).asText());
200 + }
201 + return builder.build();
202 + }
203 +
204 + // Produces a connection point from the specified uri/port text.
205 + private ConnectPoint connectPoint(String text) {
206 + int i = text.lastIndexOf("/");
207 + return new ConnectPoint(deviceId(text.substring(0, i)),
208 + portNumber(text.substring(i + 1)));
209 + }
210 +
211 + // Returns string form of the named property in the given JSON object.
212 + private String get(JsonNode node, String name) {
213 + return node.path(name).asText();
214 + }
215 +
216 + @Override
217 + public void triggerProbe(Device device) {
218 + }
219 +
220 + @Override
221 + public void roleChanged(Device device, MastershipRole newRole) {
222 + }
223 +
224 + @Override
225 + public void triggerProbe(Host host) {
226 + }
227 +
228 + @Override
229 + public ProviderId id() {
230 + return PID;
231 + }
232 +}
1 +/*
2 + * Licensed to the Apache Software Foundation (ASF) under one
3 + * or more contributor license agreements. See the NOTICE file
4 + * distributed with this work for additional information
5 + * regarding copyright ownership. The ASF licenses this file
6 + * to you under the Apache License, Version 2.0 (the
7 + * "License"); you may not use this file except in compliance
8 + * with the License. You may obtain a copy of the License at
9 + *
10 + * http://www.apache.org/licenses/LICENSE-2.0
11 + *
12 + * Unless required by applicable law or agreed to in writing,
13 + * software distributed under the License is distributed on an
14 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 + * KIND, either express or implied. See the License for the
16 + * specific language governing permissions and limitations
17 + * under the License.
18 + */
19 +package org.onlab.onos.rest;
20 +
21 +import com.fasterxml.jackson.databind.JsonNode;
22 +import com.fasterxml.jackson.databind.ObjectMapper;
23 +import org.onlab.onos.net.device.DeviceProviderRegistry;
24 +import org.onlab.onos.net.host.HostProviderRegistry;
25 +import org.onlab.onos.net.link.LinkProviderRegistry;
26 +import org.onlab.rest.BaseResource;
27 +
28 +import javax.ws.rs.Consumes;
29 +import javax.ws.rs.POST;
30 +import javax.ws.rs.Path;
31 +import javax.ws.rs.Produces;
32 +import javax.ws.rs.core.MediaType;
33 +import javax.ws.rs.core.Response;
34 +import java.io.IOException;
35 +import java.io.InputStream;
36 +
37 +/**
38 + * Resource that acts as an ancillary provider for uploading pre-configured
39 + * devices, ports and links.
40 + */
41 +@Path("config")
42 +public class ConfigResource extends BaseResource {
43 +
44 + @POST
45 + @Path("topology")
46 + @Consumes(MediaType.APPLICATION_JSON)
47 + @Produces(MediaType.APPLICATION_JSON)
48 + public Response topology(InputStream input) throws IOException {
49 + ObjectMapper mapper = new ObjectMapper();
50 + JsonNode cfg = mapper.readTree(input);
51 + new ConfigProvider(cfg, get(DeviceProviderRegistry.class),
52 + get(LinkProviderRegistry.class),
53 + get(HostProviderRegistry.class)).parse();
54 + return Response.ok(mapper.createObjectNode().toString()).build();
55 + }
56 +
57 +}
1 +{
2 + "devices" : [
3 + {
4 + "uri": "of:00000000000001", "type": "ROADM", "mfr": "Foo, Inc.", "hw": "Alpha", "sw": "1.2.3",
5 + "serial": "ab321", "mac": "00000000000001", "annotations": {"foo": "bar"},
6 + "ports": []
7 + },
8 + {
9 + "uri": "of:00000000000002", "type": "ROADM", "mfr": "Foo, Inc.", "hw": "Alpha", "sw": "1.2.3",
10 + "serial": "ab456", "mac": "00000000000002", "annotations": {"foo": "bar"},
11 + "ports": []
12 + }
13 + ],
14 +
15 + "links" : [
16 + { "src": "of:00000000000001/1", "dst": "of:00000000000002/1", "type": "OPTICAL" },
17 + { "src": "of:00000000000002/1", "dst": "of:00000000000001/1", "type": "OPTICAL" }
18 + ]
19 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -44,6 +44,11 @@ ...@@ -44,6 +44,11 @@
44 </dependency> 44 </dependency>
45 45
46 <dependency> 46 <dependency>
47 + <groupId>com.google.guava</groupId>
48 + <artifactId>guava</artifactId>
49 + </dependency>
50 +
51 + <dependency>
47 <groupId>com.sun.jersey</groupId> 52 <groupId>com.sun.jersey</groupId>
48 <artifactId>jersey-servlet</artifactId> 53 <artifactId>jersey-servlet</artifactId>
49 </dependency> 54 </dependency>
...@@ -93,6 +98,7 @@ ...@@ -93,6 +98,7 @@
93 ${project.groupId}.${project.artifactId} 98 ${project.groupId}.${project.artifactId}
94 </Bundle-SymbolicName> 99 </Bundle-SymbolicName>
95 <Import-Package> 100 <Import-Package>
101 + org.slf4j,
96 org.osgi.framework, 102 org.osgi.framework,
97 javax.ws.rs,javax.ws.rs.core, 103 javax.ws.rs,javax.ws.rs.core,
98 com.sun.jersey.api.core, 104 com.sun.jersey.api.core,
...@@ -100,6 +106,8 @@ ...@@ -100,6 +106,8 @@
100 com.sun.jersey.server.impl.container.servlet, 106 com.sun.jersey.server.impl.container.servlet,
101 com.fasterxml.jackson.databind, 107 com.fasterxml.jackson.databind,
102 com.fasterxml.jackson.databind.node, 108 com.fasterxml.jackson.databind.node,
109 + com.google.common.base.*,
110 + org.onlab.packet.*,
103 org.onlab.rest.*, 111 org.onlab.rest.*,
104 org.onlab.onos.* 112 org.onlab.onos.*
105 </Import-Package> 113 </Import-Package>
......