Claudine Chiu
Committed by Gerrit Code Review

ONOS-2184 VirtualHost CLI and REST api's

Change-Id: If0ebe4268f3161a34223eca58e3f1bdbb8d0c9be
1 +/*
2 + * Copyright 2016-present 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 +package org.onosproject.cli.net.vnet;
18 +
19 +import org.apache.karaf.shell.commands.Argument;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.apache.karaf.shell.commands.Option;
22 +import org.onlab.packet.IpAddress;
23 +import org.onlab.packet.MacAddress;
24 +import org.onlab.packet.VlanId;
25 +import org.onosproject.cli.AbstractShellCommand;
26 +import org.onosproject.incubator.net.virtual.NetworkId;
27 +import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
28 +import org.onosproject.net.DeviceId;
29 +import org.onosproject.net.HostId;
30 +import org.onosproject.net.HostLocation;
31 +import org.onosproject.net.PortNumber;
32 +
33 +import java.util.Arrays;
34 +import java.util.HashSet;
35 +import java.util.Set;
36 +
37 +/**
38 + * Creates a new virtual host.
39 + */
40 +@Command(scope = "onos", name = "vnet-create-host",
41 + description = "Creates a new virtual host in a network.")
42 +public class VirtualHostCreateCommand extends AbstractShellCommand {
43 +
44 + @Argument(index = 0, name = "networkId", description = "Network ID",
45 + required = true, multiValued = false)
46 + Long networkId = null;
47 +
48 + @Argument(index = 1, name = "mac", description = "Mac address",
49 + required = true, multiValued = false)
50 + String mac = null;
51 +
52 + @Argument(index = 2, name = "vlan", description = "Vlan",
53 + required = true, multiValued = false)
54 + short vlan;
55 +
56 + @Argument(index = 3, name = "hostLocationDeviceId", description = "Host location device ID",
57 + required = true, multiValued = false)
58 + String hostLocationDeviceId;
59 +
60 + @Argument(index = 4, name = "hostLocationPortNumber", description = "Host location port number",
61 + required = true, multiValued = false)
62 + long hostLocationPortNumber;
63 +
64 + // ip addresses
65 + @Option(name = "--hostIp", description = "Host IP addresses. Can be specified multiple times.",
66 + required = false, multiValued = true)
67 + protected String[] hostIpStrings;
68 +
69 + @Override
70 + protected void execute() {
71 + VirtualNetworkAdminService service = get(VirtualNetworkAdminService.class);
72 +
73 + Set<IpAddress> hostIps = new HashSet<>();
74 + if (hostIpStrings != null) {
75 + Arrays.asList(hostIpStrings).stream().forEach(s -> hostIps.add(IpAddress.valueOf(s)));
76 + }
77 + HostLocation hostLocation = new HostLocation(DeviceId.deviceId(hostLocationDeviceId),
78 + PortNumber.portNumber(hostLocationPortNumber),
79 + System.currentTimeMillis());
80 + MacAddress macAddress = MacAddress.valueOf(mac);
81 + VlanId vlanId = VlanId.vlanId(vlan);
82 + service.createVirtualHost(NetworkId.networkId(networkId),
83 + HostId.hostId(macAddress, vlanId), macAddress, vlanId,
84 + hostLocation, hostIps);
85 + print("Virtual host successfully created.");
86 + }
87 +}
1 +/*
2 + * Copyright 2016-present 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 +package org.onosproject.cli.net.vnet;
18 +
19 +import org.apache.karaf.shell.commands.Argument;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.incubator.net.virtual.NetworkId;
23 +import org.onosproject.incubator.net.virtual.VirtualHost;
24 +import org.onosproject.incubator.net.virtual.VirtualNetworkService;
25 +
26 +import java.util.ArrayList;
27 +import java.util.List;
28 +
29 +/**
30 + * Lists all virtual hosts for the network ID.
31 + */
32 +@Command(scope = "onos", name = "vnet-hosts",
33 + description = "Lists all virtual hosts in a virtual network.")
34 +public class VirtualHostListCommand extends AbstractShellCommand {
35 +
36 + private static final String FMT_VIRTUAL_HOST =
37 + "id=%s, mac=%s, vlan=%s, location=%s, ips=%s";
38 +
39 + @Argument(index = 0, name = "networkId", description = "Network ID",
40 + required = true, multiValued = false)
41 + Long networkId = null;
42 +
43 + @Override
44 + protected void execute() {
45 + getSortedVirtualHosts().forEach(this::printVirtualHost);
46 + }
47 +
48 + /**
49 + * Returns the list of virtual hosts sorted using the device identifier.
50 + *
51 + * @return virtual host list
52 + */
53 + private List<VirtualHost> getSortedVirtualHosts() {
54 + VirtualNetworkService service = get(VirtualNetworkService.class);
55 +
56 + List<VirtualHost> virtualHosts = new ArrayList<>();
57 + virtualHosts.addAll(service.getVirtualHosts(NetworkId.networkId(networkId)));
58 + return virtualHosts;
59 + }
60 +
61 + /**
62 + * Prints out each virtual host.
63 + *
64 + * @param virtualHost virtual host
65 + */
66 + private void printVirtualHost(VirtualHost virtualHost) {
67 + print(FMT_VIRTUAL_HOST, virtualHost.id().toString(), virtualHost.mac().toString(),
68 + virtualHost.vlan().toString(), virtualHost.location().toString(),
69 + virtualHost.ipAddresses().toString());
70 + }
71 +}
1 +/*
2 + * Copyright 2016-present 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 +package org.onosproject.cli.net.vnet;
18 +
19 +import org.apache.karaf.shell.commands.Argument;
20 +import org.apache.karaf.shell.commands.Command;
21 +import org.onosproject.cli.AbstractShellCommand;
22 +import org.onosproject.incubator.net.virtual.NetworkId;
23 +import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
24 +import org.onosproject.net.HostId;
25 +//import org.onosproject.net.HostId;
26 +
27 +/**
28 + * Removes a virtual host.
29 + */
30 +
31 +@Command(scope = "onos", name = "vnet-remove-host",
32 + description = "Removes a virtual host.")
33 +public class VirtualHostRemoveCommand extends AbstractShellCommand {
34 +
35 + @Argument(index = 0, name = "networkId", description = "Network ID",
36 + required = true, multiValued = false)
37 + Long networkId = null;
38 +
39 + @Argument(index = 1, name = "id", description = "Host ID",
40 + required = true, multiValued = false)
41 + String id = null;
42 +
43 + @Override
44 + protected void execute() {
45 + VirtualNetworkAdminService service = get(VirtualNetworkAdminService.class);
46 + service.removeVirtualHost(NetworkId.networkId(networkId), HostId.hostId(id));
47 + print("Virtual host successfully removed.");
48 + }
49 +}
...@@ -674,6 +674,15 @@ ...@@ -674,6 +674,15 @@
674 <command> 674 <command>
675 <action class="org.onosproject.cli.net.vnet.VirtualPortRemoveCommand"/> 675 <action class="org.onosproject.cli.net.vnet.VirtualPortRemoveCommand"/>
676 </command> 676 </command>
677 + <command>
678 + <action class="org.onosproject.cli.net.vnet.VirtualHostListCommand"/>
679 + </command>
680 + <command>
681 + <action class="org.onosproject.cli.net.vnet.VirtualHostCreateCommand"/>
682 + </command>
683 + <command>
684 + <action class="org.onosproject.cli.net.vnet.VirtualHostRemoveCommand"/>
685 + </command>
677 </command-bundle> 686 </command-bundle>
678 687
679 <bean id="reviewAppNameCompleter" class="org.onosproject.cli.security.ReviewApplicationNameCompleter"/> 688 <bean id="reviewAppNameCompleter" class="org.onosproject.cli.security.ReviewApplicationNameCompleter"/>
......
...@@ -30,6 +30,7 @@ import org.onosproject.core.Application; ...@@ -30,6 +30,7 @@ import org.onosproject.core.Application;
30 import org.onosproject.core.ApplicationId; 30 import org.onosproject.core.ApplicationId;
31 import org.onosproject.incubator.net.virtual.TenantId; 31 import org.onosproject.incubator.net.virtual.TenantId;
32 import org.onosproject.incubator.net.virtual.VirtualDevice; 32 import org.onosproject.incubator.net.virtual.VirtualDevice;
33 +import org.onosproject.incubator.net.virtual.VirtualHost;
33 import org.onosproject.incubator.net.virtual.VirtualLink; 34 import org.onosproject.incubator.net.virtual.VirtualLink;
34 import org.onosproject.incubator.net.virtual.VirtualNetwork; 35 import org.onosproject.incubator.net.virtual.VirtualNetwork;
35 import org.onosproject.incubator.net.virtual.VirtualPort; 36 import org.onosproject.incubator.net.virtual.VirtualPort;
...@@ -141,6 +142,7 @@ public class CodecManager implements CodecService { ...@@ -141,6 +142,7 @@ public class CodecManager implements CodecService {
141 registerCodec(VirtualDevice.class, new VirtualDeviceCodec()); 142 registerCodec(VirtualDevice.class, new VirtualDeviceCodec());
142 registerCodec(VirtualPort.class, new VirtualPortCodec()); 143 registerCodec(VirtualPort.class, new VirtualPortCodec());
143 registerCodec(VirtualLink.class, new VirtualLinkCodec()); 144 registerCodec(VirtualLink.class, new VirtualLinkCodec());
145 + registerCodec(VirtualHost.class, new VirtualHostCodec());
144 registerCodec(MastershipTerm.class, new MastershipTermCodec()); 146 registerCodec(MastershipTerm.class, new MastershipTermCodec());
145 registerCodec(MastershipRole.class, new MastershipRoleCodec()); 147 registerCodec(MastershipRole.class, new MastershipRoleCodec());
146 registerCodec(RoleInfo.class, new RoleInfoCodec()); 148 registerCodec(RoleInfo.class, new RoleInfoCodec());
......
1 +/*
2 + * Copyright 2016-present 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.codec.impl;
17 +
18 +import com.fasterxml.jackson.databind.JsonNode;
19 +import com.fasterxml.jackson.databind.node.ArrayNode;
20 +import com.fasterxml.jackson.databind.node.ObjectNode;
21 +import org.onlab.packet.IpAddress;
22 +import org.onlab.packet.MacAddress;
23 +import org.onlab.packet.VlanId;
24 +import org.onosproject.codec.CodecContext;
25 +import org.onosproject.codec.JsonCodec;
26 +import org.onosproject.incubator.net.virtual.DefaultVirtualHost;
27 +import org.onosproject.incubator.net.virtual.NetworkId;
28 +import org.onosproject.incubator.net.virtual.VirtualHost;
29 +import org.onosproject.net.DeviceId;
30 +import org.onosproject.net.HostId;
31 +import org.onosproject.net.HostLocation;
32 +import org.onosproject.net.PortNumber;
33 +
34 +import java.util.HashSet;
35 +import java.util.Iterator;
36 +import java.util.Set;
37 +
38 +import static com.google.common.base.Preconditions.checkNotNull;
39 +import static org.onlab.util.Tools.nullIsIllegal;
40 +
41 +/**
42 + * Codec for the VirtualHost class.
43 + */
44 +public class VirtualHostCodec extends JsonCodec<VirtualHost> {
45 +
46 + // JSON field names
47 + private static final String NETWORK_ID = "networkId";
48 + private static final String HOST_ID = "id";
49 + private static final String MAC_ADDRESS = "mac";
50 + private static final String VLAN = "vlan";
51 + private static final String IP_ADDRESSES = "ipAddresses";
52 + private static final String HOST_LOCATION = "location";
53 +
54 + private static final String NULL_OBJECT_MSG = "VirtualHost cannot be null";
55 + private static final String MISSING_MEMBER_MSG = " member is required in VirtualHost";
56 +
57 + @Override
58 + public ObjectNode encode(VirtualHost vHost, CodecContext context) {
59 + checkNotNull(vHost, NULL_OBJECT_MSG);
60 +
61 + final JsonCodec<HostLocation> locationCodec =
62 + context.codec(HostLocation.class);
63 + final ObjectNode result = context.mapper().createObjectNode()
64 + .put(NETWORK_ID, vHost.networkId().toString())
65 + .put(HOST_ID, vHost.id().toString())
66 + .put(MAC_ADDRESS, vHost.mac().toString())
67 + .put(VLAN, vHost.vlan().toString());
68 +
69 + final ArrayNode jsonIpAddresses = result.putArray(IP_ADDRESSES);
70 + for (final IpAddress ipAddress : vHost.ipAddresses()) {
71 + jsonIpAddresses.add(ipAddress.toString());
72 + }
73 + result.set(IP_ADDRESSES, jsonIpAddresses);
74 + result.set(HOST_LOCATION, locationCodec.encode(vHost.location(), context));
75 +
76 + return result;
77 + }
78 +
79 + @Override
80 + public VirtualHost decode(ObjectNode json, CodecContext context) {
81 + if (json == null || !json.isObject()) {
82 + return null;
83 + }
84 +
85 + NetworkId nId = NetworkId.networkId(Long.parseLong(extractMember(NETWORK_ID, json)));
86 + MacAddress mac = MacAddress.valueOf(json.get("mac").asText());
87 + VlanId vlanId = VlanId.vlanId((short) json.get("vlan").asInt(VlanId.UNTAGGED));
88 + JsonNode locationNode = json.get("location");
89 + PortNumber portNumber = PortNumber.portNumber(locationNode.get("port").asText());
90 + DeviceId deviceId = DeviceId.deviceId(locationNode.get("elementId").asText());
91 + HostLocation hostLocation = new HostLocation(deviceId, portNumber, 0);
92 + HostId id = HostId.hostId(mac, vlanId);
93 +
94 + Iterator<JsonNode> ipStrings = json.get("ipAddresses").elements();
95 + Set<IpAddress> ips = new HashSet<>();
96 + while (ipStrings.hasNext()) {
97 + ips.add(IpAddress.valueOf(ipStrings.next().asText()));
98 + }
99 +
100 + return new DefaultVirtualHost(nId, id, mac, vlanId, hostLocation, ips);
101 + }
102 +
103 + /**
104 + * Extract member from JSON ObjectNode.
105 + *
106 + * @param key key for which value is needed
107 + * @param json JSON ObjectNode
108 + * @return member value
109 + */
110 + private String extractMember(String key, ObjectNode json) {
111 + return nullIsIllegal(json.get(key), key + MISSING_MEMBER_MSG).asText();
112 + }
113 +}
...@@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; ...@@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
21 import org.onosproject.incubator.net.virtual.NetworkId; 21 import org.onosproject.incubator.net.virtual.NetworkId;
22 import org.onosproject.incubator.net.virtual.TenantId; 22 import org.onosproject.incubator.net.virtual.TenantId;
23 import org.onosproject.incubator.net.virtual.VirtualDevice; 23 import org.onosproject.incubator.net.virtual.VirtualDevice;
24 +import org.onosproject.incubator.net.virtual.VirtualHost;
24 import org.onosproject.incubator.net.virtual.VirtualLink; 25 import org.onosproject.incubator.net.virtual.VirtualLink;
25 import org.onosproject.incubator.net.virtual.VirtualNetwork; 26 import org.onosproject.incubator.net.virtual.VirtualNetwork;
26 import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService; 27 import org.onosproject.incubator.net.virtual.VirtualNetworkAdminService;
...@@ -390,6 +391,87 @@ public class VirtualNetworkWebResource extends AbstractWebResource { ...@@ -390,6 +391,87 @@ public class VirtualNetworkWebResource extends AbstractWebResource {
390 } 391 }
391 392
392 /** 393 /**
394 + * Returns all virtual network hosts in a virtual network.
395 + *
396 + * @param networkId network identifier
397 + * @return 200 OK with set of virtual network hosts
398 + * @onos.rsModel VirtualHosts
399 + */
400 + @GET
401 + @Produces(MediaType.APPLICATION_JSON)
402 + @Path("{networkId}/hosts")
403 + public Response getVirtualHosts(@PathParam("networkId") long networkId) {
404 + NetworkId nid = NetworkId.networkId(networkId);
405 + Set<VirtualHost> vhosts = vnetService.getVirtualHosts(nid);
406 + return ok(encodeArray(VirtualHost.class, "hosts", vhosts)).build();
407 + }
408 +
409 + /**
410 + * Creates a virtual network host from the JSON input stream.
411 + *
412 + * @param networkId network identifier
413 + * @param stream virtual host JSON stream
414 + * @return status of the request - CREATED if the JSON is correct,
415 + * BAD_REQUEST if the JSON is invalid
416 + * @onos.rsModel VirtualHostPut
417 + */
418 + @POST
419 + @Path("{networkId}/hosts")
420 + @Consumes(MediaType.APPLICATION_JSON)
421 + @Produces(MediaType.APPLICATION_JSON)
422 + public Response createVirtualHost(@PathParam("networkId") long networkId,
423 + InputStream stream) {
424 + try {
425 + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
426 + JsonNode specifiedNetworkId = jsonTree.get("networkId");
427 + if (specifiedNetworkId == null || specifiedNetworkId.asLong() != (networkId)) {
428 + throw new IllegalArgumentException(INVALID_FIELD + "networkId");
429 + }
430 + final VirtualHost vhostReq = codec(VirtualHost.class).decode(jsonTree, this);
431 + vnetAdminService.createVirtualHost(vhostReq.networkId(), vhostReq.id(),
432 + vhostReq.mac(), vhostReq.vlan(),
433 + vhostReq.location(), vhostReq.ipAddresses());
434 + UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
435 + .path("vnets").path(specifiedNetworkId.asText())
436 + .path("hosts");
437 + return Response
438 + .created(locationBuilder.build())
439 + .build();
440 + } catch (IOException e) {
441 + throw new IllegalArgumentException(e);
442 + }
443 + }
444 +
445 + /**
446 + * Removes the virtual network host from the JSON input stream.
447 + *
448 + * @param networkId network identifier
449 + * @param stream virtual host JSON stream
450 + * @return 204 NO CONTENT
451 + * @onos.rsModel VirtualHost
452 + */
453 + @DELETE
454 + @Path("{networkId}/hosts")
455 + @Consumes(MediaType.APPLICATION_JSON)
456 + public Response removeVirtualHost(@PathParam("networkId") long networkId,
457 + InputStream stream) {
458 + try {
459 + ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
460 + JsonNode specifiedNetworkId = jsonTree.get("networkId");
461 + if (specifiedNetworkId != null &&
462 + specifiedNetworkId.asLong() != (networkId)) {
463 + throw new IllegalArgumentException(INVALID_FIELD + "networkId");
464 + }
465 + final VirtualHost vhostReq = codec(VirtualHost.class).decode(jsonTree, this);
466 + vnetAdminService.removeVirtualHost(vhostReq.networkId(), vhostReq.id());
467 + } catch (IOException e) {
468 + throw new IllegalArgumentException(e);
469 + }
470 +
471 + return Response.noContent().build();
472 + }
473 +
474 + /**
393 * Get the tenant identifier from the JSON stream. 475 * Get the tenant identifier from the JSON stream.
394 * 476 *
395 * @param stream TenantId JSON stream 477 * @param stream TenantId JSON stream
......
1 +{
2 + "type": "object",
3 + "title": "host",
4 + "required": [
5 + "networkId",
6 + "id",
7 + "mac",
8 + "vlan",
9 + "ipAddresses",
10 + "location"
11 + ],
12 + "properties": {
13 + "networkId": {
14 + "type": "int64",
15 + "description": "Network identifier",
16 + "example": 3
17 + },
18 + "id": {
19 + "type": "string",
20 + "example": "46:E4:3C:A4:17:C8/-1"
21 + },
22 + "mac": {
23 + "type": "string",
24 + "example": "46:E4:3C:A4:17:C8"
25 + },
26 + "vlan": {
27 + "type": "string",
28 + "example": "-1"
29 + },
30 + "ipAddresses": {
31 + "type": "array",
32 + "xml": {
33 + "name": "hosts",
34 + "wrapped": true
35 + },
36 + "items": {
37 + "type": "string",
38 + "example": "127.0.0.1"
39 + }
40 + },
41 + "location": {
42 + "type": "object",
43 + "title": "location",
44 + "required": [
45 + "elementId",
46 + "port"
47 + ],
48 + "properties": {
49 + "elementId": {
50 + "type": "string",
51 + "example": "of:0000000000000002"
52 + },
53 + "port": {
54 + "type": "string",
55 + "example": "3"
56 + }
57 + }
58 + }
59 + }
60 +}
1 +{
2 + "type": "object",
3 + "title": "host",
4 + "required": [
5 + "networkId",
6 + "mac",
7 + "vlan",
8 + "ipAddresses",
9 + "location"
10 + ],
11 + "properties": {
12 + "networkId": {
13 + "type": "int64",
14 + "description": "Network identifier",
15 + "example": 3
16 + },
17 + "mac": {
18 + "type": "string",
19 + "example": "46:E4:3C:A4:17:C8"
20 + },
21 + "vlan": {
22 + "type": "string",
23 + "example": "-1"
24 + },
25 + "ipAddresses": {
26 + "type": "array",
27 + "xml": {
28 + "name": "hosts",
29 + "wrapped": true
30 + },
31 + "items": {
32 + "type": "string",
33 + "example": "127.0.0.1"
34 + }
35 + },
36 + "location": {
37 + "type": "object",
38 + "title": "location",
39 + "required": [
40 + "elementId",
41 + "port"
42 + ],
43 + "properties": {
44 + "elementId": {
45 + "type": "string",
46 + "example": "of:0000000000000002"
47 + },
48 + "port": {
49 + "type": "string",
50 + "example": "3"
51 + }
52 + }
53 + }
54 + }
55 +}
1 +{
2 + "type": "object",
3 + "title": "hosts",
4 + "required": [
5 + "hosts"
6 + ],
7 + "properties": {
8 + "hosts": {
9 + "type": "array",
10 + "xml": {
11 + "name": "hosts",
12 + "wrapped": true
13 + },
14 + "items": {
15 + "type": "object",
16 + "title": "host",
17 + "required": [
18 + "networkId",
19 + "id",
20 + "mac",
21 + "vlan",
22 + "ipAddresses",
23 + "location"
24 + ],
25 + "properties": {
26 + "networkId": {
27 + "type": "int64",
28 + "description": "Network identifier",
29 + "example": 3
30 + },
31 + "id": {
32 + "type": "string",
33 + "example": "46:E4:3C:A4:17:C8/-1"
34 + },
35 + "mac": {
36 + "type": "string",
37 + "example": "46:E4:3C:A4:17:C8"
38 + },
39 + "vlan": {
40 + "type": "string",
41 + "example": "-1"
42 + },
43 + "ipAddresses": {
44 + "type": "array",
45 + "xml": {
46 + "name": "hosts",
47 + "wrapped": true
48 + },
49 + "items": {
50 + "type": "string",
51 + "example": "127.0.0.1"
52 + }
53 + },
54 + "location": {
55 + "type": "object",
56 + "title": "location",
57 + "required": [
58 + "elementId",
59 + "port"
60 + ],
61 + "properties": {
62 + "elementId": {
63 + "type": "string",
64 + "example": "of:0000000000000002"
65 + },
66 + "port": {
67 + "type": "string",
68 + "example": "3"
69 + }
70 + }
71 + }
72 + }
73 + }
74 + }
75 + }
76 +}
1 +{
2 + "networkId": "3",
3 + "id": "00:11:00:00:00:01/11",
4 + "mac": "00:11:00:00:00:01",
5 + "vlan": "11",
6 + "location": {
7 + "elementId": "devid1",
8 + "port": "100"
9 + },
10 + "ipAddresses": [
11 + "10.0.0.1",
12 + "10.0.0.2"
13 + ]
14 +}