blob: 7f8b118d9d100f373b57f7711916f759086661e1 [file] [log] [blame]
Jian Li40f032a2019-10-02 20:36:09 +09001/*
2 * Copyright 2019-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.openstacknetworking.cli;
17
18import org.apache.karaf.shell.api.action.Command;
19import org.apache.karaf.shell.api.action.Option;
20import org.apache.karaf.shell.api.action.lifecycle.Service;
21import org.onosproject.cli.AbstractShellCommand;
22import org.onosproject.openstacknetworking.api.OpenstackNetworkAdminService;
23import org.onosproject.openstacknetworking.api.OpenstackRouterAdminService;
24import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupAdminService;
25import org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil;
26import org.onosproject.openstacknode.api.OpenstackNode;
27import org.onosproject.openstacknode.api.OpenstackNodeService;
28import org.openstack4j.api.OSClient;
29import org.openstack4j.model.common.IdEntity;
30import org.openstack4j.model.network.NetFloatingIP;
31import org.openstack4j.model.network.RouterInterface;
32
33import java.util.HashMap;
34import java.util.Map;
35import java.util.Optional;
36import java.util.Set;
37import java.util.stream.Collectors;
38
39import static org.onosproject.openstacknetworking.api.Constants.FLOATING_IP_FORMAT;
40import static org.onosproject.openstacknetworking.api.Constants.NETWORK_FORMAT;
41import static org.onosproject.openstacknetworking.api.Constants.PORT_FORMAT;
42import static org.onosproject.openstacknetworking.api.Constants.ROUTER_FORMAT;
43import static org.onosproject.openstacknetworking.api.Constants.ROUTER_INTF_FORMAT;
44import static org.onosproject.openstacknetworking.api.Constants.SECURITY_GROUP_FORMAT;
45import static org.onosproject.openstacknetworking.api.Constants.SUBNET_FORMAT;
46import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.printFloatingIp;
47import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.printNetwork;
48import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.printPort;
49import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.printRouter;
50import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.printRouterIntf;
51import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.printSecurityGroup;
52import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.printSubnet;
53import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.CONTROLLER;
54
55/**
56 * Compares cached network state diff against neutron database.
57 */
58@Service
59@Command(scope = "onos", name = "openstack-diff-state",
60 description = "Compares cached network state with neutron database.")
61public class OpenstackDiffStateCommand extends AbstractShellCommand {
62
63 private static final String HTTP_HEADER_ACCEPT = "accept";
64 private static final String HTTP_HEADER_VALUE_JSON = "application/json";
65
66 @Option(name = "-s", aliases = "--show",
67 description = "Shows the differences between cached network state with neutron database.",
68 required = false, multiValued = false)
69 private boolean show = false;
70
71 @Option(name = "-c", aliases = "--clear",
72 description = "Clears the differences between cached network state with neutron database.",
73 required = false, multiValued = false)
74 private boolean clear = false;
75
76 @Override
77 protected void doExecute() {
78 OpenstackSecurityGroupAdminService osSgService =
79 get(OpenstackSecurityGroupAdminService.class);
80 OpenstackNetworkAdminService osNetService =
81 get(OpenstackNetworkAdminService.class);
82 OpenstackRouterAdminService osRouterService =
83 get(OpenstackRouterAdminService.class);
84 OpenstackNodeService osNodeService = get(OpenstackNodeService.class);
85
86 Map<String, String> headerMap = new HashMap<>();
87 headerMap.put(HTTP_HEADER_ACCEPT, HTTP_HEADER_VALUE_JSON);
88
89 Optional<OpenstackNode> node = osNodeService.nodes(CONTROLLER).stream().findFirst();
90 if (!node.isPresent()) {
91 error("Keystone auth info has not been configured. " +
92 "Please specify auth info via network-cfg.json.");
93 return;
94 }
95
96 OSClient osClient = OpenstackNetworkingUtil.getConnectedClient(node.get());
97
98 if (osClient == null) {
99 return;
100 }
101
102 if (!clear) {
103 show = true;
104 }
105
106 if (show && clear) {
107 error("Either --show (-s) or --clear (-c) option should be specified.");
108 }
109
110 if (show) {
111 print("\nComparing OpenStack floating IPs");
112 } else if (clear) {
113 print("\nClearing OpenStack floating IPs");
114 }
115 Set<String> cachedFips = osRouterService.floatingIps().stream()
116 .map(NetFloatingIP::getId).collect(Collectors.toSet());
117 Set<String> osFips = osClient.headers(headerMap).networking()
118 .floatingip().list().stream().map(NetFloatingIP::getId)
119 .collect(Collectors.toSet());
120
121 print(FLOATING_IP_FORMAT, "ID", "Floating IP", "Fixed IP");
122 getDiff(cachedFips, osFips).forEach(fipId -> {
123 printFloatingIp(osRouterService.floatingIp(fipId));
124 if (clear) {
125 osRouterService.removeFloatingIp(fipId);
126 }
127 });
128
129 Set<String> cachedPorts = osNetService.ports().stream()
130 .map(IdEntity::getId).collect(Collectors.toSet());
131 Set<String> osPorts = osClient.headers(headerMap).networking()
132 .port().list().stream().map(IdEntity::getId)
133 .collect(Collectors.toSet());
134
135 if (show) {
136 print("\nComparing OpenStack router interfaces");
137 } else if (clear) {
138 print("\nClearing OpenStack router interfaces");
139 }
140 print(ROUTER_INTF_FORMAT, "ID", "Tenant ID", "Subnet ID");
141 getDiff(cachedPorts, osPorts).forEach(portId -> {
142 RouterInterface ri = osRouterService.routerInterface(portId);
143 if (ri != null) {
144 printRouterIntf(ri);
145 if (clear) {
146 osRouterService.removeRouterInterface(portId);
147 }
148 }
149 });
150
151 if (show) {
152 print("\nComparing OpenStack ports");
153 } else if (clear) {
154 print("\nClearing OpenStack ports");
155 }
156 print(PORT_FORMAT, "ID", "Network", "MAC", "Fixed IPs");
157 getDiff(cachedPorts, osPorts).forEach(portId -> {
158 printPort(osNetService.port(portId), osNetService);
159 if (clear) {
160 osNetService.removePort(portId);
161 }
162 });
163
164 if (show) {
165 print("\nComparing OpenStack routers");
166 } else if (clear) {
167 print("\nClearing OpenStack routers");
168 }
169 Set<String> cachedRouters = osRouterService.routers().stream()
170 .map(IdEntity::getId).collect(Collectors.toSet());
171 Set<String> osRouters = osClient.headers(headerMap).networking()
172 .router().list().stream().map(IdEntity::getId)
173 .collect(Collectors.toSet());
174
175 print(ROUTER_FORMAT, "ID", "Name", "External", "Internal");
176 getDiff(cachedRouters, osRouters).forEach(routerId -> {
177 printRouter(osRouterService.router(routerId), osNetService);
178 if (clear) {
179 osRouterService.removeRouter(routerId);
180 }
181 });
182
183 if (show) {
184 print("\nComparing OpenStack subnets");
185 } else if (clear) {
186 print("\nClearing OpenStack subnets");
187 }
188 Set<String> cachedSubnets = osNetService.subnets().stream()
189 .map(IdEntity::getId).collect(Collectors.toSet());
190 Set<String> osSubnets = osClient.headers(headerMap).networking()
191 .subnet().list().stream().map(IdEntity::getId)
192 .collect(Collectors.toSet());
193
194 print(SUBNET_FORMAT, "ID", "Network", "CIDR");
195 getDiff(cachedSubnets, osSubnets).forEach(subnetId -> {
196 printSubnet(osNetService.subnet(subnetId), osNetService);
197 if (clear) {
198 osNetService.removeSubnet(subnetId);
199 }
200 });
201
202 if (show) {
203 print("\nComparing OpenStack networks");
204 } else if (clear) {
205 print("\nClearing OpenStack networks");
206 }
207 Set<String> cachedNets = osNetService.networks().stream()
208 .map(IdEntity::getId).collect(Collectors.toSet());
209 Set<String> osNets = osClient.headers(headerMap).networking()
210 .network().list().stream().map(IdEntity::getId)
211 .collect(Collectors.toSet());
212
213 print(NETWORK_FORMAT, "ID", "Name", "VNI", "Subnets");
214 getDiff(cachedNets, osNets).forEach(netId -> {
215 printNetwork(osNetService.network(netId));
216 if (clear) {
217 osNetService.removeNetwork(netId);
218 }
219 });
220
221 if (show) {
222 print("\nComparing OpenStack security groups");
223 } else if (clear) {
224 print("\nClearing OpenStack security groups");
225 }
226 Set<String> cachedSgs = osSgService.securityGroups().stream()
227 .map(IdEntity::getId).collect(Collectors.toSet());
228 Set<String> osSgs = osClient.headers(headerMap).networking()
229 .securitygroup().list().stream().map(IdEntity::getId)
230 .collect(Collectors.toSet());
231
232 print(SECURITY_GROUP_FORMAT, "ID", "Name");
233 getDiff(cachedSgs, osSgs).forEach(sgId -> {
234 printSecurityGroup(osSgService.securityGroup(sgId));
235 if (clear) {
236 osSgService.removeSecurityGroup(sgId);
237 }
238 });
239 }
240
241 private Set<String> getDiff(Set<String> orig, Set<String> comp) {
242 return orig.stream().filter(id -> !comp.contains(id))
243 .collect(Collectors.toSet());
244 }
245}