blob: 5fed79e269cc05453aa38086bc30337ee5dc3245 [file] [log] [blame]
Thomas Vachuska7a8de842016-03-07 20:56:35 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Thomas Vachuska7a8de842016-03-07 20:56:35 -08003 *
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.cluster.impl;
18
Ray Milkeyd84f89b2018-08-17 14:54:17 -070019import org.osgi.service.component.runtime.ServiceComponentRuntime;
20import org.osgi.service.component.annotations.Activate;
21import org.osgi.service.component.annotations.Component;
22import org.osgi.service.component.annotations.Deactivate;
23import org.osgi.service.component.annotations.Reference;
24import org.osgi.service.component.annotations.ReferenceCardinality;
Thomas Vachuska7a8de842016-03-07 20:56:35 -080025import org.apache.karaf.features.Feature;
26import org.apache.karaf.features.FeaturesService;
Thomas Vachuska7a8de842016-03-07 20:56:35 -080027import org.onosproject.cluster.ClusterAdminService;
28import org.osgi.framework.Bundle;
29import org.osgi.framework.BundleContext;
30import org.osgi.service.component.ComponentContext;
Jordan Haltermandfc48552018-11-02 11:08:30 -070031import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070032import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
Thomas Vachuska7a8de842016-03-07 20:56:35 -080033import org.slf4j.Logger;
34import org.slf4j.LoggerFactory;
35
Jordan Haltermanaf3461c2019-01-07 10:03:46 -080036import java.util.concurrent.Executors;
37import java.util.concurrent.ScheduledExecutorService;
Thomas Vachuska7a8de842016-03-07 20:56:35 -080038import java.util.concurrent.ScheduledFuture;
39import java.util.concurrent.TimeUnit;
40
Jordan Haltermanaf3461c2019-01-07 10:03:46 -080041import static org.onlab.util.Tools.groupedThreads;
42
Thomas Vachuska7a8de842016-03-07 20:56:35 -080043/**
44 * Monitors the system to make sure that all bundles and their components
45 * are properly activated and keeps the cluster node service appropriately
46 * updated.
47 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070048@Component(immediate = true)
Thomas Vachuska7a8de842016-03-07 20:56:35 -080049public class ComponentsMonitor {
50
51 private Logger log = LoggerFactory.getLogger(getClass());
52
53 private static final long PERIOD = 2500;
54
Ray Milkeyd84f89b2018-08-17 14:54:17 -070055 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska7a8de842016-03-07 20:56:35 -080056 protected FeaturesService featuresService;
57
Ray Milkeyd84f89b2018-08-17 14:54:17 -070058 @Reference(cardinality = ReferenceCardinality.MANDATORY)
59 protected ServiceComponentRuntime scrService;
Thomas Vachuska7a8de842016-03-07 20:56:35 -080060
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska7a8de842016-03-07 20:56:35 -080062 protected ClusterAdminService clusterAdminService;
63
64 private BundleContext bundleContext;
Jordan Haltermanaf3461c2019-01-07 10:03:46 -080065
66 private ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(
67 groupedThreads("components-monitor", "%d", log));
Thomas Vachuska7a8de842016-03-07 20:56:35 -080068 private ScheduledFuture<?> poller;
69
70 @Activate
71 protected void activate(ComponentContext context) {
72 bundleContext = context.getBundleContext();
Jordan Haltermanaf3461c2019-01-07 10:03:46 -080073 poller = executor.scheduleAtFixedRate(this::checkStartedState, PERIOD, PERIOD, TimeUnit.MILLISECONDS);
Thomas Vachuska7a8de842016-03-07 20:56:35 -080074 log.info("Started");
75 }
76
77 @Deactivate
78 protected void deactivate() {
79 poller.cancel(false);
Jordan Haltermanaf3461c2019-01-07 10:03:46 -080080 executor.shutdownNow();
Thomas Vachuska7a8de842016-03-07 20:56:35 -080081 log.info("Stopped");
82 }
83
84 private void checkStartedState() {
85 clusterAdminService.markFullyStarted(isFullyStarted());
86 }
87
88 /**
89 * Scans the system to make sure that all bundles and their components
90 * are fully started.
91 *
92 * @return true if all bundles and their components are active
93 */
94 private boolean isFullyStarted() {
Ray Milkeyd84f89b2018-08-17 14:54:17 -070095 try {
96 for (Feature feature : featuresService.listInstalledFeatures()) {
97 if (!isFullyStarted(feature)) {
98 return false;
99 }
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800100 }
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700101 return true;
102 } catch (Exception ex) {
103 return false;
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800104 }
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800105 }
106
107 private boolean isFullyStarted(Feature feature) {
Ray Milkeyf13feb82016-08-30 10:38:59 -0700108 try {
109 return feature.getBundles().stream()
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700110 .map(info -> bundleContext.getBundle())
Ray Milkeyf13feb82016-08-30 10:38:59 -0700111 .allMatch(this::isFullyStarted);
112 } catch (NullPointerException npe) {
113 // FIXME: Remove this catch block when Felix fixes the bug
114 // Due to a bug in the Felix implementation, this can throw an NPE.
115 // Catch the error and do something sensible with it.
116 return false;
117 }
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800118 }
119
120 private boolean isFullyStarted(Bundle bundle) {
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 for (ComponentDescriptionDTO component : scrService.getComponentDescriptionDTOs(bundle)) {
Jordan Haltermandfc48552018-11-02 11:08:30 -0700122 if (scrService.isComponentEnabled(component)) {
123 for (ComponentConfigurationDTO config : scrService.getComponentConfigurationDTOs(component)) {
124 if (config.state != ComponentConfigurationDTO.ACTIVE) {
125 return false;
126 }
127 }
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800128 }
129 }
130 return true;
131 }
132
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800133}