blob: d85f39eb7a28f2af267eddcd237fd4530626318d [file] [log] [blame]
Hyunsun Moonc7219222017-03-27 11:05:59 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moonc7219222017-03-27 11:05:59 +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 */
16package org.onosproject.openstacknetworking.cli;
17
18import com.fasterxml.jackson.databind.JsonNode;
19import com.google.common.base.Strings;
20import org.apache.karaf.shell.commands.Argument;
21import org.apache.karaf.shell.commands.Command;
22import org.onosproject.cli.AbstractShellCommand;
23import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
Hyunsun Moonc7219222017-03-27 11:05:59 +090024import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
Hyunsun Moonae51e732017-04-25 17:46:21 +090025import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
Hyunsun Moonc7219222017-03-27 11:05:59 +090026import org.openstack4j.api.OSClient;
Jian Li8cbc3b92018-04-11 12:21:25 +090027import org.openstack4j.api.client.IOSClientBuilder;
Hyunsun Moonc7219222017-03-27 11:05:59 +090028import org.openstack4j.api.exceptions.AuthenticationException;
Jian Lib43b0672018-04-05 21:48:51 +090029import org.openstack4j.api.types.Facing;
Jian Li1a9e71c2018-04-03 19:00:29 +090030import org.openstack4j.core.transport.Config;
sanghoa0ef13b2018-03-09 13:56:39 +090031import org.openstack4j.model.common.Identifier;
Hyunsun Moonc7219222017-03-27 11:05:59 +090032import org.openstack4j.model.network.IP;
33import org.openstack4j.model.network.NetFloatingIP;
34import org.openstack4j.model.network.Network;
35import org.openstack4j.model.network.Port;
36import org.openstack4j.model.network.Router;
37import org.openstack4j.model.network.RouterInterface;
38import org.openstack4j.model.network.Subnet;
39import org.openstack4j.openstack.OSFactory;
40import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
41
Jian Li1a9e71c2018-04-03 19:00:29 +090042import javax.net.ssl.HostnameVerifier;
43import javax.net.ssl.HttpsURLConnection;
44import javax.net.ssl.SSLContext;
45import javax.net.ssl.TrustManager;
Hyunsun Moonc7219222017-03-27 11:05:59 +090046import java.io.IOException;
47import java.util.List;
48import java.util.Objects;
49import java.util.stream.Collectors;
50
Jian Li1a9e71c2018-04-03 19:00:29 +090051import javax.net.ssl.X509TrustManager;
52import java.security.cert.X509Certificate;
53
Hyunsun Moonc7219222017-03-27 11:05:59 +090054import static org.openstack4j.core.transport.ObjectMapperSingleton.getContext;
55
56/**
57 * Synchronizes OpenStack network states.
58 */
59@Command(scope = "onos", name = "openstack-sync-states",
60 description = "Synchronizes all OpenStack network states")
61public class OpenstackSyncStateCommand extends AbstractShellCommand {
62
63 @Argument(index = 0, name = "endpoint", description = "OpenStack service endpoint",
64 required = true, multiValued = false)
65 private String endpoint = null;
66
Jian Li8cbc3b92018-04-11 12:21:25 +090067 @Argument(index = 1, name = "tenant", description = "OpenStack admin tenant name",
Hyunsun Moonc7219222017-03-27 11:05:59 +090068 required = true, multiValued = false)
69 private String tenant = null;
70
Jian Li8cbc3b92018-04-11 12:21:25 +090071 @Argument(index = 2, name = "user", description = "OpenStack admin user name",
Hyunsun Moonc7219222017-03-27 11:05:59 +090072 required = true, multiValued = false)
73 private String user = null;
74
Jian Li8cbc3b92018-04-11 12:21:25 +090075 @Argument(index = 3, name = "password", description = "OpenStack admin user password",
Hyunsun Moonc7219222017-03-27 11:05:59 +090076 required = true, multiValued = false)
77 private String password = null;
78
Jian Li8cbc3b92018-04-11 12:21:25 +090079 @Argument(index = 4, name = "perspective", description = "OpenStack endpoint perspective",
80 required = false, multiValued = false)
81 private String perspective = null;
82
sanghoa0ef13b2018-03-09 13:56:39 +090083 private static final String DOMAIN_DEFUALT = "default";
84
Hyunsun Moonae51e732017-04-25 17:46:21 +090085 private static final String SECURITY_GROUP_FORMAT = "%-40s%-20s";
Hyunsun Moonc7219222017-03-27 11:05:59 +090086 private static final String NETWORK_FORMAT = "%-40s%-20s%-20s%-8s";
87 private static final String SUBNET_FORMAT = "%-40s%-20s%-20s";
88 private static final String PORT_FORMAT = "%-40s%-20s%-20s%-8s";
89 private static final String ROUTER_FORMAT = "%-40s%-20s%-20s%-8s";
90 private static final String FLOATING_IP_FORMAT = "%-40s%-20s%-20s";
91
92 private static final String DEVICE_OWNER_GW = "network:router_gateway";
93 private static final String DEVICE_OWNER_IFACE = "network:router_interface";
94
Jian Li8769d5b2018-03-09 21:55:40 +090095 private static final String KEYSTONE_V2 = "v2.0";
96 private static final String KEYSTONE_V3 = "v3";
97
Hyunsun Moonc7219222017-03-27 11:05:59 +090098 @Override
99 protected void execute() {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900100 OpenstackSecurityGroupAdminService osSgAdminService = get(OpenstackSecurityGroupAdminService.class);
Hyunsun Moonc7219222017-03-27 11:05:59 +0900101 OpenstackNetworkAdminService osNetAdminService = get(OpenstackNetworkAdminService.class);
Hyunsun Moonc7219222017-03-27 11:05:59 +0900102 OpenstackRouterAdminService osRouterAdminService = get(OpenstackRouterAdminService.class);
Hyunsun Moonc7219222017-03-27 11:05:59 +0900103
Jian Li8769d5b2018-03-09 21:55:40 +0900104 OSClient osClient;
sanghoa0ef13b2018-03-09 13:56:39 +0900105
Jian Li8cbc3b92018-04-11 12:21:25 +0900106 Config config = getSslConfig();
Jian Li1a9e71c2018-04-03 19:00:29 +0900107
Jian Li8769d5b2018-03-09 21:55:40 +0900108 try {
109 if (endpoint != null) {
110 if (endpoint.contains(KEYSTONE_V2)) {
Jian Li8cbc3b92018-04-11 12:21:25 +0900111 IOSClientBuilder.V2 builder = OSFactory.builderV2()
Jian Li8769d5b2018-03-09 21:55:40 +0900112 .endpoint(this.endpoint)
113 .tenantName(this.tenant)
114 .credentials(this.user, this.password)
Jian Li8cbc3b92018-04-11 12:21:25 +0900115 .withConfig(config);
116
117 if (perspective != null) {
118 builder.perspective(getFacing(perspective));
119 }
120
121 osClient = builder.authenticate();
Jian Li8769d5b2018-03-09 21:55:40 +0900122 } else if (endpoint.contains(KEYSTONE_V3)) {
123
124 Identifier project = Identifier.byName(this.tenant);
125 Identifier domain = Identifier.byName(DOMAIN_DEFUALT);
126
Jian Li8cbc3b92018-04-11 12:21:25 +0900127 IOSClientBuilder.V3 builder = OSFactory.builderV3()
Jian Li8769d5b2018-03-09 21:55:40 +0900128 .endpoint(this.endpoint)
129 .credentials(this.user, this.password, domain)
130 .scopeToProject(project, domain)
Jian Li8cbc3b92018-04-11 12:21:25 +0900131 .withConfig(config);
132
133 if (perspective != null) {
134 builder.perspective(getFacing(perspective));
135 }
136
137 osClient = builder.authenticate();
Jian Li8769d5b2018-03-09 21:55:40 +0900138 } else {
139 print("Unrecognized keystone version type");
140 return;
141 }
142 } else {
143 print("Need to specify a valid endpoint");
144 return;
145 }
Hyunsun Moonc7219222017-03-27 11:05:59 +0900146 } catch (AuthenticationException e) {
147 print("Authentication failed");
148 return;
Hyunsun Moonc7219222017-03-27 11:05:59 +0900149 }
150
Hyunsun Moonae51e732017-04-25 17:46:21 +0900151 print("Synchronizing OpenStack security groups");
152 print(SECURITY_GROUP_FORMAT, "ID", "Name");
153 osClient.networking().securitygroup().list().forEach(osSg -> {
Jian Li21536592018-03-06 15:10:55 +0900154 if (osSgAdminService.securityGroup(osSg.getId()) != null) {
Hyunsun Moonae51e732017-04-25 17:46:21 +0900155 osSgAdminService.updateSecurityGroup(osSg);
156 } else {
157 osSgAdminService.createSecurityGroup(osSg);
158 }
159 print(SECURITY_GROUP_FORMAT, osSg.getId(), osSg.getName());
160 });
161
162 print("\nSynchronizing OpenStack networks");
Hyunsun Moonc7219222017-03-27 11:05:59 +0900163 print(NETWORK_FORMAT, "ID", "Name", "VNI", "Subnets");
164 osClient.networking().network().list().forEach(osNet -> {
Jian Li5a15fe62018-03-06 13:41:20 +0900165 if (osNetAdminService.network(osNet.getId()) != null) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900166 osNetAdminService.updateNetwork(osNet);
167 } else {
168 osNetAdminService.createNetwork(osNet);
169 }
170 printNetwork(osNet);
171 });
172
Hyunsun Moonae51e732017-04-25 17:46:21 +0900173 print("\nSynchronizing OpenStack subnets");
Hyunsun Moonc7219222017-03-27 11:05:59 +0900174 print(SUBNET_FORMAT, "ID", "Network", "CIDR");
175 osClient.networking().subnet().list().forEach(osSubnet -> {
Jian Li5a15fe62018-03-06 13:41:20 +0900176 if (osNetAdminService.subnet(osSubnet.getId()) != null) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900177 osNetAdminService.updateSubnet(osSubnet);
178 } else {
179 osNetAdminService.createSubnet(osSubnet);
180 }
Jian Li5a15fe62018-03-06 13:41:20 +0900181 printSubnet(osSubnet, osNetAdminService);
Hyunsun Moonc7219222017-03-27 11:05:59 +0900182 });
183
Hyunsun Moonae51e732017-04-25 17:46:21 +0900184 print("\nSynchronizing OpenStack ports");
Hyunsun Moonc7219222017-03-27 11:05:59 +0900185 print(PORT_FORMAT, "ID", "Network", "MAC", "Fixed IPs");
186 osClient.networking().port().list().forEach(osPort -> {
Jian Li5a15fe62018-03-06 13:41:20 +0900187 if (osNetAdminService.port(osPort.getId()) != null) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900188 osNetAdminService.updatePort(osPort);
189 } else {
190 osNetAdminService.createPort(osPort);
191 }
Jian Li5a15fe62018-03-06 13:41:20 +0900192 printPort(osPort, osNetAdminService);
Hyunsun Moonc7219222017-03-27 11:05:59 +0900193 });
194
Hyunsun Moonae51e732017-04-25 17:46:21 +0900195 print("\nSynchronizing OpenStack routers");
Hyunsun Moonc7219222017-03-27 11:05:59 +0900196 print(ROUTER_FORMAT, "ID", "Name", "External", "Internal");
197 osClient.networking().router().list().forEach(osRouter -> {
Jian Lida7c6cb2018-03-06 14:58:54 +0900198 if (osRouterAdminService.router(osRouter.getId()) != null) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900199 osRouterAdminService.updateRouter(osRouter);
200 } else {
201 osRouterAdminService.createRouter(osRouter);
202 }
203
204 // FIXME do we need to manage router interfaces separately?
Jian Li5a15fe62018-03-06 13:41:20 +0900205 osNetAdminService.ports().stream()
Hyunsun Moonc7219222017-03-27 11:05:59 +0900206 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
207 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
Jian Lida7c6cb2018-03-06 14:58:54 +0900208 .forEach(osPort -> addRouterIface(osPort, osRouterAdminService));
Hyunsun Moonc7219222017-03-27 11:05:59 +0900209
Jian Li5a15fe62018-03-06 13:41:20 +0900210 printRouter(osRouter, osNetAdminService);
Hyunsun Moonc7219222017-03-27 11:05:59 +0900211 });
212
Hyunsun Moonae51e732017-04-25 17:46:21 +0900213 print("\nSynchronizing OpenStack floating IPs");
Hyunsun Moonc7219222017-03-27 11:05:59 +0900214 print(FLOATING_IP_FORMAT, "ID", "Floating IP", "Fixed IP");
215 osClient.networking().floatingip().list().forEach(osFloating -> {
Jian Lida7c6cb2018-03-06 14:58:54 +0900216 if (osRouterAdminService.floatingIp(osFloating.getId()) != null) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900217 osRouterAdminService.updateFloatingIp(osFloating);
218 } else {
219 osRouterAdminService.createFloatingIp(osFloating);
220 }
221 printFloatingIp(osFloating);
222 });
223 }
224
225 // TODO fix the logic to add router interface to router
Jian Lida7c6cb2018-03-06 14:58:54 +0900226 private void addRouterIface(Port osPort, OpenstackRouterAdminService adminService) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900227 osPort.getFixedIps().forEach(p -> {
228 JsonNode jsonTree = mapper().createObjectNode()
229 .put("id", osPort.getDeviceId())
230 .put("tenant_id", osPort.getTenantId())
231 .put("subnet_id", p.getSubnetId())
232 .put("port_id", osPort.getId());
233 try {
234 RouterInterface rIface = getContext(NeutronRouterInterface.class)
235 .readerFor(NeutronRouterInterface.class)
236 .readValue(jsonTree);
Jian Lida7c6cb2018-03-06 14:58:54 +0900237 if (adminService.routerInterface(rIface.getPortId()) != null) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900238 adminService.updateRouterInterface(rIface);
239 } else {
240 adminService.addRouterInterface(rIface);
241 }
242 } catch (IOException ignore) {
243 }
244 });
245 }
246
247 private void printNetwork(Network osNet) {
248 final String strNet = String.format(NETWORK_FORMAT,
249 osNet.getId(),
250 osNet.getName(),
251 osNet.getProviderSegID(),
252 osNet.getSubnets());
253 print(strNet);
254 }
255
Jian Li5a15fe62018-03-06 13:41:20 +0900256 private void printSubnet(Subnet osSubnet, OpenstackNetworkAdminService osNetService) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900257 final String strSubnet = String.format(SUBNET_FORMAT,
258 osSubnet.getId(),
259 osNetService.network(osSubnet.getNetworkId()).getName(),
260 osSubnet.getCidr());
261 print(strSubnet);
262 }
263
Jian Li5a15fe62018-03-06 13:41:20 +0900264 private void printPort(Port osPort, OpenstackNetworkAdminService osNetService) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900265 List<String> fixedIps = osPort.getFixedIps().stream()
266 .map(IP::getIpAddress)
267 .collect(Collectors.toList());
268 final String strPort = String.format(PORT_FORMAT,
269 osPort.getId(),
270 osNetService.network(osPort.getNetworkId()).getName(),
271 osPort.getMacAddress(),
272 fixedIps.isEmpty() ? "" : fixedIps);
273 print(strPort);
274 }
275
Jian Li5a15fe62018-03-06 13:41:20 +0900276 private void printRouter(Router osRouter, OpenstackNetworkAdminService osNetService) {
Hyunsun Moonc7219222017-03-27 11:05:59 +0900277 List<String> externals = osNetService.ports().stream()
278 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
279 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_GW))
280 .flatMap(osPort -> osPort.getFixedIps().stream())
281 .map(IP::getIpAddress)
282 .collect(Collectors.toList());
283
284 List<String> internals = osNetService.ports().stream()
285 .filter(osPort -> Objects.equals(osPort.getDeviceId(), osRouter.getId()) &&
286 Objects.equals(osPort.getDeviceOwner(), DEVICE_OWNER_IFACE))
287 .flatMap(osPort -> osPort.getFixedIps().stream())
288 .map(IP::getIpAddress)
289 .collect(Collectors.toList());
290
291 final String strRouter = String.format(ROUTER_FORMAT,
292 osRouter.getId(),
293 osRouter.getName(),
294 externals.isEmpty() ? "" : externals,
295 internals.isEmpty() ? "" : internals);
296 print(strRouter);
297 }
298
299 private void printFloatingIp(NetFloatingIP floatingIp) {
300 final String strFloating = String.format(FLOATING_IP_FORMAT,
301 floatingIp.getId(),
daniel parkeeb8e042018-02-21 14:06:58 +0900302 floatingIp.getFloatingIpAddress(),
Hyunsun Moonc7219222017-03-27 11:05:59 +0900303 Strings.isNullOrEmpty(floatingIp.getFixedIpAddress()) ?
304 "" : floatingIp.getFixedIpAddress());
305 print(strFloating);
306 }
Jian Lib43b0672018-04-05 21:48:51 +0900307
Jian Li8cbc3b92018-04-11 12:21:25 +0900308 private Config getSslConfig() {
309 // we bypass the SSL certification verification for now
310 // TODO: verify server side SSL using a given certification
311 Config config = Config.newConfig().withSSLVerificationDisabled();
312
313 TrustManager[] trustAllCerts = new TrustManager[]{
314 new X509TrustManager() {
315 public X509Certificate[] getAcceptedIssuers() {
316 return null;
317 }
318
319 public void checkClientTrusted(X509Certificate[] certs, String authType) {
320 }
321
322 public void checkServerTrusted(X509Certificate[] certs, String authType) {
323 }
324 }
325 };
326
327 HostnameVerifier allHostsValid = (hostname, session) -> true;
328
329 try {
330 SSLContext sc = SSLContext.getInstance("SSL");
331 sc.init(null, trustAllCerts, new java.security.SecureRandom());
332 HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
333 HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
334
335 config.withSSLContext(sc);
336 } catch (Exception e) {
337 print("Failed to access OpenStack service");
338 return null;
339 }
340
341 return config;
342 }
343
Jian Lib43b0672018-04-05 21:48:51 +0900344 private Facing getFacing(String strFacing) {
345
346 if (strFacing == null) {
347 return null;
348 }
349
350 switch (strFacing) {
351 case "public":
352 return Facing.PUBLIC;
353 case "admin":
354 return Facing.ADMIN;
355 case "internal":
356 return Facing.INTERNAL;
357 default:
358 return null;
359 }
360 }
Hyunsun Moonc7219222017-03-27 11:05:59 +0900361}