blob: e4a09cef0099b83d6d0d8cba11f0252e362d8839 [file] [log] [blame]
Madan Jampaniec1df022015-10-13 21:23:03 -07001package org.onosproject.store.cluster.impl;
2
3import static com.google.common.base.Preconditions.checkNotNull;
4import static java.net.NetworkInterface.getNetworkInterfaces;
5import static org.slf4j.LoggerFactory.getLogger;
6
7import java.io.File;
8import java.io.IOException;
9import java.net.InetAddress;
10import java.net.NetworkInterface;
11import java.util.Arrays;
12import java.util.Collection;
13import java.util.Collections;
14import java.util.concurrent.atomic.AtomicReference;
15import java.util.function.Function;
16
17import org.apache.felix.scr.annotations.Activate;
18import org.apache.felix.scr.annotations.Component;
19import org.apache.felix.scr.annotations.Deactivate;
20import org.apache.felix.scr.annotations.Service;
21import org.onlab.packet.IpAddress;
22import org.onosproject.cluster.ClusterMetadata;
23import org.onosproject.cluster.ClusterMetadataEvent;
24import org.onosproject.cluster.ClusterMetadataStore;
25import org.onosproject.cluster.ClusterMetadataStoreDelegate;
26import org.onosproject.cluster.ControllerNode;
27import org.onosproject.cluster.DefaultControllerNode;
28import org.onosproject.cluster.NodeId;
29import org.onosproject.cluster.Partition;
30import org.onosproject.store.AbstractStore;
31import org.onosproject.store.service.Versioned;
32import org.slf4j.Logger;
33
34import com.fasterxml.jackson.core.JsonGenerator;
35import com.fasterxml.jackson.core.JsonParser;
36import com.fasterxml.jackson.core.JsonProcessingException;
37import com.fasterxml.jackson.databind.DeserializationContext;
38import com.fasterxml.jackson.databind.JsonDeserializer;
39import com.fasterxml.jackson.databind.JsonNode;
40import com.fasterxml.jackson.databind.JsonSerializer;
41import com.fasterxml.jackson.databind.ObjectMapper;
42import com.fasterxml.jackson.databind.SerializerProvider;
43import com.fasterxml.jackson.databind.module.SimpleModule;
44import com.google.common.base.Throwables;
45import com.google.common.collect.Lists;
46import com.google.common.io.Files;
47
48/**
49 * ClusterMetadataStore backed by a local file.
50 */
51@Component(immediate = true, enabled = true)
52@Service
53public class StaticClusterMetadataStore
54 extends AbstractStore<ClusterMetadataEvent, ClusterMetadataStoreDelegate>
55 implements ClusterMetadataStore {
56
57 private final Logger log = getLogger(getClass());
David K. Bainbridge34cc1022015-11-06 10:02:19 -080058
59 private static final String ONOS_IP = "ONOS_IP";
60 private static final String ONOS_INTERFACE = "ONOS_INTERFACE";
61 private static final String DEFAULT_ONOS_INTERFACE = "eth0";
Madan Jampaniec1df022015-10-13 21:23:03 -070062 private static final String CLUSTER_METADATA_FILE = "../config/cluster.json";
63 private static final int DEFAULT_ONOS_PORT = 9876;
64 private final File metadataFile = new File(CLUSTER_METADATA_FILE);
65 private AtomicReference<ClusterMetadata> metadata = new AtomicReference<>();
66 private ObjectMapper mapper;
67 private long version;
68
69 @Activate
70 public void activate() {
71 mapper = new ObjectMapper();
72 SimpleModule module = new SimpleModule();
73 module.addSerializer(NodeId.class, new NodeIdSerializer());
74 module.addDeserializer(NodeId.class, new NodeIdDeserializer());
75 module.addSerializer(ControllerNode.class, new ControllerNodeSerializer());
76 module.addDeserializer(ControllerNode.class, new ControllerNodeDeserializer());
77 mapper.registerModule(module);
78 File metadataFile = new File(CLUSTER_METADATA_FILE);
79 if (metadataFile.exists()) {
80 try {
81 metadata.set(mapper.readValue(metadataFile, ClusterMetadata.class));
82 version = metadataFile.lastModified();
83 } catch (IOException e) {
84 Throwables.propagate(e);
85 }
86 } else {
87 String localIp = getSiteLocalAddress();
88 ControllerNode localNode =
89 new DefaultControllerNode(new NodeId(localIp), IpAddress.valueOf(localIp), DEFAULT_ONOS_PORT);
90 metadata.set(ClusterMetadata.builder()
91 .withName("default")
92 .withControllerNodes(Arrays.asList(localNode))
93 .withPartitions(Lists.newArrayList(new Partition("p1", Lists.newArrayList(localNode.id()))))
94 .build());
95 version = System.currentTimeMillis();
96 }
97 log.info("Started");
98 }
99
100 @Deactivate
101 public void deactivate() {
102 log.info("Stopped");
103 }
104
105 @Override
106 public void setDelegate(ClusterMetadataStoreDelegate delegate) {
107 checkNotNull(delegate, "Delegate cannot be null");
108 this.delegate = delegate;
109 }
110
111 @Override
112 public void unsetDelegate(ClusterMetadataStoreDelegate delegate) {
113 this.delegate = null;
114 }
115
116 @Override
117 public boolean hasDelegate() {
118 return this.delegate != null;
119 }
120
121 @Override
122 public Versioned<ClusterMetadata> getClusterMetadata() {
123 return new Versioned<>(metadata.get(), version);
124 }
125
126 @Override
127 public void setClusterMetadata(ClusterMetadata metadata) {
128 checkNotNull(metadata);
129 try {
130 Files.createParentDirs(metadataFile);
131 mapper.writeValue(metadataFile, metadata);
132 this.metadata.set(metadata);
133 } catch (IOException e) {
134 Throwables.propagate(e);
135 }
136 }
137
138 @Override
139 public void setActiveReplica(String partitionId, NodeId nodeId) {
140 throw new UnsupportedOperationException();
141 }
142
143 @Override
144 public void unsetActiveReplica(String partitionId, NodeId nodeId) {
145 throw new UnsupportedOperationException();
146 }
147
148 @Override
149 public Collection<NodeId> getActiveReplicas(String partitionId) {
150 return metadata.get().getPartitions()
151 .stream()
152 .filter(r -> r.getName().equals(partitionId))
153 .findFirst()
154 .map(r -> r.getMembers())
155 .orElse(null);
156 }
157
158 private static class ControllerNodeSerializer extends JsonSerializer<ControllerNode> {
159 @Override
160 public void serialize(ControllerNode node, JsonGenerator jgen, SerializerProvider provider)
161 throws IOException, JsonProcessingException {
162 jgen.writeStartObject();
163 jgen.writeStringField("id", node.id().toString());
164 jgen.writeStringField("ip", node.ip().toString());
165 jgen.writeNumberField("port", node.tcpPort());
166 jgen.writeEndObject();
167 }
168 }
169
170 private static class ControllerNodeDeserializer extends JsonDeserializer<ControllerNode> {
171 @Override
172 public ControllerNode deserialize(JsonParser jp, DeserializationContext ctxt)
173 throws IOException, JsonProcessingException {
174 JsonNode node = jp.getCodec().readTree(jp);
175 NodeId nodeId = new NodeId(node.get("id").textValue());
176 IpAddress ip = IpAddress.valueOf(node.get("ip").textValue());
177 int port = node.get("port").asInt();
178 return new DefaultControllerNode(nodeId, ip, port);
179 }
180 }
181
182 private static class NodeIdSerializer extends JsonSerializer<NodeId> {
183 @Override
184 public void serialize(NodeId nodeId, JsonGenerator jgen, SerializerProvider provider)
185 throws IOException, JsonProcessingException {
186 jgen.writeString(nodeId.toString());
187 }
188 }
189
190 private class NodeIdDeserializer extends JsonDeserializer<NodeId> {
191 @Override
192 public NodeId deserialize(JsonParser jp, DeserializationContext ctxt)
193 throws IOException, JsonProcessingException {
194 JsonNode node = jp.getCodec().readTree(jp);
195 return new NodeId(node.asText());
196 }
197 }
198
199
200 private static String getSiteLocalAddress() {
David K. Bainbridge34cc1022015-11-06 10:02:19 -0800201
202 /*
203 * If the IP ONOS should use is set via the environment variable we will assume it is valid and should be used.
204 * Setting the IP address takes presidence over setting the interface via the environment.
205 */
206 String useOnosIp = System.getenv(ONOS_IP);
207 if (useOnosIp != null) {
208 return useOnosIp;
209 }
210
211 // Read environment variables for IP interface information or set to default
212 String useOnosInterface = System.getenv(ONOS_INTERFACE);
213 if (useOnosInterface == null) {
214 useOnosInterface = DEFAULT_ONOS_INTERFACE;
215 }
216
Madan Jampaniec1df022015-10-13 21:23:03 -0700217 Function<NetworkInterface, IpAddress> ipLookup = nif -> {
218 for (InetAddress address : Collections.list(nif.getInetAddresses())) {
219 if (address.isSiteLocalAddress()) {
220 return IpAddress.valueOf(address);
221 }
222 }
223 return null;
224 };
225 try {
David K. Bainbridge34cc1022015-11-06 10:02:19 -0800226 IpAddress ip = ipLookup.apply(NetworkInterface.getByName(useOnosInterface));
Madan Jampaniec1df022015-10-13 21:23:03 -0700227 if (ip != null) {
228 return ip.toString();
229 }
230 for (NetworkInterface nif : Collections.list(getNetworkInterfaces())) {
231 ip = ipLookup.apply(nif);
232 if (ip != null) {
233 return ip.toString();
234 }
235 }
236 } catch (Exception e) {
237 throw new IllegalStateException("Unable to get network interfaces", e);
238 }
239 return IpAddress.valueOf(InetAddress.getLoopbackAddress()).toString();
240 }
David K. Bainbridge34cc1022015-11-06 10:02:19 -0800241}