Committed by
Gerrit Code Review
[ONOS-4681] Enables device registration in GossipDeviceStore,
exposes availability, and polls NETCONF device reachability. Change-Id: I5492c7b6109c3431d71555a9104c7e97fc6e75be
Showing
12 changed files
with
231 additions
and
33 deletions
... | @@ -38,6 +38,7 @@ public class DefaultDeviceDescription extends AbstractDescription | ... | @@ -38,6 +38,7 @@ public class DefaultDeviceDescription extends AbstractDescription |
38 | private final String swVersion; | 38 | private final String swVersion; |
39 | private final String serialNumber; | 39 | private final String serialNumber; |
40 | private final ChassisId chassisId; | 40 | private final ChassisId chassisId; |
41 | + private final boolean defaultAvailable; | ||
41 | 42 | ||
42 | /** | 43 | /** |
43 | * Creates a device description using the supplied information. | 44 | * Creates a device description using the supplied information. |
... | @@ -55,6 +56,28 @@ public class DefaultDeviceDescription extends AbstractDescription | ... | @@ -55,6 +56,28 @@ public class DefaultDeviceDescription extends AbstractDescription |
55 | String hwVersion, String swVersion, | 56 | String hwVersion, String swVersion, |
56 | String serialNumber, ChassisId chassis, | 57 | String serialNumber, ChassisId chassis, |
57 | SparseAnnotations... annotations) { | 58 | SparseAnnotations... annotations) { |
59 | + this(uri, type, manufacturer, hwVersion, swVersion, serialNumber, | ||
60 | + chassis, true, annotations); | ||
61 | + } | ||
62 | + | ||
63 | + /** | ||
64 | + * Creates a device description using the supplied information. | ||
65 | + * | ||
66 | + * @param uri device URI | ||
67 | + * @param type device type | ||
68 | + * @param manufacturer device manufacturer | ||
69 | + * @param hwVersion device HW version | ||
70 | + * @param swVersion device SW version | ||
71 | + * @param serialNumber device serial number | ||
72 | + * @param chassis chassis id | ||
73 | + * @param defaultAvailable optional whether device is by default available | ||
74 | + * @param annotations optional key/value annotations map | ||
75 | + */ | ||
76 | + public DefaultDeviceDescription(URI uri, Type type, String manufacturer, | ||
77 | + String hwVersion, String swVersion, | ||
78 | + String serialNumber, ChassisId chassis, | ||
79 | + boolean defaultAvailable, | ||
80 | + SparseAnnotations... annotations) { | ||
58 | super(annotations); | 81 | super(annotations); |
59 | this.uri = checkNotNull(uri, "Device URI cannot be null"); | 82 | this.uri = checkNotNull(uri, "Device URI cannot be null"); |
60 | this.type = checkNotNull(type, "Device type cannot be null"); | 83 | this.type = checkNotNull(type, "Device type cannot be null"); |
... | @@ -63,6 +86,7 @@ public class DefaultDeviceDescription extends AbstractDescription | ... | @@ -63,6 +86,7 @@ public class DefaultDeviceDescription extends AbstractDescription |
63 | this.swVersion = swVersion; | 86 | this.swVersion = swVersion; |
64 | this.serialNumber = serialNumber; | 87 | this.serialNumber = serialNumber; |
65 | this.chassisId = chassis; | 88 | this.chassisId = chassis; |
89 | + this.defaultAvailable = defaultAvailable; | ||
66 | } | 90 | } |
67 | 91 | ||
68 | /** | 92 | /** |
... | @@ -74,7 +98,7 @@ public class DefaultDeviceDescription extends AbstractDescription | ... | @@ -74,7 +98,7 @@ public class DefaultDeviceDescription extends AbstractDescription |
74 | SparseAnnotations... annotations) { | 98 | SparseAnnotations... annotations) { |
75 | this(base.deviceUri(), base.type(), base.manufacturer(), | 99 | this(base.deviceUri(), base.type(), base.manufacturer(), |
76 | base.hwVersion(), base.swVersion(), base.serialNumber(), | 100 | base.hwVersion(), base.swVersion(), base.serialNumber(), |
77 | - base.chassisId(), annotations); | 101 | + base.chassisId(), base.isDefaultAvailable(), annotations); |
78 | } | 102 | } |
79 | 103 | ||
80 | /** | 104 | /** |
... | @@ -83,10 +107,26 @@ public class DefaultDeviceDescription extends AbstractDescription | ... | @@ -83,10 +107,26 @@ public class DefaultDeviceDescription extends AbstractDescription |
83 | * @param type device type | 107 | * @param type device type |
84 | * @param annotations Annotations to use. | 108 | * @param annotations Annotations to use. |
85 | */ | 109 | */ |
86 | - public DefaultDeviceDescription(DeviceDescription base, Type type, SparseAnnotations... annotations) { | 110 | + public DefaultDeviceDescription(DeviceDescription base, Type type, |
111 | + SparseAnnotations... annotations) { | ||
87 | this(base.deviceUri(), type, base.manufacturer(), | 112 | this(base.deviceUri(), type, base.manufacturer(), |
88 | base.hwVersion(), base.swVersion(), base.serialNumber(), | 113 | base.hwVersion(), base.swVersion(), base.serialNumber(), |
89 | - base.chassisId(), annotations); | 114 | + base.chassisId(), base.isDefaultAvailable(), annotations); |
115 | + } | ||
116 | + | ||
117 | + /** | ||
118 | + * Creates a device description using the supplied information. | ||
119 | + * | ||
120 | + * @param base DeviceDescription to basic information (except for defaultAvailable) | ||
121 | + * @param defaultAvailable whether device should be made available by default | ||
122 | + * @param annotations Annotations to use. | ||
123 | + */ | ||
124 | + public DefaultDeviceDescription(DeviceDescription base, | ||
125 | + boolean defaultAvailable, | ||
126 | + SparseAnnotations... annotations) { | ||
127 | + this(base.deviceUri(), base.type(), base.manufacturer(), | ||
128 | + base.hwVersion(), base.swVersion(), base.serialNumber(), | ||
129 | + base.chassisId(), defaultAvailable, annotations); | ||
90 | } | 130 | } |
91 | 131 | ||
92 | @Override | 132 | @Override |
... | @@ -125,6 +165,11 @@ public class DefaultDeviceDescription extends AbstractDescription | ... | @@ -125,6 +165,11 @@ public class DefaultDeviceDescription extends AbstractDescription |
125 | } | 165 | } |
126 | 166 | ||
127 | @Override | 167 | @Override |
168 | + public boolean isDefaultAvailable() { | ||
169 | + return defaultAvailable; | ||
170 | + } | ||
171 | + | ||
172 | + @Override | ||
128 | public String toString() { | 173 | public String toString() { |
129 | return toStringHelper(this) | 174 | return toStringHelper(this) |
130 | .add("uri", uri).add("type", type).add("mfr", manufacturer) | 175 | .add("uri", uri).add("type", type).add("mfr", manufacturer) |
... | @@ -137,7 +182,8 @@ public class DefaultDeviceDescription extends AbstractDescription | ... | @@ -137,7 +182,8 @@ public class DefaultDeviceDescription extends AbstractDescription |
137 | @Override | 182 | @Override |
138 | public int hashCode() { | 183 | public int hashCode() { |
139 | return Objects.hashCode(super.hashCode(), uri, type, manufacturer, | 184 | return Objects.hashCode(super.hashCode(), uri, type, manufacturer, |
140 | - hwVersion, swVersion, serialNumber, chassisId); | 185 | + hwVersion, swVersion, serialNumber, chassisId, |
186 | + defaultAvailable); | ||
141 | } | 187 | } |
142 | 188 | ||
143 | @Override | 189 | @Override |
... | @@ -153,7 +199,8 @@ public class DefaultDeviceDescription extends AbstractDescription | ... | @@ -153,7 +199,8 @@ public class DefaultDeviceDescription extends AbstractDescription |
153 | && Objects.equal(this.hwVersion, that.hwVersion) | 199 | && Objects.equal(this.hwVersion, that.hwVersion) |
154 | && Objects.equal(this.swVersion, that.swVersion) | 200 | && Objects.equal(this.swVersion, that.swVersion) |
155 | && Objects.equal(this.serialNumber, that.serialNumber) | 201 | && Objects.equal(this.serialNumber, that.serialNumber) |
156 | - && Objects.equal(this.chassisId, that.chassisId); | 202 | + && Objects.equal(this.chassisId, that.chassisId) |
203 | + && Objects.equal(this.defaultAvailable, that.defaultAvailable); | ||
157 | } | 204 | } |
158 | return false; | 205 | return false; |
159 | } | 206 | } |
... | @@ -167,5 +214,6 @@ public class DefaultDeviceDescription extends AbstractDescription | ... | @@ -167,5 +214,6 @@ public class DefaultDeviceDescription extends AbstractDescription |
167 | this.swVersion = null; | 214 | this.swVersion = null; |
168 | this.serialNumber = null; | 215 | this.serialNumber = null; |
169 | this.chassisId = null; | 216 | this.chassisId = null; |
217 | + this.defaultAvailable = true; | ||
170 | } | 218 | } |
171 | } | 219 | } | ... | ... |
... | @@ -77,4 +77,11 @@ public interface DeviceDescription extends Description { | ... | @@ -77,4 +77,11 @@ public interface DeviceDescription extends Description { |
77 | */ | 77 | */ |
78 | ChassisId chassisId(); | 78 | ChassisId chassisId(); |
79 | 79 | ||
80 | + /** | ||
81 | + * Return whether device should be made available by default. | ||
82 | + * | ||
83 | + * @return default availability | ||
84 | + */ | ||
85 | + boolean isDefaultAvailable(); | ||
86 | + | ||
80 | } | 87 | } | ... | ... |
... | @@ -52,8 +52,6 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { | ... | @@ -52,8 +52,6 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { |
52 | */ | 52 | */ |
53 | Iterable<Device> getAvailableDevices(); | 53 | Iterable<Device> getAvailableDevices(); |
54 | 54 | ||
55 | - | ||
56 | - | ||
57 | /** | 55 | /** |
58 | * Returns the device with the specified identifier. | 56 | * Returns the device with the specified identifier. |
59 | * | 57 | * |
... | @@ -74,6 +72,7 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { | ... | @@ -74,6 +72,7 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { |
74 | DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, | 72 | DeviceEvent createOrUpdateDevice(ProviderId providerId, DeviceId deviceId, |
75 | DeviceDescription deviceDescription); | 73 | DeviceDescription deviceDescription); |
76 | 74 | ||
75 | + | ||
77 | // TODO: We may need to enforce that ancillary cannot interfere this state | 76 | // TODO: We may need to enforce that ancillary cannot interfere this state |
78 | /** | 77 | /** |
79 | * Removes the specified infrastructure device. | 78 | * Removes the specified infrastructure device. |
... | @@ -84,6 +83,14 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { | ... | @@ -84,6 +83,14 @@ public interface DeviceStore extends Store<DeviceEvent, DeviceStoreDelegate> { |
84 | DeviceEvent markOffline(DeviceId deviceId); | 83 | DeviceEvent markOffline(DeviceId deviceId); |
85 | 84 | ||
86 | /** | 85 | /** |
86 | + * Marks the device as available. | ||
87 | + * | ||
88 | + * @param deviceId device identifier | ||
89 | + * @return true if availability change request was accepted and changed the state | ||
90 | + */ | ||
91 | + boolean markOnline(DeviceId deviceId); | ||
92 | + | ||
93 | + /** | ||
87 | * Updates the ports of the specified infrastructure device using the given | 94 | * Updates the ports of the specified infrastructure device using the given |
88 | * list of port descriptions. The list is assumed to be comprehensive. | 95 | * list of port descriptions. The list is assumed to be comprehensive. |
89 | * | 96 | * | ... | ... |
... | @@ -57,6 +57,11 @@ public class DeviceStoreAdapter implements DeviceStore { | ... | @@ -57,6 +57,11 @@ public class DeviceStoreAdapter implements DeviceStore { |
57 | } | 57 | } |
58 | 58 | ||
59 | @Override | 59 | @Override |
60 | + public boolean markOnline(DeviceId deviceId) { | ||
61 | + return false; | ||
62 | + } | ||
63 | + | ||
64 | + @Override | ||
60 | public DeviceEvent markOffline(DeviceId deviceId) { | 65 | public DeviceEvent markOffline(DeviceId deviceId) { |
61 | return null; | 66 | return null; |
62 | } | 67 | } | ... | ... |
... | @@ -245,6 +245,13 @@ public class SimpleDeviceStore | ... | @@ -245,6 +245,13 @@ public class SimpleDeviceStore |
245 | } | 245 | } |
246 | } | 246 | } |
247 | 247 | ||
248 | + // implement differently if desired | ||
249 | + @Override | ||
250 | + public boolean markOnline(DeviceId deviceId) { | ||
251 | + log.warn("Mark online not supported"); | ||
252 | + return false; | ||
253 | + } | ||
254 | + | ||
248 | @Override | 255 | @Override |
249 | public List<DeviceEvent> updatePorts(ProviderId providerId, | 256 | public List<DeviceEvent> updatePorts(ProviderId providerId, |
250 | DeviceId deviceId, | 257 | DeviceId deviceId, | ... | ... |
... | @@ -79,7 +79,8 @@ public final class BasicDeviceOperator implements ConfigOperator { | ... | @@ -79,7 +79,8 @@ public final class BasicDeviceOperator implements ConfigOperator { |
79 | SparseAnnotations sa = combine(bdc, descr.annotations()); | 79 | SparseAnnotations sa = combine(bdc, descr.annotations()); |
80 | return new DefaultDeviceDescription(descr.deviceUri(), type, manufacturer, | 80 | return new DefaultDeviceDescription(descr.deviceUri(), type, manufacturer, |
81 | hwVersion, swVersion, | 81 | hwVersion, swVersion, |
82 | - serial, descr.chassisId(), sa); | 82 | + serial, descr.chassisId(), |
83 | + descr.isDefaultAvailable(), sa); | ||
83 | } | 84 | } |
84 | 85 | ||
85 | /** | 86 | /** | ... | ... |
... | @@ -64,7 +64,6 @@ import org.onosproject.net.config.NetworkConfigListener; | ... | @@ -64,7 +64,6 @@ import org.onosproject.net.config.NetworkConfigListener; |
64 | import org.onosproject.net.config.NetworkConfigService; | 64 | import org.onosproject.net.config.NetworkConfigService; |
65 | import org.onosproject.net.config.basics.BasicDeviceConfig; | 65 | import org.onosproject.net.config.basics.BasicDeviceConfig; |
66 | import org.onosproject.net.config.basics.OpticalPortConfig; | 66 | import org.onosproject.net.config.basics.OpticalPortConfig; |
67 | -import org.onosproject.net.device.DefaultDeviceDescription; | ||
68 | import org.onosproject.net.device.DefaultPortDescription; | 67 | import org.onosproject.net.device.DefaultPortDescription; |
69 | import org.onosproject.net.device.DeviceAdminService; | 68 | import org.onosproject.net.device.DeviceAdminService; |
70 | import org.onosproject.net.device.DeviceDescription; | 69 | import org.onosproject.net.device.DeviceDescription; |
... | @@ -288,6 +287,19 @@ public class DeviceManager | ... | @@ -288,6 +287,19 @@ public class DeviceManager |
288 | log.trace("Checking device {}", deviceId); | 287 | log.trace("Checking device {}", deviceId); |
289 | 288 | ||
290 | if (!isReachable(deviceId)) { | 289 | if (!isReachable(deviceId)) { |
290 | + if (mastershipService.getLocalRole(deviceId) != NONE) { | ||
291 | + // can't be master if device is not reachable | ||
292 | + try { | ||
293 | + post(store.markOffline(deviceId)); | ||
294 | + //relinquish master role and ability to be backup. | ||
295 | + mastershipService.relinquishMastership(deviceId).get(); | ||
296 | + } catch (InterruptedException e) { | ||
297 | + log.warn("Interrupted while reliquishing role for {}", deviceId); | ||
298 | + Thread.currentThread().interrupt(); | ||
299 | + } catch (ExecutionException e) { | ||
300 | + log.error("Exception thrown while relinquishing role for {}", deviceId, e); | ||
301 | + } | ||
302 | + } | ||
291 | continue; | 303 | continue; |
292 | } | 304 | } |
293 | 305 | ||
... | @@ -334,7 +346,6 @@ public class DeviceManager | ... | @@ -334,7 +346,6 @@ public class DeviceManager |
334 | } | 346 | } |
335 | provider.roleChanged(deviceId, newRole); | 347 | provider.roleChanged(deviceId, newRole); |
336 | // not triggering probe when triggered by provider service event | 348 | // not triggering probe when triggered by provider service event |
337 | - | ||
338 | return true; | 349 | return true; |
339 | } | 350 | } |
340 | 351 | ||
... | @@ -360,12 +371,15 @@ public class DeviceManager | ... | @@ -360,12 +371,15 @@ public class DeviceManager |
360 | 371 | ||
361 | DeviceEvent event = store.createOrUpdateDevice(provider().id(), deviceId, | 372 | DeviceEvent event = store.createOrUpdateDevice(provider().id(), deviceId, |
362 | deviceDescription); | 373 | deviceDescription); |
374 | + if (deviceDescription.isDefaultAvailable()) { | ||
363 | log.info("Device {} connected", deviceId); | 375 | log.info("Device {} connected", deviceId); |
376 | + } else { | ||
377 | + log.info("Device {} registered", deviceId); | ||
378 | + } | ||
364 | if (event != null) { | 379 | if (event != null) { |
365 | log.trace("event: {} {}", event.type(), event); | 380 | log.trace("event: {} {}", event.type(), event); |
366 | post(event); | 381 | post(event); |
367 | } | 382 | } |
368 | - | ||
369 | } | 383 | } |
370 | 384 | ||
371 | private PortDescription ensurePortEnabledState(PortDescription desc, boolean enabled) { | 385 | private PortDescription ensurePortEnabledState(PortDescription desc, boolean enabled) { |
... | @@ -684,19 +698,7 @@ public class DeviceManager | ... | @@ -684,19 +698,7 @@ public class DeviceManager |
684 | case MASTER: | 698 | case MASTER: |
685 | final Device device = getDevice(did); | 699 | final Device device = getDevice(did); |
686 | if ((device != null) && !isAvailable(did)) { | 700 | if ((device != null) && !isAvailable(did)) { |
687 | - //flag the device as online. Is there a better way to do this? | 701 | + store.markOnline(did); |
688 | - DefaultDeviceDescription deviceDescription | ||
689 | - = new DefaultDeviceDescription(did.uri(), | ||
690 | - device.type(), | ||
691 | - device.manufacturer(), | ||
692 | - device.hwVersion(), | ||
693 | - device.swVersion(), | ||
694 | - device.serialNumber(), | ||
695 | - device.chassisId()); | ||
696 | - DeviceEvent devEvent = | ||
697 | - store.createOrUpdateDevice(device.providerId(), did, | ||
698 | - deviceDescription); | ||
699 | - post(devEvent); | ||
700 | } | 702 | } |
701 | // TODO: should apply role only if there is mismatch | 703 | // TODO: should apply role only if there is mismatch |
702 | log.debug("Applying role {} to {}", myNextRole, did); | 704 | log.debug("Applying role {} to {}", myNextRole, did); | ... | ... |
... | @@ -275,6 +275,7 @@ public class ECDeviceStore | ... | @@ -275,6 +275,7 @@ public class ECDeviceStore |
275 | return devices.get(deviceId); | 275 | return devices.get(deviceId); |
276 | } | 276 | } |
277 | 277 | ||
278 | + // FIXME handle deviceDescription.isDefaultAvailable()=false case properly. | ||
278 | @Override | 279 | @Override |
279 | public DeviceEvent createOrUpdateDevice(ProviderId providerId, | 280 | public DeviceEvent createOrUpdateDevice(ProviderId providerId, |
280 | DeviceId deviceId, | 281 | DeviceId deviceId, |
... | @@ -392,9 +393,14 @@ public class ECDeviceStore | ... | @@ -392,9 +393,14 @@ public class ECDeviceStore |
392 | return null; | 393 | return null; |
393 | } | 394 | } |
394 | 395 | ||
395 | - private boolean markOnline(DeviceId deviceId) { | 396 | + // FIXME publicization of markOnline -- trigger some action independently? |
397 | + public boolean markOnline(DeviceId deviceId) { | ||
398 | + if (devices.containsKey(deviceId)) { | ||
396 | return availableDevices.add(deviceId); | 399 | return availableDevices.add(deviceId); |
397 | } | 400 | } |
401 | + log.warn("Device {} does not exist in store", deviceId); | ||
402 | + return false; | ||
403 | + } | ||
398 | 404 | ||
399 | @Override | 405 | @Override |
400 | public DeviceEvent markOffline(DeviceId deviceId) { | 406 | public DeviceEvent markOffline(DeviceId deviceId) { | ... | ... |
... | @@ -406,11 +406,16 @@ public class GossipDeviceStore | ... | @@ -406,11 +406,16 @@ public class GossipDeviceStore |
406 | return null; | 406 | return null; |
407 | } | 407 | } |
408 | if (oldDevice == null) { | 408 | if (oldDevice == null) { |
409 | + // REGISTER | ||
410 | + if (!deltaDesc.value().isDefaultAvailable()) { | ||
411 | + return registerDevice(providerId, newDevice); | ||
412 | + } | ||
409 | // ADD | 413 | // ADD |
410 | return createDevice(providerId, newDevice, deltaDesc.timestamp()); | 414 | return createDevice(providerId, newDevice, deltaDesc.timestamp()); |
411 | } else { | 415 | } else { |
412 | // UPDATE or ignore (no change or stale) | 416 | // UPDATE or ignore (no change or stale) |
413 | - return updateDevice(providerId, oldDevice, newDevice, deltaDesc.timestamp()); | 417 | + return updateDevice(providerId, oldDevice, newDevice, deltaDesc.timestamp(), |
418 | + deltaDesc.value().isDefaultAvailable()); | ||
414 | } | 419 | } |
415 | } | 420 | } |
416 | } | 421 | } |
... | @@ -437,7 +442,8 @@ public class GossipDeviceStore | ... | @@ -437,7 +442,8 @@ public class GossipDeviceStore |
437 | // Guarded by deviceDescs value (=Device lock) | 442 | // Guarded by deviceDescs value (=Device lock) |
438 | private DeviceEvent updateDevice(ProviderId providerId, | 443 | private DeviceEvent updateDevice(ProviderId providerId, |
439 | Device oldDevice, | 444 | Device oldDevice, |
440 | - Device newDevice, Timestamp newTimestamp) { | 445 | + Device newDevice, Timestamp newTimestamp, |
446 | + boolean forceAvailable) { | ||
441 | // We allow only certain attributes to trigger update | 447 | // We allow only certain attributes to trigger update |
442 | boolean propertiesChanged = | 448 | boolean propertiesChanged = |
443 | !Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || | 449 | !Objects.equals(oldDevice.hwVersion(), newDevice.hwVersion()) || |
... | @@ -461,7 +467,7 @@ public class GossipDeviceStore | ... | @@ -461,7 +467,7 @@ public class GossipDeviceStore |
461 | event = new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null); | 467 | event = new DeviceEvent(DeviceEvent.Type.DEVICE_UPDATED, newDevice, null); |
462 | } | 468 | } |
463 | 469 | ||
464 | - if (!providerId.isAncillary()) { | 470 | + if (!providerId.isAncillary() && forceAvailable) { |
465 | boolean wasOnline = availableDevices.contains(newDevice.id()); | 471 | boolean wasOnline = availableDevices.contains(newDevice.id()); |
466 | markOnline(newDevice.id(), newTimestamp); | 472 | markOnline(newDevice.id(), newTimestamp); |
467 | if (!wasOnline) { | 473 | if (!wasOnline) { |
... | @@ -471,6 +477,20 @@ public class GossipDeviceStore | ... | @@ -471,6 +477,20 @@ public class GossipDeviceStore |
471 | return event; | 477 | return event; |
472 | } | 478 | } |
473 | 479 | ||
480 | + private DeviceEvent registerDevice(ProviderId providerId, Device newDevice) { | ||
481 | + // update composed device cache | ||
482 | + Device oldDevice = devices.putIfAbsent(newDevice.id(), newDevice); | ||
483 | + verify(oldDevice == null, | ||
484 | + "Unexpected Device in cache. PID:%s [old=%s, new=%s]", | ||
485 | + providerId, oldDevice, newDevice); | ||
486 | + | ||
487 | + if (!providerId.isAncillary()) { | ||
488 | + markOffline(newDevice.id()); | ||
489 | + } | ||
490 | + | ||
491 | + return new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, newDevice, null); | ||
492 | + } | ||
493 | + | ||
474 | @Override | 494 | @Override |
475 | public DeviceEvent markOffline(DeviceId deviceId) { | 495 | public DeviceEvent markOffline(DeviceId deviceId) { |
476 | final Timestamp timestamp = deviceClockService.getTimestamp(deviceId); | 496 | final Timestamp timestamp = deviceClockService.getTimestamp(deviceId); |
... | @@ -514,6 +534,24 @@ public class GossipDeviceStore | ... | @@ -514,6 +534,24 @@ public class GossipDeviceStore |
514 | } | 534 | } |
515 | } | 535 | } |
516 | 536 | ||
537 | + public boolean markOnline(DeviceId deviceId) { | ||
538 | + if (devices.containsKey(deviceId)) { | ||
539 | + final Timestamp timestamp = deviceClockService.getTimestamp(deviceId); | ||
540 | + Map<?, ?> deviceLock = getOrCreateDeviceDescriptionsMap(deviceId); | ||
541 | + synchronized (deviceLock) { | ||
542 | + if (markOnline(deviceId, timestamp)) { | ||
543 | + notifyDelegate(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, getDevice(deviceId), null)); | ||
544 | + return true; | ||
545 | + } else { | ||
546 | + return false; | ||
547 | + } | ||
548 | + } | ||
549 | + } | ||
550 | + log.warn("Device {} does not exist in store", deviceId); | ||
551 | + return false; | ||
552 | + | ||
553 | + } | ||
554 | + | ||
517 | /** | 555 | /** |
518 | * Marks the device as available if the given timestamp is not outdated, | 556 | * Marks the device as available if the given timestamp is not outdated, |
519 | * compared to the time the device has been marked offline. | 557 | * compared to the time the device has been marked offline. |
... | @@ -1576,7 +1614,8 @@ public class GossipDeviceStore | ... | @@ -1576,7 +1614,8 @@ public class GossipDeviceStore |
1576 | Timestamped<DeviceDescription> deviceDescription = event.deviceDescription(); | 1614 | Timestamped<DeviceDescription> deviceDescription = event.deviceDescription(); |
1577 | 1615 | ||
1578 | try { | 1616 | try { |
1579 | - notifyDelegateIfNotNull(createOrUpdateDeviceInternal(providerId, deviceId, deviceDescription)); | 1617 | + notifyDelegateIfNotNull(createOrUpdateDeviceInternal(providerId, deviceId, |
1618 | + deviceDescription)); | ||
1580 | } catch (Exception e) { | 1619 | } catch (Exception e) { |
1581 | log.warn("Exception thrown handling device update", e); | 1620 | log.warn("Exception thrown handling device update", e); |
1582 | } | 1621 | } | ... | ... |
... | @@ -450,7 +450,6 @@ public class GrpcRemoteServiceTest { | ... | @@ -450,7 +450,6 @@ public class GrpcRemoteServiceTest { |
450 | deviceConnected.countDown(); | 450 | deviceConnected.countDown(); |
451 | } | 451 | } |
452 | 452 | ||
453 | - | ||
454 | final CountDownLatch updatePorts = new CountDownLatch(1); | 453 | final CountDownLatch updatePorts = new CountDownLatch(1); |
455 | DeviceId updatePortsDid; | 454 | DeviceId updatePortsDid; |
456 | List<PortDescription> updatePortsDescs; | 455 | List<PortDescription> updatePortsDescs; | ... | ... |
... | @@ -258,7 +258,6 @@ public class IsisTopologyProviderTest { | ... | @@ -258,7 +258,6 @@ public class IsisTopologyProviderTest { |
258 | 258 | ||
259 | } | 259 | } |
260 | 260 | ||
261 | - | ||
262 | @Override | 261 | @Override |
263 | public void deviceDisconnected(DeviceId deviceId) { | 262 | public void deviceDisconnected(DeviceId deviceId) { |
264 | 263 | ... | ... |
... | @@ -67,6 +67,9 @@ import java.net.URISyntaxException; | ... | @@ -67,6 +67,9 @@ import java.net.URISyntaxException; |
67 | import java.util.Arrays; | 67 | import java.util.Arrays; |
68 | import java.util.concurrent.ExecutorService; | 68 | import java.util.concurrent.ExecutorService; |
69 | import java.util.concurrent.Executors; | 69 | import java.util.concurrent.Executors; |
70 | +import java.util.concurrent.ScheduledExecutorService; | ||
71 | +import java.util.concurrent.ScheduledFuture; | ||
72 | +import java.util.concurrent.TimeUnit; | ||
70 | 73 | ||
71 | import static org.onlab.util.Tools.groupedThreads; | 74 | import static org.onlab.util.Tools.groupedThreads; |
72 | import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; | 75 | import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY; |
... | @@ -114,17 +117,21 @@ public class NetconfDeviceProvider extends AbstractProvider | ... | @@ -114,17 +117,21 @@ public class NetconfDeviceProvider extends AbstractProvider |
114 | private static final String IPADDRESS = "ipaddress"; | 117 | private static final String IPADDRESS = "ipaddress"; |
115 | private static final String NETCONF = "netconf"; | 118 | private static final String NETCONF = "netconf"; |
116 | private static final String PORT = "port"; | 119 | private static final String PORT = "port"; |
120 | + private static final int CORE_POOL_SIZE = 10; | ||
117 | //FIXME eventually a property | 121 | //FIXME eventually a property |
118 | private static final int ISREACHABLE_TIMEOUT = 2000; | 122 | private static final int ISREACHABLE_TIMEOUT = 2000; |
123 | + private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 30; | ||
119 | 124 | ||
120 | private final ExecutorService executor = | 125 | private final ExecutorService executor = |
121 | Executors.newFixedThreadPool(5, groupedThreads("onos/netconfdeviceprovider", | 126 | Executors.newFixedThreadPool(5, groupedThreads("onos/netconfdeviceprovider", |
122 | "device-installer-%d", log)); | 127 | "device-installer-%d", log)); |
128 | + protected ScheduledExecutorService connectionExecutor = Executors.newScheduledThreadPool(CORE_POOL_SIZE); | ||
123 | 129 | ||
124 | private DeviceProviderService providerService; | 130 | private DeviceProviderService providerService; |
125 | private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener(); | 131 | private NetconfDeviceListener innerNodeListener = new InnerNetconfDeviceListener(); |
126 | private InternalDeviceListener deviceListener = new InternalDeviceListener(); | 132 | private InternalDeviceListener deviceListener = new InternalDeviceListener(); |
127 | private NodeId localNodeId; | 133 | private NodeId localNodeId; |
134 | + private ScheduledFuture<?> scheduledTask; | ||
128 | 135 | ||
129 | private final ConfigFactory factory = | 136 | private final ConfigFactory factory = |
130 | new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY, | 137 | new ConfigFactory<ApplicationId, NetconfProviderConfig>(APP_SUBJECT_FACTORY, |
... | @@ -152,6 +159,7 @@ public class NetconfDeviceProvider extends AbstractProvider | ... | @@ -152,6 +159,7 @@ public class NetconfDeviceProvider extends AbstractProvider |
152 | deviceService.addListener(deviceListener); | 159 | deviceService.addListener(deviceListener); |
153 | executor.execute(NetconfDeviceProvider.this::connectDevices); | 160 | executor.execute(NetconfDeviceProvider.this::connectDevices); |
154 | localNodeId = clusterService.getLocalNode().id(); | 161 | localNodeId = clusterService.getLocalNode().id(); |
162 | + scheduledTask = schedulePolling(); | ||
155 | log.info("Started"); | 163 | log.info("Started"); |
156 | } | 164 | } |
157 | 165 | ||
... | @@ -169,6 +177,7 @@ public class NetconfDeviceProvider extends AbstractProvider | ... | @@ -169,6 +177,7 @@ public class NetconfDeviceProvider extends AbstractProvider |
169 | providerRegistry.unregister(this); | 177 | providerRegistry.unregister(this); |
170 | providerService = null; | 178 | providerService = null; |
171 | cfgService.unregisterConfigFactory(factory); | 179 | cfgService.unregisterConfigFactory(factory); |
180 | + scheduledTask.cancel(true); | ||
172 | executor.shutdown(); | 181 | executor.shutdown(); |
173 | log.info("Stopped"); | 182 | log.info("Stopped"); |
174 | } | 183 | } |
... | @@ -177,6 +186,15 @@ public class NetconfDeviceProvider extends AbstractProvider | ... | @@ -177,6 +186,15 @@ public class NetconfDeviceProvider extends AbstractProvider |
177 | super(new ProviderId(SCHEME_NAME, DEVICE_PROVIDER_PACKAGE)); | 186 | super(new ProviderId(SCHEME_NAME, DEVICE_PROVIDER_PACKAGE)); |
178 | } | 187 | } |
179 | 188 | ||
189 | + // Checks connection to devices in the config file | ||
190 | + // every DEFAULT_POLL_FREQUENCY_SECONDS seconds. | ||
191 | + private ScheduledFuture schedulePolling() { | ||
192 | + return connectionExecutor.scheduleAtFixedRate(this::checkAndUpdateDevices, | ||
193 | + DEFAULT_POLL_FREQUENCY_SECONDS / 10, | ||
194 | + DEFAULT_POLL_FREQUENCY_SECONDS, | ||
195 | + TimeUnit.SECONDS); | ||
196 | + } | ||
197 | + | ||
180 | @Override | 198 | @Override |
181 | public void triggerProbe(DeviceId deviceId) { | 199 | public void triggerProbe(DeviceId deviceId) { |
182 | // TODO: This will be implemented later. | 200 | // TODO: This will be implemented later. |
... | @@ -270,8 +288,14 @@ public class NetconfDeviceProvider extends AbstractProvider | ... | @@ -270,8 +288,14 @@ public class NetconfDeviceProvider extends AbstractProvider |
270 | @Override | 288 | @Override |
271 | public void deviceRemoved(DeviceId deviceId) { | 289 | public void deviceRemoved(DeviceId deviceId) { |
272 | Preconditions.checkNotNull(deviceId, ISNULL); | 290 | Preconditions.checkNotNull(deviceId, ISNULL); |
273 | - log.debug("Netconf device {} removed from Netconf subController", deviceId); | 291 | + |
292 | + if (deviceService.getDevice(deviceId) != null) { | ||
274 | providerService.deviceDisconnected(deviceId); | 293 | providerService.deviceDisconnected(deviceId); |
294 | + log.debug("Netconf device {} removed from Netconf subController", deviceId); | ||
295 | + } else { | ||
296 | + log.warn("Netconf device {} does not exist in the store, " + | ||
297 | + "it may already have been removed", deviceId); | ||
298 | + } | ||
275 | } | 299 | } |
276 | } | 300 | } |
277 | 301 | ||
... | @@ -295,13 +319,67 @@ public class NetconfDeviceProvider extends AbstractProvider | ... | @@ -295,13 +319,67 @@ public class NetconfDeviceProvider extends AbstractProvider |
295 | Device.Type.SWITCH, | 319 | Device.Type.SWITCH, |
296 | UNKNOWN, UNKNOWN, | 320 | UNKNOWN, UNKNOWN, |
297 | UNKNOWN, UNKNOWN, | 321 | UNKNOWN, UNKNOWN, |
298 | - cid, | 322 | + cid, false, |
299 | annotations); | 323 | annotations); |
300 | deviceKeyAdminService.addKey( | 324 | deviceKeyAdminService.addKey( |
301 | DeviceKey.createDeviceKeyUsingUsernamePassword( | 325 | DeviceKey.createDeviceKeyUsingUsernamePassword( |
302 | DeviceKeyId.deviceKeyId(deviceId.toString()), | 326 | DeviceKeyId.deviceKeyId(deviceId.toString()), |
303 | null, addr.name(), addr.password())); | 327 | null, addr.name(), addr.password())); |
328 | + if (deviceService.getDevice(deviceId) == null) { | ||
304 | providerService.deviceConnected(deviceId, deviceDescription); | 329 | providerService.deviceConnected(deviceId, deviceDescription); |
330 | + } | ||
331 | + checkAndUpdateDevice(deviceId, deviceDescription); | ||
332 | + }); | ||
333 | + } catch (ConfigException e) { | ||
334 | + log.error("Cannot read config error " + e); | ||
335 | + } | ||
336 | + } | ||
337 | + } | ||
338 | + | ||
339 | + private void checkAndUpdateDevice(DeviceId deviceId, DeviceDescription deviceDescription) { | ||
340 | + if (deviceService.getDevice(deviceId) == null) { | ||
341 | + log.warn("Device {} has not been added to store, " + | ||
342 | + "maybe due to a problem in connectivity", deviceId); | ||
343 | + } else { | ||
344 | + boolean isReachable = isReachable(deviceId); | ||
345 | + if (isReachable && !deviceService.isAvailable(deviceId)) { | ||
346 | + providerService.deviceConnected( | ||
347 | + deviceId, new DefaultDeviceDescription( | ||
348 | + deviceDescription, true, deviceDescription.annotations())); | ||
349 | + } else if (!isReachable && deviceService.isAvailable(deviceId)) { | ||
350 | + providerService.deviceDisconnected(deviceId); | ||
351 | + } | ||
352 | + } | ||
353 | + } | ||
354 | + | ||
355 | + private void checkAndUpdateDevices() { | ||
356 | + NetconfProviderConfig cfg = cfgService.getConfig(appId, NetconfProviderConfig.class); | ||
357 | + if (cfg != null) { | ||
358 | + log.info("Checking connection to devices in configuration"); | ||
359 | + try { | ||
360 | + cfg.getDevicesAddresses().stream().forEach(addr -> { | ||
361 | + DeviceId deviceId = getDeviceId(addr.ip().toString(), addr.port()); | ||
362 | + Preconditions.checkNotNull(deviceId, ISNULL); | ||
363 | + //Netconf configuration object | ||
364 | + ChassisId cid = new ChassisId(); | ||
365 | + String ipAddress = addr.ip().toString(); | ||
366 | + SparseAnnotations annotations = DefaultAnnotations.builder() | ||
367 | + .set(IPADDRESS, ipAddress) | ||
368 | + .set(PORT, String.valueOf(addr.port())) | ||
369 | + .set(AnnotationKeys.PROTOCOL, SCHEME_NAME.toUpperCase()) | ||
370 | + .build(); | ||
371 | + DeviceDescription deviceDescription = new DefaultDeviceDescription( | ||
372 | + deviceId.uri(), | ||
373 | + Device.Type.SWITCH, | ||
374 | + UNKNOWN, UNKNOWN, | ||
375 | + UNKNOWN, UNKNOWN, | ||
376 | + cid, false, | ||
377 | + annotations); | ||
378 | + deviceKeyAdminService.addKey( | ||
379 | + DeviceKey.createDeviceKeyUsingUsernamePassword( | ||
380 | + DeviceKeyId.deviceKeyId(deviceId.toString()), | ||
381 | + null, addr.name(), addr.password())); | ||
382 | + checkAndUpdateDevice(deviceId, deviceDescription); | ||
305 | }); | 383 | }); |
306 | } catch (ConfigException e) { | 384 | } catch (ConfigException e) { |
307 | log.error("Cannot read config error " + e); | 385 | log.error("Cannot read config error " + e); | ... | ... |
-
Please register or login to post a comment