Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 1 | /* |
Brian O'Connor | 8e57fd5 | 2016-04-09 01:19:45 -0700 | [diff] [blame] | 2 | * Copyright 2016-present Open Networking Laboratory |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 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 | */ |
alshabib | b4d3171 | 2016-06-01 18:51:03 -0700 | [diff] [blame] | 16 | package org.opencord.cordvtn.impl; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 17 | |
Hyunsun Moon | 81a1356 | 2016-08-04 13:48:08 -0700 | [diff] [blame] | 18 | import com.google.common.base.Strings; |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 19 | import com.google.common.collect.ImmutableSet; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 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.Reference; |
| 24 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
| 25 | import org.apache.felix.scr.annotations.Service; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 26 | import org.onosproject.cluster.ClusterService; |
Hyunsun Moon | 7004fcf | 2016-03-08 04:36:02 -0800 | [diff] [blame] | 27 | import org.onosproject.cluster.LeadershipService; |
| 28 | import org.onosproject.cluster.NodeId; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 29 | import org.onosproject.core.ApplicationId; |
| 30 | import org.onosproject.core.CoreService; |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 31 | import org.onosproject.event.ListenerRegistry; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 32 | import org.onosproject.net.DeviceId; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 33 | import org.onosproject.net.config.NetworkConfigEvent; |
| 34 | import org.onosproject.net.config.NetworkConfigListener; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 35 | import org.onosproject.net.config.NetworkConfigService; |
Hyunsun Moon | 187bf53 | 2017-01-19 10:57:40 +0900 | [diff] [blame] | 36 | import org.opencord.cordvtn.api.CordVtnConfig; |
Hyunsun Moon | 0984cbd | 2016-12-01 17:34:11 -0800 | [diff] [blame] | 37 | import org.opencord.cordvtn.api.node.CordVtnNode; |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 38 | import org.opencord.cordvtn.api.node.CordVtnNodeAdminService; |
| 39 | import org.opencord.cordvtn.api.node.CordVtnNodeEvent; |
| 40 | import org.opencord.cordvtn.api.node.CordVtnNodeListener; |
| 41 | import org.opencord.cordvtn.api.node.CordVtnNodeService; |
| 42 | import org.opencord.cordvtn.api.node.CordVtnNodeStore; |
| 43 | import org.opencord.cordvtn.api.node.CordVtnNodeStoreDelegate; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 44 | import org.slf4j.Logger; |
| 45 | |
Hyunsun Moon | 7004fcf | 2016-03-08 04:36:02 -0800 | [diff] [blame] | 46 | import java.util.Objects; |
Hyunsun Moon | 126171d | 2016-02-09 01:55:48 -0800 | [diff] [blame] | 47 | import java.util.Set; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 48 | import java.util.concurrent.ExecutorService; |
Hyunsun Moon | 58ddbdc | 2016-03-07 16:37:17 -0800 | [diff] [blame] | 49 | import java.util.stream.Collectors; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 50 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 51 | import static com.google.common.base.Preconditions.checkArgument; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 52 | import static com.google.common.base.Preconditions.checkNotNull; |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 53 | import static java.lang.String.format; |
Hyunsun Moon | 537018f | 2016-07-27 18:51:00 -0700 | [diff] [blame] | 54 | import static java.util.concurrent.Executors.newSingleThreadExecutor; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 55 | import static org.onlab.util.Tools.groupedThreads; |
Hyunsun Moon | 5401aaa | 2016-06-12 17:40:34 -0700 | [diff] [blame] | 56 | import static org.opencord.cordvtn.api.Constants.*; |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 57 | import static org.opencord.cordvtn.api.node.CordVtnNodeState.*; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 58 | import static org.slf4j.LoggerFactory.getLogger; |
| 59 | |
| 60 | /** |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 61 | * Manages the inventory of the cordvtn nodes provided via network configuration. |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 62 | */ |
| 63 | @Component(immediate = true) |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 64 | @Service |
| 65 | public class CordVtnNodeManager extends ListenerRegistry<CordVtnNodeEvent, CordVtnNodeListener> |
| 66 | implements CordVtnNodeAdminService, CordVtnNodeService { |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 67 | |
| 68 | protected final Logger log = getLogger(getClass()); |
| 69 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 70 | private static final String MSG_NODE = "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"; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 74 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 75 | private static final String ERR_NULL_NODE = "CordVtn node cannot be null"; |
| 76 | private static final String ERR_NULL_HOSTNAME = "CordVtn node hostname cannot be null"; |
| 77 | private static final String ERR_NULL_DEVICE_ID = "Device ID cannot be null"; |
| 78 | private static final String ERR_NOT_FOUND = "does not exist"; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 79 | |
| 80 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 81 | protected CoreService coreService; |
| 82 | |
| 83 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 84 | protected NetworkConfigService configService; |
| 85 | |
| 86 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 87 | protected LeadershipService leadershipService; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 88 | |
| 89 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
| 90 | protected ClusterService clusterService; |
| 91 | |
| 92 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 93 | protected CordVtnNodeStore nodeStore; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 94 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 95 | private final ExecutorService eventExecutor = newSingleThreadExecutor( |
| 96 | groupedThreads(this.getClass().getSimpleName(), "event-handler", log)); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 97 | |
| 98 | private final NetworkConfigListener configListener = new InternalConfigListener(); |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 99 | private final CordVtnNodeStoreDelegate delegate = new InternalCordVtnNodeStoreDelegate(); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 100 | |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 101 | private ApplicationId appId; |
Hyunsun Moon | 7004fcf | 2016-03-08 04:36:02 -0800 | [diff] [blame] | 102 | private NodeId localNodeId; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 103 | |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 104 | @Activate |
Hyunsun Moon | 479b775 | 2016-05-06 20:13:28 -0700 | [diff] [blame] | 105 | protected void activate() { |
Hyunsun Moon | eaf75e6 | 2016-09-27 16:40:23 -0700 | [diff] [blame] | 106 | appId = coreService.registerApplication(CORDVTN_APP_ID); |
Hyunsun Moon | 7004fcf | 2016-03-08 04:36:02 -0800 | [diff] [blame] | 107 | leadershipService.runForLeadership(appId.name()); |
Hyunsun Moon | 3fc0cbc | 2016-11-22 18:29:12 -0800 | [diff] [blame] | 108 | localNodeId = clusterService.getLocalNode().id(); |
Hyunsun Moon | 7004fcf | 2016-03-08 04:36:02 -0800 | [diff] [blame] | 109 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 110 | nodeStore.setDelegate(delegate); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 111 | configService.addListener(configListener); |
Hyunsun Moon | 479b775 | 2016-05-06 20:13:28 -0700 | [diff] [blame] | 112 | |
Hyunsun Moon | 9620731 | 2017-03-20 16:17:07 +0900 | [diff] [blame] | 113 | readNodes(); |
Hyunsun Moon | 479b775 | 2016-05-06 20:13:28 -0700 | [diff] [blame] | 114 | log.info("Started"); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | @Deactivate |
| 118 | protected void deactivate() { |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 119 | configService.removeListener(configListener); |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 120 | nodeStore.unsetDelegate(delegate); |
Hyunsun Moon | ff55e81 | 2016-03-10 12:40:16 -0800 | [diff] [blame] | 121 | |
Hyunsun Moon | 7004fcf | 2016-03-08 04:36:02 -0800 | [diff] [blame] | 122 | leadershipService.withdraw(appId.name()); |
Hyunsun Moon | ff55e81 | 2016-03-10 12:40:16 -0800 | [diff] [blame] | 123 | eventExecutor.shutdown(); |
Hyunsun Moon | 479b775 | 2016-05-06 20:13:28 -0700 | [diff] [blame] | 124 | |
| 125 | log.info("Stopped"); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 126 | } |
| 127 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 128 | @Override |
| 129 | public void createNode(CordVtnNode node) { |
| 130 | checkNotNull(node, ERR_NULL_NODE); |
| 131 | nodeStore.createNode(node); |
| 132 | log.info(format(MSG_NODE, node.hostname(), MSG_CREATED)); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 133 | } |
| 134 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 135 | @Override |
| 136 | public void updateNode(CordVtnNode node) { |
| 137 | checkNotNull(node, ERR_NULL_NODE); |
| 138 | nodeStore.updateNode(node); |
| 139 | log.debug(format(MSG_NODE, node.hostname(), MSG_UPDATED)); |
| 140 | } |
| 141 | |
| 142 | @Override |
| 143 | public CordVtnNode removeNode(String hostname) { |
| 144 | checkArgument(!Strings.isNullOrEmpty(hostname), ERR_NULL_HOSTNAME); |
| 145 | CordVtnNode removed = nodeStore.removeNode(hostname); |
| 146 | if (removed == null) { |
| 147 | log.warn(format(MSG_NODE, hostname, ERR_NOT_FOUND)); |
| 148 | return null; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 149 | } |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 150 | log.info(format(MSG_NODE, hostname, MSG_REMOVED)); |
| 151 | return removed; |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 152 | } |
| 153 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 154 | @Override |
| 155 | public Set<CordVtnNode> nodes() { |
| 156 | return nodeStore.nodes(); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 157 | } |
| 158 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 159 | @Override |
Hyunsun Moon | e7e4bb3 | 2016-05-16 04:32:45 -0700 | [diff] [blame] | 160 | public Set<CordVtnNode> completeNodes() { |
Hyunsun Moon | e7e4bb3 | 2016-05-16 04:32:45 -0700 | [diff] [blame] | 161 | // the state saved in nodeStore can be wrong if IP address settings are changed |
| 162 | // after the node init has been completed since there's no way to detect it |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 163 | Set<CordVtnNode> nodes = nodes().stream() |
| 164 | .filter(node -> node.state() == COMPLETE) |
| 165 | .collect(Collectors.toSet()); |
| 166 | return ImmutableSet.copyOf(nodes); |
Hyunsun Moon | e7e4bb3 | 2016-05-16 04:32:45 -0700 | [diff] [blame] | 167 | } |
| 168 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 169 | @Override |
| 170 | public CordVtnNode node(String hostname) { |
| 171 | checkArgument(!Strings.isNullOrEmpty(hostname), ERR_NULL_HOSTNAME); |
| 172 | return nodeStore.node(hostname); |
Hyunsun Moon | e7e4bb3 | 2016-05-16 04:32:45 -0700 | [diff] [blame] | 173 | } |
| 174 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 175 | @Override |
| 176 | public CordVtnNode node(DeviceId deviceId) { |
| 177 | checkNotNull(deviceId, ERR_NULL_DEVICE_ID); |
| 178 | return nodes().stream() |
| 179 | .filter(node -> node.integrationBridgeId().equals(deviceId) || |
| 180 | node.ovsdbId().equals(deviceId)) |
| 181 | .findAny().orElse(null); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 182 | } |
| 183 | |
| 184 | /** |
Hyunsun Moon | 3fc17f7 | 2016-01-24 21:47:06 -0800 | [diff] [blame] | 185 | * Reads cordvtn nodes from config file. |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 186 | */ |
Hyunsun Moon | 3fc0cbc | 2016-11-22 18:29:12 -0800 | [diff] [blame] | 187 | private void readNodes() { |
| 188 | NodeId leaderNodeId = leadershipService.getLeader(appId.name()); |
| 189 | if (!Objects.equals(localNodeId, leaderNodeId)) { |
| 190 | // do not allow to proceed without leadership |
| 191 | return; |
| 192 | } |
| 193 | |
Hyunsun Moon | 0984cbd | 2016-12-01 17:34:11 -0800 | [diff] [blame] | 194 | CordVtnConfig config = configService.getConfig(appId, CordVtnConfig.class); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 195 | if (config == null) { |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 196 | log.warn("No configuration found"); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 197 | return; |
| 198 | } |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 199 | config.cordVtnNodes().forEach(node -> { |
| 200 | log.info("Read node from network config: {}", node.hostname()); |
| 201 | CordVtnNode existing = node(node.hostname()); |
| 202 | if (existing == null) { |
| 203 | createNode(node); |
| 204 | } else if (!existing.equals(node)) { |
| 205 | // FIXME maybe we need to re-check node states |
| 206 | updateNode(node); |
| 207 | } |
Hyunsun Moon | 3fc0cbc | 2016-11-22 18:29:12 -0800 | [diff] [blame] | 208 | }); |
| 209 | } |
| 210 | |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 211 | private class InternalConfigListener implements NetworkConfigListener { |
| 212 | |
| 213 | @Override |
| 214 | public void event(NetworkConfigEvent event) { |
| 215 | if (!event.configClass().equals(CordVtnConfig.class)) { |
| 216 | return; |
| 217 | } |
| 218 | |
| 219 | switch (event.type()) { |
| 220 | case CONFIG_ADDED: |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 221 | case CONFIG_UPDATED: |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 222 | eventExecutor.execute(CordVtnNodeManager.this::readNodes); |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 223 | break; |
| 224 | default: |
| 225 | break; |
| 226 | } |
| 227 | } |
| 228 | } |
Hyunsun Moon | ff55e81 | 2016-03-10 12:40:16 -0800 | [diff] [blame] | 229 | |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 230 | private class InternalCordVtnNodeStoreDelegate implements CordVtnNodeStoreDelegate { |
Hyunsun Moon | ff55e81 | 2016-03-10 12:40:16 -0800 | [diff] [blame] | 231 | |
| 232 | @Override |
Hyunsun Moon | 2c3f0ee | 2017-04-06 16:47:21 +0900 | [diff] [blame] | 233 | public void notify(CordVtnNodeEvent event) { |
| 234 | if (event != null) { |
| 235 | process(event); |
Hyunsun Moon | ff55e81 | 2016-03-10 12:40:16 -0800 | [diff] [blame] | 236 | } |
| 237 | } |
| 238 | } |
Hyunsun Moon | cb79944 | 2016-01-15 20:03:18 -0800 | [diff] [blame] | 239 | } |