blob: 2f25bb36f511fce2b78ee7fc0d741cc0605dd457 [file] [log] [blame]
Andrea Campanella945ded22016-01-07 13:17:43 -08001/*
2 * Copyright 2016 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
17package org.onosproject.provider.rest.device.impl;
18
19import com.google.common.base.Preconditions;
20import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.onlab.packet.ChassisId;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
28import org.onosproject.incubator.net.config.basics.ConfigException;
Marc De Leenheerb0d131c2016-03-01 20:34:59 -080029import org.onosproject.net.AnnotationKeys;
Andrea Campanella945ded22016-01-07 13:17:43 -080030import org.onosproject.net.DefaultAnnotations;
31import org.onosproject.net.Device;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.MastershipRole;
34import org.onosproject.net.SparseAnnotations;
Andrea Campanellad8d92db2016-01-14 16:24:41 -080035import org.onosproject.net.behaviour.PortDiscovery;
Andrea Campanella945ded22016-01-07 13:17:43 -080036import org.onosproject.net.config.ConfigFactory;
37import org.onosproject.net.config.NetworkConfigEvent;
38import org.onosproject.net.config.NetworkConfigListener;
39import org.onosproject.net.config.NetworkConfigRegistry;
40import org.onosproject.net.device.DefaultDeviceDescription;
41import org.onosproject.net.device.DeviceDescription;
42import org.onosproject.net.device.DeviceProvider;
43import org.onosproject.net.device.DeviceProviderRegistry;
44import org.onosproject.net.device.DeviceProviderService;
Andrea Campanellad8d92db2016-01-14 16:24:41 -080045import org.onosproject.net.driver.DriverHandler;
46import org.onosproject.net.driver.DriverService;
Andrea Campanella945ded22016-01-07 13:17:43 -080047import org.onosproject.net.provider.AbstractProvider;
48import org.onosproject.net.provider.ProviderId;
49import org.onosproject.protocol.rest.RestSBController;
50import org.onosproject.protocol.rest.RestSBDevice;
51import org.slf4j.Logger;
52
Andrea Campanellac6ecc632016-03-10 17:57:06 -080053import javax.ws.rs.ProcessingException;
Andrea Campanella945ded22016-01-07 13:17:43 -080054import java.util.HashSet;
Andrea Campanella945ded22016-01-07 13:17:43 -080055import java.util.Set;
Andrea Campanella784ee0f2016-02-17 15:50:59 -080056import java.util.concurrent.ExecutorService;
57import java.util.concurrent.Executors;
Andrea Campanella945ded22016-01-07 13:17:43 -080058
Andrea Campanella784ee0f2016-02-17 15:50:59 -080059import static org.onlab.util.Tools.groupedThreads;
Andrea Campanella945ded22016-01-07 13:17:43 -080060import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_ADDED;
61import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UPDATED;
62import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
63import static org.slf4j.LoggerFactory.getLogger;
64
65/**
66 * Provider for devices that use REST as means of configuration communication.
67 */
68@Component(immediate = true)
69public class RestDeviceProvider extends AbstractProvider
70 implements DeviceProvider {
71 private static final String APP_NAME = "org.onosproject.restsb";
72 private static final String REST = "rest";
73 private static final String PROVIDER = "org.onosproject.provider.rest.device";
74 private static final String IPADDRESS = "ipaddress";
75 private static final int TEST_CONNECT_TIMEOUT = 1000;
Andrea Campanella2947e622016-01-27 09:23:46 -080076 private static final String HTTPS = "https";
77 private static final String AUTHORIZATION_PROPERTY = "authorization";
78 private static final String BASIC_AUTH_PREFIX = "Basic ";
79 private static final String URL_SEPARATOR = "://";
Andrea Campanella945ded22016-01-07 13:17:43 -080080 private final Logger log = getLogger(getClass());
81
82 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 protected DeviceProviderRegistry providerRegistry;
84
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected RestSBController controller;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected NetworkConfigRegistry cfgService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected CoreService coreService;
93
Andrea Campanellad8d92db2016-01-14 16:24:41 -080094 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected DriverService driverService;
96
Andrea Campanella945ded22016-01-07 13:17:43 -080097
98 private DeviceProviderService providerService;
99 protected static final String ISNOTNULL = "Rest device is not null";
100 private static final String UNKNOWN = "unknown";
101
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800102 private final ExecutorService executor =
Andrea Campanella90f044f2016-03-02 09:14:57 -0800103 Executors.newFixedThreadPool(5, groupedThreads("onos/restsbprovider", "device-installer-%d", log));
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800104
Andrea Campanella945ded22016-01-07 13:17:43 -0800105 private final ConfigFactory factory =
106 new ConfigFactory<ApplicationId, RestProviderConfig>(APP_SUBJECT_FACTORY,
107 RestProviderConfig.class,
108 "restDevices",
109 true) {
110 @Override
111 public RestProviderConfig createConfig() {
112 return new RestProviderConfig();
113 }
114 };
115 private final NetworkConfigListener cfgLister = new InternalNetworkConfigListener();
116 private ApplicationId appId;
117
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800118 private Set<DeviceId> addedDevices = new HashSet<>();
119
Andrea Campanella945ded22016-01-07 13:17:43 -0800120
121 @Activate
122 public void activate() {
123 appId = coreService.registerApplication(APP_NAME);
124 providerService = providerRegistry.register(this);
125 cfgService.registerConfigFactory(factory);
126 cfgService.addListener(cfgLister);
Andrea Campanella7d8449b2016-03-02 10:16:42 -0800127 executor.execute(RestDeviceProvider.this::connectDevices);
Andrea Campanella945ded22016-01-07 13:17:43 -0800128 log.info("Started");
129 }
130
Andrea Campanella945ded22016-01-07 13:17:43 -0800131 @Deactivate
132 public void deactivate() {
Andrea Campanella86294db2016-03-07 11:42:49 -0800133 cfgService.removeListener(cfgLister);
134 controller.getDevices().keySet().forEach(this::deviceRemoved);
Andrea Campanella945ded22016-01-07 13:17:43 -0800135 providerRegistry.unregister(this);
136 providerService = null;
137 cfgService.unregisterConfigFactory(factory);
Andrea Campanella945ded22016-01-07 13:17:43 -0800138 log.info("Stopped");
139 }
140
141 public RestDeviceProvider() {
142 super(new ProviderId(REST, PROVIDER));
143 }
144
145 @Override
146 public void triggerProbe(DeviceId deviceId) {
147 // TODO: This will be implemented later.
148 log.info("Triggering probe on device {}", deviceId);
149 }
150
151 @Override
152 public void roleChanged(DeviceId deviceId, MastershipRole newRole) {
153 // TODO: This will be implemented later.
154 }
155
156
157 @Override
158 public boolean isReachable(DeviceId deviceId) {
159 RestSBDevice restDevice = controller.getDevice(deviceId);
160 if (restDevice == null) {
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800161 log.debug("the requested device id: " +
162 deviceId.toString() +
163 " is not associated to any REST Device");
Andrea Campanella945ded22016-01-07 13:17:43 -0800164 return false;
165 }
166 return restDevice.isActive();
167 }
168
169 private void deviceAdded(RestSBDevice nodeId) {
170 Preconditions.checkNotNull(nodeId, ISNOTNULL);
171 DeviceId deviceId = nodeId.deviceId();
172 ChassisId cid = new ChassisId();
173 String ipAddress = nodeId.ip().toString();
174 SparseAnnotations annotations = DefaultAnnotations.builder()
Marc De Leenheerb0d131c2016-03-01 20:34:59 -0800175 .set(IPADDRESS, ipAddress)
176 .set(AnnotationKeys.PROTOCOL, REST.toUpperCase())
177 .build();
Andrea Campanella945ded22016-01-07 13:17:43 -0800178 DeviceDescription deviceDescription = new DefaultDeviceDescription(
179 deviceId.uri(),
180 Device.Type.SWITCH,
181 UNKNOWN, UNKNOWN,
182 UNKNOWN, UNKNOWN,
183 cid,
184 annotations);
Andrea Campanella945ded22016-01-07 13:17:43 -0800185 nodeId.setActive(true);
Andrea Campanellac6ecc632016-03-10 17:57:06 -0800186 providerService.deviceConnected(deviceId, deviceDescription);
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800187 addedDevices.add(deviceId);
Andrea Campanella945ded22016-01-07 13:17:43 -0800188 }
189
Andrea Campanella86294db2016-03-07 11:42:49 -0800190 private void deviceRemoved(DeviceId deviceId) {
191 Preconditions.checkNotNull(deviceId, ISNOTNULL);
Andrea Campanella945ded22016-01-07 13:17:43 -0800192 providerService.deviceDisconnected(deviceId);
Andrea Campanella86294db2016-03-07 11:42:49 -0800193 controller.removeDevice(deviceId);
Andrea Campanella945ded22016-01-07 13:17:43 -0800194 }
195
196 private void connectDevices() {
197 RestProviderConfig cfg = cfgService.getConfig(appId, RestProviderConfig.class);
198 try {
199 if (cfg != null && cfg.getDevicesAddresses() != null) {
200 //Precomputing the devices to be removed
201 Set<RestSBDevice> toBeRemoved = new HashSet<>(controller.getDevices().values());
202 toBeRemoved.removeAll(cfg.getDevicesAddresses());
203 //Adding new devices
204 cfg.getDevicesAddresses().stream()
Andrea Campanellac6ecc632016-03-10 17:57:06 -0800205 .filter(device -> {
206 device.setActive(false);
207 controller.addDevice(device);
208 return testDeviceConnection(device);
209 })
Andrea Campanella945ded22016-01-07 13:17:43 -0800210 .forEach(device -> {
211 deviceAdded(device);
212 });
213 //Removing devices not wanted anymore
Andrea Campanella86294db2016-03-07 11:42:49 -0800214 toBeRemoved.stream().forEach(device -> deviceRemoved(device.deviceId()));
Andrea Campanella945ded22016-01-07 13:17:43 -0800215
216 }
217 } catch (ConfigException e) {
218 log.error("Configuration error {}", e);
219 }
Andrea Campanella2947e622016-01-27 09:23:46 -0800220 log.debug("REST Devices {}", controller.getDevices());
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800221 addedDevices.forEach(deviceId -> {
Andrea Campanellad8d92db2016-01-14 16:24:41 -0800222 DriverHandler h = driverService.createHandler(deviceId);
223 PortDiscovery portConfig = h.behaviour(PortDiscovery.class);
224 if (portConfig != null) {
225 providerService.updatePorts(deviceId, portConfig.getPorts());
226 } else {
227 log.warn("No portGetter behaviour for device {}", deviceId);
228 }
229 });
Andrea Campanella784ee0f2016-02-17 15:50:59 -0800230 addedDevices.clear();
231
Andrea Campanella945ded22016-01-07 13:17:43 -0800232 }
233
234 private boolean testDeviceConnection(RestSBDevice device) {
235 try {
Andrea Campanellac6ecc632016-03-10 17:57:06 -0800236 return controller.get(device.deviceId(), "", "json") != null;
237 } catch (ProcessingException e) {
238 log.warn("Cannot connect to device {}", device, e);
Andrea Campanella945ded22016-01-07 13:17:43 -0800239 }
240 return false;
241 }
242
243 private class InternalNetworkConfigListener implements NetworkConfigListener {
244
245
246 @Override
247 public void event(NetworkConfigEvent event) {
Andrea Campanella90f044f2016-03-02 09:14:57 -0800248 executor.execute(RestDeviceProvider.this::connectDevices);
Andrea Campanella945ded22016-01-07 13:17:43 -0800249 }
250
251 @Override
252 public boolean isRelevant(NetworkConfigEvent event) {
253 //TODO refactor
254 return event.configClass().equals(RestProviderConfig.class) &&
255 (event.type() == CONFIG_ADDED ||
256 event.type() == CONFIG_UPDATED);
257 }
258 }
259}