HIGUCHI Yuta
Committed by Gerrit Code Review

[Emu] ONOS-3512 CLI for new resource subsystem

- "resources" command to print available resources on new resource service.
- "allocations" command to dump current allocations
- "test-allocate-resource" command to allocate a resource

Change-Id: I89e531c71ef288b8c06dcd355a3a819d667c8225
/*
* Copyright 2015 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.Collection;
import java.util.stream.StreamSupport;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
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.device.DeviceService;
import org.onosproject.net.newresource.ResourceAllocation;
import org.onosproject.net.newresource.ResourcePath;
import org.onosproject.net.newresource.ResourceService;
import com.google.common.base.Strings;
/**
* Lists allocated resources.
*/
@Command(scope = "onos", name = "allocations",
description = "Lists allocated resources")
public class AllocationsCommand extends AbstractShellCommand {
// TODO add other resource types
@Option(name = "-l", aliases = "--lambda", description = "Lambda Resource",
required = false, multiValued = false)
private boolean lambda = true;
@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 (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));
// TODO: Current design cannot deal with sub-resources
// (e.g., TX/RX under Port)
ResourcePath path = ResourcePath.discrete(did, num);
if (lambda) {
//print("Lambda resources:");
Collection<ResourceAllocation> allocations
= resourceService.getResourceAllocations(path, OchSignal.class);
for (ResourceAllocation a : allocations) {
print("%s%s allocated by %s", Strings.repeat(" ", level + 1),
a.resource().last(), asVerboseString(a.consumer()));
}
}
}
/**
* 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);
}
}
}
/*
* Copyright 2015 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 com.google.common.base.Preconditions.checkArgument;
import static org.onlab.osgi.DefaultServiceDirectory.getService;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.apache.karaf.shell.console.completer.ArgumentCompleter.ArgumentList;
import org.onosproject.cli.AbstractChoicesCompleter;
import org.onosproject.net.DeviceId;
import org.onosproject.net.device.DeviceService;
/**
* PortNumber completer.
*
* Assumes argument right before the one being completed is DeviceId.
*/
public class PortNumberCompleter extends AbstractChoicesCompleter {
@Override
protected List<String> choices() {
ArgumentList args = getArgumentList();
checkArgument(args.getCursorArgumentIndex() >= 1,
"Expects DeviceId as previous argument");
String deviceIdStr = args.getArguments()[args.getCursorArgumentIndex() - 1];
DeviceId deviceId = DeviceId.deviceId(deviceIdStr);
DeviceService deviceService = getService(DeviceService.class);
return StreamSupport.stream(deviceService.getPorts(deviceId).spliterator(), false)
.map(port -> port.number().toString())
.collect(Collectors.toList());
}
}
/*
* Copyright 2015 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.Collection;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.newresource.ResourcePath;
import org.onosproject.net.newresource.ResourceService;
import com.google.common.base.Strings;
/**
* Lists available resources.
*/
@Command(scope = "onos", name = "resources",
description = "Lists available resources")
public class ResourcesCommand extends AbstractShellCommand {
@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 ResourceService resourceService;
@Override
protected void execute() {
resourceService = get(ResourceService.class);
if (deviceIdStr != null && portNumberStr != null) {
DeviceId deviceId = deviceId(deviceIdStr);
PortNumber portNumber = PortNumber.fromString(portNumberStr);
printResource(ResourcePath.discrete(deviceId, portNumber), 0);
} else if (deviceIdStr != null) {
DeviceId deviceId = deviceId(deviceIdStr);
printResource(ResourcePath.discrete(deviceId), 0);
} else {
printResource(ResourcePath.ROOT, 0);
}
}
private void printResource(ResourcePath resource, int level) {
if (resource.equals(ResourcePath.ROOT)) {
print("ROOT");
} else {
String name = resource.last().getClass().getSimpleName();
String toString = String.valueOf(resource.last());
if (toString.startsWith(name)) {
print("%s%s", Strings.repeat(" ", level),
toString);
} else {
print("%s%s:%s", Strings.repeat(" ", level),
name,
toString);
}
}
Collection<ResourcePath> resources = resourceService.getAvailableResources(resource);
// TODO: Should consider better output for leaf nodes
resources.forEach(r -> printResource(r, level + 1));
}
}
/*
* Copyright 2015 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.newresource.ResourcePath.discrete;
import java.util.Optional;
import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.apache.karaf.shell.commands.Option;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.net.ChannelSpacing;
import org.onosproject.net.DeviceId;
import org.onosproject.net.GridType;
import org.onosproject.net.OchSignal;
import org.onosproject.net.PortNumber;
import org.onosproject.net.intent.IntentId;
import org.onosproject.net.newresource.ResourceAllocation;
import org.onosproject.net.newresource.ResourceConsumer;
import org.onosproject.net.newresource.ResourcePath;
import org.onosproject.net.newresource.ResourceService;
/**
* Test tool to allocate resources.
*/
@Command(scope = "onos", name = "test-allocate-resources",
description = "Test tool to allocate resources")
public class TestAllocateResource extends AbstractShellCommand {
// TODO add support for other resource types
// FIXME provide a proper way to specify a lambda and lambda ranges
@Option(name = "-l", aliases = "--lambda",
description = "Lambda Resource to allocate",
required = false, multiValued = false)
private String lambda = "1";
@Option(name = "-i", aliases = "--intentId",
description = "IntentId to use for allocation",
required = false, multiValued = false)
private int nIntendId = 42;
@Argument(index = 0, name = "deviceIdString", description = "Device ID",
required = true, multiValued = false)
String deviceIdStr = null;
@Argument(index = 1, name = "portNumberString", description = "PortNumber",
required = true, multiValued = false)
String portNumberStr = null;
private ResourceService resourceService;
@Override
protected void execute() {
resourceService = get(ResourceService.class);
DeviceId did = DeviceId.deviceId(deviceIdStr);
PortNumber portNum = PortNumber.fromString(portNumberStr);
ResourceConsumer consumer = IntentId.valueOf(nIntendId);
ResourcePath resource = discrete(did, portNum,
createLambda(Integer.parseInt(lambda)));
Optional<ResourceAllocation> allocate = resourceService.allocate(consumer, resource);
if (allocate.isPresent()) {
print("Allocated: %s", allocate.get());
} else {
print("Failed to allocate %s for %s", resource, consumer);
}
}
private OchSignal createLambda(int i) {
return new OchSignal(GridType.FLEX,
ChannelSpacing.CHL_12P5GHZ,
i,
1);
}
}
......@@ -295,6 +295,29 @@
</completers>
</command>
<command>
<action class="org.onosproject.cli.net.ResourcesCommand"/>
<completers>
<ref component-id="deviceIdCompleter"/>
<ref component-id="portNumberCompleter"/>
</completers>
</command>
<command>
<action class="org.onosproject.cli.net.AllocationsCommand"/>
<completers>
<ref component-id="deviceIdCompleter"/>
<ref component-id="portNumberCompleter"/>
</completers>
</command>
<command>
<action class="org.onosproject.cli.net.TestAllocateResource"/>
<completers>
<ref component-id="deviceIdCompleter"/>
<ref component-id="portNumberCompleter"/>
</completers>
</command>
<!-- Should deprecate following 3 commands soon. -->
<command>
<action class="org.onosproject.cli.net.ResourceAllocationsCommand"/>
<completers>
<ref component-id="connectPointCompleter"/>
......@@ -487,6 +510,7 @@
<bean id="componentPropertyNameCompleter" class="org.onosproject.cli.cfg.ComponentPropertyNameCompleter"/>
<bean id="nodeIdCompleter" class="org.onosproject.cli.NodeIdCompleter"/>
<bean id="deviceIdCompleter" class="org.onosproject.cli.net.DeviceIdCompleter"/>
<bean id="portNumberCompleter" class="org.onosproject.cli.net.PortNumberCompleter"/>
<bean id="clusterIdCompleter" class="org.onosproject.cli.net.ClusterIdCompleter"/>
<bean id="roleCompleter" class="org.onosproject.cli.net.RoleCompleter"/>
<bean id="hostIdCompleter" class="org.onosproject.cli.net.HostIdCompleter"/>
......