blob: 08824290467e4603241f69e3a33c9d00a675736e [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.cli.net;
import static org.onosproject.net.DeviceId.deviceId;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.StreamSupport;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onlab.util.Bandwidth;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.OchSignal;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.TributarySlot;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.intent.IntentId;
import org.onosproject.net.resource.ResourceConsumerId;
import org.onosproject.net.resource.Resources;
import org.onosproject.net.resource.DiscreteResourceId;
import org.onosproject.net.resource.ResourceAllocation;
import org.onosproject.net.resource.ResourceService;
/**
* Lists allocated resources.
*/
@Command(scope = "onos", name = "allocations",
description = "Lists allocated resources")
public class AllocationsCommand extends AbstractShellCommand {
@Option(name = "-t", aliases = "--type", description = "List of resource types",
required = false, multiValued = true)
String[] typeStrings = null;
Set<String> typesToPrint;
@Option(name = "-i", aliases = "--intentId", description = "Intent ID",
required = false, multiValued = true)
String[] intentStrings;
Set<String> intentsToPrint;
@Argument(index = 0, name = "deviceIdString", description = "Device ID",
required = false, multiValued = false)
String deviceIdStr = null;
@Argument(index = 1, name = "portNumberString", description = "PortNumber",
required = false, multiValued = false)
String portNumberStr = null;
private DeviceService deviceService;
private ResourceService resourceService;
@Override
protected void execute() {
deviceService = get(DeviceService.class);
resourceService = get(ResourceService.class);
if (typeStrings != null) {
typesToPrint = new HashSet<>(Arrays.asList(typeStrings));
} else {
typesToPrint = Collections.emptySet();
}
if (intentStrings != null) {
intentsToPrint = new HashSet<>(Arrays.asList(intentStrings));
} else {
intentsToPrint = Collections.emptySet();
}
if (deviceIdStr != null && portNumberStr != null) {
DeviceId deviceId = deviceId(deviceIdStr);
PortNumber portNumber = PortNumber.fromString(portNumberStr);
printAllocation(deviceId, portNumber, 0);
} else if (deviceIdStr != null) {
DeviceId deviceId = deviceId(deviceIdStr);
printAllocation(deviceId, 0);
} else {
printAllocation();
}
}
private void printAllocation() {
print("ROOT");
StreamSupport.stream(deviceService.getAvailableDevices().spliterator(), false)
.map(Device::id)
.forEach(did -> printAllocation(did, 1));
}
private void printAllocation(DeviceId did, int level) {
print("%s%s", Strings.repeat(" ", level), did);
StreamSupport.stream(deviceService.getPorts(did).spliterator(), false)
.map(Port::number)
.forEach(num -> printAllocation(did, num, level + 1));
}
private void printAllocation(DeviceId did, PortNumber num, int level) {
if (level == 0) {
// print DeviceId when Port was directly specified.
print("%s", did);
}
print("%s%s", Strings.repeat(" ", level), asVerboseString(num));
// FIXME: This workaround induces a lot of distributed store access.
// ResourceService should have an API to get all allocations under a parent resource.
Set<Class<?>> subResourceTypes = ImmutableSet.<Class<?>>builder()
.add(OchSignal.class)
.add(VlanId.class)
.add(MplsLabel.class)
.add(Bandwidth.class)
.add(TributarySlot.class)
.build();
DiscreteResourceId resourceId = Resources.discrete(did, num).id();
for (Class<?> t : subResourceTypes) {
resourceService.getResourceAllocations(resourceId, t).stream()
.filter(a -> isSubjectToPrint(a))
.forEach(a -> print("%s%s allocated by %s", Strings.repeat(" ", level + 1),
a.resource().valueAs(Object.class).orElse(""), asVerboseString(a.consumerId())));
}
}
private boolean isSubjectToPrint(ResourceAllocation allocation) {
if (!intentsToPrint.isEmpty()
&& allocation.consumerId().isClassOf(IntentId.class)
&& !intentsToPrint.contains(allocation.consumerId().toString())) {
return false;
}
if (!typesToPrint.isEmpty()
&& !typesToPrint.contains(allocation.resource().simpleTypeName())) {
return false;
}
return true;
}
/**
* Add type name if the toString does not start with them.
*
* e.g., IntentId#toString result in "42"
* asVerboseString(id) will result in "IntentId:42"
*
* @param obj non-null Object to print.
* @return verbose String representation
*/
private static String asVerboseString(Object obj) {
String name = obj.getClass().getSimpleName();
String toString = String.valueOf(obj);
if (toString.startsWith(name)) {
return toString;
} else {
return String.format("%s:%s", name, toString);
}
}
private static String asVerboseString(ResourceConsumerId consumerId) {
return String.format("%s:%s", consumerId.consumerClass(), consumerId.value());
}
}