blob: 65d565aee6841bcc0428294300f5f29cdee1f706 [file] [log] [blame]
Hyunsun Moon0d457362017-06-27 17:19:41 +09001/*
2 * Copyright 2017-present 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.openstacknode.impl;
17
18import com.google.common.base.Strings;
19import com.google.common.collect.ImmutableSet;
20import 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.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
26import org.onosproject.cluster.ClusterService;
27import org.onosproject.cluster.LeadershipService;
28import org.onosproject.cluster.NodeId;
29import org.onosproject.core.ApplicationId;
30import org.onosproject.core.CoreService;
31import org.onosproject.event.ListenerRegistry;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.config.ConfigFactory;
34import org.onosproject.net.config.NetworkConfigEvent;
35import org.onosproject.net.config.NetworkConfigListener;
36import org.onosproject.net.config.NetworkConfigRegistry;
37import org.onosproject.net.config.basics.SubjectFactories;
38import org.onosproject.openstacknode.api.OpenstackNodeConfig;
39import org.onosproject.openstacknode.api.OpenstackNode;
40import org.onosproject.openstacknode.api.OpenstackNodeAdminService;
41import org.onosproject.openstacknode.api.OpenstackNodeEvent;
42import org.onosproject.openstacknode.api.OpenstackNodeListener;
43import org.onosproject.openstacknode.api.OpenstackNodeService;
44import org.onosproject.openstacknode.api.OpenstackNodeStore;
45import org.onosproject.openstacknode.api.OpenstackNodeStoreDelegate;
46import org.slf4j.Logger;
47
48import java.util.Objects;
49import java.util.Set;
50import java.util.concurrent.ExecutorService;
51import java.util.stream.Collectors;
52
53import static com.google.common.base.Preconditions.checkArgument;
54import static com.google.common.base.Preconditions.checkNotNull;
55import static java.util.concurrent.Executors.newSingleThreadExecutor;
56import static org.onlab.util.Tools.groupedThreads;
57import static org.onosproject.openstacknode.api.NodeState.COMPLETE;
58import static org.slf4j.LoggerFactory.getLogger;
59
60/**
61 * Service administering the inventory of openstack nodes.
62 */
63@Service
64@Component(immediate = true)
65public class OpenstackNodeManager extends ListenerRegistry<OpenstackNodeEvent, OpenstackNodeListener>
66 implements OpenstackNodeService, OpenstackNodeAdminService {
67
68 protected final Logger log = getLogger(getClass());
69
70 private static final String MSG_NODE = "OpenStack node %s %s";
71 private static final String MSG_CREATED = "created";
72 private static final String MSG_UPDATED = "updated";
73 private static final String MSG_REMOVED = "removed";
74
75 private static final String ERR_NULL_NODE = "OpenStack node cannot be null";
76 private static final String ERR_NULL_HOSTNAME = "OpenStack node hostname cannot be null";
77
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected OpenstackNodeStore osNodeStore;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected CoreService coreService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected ClusterService clusterService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected LeadershipService leadershipService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected NetworkConfigRegistry configRegistry;
92
93 private final ExecutorService eventExecutor = newSingleThreadExecutor(
94 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
95
96 private final ConfigFactory configFactory =
97 new ConfigFactory<ApplicationId, OpenstackNodeConfig>(
98 SubjectFactories.APP_SUBJECT_FACTORY, OpenstackNodeConfig.class, "openstacknode") {
99 @Override
100 public OpenstackNodeConfig createConfig() {
101 return new OpenstackNodeConfig();
102 }
103 };
104
105 private final NetworkConfigListener configListener = new InternalConfigListener();
106 private final OpenstackNodeStoreDelegate delegate = new InternalNodeStoreDelegate();
107
108 private ApplicationId appId;
109 private NodeId localNode;
110
111 @Activate
112 protected void activate() {
113 appId = coreService.registerApplication(APP_ID);
114 osNodeStore.setDelegate(delegate);
115
116 localNode = clusterService.getLocalNode().id();
117 leadershipService.runForLeadership(appId.name());
118
119 configRegistry.registerConfigFactory(configFactory);
120 configRegistry.addListener(configListener);
121
122 readConfiguration();
123 log.info("Started");
124 }
125
126 @Deactivate
127 protected void deactivate() {
128 osNodeStore.unsetDelegate(delegate);
129 configRegistry.removeListener(configListener);
130 configRegistry.unregisterConfigFactory(configFactory);
131
132 leadershipService.withdraw(appId.name());
133 eventExecutor.shutdown();
134
135 log.info("Stopped");
136 }
137
138 @Override
139 public void createNode(OpenstackNode osNode) {
140 checkNotNull(osNode, ERR_NULL_NODE);
141 osNodeStore.createNode(osNode);
142 log.info(String.format(MSG_NODE, osNode.hostname(), MSG_CREATED));
143 }
144
145 @Override
146 public void updateNode(OpenstackNode osNode) {
147 checkNotNull(osNode, ERR_NULL_NODE);
148 osNodeStore.updateNode(osNode);
149 log.info(String.format(MSG_NODE, osNode.hostname(), MSG_UPDATED));
150 }
151
152 @Override
153 public OpenstackNode removeNode(String hostname) {
154 checkArgument(!Strings.isNullOrEmpty(hostname), ERR_NULL_HOSTNAME);
155 OpenstackNode osNode = osNodeStore.removeNode(hostname);
156 log.info(String.format(MSG_NODE, hostname, MSG_REMOVED));
157 return osNode;
158 }
159
160 @Override
161 public Set<OpenstackNode> nodes() {
162 return osNodeStore.nodes();
163 }
164
165 @Override
166 public Set<OpenstackNode> nodes(OpenstackNode.NodeType type) {
167 Set<OpenstackNode> osNodes = osNodeStore.nodes().stream()
168 .filter(osNode -> Objects.equals(osNode.type(), type))
169 .collect(Collectors.toSet());
170 return ImmutableSet.copyOf(osNodes);
171 }
172
173 @Override
174 public Set<OpenstackNode> completeNodes() {
175 Set<OpenstackNode> osNodes = osNodeStore.nodes().stream()
176 .filter(osNode -> Objects.equals(osNode.state(), COMPLETE))
177 .collect(Collectors.toSet());
178 return ImmutableSet.copyOf(osNodes);
179 }
180
181 @Override
182 public Set<OpenstackNode> completeNodes(OpenstackNode.NodeType type) {
183 Set<OpenstackNode> osNodes = osNodeStore.nodes().stream()
184 .filter(osNode -> osNode.type() == type &&
185 Objects.equals(osNode.state(), COMPLETE))
186 .collect(Collectors.toSet());
187 return ImmutableSet.copyOf(osNodes);
188 }
189
190 @Override
191 public OpenstackNode node(String hostname) {
192 return osNodeStore.node(hostname);
193 }
194
195 @Override
196 public OpenstackNode node(DeviceId deviceId) {
197 OpenstackNode result = osNodeStore.nodes().stream()
198 .filter(osNode -> Objects.equals(osNode.intgBridge(), deviceId) ||
199 Objects.equals(osNode.ovsdb(), deviceId) ||
200 Objects.equals(osNode.routerBridge(), deviceId))
201 .findFirst().orElse(null);
202 return result;
203 }
204
205 private class InternalNodeStoreDelegate implements OpenstackNodeStoreDelegate {
206
207 @Override
208 public void notify(OpenstackNodeEvent event) {
209 if (event != null) {
210 log.trace("send openstack node event {}", event);
211 process(event);
212 }
213 }
214 }
215
216 private void readConfiguration() {
217 OpenstackNodeConfig config = configRegistry.getConfig(appId, OpenstackNodeConfig.class);
218 if (config == null) {
219 log.debug("No configuration found");
220 return;
221 }
222
223 log.info("Read openstack node configurations...");
224 Set<String> hostnames = config.openstackNodes().stream()
225 .map(OpenstackNode::hostname)
226 .collect(Collectors.toSet());
227 nodes().stream().filter(osNode -> !hostnames.contains(osNode.hostname()))
228 .forEach(osNode -> removeNode(osNode.hostname()));
229
230 config.openstackNodes().forEach(osNode -> {
231 OpenstackNode existing = node(osNode.hostname());
232 if (existing == null) {
233 createNode(osNode);
234 } else if (!existing.equals(osNode)) {
235 updateNode(osNode);
236 }
237 });
238 }
239
240 private class InternalConfigListener implements NetworkConfigListener {
241
242 @Override
243 public void event(NetworkConfigEvent event) {
244 NodeId leaderNodeId = leadershipService.getLeader(appId.name());
245 if (!Objects.equals(localNode, leaderNodeId)) {
246 // do not allow to proceed without leadership
247 return;
248 }
249
250 if (!event.configClass().equals(OpenstackNodeConfig.class)) {
251 return;
252 }
253
254 switch (event.type()) {
255 case CONFIG_ADDED:
256 case CONFIG_UPDATED:
257 eventExecutor.execute(OpenstackNodeManager.this::readConfiguration);
258 break;
259 default:
260 break;
261 }
262 }
263 }
264}