blob: 21a4d734b9797f4c90e7837163a95e91b817a1f1 [file] [log] [blame]
sanghoshinf25d2e02015-11-11 23:07:17 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
sanghoshinf25d2e02015-11-11 23:07:17 +09003 *
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 Moon0dba61f2016-03-03 14:05:21 -080016package org.onosproject.openstackinterface.impl;
sanghoshinf25d2e02015-11-11 23:07:17 +090017
18import com.fasterxml.jackson.databind.ObjectMapper;
19import com.fasterxml.jackson.databind.node.ArrayNode;
20import com.fasterxml.jackson.databind.node.ObjectNode;
Hyunsun Moonef6bad22016-07-19 16:25:43 -070021import com.google.common.base.Strings;
sangho93447f12016-02-24 00:33:22 +090022import com.google.common.collect.ImmutableSet;
sanghoshinf25d2e02015-11-11 23:07:17 +090023import com.google.common.collect.Lists;
Daniel Parka26f2652016-09-08 16:48:26 +090024import org.apache.commons.io.IOUtils;
sangho0c2a3da2016-02-16 13:39:07 +090025import 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.apache.felix.scr.annotations.Service;
Hyunsun Moonef6bad22016-07-19 16:25:43 -070031import org.glassfish.jersey.client.ClientProperties;
Daniel Parka26f2652016-09-08 16:48:26 +090032import org.onlab.packet.Ip4Address;
sangho0c2a3da2016-02-16 13:39:07 +090033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.net.Port;
sangho93447f12016-02-24 00:33:22 +090036import org.onosproject.net.config.ConfigFactory;
37import org.onosproject.net.config.NetworkConfigEvent;
38import org.onosproject.net.config.NetworkConfigListener;
39import org.onosproject.net.config.NetworkConfigRegistry;
sanghod177f8f2016-06-29 21:52:23 +090040import org.onosproject.openstackinterface.OpenstackFloatingIP;
Hyunsun Moon0dba61f2016-03-03 14:05:21 -080041import org.onosproject.openstackinterface.OpenstackInterfaceService;
42import org.onosproject.openstackinterface.OpenstackNetwork;
sangho48907542016-03-28 16:07:07 +090043import org.onosproject.openstackinterface.OpenstackInterfaceConfig;
Hyunsun Moon0dba61f2016-03-03 14:05:21 -080044import org.onosproject.openstackinterface.OpenstackPort;
45import org.onosproject.openstackinterface.OpenstackRouter;
46import org.onosproject.openstackinterface.OpenstackSecurityGroup;
47import org.onosproject.openstackinterface.OpenstackSubnet;
sanghod177f8f2016-06-29 21:52:23 +090048import org.onosproject.openstackinterface.web.OpenstackFloatingIpCodec;
sangho93447f12016-02-24 00:33:22 +090049import org.onosproject.openstackinterface.web.OpenstackNetworkCodec;
50import org.onosproject.openstackinterface.web.OpenstackPortCodec;
51import org.onosproject.openstackinterface.web.OpenstackRouterCodec;
52import org.onosproject.openstackinterface.web.OpenstackSecurityGroupCodec;
53import org.onosproject.openstackinterface.web.OpenstackSubnetCodec;
sanghoshinf25d2e02015-11-11 23:07:17 +090054import org.slf4j.Logger;
Jian Li9d616492016-03-09 10:52:49 -080055
56import javax.ws.rs.client.Client;
57import javax.ws.rs.client.ClientBuilder;
58import javax.ws.rs.client.Entity;
59import javax.ws.rs.client.Invocation;
60import javax.ws.rs.client.WebTarget;
sanghoshinf25d2e02015-11-11 23:07:17 +090061import javax.ws.rs.core.MediaType;
Daniel Parka26f2652016-09-08 16:48:26 +090062import javax.ws.rs.core.Response;
63import java.io.ByteArrayInputStream;
sanghoshinf25d2e02015-11-11 23:07:17 +090064import java.io.IOException;
Daniel Parka26f2652016-09-08 16:48:26 +090065import java.io.InputStream;
66import java.nio.charset.StandardCharsets;
sangho9f189ec2016-04-05 14:22:17 +090067import java.text.ParseException;
68import java.text.SimpleDateFormat;
69import java.util.Calendar;
sanghoshinf25d2e02015-11-11 23:07:17 +090070import java.util.Collection;
Hyunsun Moonf7895202016-01-12 12:21:48 -080071import java.util.Collections;
sangho9f189ec2016-04-05 14:22:17 +090072import java.util.Date;
sanghoshinf25d2e02015-11-11 23:07:17 +090073import java.util.List;
Daniel Parka26f2652016-09-08 16:48:26 +090074import java.util.Optional;
sangho93447f12016-02-24 00:33:22 +090075import java.util.Set;
76import java.util.concurrent.ExecutorService;
77import java.util.concurrent.Executors;
sangho0c2a3da2016-02-16 13:39:07 +090078import java.util.stream.Collectors;
sanghoshinf25d2e02015-11-11 23:07:17 +090079
80import static com.google.common.base.Preconditions.checkNotNull;
81import static com.google.common.net.MediaType.JSON_UTF_8;
sangho93447f12016-02-24 00:33:22 +090082import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moonef6bad22016-07-19 16:25:43 -070083import static org.onosproject.net.AnnotationKeys.PORT_NAME;
sangho93447f12016-02-24 00:33:22 +090084import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
sanghoshinf25d2e02015-11-11 23:07:17 +090085import static org.slf4j.LoggerFactory.getLogger;
86
87/**
88 * Handles REST Calls to Openstack Neutron.
89 *
90 */
sangho0c2a3da2016-02-16 13:39:07 +090091@Service
92@Component(immediate = true)
sangho93447f12016-02-24 00:33:22 +090093public class OpenstackInterfaceManager implements OpenstackInterfaceService {
sanghoshinf25d2e02015-11-11 23:07:17 +090094
sangho5db8e052016-01-29 16:08:23 +090095 private static final String URI_NETWORKS = "networks";
96 private static final String URI_PORTS = "ports";
97 private static final String URI_SUBNETS = "subnets";
98 private static final String URI_SECURITY_GROUPS = "security-groups";
sanghod177f8f2016-06-29 21:52:23 +090099 private static final String URI_FLOATINGIPS = "floatingips";
sangho5db8e052016-01-29 16:08:23 +0900100 private static final String URI_TOKENS = "tokens";
Daniel Parka26f2652016-09-08 16:48:26 +0900101 private static final String FLOATINGIP = "floatingip";
102 private static final String PORT_ID = "port_id";
103 private static final String FIXED_IP_ADDRESS = "fixed_ip_address";
sangho5db8e052016-01-29 16:08:23 +0900104
Daniel Park3a06c522016-01-28 20:51:12 +0900105 private static final String PATH_ROUTERS = "routers";
sangho5db8e052016-01-29 16:08:23 +0900106 private static final String PATH_NETWORKS = "networks";
107 private static final String PATH_PORTS = "ports";
108 private static final String PATH_SUBNETS = "subnets";
sanghod177f8f2016-06-29 21:52:23 +0900109 private static final String PATH_FLOATINGIPS = "floatingips";
sangho5db8e052016-01-29 16:08:23 +0900110 private static final String PATH_ACCESS = "access";
111 private static final String PATH_TOKEN = "token";
112 private static final String PATH_ID = "id";
sangho9f189ec2016-04-05 14:22:17 +0900113 private static final String PATH_EXPIRES = "expires";
sangho5db8e052016-01-29 16:08:23 +0900114
115 private static final String HEADER_AUTH_TOKEN = "X-Auth-Token";
sangho9f189ec2016-04-05 14:22:17 +0900116 private static final String TOKEN_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700117 private static final int DEFAULT_TIMEOUT_MS = 2000;
sangho5db8e052016-01-29 16:08:23 +0900118
sanghoshinf25d2e02015-11-11 23:07:17 +0900119 private final Logger log = getLogger(getClass());
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700120 private final Client client = ClientBuilder.newClient();
121
sanghoshinf25d2e02015-11-11 23:07:17 +0900122 private String neutronUrl;
123 private String keystoneUrl;
124 private String tokenId;
sangho9f189ec2016-04-05 14:22:17 +0900125 private String tokenExpires;
sanghoshinf25d2e02015-11-11 23:07:17 +0900126 private String userName;
127 private String pass;
128
sangho0c2a3da2016-02-16 13:39:07 +0900129 private ApplicationId appId;
130
131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 protected CoreService coreService;
133
134 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sangho93447f12016-02-24 00:33:22 +0900135 protected NetworkConfigRegistry cfgService;
sangho0c2a3da2016-02-16 13:39:07 +0900136
sangho93447f12016-02-24 00:33:22 +0900137 private InternalConfigListener internalConfigListener = new InternalConfigListener();
138 private ExecutorService networkEventExcutorService =
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700139 Executors.newSingleThreadExecutor(groupedThreads("onos/openstackinterface", "config-event", log));
sangho93447f12016-02-24 00:33:22 +0900140
141 private final Set<ConfigFactory> factories = ImmutableSet.of(
sangho48907542016-03-28 16:07:07 +0900142 new ConfigFactory<ApplicationId, OpenstackInterfaceConfig>(APP_SUBJECT_FACTORY,
143 OpenstackInterfaceConfig.class,
sangho93447f12016-02-24 00:33:22 +0900144 "openstackinterface") {
145 @Override
sangho48907542016-03-28 16:07:07 +0900146 public OpenstackInterfaceConfig createConfig() {
147 return new OpenstackInterfaceConfig();
sangho93447f12016-02-24 00:33:22 +0900148 }
149 }
150 );
151
sangho0c2a3da2016-02-16 13:39:07 +0900152 @Activate
153 protected void activate() {
154 appId = coreService
sangho93447f12016-02-24 00:33:22 +0900155 .registerApplication("org.onosproject.openstackinterface");
156
157 factories.forEach(cfgService::registerConfigFactory);
158 cfgService.addListener(internalConfigListener);
sangho0c2a3da2016-02-16 13:39:07 +0900159
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700160 client.property(ClientProperties.CONNECT_TIMEOUT, DEFAULT_TIMEOUT_MS);
161 client.property(ClientProperties.READ_TIMEOUT, DEFAULT_TIMEOUT_MS);
162
163 configureNetwork();
sangho0c2a3da2016-02-16 13:39:07 +0900164 log.info("started");
165 }
166
167 @Deactivate
168 protected void deactivate() {
sangho93447f12016-02-24 00:33:22 +0900169 cfgService.removeListener(internalConfigListener);
170 factories.forEach(cfgService::unregisterConfigFactory);
sangho0c2a3da2016-02-16 13:39:07 +0900171 log.info("stopped");
sanghoshinf25d2e02015-11-11 23:07:17 +0900172 }
173
174 /**
175 * Returns network information stored in Neutron.
176 *
177 * @return List of OpenstackNetwork
178 */
179 public Collection<OpenstackNetwork> getNetworks() {
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700180 Invocation.Builder builder = getClientBuilder(neutronUrl, URI_NETWORKS);
181 if (builder == null) {
182 log.warn("Failed to get networks");
183 return Collections.EMPTY_LIST;
184 }
sanghoshinf25d2e02015-11-11 23:07:17 +0900185
sanghoshinf25d2e02015-11-11 23:07:17 +0900186 String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
sangho5db8e052016-01-29 16:08:23 +0900187 header(HEADER_AUTH_TOKEN, getToken()).get(String.class);
Hyunsun Moonf7895202016-01-12 12:21:48 -0800188 log.debug("networks response:" + response);
189
sanghoshinf25d2e02015-11-11 23:07:17 +0900190 ObjectMapper mapper = new ObjectMapper();
191 List<OpenstackNetwork> openstackNetworks = Lists.newArrayList();
192 try {
193 ObjectNode node = (ObjectNode) mapper.readTree(response);
sangho5db8e052016-01-29 16:08:23 +0900194 ArrayNode networkList = (ArrayNode) node.path(PATH_NETWORKS);
sanghoshinf25d2e02015-11-11 23:07:17 +0900195 OpenstackNetworkCodec networkCodec = new OpenstackNetworkCodec();
196 networkList.forEach(n -> openstackNetworks.add(networkCodec.decode((ObjectNode) n, null)));
197 } catch (IOException e) {
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800198 log.warn("getNetworks()", e);
sanghoshinf25d2e02015-11-11 23:07:17 +0900199 }
200
Hyunsun Moonf7895202016-01-12 12:21:48 -0800201 openstackNetworks.removeAll(Collections.singleton(null));
sanghoshinf25d2e02015-11-11 23:07:17 +0900202 openstackNetworks.forEach(n -> log.debug("network ID: {}", n.id()));
203
204 return openstackNetworks;
205 }
206
207 /**
208 * Returns port information stored in Neutron.
209 *
210 * @return List of OpenstackPort
211 */
212 public Collection<OpenstackPort> getPorts() {
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700213 Invocation.Builder builder = getClientBuilder(neutronUrl, URI_PORTS);
214 if (builder == null) {
215 log.warn("Failed to get ports");
216 return Collections.EMPTY_LIST;
217 }
sanghoshinf25d2e02015-11-11 23:07:17 +0900218
sanghoshinf25d2e02015-11-11 23:07:17 +0900219 String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
sangho5db8e052016-01-29 16:08:23 +0900220 header(HEADER_AUTH_TOKEN, getToken()).get(String.class);
sanghoshinf25d2e02015-11-11 23:07:17 +0900221
222 ObjectMapper mapper = new ObjectMapper();
223 List<OpenstackPort> openstackPorts = Lists.newArrayList();
224 try {
225 ObjectNode node = (ObjectNode) mapper.readTree(response);
sangho5db8e052016-01-29 16:08:23 +0900226 ArrayNode portList = (ArrayNode) node.path(PATH_PORTS);
sanghoshinf25d2e02015-11-11 23:07:17 +0900227 OpenstackPortCodec portCodec = new OpenstackPortCodec();
228 portList.forEach(p -> openstackPorts.add(portCodec.decode((ObjectNode) p, null)));
229 } catch (IOException e) {
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800230 log.warn("getPorts()", e);
sanghoshinf25d2e02015-11-11 23:07:17 +0900231 }
232
233 log.debug("port response:" + response);
234 openstackPorts.forEach(n -> log.debug("port ID: {}", n.id()));
235
236 return openstackPorts;
237 }
238
Daniel Park3a06c522016-01-28 20:51:12 +0900239 public Collection<OpenstackRouter> getRouters() {
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700240 Invocation.Builder builder = getClientBuilder(neutronUrl, PATH_ROUTERS);
241 if (builder == null) {
242 log.warn("Failed to get routers");
243 return Collections.EMPTY_LIST;
244 }
245
Daniel Park3a06c522016-01-28 20:51:12 +0900246 String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
247 header(HEADER_AUTH_TOKEN, getToken()).get(String.class);
248
249 ObjectMapper mapper = new ObjectMapper();
250 List<OpenstackRouter> openstackRouters = Lists.newArrayList();
251
252 try {
253 ObjectNode node = (ObjectNode) mapper.readTree(response);
254 ArrayNode routerList = (ArrayNode) node.path(PATH_ROUTERS);
255 OpenstackRouterCodec openstackRouterCodec = new OpenstackRouterCodec();
256 routerList.forEach(r -> openstackRouters
257 .add(openstackRouterCodec.decode((ObjectNode) r, null)));
258 } catch (IOException e) {
259 log.warn("getRouters()", e);
260 }
261
262 log.debug("router response:" + response);
263 openstackRouters.forEach(r -> log.debug("router ID: {}", r.id()));
264
265 return openstackRouters;
266 }
267
sanghoshinf25d2e02015-11-11 23:07:17 +0900268 /**
269 * Returns Subnet information in Neutron.
270 *
271 * @return List of OpenstackSubnet
272 */
273 public Collection<OpenstackSubnet> getSubnets() {
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700274 Invocation.Builder builder = getClientBuilder(neutronUrl, URI_SUBNETS);
275 if (builder == null) {
276 log.warn("Failed to get subnets");
277 return Collections.EMPTY_LIST;
278 }
279
sanghoshinf25d2e02015-11-11 23:07:17 +0900280 String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
sangho5db8e052016-01-29 16:08:23 +0900281 header(HEADER_AUTH_TOKEN, getToken()).get(String.class);
sanghoshinf25d2e02015-11-11 23:07:17 +0900282
283 ObjectMapper mapper = new ObjectMapper();
284 List<OpenstackSubnet> subnets = Lists.newArrayList();
285 try {
286 ObjectNode node = (ObjectNode) mapper.readTree(response);
sangho5db8e052016-01-29 16:08:23 +0900287 ArrayNode subnetList = (ArrayNode) node.path(PATH_SUBNETS);
sanghoshinf25d2e02015-11-11 23:07:17 +0900288 OpenstackSubnetCodec subnetCodec = new OpenstackSubnetCodec();
289 subnetList.forEach(s -> subnets.add(subnetCodec.decode((ObjectNode) s, null)));
290 } catch (IOException e) {
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800291 log.warn("getSubnets()", e);
sanghoshinf25d2e02015-11-11 23:07:17 +0900292 }
293
294 log.debug("subnets response:" + response);
295 subnets.forEach(s -> log.debug("subnet ID: {}", s.id()));
296
297 return subnets;
298 }
299
sangho5db8e052016-01-29 16:08:23 +0900300 /**
301 * Extracts OpenstackSecurityGroup information for the ID.
302 *
303 * @param id Security Group ID
304 * @return OpenstackSecurityGroup object or null if fails
305 */
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700306 @Override
sanghod177f8f2016-06-29 21:52:23 +0900307 public OpenstackSecurityGroup securityGroup(String id) {
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700308 Invocation.Builder builder = getClientBuilder(neutronUrl, URI_SECURITY_GROUPS + "/" + id);
309 if (builder == null) {
310 log.warn("Failed to get security group {}", id);
311 return null;
312 }
313
sangho5db8e052016-01-29 16:08:23 +0900314 String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
315 header(HEADER_AUTH_TOKEN, getToken()).get(String.class);
316
317 ObjectMapper mapper = new ObjectMapper();
318 OpenstackSecurityGroup securityGroup = null;
319 try {
320 ObjectNode node = (ObjectNode) mapper.readTree(response);
321 OpenstackSecurityGroupCodec sgCodec = new OpenstackSecurityGroupCodec();
322 securityGroup = sgCodec.decode(node, null);
323 } catch (IOException e) {
sanghod177f8f2016-06-29 21:52:23 +0900324 log.warn("securityGroup()", e);
sangho5db8e052016-01-29 16:08:23 +0900325 }
326
327 return securityGroup;
328 }
329
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700330 private Invocation.Builder getClientBuilder(String baseUrl, String path) {
331 if (Strings.isNullOrEmpty(baseUrl)) {
332 log.warn("Keystone or Neutron URL is not set");
333 return null;
334 }
335
336 WebTarget wt = client.target(baseUrl + path);
Jian Li9d616492016-03-09 10:52:49 -0800337 return wt.request(JSON_UTF_8.toString());
sanghoshinf25d2e02015-11-11 23:07:17 +0900338 }
339
340 private String getToken() {
sangho9f189ec2016-04-05 14:22:17 +0900341 if (!isTokenValid()) {
sanghoshinf25d2e02015-11-11 23:07:17 +0900342 String request = "{\"auth\": {\"tenantName\": \"admin\", " +
343 "\"passwordCredentials\": {\"username\": \"" +
344 userName + "\",\"password\": \"" + pass + "\"}}}";
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700345 Invocation.Builder builder = getClientBuilder(keystoneUrl, URI_TOKENS);
346 if (builder == null) {
347 log.warn("Failed to get token");
348 return null;
349 }
sanghoshinf25d2e02015-11-11 23:07:17 +0900350
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700351 String response = builder.accept(MediaType.APPLICATION_JSON).post(Entity.json(request), String.class);
sanghoshinf25d2e02015-11-11 23:07:17 +0900352 ObjectMapper mapper = new ObjectMapper();
353 try {
354 ObjectNode node = (ObjectNode) mapper.readTree(response);
sangho5db8e052016-01-29 16:08:23 +0900355 tokenId = node.path(PATH_ACCESS).path(PATH_TOKEN).path(PATH_ID).asText();
sangho9f189ec2016-04-05 14:22:17 +0900356 tokenExpires = node.path(PATH_ACCESS).path(PATH_TOKEN).path(PATH_EXPIRES).asText();
sanghoshinf25d2e02015-11-11 23:07:17 +0900357 } catch (IOException e) {
Ray Milkey4fd3ceb2015-12-10 14:43:08 -0800358 log.warn("getToken()", e);
sanghoshinf25d2e02015-11-11 23:07:17 +0900359 }
360 log.debug("token response:" + response);
361 }
362
363 return tokenId;
364 }
365
sangho9f189ec2016-04-05 14:22:17 +0900366 private boolean isTokenValid() {
367
368 if (tokenExpires == null || tokenId == null || tokenExpires.isEmpty()) {
369 return false;
370 }
371
372 try {
373 SimpleDateFormat dateFormat = new SimpleDateFormat(TOKEN_DATE_FORMAT);
374 Date exireDate = dateFormat.parse(tokenExpires);
375
376 Calendar today = Calendar.getInstance();
377 if (exireDate.after(today.getTime())) {
378 return true;
379 }
380 } catch (ParseException e) {
381 log.error("Token parse exception error : {}", e.getMessage());
382 return false;
383 }
384
385 log.debug("token is Invalid");
386 return false;
sanghoshinf25d2e02015-11-11 23:07:17 +0900387 }
388
sangho0c2a3da2016-02-16 13:39:07 +0900389 @Override
390 public Collection<OpenstackPort> ports(String networkId) {
391 return getPorts().stream()
392 .filter(port -> port.networkId().equals(networkId))
393 .collect(Collectors.toList());
394 }
395
396 @Override
397 public Collection<OpenstackPort> ports() {
398 return getPorts();
399 }
400
401 @Override
402 public OpenstackPort port(Port port) {
403 String uuid = port.annotations().value(PORT_NAME).substring(3);
404 return getPorts().stream()
405 .filter(p -> p.id().startsWith(uuid))
406 .findAny().orElse(null);
407 }
408
409 @Override
410 public OpenstackPort port(String portId) {
411 return getPorts().stream()
412 .filter(p -> p.id().equals(portId))
413 .findAny().orElse(null);
414 }
415
416 @Override
417 public OpenstackNetwork network(String networkId) {
Hyunsun Moonb0f09be2016-02-23 04:21:42 -0800418 Collection<OpenstackSubnet> subnets = getSubnets().stream()
419 .filter(s -> s.networkId().equals(networkId))
420 .collect(Collectors.toList());
421
422 OpenstackNetwork openstackNetwork = getNetworks().stream()
sangho0c2a3da2016-02-16 13:39:07 +0900423 .filter(n -> n.id().equals(networkId))
424 .findAny().orElse(null);
Hyunsun Moonb0f09be2016-02-23 04:21:42 -0800425
426 if (openstackNetwork == null) {
427 return null;
428 }
429
430 return OpenstackNetwork.builder()
431 .id(openstackNetwork.id())
432 .name(openstackNetwork.name())
433 .networkType(openstackNetwork.networkType())
434 .segmentId(openstackNetwork.segmentId())
435 .tenantId(openstackNetwork.tenantId())
436 .subnets(subnets)
437 .build();
sangho0c2a3da2016-02-16 13:39:07 +0900438 }
439
440 @Override
441 public Collection<OpenstackNetwork> networks() {
442 return getNetworks();
443 }
444
445 @Override
446 public OpenstackSubnet subnet(String subnetId) {
447 return getSubnets().stream()
448 .filter(subnet -> subnet.id().equals(subnetId))
449 .findAny().orElse(null);
450 }
451
452 @Override
453 public Collection<OpenstackSubnet> subnets() {
454 return getSubnets();
455 }
456
457 @Override
458 public Collection<OpenstackRouter> routers() {
459 return getRouters();
460 }
461
462 @Override
463 public OpenstackRouter router(String routerId) {
464 return getRouters().stream()
465 .filter(router -> router.id().equals(routerId))
466 .findAny().orElse(null);
467 }
468
sanghod177f8f2016-06-29 21:52:23 +0900469 @Override
470 public Collection<OpenstackFloatingIP> floatingIps() {
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700471 Invocation.Builder builder = getClientBuilder(neutronUrl, URI_FLOATINGIPS);
472 if (builder == null) {
473 log.warn("Failed to get floating IPs");
474 return Collections.EMPTY_LIST;
475 }
476
sanghod177f8f2016-06-29 21:52:23 +0900477 String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
478 header(HEADER_AUTH_TOKEN, getToken()).get(String.class);
479
480 log.debug("floatingIps response:" + response);
481
482 ObjectMapper mapper = new ObjectMapper();
483 List<OpenstackFloatingIP> openstackFloatingIPs = Lists.newArrayList();
484 try {
485 ObjectNode node = (ObjectNode) mapper.readTree(response);
486 ArrayNode floatingIpList = (ArrayNode) node.path(PATH_FLOATINGIPS);
487 OpenstackFloatingIpCodec fipCodec = new OpenstackFloatingIpCodec();
488 floatingIpList.forEach(f -> openstackFloatingIPs.add(fipCodec.decode((ObjectNode) f, null)));
489 } catch (IOException e) {
490 log.warn("floatingIps()", e);
491 }
492
493 openstackFloatingIPs.removeAll(Collections.singleton(null));
494
495 return openstackFloatingIPs;
496 }
497
Daniel Parka26f2652016-09-08 16:48:26 +0900498 @Override
499 public boolean updateFloatingIp(String id, String portId, Optional<Ip4Address> fixedIpAddress) {
500 Invocation.Builder builder = getClientBuilder(neutronUrl, URI_FLOATINGIPS + "/" + id);
501
502 if (builder == null || (portId != null && !fixedIpAddress.isPresent())) {
503 log.warn("Failed to update floating IP");
504 return false;
505 }
506
507 ObjectNode objectNode = createFloatingIpObject(portId, fixedIpAddress);
508
509 InputStream inputStream = new ByteArrayInputStream(objectNode.toString().getBytes());
510
511 try {
512 Response response = builder.header(HEADER_AUTH_TOKEN, getToken())
513 .put(Entity.entity(IOUtils.toString(inputStream, StandardCharsets.UTF_8),
514 MediaType.APPLICATION_JSON));
515 log.debug("updateFloatingIp called: {}, status: {}", response.readEntity(String.class),
516 String.valueOf(response.getStatus()));
517
518 return checkReply(response);
519 } catch (IOException e) {
520 log.error("Cannot do PUT {} request");
521 return false;
522 }
523 }
524
525 private ObjectNode createFloatingIpObject(String portId, Optional<Ip4Address> fixedIpAddress) {
526 ObjectMapper mapper = new ObjectMapper();
527 ObjectNode objectNode = mapper.createObjectNode();
528
529 objectNode.putObject(FLOATINGIP)
530 .put(PORT_ID, portId);
531
532 if (portId != null) {
533 objectNode.put(FIXED_IP_ADDRESS, fixedIpAddress.get().toString());
534 }
535
536 return objectNode;
537 }
538
539 private boolean checkReply(Response response) {
540 if (response != null) {
541 return checkStatusCode(response.getStatus());
542 }
543
544 log.warn("Null floating IP response from openstack");
545 return false;
546 }
547
548 private boolean checkStatusCode(int statusCode) {
549 if (statusCode == Response.Status.OK.getStatusCode()) {
550 return true;
551 }
552
553 return false;
554 }
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700555 private void configureNetwork() {
556 OpenstackInterfaceConfig cfg =
557 cfgService.getConfig(appId, OpenstackInterfaceConfig.class);
558 if (cfg == null) {
559 log.error("There is no openstack server information in config.");
560 return;
sangho93447f12016-02-24 00:33:22 +0900561 }
562
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700563 neutronUrl = checkNotNull(cfg.neutronServer());
564 keystoneUrl = checkNotNull(cfg.keystoneServer());
565 userName = checkNotNull(cfg.userName());
566 pass = checkNotNull(cfg.password());
567 }
568
569 private class InternalConfigListener implements NetworkConfigListener {
570
sangho93447f12016-02-24 00:33:22 +0900571 @Override
572 public void event(NetworkConfigEvent event) {
573 if (((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
574 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)) &&
sangho48907542016-03-28 16:07:07 +0900575 event.configClass().equals(OpenstackInterfaceConfig.class)) {
sangho93447f12016-02-24 00:33:22 +0900576
577 log.info("Network configuration changed");
Hyunsun Moonef6bad22016-07-19 16:25:43 -0700578 networkEventExcutorService.execute(() -> configureNetwork());
sangho93447f12016-02-24 00:33:22 +0900579 }
580 }
sangho0c2a3da2016-02-16 13:39:07 +0900581 }
Jian Li9d616492016-03-09 10:52:49 -0800582}