blob: 3cf47bae0bdd6986887228bf9277bc5a1dd0e2ba [file] [log] [blame]
Madan Jampaniab7e7cd2016-01-14 14:02:32 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Madan Jampaniab7e7cd2016-01-14 14:02:32 -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 */
Madan Jampaniec1df022015-10-13 21:23:03 -070016package org.onosproject.cluster.impl;
17
Madan Jampaniec1df022015-10-13 21:23:03 -070018import org.onlab.packet.IpAddress;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070019import org.onlab.util.Tools;
Madan Jampaniec1df022015-10-13 21:23:03 -070020import org.onosproject.cluster.ClusterMetadata;
Madan Jampaniab7e7cd2016-01-14 14:02:32 -080021import org.onosproject.cluster.ClusterMetadataAdminService;
Madan Jampaniec1df022015-10-13 21:23:03 -070022import org.onosproject.cluster.ClusterMetadataEvent;
23import org.onosproject.cluster.ClusterMetadataEventListener;
Madan Jampaniad3c5262016-01-20 00:50:17 -080024import org.onosproject.cluster.ClusterMetadataProvider;
25import org.onosproject.cluster.ClusterMetadataProviderRegistry;
26import org.onosproject.cluster.ClusterMetadataProviderService;
Madan Jampaniec1df022015-10-13 21:23:03 -070027import org.onosproject.cluster.ClusterMetadataService;
Madan Jampaniec1df022015-10-13 21:23:03 -070028import org.onosproject.cluster.ControllerNode;
Jordan Halterman00e92da2018-05-22 23:05:52 -070029import org.onosproject.cluster.DefaultControllerNode;
Madan Jampaniad3c5262016-01-20 00:50:17 -080030import org.onosproject.cluster.NodeId;
31import org.onosproject.cluster.PartitionId;
32import org.onosproject.net.provider.AbstractListenerProviderRegistry;
33import org.onosproject.net.provider.AbstractProviderService;
Madan Jampaniec1df022015-10-13 21:23:03 -070034import org.onosproject.store.service.Versioned;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070035import org.osgi.service.component.annotations.Activate;
36import org.osgi.service.component.annotations.Component;
37import org.osgi.service.component.annotations.Deactivate;
Madan Jampaniec1df022015-10-13 21:23:03 -070038import org.slf4j.Logger;
39
Ray Milkeyd84f89b2018-08-17 14:54:17 -070040import java.net.Inet4Address;
41import java.net.InetAddress;
42import java.net.MalformedURLException;
43import java.net.NetworkInterface;
44import java.net.SocketException;
45import java.net.URL;
46import java.net.UnknownHostException;
47import java.util.Enumeration;
48
Heedo Kang4a47a302016-02-29 17:40:23 +090049import static com.google.common.base.Preconditions.checkNotNull;
50import static org.onosproject.security.AppGuard.checkPermission;
51import static org.onosproject.security.AppPermission.Type.CLUSTER_READ;
52import static org.slf4j.LoggerFactory.getLogger;
53
Madan Jampaniec1df022015-10-13 21:23:03 -070054/**
55 * Implementation of ClusterMetadataService.
56 */
Ray Milkey86ad7bb2018-09-27 12:32:28 -070057@Component(immediate = true,
58 service = {ClusterMetadataService.class, ClusterMetadataAdminService.class,
59 ClusterMetadataProviderRegistry.class})
Madan Jampaniec1df022015-10-13 21:23:03 -070060public class ClusterMetadataManager
Madan Jampaniad3c5262016-01-20 00:50:17 -080061 extends AbstractListenerProviderRegistry<ClusterMetadataEvent,
62 ClusterMetadataEventListener,
63 ClusterMetadataProvider,
64 ClusterMetadataProviderService>
65 implements ClusterMetadataService, ClusterMetadataAdminService, ClusterMetadataProviderRegistry {
Madan Jampaniec1df022015-10-13 21:23:03 -070066
Ray Milkeyd84f89b2018-08-17 14:54:17 -070067 private static final int MAX_WAIT_TRIES = 600;
68 private static final int MAX_WAIT_MS = 100;
69
Madan Jampaniec1df022015-10-13 21:23:03 -070070 private final Logger log = getLogger(getClass());
Madan Jampaniab7e7cd2016-01-14 14:02:32 -080071 private ControllerNode localNode;
Madan Jampaniec1df022015-10-13 21:23:03 -070072
Madan Jampaniec1df022015-10-13 21:23:03 -070073 @Activate
74 public void activate() {
Madan Jampaniad3c5262016-01-20 00:50:17 -080075 // FIXME: Need to ensure all cluster metadata providers are registered before we activate
Madan Jampaniec1df022015-10-13 21:23:03 -070076 eventDispatcher.addSink(ClusterMetadataEvent.class, listenerRegistry);
Madan Jampaniec1df022015-10-13 21:23:03 -070077 log.info("Started");
78 }
79
80 @Deactivate
81 public void deactivate() {
Madan Jampaniec1df022015-10-13 21:23:03 -070082 eventDispatcher.removeSink(ClusterMetadataEvent.class);
83 log.info("Stopped");
84 }
85
86 @Override
87 public ClusterMetadata getClusterMetadata() {
Heedo Kang4a47a302016-02-29 17:40:23 +090088 checkPermission(CLUSTER_READ);
Ray Milkeyd84f89b2018-08-17 14:54:17 -070089 waitForAvailableProvider();
Madan Jampaniad3c5262016-01-20 00:50:17 -080090 Versioned<ClusterMetadata> metadata = getProvider().getClusterMetadata();
91 return metadata.value();
92 }
93
Ray Milkeyd84f89b2018-08-17 14:54:17 -070094 // FIXME: Temporary hack to navigate around bootstrap timing issue
95 private void waitForAvailableProvider() {
96 for (int i = 0; i < MAX_WAIT_TRIES && getProvider() == null; i++) {
97 Tools.delay(MAX_WAIT_MS);
98 }
99 if (getProvider() == null) {
100 log.error("Unable to find cluster metadata provider");
101 throw new IllegalStateException("Unable to find cluster metadata provider");
102 }
103 }
Madan Jampaniad3c5262016-01-20 00:50:17 -0800104
105 @Override
106 protected ClusterMetadataProviderService createProviderService(
107 ClusterMetadataProvider provider) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900108 checkPermission(CLUSTER_READ);
Madan Jampaniad3c5262016-01-20 00:50:17 -0800109 return new InternalClusterMetadataProviderService(provider);
Madan Jampaniec1df022015-10-13 21:23:03 -0700110 }
111
112 @Override
113 public ControllerNode getLocalNode() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900114 checkPermission(CLUSTER_READ);
Madan Jampaniad3c5262016-01-20 00:50:17 -0800115 if (localNode == null) {
Jordan Halterman19c123a2018-07-30 13:57:19 -0700116 ClusterMetadata metadata = getProvider().getClusterMetadata().value();
117 ControllerNode localNode = metadata.getLocalNode();
Jordan Halterman00e92da2018-05-22 23:05:52 -0700118 try {
119 if (localNode != null) {
120 this.localNode = new DefaultControllerNode(
121 localNode.id(),
122 localNode.ip() != null ? localNode.ip() : findLocalIp(),
123 localNode.tcpPort());
124 } else {
125 IpAddress ip = findLocalIp();
Jordan Halterman19c123a2018-07-30 13:57:19 -0700126 localNode = metadata.getControllerNodes().stream()
127 .filter(node -> node.ip().equals(ip))
128 .findFirst()
129 .orElse(null);
130 if (localNode != null) {
131 this.localNode = localNode;
132 } else {
133 this.localNode = new DefaultControllerNode(NodeId.nodeId(ip.toString()), ip);
134 }
Jordan Halterman00e92da2018-05-22 23:05:52 -0700135 }
136 } catch (SocketException e) {
137 throw new IllegalStateException(e);
138 }
Madan Jampaniad3c5262016-01-20 00:50:17 -0800139 }
Madan Jampaniec1df022015-10-13 21:23:03 -0700140 return localNode;
141 }
142
143 @Override
144 public void setClusterMetadata(ClusterMetadata metadata) {
145 checkNotNull(metadata, "Cluster metadata cannot be null");
Madan Jampaniad3c5262016-01-20 00:50:17 -0800146 ClusterMetadataProvider primaryProvider = getPrimaryProvider();
147 if (primaryProvider == null) {
148 throw new IllegalStateException("Missing primary provider. Cannot update cluster metadata");
149 }
150 primaryProvider.setClusterMetadata(metadata);
Madan Jampaniec1df022015-10-13 21:23:03 -0700151 }
152
Madan Jampaniad3c5262016-01-20 00:50:17 -0800153 /**
154 * Returns the provider to use for fetching cluster metadata.
155 * @return cluster metadata provider
156 */
157 private ClusterMetadataProvider getProvider() {
158 ClusterMetadataProvider primaryProvider = getPrimaryProvider();
159 if (primaryProvider != null && primaryProvider.isAvailable()) {
160 return primaryProvider;
161 }
Madan Jampaniad3c5262016-01-20 00:50:17 -0800162 return getProvider("default");
163 }
164
165 /**
166 * Returns the primary provider for cluster metadata.
167 * @return primary cluster metadata provider
168 */
169 private ClusterMetadataProvider getPrimaryProvider() {
Madan Jampanif172d402016-03-04 00:56:38 -0800170 String metadataUri = System.getProperty("onos.cluster.metadata.uri");
Madan Jampaniad3c5262016-01-20 00:50:17 -0800171 try {
Madan Jampanif172d402016-03-04 00:56:38 -0800172 String protocol = metadataUri == null ? null : new URL(metadataUri).getProtocol();
Ray Milkey36cbc712017-04-07 13:33:59 -0700173 if (protocol != null && (!"file".equals(protocol) && !"http".equals(protocol))) {
Madan Jampanif172d402016-03-04 00:56:38 -0800174 return getProvider(protocol);
175 }
176 // file provider supports both "file" and "http" uris
177 return getProvider("file");
178 } catch (MalformedURLException e) {
Madan Jampaniad3c5262016-01-20 00:50:17 -0800179 return null;
Madan Jampaniec1df022015-10-13 21:23:03 -0700180 }
181 }
182
Jordan Halterman00e92da2018-05-22 23:05:52 -0700183 private IpAddress findLocalIp() throws SocketException {
184 Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
Madan Jampaniec1df022015-10-13 21:23:03 -0700185 while (interfaces.hasMoreElements()) {
186 NetworkInterface iface = interfaces.nextElement();
Jordan Halterman00e92da2018-05-22 23:05:52 -0700187 if (iface.isLoopback() || iface.isPointToPoint()) {
188 continue;
189 }
190
Madan Jampaniec1df022015-10-13 21:23:03 -0700191 Enumeration<InetAddress> inetAddresses = iface.getInetAddresses();
192 while (inetAddresses.hasMoreElements()) {
Jordan Halterman00e92da2018-05-22 23:05:52 -0700193 InetAddress inetAddress = inetAddresses.nextElement();
194 if (inetAddress instanceof Inet4Address) {
195 Inet4Address inet4Address = (Inet4Address) inetAddress;
196 try {
197 if (!inet4Address.getHostAddress().equals(InetAddress.getLocalHost().getHostAddress())) {
198 return IpAddress.valueOf(inetAddress);
199 }
200 } catch (UnknownHostException e) {
201 return IpAddress.valueOf(inetAddress);
202 }
Madan Jampaniec1df022015-10-13 21:23:03 -0700203 }
204 }
205 }
206 throw new IllegalStateException("Unable to determine local ip");
207 }
208
Madan Jampaniad3c5262016-01-20 00:50:17 -0800209 private class InternalClusterMetadataProviderService
210 extends AbstractProviderService<ClusterMetadataProvider>
211 implements ClusterMetadataProviderService {
212
213 InternalClusterMetadataProviderService(ClusterMetadataProvider provider) {
214 super(provider);
215 }
216
217 @Override
218 public void clusterMetadataChanged(Versioned<ClusterMetadata> newMetadata) {
219 log.info("Cluster metadata changed. New metadata: {}", newMetadata);
220 post(new ClusterMetadataEvent(ClusterMetadataEvent.Type.METADATA_CHANGED, newMetadata.value()));
221 }
222
223 @Override
224 public void newActiveMemberForPartition(PartitionId partitionId, NodeId nodeId) {
225 log.info("Node {} is active member for partition {}", nodeId, partitionId);
226 // TODO: notify listeners
227 }
228 }
Heedo Kang4a47a302016-02-29 17:40:23 +0900229}