blob: 825aa0a0d1f82c871271d53f7e2d243bab6ac2e4 [file] [log] [blame]
Madan Jampaniad3c5262016-01-20 00:50:17 -08001/*
2 * Copyright 2015-2016 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 */
16package org.onosproject.cluster.impl;
17
18import static org.slf4j.LoggerFactory.getLogger;
19
20import java.io.File;
21import java.io.IOException;
22import java.util.Set;
23import java.util.concurrent.atomic.AtomicReference;
24
25import org.apache.felix.scr.annotations.Activate;
26import org.apache.felix.scr.annotations.Component;
27import org.apache.felix.scr.annotations.Deactivate;
28import org.apache.felix.scr.annotations.Reference;
29import org.apache.felix.scr.annotations.ReferenceCardinality;
30import org.onlab.packet.IpAddress;
31import org.onosproject.cluster.ClusterMetadata;
32import org.onosproject.cluster.ClusterMetadataProvider;
33import org.onosproject.cluster.ClusterMetadataProviderRegistry;
34import org.onosproject.cluster.ClusterMetadataProviderService;
35import org.onosproject.cluster.ControllerNode;
36import org.onosproject.cluster.DefaultControllerNode;
37import org.onosproject.cluster.DefaultPartition;
38import org.onosproject.cluster.NodeId;
39import org.onosproject.cluster.Partition;
40import org.onosproject.cluster.PartitionId;
41import org.onosproject.net.provider.ProviderId;
42import org.onosproject.store.service.Versioned;
43import org.slf4j.Logger;
44
45import com.fasterxml.jackson.core.JsonGenerator;
46import com.fasterxml.jackson.core.JsonParser;
47import com.fasterxml.jackson.core.JsonProcessingException;
48import com.fasterxml.jackson.databind.DeserializationContext;
49import com.fasterxml.jackson.databind.JsonDeserializer;
50import com.fasterxml.jackson.databind.JsonNode;
51import com.fasterxml.jackson.databind.JsonSerializer;
52import com.fasterxml.jackson.databind.ObjectMapper;
53import com.fasterxml.jackson.databind.SerializerProvider;
54import com.fasterxml.jackson.databind.module.SimpleModule;
55import com.google.common.base.Throwables;
56import com.google.common.collect.Sets;
57import com.google.common.io.Files;
58
59import static com.google.common.base.Preconditions.checkState;
60
61/**
62 * Provider of {@link ClusterMetadata cluster metadata} sourced from a local config file.
63 */
64@Component(immediate = true)
65public class ConfigFileBasedClusterMetadataProvider implements ClusterMetadataProvider {
66
67 private final Logger log = getLogger(getClass());
68
69 // constants for filed names (used in serialization)
70 private static final String ID = "id";
71 private static final String PORT = "port";
72 private static final String IP = "ip";
73
74 private static final File CONFIG_FILE = new File("../config/cluster.json");
75
76 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 protected ClusterMetadataProviderRegistry providerRegistry;
78
79 private static final ProviderId PROVIDER_ID = new ProviderId("config", "none");
80 private AtomicReference<Versioned<ClusterMetadata>> cachedMetadata = new AtomicReference<>();
81
82 private ObjectMapper mapper;
83 private ClusterMetadataProviderService providerService;
84
85 @Activate
86 public void activate() {
87 mapper = new ObjectMapper();
88 SimpleModule module = new SimpleModule();
89 module.addSerializer(NodeId.class, new NodeIdSerializer());
90 module.addDeserializer(NodeId.class, new NodeIdDeserializer());
91 module.addSerializer(ControllerNode.class, new ControllerNodeSerializer());
92 module.addDeserializer(ControllerNode.class, new ControllerNodeDeserializer());
93 module.addDeserializer(Partition.class, new PartitionDeserializer());
94 module.addSerializer(PartitionId.class, new PartitionIdSerializer());
95 module.addDeserializer(PartitionId.class, new PartitionIdDeserializer());
96 mapper.registerModule(module);
97 providerService = providerRegistry.register(this);
98 log.info("Started");
99 }
100
101 @Deactivate
102 public void deactivate() {
103 providerRegistry.unregister(this);
104 log.info("Stopped");
105 }
106
107 @Override
108 public ProviderId id() {
109 return PROVIDER_ID;
110 }
111
112 @Override
113 public Versioned<ClusterMetadata> getClusterMetadata() {
114 checkState(isAvailable());
115 synchronized (this) {
116 if (cachedMetadata.get() == null) {
117 loadMetadata();
118 }
119 return cachedMetadata.get();
120 }
121 }
122
123 @Override
124 public void setClusterMetadata(ClusterMetadata metadata) {
125 try {
126 Files.createParentDirs(CONFIG_FILE);
127 mapper.writeValue(CONFIG_FILE, metadata);
128 providerService.clusterMetadataChanged(new Versioned<>(metadata, CONFIG_FILE.lastModified()));
129 } catch (IOException e) {
130 Throwables.propagate(e);
131 }
132 }
133
134 @Override
135 public void addActivePartitionMember(PartitionId partitionId, NodeId nodeId) {
136 throw new UnsupportedOperationException();
137 }
138
139 @Override
140 public void removeActivePartitionMember(PartitionId partitionId, NodeId nodeId) {
141 throw new UnsupportedOperationException();
142 }
143
144 @Override
145 public Set<NodeId> getActivePartitionMembers(PartitionId partitionId) {
146 throw new UnsupportedOperationException();
147 }
148
149 @Override
150 public boolean isAvailable() {
151 return CONFIG_FILE.exists();
152 }
153
154 private void loadMetadata() {
155 ClusterMetadata metadata = null;
156 long version = 0;
157 try {
158 metadata = mapper.readValue(CONFIG_FILE, ClusterMetadata.class);
159 version = metadata.hashCode();
160 } catch (IOException e) {
161 Throwables.propagate(e);
162 }
163 cachedMetadata.set(new Versioned<>(new ClusterMetadata(PROVIDER_ID,
164 metadata.getName(),
165 Sets.newHashSet(metadata.getNodes()),
166 Sets.newHashSet(metadata.getPartitions())),
167 version));
168 }
169
170 private static class PartitionDeserializer extends JsonDeserializer<Partition> {
171 @Override
172 public Partition deserialize(JsonParser jp, DeserializationContext ctxt)
173 throws IOException, JsonProcessingException {
174 return jp.readValueAs(DefaultPartition.class);
175 }
176 }
177
178 private static class PartitionIdSerializer extends JsonSerializer<PartitionId> {
179 @Override
180 public void serialize(PartitionId partitionId, JsonGenerator jgen, SerializerProvider provider)
181 throws IOException, JsonProcessingException {
182 jgen.writeNumber(partitionId.asInt());
183 }
184 }
185
186 private class PartitionIdDeserializer extends JsonDeserializer<PartitionId> {
187 @Override
188 public PartitionId deserialize(JsonParser jp, DeserializationContext ctxt)
189 throws IOException, JsonProcessingException {
190 JsonNode node = jp.getCodec().readTree(jp);
191 return new PartitionId(node.asInt());
192 }
193 }
194
195 private static class ControllerNodeSerializer extends JsonSerializer<ControllerNode> {
196 @Override
197 public void serialize(ControllerNode node, JsonGenerator jgen, SerializerProvider provider)
198 throws IOException, JsonProcessingException {
199 jgen.writeStartObject();
200 jgen.writeStringField(ID, node.id().toString());
201 jgen.writeStringField(IP, node.ip().toString());
202 jgen.writeNumberField(PORT, node.tcpPort());
203 jgen.writeEndObject();
204 }
205 }
206
207 private static class ControllerNodeDeserializer extends JsonDeserializer<ControllerNode> {
208 @Override
209 public ControllerNode deserialize(JsonParser jp, DeserializationContext ctxt)
210 throws IOException, JsonProcessingException {
211 JsonNode node = jp.getCodec().readTree(jp);
212 NodeId nodeId = new NodeId(node.get(ID).textValue());
213 IpAddress ip = IpAddress.valueOf(node.get(IP).textValue());
214 int port = node.get(PORT).asInt();
215 return new DefaultControllerNode(nodeId, ip, port);
216 }
217 }
218
219 private static class NodeIdSerializer extends JsonSerializer<NodeId> {
220 @Override
221 public void serialize(NodeId nodeId, JsonGenerator jgen, SerializerProvider provider)
222 throws IOException, JsonProcessingException {
223 jgen.writeString(nodeId.toString());
224 }
225 }
226
227 private class NodeIdDeserializer extends JsonDeserializer<NodeId> {
228 @Override
229 public NodeId deserialize(JsonParser jp, DeserializationContext ctxt)
230 throws IOException, JsonProcessingException {
231 JsonNode node = jp.getCodec().readTree(jp);
232 return new NodeId(node.asText());
233 }
234 }
235}