blob: df77d0962c21bc898dadb601477b1cb9d23a226a [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
Ray Milkey584f54b2018-10-08 14:45:20 -070018import com.google.common.collect.ImmutableList;
Madan Jampaniec1df022015-10-13 21:23:03 -070019import org.onlab.packet.IpAddress;
20import 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;
Ray Milkey584f54b2018-10-08 14:45:20 -070034import org.onosproject.net.provider.ProviderId;
35import org.onosproject.store.atomix.ClusterActivator;
Madan Jampaniec1df022015-10-13 21:23:03 -070036import org.onosproject.store.service.Versioned;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070037import org.osgi.service.component.annotations.Activate;
38import org.osgi.service.component.annotations.Component;
39import org.osgi.service.component.annotations.Deactivate;
Ray Milkey584f54b2018-10-08 14:45:20 -070040import org.osgi.service.component.annotations.Reference;
41import org.osgi.service.component.annotations.ReferenceCardinality;
Madan Jampaniec1df022015-10-13 21:23:03 -070042import org.slf4j.Logger;
43
Ray Milkeyd84f89b2018-08-17 14:54:17 -070044import java.net.Inet4Address;
45import java.net.InetAddress;
46import java.net.MalformedURLException;
47import java.net.NetworkInterface;
48import java.net.SocketException;
49import java.net.URL;
50import java.net.UnknownHostException;
51import java.util.Enumeration;
Ray Milkey584f54b2018-10-08 14:45:20 -070052import java.util.List;
53import java.util.Set;
54import java.util.stream.Collectors;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070055
Heedo Kang4a47a302016-02-29 17:40:23 +090056import static com.google.common.base.Preconditions.checkNotNull;
57import static org.onosproject.security.AppGuard.checkPermission;
58import static org.onosproject.security.AppPermission.Type.CLUSTER_READ;
59import static org.slf4j.LoggerFactory.getLogger;
60
Madan Jampaniec1df022015-10-13 21:23:03 -070061/**
62 * Implementation of ClusterMetadataService.
63 */
Ray Milkey86ad7bb2018-09-27 12:32:28 -070064@Component(immediate = true,
65 service = {ClusterMetadataService.class, ClusterMetadataAdminService.class,
66 ClusterMetadataProviderRegistry.class})
Madan Jampaniec1df022015-10-13 21:23:03 -070067public class ClusterMetadataManager
Madan Jampaniad3c5262016-01-20 00:50:17 -080068 extends AbstractListenerProviderRegistry<ClusterMetadataEvent,
69 ClusterMetadataEventListener,
70 ClusterMetadataProvider,
71 ClusterMetadataProviderService>
72 implements ClusterMetadataService, ClusterMetadataAdminService, ClusterMetadataProviderRegistry {
Madan Jampaniec1df022015-10-13 21:23:03 -070073
Ray Milkeyd84f89b2018-08-17 14:54:17 -070074 private static final int MAX_WAIT_TRIES = 600;
75 private static final int MAX_WAIT_MS = 100;
76
Ray Milkey584f54b2018-10-08 14:45:20 -070077 private List<String> requiredProviders = ImmutableList.of("file", "default");
78
Madan Jampaniec1df022015-10-13 21:23:03 -070079 private final Logger log = getLogger(getClass());
Madan Jampaniab7e7cd2016-01-14 14:02:32 -080080 private ControllerNode localNode;
Madan Jampaniec1df022015-10-13 21:23:03 -070081
Ray Milkey584f54b2018-10-08 14:45:20 -070082 @Reference(cardinality = ReferenceCardinality.MANDATORY)
83 private ClusterActivator clusterActivator;
84
Madan Jampaniec1df022015-10-13 21:23:03 -070085 @Activate
86 public void activate() {
Madan Jampaniec1df022015-10-13 21:23:03 -070087 eventDispatcher.addSink(ClusterMetadataEvent.class, listenerRegistry);
Madan Jampaniec1df022015-10-13 21:23:03 -070088 log.info("Started");
89 }
90
91 @Deactivate
92 public void deactivate() {
Madan Jampaniec1df022015-10-13 21:23:03 -070093 eventDispatcher.removeSink(ClusterMetadataEvent.class);
94 log.info("Stopped");
95 }
96
97 @Override
Ray Milkey584f54b2018-10-08 14:45:20 -070098 public synchronized ClusterMetadataProviderService register(ClusterMetadataProvider provider) {
99 ClusterMetadataProviderService s = super.register(provider);
100 Set<String> providerNames = getProviders().stream().map(ProviderId::scheme).collect(Collectors.toSet());
101 if (providerNames.containsAll(requiredProviders)) {
102 // Safe to release Atomix now, cluster metadata is ready
103 clusterActivator.activateCluster();
104 }
105 return s;
Madan Jampaniad3c5262016-01-20 00:50:17 -0800106 }
107
Ray Milkey584f54b2018-10-08 14:45:20 -0700108
109 @Override
110 public ClusterMetadata getClusterMetadata() {
111 checkPermission(CLUSTER_READ);
112 Versioned<ClusterMetadata> metadata = getProvider().getClusterMetadata();
113 return metadata.value();
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700114 }
Madan Jampaniad3c5262016-01-20 00:50:17 -0800115
116 @Override
117 protected ClusterMetadataProviderService createProviderService(
118 ClusterMetadataProvider provider) {
Heedo Kang4a47a302016-02-29 17:40:23 +0900119 checkPermission(CLUSTER_READ);
Madan Jampaniad3c5262016-01-20 00:50:17 -0800120 return new InternalClusterMetadataProviderService(provider);
Madan Jampaniec1df022015-10-13 21:23:03 -0700121 }
122
123 @Override
124 public ControllerNode getLocalNode() {
Heedo Kang4a47a302016-02-29 17:40:23 +0900125 checkPermission(CLUSTER_READ);
Madan Jampaniad3c5262016-01-20 00:50:17 -0800126 if (localNode == null) {
Jordan Halterman19c123a2018-07-30 13:57:19 -0700127 ClusterMetadata metadata = getProvider().getClusterMetadata().value();
128 ControllerNode localNode = metadata.getLocalNode();
Jordan Halterman00e92da2018-05-22 23:05:52 -0700129 try {
130 if (localNode != null) {
131 this.localNode = new DefaultControllerNode(
132 localNode.id(),
133 localNode.ip() != null ? localNode.ip() : findLocalIp(),
134 localNode.tcpPort());
135 } else {
136 IpAddress ip = findLocalIp();
Jordan Halterman19c123a2018-07-30 13:57:19 -0700137 localNode = metadata.getControllerNodes().stream()
138 .filter(node -> node.ip().equals(ip))
139 .findFirst()
140 .orElse(null);
141 if (localNode != null) {
142 this.localNode = localNode;
143 } else {
144 this.localNode = new DefaultControllerNode(NodeId.nodeId(ip.toString()), ip);
145 }
Jordan Halterman00e92da2018-05-22 23:05:52 -0700146 }
147 } catch (SocketException e) {
148 throw new IllegalStateException(e);
149 }
Madan Jampaniad3c5262016-01-20 00:50:17 -0800150 }
Madan Jampaniec1df022015-10-13 21:23:03 -0700151 return localNode;
152 }
153
154 @Override
155 public void setClusterMetadata(ClusterMetadata metadata) {
156 checkNotNull(metadata, "Cluster metadata cannot be null");
Madan Jampaniad3c5262016-01-20 00:50:17 -0800157 ClusterMetadataProvider primaryProvider = getPrimaryProvider();
158 if (primaryProvider == null) {
159 throw new IllegalStateException("Missing primary provider. Cannot update cluster metadata");
160 }
161 primaryProvider.setClusterMetadata(metadata);
Madan Jampaniec1df022015-10-13 21:23:03 -0700162 }
163
Madan Jampaniad3c5262016-01-20 00:50:17 -0800164 /**
165 * Returns the provider to use for fetching cluster metadata.
166 * @return cluster metadata provider
167 */
168 private ClusterMetadataProvider getProvider() {
169 ClusterMetadataProvider primaryProvider = getPrimaryProvider();
170 if (primaryProvider != null && primaryProvider.isAvailable()) {
171 return primaryProvider;
172 }
Madan Jampaniad3c5262016-01-20 00:50:17 -0800173 return getProvider("default");
174 }
175
176 /**
177 * Returns the primary provider for cluster metadata.
178 * @return primary cluster metadata provider
179 */
180 private ClusterMetadataProvider getPrimaryProvider() {
Madan Jampanif172d402016-03-04 00:56:38 -0800181 String metadataUri = System.getProperty("onos.cluster.metadata.uri");
Madan Jampaniad3c5262016-01-20 00:50:17 -0800182 try {
Madan Jampanif172d402016-03-04 00:56:38 -0800183 String protocol = metadataUri == null ? null : new URL(metadataUri).getProtocol();
Ray Milkey36cbc712017-04-07 13:33:59 -0700184 if (protocol != null && (!"file".equals(protocol) && !"http".equals(protocol))) {
Madan Jampanif172d402016-03-04 00:56:38 -0800185 return getProvider(protocol);
186 }
187 // file provider supports both "file" and "http" uris
188 return getProvider("file");
189 } catch (MalformedURLException e) {
Madan Jampaniad3c5262016-01-20 00:50:17 -0800190 return null;
Madan Jampaniec1df022015-10-13 21:23:03 -0700191 }
192 }
193
Jordan Halterman00e92da2018-05-22 23:05:52 -0700194 private IpAddress findLocalIp() throws SocketException {
195 Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
Madan Jampaniec1df022015-10-13 21:23:03 -0700196 while (interfaces.hasMoreElements()) {
197 NetworkInterface iface = interfaces.nextElement();
Jordan Halterman00e92da2018-05-22 23:05:52 -0700198 if (iface.isLoopback() || iface.isPointToPoint()) {
199 continue;
200 }
201
Madan Jampaniec1df022015-10-13 21:23:03 -0700202 Enumeration<InetAddress> inetAddresses = iface.getInetAddresses();
203 while (inetAddresses.hasMoreElements()) {
Jordan Halterman00e92da2018-05-22 23:05:52 -0700204 InetAddress inetAddress = inetAddresses.nextElement();
205 if (inetAddress instanceof Inet4Address) {
206 Inet4Address inet4Address = (Inet4Address) inetAddress;
207 try {
208 if (!inet4Address.getHostAddress().equals(InetAddress.getLocalHost().getHostAddress())) {
209 return IpAddress.valueOf(inetAddress);
210 }
211 } catch (UnknownHostException e) {
212 return IpAddress.valueOf(inetAddress);
213 }
Madan Jampaniec1df022015-10-13 21:23:03 -0700214 }
215 }
216 }
217 throw new IllegalStateException("Unable to determine local ip");
218 }
219
Madan Jampaniad3c5262016-01-20 00:50:17 -0800220 private class InternalClusterMetadataProviderService
221 extends AbstractProviderService<ClusterMetadataProvider>
222 implements ClusterMetadataProviderService {
223
224 InternalClusterMetadataProviderService(ClusterMetadataProvider provider) {
225 super(provider);
226 }
227
228 @Override
229 public void clusterMetadataChanged(Versioned<ClusterMetadata> newMetadata) {
230 log.info("Cluster metadata changed. New metadata: {}", newMetadata);
231 post(new ClusterMetadataEvent(ClusterMetadataEvent.Type.METADATA_CHANGED, newMetadata.value()));
232 }
233
234 @Override
235 public void newActiveMemberForPartition(PartitionId partitionId, NodeId nodeId) {
236 log.info("Node {} is active member for partition {}", nodeId, partitionId);
237 // TODO: notify listeners
238 }
239 }
Heedo Kang4a47a302016-02-29 17:40:23 +0900240}