2 * Copyright 2015 Open Networking Laboratory
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.onosproject.store.cluster.impl;
18 import com.google.common.collect.ImmutableSet;
19 import com.google.common.collect.Sets;
20 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate;
23 import org.apache.felix.scr.annotations.Service;
24 import org.onlab.packet.IpAddress;
25 import org.onosproject.cluster.ClusterDefinitionService;
26 import org.onosproject.cluster.ControllerNode;
27 import org.onosproject.cluster.DefaultControllerNode;
28 import org.onosproject.cluster.NodeId;
29 import org.onosproject.store.consistent.impl.DatabaseDefinition;
30 import org.onosproject.store.consistent.impl.DatabaseDefinitionStore;
31 import org.slf4j.Logger;
34 import java.io.IOException;
35 import java.net.InetAddress;
36 import java.net.NetworkInterface;
37 import java.net.SocketException;
38 import java.util.Enumeration;
40 import java.util.stream.Collectors;
42 import static java.net.NetworkInterface.getNetworkInterfaces;
43 import static java.util.Collections.list;
44 import static org.onosproject.cluster.DefaultControllerNode.DEFAULT_PORT;
45 import static org.onosproject.store.consistent.impl.DatabaseManager.PARTITION_DEFINITION_FILE;
46 import static org.slf4j.LoggerFactory.getLogger;
49 * Implementation of ClusterDefinitionService.
51 @Component(immediate = true)
53 public class ClusterDefinitionManager implements ClusterDefinitionService {
55 public static final String CLUSTER_DEFINITION_FILE = "../config/cluster.json";
56 private static final String ONOS_NIC = "ONOS_NIC";
57 private static final Logger log = getLogger(ClusterDefinitionManager.class);
58 private ControllerNode localNode;
59 private Set<ControllerNode> seedNodes;
62 public void activate() {
63 File clusterDefinitionFile = new File(CLUSTER_DEFINITION_FILE);
64 ClusterDefinitionStore clusterDefinitionStore =
65 new ClusterDefinitionStore(clusterDefinitionFile.getPath());
67 if (!clusterDefinitionFile.exists()) {
68 createDefaultClusterDefinition(clusterDefinitionStore);
72 ClusterDefinition clusterDefinition = clusterDefinitionStore.read();
73 establishSelfIdentity(clusterDefinition);
74 seedNodes = ImmutableSet
75 .copyOf(clusterDefinition.getNodes())
77 .filter(n -> !localNode.id().equals(new NodeId(n.getId())))
78 .map(n -> new DefaultControllerNode(new NodeId(n.getId()),
79 IpAddress.valueOf(n.getIp()),
81 .collect(Collectors.toSet());
82 } catch (IOException e) {
83 throw new IllegalStateException("Failed to read cluster definition.", e);
90 public void deactivate() {
95 public ControllerNode localNode() {
100 public Set<ControllerNode> seedNodes() {
105 public void formCluster(Set<ControllerNode> nodes, String ipPrefix) {
107 Set<NodeInfo> infos = Sets.newHashSet();
108 nodes.forEach(n -> infos.add(NodeInfo.from(n.id().toString(),
112 ClusterDefinition cdef = ClusterDefinition.from(infos, ipPrefix);
113 new ClusterDefinitionStore(CLUSTER_DEFINITION_FILE).write(cdef);
115 DatabaseDefinition ddef = DatabaseDefinition.from(infos);
116 new DatabaseDefinitionStore(PARTITION_DEFINITION_FILE).write(ddef);
117 } catch (IOException e) {
118 log.error("Unable to form cluster", e);
122 private IpAddress findLocalIp(ClusterDefinition clusterDefinition) throws SocketException {
123 Enumeration<NetworkInterface> interfaces =
124 NetworkInterface.getNetworkInterfaces();
125 while (interfaces.hasMoreElements()) {
126 NetworkInterface iface = interfaces.nextElement();
127 Enumeration<InetAddress> inetAddresses = iface.getInetAddresses();
128 while (inetAddresses.hasMoreElements()) {
129 IpAddress ip = IpAddress.valueOf(inetAddresses.nextElement());
130 if (clusterDefinition.getNodes().stream()
131 .map(NodeInfo::getIp)
132 .map(IpAddress::valueOf)
133 .anyMatch(nodeIp -> ip.equals(nodeIp))) {
138 throw new IllegalStateException("Unable to determine local ip");
141 private void establishSelfIdentity(ClusterDefinition clusterDefinition) {
143 IpAddress ip = findLocalIp(clusterDefinition);
144 localNode = new DefaultControllerNode(new NodeId(ip.toString()), ip);
145 } catch (SocketException e) {
146 throw new IllegalStateException("Cannot determine local IP", e);
150 private void createDefaultClusterDefinition(ClusterDefinitionStore store) {
151 // Assumes IPv4 is returned.
152 String ip = getSiteLocalAddress();
153 String ipPrefix = ip.replaceFirst("\\.[0-9]*$", ".*");
154 NodeInfo node = NodeInfo.from(ip, ip, DEFAULT_PORT);
156 store.write(ClusterDefinition.from(ImmutableSet.of(node), ipPrefix));
157 } catch (IOException e) {
158 log.warn("Unable to write default cluster definition", e);
163 * Returns the address that matches the IP prefix given in ONOS_NIC
164 * environment variable if one was specified, or the first site local
165 * address if one can be found or the loopback address otherwise.
167 * @return site-local address in string form
169 public static String getSiteLocalAddress() {
171 String ipPrefix = System.getenv(ONOS_NIC);
172 for (NetworkInterface nif : list(getNetworkInterfaces())) {
173 for (InetAddress address : list(nif.getInetAddresses())) {
174 IpAddress ip = IpAddress.valueOf(address);
175 if (ipPrefix == null && address.isSiteLocalAddress() ||
176 ipPrefix != null && matchInterface(ip.toString(), ipPrefix)) {
177 return ip.toString();
181 } catch (SocketException e) {
182 log.error("Unable to get network interfaces", e);
185 return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString();
188 // Indicates whether the specified interface address matches the given prefix.
189 // FIXME: Add a facility to IpPrefix to make this more robust
190 private static boolean matchInterface(String ip, String ipPrefix) {
191 String s = ipPrefix.replaceAll("\\.\\*", "");
192 return ip.startsWith(s);