blob: ebb132fb07c6b37788edacdb7066f74d413ef58b [file] [log] [blame]
Jian Li0b93b002018-07-31 13:41:08 +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.openstacktroubleshoot.cli;
17
Jian Lie189c1c2018-08-08 15:55:08 +090018import com.google.common.collect.Sets;
Ray Milkey86ad7bb2018-09-27 12:32:28 -070019import org.apache.karaf.shell.api.action.Argument;
20import org.apache.karaf.shell.api.action.Command;
21import org.apache.karaf.shell.api.action.Option;
Jian Lie189c1c2018-08-08 15:55:08 +090022import org.onlab.packet.IpAddress;
Jian Li0b93b002018-07-31 13:41:08 +090023import org.onosproject.cli.AbstractShellCommand;
Jian Li43d04282018-08-22 14:31:21 +090024import org.onosproject.cluster.ClusterService;
25import org.onosproject.cluster.NodeId;
26import org.onosproject.mastership.MastershipService;
Jian Lie189c1c2018-08-08 15:55:08 +090027import org.onosproject.openstacknetworking.api.InstancePort;
28import org.onosproject.openstacknetworking.api.InstancePortService;
Jian Li43d04282018-08-22 14:31:21 +090029import org.onosproject.openstacknode.api.OpenstackNode;
30import org.onosproject.openstacknode.api.OpenstackNodeService;
Jian Li0b93b002018-07-31 13:41:08 +090031import org.onosproject.openstacktroubleshoot.api.OpenstackTroubleshootService;
32import org.onosproject.openstacktroubleshoot.api.Reachability;
33
Jian Lie189c1c2018-08-08 15:55:08 +090034import java.util.Optional;
35import java.util.Set;
36import java.util.stream.Collectors;
Jian Li0b93b002018-07-31 13:41:08 +090037
Jian Lic38e9032018-08-09 17:08:38 +090038import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
Jian Li43d04282018-08-22 14:31:21 +090039import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
Jian Lic38e9032018-08-09 17:08:38 +090040
Jian Li0b93b002018-07-31 13:41:08 +090041/**
42 * Checks the east-west VMs connectivity.
43 */
44@Command(scope = "onos", name = "openstack-check-east-west",
45 description = "Checks the east-west VMs connectivity")
46public class OpenstackEastWestProbeCommand extends AbstractShellCommand {
47
48 private static final String REACHABLE = "Reachable :)";
49 private static final String UNREACHABLE = "Unreachable :(";
50 private static final String ARROW = "->";
51
52 private static final String FORMAT = "%-20s%-5s%-20s%-20s";
53
Jian Lie189c1c2018-08-08 15:55:08 +090054 @Option(name = "-a", aliases = "--all", description = "Apply this command to all VMs",
55 required = false, multiValued = false)
56 private boolean isAll = false;
57
58 @Argument(index = 0, name = "vmIps", description = "VMs' IP addresses",
59 required = false, multiValued = true)
60 private String[] vmIps = null;
61
Jian Li0b93b002018-07-31 13:41:08 +090062 @Override
Ray Milkey86ad7bb2018-09-27 12:32:28 -070063 protected void doExecute() {
Jian Li43d04282018-08-22 14:31:21 +090064 OpenstackTroubleshootService tsService = get(OpenstackTroubleshootService.class);
Jian Lic38e9032018-08-09 17:08:38 +090065 InstancePortService instPortService = get(InstancePortService.class);
Jian Li43d04282018-08-22 14:31:21 +090066 MastershipService mastershipService = get(MastershipService.class);
67 ClusterService clusterService = get(ClusterService.class);
68 OpenstackNodeService osNodeService = get(OpenstackNodeService.class);
Jian Lie189c1c2018-08-08 15:55:08 +090069
70 if (tsService == null) {
Jian Li0b93b002018-07-31 13:41:08 +090071 error("Failed to troubleshoot openstack networking.");
72 return;
73 }
74
Jian Lie189c1c2018-08-08 15:55:08 +090075 if ((!isAll && vmIps == null) || (isAll && vmIps != null)) {
76 print("Please specify one of VM IP address or -a option.");
77 return;
78 }
79
Jian Li43d04282018-08-22 14:31:21 +090080 NodeId localNodeId = clusterService.getLocalNode().id();
81
82 for (OpenstackNode node : osNodeService.completeNodes(COMPUTE)) {
83 if (!localNodeId.equals(mastershipService.getMasterFor(node.intgBridge()))) {
84 error("Current node is not the master for all compute nodes. " +
85 "Please enforce mastership first using openstack-reset-mastership -c !");
86 return;
87 }
88 }
89
Jian Lie189c1c2018-08-08 15:55:08 +090090 if (isAll) {
91 printHeader();
Jian Lic38e9032018-08-09 17:08:38 +090092 // send ICMP PACKET_OUT to all connect VMs whose instance port state is ACTIVE
93 Set<InstancePort> activePorts = instPortService.instancePorts().stream()
94 .filter(p -> p.state() == ACTIVE)
95 .collect(Collectors.toSet());
96
97 activePorts.forEach(srcPort ->
98 activePorts.forEach(dstPort ->
99 printReachability(tsService.probeEastWest(srcPort, dstPort))
100 )
101 );
Jian Lie189c1c2018-08-08 15:55:08 +0900102 } else {
103 if (vmIps.length > 2) {
104 print("Too many VM IPs. The number of IP should be limited to 2.");
105 return;
106 }
107
Jian Lic38e9032018-08-09 17:08:38 +0900108 IpAddress srcIp = getIpAddress(vmIps[0]);
109
110 if (srcIp == null) {
111 return;
112 }
113
Jian Lie189c1c2018-08-08 15:55:08 +0900114 InstancePort srcPort = instPort(instPortService, srcIp);
115
116 if (srcPort == null) {
117 print("Specified source IP is not existing.");
118 return;
119 }
120
121 final Set<IpAddress> dstIps = Sets.newConcurrentHashSet();
122
123 if (vmIps.length == 2) {
Jian Lic38e9032018-08-09 17:08:38 +0900124 IpAddress dstIp = getIpAddress(vmIps[1]);
125
126 if (dstIp == null) {
127 return;
128 }
129
130 dstIps.add(dstIp);
Jian Lie189c1c2018-08-08 15:55:08 +0900131 }
132
133 if (vmIps.length == 1) {
134 dstIps.addAll(instPortService.instancePorts().stream()
135 .filter(p -> !p.ipAddress().equals(srcIp))
136 .filter(p -> p.state().equals(InstancePort.State.ACTIVE))
137 .map(InstancePort::ipAddress)
138 .collect(Collectors.toSet()));
139 }
140
141 printHeader();
142 dstIps.stream()
143 .filter(ip -> instPort(instPortService, ip) != null)
144 .map(ip -> instPort(instPortService, ip))
145 .forEach(port -> printReachability(tsService.probeEastWest(srcPort, port)));
146 }
147 }
148
149 private InstancePort instPort(InstancePortService service, IpAddress ip) {
150 Optional<InstancePort> port = service.instancePorts().stream()
151 .filter(p -> p.ipAddress().equals(ip)).findFirst();
152
153 if (port.isPresent()) {
154 return port.get();
155 } else {
156 print("Specified destination IP is not existing.");
157 return null;
158 }
159 }
160
161 private void printHeader() {
Jian Li0b93b002018-07-31 13:41:08 +0900162 print(FORMAT, "Source IP", "", "Destination IP", "Reachability");
Jian Lie189c1c2018-08-08 15:55:08 +0900163 }
Jian Li0b93b002018-07-31 13:41:08 +0900164
Jian Lie189c1c2018-08-08 15:55:08 +0900165 private void printReachability(Reachability r) {
166 String result = r.isReachable() ? REACHABLE : UNREACHABLE;
167 print(FORMAT, r.srcIp().toString(), ARROW, r.dstIp().toString(), result);
Jian Li0b93b002018-07-31 13:41:08 +0900168 }
Jian Lic38e9032018-08-09 17:08:38 +0900169
170 private IpAddress getIpAddress(String ipString) {
171 try {
172 return IpAddress.valueOf(vmIps[0]);
173 } catch (IllegalArgumentException e) {
174 error("Invalid IP address string.");
175 return null;
176 }
177 }
Jian Li0b93b002018-07-31 13:41:08 +0900178}