blob: cfd0f26439dfe391a370ab4c92a92b001ecb12b1 [file] [log] [blame]
Jian Lif96d41f2016-05-03 09:49:12 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Jian Lif96d41f2016-05-03 09:49:12 -07003 *
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 */
16package org.onosproject.rest.resources;
17
18import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
21import org.onosproject.cluster.NodeId;
22import org.onosproject.cluster.RoleInfo;
23import org.onosproject.mastership.MastershipAdminService;
24import org.onosproject.mastership.MastershipService;
25import org.onosproject.net.DeviceId;
26import org.onosproject.net.MastershipRole;
Kavitha Alagesan60093392016-10-26 17:04:26 +053027import org.onosproject.net.device.DeviceService;
Jian Lif96d41f2016-05-03 09:49:12 -070028import org.onosproject.rest.AbstractWebResource;
29
30import javax.ws.rs.Consumes;
31import javax.ws.rs.GET;
32import javax.ws.rs.PUT;
33import javax.ws.rs.Path;
34import javax.ws.rs.PathParam;
35import javax.ws.rs.Produces;
36import javax.ws.rs.core.MediaType;
37import javax.ws.rs.core.Response;
38import java.io.IOException;
39import java.io.InputStream;
40import java.util.Set;
Jian Lif96d41f2016-05-03 09:49:12 -070041
42import static org.onlab.util.Tools.nullIsNotFound;
Ray Milkeyb784adb2018-04-02 15:33:07 -070043import static org.onlab.util.Tools.readTreeFromStream;
Jian Lif96d41f2016-05-03 09:49:12 -070044
45/**
46 * Manage the mastership of ONOS instances.
47 */
48@Path("mastership")
49public final class MastershipWebResource extends AbstractWebResource {
50
Jian Li0409b702016-05-03 18:21:37 -070051 private static final String DEVICE_IDS = "deviceIds";
Jian Lif96d41f2016-05-03 09:49:12 -070052 private static final String DEVICE_ID = "deviceId";
53 private static final String NODE_ID = "nodeId";
54
55 private static final String DEVICE_ID_INVALID = "Invalid deviceId for setting role";
56 private static final String NODE_ID_INVALID = "Invalid nodeId for setting role";
57
Kavitha Alagesan60093392016-10-26 17:04:26 +053058 private static final String DEVICE_ID_NOT_FOUND = "Device Id is not found";
Jian Lif96d41f2016-05-03 09:49:12 -070059 private static final String NODE_ID_NOT_FOUND = "Node id is not found";
60 private static final String ROLE_INFO_NOT_FOUND = "Role info is not found";
61 private static final String MASTERSHIP_ROLE_NOT_FOUND = "Mastership role is not found";
Jian Lif96d41f2016-05-03 09:49:12 -070062
Kavitha Alagesan60093392016-10-26 17:04:26 +053063 private final DeviceService deviceService = get(DeviceService.class);
Jian Lif96d41f2016-05-03 09:49:12 -070064 private final MastershipService mastershipService = get(MastershipService.class);
65 private final MastershipAdminService mastershipAdminService =
66 get(MastershipAdminService.class);
67
68 /**
69 * Returns the role of the local node for the specified device.
70 *
71 * @param deviceId device identifier
Jian Licc730a62016-05-10 16:36:16 -070072 * @return 200 OK with role of the current node
Jian Lif96d41f2016-05-03 09:49:12 -070073 * @onos.rsModel MastershipRole
74 */
75 @GET
76 @Produces(MediaType.APPLICATION_JSON)
77 @Path("{deviceId}/local")
78 public Response getLocalRole(@PathParam("deviceId") String deviceId) {
79 MastershipRole role = mastershipService.getLocalRole(DeviceId.deviceId(deviceId));
80 ObjectNode root = codec(MastershipRole.class).encode(role, this);
81 return ok(root).build();
82 }
83
84 /**
85 * Returns the current master for a given device.
86 *
87 * @param deviceId device identifier
Jian Licc730a62016-05-10 16:36:16 -070088 * @return 200 OK with the identifier of the master controller for the device
Jian Li0409b702016-05-03 18:21:37 -070089 * @onos.rsModel NodeId
Jian Lif96d41f2016-05-03 09:49:12 -070090 */
91 @GET
92 @Produces(MediaType.APPLICATION_JSON)
93 @Path("{deviceId}/master")
94 public Response getMasterFor(@PathParam("deviceId") String deviceId) {
95 NodeId id = nullIsNotFound(mastershipService.getMasterFor(
96 DeviceId.deviceId(deviceId)), NODE_ID_NOT_FOUND);
97
98 ObjectNode root = mapper().createObjectNode();
Jian Li0409b702016-05-03 18:21:37 -070099 root.put(NODE_ID, id.id());
Jian Lif96d41f2016-05-03 09:49:12 -0700100 return ok(root).build();
101 }
102
103 /**
104 * Returns controllers connected to a given device, in order of
105 * preference. The first entry in the list is the current master.
106 *
107 * @param deviceId device identifier
Jian Licc730a62016-05-10 16:36:16 -0700108 * @return 200 OK with a list of controller identifiers
Jian Lif96d41f2016-05-03 09:49:12 -0700109 * @onos.rsModel RoleInfo
110 */
111 @GET
112 @Produces(MediaType.APPLICATION_JSON)
113 @Path("{deviceId}/role")
114 public Response getNodesFor(@PathParam("deviceId") String deviceId) {
115 RoleInfo info = nullIsNotFound(mastershipService.getNodesFor(
116 DeviceId.deviceId(deviceId)), ROLE_INFO_NOT_FOUND);
117 ObjectNode root = codec(RoleInfo.class).encode(info, this);
118 return ok(root).build();
119 }
120
121 /**
122 * Returns the devices for which a controller is master.
123 *
124 * @param nodeId controller identifier
Jian Licc730a62016-05-10 16:36:16 -0700125 * @return 200 OK with a set of device identifiers
Jian Li0409b702016-05-03 18:21:37 -0700126 * @onos.rsModel DeviceIds
Jian Lif96d41f2016-05-03 09:49:12 -0700127 */
128 @GET
129 @Produces(MediaType.APPLICATION_JSON)
130 @Path("{nodeId}/device")
131 public Response getDeviceOf(@PathParam("nodeId") String nodeId) {
132 ObjectNode root = mapper().createObjectNode();
Jian Li0409b702016-05-03 18:21:37 -0700133 ArrayNode devicesNode = root.putArray(DEVICE_IDS);
Jian Lif96d41f2016-05-03 09:49:12 -0700134
135 Set<DeviceId> devices = mastershipService.getDevicesOf(NodeId.nodeId(nodeId));
136 if (devices != null) {
137 devices.forEach(id -> devicesNode.add(id.toString()));
138 }
139
140 return ok(root).build();
141 }
142
143 /**
144 * Returns the mastership status of the local controller for a given
145 * device forcing master selection if necessary.
146 *
147 * @param deviceId device identifier
Jian Licc730a62016-05-10 16:36:16 -0700148 * @return 200 OK with the role of this controller instance
Jian Lif96d41f2016-05-03 09:49:12 -0700149 * @onos.rsModel MastershipRole
150 */
151 @GET
152 @Produces(MediaType.APPLICATION_JSON)
153 @Path("{deviceId}/request")
154 public Response requestRoleFor(@PathParam("deviceId") String deviceId) {
Kavitha Alagesan60093392016-10-26 17:04:26 +0530155 DeviceId id = DeviceId.deviceId(deviceId);
156 nullIsNotFound(deviceService.getDevice(id), DEVICE_ID_NOT_FOUND);
157
158 MastershipRole role = nullIsNotFound(mastershipService.requestRoleForSync(id),
159 MASTERSHIP_ROLE_NOT_FOUND);
Jian Li0409b702016-05-03 18:21:37 -0700160 ObjectNode root = codec(MastershipRole.class).encode(role, this);
161 return ok(root).build();
Jian Lif96d41f2016-05-03 09:49:12 -0700162 }
163
164 /**
165 * Abandons mastership of the specified device on the local node thus
166 * forcing selection of a new master. If the local node is not a master
167 * for this device, no master selection will occur.
168 *
169 * @param deviceId device identifier
Jian Licc730a62016-05-10 16:36:16 -0700170 * @return status of the request - CREATED if the JSON is correct
Jian Lif96d41f2016-05-03 09:49:12 -0700171 */
172 @GET
173 @Produces(MediaType.APPLICATION_JSON)
174 @Path("{deviceId}/relinquish")
175 public Response relinquishMastership(@PathParam("deviceId") String deviceId) {
176 DeviceId id = DeviceId.deviceId(deviceId);
Jian Li0409b702016-05-03 18:21:37 -0700177 mastershipService.relinquishMastershipSync(id);
178 return Response.created(id.uri()).build();
Jian Lif96d41f2016-05-03 09:49:12 -0700179 }
180
181 /**
182 * Applies the current mastership role for the specified device.
183 *
184 * @param stream JSON representation of device, node, mastership info
185 * @return status of the request - CREATED if the JSON is correct,
186 * BAD_REQUEST if the JSON is invalid
187 * @onos.rsModel MastershipPut
188 */
189 @PUT
190 @Consumes(MediaType.APPLICATION_JSON)
Jian Lif96d41f2016-05-03 09:49:12 -0700191 public Response setRole(InputStream stream) {
192
193 try {
Ray Milkeyb784adb2018-04-02 15:33:07 -0700194 ObjectNode jsonTree = readTreeFromStream(mapper(), stream);
Jian Lif96d41f2016-05-03 09:49:12 -0700195 JsonNode deviceIdJson = jsonTree.get(DEVICE_ID);
196 JsonNode nodeIdJson = jsonTree.get(NODE_ID);
197 MastershipRole role = codec(MastershipRole.class).decode(jsonTree, this);
198
199 if (deviceIdJson == null) {
200 throw new IllegalArgumentException(DEVICE_ID_INVALID);
201 }
202
203 if (nodeIdJson == null) {
204 throw new IllegalArgumentException(NODE_ID_INVALID);
205 }
206
Jian Li0409b702016-05-03 18:21:37 -0700207 mastershipAdminService.setRoleSync(NodeId.nodeId(nodeIdJson.asText()),
208 DeviceId.deviceId(deviceIdJson.asText()), role);
Jian Lif96d41f2016-05-03 09:49:12 -0700209
210 return Response.ok().build();
Jian Li0409b702016-05-03 18:21:37 -0700211 } catch (IOException e) {
Jian Lif96d41f2016-05-03 09:49:12 -0700212 throw new IllegalArgumentException(e);
213 }
214 }
215
216 /**
217 * Balances the mastership to be shared as evenly as possibly by all
218 * online instances.
219 *
220 * @return status of the request - OK if the request is successfully processed
221 */
222 @GET
223 @Produces(MediaType.APPLICATION_JSON)
224 public Response balanceRoles() {
225 mastershipAdminService.balanceRoles();
226 return Response.ok().build();
227 }
228}