Kedar Gupta
Committed by Gerrit Code Review

Add POST method for the Host REST API and fix minor documentation errors

Change-Id: I598ace5a94f83f010fdde1b3ad43b90f762a9d33
...@@ -61,9 +61,9 @@ public final class HostId extends ElementId { ...@@ -61,9 +61,9 @@ public final class HostId extends ElementId {
61 } 61 }
62 62
63 /** 63 /**
64 - * Returns the host MAC address. 64 + * Returns the host vlan Id.
65 * 65 *
66 - * @return MAC address 66 + * @return vlan Id
67 */ 67 */
68 public VlanId vlanId() { 68 public VlanId vlanId() {
69 return vlanId; 69 return vlanId;
......
...@@ -25,7 +25,7 @@ public interface HostProviderService extends ProviderService<HostProvider> { ...@@ -25,7 +25,7 @@ public interface HostProviderService extends ProviderService<HostProvider> {
25 25
26 /** 26 /**
27 * Notifies the core when a host has been detected on a network along with 27 * Notifies the core when a host has been detected on a network along with
28 - * information that identifies the hoot location. 28 + * information that identifies the host location.
29 * 29 *
30 * @param hostId id of the host that been detected 30 * @param hostId id of the host that been detected
31 * @param hostDescription description of host and its location 31 * @param hostDescription description of host and its location
......
...@@ -15,17 +15,42 @@ ...@@ -15,17 +15,42 @@
15 */ 15 */
16 package org.onosproject.rest.resources; 16 package org.onosproject.rest.resources;
17 17
18 +import com.fasterxml.jackson.databind.JsonNode;
18 import com.fasterxml.jackson.databind.node.ObjectNode; 19 import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import org.onlab.packet.IpAddress;
21 +import org.onlab.packet.MacAddress;
22 +import org.onlab.packet.VlanId;
23 +import org.onosproject.net.ConnectPoint;
24 +import org.onosproject.net.DefaultAnnotations;
19 import org.onosproject.net.Host; 25 import org.onosproject.net.Host;
26 +import org.onosproject.net.HostId;
27 +import org.onosproject.net.HostLocation;
28 +import org.onosproject.net.SparseAnnotations;
29 +import org.onosproject.net.host.DefaultHostDescription;
30 +import org.onosproject.net.host.HostProvider;
31 +import org.onosproject.net.host.HostProviderRegistry;
32 +import org.onosproject.net.host.HostProviderService;
20 import org.onosproject.net.host.HostService; 33 import org.onosproject.net.host.HostService;
34 +import org.onosproject.net.provider.ProviderId;
21 import org.onosproject.rest.AbstractWebResource; 35 import org.onosproject.rest.AbstractWebResource;
22 36
37 +import javax.ws.rs.Consumes;
23 import javax.ws.rs.GET; 38 import javax.ws.rs.GET;
39 +import javax.ws.rs.POST;
24 import javax.ws.rs.Path; 40 import javax.ws.rs.Path;
25 import javax.ws.rs.PathParam; 41 import javax.ws.rs.PathParam;
26 import javax.ws.rs.Produces; 42 import javax.ws.rs.Produces;
43 +import javax.ws.rs.core.Context;
27 import javax.ws.rs.core.MediaType; 44 import javax.ws.rs.core.MediaType;
28 import javax.ws.rs.core.Response; 45 import javax.ws.rs.core.Response;
46 +import javax.ws.rs.core.UriBuilder;
47 +import javax.ws.rs.core.UriInfo;
48 +import java.io.IOException;
49 +import java.io.InputStream;
50 +import java.net.URI;
51 +import java.util.HashSet;
52 +import java.util.Iterator;
53 +import java.util.Set;
29 54
30 import static org.onlab.util.Tools.nullIsNotFound; 55 import static org.onlab.util.Tools.nullIsNotFound;
31 import static org.onosproject.net.HostId.hostId; 56 import static org.onosproject.net.HostId.hostId;
...@@ -36,6 +61,8 @@ import static org.onosproject.net.HostId.hostId; ...@@ -36,6 +61,8 @@ import static org.onosproject.net.HostId.hostId;
36 @Path("hosts") 61 @Path("hosts")
37 public class HostsWebResource extends AbstractWebResource { 62 public class HostsWebResource extends AbstractWebResource {
38 63
64 + @Context
65 + UriInfo uriInfo;
39 public static final String HOST_NOT_FOUND = "Host is not found"; 66 public static final String HOST_NOT_FOUND = "Host is not found";
40 67
41 @GET 68 @GET
...@@ -51,7 +78,7 @@ public class HostsWebResource extends AbstractWebResource { ...@@ -51,7 +78,7 @@ public class HostsWebResource extends AbstractWebResource {
51 @Path("{id}") 78 @Path("{id}")
52 public Response getHostById(@PathParam("id") String id) { 79 public Response getHostById(@PathParam("id") String id) {
53 final Host host = nullIsNotFound(get(HostService.class).getHost(hostId(id)), 80 final Host host = nullIsNotFound(get(HostService.class).getHost(hostId(id)),
54 - HOST_NOT_FOUND); 81 + HOST_NOT_FOUND);
55 final ObjectNode root = codec(Host.class).encode(host, this); 82 final ObjectNode root = codec(Host.class).encode(host, this);
56 return ok(root).build(); 83 return ok(root).build();
57 } 84 }
...@@ -62,9 +89,121 @@ public class HostsWebResource extends AbstractWebResource { ...@@ -62,9 +89,121 @@ public class HostsWebResource extends AbstractWebResource {
62 public Response getHostByMacAndVlan(@PathParam("mac") String mac, 89 public Response getHostByMacAndVlan(@PathParam("mac") String mac,
63 @PathParam("vlan") String vlan) { 90 @PathParam("vlan") String vlan) {
64 final Host host = nullIsNotFound(get(HostService.class).getHost(hostId(mac + "/" + vlan)), 91 final Host host = nullIsNotFound(get(HostService.class).getHost(hostId(mac + "/" + vlan)),
65 - HOST_NOT_FOUND); 92 + HOST_NOT_FOUND);
66 final ObjectNode root = codec(Host.class).encode(host, this); 93 final ObjectNode root = codec(Host.class).encode(host, this);
67 return ok(root).build(); 94 return ok(root).build();
68 } 95 }
96 +
97 + /**
98 + * Creates a new host based on JSON input and adds it to the current
99 + * host inventory.
100 + *
101 + * @param stream input JSON
102 + * @return status of the request - CREATED if the JSON is correct,
103 + * BAD_REQUEST if the JSON is invalid
104 + */
105 + @POST
106 + @Consumes(MediaType.APPLICATION_JSON)
107 + @Produces(MediaType.APPLICATION_JSON)
108 + public Response createAndAddHost(InputStream stream) {
109 + URI location;
110 + try {
111 + // Parse the input stream
112 + ObjectNode root = (ObjectNode) mapper().readTree(stream);
113 +
114 + HostProviderRegistry hostProviderRegistry = get(HostProviderRegistry.class);
115 + InternalHostProvider hostProvider = new InternalHostProvider(hostProviderRegistry);
116 + hostProvider.register();
117 + HostId hostId = hostProvider.parseHost(root);
118 +
119 + UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
120 + .path("hosts")
121 + .path(hostId.mac().toString())
122 + .path(hostId.vlanId().toString());
123 + location = locationBuilder.build();
124 + hostProvider.unregister();
125 +
126 + } catch (IOException ex) {
127 + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
128 + }
129 + return Response
130 + .created(location)
131 + .build();
132 + }
133 +
134 + /**
135 + * Produces annotations from specified JsonNode. Copied from the ConfigProvider
136 + * class for use in the POST method.
137 + *
138 + * @param node node to be annotated
139 + * @return SparseAnnotations object with information about node
140 + */
141 + private SparseAnnotations annotations(JsonNode node) {
142 + if (node == null) {
143 + return DefaultAnnotations.EMPTY;
144 + }
145 +
146 + DefaultAnnotations.Builder builder = DefaultAnnotations.builder();
147 + Iterator<String> it = node.fieldNames();
148 + while (it.hasNext()) {
149 + String k = it.next();
150 + builder.set(k, node.get(k).asText());
151 + }
152 + return builder.build();
153 + }
154 +
155 + private final class InternalHostProvider implements HostProvider {
156 + private final ProviderId providerId =
157 + new ProviderId("host", "org.onosproject.rest", true);
158 + private HostProviderRegistry hostProviderRegistry;
159 + private HostProviderService hostProviderService;
160 +
161 + public void triggerProbe(Host host) {
162 + // No need to implement since we don't need to check if the host exists
163 + }
164 +
165 + private InternalHostProvider(HostProviderRegistry hostProviderRegistry) {
166 + this.hostProviderRegistry = hostProviderRegistry;
167 + }
168 +
169 + private void register() {
170 + this.hostProviderService = hostProviderRegistry.register(this);
171 + }
172 +
173 + private void unregister() {
174 + hostProviderRegistry.unregister(this);
175 + }
176 +
177 + public ProviderId id() {
178 + return providerId;
179 + }
180 +
181 + /**
182 + * Creates and adds new host based on given data and returns its host ID.
183 + * @param node JsonNode containing host information
184 + * @return host ID of new host created
185 + */
186 + private HostId parseHost(JsonNode node) {
187 + MacAddress mac = MacAddress.valueOf(node.get("mac").asText());
188 + VlanId vlanId = VlanId.vlanId(((short) node.get("vlan").asInt((VlanId.UNTAGGED))));
189 + JsonNode locationNode = node.get("location");
190 + String deviceAndPort = locationNode.get("elementId").asText() + "/" +
191 + locationNode.get("port").asText();
192 + HostLocation hostLocation = new HostLocation(ConnectPoint.deviceConnectPoint(deviceAndPort), 0);
193 +
194 + Iterator<JsonNode> ipStrings = node.get("ipAddresses").elements();
195 + Set<IpAddress> ips = new HashSet<>();
196 + while (ipStrings.hasNext()) {
197 + ips.add(IpAddress.valueOf(ipStrings.next().asText()));
198 + }
199 + SparseAnnotations annotations = annotations(node);
200 + // Update host inventory
201 +
202 + HostId hostId = HostId.hostId(mac, vlanId);
203 + DefaultHostDescription desc = new DefaultHostDescription(mac, vlanId, hostLocation, ips, annotations);
204 + hostProviderService.hostDetected(hostId, desc);
205 + return hostId;
206 + }
207 + }
69 } 208 }
70 209
......