blob: 3dd5dda1dc46abafd771cccc64d8b2de56504ed8 [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;
27import org.onlab.util.SharedScheduledExecutors;
28import org.onosproject.cluster.ClusterAdminService;
29import org.osgi.framework.Bundle;
30import org.osgi.framework.BundleContext;
31import org.osgi.service.component.ComponentContext;
Jordan Haltermandfc48552018-11-02 11:08:30 -070032import org.osgi.service.component.runtime.dto.ComponentConfigurationDTO;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070033import org.osgi.service.component.runtime.dto.ComponentDescriptionDTO;
Thomas Vachuska7a8de842016-03-07 20:56:35 -080034import org.slf4j.Logger;
35import org.slf4j.LoggerFactory;
36
37import java.util.concurrent.ScheduledFuture;
38import java.util.concurrent.TimeUnit;
39
40/**
41 * Monitors the system to make sure that all bundles and their components
42 * are properly activated and keeps the cluster node service appropriately
43 * updated.
44 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070045@Component(immediate = true)
Thomas Vachuska7a8de842016-03-07 20:56:35 -080046public class ComponentsMonitor {
47
48 private Logger log = LoggerFactory.getLogger(getClass());
49
50 private static final long PERIOD = 2500;
51
Ray Milkeyd84f89b2018-08-17 14:54:17 -070052 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska7a8de842016-03-07 20:56:35 -080053 protected FeaturesService featuresService;
54
Ray Milkeyd84f89b2018-08-17 14:54:17 -070055 @Reference(cardinality = ReferenceCardinality.MANDATORY)
56 protected ServiceComponentRuntime scrService;
Thomas Vachuska7a8de842016-03-07 20:56:35 -080057
Ray Milkeyd84f89b2018-08-17 14:54:17 -070058 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska7a8de842016-03-07 20:56:35 -080059 protected ClusterAdminService clusterAdminService;
60
61 private BundleContext bundleContext;
62 private ScheduledFuture<?> poller;
63
64 @Activate
65 protected void activate(ComponentContext context) {
66 bundleContext = context.getBundleContext();
67 poller = SharedScheduledExecutors.getSingleThreadExecutor()
68 .scheduleAtFixedRate(this::checkStartedState, PERIOD,
69 PERIOD, TimeUnit.MILLISECONDS);
70 log.info("Started");
71 }
72
73 @Deactivate
74 protected void deactivate() {
75 poller.cancel(false);
76 log.info("Stopped");
77 }
78
79 private void checkStartedState() {
80 clusterAdminService.markFullyStarted(isFullyStarted());
81 }
82
83 /**
84 * Scans the system to make sure that all bundles and their components
85 * are fully started.
86 *
87 * @return true if all bundles and their components are active
88 */
89 private boolean isFullyStarted() {
Ray Milkeyd84f89b2018-08-17 14:54:17 -070090 try {
91 for (Feature feature : featuresService.listInstalledFeatures()) {
92 if (!isFullyStarted(feature)) {
93 return false;
94 }
Thomas Vachuska7a8de842016-03-07 20:56:35 -080095 }
Ray Milkeyd84f89b2018-08-17 14:54:17 -070096 return true;
97 } catch (Exception ex) {
98 return false;
Thomas Vachuska7a8de842016-03-07 20:56:35 -080099 }
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800100 }
101
102 private boolean isFullyStarted(Feature feature) {
Ray Milkeyf13feb82016-08-30 10:38:59 -0700103 try {
104 return feature.getBundles().stream()
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700105 .map(info -> bundleContext.getBundle())
Ray Milkeyf13feb82016-08-30 10:38:59 -0700106 .allMatch(this::isFullyStarted);
107 } catch (NullPointerException npe) {
108 // FIXME: Remove this catch block when Felix fixes the bug
109 // Due to a bug in the Felix implementation, this can throw an NPE.
110 // Catch the error and do something sensible with it.
111 return false;
112 }
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800113 }
114
115 private boolean isFullyStarted(Bundle bundle) {
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700116 for (ComponentDescriptionDTO component : scrService.getComponentDescriptionDTOs(bundle)) {
Jordan Haltermandfc48552018-11-02 11:08:30 -0700117 if (scrService.isComponentEnabled(component)) {
118 for (ComponentConfigurationDTO config : scrService.getComponentConfigurationDTOs(component)) {
119 if (config.state != ComponentConfigurationDTO.ACTIVE) {
120 return false;
121 }
122 }
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800123 }
124 }
125 return true;
126 }
127
Thomas Vachuska7a8de842016-03-07 20:56:35 -0800128}