blob: 192eb2e21a42bbeaf1dd5b0d1bf2acac766d7d29 [file] [log] [blame]
Jimmy Yanda878fc2016-09-02 16:32:01 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Jimmy Yanda878fc2016-09-02 16:32:01 -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.roadm;
17
MaoLu2846b112017-05-15 17:18:55 -070018import com.fasterxml.jackson.databind.node.ArrayNode;
19import com.fasterxml.jackson.databind.node.JsonNodeFactory;
Jimmy Yanda878fc2016-09-02 16:32:01 -070020import com.fasterxml.jackson.databind.node.ObjectNode;
21import com.google.common.collect.ImmutableSet;
22import com.google.common.collect.Range;
23import org.onlab.osgi.ServiceDirectory;
MaoLu937cf422017-03-03 23:31:46 -080024import org.onlab.util.Frequency;
Jimmy Yanda878fc2016-09-02 16:32:01 -070025import org.onosproject.net.AnnotationKeys;
MaoLu2846b112017-05-15 17:18:55 -070026import org.onosproject.net.ConnectPoint;
Jimmy Yanda878fc2016-09-02 16:32:01 -070027import org.onosproject.net.DeviceId;
MaoLu2846b112017-05-15 17:18:55 -070028import org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState;
29import org.onosproject.net.behaviour.protection.TransportEndpointState;
MaoLu937cf422017-03-03 23:31:46 -080030import org.onosproject.net.device.DeviceService;
31import org.onosproject.net.OchSignal;
Jimmy Yanda878fc2016-09-02 16:32:01 -070032import org.onosproject.net.Port;
33import org.onosproject.net.PortNumber;
alessiod4a2b842019-04-30 18:43:17 +020034import org.onosproject.net.intent.OpticalPathIntent;
MaoLu2846b112017-05-15 17:18:55 -070035import org.onosproject.net.optical.OpticalAnnotations;
Jimmy Yanda878fc2016-09-02 16:32:01 -070036import org.onosproject.ui.RequestHandler;
37import org.onosproject.ui.UiConnection;
38import org.onosproject.ui.UiMessageHandler;
39import org.onosproject.ui.table.TableModel;
40import org.onosproject.ui.table.TableRequestHandler;
41import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
43
44import java.util.Collection;
MaoLu937cf422017-03-03 23:31:46 -080045import java.util.Collections;
46import java.util.Comparator;
Jimmy Yanda878fc2016-09-02 16:32:01 -070047import java.util.List;
MaoLu2846b112017-05-15 17:18:55 -070048import java.util.Map;
MaoLu937cf422017-03-03 23:31:46 -080049import java.util.Set;
50
51import static org.onosproject.net.Device.Type;
MaoLu2846b112017-05-15 17:18:55 -070052import static org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState.ACTIVE_UNKNOWN;
53import static org.onosproject.roadm.RoadmUtil.OPS_OPT_AUTO;
54import static org.onosproject.roadm.RoadmUtil.OPS_OPT_FORCE;
55import static org.onosproject.roadm.RoadmUtil.OPS_OPT_MANUAL;
Jimmy Yanda878fc2016-09-02 16:32:01 -070056
57/**
58 * Table-View message handler for ROADM port view.
59 */
60public class RoadmPortViewMessageHandler extends UiMessageHandler {
61
62 private static final String ROADM_PORT_DATA_REQ = "roadmPortDataRequest";
63 private static final String ROADM_PORT_DATA_RESP = "roadmPortDataResponse";
64 private static final String ROADM_PORTS = "roadmPorts";
Jimmy Yanda878fc2016-09-02 16:32:01 -070065 private static final String ROADM_SET_TARGET_POWER_REQ = "roadmSetTargetPowerRequest";
66 private static final String ROADM_SET_TARGET_POWER_RESP = "roadmSetTargetPowerResponse";
MaoLu937cf422017-03-03 23:31:46 -080067 private static final String ROADM_SHOW_ITEMS_REQ = "roadmShowPortItemsRequest";
68 private static final String ROADM_SHOW_ITEMS_RESP = "roadmShowPortItemsResponse";
69 private static final String ROADM_SET_OPS_MODE_REQ = "roadmSetOpsModeRequest";
70 private static final String ROADM_SET_OPS_MODE_RESP = "roadmSetOpsModeResponse";
Jimmy Yanda878fc2016-09-02 16:32:01 -070071
72 private static final String ID = "id";
alessiod4a2b842019-04-30 18:43:17 +020073 private static final String REVERSE_PORT = "reversePort";
Jimmy Yanda878fc2016-09-02 16:32:01 -070074 private static final String NAME = "name";
MaoLu937cf422017-03-03 23:31:46 -080075 private static final String TYPE = "type";
Jimmy Yanda878fc2016-09-02 16:32:01 -070076 private static final String ENABLED = "enabled";
77 private static final String MIN_FREQ = "minFreq";
78 private static final String MAX_FREQ = "maxFreq";
79 private static final String GRID = "grid";
MaoLu2f7eadb2017-05-02 15:38:43 -070080 private static final String POWER_RANGE = "powerRange";
Jimmy Yanda878fc2016-09-02 16:32:01 -070081 private static final String CURRENT_POWER = "currentPower";
82 private static final String TARGET_POWER = "targetPower";
83 private static final String HAS_TARGET_POWER = "hasTargetPower";
MaoLu937cf422017-03-03 23:31:46 -080084 private static final String SERVICE_STATE = "serviceState";
Jimmy Yanda878fc2016-09-02 16:32:01 -070085
86 private static final String[] COLUMN_IDS = {
alessiod4a2b842019-04-30 18:43:17 +020087 ID, REVERSE_PORT, TYPE, NAME, ENABLED, MIN_FREQ, MAX_FREQ, GRID, POWER_RANGE,
MaoLu937cf422017-03-03 23:31:46 -080088 CURRENT_POWER, SERVICE_STATE, TARGET_POWER, HAS_TARGET_POWER
Jimmy Yanda878fc2016-09-02 16:32:01 -070089 };
90
Jimmy Yanda878fc2016-09-02 16:32:01 -070091 private RoadmService roadmService;
MaoLu937cf422017-03-03 23:31:46 -080092 private DeviceService deviceService;
Jimmy Yanda878fc2016-09-02 16:32:01 -070093
94 private final Logger log = LoggerFactory.getLogger(getClass());
95
96 @Override
97 public void init(UiConnection connection, ServiceDirectory directory) {
98 super.init(connection, directory);
Jimmy Yanda878fc2016-09-02 16:32:01 -070099 roadmService = get(RoadmService.class);
MaoLu937cf422017-03-03 23:31:46 -0800100 deviceService = get(DeviceService.class);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700101 }
102
103 @Override
104 protected Collection<RequestHandler> createRequestHandlers() {
MaoLu937cf422017-03-03 23:31:46 -0800105 return ImmutableSet.of(new PortTableDataRequestHandler(),
106 new SetTargetPowerRequestHandler(),
107 new CreateShowItemsRequestHandler(),
108 new CreateOpsModeSetRequestHandler()
109 );
Jimmy Yanda878fc2016-09-02 16:32:01 -0700110 }
111
112 // Handler for sample table requests
113 private final class PortTableDataRequestHandler extends TableRequestHandler {
114
115 private PortTableDataRequestHandler() {
116 super(ROADM_PORT_DATA_REQ, ROADM_PORT_DATA_RESP, ROADM_PORTS);
117 }
118
119 @Override
120 protected String[] getColumnIds() {
121 return COLUMN_IDS;
122 }
123
124 @Override
125 protected String noRowsMessage(ObjectNode payload) {
MaoLu937cf422017-03-03 23:31:46 -0800126 return RoadmUtil.NO_ROWS_MESSAGE;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700127 }
128
129 @Override
130 protected void populateTable(TableModel tm, ObjectNode payload) {
MaoLu937cf422017-03-03 23:31:46 -0800131 DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
Jimmy Yanda878fc2016-09-02 16:32:01 -0700132 if (deviceService.isAvailable(deviceId)) {
133 List<Port> ports = deviceService.getPorts(deviceId);
134 for (Port port : ports) {
135 populateRow(tm.addRow(), port, deviceId);
136 }
137 }
138 }
139
140 private void populateRow(TableModel.Row row, Port port, DeviceId deviceId) {
MaoLu937cf422017-03-03 23:31:46 -0800141 PortNumber portNum = port.number();
142 getFrequencyLimit(deviceId, portNum);
143 row.cell(ID, portNum.toLong())
alessiod4a2b842019-04-30 18:43:17 +0200144 .cell(REVERSE_PORT, RoadmUtil.getAnnotation(port.annotations(),
145 OpticalPathIntent.REVERSE_PORT_ANNOTATION_KEY))
Jimmy Yanda878fc2016-09-02 16:32:01 -0700146 .cell(TYPE, port.type())
147 .cell(ENABLED, port.isEnabled())
MaoLu937cf422017-03-03 23:31:46 -0800148 .cell(NAME, RoadmUtil.getAnnotation(port.annotations(), AnnotationKeys.PORT_NAME))
149 .cell(MIN_FREQ, RoadmUtil.asTHz(minFreq))
150 .cell(MAX_FREQ, RoadmUtil.asTHz(maxFreq))
151 .cell(GRID, RoadmUtil.asGHz(channelSpacing))
MaoLu2f7eadb2017-05-02 15:38:43 -0700152 .cell(POWER_RANGE, getPowerRange(deviceId, portNum))
MaoLu937cf422017-03-03 23:31:46 -0800153 .cell(CURRENT_POWER, getCurrentPower(deviceId, portNum))
154 .cell(SERVICE_STATE, getPortServiceState(deviceId, portNum))
155 .cell(TARGET_POWER, getTargetPower(deviceId, portNum))
156 .cell(HAS_TARGET_POWER, roadmService.hasPortTargetPower(deviceId, portNum));
157 }
158
159 private String getPortServiceState(DeviceId deviceId, PortNumber portNumber) {
MaoLu2846b112017-05-15 17:18:55 -0700160 if (deviceService.getDevice(deviceId).type() != Type.FIBER_SWITCH) {
161 return RoadmUtil.NA;
162 }
163 Map<ConnectPoint, ProtectedTransportEndpointState> map =
164 roadmService.getProtectionSwitchStates(deviceId);
165 for (ProtectedTransportEndpointState state : map.values()) {
166 for (TransportEndpointState element : state.pathStates()) {
167 if (element.description().output().connectPoint().port().equals(portNumber)) {
168 return RoadmUtil.defaultString(element.attributes()
169 .get(OpticalAnnotations.INPUT_PORT_STATUS), RoadmUtil.UNKNOWN);
170 }
171 }
172 }
173 return RoadmUtil.UNKNOWN;
MaoLu937cf422017-03-03 23:31:46 -0800174 }
175
176 private Frequency minFreq = null, maxFreq = null, channelSpacing = null;
177 // Gets min frequency, max frequency, channel spacing
178 private void getFrequencyLimit(DeviceId deviceId, PortNumber portNumber) {
179 Set<OchSignal> signals = roadmService.queryLambdas(deviceId, portNumber);
180 if (signals.isEmpty()) {
181 return;
182 }
183 Comparator<OchSignal> compare =
184 (OchSignal a, OchSignal b) -> a.spacingMultiplier() - b.spacingMultiplier();
185 OchSignal minOch = Collections.min(signals, compare);
186 OchSignal maxOch = Collections.max(signals, compare);
187 minFreq = minOch.centralFrequency();
188 maxFreq = maxOch.centralFrequency();
189 channelSpacing = minOch.channelSpacing().frequency();
Jimmy Yanda878fc2016-09-02 16:32:01 -0700190 }
191
MaoLu2f7eadb2017-05-02 15:38:43 -0700192 // Returns the power range as a string, N/A if the power range not exists.
193 // The power range would be input power range or target power range determined by port property.
194 // If the port is RX direction then acquire the input power range from driver.
195 // Otherwise there will be a TX direction port, thus acquire the target power range.
196 private String getPowerRange(DeviceId deviceId, PortNumber portNumber) {
MaoLu937cf422017-03-03 23:31:46 -0800197 Range<Long> range = roadmService.inputPortPowerRange(deviceId, portNumber);
MaoLu2f7eadb2017-05-02 15:38:43 -0700198 if (range == null) {
199 range = roadmService.targetPortPowerRange(deviceId, portNumber);
200 }
MaoLu937cf422017-03-03 23:31:46 -0800201 return RoadmUtil.objectToString(range, RoadmUtil.NA);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700202 }
203
204 // Returns the current power as a string, Unknown if no value can be found.
205 private String getCurrentPower(DeviceId deviceId, PortNumber portNumber) {
MaoLu937cf422017-03-03 23:31:46 -0800206 Long currentPower = roadmService.getCurrentPortPower(deviceId, portNumber);
207 return RoadmUtil.objectToString(currentPower, RoadmUtil.UNKNOWN);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700208 }
209
210 // Returns target power as a string, Unknown if target power is expected but
211 // cannot be found, N/A if port does not have configurable target power
212 private String getTargetPower(DeviceId deviceId, PortNumber portNumber) {
MaoLu937cf422017-03-03 23:31:46 -0800213 if (!roadmService.hasPortTargetPower(deviceId, portNumber)) {
214 return RoadmUtil.NA;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700215 }
MaoLu937cf422017-03-03 23:31:46 -0800216 Long targetPower = roadmService.getTargetPortPower(deviceId, portNumber);
217 return RoadmUtil.objectToString(targetPower, RoadmUtil.UNKNOWN);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700218 }
219 }
220
221
222 // Handler for setting port target power
223 private final class SetTargetPowerRequestHandler extends RequestHandler {
224
Jimmy Yanda878fc2016-09-02 16:32:01 -0700225 private static final String TARGET_POWER_ERR_MSG = "Target power range is %s.";
226
227 private SetTargetPowerRequestHandler() {
228 super(ROADM_SET_TARGET_POWER_REQ);
229 }
230
231 @Override
232 public void process(ObjectNode payload) {
MaoLu937cf422017-03-03 23:31:46 -0800233 DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
Jimmy Yanda878fc2016-09-02 16:32:01 -0700234 PortNumber portNumber = PortNumber.portNumber(payload.get(ID).asLong());
MaoLu937cf422017-03-03 23:31:46 -0800235 Range<Long> range = roadmService.targetPortPowerRange(deviceId, portNumber);
236 if (range == null) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700237 log.warn("Unable to determine target power range for device {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800238 return;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700239 }
MaoLu937cf422017-03-03 23:31:46 -0800240 Long targetPower = payload.get(TARGET_POWER).asLong();
241 boolean validTargetPower = range.contains(targetPower);
242 if (validTargetPower) {
243 roadmService.setTargetPortPower(deviceId, portNumber, targetPower);
244 }
245 ObjectNode rootNode = objectNode();
246 rootNode.put(ID, payload.get(ID).asText());
247 rootNode.put(RoadmUtil.VALID, validTargetPower);
248 rootNode.put(RoadmUtil.MESSAGE, String.format(TARGET_POWER_ERR_MSG, range.toString()));
249 sendMessage(ROADM_SET_TARGET_POWER_RESP, rootNode);
250 }
251 }
252
MaoLu2846b112017-05-15 17:18:55 -0700253 // Protection switch operation type and path index
254 private static final String OPS_ARRAY_INDEX = "index";
255 private static final String OPS_ARRAY_OPERATION = "operation";
256 private static final String[] OPS_NON_AUTO_OPTS = {OPS_OPT_FORCE, OPS_OPT_MANUAL};
257
MaoLu937cf422017-03-03 23:31:46 -0800258 private final class CreateShowItemsRequestHandler extends RequestHandler {
259 private static final String SHOW_TARGET_POWER = "showTargetPower";
260 private static final String SHOW_SERVICE_STATE = "showServiceState";
261 private static final String SHOW_FLOW_ICON = "showFlowIcon";
MaoLu2846b112017-05-15 17:18:55 -0700262 private static final String OPS_PATHS = "opsOperations";
263 private static final String OPS_ARRAY_NAME = "name";
264 private static final String OPS_GROUP_FMT = "GROUP%d ";
MaoLu937cf422017-03-03 23:31:46 -0800265
266 private CreateShowItemsRequestHandler() {
267 super(ROADM_SHOW_ITEMS_REQ);
268 }
269
270 @Override
271 public void process(ObjectNode payload) {
272 DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
273 Type devType = deviceService.getDevice(did).type();
274 // Build response
275 ObjectNode node = objectNode();
MaoLu937cf422017-03-03 23:31:46 -0800276 node.put(SHOW_FLOW_ICON, devType == Type.ROADM);
MaoLu2846b112017-05-15 17:18:55 -0700277 if (devType == Type.FIBER_SWITCH) {
278 node.put(SHOW_TARGET_POWER, false);
279 node.put(SHOW_SERVICE_STATE, true);
280 // add protection switch paths
281 putProtectionSwitchPaths(did, node);
282 } else {
283 node.put(SHOW_TARGET_POWER, true);
284 node.put(SHOW_SERVICE_STATE, false);
285 }
MaoLu937cf422017-03-03 23:31:46 -0800286 sendMessage(ROADM_SHOW_ITEMS_RESP, node);
287 }
MaoLu2846b112017-05-15 17:18:55 -0700288
289 private void putProtectionSwitchPaths(DeviceId deviceId, ObjectNode node) {
290 Map<ConnectPoint, ProtectedTransportEndpointState> states =
291 roadmService.getProtectionSwitchStates(deviceId);
292 ArrayNode nodes = node.putArray(OPS_PATHS);
293 // Add path names for every identifier.
294 int groupIndex = 0;
295 for (ConnectPoint identifier : states.keySet()) {
296 // No group name needed if there is only one connection point identifier.
297 String groupName = states.keySet().size() == 1 ? "" : String.format(OPS_GROUP_FMT, ++groupIndex);
298 // Add AUTOMATIC operation.
299 nodes.add(new ObjectNode(JsonNodeFactory.instance)
300 .put(OPS_ARRAY_INDEX, ACTIVE_UNKNOWN)
301 .put(OPS_ARRAY_OPERATION, OPS_OPT_AUTO)
302 .put(OPS_ARRAY_NAME, String.format("%s%s", groupName, OPS_OPT_AUTO)));
303 // Add FORCE and MANUAL operations for every path.
304 for (String opt : OPS_NON_AUTO_OPTS) {
305 int pathIndex = 0;
306 for (TransportEndpointState state : states.get(identifier).pathStates()) {
307 nodes.add(new ObjectNode(JsonNodeFactory.instance)
308 .put(OPS_ARRAY_INDEX, pathIndex++)
309 .put(OPS_ARRAY_OPERATION, opt)
310 .put(OPS_ARRAY_NAME,
311 String.format("%s%s %s", groupName, opt, state.id().id().toUpperCase())));
312 }
313 }
314 }
315
316
317 }
MaoLu937cf422017-03-03 23:31:46 -0800318 }
319
320 private final class CreateOpsModeSetRequestHandler extends RequestHandler {
MaoLu937cf422017-03-03 23:31:46 -0800321 private static final String DEVICE_INVALID_ERR_MSG = "Apply failed: device is offline or unavailable.";
322 private static final String TYPE_INVALID_ERR_MSG = "Apply failed: invalid device type.";
323
324 private CreateOpsModeSetRequestHandler() {
325 super(ROADM_SET_OPS_MODE_REQ);
326 }
327
328 @Override
329 public void process(ObjectNode payload) {
330 DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
331 ObjectNode node = objectNode();
332 if (!deviceService.isAvailable(did)) {
333 node.put(RoadmUtil.VALID, false);
334 node.put(RoadmUtil.MESSAGE, DEVICE_INVALID_ERR_MSG);
335 sendMessage(ROADM_SET_OPS_MODE_RESP, node);
336 return;
337 }
338 Type devType = deviceService.getDevice(did).type();
339 if (devType != Type.FIBER_SWITCH) {
340 node.put(RoadmUtil.VALID, false);
341 node.put(RoadmUtil.MESSAGE, TYPE_INVALID_ERR_MSG);
342 sendMessage(ROADM_SET_OPS_MODE_RESP, node);
343 return;
344 }
MaoLu2846b112017-05-15 17:18:55 -0700345 // get switch configuration from payload, and then switch the device.
346 roadmService.configProtectionSwitch(did, string(payload, OPS_ARRAY_OPERATION),
347 roadmService.getProtectionSwitchStates(did).keySet().toArray(new ConnectPoint[0])[0],
348 (int) number(payload, OPS_ARRAY_INDEX));
MaoLu937cf422017-03-03 23:31:46 -0800349 node.put(RoadmUtil.VALID, true);
350 sendMessage(ROADM_SET_OPS_MODE_RESP, node);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700351 }
352 }
353}