blob: 7f5a10249ef79b20e3c5353881ce72d4f038020b [file] [log] [blame]
Hyunsun Moone9d75992015-09-15 22:39:16 -07001/*
Brian O'Connor8e57fd52016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Hyunsun Moone9d75992015-09-15 22:39:16 -07003 *
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 */
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070016package org.opencord.cordvtn.api.config;
Hyunsun Moone9d75992015-09-15 22:39:16 -070017
18import com.fasterxml.jackson.databind.JsonNode;
Hyunsun Moon153db182016-08-04 14:06:40 -070019import com.fasterxml.jackson.databind.node.ObjectNode;
Hyunsun Moon81a13562016-08-04 13:48:08 -070020import com.google.common.base.Strings;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080021import com.google.common.collect.ImmutableList;
22import com.google.common.collect.Lists;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080023import com.google.common.collect.Maps;
Hyunsun Moone9d75992015-09-15 22:39:16 -070024import com.google.common.collect.Sets;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080025import org.onlab.osgi.DefaultServiceDirectory;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080026import org.onlab.packet.IpAddress;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080027import org.onlab.packet.MacAddress;
Hyunsun Moone9d75992015-09-15 22:39:16 -070028import org.onlab.packet.TpPort;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080029import org.onosproject.cluster.ClusterService;
Hyunsun Moone9d75992015-09-15 22:39:16 -070030import org.onosproject.core.ApplicationId;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080031import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moone9d75992015-09-15 22:39:16 -070032import org.onosproject.net.config.Config;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080033import org.onosproject.net.config.InvalidFieldException;
Hyunsun Moonfd5a24e2016-10-19 19:15:48 -070034import org.opencord.cordvtn.api.node.CordVtnNode;
35import org.opencord.cordvtn.api.node.NetworkAddress;
36import org.opencord.cordvtn.api.node.SshAccessInfo;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080037import org.slf4j.Logger;
Hyunsun Moone9d75992015-09-15 22:39:16 -070038
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080039import java.util.List;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -080040import java.util.Map;
Hyunsun Moone9d75992015-09-15 22:39:16 -070041import java.util.Set;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080042import java.util.stream.Collectors;
Hyunsun Moone9d75992015-09-15 22:39:16 -070043
Hyunsun Moon153db182016-08-04 14:06:40 -070044import static org.onosproject.net.config.Config.FieldPresence.MANDATORY;
45import static org.onosproject.net.config.Config.FieldPresence.OPTIONAL;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080046import static org.opencord.cordvtn.api.Constants.DEFAULT_OF_PORT;
47import static org.opencord.cordvtn.api.Constants.DEFAULT_OF_PROTOCOL;
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080048import static org.slf4j.LoggerFactory.getLogger;
Hyunsun Moone9d75992015-09-15 22:39:16 -070049
50/**
Hyunsun Moon9661d642015-09-23 13:24:35 -070051 * Configuration object for CordVtn service.
Hyunsun Moone9d75992015-09-15 22:39:16 -070052 */
53public class CordVtnConfig extends Config<ApplicationId> {
54
Hyunsun Moon3fc17f72016-01-24 21:47:06 -080055 protected final Logger log = getLogger(getClass());
56
Hyunsun Moon60a10672016-06-12 17:39:12 -070057 private static final String PRIVATE_GATEWAY_MAC = "privateGatewayMac";
58 private static final String PUBLIC_GATEWAYS = "publicGateways";
59 private static final String GATEWAY_IP = "gatewayIp";
60 private static final String GATEWAY_MAC = "gatewayMac";
61 private static final String LOCAL_MANAGEMENT_IP = "localManagementIp";
62 private static final String OVSDB_PORT = "ovsdbPort";
Hyunsun Moond05b32e2016-03-02 19:27:26 -080063
Hyunsun Moon60a10672016-06-12 17:39:12 -070064 private static final String CORDVTN_NODES = "nodes";
65 private static final String HOSTNAME = "hostname";
66 private static final String HOST_MANAGEMENT_IP = "hostManagementIp";
Hyunsun Moon81a13562016-08-04 13:48:08 -070067 private static final String HOST_MANAGEMENT_IFACE = "hostManagementIface";
68 private static final String DATA_IP = "dataPlaneIp";
69 private static final String DATA_IFACE = "dataPlaneIntf";
70 private static final String INTEGRATION_BRIDGE_ID = "bridgeId";
Hyunsun Moone9d75992015-09-15 22:39:16 -070071
Hyunsun Moon60a10672016-06-12 17:39:12 -070072 private static final String SSH = "ssh";
73 private static final String SSH_PORT = "sshPort";
74 private static final String SSH_USER = "sshUser";
75 private static final String SSH_KEY_FILE = "sshKeyFile";
Hyunsun Moon61e79ee2016-04-14 19:04:23 -070076
Hyunsun Moon60a10672016-06-12 17:39:12 -070077 private static final String OPENSTACK = "openstack";
78 private static final String XOS = "xos";
Hyunsun Moon60a10672016-06-12 17:39:12 -070079 private static final String ENDPOINT = "endpoint";
80 private static final String TENANT = "tenant";
81 private static final String USER = "user";
82 private static final String PASSWORD = "password";
Hyunsun Moon61e79ee2016-04-14 19:04:23 -070083
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -080084 private static final String CONTROLLERS = "controllers";
85 private static final int INDEX_IP = 0;
86 private static final int INDEX_PORT = 1;
87
88 private final ClusterService clusterService =
89 DefaultServiceDirectory.getService(ClusterService.class);
90
Hyunsun Moon153db182016-08-04 14:06:40 -070091 @Override
92 public boolean isValid() {
93 // check only allowed fields are present
94 boolean result = hasOnlyFields(
95 PRIVATE_GATEWAY_MAC,
96 PUBLIC_GATEWAYS,
97 LOCAL_MANAGEMENT_IP,
98 OVSDB_PORT,
99 SSH,
100 OPENSTACK,
101 XOS,
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800102 CORDVTN_NODES,
103 CONTROLLERS);
Hyunsun Moon153db182016-08-04 14:06:40 -0700104
105 if (object.get(CORDVTN_NODES) == null || object.get(CORDVTN_NODES).size() < 1) {
106 final String msg = "No node is present";
107 throw new IllegalArgumentException(msg);
108 }
109
110 // check all mandatory fields are present and valid
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800111 result &= isMacAddress(PRIVATE_GATEWAY_MAC, MANDATORY);
112 result &= isIpPrefix(LOCAL_MANAGEMENT_IP, MANDATORY);
Hyunsun Moon153db182016-08-04 14:06:40 -0700113
114 for (JsonNode node : object.get(CORDVTN_NODES)) {
115 ObjectNode vtnNode = (ObjectNode) node;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800116 result &= hasFields(
Hyunsun Moon153db182016-08-04 14:06:40 -0700117 vtnNode,
118 HOSTNAME,
119 HOST_MANAGEMENT_IP,
120 DATA_IP,
121 DATA_IFACE,
122 INTEGRATION_BRIDGE_ID);
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800123 result &= isIpPrefix(vtnNode, HOST_MANAGEMENT_IP, MANDATORY);
124 result &= isIpPrefix(vtnNode, DATA_IP, MANDATORY);
Hyunsun Moon153db182016-08-04 14:06:40 -0700125
126 NetworkAddress localMgmt = NetworkAddress.valueOf(get(LOCAL_MANAGEMENT_IP, ""));
127 NetworkAddress hostsMgmt = NetworkAddress.valueOf(getConfig(vtnNode, HOST_MANAGEMENT_IP));
128 if (hostsMgmt.prefix().contains(localMgmt.prefix()) ||
129 localMgmt.prefix().contains(hostsMgmt.prefix())) {
130 final String msg = "Host and local management network IP conflict";
131 throw new IllegalArgumentException(msg);
132 }
133 }
134
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800135 result &= hasFields(
Hyunsun Moon153db182016-08-04 14:06:40 -0700136 (ObjectNode) object.get(SSH),
137 SSH_PORT,
138 SSH_USER,
139 SSH_KEY_FILE);
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800140 result &= isTpPort(
Hyunsun Moon153db182016-08-04 14:06:40 -0700141 (ObjectNode) object.get(SSH),
142 SSH_PORT,
143 MANDATORY);
144
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800145 result &= hasFields(
Hyunsun Moon153db182016-08-04 14:06:40 -0700146 (ObjectNode) object.get(OPENSTACK),
147 ENDPOINT,
148 TENANT,
149 USER,
150 PASSWORD);
151
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800152 result &= hasFields(
Hyunsun Moon153db182016-08-04 14:06:40 -0700153 (ObjectNode) object.get(XOS),
154 ENDPOINT,
155 USER,
156 PASSWORD);
157
158 // check all optional fields are valid
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800159 result &= isTpPort(OVSDB_PORT, OPTIONAL);
Hyunsun Moon153db182016-08-04 14:06:40 -0700160
161 if (object.get(PUBLIC_GATEWAYS) != null && object.get(PUBLIC_GATEWAYS).isArray()) {
162 for (JsonNode node : object.get(PUBLIC_GATEWAYS)) {
163 ObjectNode gateway = (ObjectNode) node;
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800164 result &= isIpAddress(gateway, GATEWAY_IP, MANDATORY);
165 result &= isMacAddress(gateway, GATEWAY_MAC, MANDATORY);
166 }
167 }
168
169 if (object.get(CONTROLLERS) != null) {
170 for (JsonNode jsonNode : object.get(CONTROLLERS)) {
171 result &= isController(jsonNode);
Hyunsun Moon153db182016-08-04 14:06:40 -0700172 }
173 }
174 return result;
175 }
Hyunsun Moon81a13562016-08-04 13:48:08 -0700176
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800177 private boolean isController(JsonNode jsonNode) {
178 String[] ctrl = jsonNode.asText().split(":");
179 final String error = "Malformed controller string " + jsonNode.asText() +
180 ". Controller only takes a list of 'IP:port', 'IP', " +
181 "or just one ':port'.";
182 try {
183 if (ctrl.length == 1) {
184 IpAddress.valueOf(ctrl[INDEX_IP]);
185 return true;
186 }
187 if (ctrl.length == 2 && ctrl[INDEX_IP].isEmpty() &&
188 object.get(CONTROLLERS).size() == 1) {
189 TpPort.tpPort(Integer.valueOf(ctrl[INDEX_PORT]));
190 return true;
191 }
192 if (ctrl.length == 2 && !ctrl[INDEX_IP].isEmpty()) {
193 IpAddress.valueOf(ctrl[INDEX_IP]);
194 TpPort.tpPort(Integer.valueOf(ctrl[INDEX_PORT]));
195 return true;
196 }
197 throw new InvalidFieldException(CONTROLLERS, error);
198 } catch (IllegalArgumentException e) {
199 throw new InvalidFieldException(CONTROLLERS, error);
200 }
201 }
202
Hyunsun Moone9d75992015-09-15 22:39:16 -0700203 /**
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800204 * Returns the set of nodes read from network config.
Hyunsun Moone9d75992015-09-15 22:39:16 -0700205 *
Hyunsun Moon58ddbdc2016-03-07 16:37:17 -0800206 * @return set of CordVtnNodeConfig or empty set
Hyunsun Moone9d75992015-09-15 22:39:16 -0700207 */
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800208 public Set<CordVtnNode> cordVtnNodes() {
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800209 Set<CordVtnNode> nodes = Sets.newHashSet();
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700210 JsonNode sshNode = object.get(SSH);
Hyunsun Moon153db182016-08-04 14:06:40 -0700211 String ovsdbPort = getConfig(object, OVSDB_PORT);
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700212
Hyunsun Moon153db182016-08-04 14:06:40 -0700213 object.get(CORDVTN_NODES).forEach(vtnNode -> {
214 NetworkAddress localMgmt = NetworkAddress.valueOf(get(LOCAL_MANAGEMENT_IP, ""));
215 NetworkAddress hostsMgmt = NetworkAddress.valueOf(getConfig(vtnNode, HOST_MANAGEMENT_IP));
Hyunsun Moon0592c3d2016-06-23 14:47:52 -0700216
Hyunsun Moon81a13562016-08-04 13:48:08 -0700217 SshAccessInfo sshInfo = new SshAccessInfo(
Hyunsun Moon153db182016-08-04 14:06:40 -0700218 hostsMgmt.ip().getIp4Address(),
Hyunsun Moon81a13562016-08-04 13:48:08 -0700219 TpPort.tpPort(Integer.parseInt(getConfig(sshNode, SSH_PORT))),
Hyunsun Moon153db182016-08-04 14:06:40 -0700220 getConfig(sshNode, SSH_USER),
221 getConfig(sshNode, SSH_KEY_FILE));
Hyunsun Moon81a13562016-08-04 13:48:08 -0700222
223 CordVtnNode.Builder nodeBuilder = CordVtnNode.builder()
Hyunsun Moon153db182016-08-04 14:06:40 -0700224 .hostname(getConfig(vtnNode, HOSTNAME))
225 .hostMgmtIp(hostsMgmt)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700226 .localMgmtIp(localMgmt)
Hyunsun Moon153db182016-08-04 14:06:40 -0700227 .dataIp(getConfig(vtnNode, DATA_IP))
Hyunsun Moon81a13562016-08-04 13:48:08 -0700228 .sshInfo(sshInfo)
Hyunsun Moon153db182016-08-04 14:06:40 -0700229 .integrationBridgeId(getConfig(vtnNode, INTEGRATION_BRIDGE_ID))
230 .dataIface(getConfig(vtnNode, DATA_IFACE));
Hyunsun Moon81a13562016-08-04 13:48:08 -0700231
Hyunsun Moon81a13562016-08-04 13:48:08 -0700232 if (!Strings.isNullOrEmpty(ovsdbPort)) {
233 nodeBuilder.ovsdbPort(Integer.parseInt(ovsdbPort));
234 }
235
Hyunsun Moon153db182016-08-04 14:06:40 -0700236 String hostMgmtIface = getConfig(vtnNode, HOST_MANAGEMENT_IFACE);
Hyunsun Moon81a13562016-08-04 13:48:08 -0700237 if (!Strings.isNullOrEmpty(hostMgmtIface)) {
238 nodeBuilder.hostMgmtIface(hostMgmtIface);
239 }
240
241 nodes.add(nodeBuilder.build());
Hyunsun Moon153db182016-08-04 14:06:40 -0700242 });
243
Hyunsun Moon4edb0172015-11-07 22:08:43 -0800244 return nodes;
Hyunsun Moone9d75992015-09-15 22:39:16 -0700245 }
246
247 /**
Hyunsun Moon153db182016-08-04 14:06:40 -0700248 * Gets the specified property as a string.
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800249 *
Hyunsun Moon153db182016-08-04 14:06:40 -0700250 * @param jsonNode node whose fields to get
251 * @param path property to get
252 * @return value as a string
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800253 */
254 private String getConfig(JsonNode jsonNode, String path) {
255 jsonNode = jsonNode.path(path);
Hyunsun Moon153db182016-08-04 14:06:40 -0700256 return jsonNode.asText();
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800257 }
258
259 /**
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800260 * Returns private network gateway MAC address.
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800261 *
Hyunsun Moon153db182016-08-04 14:06:40 -0700262 * @return mac address
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800263 */
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800264 public MacAddress privateGatewayMac() {
265 JsonNode jsonNode = object.get(PRIVATE_GATEWAY_MAC);
Hyunsun Moon153db182016-08-04 14:06:40 -0700266 return MacAddress.valueOf(jsonNode.asText());
Hyunsun Moon3fc17f72016-01-24 21:47:06 -0800267 }
268
269 /**
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800270 * Returns public network gateway IP and MAC address pairs.
271 *
272 * @return map of ip and mac address
273 */
274 public Map<IpAddress, MacAddress> publicGateways() {
275 JsonNode jsonNodes = object.get(PUBLIC_GATEWAYS);
Hyunsun Moon153db182016-08-04 14:06:40 -0700276 Map<IpAddress, MacAddress> publicGateways = Maps.newHashMap();
277
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800278 if (jsonNodes == null) {
Hyunsun Moon153db182016-08-04 14:06:40 -0700279 return publicGateways;
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800280 }
281
Hyunsun Moon153db182016-08-04 14:06:40 -0700282 jsonNodes.forEach(jsonNode -> publicGateways.put(
283 IpAddress.valueOf(jsonNode.path(GATEWAY_IP).asText()),
284 MacAddress.valueOf(jsonNode.path(GATEWAY_MAC).asText())));
Hyunsun Moonb5f92e52016-02-17 15:02:06 -0800285 return publicGateways;
286 }
Hyunsun Moond05b32e2016-03-02 19:27:26 -0800287
Hyunsun Moon4a94c2e2016-10-21 17:37:05 -0700288 /**
289 * Returns XOS API endpoint and credential configuration.
290 *
291 * @return xos api configuration
292 */
293 public XosConfig xosConfig() {
294 JsonNode jsonNode = object.get(XOS);
295 return new XosConfig(getConfig(jsonNode, ENDPOINT),
296 getConfig(jsonNode, USER),
297 getConfig(jsonNode, PASSWORD));
298 }
Hyunsun Moon97b96272016-10-21 17:41:29 -0700299
300 /**
301 * Returns OpenStack API endpoint and credential configuration.
302 *
303 * @return openstack api configuration
304 */
305 public OpenStackConfig openStackConfig() {
306 JsonNode jsonNode = object.get(OPENSTACK);
307 return new OpenStackConfig(jsonNode.path(ENDPOINT).asText(),
308 jsonNode.path(TENANT).asText(),
309 jsonNode.path(USER).asText(),
310 jsonNode.path(PASSWORD).asText());
311 }
Hyunsun Moon3fc0cbc2016-11-22 18:29:12 -0800312
313 /**
314 * Returns controllers for the integration bridge.
315 * It returns the information taken from cluster service with the default OF
316 * port if no controller is specified in the network config.
317 *
318 * @return list of controller information
319 */
320 public List<ControllerInfo> controllers() {
321 List<ControllerInfo> ctrls = Lists.newArrayList();
322 JsonNode ctrlNodes = object.get(CONTROLLERS);
323
324 if (ctrlNodes == null || isCtrlPortOnly()) {
325 ctrls = clusterService.getNodes().stream()
326 .map(ctrl -> new ControllerInfo(
327 ctrl.ip(),
328 ctrlNodes == null ? DEFAULT_OF_PORT : getCtrlPort(),
329 DEFAULT_OF_PROTOCOL))
330 .collect(Collectors.toList());
331 } else {
332 for (JsonNode ctrlNode : ctrlNodes) {
333 String[] ctrl = ctrlNode.asText().split(":");
334 ctrls.add(new ControllerInfo(
335 IpAddress.valueOf(ctrl[INDEX_IP]),
336 ctrl.length == 1 ? DEFAULT_OF_PORT :
337 Integer.parseInt(ctrl[INDEX_PORT]),
338 DEFAULT_OF_PROTOCOL));
339 }
340 }
341 return ImmutableList.copyOf(ctrls);
342 }
343
344 private boolean isCtrlPortOnly() {
345 if (object.get(CONTROLLERS).size() != 1) {
346 return false;
347 }
348 JsonNode jsonNode = object.get(CONTROLLERS).get(0);
349 String[] ctrl = jsonNode.asText().split(":");
350 return ctrl.length == 2 && ctrl[INDEX_IP].isEmpty();
351 }
352
353 private int getCtrlPort() {
354 JsonNode jsonNode = object.get(CONTROLLERS).get(0);
355 String[] ctrl = jsonNode.asText().split(":");
356 return Integer.parseInt(ctrl[INDEX_PORT]);
357 }
Hyunsun Moon61e79ee2016-04-14 19:04:23 -0700358}