package org.opennaas.extensions.router.junos.actionssets.actions.chassis; import static com.google.common.base.Strings.nullToEmpty; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; 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.protocol.IProtocolSession; import org.opennaas.core.resources.protocol.ProtocolException; import org.opennaas.extensions.router.junos.actionssets.ActionConstants; import org.opennaas.extensions.router.junos.actionssets.actions.JunosAction; import org.opennaas.extensions.router.junos.commandsets.commands.CommandNetconfConstants.TargetConfiguration; import org.opennaas.extensions.router.junos.commandsets.commands.EditNetconfCommand; import org.opennaas.extensions.router.junos.commandsets.commands.GetNetconfCommand; import org.opennaas.extensions.router.junos.commandsets.commands.JunosCommand; import org.opennaas.extensions.router.model.ComputerSystem; import org.opennaas.extensions.router.model.LogicalPort; import org.opennaas.extensions.router.model.NetworkPort; import org.opennaas.extensions.router.model.ProtocolEndpoint; import com.google.common.collect.Iterables; public class SetVlanIdAction extends JunosAction { private String getSubInterfaceTemplate = "/VM_files/getSubInterface.vm"; public SetVlanIdAction() { this.setActionID(ActionConstants.SET_VLANID); this.protocolName = "netconf"; } @Override public void executeListCommand(ActionResponse actionResponse, IProtocolSession protocol) throws ActionException { try { Response getInterfaceResponse = getInterfaceFromCandidate((LogicalPort) params, protocol); actionResponse.addResponse(getInterfaceResponse); if (getInterfaceResponse.getStatus().equals(Response.Status.OK)) { // Check params is in current candidate configuration // Not all interfaces are in config. // However, interfaces with tagged-ethernet should be, as they have something configured. checkInterfaceExists(getInterfaceResponse); // No need to check that params has tagged-ethernet encapsulation, router will fail if not. EditNetconfCommand command = new EditNetconfCommand(getVelocityMessage()); command.initialize(); actionResponse.addResponse(sendCommandToProtocol(command, protocol)); } validateAction(actionResponse); } catch (Exception e) { throw new ActionException(this.actionID + ": " + e.getMessage(), e); } } @Override public void parseResponse(Object responseMessage, Object model) throws ActionException { // Nothing to parse by now. GetConfigurationAction will do it at the end of each queue execution } @Override public boolean checkParams(Object params) throws ActionException { if (!(params instanceof NetworkPort)) { // this also assures it's a logical interface: // physical interfaces are of class LogicalPort // logical interfaces are of NetworkPort subclasses class. throw new ActionException("Invalid parameters type. A NetworkPort is expected"); } if (((NetworkPort) params).getName() == null || ((NetworkPort) params).getName().isEmpty()) throw new ActionException("Invalid parameter. A NetworkPort must have a name"); if (isLoopbackInterface((NetworkPort) params)) { throw new ActionException("Vlan configuration in loopback interfaces is not supported."); } if (!isValidVlanId(obtainDesiredVlanId((NetworkPort) params))) { throw new ActionException("Invalid vlanId. Valid range is [0, 4096)"); } return true; } @Override public void prepareMessage() throws ActionException { checkParams(params); setTemplateAccordingToParamsType((NetworkPort) params); String logicalRouterName = nullToEmpty(((ComputerSystem) modelToUpdate).getElementName()); Map<String, Object> extraParams = new HashMap<String, Object>(); extraParams.put("elementName", logicalRouterName); extraParams.put("vlanId", obtainDesiredVlanId((NetworkPort) params)); try { setVelocityMessage(prepareVelocityCommand(params, template, extraParams)); } catch (Exception e) { throw new ActionException(e); } } private boolean isValidVlanId(int vlanId) { // The IEEE 802.1Q (VLAN) label. // The 12-bit value in the 802.1Q header for Tagged Ethernet. return (vlanId > 0 && vlanId < 4096); } private boolean isEthernetInterface(LogicalPort iface) { return isEthernetInterfaceName(iface.getName()); } private boolean isLogicalTunnelInterface(LogicalPort iface) { return isLogicalTunnelInterfaceName(iface.getName()); } private boolean isLoopbackInterface(LogicalPort iface) { return isLoopbackInterfaceName(iface.getName()); } private boolean isEthernetInterfaceName(String interfaceName) { return (interfaceName.startsWith("ge") || interfaceName.startsWith("fe")); } private boolean isLogicalTunnelInterfaceName(String interfaceName) { return (interfaceName.startsWith("lt")); } private boolean isLoopbackInterfaceName(String interfaceName) { return (interfaceName.startsWith("lo")); } private int obtainDesiredVlanId(NetworkPort networkPort) throws ActionException { try { ProtocolEndpoint endpoint = Iterables.getOnlyElement(networkPort.getProtocolEndpoint()); return Integer.parseInt(endpoint.getName()); // endpoint name stores the encapsulation label (vlanId in this case) } catch (NoSuchElementException e) { throw new ActionException("Invalid parameter. A vlanId must be specified."); } } private void setTemplateAccordingToParamsType(LogicalPort params) throws ActionException { if (isLogicalTunnelInterface(params)) { setTemplate("/VM_files/setVlanId.vm"); } else if (isEthernetInterface(params)) { setTemplate("/VM_files/setVlanId.vm"); } else { throw new ActionException("Failed to determine Velocity template in Action " + getActionID()); } } private Response getInterfaceFromCandidate(LogicalPort iface, IProtocolSession protocol) throws ActionException, ProtocolException { String getInterfaceFilter = prepareGetInterfaceMessage(iface); JunosCommand getCommand = new GetNetconfCommand(getInterfaceFilter, TargetConfiguration.CANDIDATE); getCommand.initialize(); return sendCommandToProtocol(getCommand, protocol); } private String prepareGetInterfaceMessage(LogicalPort iface) throws ActionException { Map<String, Object> extraParams = new HashMap<String, Object>(); extraParams.put("elementName", nullToEmpty(((ComputerSystem) getModelToUpdate()).getElementName())); try { return prepareVelocityCommand(iface, getSubInterfaceTemplate, extraParams); } catch (Exception e) { throw new ActionException(e); } } private void checkInterfaceExists(Response getInterfaceResponse) throws ActionException { if (getInterfaceResponse.getInformation().equals("<configuration></configuration>")) { // an empty configuration means filter has failed throw new ActionException("Interface not found in this router"); } } }