blob: 80d7db660e2a01e4087321801aefedab43c4a958 [file] [log] [blame]
Jian Li51728702019-05-17 18:38:56 +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 com.google.common.collect.ImmutableMap;
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Sets;
21import org.apache.commons.lang3.StringUtils;
22import org.apache.karaf.shell.api.action.Argument;
23import org.apache.karaf.shell.api.action.Command;
24import org.apache.karaf.shell.api.action.Completion;
25import org.apache.karaf.shell.api.action.Option;
26import org.apache.karaf.shell.api.action.lifecycle.Service;
27import org.onosproject.cli.AbstractShellCommand;
28import org.onosproject.net.device.DeviceService;
29import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
30import org.onosproject.openstacknode.api.OpenstackNode;
31import org.onosproject.openstacknode.api.OpenstackNodeService;
32import org.onosproject.ovsdb.controller.OvsdbClientService;
33import org.onosproject.ovsdb.controller.OvsdbController;
34import org.onosproject.ovsdb.controller.OvsdbInterface;
35import org.openstack4j.model.network.Port;
36
37import java.util.List;
38import java.util.Map;
39import java.util.Set;
40import java.util.stream.Collectors;
41
42import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getOvsdbClient;
43import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.ifaceNameFromOsPortId;
44import static org.onosproject.openstacknode.api.Constants.INTEGRATION_BRIDGE;
45import static org.onosproject.ovsdb.rfc.table.Interface.InterfaceColumn.EXTERNALIDS;
46
47/**
48 * Recovers the openvswitch tap ports.
49 */
50@Service
51@Command(scope = "onos", name = "openstack-recover-ports",
52 description = "Recovers VM's tap ports detached from OpenvSwitch.")
53public class OpenstackRecoverPortsCommand extends AbstractShellCommand {
54
55 private static final int OVS_DB_PORT = 6640;
56
57 private static final String ATTACHED_MAC = "attached-mac";
58 private static final String IFACE_ID = "iface-id";
59 private static final String IFACE_STATUS = "iface-status";
60 private static final String VM_ID = "vm-id";
61
62 private static final String PORT_NAME = "portName";
63
64 @Option(name = "-a", aliases = "--all", description = "Apply this command to all nodes",
65 required = false, multiValued = false)
66 private boolean isAll = false;
67
68 @Argument(index = 0, name = "hostnames", description = "Hostname(s) to apply this command",
69 required = false, multiValued = true)
70 @Completion(OpenstackComputeNodeCompleter.class)
71 private String[] hostnames = null;
72
73 @Override
74 protected void doExecute() {
75 OvsdbController controller = get(OvsdbController.class);
76 OpenstackNodeService nodeService = get(OpenstackNodeService.class);
77 OpenstackNetworkService networkService = get(OpenstackNetworkService.class);
78 DeviceService deviceService = get(DeviceService.class);
79
80 if (isAll) {
81 hostnames = nodeService.completeNodes().stream()
82 .map(OpenstackNode::hostname).toArray(String[]::new);
83 }
84
85 if (hostnames == null) {
86 print("Please specify one of hostname or --all options.");
87 return;
88 }
89
90 for (String hostname : hostnames) {
91 networkService.ports().forEach(p -> {
92 if (hostname.equals(p.getHostId())) {
93 OpenstackNode osNode = nodeService.node(p.getHostId());
94 if (osNode != null) {
95 Set<String> recoveredPortNames =
96 recoverOvsPort(controller, OVS_DB_PORT, osNode, p,
97 deviceService.getPorts(osNode.intgBridge()));
98 recoveredPortNames.forEach(pn -> print(pn + " is recovered!"));
99 }
100 }
101 });
102 }
103 }
104
105 /**
106 * Recovers the openvswitch port from conf.db corruption.
107 *
108 * @param controller ovsdb controller
109 * @param ovsdbPort ovsdb port number
110 * @param node openstack node
111 * @param osPort an openstack port
112 * @param ovsPorts set of openvswitch ports
113 *
114 * @return a set of recovered port name
115 */
116 private Set<String> recoverOvsPort(OvsdbController controller, int ovsdbPort,
117 OpenstackNode node, Port osPort,
118 List<org.onosproject.net.Port> ovsPorts) {
119 OvsdbClientService client = getOvsdbClient(node, ovsdbPort, controller);
120
121 if (client == null) {
122 return ImmutableSet.of();
123 }
124
125 Set<String> portNames = ovsPorts.stream()
126 .filter(ovsPort -> ovsPort.annotations() != null ||
127 ovsPort.annotations().keys().contains(PORT_NAME))
128 .map(ovsPort -> ovsPort.annotations().value(PORT_NAME))
129 .collect(Collectors.toSet());
130
131 String tapPort = ifaceNameFromOsPortId(osPort.getId());
132 Set<String> recoveredPortNames = Sets.newConcurrentHashSet();
133 if (!portNames.contains(tapPort)) {
134 Map<String, String> extIdMap =
135 ImmutableMap.of(ATTACHED_MAC, osPort.getMacAddress(),
136 IFACE_ID, osPort.getId(), IFACE_STATUS,
137 StringUtils.lowerCase(osPort.getState().name()),
138 VM_ID, osPort.getDeviceId());
139
140 OvsdbInterface ovsIface = OvsdbInterface.builder()
141 .name(tapPort)
142 .options(ImmutableMap.of())
143 .data(ImmutableMap.of(EXTERNALIDS, extIdMap))
144 .build();
145 client.createInterface(INTEGRATION_BRIDGE, ovsIface);
146 recoveredPortNames.add(tapPort);
147 }
148 return ImmutableSet.copyOf(recoveredPortNames);
149 }
150}