blob: 84297f80551caddd3c013135a385c249905b2327 [file] [log] [blame]
Jimmy Yanda878fc2016-09-02 16:32:01 -07001/*
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 */
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;
MaoLu2846b112017-05-15 17:18:55 -070034import org.onosproject.net.optical.OpticalAnnotations;
Jimmy Yanda878fc2016-09-02 16:32:01 -070035import org.onosproject.ui.RequestHandler;
36import org.onosproject.ui.UiConnection;
37import org.onosproject.ui.UiMessageHandler;
38import org.onosproject.ui.table.TableModel;
39import org.onosproject.ui.table.TableRequestHandler;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
43import java.util.Collection;
MaoLu937cf422017-03-03 23:31:46 -080044import java.util.Collections;
45import java.util.Comparator;
Jimmy Yanda878fc2016-09-02 16:32:01 -070046import java.util.List;
MaoLu2846b112017-05-15 17:18:55 -070047import java.util.Map;
MaoLu937cf422017-03-03 23:31:46 -080048import java.util.Set;
49
50import static org.onosproject.net.Device.Type;
MaoLu2846b112017-05-15 17:18:55 -070051import static org.onosproject.net.behaviour.protection.ProtectedTransportEndpointState.ACTIVE_UNKNOWN;
52import static org.onosproject.roadm.RoadmUtil.OPS_OPT_AUTO;
53import static org.onosproject.roadm.RoadmUtil.OPS_OPT_FORCE;
54import static org.onosproject.roadm.RoadmUtil.OPS_OPT_MANUAL;
Jimmy Yanda878fc2016-09-02 16:32:01 -070055
56/**
57 * Table-View message handler for ROADM port view.
58 */
59public class RoadmPortViewMessageHandler extends UiMessageHandler {
60
61 private static final String ROADM_PORT_DATA_REQ = "roadmPortDataRequest";
62 private static final String ROADM_PORT_DATA_RESP = "roadmPortDataResponse";
63 private static final String ROADM_PORTS = "roadmPorts";
Jimmy Yanda878fc2016-09-02 16:32:01 -070064 private static final String ROADM_SET_TARGET_POWER_REQ = "roadmSetTargetPowerRequest";
65 private static final String ROADM_SET_TARGET_POWER_RESP = "roadmSetTargetPowerResponse";
MaoLu937cf422017-03-03 23:31:46 -080066 private static final String ROADM_SHOW_ITEMS_REQ = "roadmShowPortItemsRequest";
67 private static final String ROADM_SHOW_ITEMS_RESP = "roadmShowPortItemsResponse";
68 private static final String ROADM_SET_OPS_MODE_REQ = "roadmSetOpsModeRequest";
69 private static final String ROADM_SET_OPS_MODE_RESP = "roadmSetOpsModeResponse";
Jimmy Yanda878fc2016-09-02 16:32:01 -070070
71 private static final String ID = "id";
Jimmy Yanda878fc2016-09-02 16:32:01 -070072 private static final String NAME = "name";
MaoLu937cf422017-03-03 23:31:46 -080073 private static final String TYPE = "type";
Jimmy Yanda878fc2016-09-02 16:32:01 -070074 private static final String ENABLED = "enabled";
75 private static final String MIN_FREQ = "minFreq";
76 private static final String MAX_FREQ = "maxFreq";
77 private static final String GRID = "grid";
MaoLu2f7eadb2017-05-02 15:38:43 -070078 private static final String POWER_RANGE = "powerRange";
Jimmy Yanda878fc2016-09-02 16:32:01 -070079 private static final String CURRENT_POWER = "currentPower";
80 private static final String TARGET_POWER = "targetPower";
81 private static final String HAS_TARGET_POWER = "hasTargetPower";
MaoLu937cf422017-03-03 23:31:46 -080082 private static final String SERVICE_STATE = "serviceState";
Jimmy Yanda878fc2016-09-02 16:32:01 -070083
84 private static final String[] COLUMN_IDS = {
MaoLu2f7eadb2017-05-02 15:38:43 -070085 ID, TYPE, NAME, ENABLED, MIN_FREQ, MAX_FREQ, GRID, POWER_RANGE,
MaoLu937cf422017-03-03 23:31:46 -080086 CURRENT_POWER, SERVICE_STATE, TARGET_POWER, HAS_TARGET_POWER
Jimmy Yanda878fc2016-09-02 16:32:01 -070087 };
88
Jimmy Yanda878fc2016-09-02 16:32:01 -070089 private RoadmService roadmService;
MaoLu937cf422017-03-03 23:31:46 -080090 private DeviceService deviceService;
Jimmy Yanda878fc2016-09-02 16:32:01 -070091
92 private final Logger log = LoggerFactory.getLogger(getClass());
93
94 @Override
95 public void init(UiConnection connection, ServiceDirectory directory) {
96 super.init(connection, directory);
Jimmy Yanda878fc2016-09-02 16:32:01 -070097 roadmService = get(RoadmService.class);
MaoLu937cf422017-03-03 23:31:46 -080098 deviceService = get(DeviceService.class);
Jimmy Yanda878fc2016-09-02 16:32:01 -070099 }
100
101 @Override
102 protected Collection<RequestHandler> createRequestHandlers() {
MaoLu937cf422017-03-03 23:31:46 -0800103 return ImmutableSet.of(new PortTableDataRequestHandler(),
104 new SetTargetPowerRequestHandler(),
105 new CreateShowItemsRequestHandler(),
106 new CreateOpsModeSetRequestHandler()
107 );
Jimmy Yanda878fc2016-09-02 16:32:01 -0700108 }
109
110 // Handler for sample table requests
111 private final class PortTableDataRequestHandler extends TableRequestHandler {
112
113 private PortTableDataRequestHandler() {
114 super(ROADM_PORT_DATA_REQ, ROADM_PORT_DATA_RESP, ROADM_PORTS);
115 }
116
117 @Override
118 protected String[] getColumnIds() {
119 return COLUMN_IDS;
120 }
121
122 @Override
123 protected String noRowsMessage(ObjectNode payload) {
MaoLu937cf422017-03-03 23:31:46 -0800124 return RoadmUtil.NO_ROWS_MESSAGE;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700125 }
126
127 @Override
128 protected void populateTable(TableModel tm, ObjectNode payload) {
MaoLu937cf422017-03-03 23:31:46 -0800129 DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
Jimmy Yanda878fc2016-09-02 16:32:01 -0700130 if (deviceService.isAvailable(deviceId)) {
131 List<Port> ports = deviceService.getPorts(deviceId);
132 for (Port port : ports) {
133 populateRow(tm.addRow(), port, deviceId);
134 }
135 }
136 }
137
138 private void populateRow(TableModel.Row row, Port port, DeviceId deviceId) {
MaoLu937cf422017-03-03 23:31:46 -0800139 PortNumber portNum = port.number();
140 getFrequencyLimit(deviceId, portNum);
141 row.cell(ID, portNum.toLong())
Jimmy Yanda878fc2016-09-02 16:32:01 -0700142 .cell(TYPE, port.type())
143 .cell(ENABLED, port.isEnabled())
MaoLu937cf422017-03-03 23:31:46 -0800144 .cell(NAME, RoadmUtil.getAnnotation(port.annotations(), AnnotationKeys.PORT_NAME))
145 .cell(MIN_FREQ, RoadmUtil.asTHz(minFreq))
146 .cell(MAX_FREQ, RoadmUtil.asTHz(maxFreq))
147 .cell(GRID, RoadmUtil.asGHz(channelSpacing))
MaoLu2f7eadb2017-05-02 15:38:43 -0700148 .cell(POWER_RANGE, getPowerRange(deviceId, portNum))
MaoLu937cf422017-03-03 23:31:46 -0800149 .cell(CURRENT_POWER, getCurrentPower(deviceId, portNum))
150 .cell(SERVICE_STATE, getPortServiceState(deviceId, portNum))
151 .cell(TARGET_POWER, getTargetPower(deviceId, portNum))
152 .cell(HAS_TARGET_POWER, roadmService.hasPortTargetPower(deviceId, portNum));
153 }
154
155 private String getPortServiceState(DeviceId deviceId, PortNumber portNumber) {
MaoLu2846b112017-05-15 17:18:55 -0700156 if (deviceService.getDevice(deviceId).type() != Type.FIBER_SWITCH) {
157 return RoadmUtil.NA;
158 }
159 Map<ConnectPoint, ProtectedTransportEndpointState> map =
160 roadmService.getProtectionSwitchStates(deviceId);
161 for (ProtectedTransportEndpointState state : map.values()) {
162 for (TransportEndpointState element : state.pathStates()) {
163 if (element.description().output().connectPoint().port().equals(portNumber)) {
164 return RoadmUtil.defaultString(element.attributes()
165 .get(OpticalAnnotations.INPUT_PORT_STATUS), RoadmUtil.UNKNOWN);
166 }
167 }
168 }
169 return RoadmUtil.UNKNOWN;
MaoLu937cf422017-03-03 23:31:46 -0800170 }
171
172 private Frequency minFreq = null, maxFreq = null, channelSpacing = null;
173 // Gets min frequency, max frequency, channel spacing
174 private void getFrequencyLimit(DeviceId deviceId, PortNumber portNumber) {
175 Set<OchSignal> signals = roadmService.queryLambdas(deviceId, portNumber);
176 if (signals.isEmpty()) {
177 return;
178 }
179 Comparator<OchSignal> compare =
180 (OchSignal a, OchSignal b) -> a.spacingMultiplier() - b.spacingMultiplier();
181 OchSignal minOch = Collections.min(signals, compare);
182 OchSignal maxOch = Collections.max(signals, compare);
183 minFreq = minOch.centralFrequency();
184 maxFreq = maxOch.centralFrequency();
185 channelSpacing = minOch.channelSpacing().frequency();
Jimmy Yanda878fc2016-09-02 16:32:01 -0700186 }
187
MaoLu2f7eadb2017-05-02 15:38:43 -0700188 // Returns the power range as a string, N/A if the power range not exists.
189 // The power range would be input power range or target power range determined by port property.
190 // If the port is RX direction then acquire the input power range from driver.
191 // Otherwise there will be a TX direction port, thus acquire the target power range.
192 private String getPowerRange(DeviceId deviceId, PortNumber portNumber) {
MaoLu937cf422017-03-03 23:31:46 -0800193 Range<Long> range = roadmService.inputPortPowerRange(deviceId, portNumber);
MaoLu2f7eadb2017-05-02 15:38:43 -0700194 if (range == null) {
195 range = roadmService.targetPortPowerRange(deviceId, portNumber);
196 }
MaoLu937cf422017-03-03 23:31:46 -0800197 return RoadmUtil.objectToString(range, RoadmUtil.NA);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700198 }
199
200 // Returns the current power as a string, Unknown if no value can be found.
201 private String getCurrentPower(DeviceId deviceId, PortNumber portNumber) {
MaoLu937cf422017-03-03 23:31:46 -0800202 Long currentPower = roadmService.getCurrentPortPower(deviceId, portNumber);
203 return RoadmUtil.objectToString(currentPower, RoadmUtil.UNKNOWN);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700204 }
205
206 // Returns target power as a string, Unknown if target power is expected but
207 // cannot be found, N/A if port does not have configurable target power
208 private String getTargetPower(DeviceId deviceId, PortNumber portNumber) {
MaoLu937cf422017-03-03 23:31:46 -0800209 if (!roadmService.hasPortTargetPower(deviceId, portNumber)) {
210 return RoadmUtil.NA;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700211 }
MaoLu937cf422017-03-03 23:31:46 -0800212 Long targetPower = roadmService.getTargetPortPower(deviceId, portNumber);
213 return RoadmUtil.objectToString(targetPower, RoadmUtil.UNKNOWN);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700214 }
215 }
216
217
218 // Handler for setting port target power
219 private final class SetTargetPowerRequestHandler extends RequestHandler {
220
Jimmy Yanda878fc2016-09-02 16:32:01 -0700221 private static final String TARGET_POWER_ERR_MSG = "Target power range is %s.";
222
223 private SetTargetPowerRequestHandler() {
224 super(ROADM_SET_TARGET_POWER_REQ);
225 }
226
227 @Override
228 public void process(ObjectNode payload) {
MaoLu937cf422017-03-03 23:31:46 -0800229 DeviceId deviceId = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
Jimmy Yanda878fc2016-09-02 16:32:01 -0700230 PortNumber portNumber = PortNumber.portNumber(payload.get(ID).asLong());
MaoLu937cf422017-03-03 23:31:46 -0800231 Range<Long> range = roadmService.targetPortPowerRange(deviceId, portNumber);
232 if (range == null) {
Jimmy Yanda878fc2016-09-02 16:32:01 -0700233 log.warn("Unable to determine target power range for device {}", deviceId);
MaoLu937cf422017-03-03 23:31:46 -0800234 return;
Jimmy Yanda878fc2016-09-02 16:32:01 -0700235 }
MaoLu937cf422017-03-03 23:31:46 -0800236 Long targetPower = payload.get(TARGET_POWER).asLong();
237 boolean validTargetPower = range.contains(targetPower);
238 if (validTargetPower) {
239 roadmService.setTargetPortPower(deviceId, portNumber, targetPower);
240 }
241 ObjectNode rootNode = objectNode();
242 rootNode.put(ID, payload.get(ID).asText());
243 rootNode.put(RoadmUtil.VALID, validTargetPower);
244 rootNode.put(RoadmUtil.MESSAGE, String.format(TARGET_POWER_ERR_MSG, range.toString()));
245 sendMessage(ROADM_SET_TARGET_POWER_RESP, rootNode);
246 }
247 }
248
MaoLu2846b112017-05-15 17:18:55 -0700249 // Protection switch operation type and path index
250 private static final String OPS_ARRAY_INDEX = "index";
251 private static final String OPS_ARRAY_OPERATION = "operation";
252 private static final String[] OPS_NON_AUTO_OPTS = {OPS_OPT_FORCE, OPS_OPT_MANUAL};
253
MaoLu937cf422017-03-03 23:31:46 -0800254 private final class CreateShowItemsRequestHandler extends RequestHandler {
255 private static final String SHOW_TARGET_POWER = "showTargetPower";
256 private static final String SHOW_SERVICE_STATE = "showServiceState";
257 private static final String SHOW_FLOW_ICON = "showFlowIcon";
MaoLu2846b112017-05-15 17:18:55 -0700258 private static final String OPS_PATHS = "opsOperations";
259 private static final String OPS_ARRAY_NAME = "name";
260 private static final String OPS_GROUP_FMT = "GROUP%d ";
MaoLu937cf422017-03-03 23:31:46 -0800261
262 private CreateShowItemsRequestHandler() {
263 super(ROADM_SHOW_ITEMS_REQ);
264 }
265
266 @Override
267 public void process(ObjectNode payload) {
268 DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
269 Type devType = deviceService.getDevice(did).type();
270 // Build response
271 ObjectNode node = objectNode();
MaoLu937cf422017-03-03 23:31:46 -0800272 node.put(SHOW_FLOW_ICON, devType == Type.ROADM);
MaoLu2846b112017-05-15 17:18:55 -0700273 if (devType == Type.FIBER_SWITCH) {
274 node.put(SHOW_TARGET_POWER, false);
275 node.put(SHOW_SERVICE_STATE, true);
276 // add protection switch paths
277 putProtectionSwitchPaths(did, node);
278 } else {
279 node.put(SHOW_TARGET_POWER, true);
280 node.put(SHOW_SERVICE_STATE, false);
281 }
MaoLu937cf422017-03-03 23:31:46 -0800282 sendMessage(ROADM_SHOW_ITEMS_RESP, node);
283 }
MaoLu2846b112017-05-15 17:18:55 -0700284
285 private void putProtectionSwitchPaths(DeviceId deviceId, ObjectNode node) {
286 Map<ConnectPoint, ProtectedTransportEndpointState> states =
287 roadmService.getProtectionSwitchStates(deviceId);
288 ArrayNode nodes = node.putArray(OPS_PATHS);
289 // Add path names for every identifier.
290 int groupIndex = 0;
291 for (ConnectPoint identifier : states.keySet()) {
292 // No group name needed if there is only one connection point identifier.
293 String groupName = states.keySet().size() == 1 ? "" : String.format(OPS_GROUP_FMT, ++groupIndex);
294 // Add AUTOMATIC operation.
295 nodes.add(new ObjectNode(JsonNodeFactory.instance)
296 .put(OPS_ARRAY_INDEX, ACTIVE_UNKNOWN)
297 .put(OPS_ARRAY_OPERATION, OPS_OPT_AUTO)
298 .put(OPS_ARRAY_NAME, String.format("%s%s", groupName, OPS_OPT_AUTO)));
299 // Add FORCE and MANUAL operations for every path.
300 for (String opt : OPS_NON_AUTO_OPTS) {
301 int pathIndex = 0;
302 for (TransportEndpointState state : states.get(identifier).pathStates()) {
303 nodes.add(new ObjectNode(JsonNodeFactory.instance)
304 .put(OPS_ARRAY_INDEX, pathIndex++)
305 .put(OPS_ARRAY_OPERATION, opt)
306 .put(OPS_ARRAY_NAME,
307 String.format("%s%s %s", groupName, opt, state.id().id().toUpperCase())));
308 }
309 }
310 }
311
312
313 }
MaoLu937cf422017-03-03 23:31:46 -0800314 }
315
316 private final class CreateOpsModeSetRequestHandler extends RequestHandler {
MaoLu937cf422017-03-03 23:31:46 -0800317 private static final String DEVICE_INVALID_ERR_MSG = "Apply failed: device is offline or unavailable.";
318 private static final String TYPE_INVALID_ERR_MSG = "Apply failed: invalid device type.";
319
320 private CreateOpsModeSetRequestHandler() {
321 super(ROADM_SET_OPS_MODE_REQ);
322 }
323
324 @Override
325 public void process(ObjectNode payload) {
326 DeviceId did = DeviceId.deviceId(string(payload, RoadmUtil.DEV_ID));
327 ObjectNode node = objectNode();
328 if (!deviceService.isAvailable(did)) {
329 node.put(RoadmUtil.VALID, false);
330 node.put(RoadmUtil.MESSAGE, DEVICE_INVALID_ERR_MSG);
331 sendMessage(ROADM_SET_OPS_MODE_RESP, node);
332 return;
333 }
334 Type devType = deviceService.getDevice(did).type();
335 if (devType != Type.FIBER_SWITCH) {
336 node.put(RoadmUtil.VALID, false);
337 node.put(RoadmUtil.MESSAGE, TYPE_INVALID_ERR_MSG);
338 sendMessage(ROADM_SET_OPS_MODE_RESP, node);
339 return;
340 }
MaoLu2846b112017-05-15 17:18:55 -0700341 // get switch configuration from payload, and then switch the device.
342 roadmService.configProtectionSwitch(did, string(payload, OPS_ARRAY_OPERATION),
343 roadmService.getProtectionSwitchStates(did).keySet().toArray(new ConnectPoint[0])[0],
344 (int) number(payload, OPS_ARRAY_INDEX));
MaoLu937cf422017-03-03 23:31:46 -0800345 node.put(RoadmUtil.VALID, true);
346 sendMessage(ROADM_SET_OPS_MODE_RESP, node);
Jimmy Yanda878fc2016-09-02 16:32:01 -0700347 }
348 }
349}