blob: 69713377df932d20b442fa6387f4436c3e55ea29 [file] [log] [blame]
Jian Li23c8be22018-02-13 11:34:15 +09001/*
2 * Copyright 2018-present Open Networking Foundation
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.codec;
17
Jian Lie6312162018-03-21 21:41:00 +090018import com.fasterxml.jackson.databind.JsonNode;
19import com.fasterxml.jackson.databind.node.ArrayNode;
Jian Li23c8be22018-02-13 11:34:15 +090020import com.fasterxml.jackson.databind.node.ObjectNode;
21import org.onlab.packet.IpAddress;
22import org.onosproject.codec.CodecContext;
23import org.onosproject.codec.JsonCodec;
24import org.onosproject.net.DeviceId;
Jian Li789fadb2018-07-10 13:59:47 +090025import org.onosproject.net.behaviour.ControllerInfo;
Jian Li00917602019-03-04 10:39:28 +090026import org.onosproject.openstacknode.api.DefaultKeystoneConfig;
Jian Li789fadb2018-07-10 13:59:47 +090027import org.onosproject.openstacknode.api.DefaultOpenstackNode;
Daniel Parkd02d7bd2018-08-23 23:04:31 +090028import org.onosproject.openstacknode.api.DpdkConfig;
Jian Lic704b672018-09-04 18:52:53 +090029import org.onosproject.openstacknode.api.KeystoneConfig;
30import org.onosproject.openstacknode.api.NeutronConfig;
Jian Li23c8be22018-02-13 11:34:15 +090031import org.onosproject.openstacknode.api.NodeState;
Jian Li27841662018-04-14 01:59:47 +090032import org.onosproject.openstacknode.api.OpenstackAuth;
Jian Li23c8be22018-02-13 11:34:15 +090033import org.onosproject.openstacknode.api.OpenstackNode;
Jian Lie6312162018-03-21 21:41:00 +090034import org.onosproject.openstacknode.api.OpenstackPhyInterface;
Daniel Parkdeefa702018-07-17 17:55:51 +090035import org.onosproject.openstacknode.api.OpenstackSshAuth;
Jian Li23c8be22018-02-13 11:34:15 +090036import org.slf4j.Logger;
37
Jian Lie6312162018-03-21 21:41:00 +090038import java.util.ArrayList;
39import java.util.List;
40import java.util.stream.IntStream;
41
Jian Li23c8be22018-02-13 11:34:15 +090042import static com.google.common.base.Preconditions.checkNotNull;
43import static org.onlab.util.Tools.nullIsIllegal;
Jian Li27841662018-04-14 01:59:47 +090044import static org.onosproject.openstacknode.api.Constants.CONTROLLER;
Jian Li23c8be22018-02-13 11:34:15 +090045import static org.onosproject.openstacknode.api.Constants.DATA_IP;
46import static org.onosproject.openstacknode.api.Constants.GATEWAY;
47import static org.onosproject.openstacknode.api.Constants.HOST_NAME;
48import static org.onosproject.openstacknode.api.Constants.MANAGEMENT_IP;
49import static org.onosproject.openstacknode.api.Constants.UPLINK_PORT;
50import static org.onosproject.openstacknode.api.Constants.VLAN_INTF_NAME;
51import static org.slf4j.LoggerFactory.getLogger;
52
53/**
54 * Openstack node codec used for serializing and de-serializing JSON string.
55 */
56public final class OpenstackNodeCodec extends JsonCodec<OpenstackNode> {
57
58 private final Logger log = getLogger(getClass());
59
60 private static final String TYPE = "type";
61 private static final String INTEGRATION_BRIDGE = "integrationBridge";
Jian Li5ca0be82018-02-27 13:08:04 +090062 private static final String STATE = "state";
Jian Lie6312162018-03-21 21:41:00 +090063 private static final String PHYSICAL_INTERFACES = "phyIntfs";
Jian Li789fadb2018-07-10 13:59:47 +090064 private static final String CONTROLLERS = "controllers";
Jian Lic704b672018-09-04 18:52:53 +090065 private static final String KEYSTONE_CONFIG = "keystoneConfig";
66 private static final String ENDPOINT = "endpoint";
Jian Li27841662018-04-14 01:59:47 +090067 private static final String AUTHENTICATION = "authentication";
Jian Lic704b672018-09-04 18:52:53 +090068 private static final String NEUTRON_CONFIG = "neutronConfig";
Daniel Parkdeefa702018-07-17 17:55:51 +090069 private static final String SSH_AUTH = "sshAuth";
Daniel Parkd02d7bd2018-08-23 23:04:31 +090070 private static final String DPDK_CONFIG = "dpdkConfig";
Jian Li23c8be22018-02-13 11:34:15 +090071
72 private static final String MISSING_MESSAGE = " is required in OpenstackNode";
73
74 @Override
75 public ObjectNode encode(OpenstackNode node, CodecContext context) {
76 checkNotNull(node, "Openstack node cannot be null");
77
78 ObjectNode result = context.mapper().createObjectNode()
79 .put(HOST_NAME, node.hostname())
80 .put(TYPE, node.type().name())
Jian Li92d42fc2018-05-25 16:23:49 +090081 .put(STATE, node.state().name())
Daniel Parkd02d7bd2018-08-23 23:04:31 +090082 .put(MANAGEMENT_IP, node.managementIp().toString());
Jian Li23c8be22018-02-13 11:34:15 +090083
84 OpenstackNode.NodeType type = node.type();
85
Jian Li00917602019-03-04 10:39:28 +090086 // serialize uplink port only for gateway node
Jian Li23c8be22018-02-13 11:34:15 +090087 if (type == OpenstackNode.NodeType.GATEWAY) {
88 result.put(UPLINK_PORT, node.uplinkPort());
89 }
90
Jian Li00917602019-03-04 10:39:28 +090091 // serialize keystone config for controller node
Jian Lie3141542018-08-13 18:05:43 +090092 if (type == OpenstackNode.NodeType.CONTROLLER) {
Jian Lic704b672018-09-04 18:52:53 +090093
94 ObjectNode keystoneConfigJson = context.codec(KeystoneConfig.class)
95 .encode(node.keystoneConfig(), context);
96
97 result.set(KEYSTONE_CONFIG, keystoneConfigJson);
Jian Li00917602019-03-04 10:39:28 +090098
99 // serialize neutron config for controller node
100 if (node.neutronConfig() != null) {
101 ObjectNode neutronConfigJson = context.codec(NeutronConfig.class)
102 .encode(node.neutronConfig(), context);
103
104 result.set(NEUTRON_CONFIG, neutronConfigJson);
105 }
Jian Lic704b672018-09-04 18:52:53 +0900106 }
107
Jian Li00917602019-03-04 10:39:28 +0900108 // serialize integration bridge config
Jian Lie3141542018-08-13 18:05:43 +0900109 if (node.intgBridge() != null) {
110 result.put(INTEGRATION_BRIDGE, node.intgBridge().toString());
111 }
112
Jian Li00917602019-03-04 10:39:28 +0900113 // serialize VLAN interface, it is valid only if any VLAN interface presents
Jian Li23c8be22018-02-13 11:34:15 +0900114 if (node.vlanIntf() != null) {
115 result.put(VLAN_INTF_NAME, node.vlanIntf());
116 }
117
Jian Li00917602019-03-04 10:39:28 +0900118 // serialize data IP only if it presents
Jian Li23c8be22018-02-13 11:34:15 +0900119 if (node.dataIp() != null) {
120 result.put(DATA_IP, node.dataIp().toString());
121 }
122
Jian Li00917602019-03-04 10:39:28 +0900123 // serialize physical interfaces, it is valid only if any of physical interface presents
124 if (node.phyIntfs() != null && !node.phyIntfs().isEmpty()) {
125 ArrayNode phyIntfs = context.mapper().createArrayNode();
126 node.phyIntfs().forEach(phyIntf -> {
127 ObjectNode phyIntfJson =
128 context.codec(OpenstackPhyInterface.class).encode(phyIntf, context);
129 phyIntfs.add(phyIntfJson);
130 });
131 result.set(PHYSICAL_INTERFACES, phyIntfs);
132 }
Jian Lie6312162018-03-21 21:41:00 +0900133
Jian Li00917602019-03-04 10:39:28 +0900134 // serialize controllers, it is valid only if any of controller presents
135 if (node.controllers() != null && !node.controllers().isEmpty()) {
136 ArrayNode controllers = context.mapper().createArrayNode();
137 node.controllers().forEach(controller -> {
138 ObjectNode controllerJson =
139 context.codec(ControllerInfo.class).encode(controller, context);
140 controllers.add(controllerJson);
141 });
142 result.set(CONTROLLERS, controllers);
143 }
Jian Li789fadb2018-07-10 13:59:47 +0900144
Jian Li00917602019-03-04 10:39:28 +0900145 // serialize SSH authentication info, it is valid only if auth info presents
Daniel Parkdeefa702018-07-17 17:55:51 +0900146 if (node.sshAuthInfo() != null) {
147 ObjectNode sshAuthJson = context.codec(OpenstackSshAuth.class)
148 .encode(node.sshAuthInfo(), context);
149 result.set(SSH_AUTH, sshAuthJson);
Jian Li27841662018-04-14 01:59:47 +0900150 }
151
Jian Li00917602019-03-04 10:39:28 +0900152 // serialize DPDK config, it is valid only if dpdk config presents
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900153 if (node.dpdkConfig() != null) {
154 ObjectNode dpdkConfigJson = context.codec(DpdkConfig.class)
155 .encode(node.dpdkConfig(), context);
156 result.set(DPDK_CONFIG, dpdkConfigJson);
Daniel Park7e8c4d82018-08-13 23:47:49 +0900157 }
158
Jian Li23c8be22018-02-13 11:34:15 +0900159 return result;
160 }
161
162 @Override
163 public OpenstackNode decode(ObjectNode json, CodecContext context) {
164 if (json == null || !json.isObject()) {
165 return null;
166 }
167
168 String hostname = nullIsIllegal(json.get(HOST_NAME).asText(),
169 HOST_NAME + MISSING_MESSAGE);
170 String type = nullIsIllegal(json.get(TYPE).asText(),
171 TYPE + MISSING_MESSAGE);
Jian Li92d42fc2018-05-25 16:23:49 +0900172 String mIp = nullIsIllegal(json.get(MANAGEMENT_IP).asText(),
173 MANAGEMENT_IP + MISSING_MESSAGE);
Jian Li23c8be22018-02-13 11:34:15 +0900174
175 DefaultOpenstackNode.Builder nodeBuilder = DefaultOpenstackNode.builder()
176 .hostname(hostname)
177 .type(OpenstackNode.NodeType.valueOf(type))
Jian Li92d42fc2018-05-25 16:23:49 +0900178 .state(NodeState.INIT)
179 .managementIp(IpAddress.valueOf(mIp));
Jian Li23c8be22018-02-13 11:34:15 +0900180
181 if (type.equals(GATEWAY)) {
182 nodeBuilder.uplinkPort(nullIsIllegal(json.get(UPLINK_PORT).asText(),
183 UPLINK_PORT + MISSING_MESSAGE));
184 }
Jian Lie3141542018-08-13 18:05:43 +0900185 if (type.equals(CONTROLLER)) {
Jian Lic704b672018-09-04 18:52:53 +0900186
187 JsonNode keystoneConfigJson = json.get(KEYSTONE_CONFIG);
188
189 KeystoneConfig keystoneConfig;
190 if (keystoneConfigJson != null) {
191 final JsonCodec<KeystoneConfig> keystoneConfigCodec =
192 context.codec(KeystoneConfig.class);
193 keystoneConfig = keystoneConfigCodec.decode((ObjectNode)
194 keystoneConfigJson.deepCopy(), context);
195 } else {
196 JsonNode authJson = json.get(AUTHENTICATION);
197 final JsonCodec<OpenstackAuth> authCodec = context.codec(OpenstackAuth.class);
198 OpenstackAuth auth = authCodec.decode((ObjectNode) authJson.deepCopy(), context);
199
200 String endpoint = nullIsIllegal(json.get(ENDPOINT).asText(),
201 ENDPOINT + MISSING_MESSAGE);
202
203 keystoneConfig = DefaultKeystoneConfig.builder()
204 .authentication(auth)
205 .endpoint(endpoint)
206 .build();
207 }
208
209 nodeBuilder.keystoneConfig(keystoneConfig);
Jian Li27841662018-04-14 01:59:47 +0900210 }
Jian Li23c8be22018-02-13 11:34:15 +0900211 if (json.get(VLAN_INTF_NAME) != null) {
212 nodeBuilder.vlanIntf(json.get(VLAN_INTF_NAME).asText());
213 }
214 if (json.get(DATA_IP) != null) {
215 nodeBuilder.dataIp(IpAddress.valueOf(json.get(DATA_IP).asText()));
216 }
217
Jian Lie3141542018-08-13 18:05:43 +0900218 JsonNode intBridgeJson = json.get(INTEGRATION_BRIDGE);
219 if (intBridgeJson != null) {
220 nodeBuilder.intgBridge(DeviceId.deviceId(intBridgeJson.asText()));
221 }
222
Jian Lie6312162018-03-21 21:41:00 +0900223 // parse physical interfaces
224 List<OpenstackPhyInterface> phyIntfs = new ArrayList<>();
225 JsonNode phyIntfsJson = json.get(PHYSICAL_INTERFACES);
226 if (phyIntfsJson != null) {
Jian Li27841662018-04-14 01:59:47 +0900227
228 final JsonCodec<OpenstackPhyInterface>
229 phyIntfCodec = context.codec(OpenstackPhyInterface.class);
230
Jian Lie6312162018-03-21 21:41:00 +0900231 IntStream.range(0, phyIntfsJson.size()).forEach(i -> {
232 ObjectNode intfJson = get(phyIntfsJson, i);
233 phyIntfs.add(phyIntfCodec.decode(intfJson, context));
234 });
235 }
236 nodeBuilder.phyIntfs(phyIntfs);
237
Jian Li789fadb2018-07-10 13:59:47 +0900238 // parse customized controllers
239 List<ControllerInfo> controllers = new ArrayList<>();
240 JsonNode controllersJson = json.get(CONTROLLERS);
241 if (controllersJson != null) {
242
243 final JsonCodec<ControllerInfo>
244 controllerCodec = context.codec(ControllerInfo.class);
245
246 IntStream.range(0, controllersJson.size()).forEach(i -> {
247 ObjectNode controllerJson = get(controllersJson, i);
248 controllers.add(controllerCodec.decode(controllerJson, context));
249 });
250 }
251 nodeBuilder.controllers(controllers);
252
Jian Lic704b672018-09-04 18:52:53 +0900253 // parse neutron config
254 JsonNode neutronConfigJson = json.get(NEUTRON_CONFIG);
255 if (neutronConfigJson != null) {
256 final JsonCodec<NeutronConfig> neutronConfigJsonCodec =
257 context.codec(NeutronConfig.class);
Jian Li27841662018-04-14 01:59:47 +0900258
Jian Lic704b672018-09-04 18:52:53 +0900259 NeutronConfig neutronConfig =
260 neutronConfigJsonCodec.decode((ObjectNode)
261 neutronConfigJson.deepCopy(), context);
262 nodeBuilder.neutronConfig(neutronConfig);
Jian Li27841662018-04-14 01:59:47 +0900263 }
264
Daniel Parkdeefa702018-07-17 17:55:51 +0900265 // parse ssh authentication
266 JsonNode sshAuthJson = json.get(SSH_AUTH);
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900267 if (sshAuthJson != null) {
Jian Lic704b672018-09-04 18:52:53 +0900268 final JsonCodec<OpenstackSshAuth> sshAuthJsonCodec =
269 context.codec(OpenstackSshAuth.class);
Daniel Parkdeefa702018-07-17 17:55:51 +0900270
Jian Lic704b672018-09-04 18:52:53 +0900271 OpenstackSshAuth sshAuth = sshAuthJsonCodec.decode((ObjectNode)
272 sshAuthJson.deepCopy(), context);
Daniel Parkdeefa702018-07-17 17:55:51 +0900273 nodeBuilder.sshAuthInfo(sshAuth);
274 }
275
Jian Li00917602019-03-04 10:39:28 +0900276 // parse DPDK configuration
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900277 JsonNode dpdkConfigJson = json.get(DPDK_CONFIG);
278 if (dpdkConfigJson != null) {
Jian Lic704b672018-09-04 18:52:53 +0900279 final JsonCodec<DpdkConfig> dpdkConfigJsonCodec =
280 context.codec(DpdkConfig.class);
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900281
Jian Lic704b672018-09-04 18:52:53 +0900282 DpdkConfig dpdkConfig = dpdkConfigJsonCodec.decode((ObjectNode)
283 dpdkConfigJson.deepCopy(), context);
Daniel Parkd02d7bd2018-08-23 23:04:31 +0900284 nodeBuilder.dpdkConfig(dpdkConfig);
285 }
286
Jian Li23c8be22018-02-13 11:34:15 +0900287 log.trace("node is {}", nodeBuilder.build().toString());
288
289 return nodeBuilder.build();
290 }
291}