blob: 8b0001d8d5c8e5768337f0012e350cba28e7db39 [file] [log] [blame]
Thomas Vachuska58de4162015-09-10 16:15:33 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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 Jampaniafeebbd2015-05-19 15:26:01 -070016package org.onosproject.store.cluster.impl;
17
Jonathan Hart052a6c52015-07-16 14:10:10 -070018import com.google.common.collect.ImmutableSet;
19import com.google.common.collect.Sets;
Madan Jampaniafeebbd2015-05-19 15:26:01 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Service;
24import org.onlab.packet.IpAddress;
25import org.onosproject.cluster.ClusterDefinitionService;
26import org.onosproject.cluster.ControllerNode;
27import org.onosproject.cluster.DefaultControllerNode;
28import org.onosproject.cluster.NodeId;
29import org.onosproject.store.consistent.impl.DatabaseDefinition;
30import org.onosproject.store.consistent.impl.DatabaseDefinitionStore;
31import org.slf4j.Logger;
32
Jonathan Hart052a6c52015-07-16 14:10:10 -070033import java.io.File;
34import java.io.IOException;
35import java.net.InetAddress;
36import java.net.NetworkInterface;
37import java.net.SocketException;
38import java.util.Enumeration;
39import java.util.Set;
40import java.util.stream.Collectors;
41
42import static java.net.NetworkInterface.getNetworkInterfaces;
43import static java.util.Collections.list;
44import static org.onosproject.cluster.DefaultControllerNode.DEFAULT_PORT;
45import static org.onosproject.store.consistent.impl.DatabaseManager.PARTITION_DEFINITION_FILE;
46import static org.slf4j.LoggerFactory.getLogger;
Madan Jampaniafeebbd2015-05-19 15:26:01 -070047
48/**
49 * Implementation of ClusterDefinitionService.
50 */
51@Component(immediate = true)
52@Service
53public class ClusterDefinitionManager implements ClusterDefinitionService {
54
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;
60
61 @Activate
62 public void activate() {
63 File clusterDefinitionFile = new File(CLUSTER_DEFINITION_FILE);
64 ClusterDefinitionStore clusterDefinitionStore =
65 new ClusterDefinitionStore(clusterDefinitionFile.getPath());
66
67 if (!clusterDefinitionFile.exists()) {
68 createDefaultClusterDefinition(clusterDefinitionStore);
69 }
70
71 try {
72 ClusterDefinition clusterDefinition = clusterDefinitionStore.read();
73 establishSelfIdentity(clusterDefinition);
74 seedNodes = ImmutableSet
75 .copyOf(clusterDefinition.getNodes())
76 .stream()
77 .filter(n -> !localNode.id().equals(new NodeId(n.getId())))
78 .map(n -> new DefaultControllerNode(new NodeId(n.getId()),
79 IpAddress.valueOf(n.getIp()),
80 n.getTcpPort()))
81 .collect(Collectors.toSet());
82 } catch (IOException e) {
83 throw new IllegalStateException("Failed to read cluster definition.", e);
84 }
85
86 log.info("Started");
87 }
88
89 @Deactivate
90 public void deactivate() {
91 log.info("Stopped");
92 }
93
94 @Override
95 public ControllerNode localNode() {
96 return localNode;
97 }
98
99 @Override
100 public Set<ControllerNode> seedNodes() {
101 return seedNodes;
102 }
103
104 @Override
105 public void formCluster(Set<ControllerNode> nodes, String ipPrefix) {
106 try {
107 Set<NodeInfo> infos = Sets.newHashSet();
108 nodes.forEach(n -> infos.add(NodeInfo.from(n.id().toString(),
109 n.ip().toString(),
110 n.tcpPort())));
111
112 ClusterDefinition cdef = ClusterDefinition.from(infos, ipPrefix);
113 new ClusterDefinitionStore(CLUSTER_DEFINITION_FILE).write(cdef);
114
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);
119 }
120 }
121
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());
Jonathan Hart052a6c52015-07-16 14:10:10 -0700130 if (clusterDefinition.getNodes().stream()
131 .map(NodeInfo::getIp)
132 .map(IpAddress::valueOf)
133 .anyMatch(nodeIp -> ip.equals(nodeIp))) {
Madan Jampaniafeebbd2015-05-19 15:26:01 -0700134 return ip;
135 }
136 }
137 }
138 throw new IllegalStateException("Unable to determine local ip");
139 }
140
141 private void establishSelfIdentity(ClusterDefinition clusterDefinition) {
142 try {
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);
147 }
148 }
149
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);
155 try {
156 store.write(ClusterDefinition.from(ImmutableSet.of(node), ipPrefix));
157 } catch (IOException e) {
158 log.warn("Unable to write default cluster definition", e);
159 }
160 }
161
162 /**
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.
166 *
167 * @return site-local address in string form
168 */
169 public static String getSiteLocalAddress() {
170 try {
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();
178 }
179 }
180 }
181 } catch (SocketException e) {
182 log.error("Unable to get network interfaces", e);
183 }
184
185 return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString();
186 }
Thomas Vachuskaba082b82015-05-20 13:47:38 -0700187
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);
193 }
Madan Jampaniafeebbd2015-05-19 15:26:01 -0700194}