/*
* Copyright (c) 2015 Huawei, Inc and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.nic.nemo.rpc;
import static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.condition.instance.ConditionSegment.ConditionParameterMatchPattern.LessThan;
import static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.condition.instance.ConditionSegment.ConditionParameterMatchPattern.NotLessThan;
import static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.condition.instance.ConditionSegment.PrecursorRelationOperator.And;
import static org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.condition.instance.ConditionSegment.PrecursorRelationOperator.None;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import org.joda.time.LocalTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.opendaylight.nic.nemo.renderer.NEMOIntentParser;
import org.opendaylight.nic.nemo.renderer.NEMOIntentParser.BandwidthOnDemandParameters;
import org.opendaylight.nic.nemo.renderer.NEMORenderer;
import org.opendaylight.yang.gen.v1.urn.opendaylight.intent.rev150122.intents.Intent;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.ActionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.ConditionParameterName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.ConditionSegmentId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.ConnectionId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.ConnectionName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.ConnectionType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.NodeId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.NodeName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.NodeType;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.OperationId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.common.rev151010.OperationName;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.CommonRpcResult;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.NemoIntentService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.StructureStyleNemoUpdateInput;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.StructureStyleNemoUpdateInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.Objects;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.ObjectsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.Operations;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.OperationsBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.objects.Connection;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.objects.ConnectionBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.objects.Node;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.objects.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.operations.Operation;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.user.intent.operations.OperationBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.intent.rev151010.users.User;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.object.rev151010.connection.instance.EndNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.object.rev151010.connection.instance.EndNodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.object.rev151010.node.instance.SubNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.action.instance.ParameterValuesBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.action.instance.parameter.values.IntValue;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.action.instance.parameter.values.IntValueBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.condition.instance.ConditionSegment;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.condition.instance.ConditionSegment.ConditionParameterMatchPattern;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.condition.instance.ConditionSegment.PrecursorRelationOperator;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.condition.instance.ConditionSegmentBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.condition.instance.condition.segment.ConditionParameterTargetValueBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.operation.instance.Action;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.nemo.operation.rev151010.operation.instance.ActionBuilder;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author gwu
*
*/
public class NemoUpdate implements NemoRpc {
private static final ActionName ACTION_QOS_BANDWIDTH = new ActionName("qos-bandwidth");
private static final ConnectionType P2P = new ConnectionType("p2p");
private static final NodeType L2_GROUP = new NodeType("l2-group");
private static final ConditionParameterName CONDITION_TIME = new ConditionParameterName("time");
private static final DateTimeFormatter timeFormatter = DateTimeFormat.forPattern("HH:mm:ss");
private static final Logger LOG = LoggerFactory.getLogger(NemoUpdate.class);
private final BandwidthOnDemandParameters params;
public NemoUpdate(Intent intent) {
BandwidthOnDemandParameters params0 = null;
try {
params0 = NEMOIntentParser.parseBandwidthOnDemand(intent);
} catch (Exception e) {
LOG.info("Unable to parse BoD intent", e);
}
params = params0;
}
public static StructureStyleNemoUpdateInput buildInput(final BandwidthOnDemandParameters params, final User user) {
List<Node> existingNodes = new ArrayList<>();
if (user.getObjects() != null && user.getObjects().getNode() != null) {
existingNodes.addAll(user.getObjects().getNode());
}
// convert parameters to StructureStyleNemoUpdateInput
// All this code just to do the following:
// CREATE Node <from> Type l2-group;
// CREATE Node <to> Type l2-group;
// CREATE Connection c1 Type p2p Endnodes <from>,<to>;
// CREATE Operation o1 Priority 2 Target c1 Condition time>=9&&time<18 Action qos-bandwidth <bandwidth>
Node nodeFrom = null;
Node nodeTo = null;
for (Node node : existingNodes) {
if (node.getNodeName().getValue().equals(params.from)) {
nodeFrom = node;
}
if (node.getNodeName().getValue().equals(params.to)) {
nodeTo = node;
}
}
List<Node> newNodes = new ArrayList<Node>();
if (nodeFrom == null) {
nodeFrom = node(params.from, L2_GROUP);
newNodes.add(nodeFrom);
}
if (nodeTo == null) {
nodeTo = node(params.to, L2_GROUP);
newNodes.add(nodeTo);
}
Connection connection = connection(P2P, Arrays.asList(nodeFrom, nodeTo));
List<Connection> connections = Arrays.asList(connection);
Objects objects = new ObjectsBuilder().setNode(newNodes).setConnection(connections).build();
LocalTime endTime = params.startTime.plus(params.duration);
ConditionSegment cs1 = condition(1L, None, CONDITION_TIME, NotLessThan,
params.startTime.toString(timeFormatter));
ConditionSegment cs2 = condition(2L, And, CONDITION_TIME, LessThan, endTime.toString(timeFormatter));
List<ConditionSegment> conditions = Arrays.asList(cs1, cs2);
Action action = action(1L, ACTION_QOS_BANDWIDTH, params.bandwidth);
List<Action> actions = Arrays.asList(action);
Operation op = operation(2L, connection.getConnectionId(), conditions, actions);
Operations operations = new OperationsBuilder().setOperation(Arrays.asList(op)).build();
return new StructureStyleNemoUpdateInputBuilder().setObjects(objects).setOperations(operations)
.setUserId(user.getUserId()).build();
}
private static Action action(long order, ActionName name, long value) {
IntValue v = new IntValueBuilder().setOrder(1L).setValue(value).build();
return new ActionBuilder().setActionName(name).setOrder(order)
.setParameterValues(new ParameterValuesBuilder().setIntValue(Arrays.asList(v)).build()).build();
}
private static Node node(String name, NodeType type) {
return new NodeBuilder().setNodeId(new NodeId(UUID.randomUUID().toString())).setNodeName(new NodeName(name))
.setNodeType(type).setSubNode(new ArrayList<SubNode>()).build();
}
private static List<EndNode> endNodes(List<Node> nodes) {
List<EndNode> endNodes = new ArrayList<>();
long i = 1;
for (Node node : nodes) {
endNodes.add(new EndNodeBuilder().setOrder(i).setNodeId(node.getNodeId()).build());
++i;
}
return endNodes;
}
private static Connection connection(ConnectionType type, List<Node> nodes) {
final String connectionId = UUID.randomUUID().toString();
List<EndNode> endNodes = endNodes(nodes);
Connection connection = new ConnectionBuilder().setConnectionId(new ConnectionId(connectionId))
.setConnectionName(new ConnectionName(NEMORenderer.NIC_PREFIX + connectionId)).setConnectionType(type)
.setEndNode(endNodes).build();
return connection;
}
private static ConditionSegment condition(long order, PrecursorRelationOperator relation,
ConditionParameterName parameterName, ConditionParameterMatchPattern matchPattern, String targetValue) {
return new ConditionSegmentBuilder()
.setOrder(order)
.setPrecursorRelationOperator(relation)
.setConditionSegmentId(new ConditionSegmentId(UUID.randomUUID().toString()))
.setConditionParameterName(parameterName)
.setConditionParameterMatchPattern(matchPattern)
.setConditionParameterTargetValue(
new ConditionParameterTargetValueBuilder().setStringValue(targetValue).build()).build();
}
private static Operation operation(long priority, ConnectionId target, List<ConditionSegment> conditions,
List<Action> actions) {
final String operationId = UUID.randomUUID().toString();
return new OperationBuilder().setOperationId(new OperationId(operationId))
.setOperationName(new OperationName(NEMORenderer.NIC_PREFIX + operationId)).setTargetObject(target)
.setPriority(priority).setConditionSegment(conditions).setAction(actions).build();
}
@Override
public RpcResult<? extends CommonRpcResult> apply(NemoIntentService nemoEngine, User user)
throws InterruptedException, ExecutionException {
if (params != null) {
StructureStyleNemoUpdateInput updateInput = buildInput(params, user);
return nemoEngine.structureStyleNemoUpdate(updateInput).get();
} else {
return null;
}
}
@Override
public boolean isInputValid() {
return params != null;
}
}