blob: b242a3c7e226d62c8ac86dccf2051164d5322a5b [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;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070032import org.onosproject.event.EventDeliveryService;
Madan Jampaniad3c5262016-01-20 00:50:17 -080033import org.onosproject.net.provider.AbstractListenerProviderRegistry;
34import org.onosproject.net.provider.AbstractProviderService;
Madan Jampaniec1df022015-10-13 21:23:03 -070035import org.onosproject.store.service.Versioned;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070036import org.osgi.service.component.annotations.Activate;
37import org.osgi.service.component.annotations.Component;
38import org.osgi.service.component.annotations.Deactivate;
39import org.osgi.service.component.annotations.Reference;
40import org.osgi.service.component.annotations.ReferenceCardinality;
Madan Jampaniec1df022015-10-13 21:23:03 -070041import org.slf4j.Logger;
42
Ray Milkeyd84f89b2018-08-17 14:54:17 -070043import java.net.Inet4Address;
44import java.net.InetAddress;
45import java.net.MalformedURLException;
46import java.net.NetworkInterface;
47import java.net.SocketException;
48import java.net.URL;
49import java.net.UnknownHostException;
50import java.util.Enumeration;
51
Heedo Kang4a47a302016-02-29 17:40:23 +090052import static com.google.common.base.Preconditions.checkNotNull;
53import static org.onosproject.security.AppGuard.checkPermission;
54import static org.onosproject.security.AppPermission.Type.CLUSTER_READ;
55import static org.slf4j.LoggerFactory.getLogger;
56
Madan Jampaniec1df022015-10-13 21:23:03 -070057/**
58 * Implementation of ClusterMetadataService.
59 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070060@Component(immediate = true, service = {ClusterMetadataService.class, ClusterMetadataAdminService.class, ClusterMetadataProviderRegistry.class})
Madan Jampaniec1df022015-10-13 21:23:03 -070061public class ClusterMetadataManager
Madan Jampaniad3c5262016-01-20 00:50:17 -080062 extends AbstractListenerProviderRegistry<ClusterMetadataEvent,
63 ClusterMetadataEventListener,
64 ClusterMetadataProvider,
65 ClusterMetadataProviderService>
66 implements ClusterMetadataService, ClusterMetadataAdminService, ClusterMetadataProviderRegistry {
Madan Jampaniec1df022015-10-13 21:23:03 -070067
Ray Milkeyd84f89b2018-08-17 14:54:17 -070068 private static final int MAX_WAIT_TRIES = 600;
69 private static final int MAX_WAIT_MS = 100;
70
Madan Jampaniec1df022015-10-13 21:23:03 -070071 private final Logger log = getLogger(getClass());
Madan Jampaniab7e7cd2016-01-14 14:02:32 -080072 private ControllerNode localNode;
Madan Jampaniec1df022015-10-13 21:23:03 -070073
Madan Jampaniec1df022015-10-13 21:23:03 -070074 @Activate
75 public void activate() {
Madan Jampaniad3c5262016-01-20 00:50:17 -080076 // FIXME: Need to ensure all cluster metadata providers are registered before we activate
Madan Jampaniec1df022015-10-13 21:23:03 -070077 eventDispatcher.addSink(ClusterMetadataEvent.class, listenerRegistry);
Madan Jampaniec1df022015-10-13 21:23:03 -070078 log.info("Started");
79 }
80
81 @Deactivate
82 public void deactivate() {
Madan Jampaniec1df022015-10-13 21:23:03 -070083 eventDispatcher.removeSink(ClusterMetadataEvent.class);
84 log.info("Stopped");
85 }
86
87 @Override
88 public ClusterMetadata getClusterMetadata() {
Heedo Kang4a47a302016-02-29 17:40:23 +090089 checkPermission(CLUSTER_READ);
Ray Milkeyd84f89b2018-08-17 14:54:17 -070090 waitForAvailableProvider();
Madan Jampaniad3c5262016-01-20 00:50:17 -080091 Versioned<ClusterMetadata> metadata = getProvider().getClusterMetadata();
92 return metadata.value();
93 }
94
Ray Milkeyd84f89b2018-08-17 14:54:17 -070095 // FIXME: Temporary hack to navigate around bootstrap timing issue
96 private void waitForAvailableProvider() {
97 for (int i = 0; i < MAX_WAIT_TRIES && getProvider() == null; i++) {
98 Tools.delay(MAX_WAIT_MS);
99 }
100 if (getProvider() == null) {
101 log.error("Unable to find cluster metadata provider");
102 throw new IllegalStateException("Unable to find cluster metadata provider");
103 }
104 }
Madan Jampaniad3c5262016-01-20 00:50:17 -0800105
106 @Override
107 protected ClusterMetadataProviderService createProviderService(
108 ClusterMetadataProvider provider) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900109 checkPermission(CLUSTER_READ);
Madan Jampaniad3c5262016-01-20 00:50:17 -0800110 return new InternalClusterMetadataProviderService(provider);
Madan Jampaniec1df022015-10-13 21:23:03 -0700111 }
112
113 @Override
114 public ControllerNode getLocalNode() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900115 checkPermission(CLUSTER_READ);
Madan Jampaniad3c5262016-01-20 00:50:17 -0800116 if (localNode == null) {
Jordan Halterman19c123a2018-07-30 13:57:19 -0700117 ClusterMetadata metadata = getProvider().getClusterMetadata().value();
118 ControllerNode localNode = metadata.getLocalNode();
Jordan Halterman00e92da2018-05-22 23:05:52 -0700119 try {
120 if (localNode != null) {
121 this.localNode = new DefaultControllerNode(
122 localNode.id(),
123 localNode.ip() != null ? localNode.ip() : findLocalIp(),
124 localNode.tcpPort());
125 } else {
126 IpAddress ip = findLocalIp();
Jordan Halterman19c123a2018-07-30 13:57:19 -0700127 localNode = metadata.getControllerNodes().stream()
128 .filter(node -> node.ip().equals(ip))
129 .findFirst()
130 .orElse(null);
131 if (localNode != null) {
132 this.localNode = localNode;
133 } else {
134 this.localNode = new DefaultControllerNode(NodeId.nodeId(ip.toString()), ip);
135 }
Jordan Halterman00e92da2018-05-22 23:05:52 -0700136 }
137 } catch (SocketException e) {
138 throw new IllegalStateException(e);
139 }
Madan Jampaniad3c5262016-01-20 00:50:17 -0800140 }
Madan Jampaniec1df022015-10-13 21:23:03 -0700141 return localNode;
142 }
143
144 @Override
145 public void setClusterMetadata(ClusterMetadata metadata) {
146 checkNotNull(metadata, "Cluster metadata cannot be null");
Madan Jampaniad3c5262016-01-20 00:50:17 -0800147 ClusterMetadataProvider primaryProvider = getPrimaryProvider();
148 if (primaryProvider == null) {
149 throw new IllegalStateException("Missing primary provider. Cannot update cluster metadata");
150 }
151 primaryProvider.setClusterMetadata(metadata);
Madan Jampaniec1df022015-10-13 21:23:03 -0700152 }
153
Madan Jampaniad3c5262016-01-20 00:50:17 -0800154 /**
155 * Returns the provider to use for fetching cluster metadata.
156 * @return cluster metadata provider
157 */
158 private ClusterMetadataProvider getProvider() {
159 ClusterMetadataProvider primaryProvider = getPrimaryProvider();
160 if (primaryProvider != null && primaryProvider.isAvailable()) {
161 return primaryProvider;
162 }
Madan Jampaniad3c5262016-01-20 00:50:17 -0800163 return getProvider("default");
164 }
165
166 /**
167 * Returns the primary provider for cluster metadata.
168 * @return primary cluster metadata provider
169 */
170 private ClusterMetadataProvider getPrimaryProvider() {
Madan Jampanif172d402016-03-04 00:56:38 -0800171 String metadataUri = System.getProperty("onos.cluster.metadata.uri");
Madan Jampaniad3c5262016-01-20 00:50:17 -0800172 try {
Madan Jampanif172d402016-03-04 00:56:38 -0800173 String protocol = metadataUri == null ? null : new URL(metadataUri).getProtocol();
Ray Milkey36cbc712017-04-07 13:33:59 -0700174 if (protocol != null && (!"file".equals(protocol) && !"http".equals(protocol))) {
Madan Jampanif172d402016-03-04 00:56:38 -0800175 return getProvider(protocol);
176 }
177 // file provider supports both "file" and "http" uris
178 return getProvider("file");
179 } catch (MalformedURLException e) {
Madan Jampaniad3c5262016-01-20 00:50:17 -0800180 return null;
Madan Jampaniec1df022015-10-13 21:23:03 -0700181 }
182 }
183
Jordan Halterman00e92da2018-05-22 23:05:52 -0700184 private IpAddress findLocalIp() throws SocketException {
185 Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
Madan Jampaniec1df022015-10-13 21:23:03 -0700186 while (interfaces.hasMoreElements()) {
187 NetworkInterface iface = interfaces.nextElement();
Jordan Halterman00e92da2018-05-22 23:05:52 -0700188 if (iface.isLoopback() || iface.isPointToPoint()) {
189 continue;
190 }
191
Madan Jampaniec1df022015-10-13 21:23:03 -0700192 Enumeration<InetAddress> inetAddresses = iface.getInetAddresses();
193 while (inetAddresses.hasMoreElements()) {
Jordan Halterman00e92da2018-05-22 23:05:52 -0700194 InetAddress inetAddress = inetAddresses.nextElement();
195 if (inetAddress instanceof Inet4Address) {
196 Inet4Address inet4Address = (Inet4Address) inetAddress;
197 try {
198 if (!inet4Address.getHostAddress().equals(InetAddress.getLocalHost().getHostAddress())) {
199 return IpAddress.valueOf(inetAddress);
200 }
201 } catch (UnknownHostException e) {
202 return IpAddress.valueOf(inetAddress);
203 }
Madan Jampaniec1df022015-10-13 21:23:03 -0700204 }
205 }
206 }
207 throw new IllegalStateException("Unable to determine local ip");
208 }
209
Madan Jampaniad3c5262016-01-20 00:50:17 -0800210 private class InternalClusterMetadataProviderService
211 extends AbstractProviderService<ClusterMetadataProvider>
212 implements ClusterMetadataProviderService {
213
214 InternalClusterMetadataProviderService(ClusterMetadataProvider provider) {
215 super(provider);
216 }
217
218 @Override
219 public void clusterMetadataChanged(Versioned<ClusterMetadata> newMetadata) {
220 log.info("Cluster metadata changed. New metadata: {}", newMetadata);
221 post(new ClusterMetadataEvent(ClusterMetadataEvent.Type.METADATA_CHANGED, newMetadata.value()));
222 }
223
224 @Override
225 public void newActiveMemberForPartition(PartitionId partitionId, NodeId nodeId) {
226 log.info("Node {} is active member for partition {}", nodeId, partitionId);
227 // TODO: notify listeners
228 }
229 }
Heedo Kang4a47a302016-02-29 17:40:23 +0900230}