package org.opennaas.extensions.router.junos.actionssets.actions.linkaggregation;
/*
* #%L
* OpenNaaS :: Router :: Junos ActionSet
* %%
* Copyright (C) 2007 - 2014 FundaciĆ³ Privada i2CAT, Internet i InnovaciĆ³ a Catalunya
* %%
* 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.
* #L%
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.opennaas.core.resources.action.ActionException;
import org.opennaas.core.resources.action.ActionResponse;
import org.opennaas.core.resources.command.Response;
import org.opennaas.core.resources.helpers.XmlHelper;
import org.opennaas.core.resources.protocol.IProtocolSession;
import org.opennaas.extensions.router.capability.linkaggregation.LinkAggregationActionSet;
import org.opennaas.extensions.router.junos.actionssets.actions.JunosAction;
import org.opennaas.extensions.router.junos.commandsets.commands.CommandNetconfConstants;
import org.opennaas.extensions.router.junos.commandsets.commands.EditNetconfCommand;
import org.opennaas.extensions.router.model.AggregatedLogicalPort;
import org.opennaas.extensions.router.model.ComputerSystem;
import org.opennaas.extensions.router.model.NetworkPort;
import org.opennaas.extensions.router.model.utils.ModelHelper;
/**
* Implementation of LinkAggregationActionSet.CREATE_AGGRETATED_INTERFACE for junos 10.04 devices.
*
* Configures a new aggregated interface specified by given AggregatedLogicalPort.
*
* NOTICE: This action will fail if any interface in AggregatedLogicalPort.getInterfaces() contains subinterfaces (units). The router will launch
* following error: "logical unit is not allowed on aggregated links : unit XX". The user is forced to manually delete these subinterfaces in order to
* be able to put an interface as part of an aggregated.
*
* @author Isart Canyameres Gimenez (i2cat)
*/
public class CreateAggregatedInterfaceAction extends JunosAction {
/**
* The name of any aggregated interface in junos devices must start with this prefix
*/
public static final String JUNOS_AGGREGATED_INTERFACES_PREFIX = "ae";
private static final String CREATION_TEMPLATE = "/VM_files/createAggregatedInterface.vm";
private static final String ADD_TO_AGGREGATED_TEMPLATE = "/VM_files/addInterfaceToAggregated.vm";
private static final String REMOVE_UNIT_TEMPLATE = "/VM_files/removeInterfaceUnit.vm";
private AggregatedLogicalPort aggregator;
private boolean forceFlag = false;
public CreateAggregatedInterfaceAction() {
super();
setActionID(LinkAggregationActionSet.CREATE_AGGREGATED_INTERFACE);
this.protocolName = "netconf";
}
@Override
public boolean checkParams(Object params) throws ActionException {
Object[] paramsArray = (Object[]) params;
if (paramsArray.length != 2)
throw new ActionException("Invalid parameter in action " + actionID + ". Two parameters expected");
if (!(paramsArray[0] instanceof AggregatedLogicalPort)) {
throw new ActionException("Invalid parameter in action " + actionID + ". Expected AggregatedLogicalPort.");
}
if (!(paramsArray[1] instanceof Boolean)) {
throw new ActionException("Invalid parameter in action " + actionID + ". Expected Boolean.");
}
AggregatedLogicalPort aggregator = (AggregatedLogicalPort) paramsArray[0];
if (StringUtils.isEmpty(aggregator.getElementName()))
throw new ActionException("Invalid parameter in action " + actionID + "." +
" Missing AggregatedLogicalPort name.");
if (!aggregator.getElementName().startsWith(JUNOS_AGGREGATED_INTERFACES_PREFIX))
throw new ActionException("Invalid parameter in action " + actionID + "." +
" AggregatedLogicalPort name must begin with " + JUNOS_AGGREGATED_INTERFACES_PREFIX + " in junos.");
if (aggregator.getInterfaces() == null || aggregator.getInterfaces().isEmpty())
throw new ActionException("Invalid parameter in action " + actionID + "." +
" Given AggregatedLogicalPort must contain at least one interface to be aggregated.");
return true;
}
@Override
public void prepareMessage() throws ActionException {
checkParams(params);
Object[] paramsArray = (Object[]) params;
this.aggregator = (AggregatedLogicalPort) paramsArray[0];
this.forceFlag = ((Boolean) paramsArray[1]).booleanValue();
// Nothing to prepare
// Messages are prepared in executeListCommand
}
@Override
public void executeListCommand(ActionResponse actionResponse, IProtocolSession protocol) throws ActionException {
actionResponse.addResponse(execEditCommand(prepareCreateAggregatedInterfaceMessage(aggregator), protocol));
for (String interfaceName : aggregator.getInterfaces()) {
if (forceFlag) {
for (NetworkPort unitToClear : getInterfacesToRemove(interfaceName)) {
actionResponse.addResponse(execRemovingEditCommand(
prepareClearUnitMessage(interfaceName, unitToClear.getPortNumber()), protocol));
}
}
actionResponse.addResponse(execEditCommand(
prepareAddInterfaceToAggregatedMessage(interfaceName, aggregator.getElementName()), protocol));
}
validateAction(actionResponse);
}
@Override
public void parseResponse(Object responseMessage, Object model) throws ActionException {
// nothing to parse
}
/**
* Creates an xml message that configures given aggregated interface (aggregator). <br/>
* If given interface already exists, the operation will fail.
*
* @param aggregator
* @return
* @throws ActionException
*/
private String prepareCreateAggregatedInterfaceMessage(AggregatedLogicalPort aggregator) throws ActionException {
Map<String, Object> extraParams = prepareCreateAggregatedInterfaceExtraParams(aggregator);
try {
// FIXME passing unchecked values to junos (inside aggregator). May cause security issues.
return XmlHelper.formatXML(prepareVelocityCommand(aggregator, CREATION_TEMPLATE, extraParams));
} catch (Exception e) {
throw new ActionException(e);
}
}
/**
* Creates an xml message that configures given interfaceName to be part of given aggregatedInterfaceName.<br/>
* This operation replaces the aggregatedInterfaceName interfaceName is part of, despite the fact that ifaceName may be part of another
* aggregatedInterface before sending these message.
*
* @param interfaceName
* @param aggregatedInterfaceName
* @return
* @throws ActionException
*/
private String prepareAddInterfaceToAggregatedMessage(String interfaceName, String aggregatedInterfaceName) throws ActionException {
Map<String, Object> extraParams = prepareAddInterfaceToAggregatedExtraParams(interfaceName, aggregatedInterfaceName);
try {
// FIXME passing unchecked values to junos (interfaceName and inside extraParams). May cause security issues.
return XmlHelper.formatXML(prepareVelocityCommand(interfaceName, ADD_TO_AGGREGATED_TEMPLATE, extraParams));
} catch (Exception e) {
throw new ActionException(e);
}
}
private String prepareClearUnitMessage(String interfaceName, int portNumber) throws ActionException {
Map<String, Object> extraParams = prepareLRVelocityExtraParams();
extraParams.put("ifaceName", interfaceName);
extraParams.put("unitName", portNumber);
try {
// FIXME passing unchecked values to junos (interfaceName and inside extraParams). May cause security issues.
return XmlHelper.formatXML(prepareVelocityCommand(interfaceName, REMOVE_UNIT_TEMPLATE, extraParams));
} catch (Exception e) {
throw new ActionException(e);
}
}
/**
* Prepares extraParams for CREATION_TEMPLATE.<br/>
*
* Sets following params: <br/>
* - boolean setMinimumLinks <br/>
* - boolean setLinkSpeed <br/>
* - boolean isLR <br/>
* - String lrName <br/>
*
* See the template for more information.
*
* @param aggregator
* @return extraParams required for CREATION_TEMPLATE
*/
private Map<String, Object> prepareCreateAggregatedInterfaceExtraParams(AggregatedLogicalPort aggregator) {
Map<String, Object> extraParams = prepareLRVelocityExtraParams();
boolean setMinimumLinks = true;
if (StringUtils.isEmpty(aggregator.getAggregatedOptions().getMinimumLinks()))
setMinimumLinks = false;
boolean setLinkSpeed = true;
if (StringUtils.isEmpty(aggregator.getAggregatedOptions().getLinkSpeed()))
setLinkSpeed = false;
extraParams.put("setMinimumLinks", setMinimumLinks);
extraParams.put("setLinkSpeed", setLinkSpeed);
return extraParams;
}
/**
* Prepares extraParams for ADD_TO_AGGREGATED_TEMPLATE. <br/>
*
* Sets following params: <br/>
* - String aggregatedIfaceName <br/>
* - boolean isLR <br/>
* - String lrName <br/>
* See the template for more information.
*
* @param interfaceName
* the interface to be aggregated
* @param aggregatedInterfaceName
* the interface to aggregate to
* @return extraParams required for ADD_TO_AGGREGATED_TEMPLATE
*/
private Map<String, Object> prepareAddInterfaceToAggregatedExtraParams(String interfaceName, String aggregatedInterfaceName) {
Map<String, Object> extraParams = prepareLRVelocityExtraParams();
extraParams.put("ifaceName", interfaceName);
extraParams.put("aggregatedIfaceName", aggregatedInterfaceName);
return extraParams;
}
private Map<String, Object> prepareLRVelocityExtraParams() {
Map<String, Object> extraParams = new HashMap<String, Object>();
boolean isLR = isLogicalRouter((ComputerSystem) modelToUpdate);
extraParams.put("isLR", isLR);
if (isLR)
extraParams.put("lrName", getLogicalRouterName((ComputerSystem) modelToUpdate));
return extraParams;
}
private boolean isLogicalRouter(ComputerSystem system) {
if (system.getElementName() != null) {
return true;
}
return false;
}
private String getLogicalRouterName(ComputerSystem system) {
if (!isLogicalRouter(system))
return null;
return system.getElementName();
}
private Response execEditCommand(String netconfMsg, IProtocolSession protocol) throws ActionException {
try {
EditNetconfCommand command = new EditNetconfCommand(netconfMsg);
command.initialize();
return sendCommandToProtocol(command, protocol);
} catch (Exception e) {
throw new ActionException(this.actionID + ": " + e.getMessage(), e);
}
}
private Response execRemovingEditCommand(String netconfMsg, IProtocolSession protocol) throws ActionException {
try {
// when removing tags, none operation should be used as default
EditNetconfCommand command = new EditNetconfCommand(netconfMsg, CommandNetconfConstants.NONE_OPERATION);
command.initialize();
return sendCommandToProtocol(command, protocol);
} catch (Exception e) {
throw new ActionException(this.actionID + ": " + e.getMessage(), e);
}
}
private List<NetworkPort> getInterfacesToRemove(String interfaceName) {
List<NetworkPort> allPorts = ModelHelper.getInterfaces((ComputerSystem) modelToUpdate);
List<NetworkPort> filtered = new ArrayList<NetworkPort>();
for (NetworkPort port : allPorts) {
if (port.getName().equals(interfaceName))
filtered.add(port);
}
return filtered;
}
}