diff --git a/LICENSE.header b/LICENSE.header new file mode 100644 index 00000000000..4eacb643179 --- /dev/null +++ b/LICENSE.header @@ -0,0 +1,16 @@ +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you 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. diff --git a/plugins/network-elements/opendaylight/pom.xml b/plugins/network-elements/opendaylight/pom.xml new file mode 100644 index 00000000000..8c69b6ebe17 --- /dev/null +++ b/plugins/network-elements/opendaylight/pom.xml @@ -0,0 +1,132 @@ + + + 4.0.0 + cloud-plugin-network-opendaylight + Apache CloudStack Plugin - Network Opendaylight + + org.apache.cloudstack + cloudstack-plugins + 4.4.0-SNAPSHOT + ../../pom.xml + + + + + ${basedir}/src/main/java + ${basedir}/src/main/scripts + ${basedir}/src/test/java + ${basedir}/target/classes + ${basedir}/target/test-classes + + + ${basedir}/src/main/resources + + + + + ${basedir}/src/test/resources + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.apache.cloudstack + checkstyle + ${project.version} + + + + + process-classes + + check + + + + + true + tooling/checkstyle.xml + true + true + ${project.basedir} + **\/*.java,**\/*.xml,**\/*.ini,**\/*.sh,**\/*.bat + **\/target\/,**\/bin\/ + + + + com.mycila.maven-license-plugin + maven-license-plugin + 1.9.0 + + + process-classes + + format + + + + + true + true +
../../../LICENSE.header
+ + XML_STYLE +     DOUBLESLASH_STYLE +     SEMICOLON_STYLE + + false + + target/** + .settings/** + .checkstyle + .project + .classpath + +
+
+
+
+ + + integration + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + + + + +
diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightElement.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightElement.java new file mode 100644 index 00000000000..9761e744f6b --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightElement.java @@ -0,0 +1,174 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.ejb.Local; +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import org.apache.cloudstack.network.opendaylight.agent.commands.StartupOpenDaylightControllerCommand; + +import com.cloud.agent.api.StartupCommand; +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.network.Network; +import com.cloud.network.Network.Capability; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.element.ConnectivityProvider; +import com.cloud.network.element.NetworkElement; +import com.cloud.offering.NetworkOffering; +import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceStateAdapter; +import com.cloud.resource.ServerResource; +import com.cloud.resource.UnableDeleteHostException; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachineProfile; + +@Component +@Local(value = {NetworkElement.class, ConnectivityProvider.class}) +public class OpendaylightElement extends AdapterBase implements ConnectivityProvider, ResourceStateAdapter { + + private static final Logger s_logger = Logger.getLogger(OpendaylightElement.class); + private static final Map> s_capabilities = setCapabilities(); + + @Inject + ResourceManager resourceManager; + + @Override + public Map> getCapabilities() { + return s_capabilities; + } + + @Override + public Provider getProvider() { + return Provider.Opendaylight; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + boolean configured = super.configure(name, params); + if (configured) + resourceManager.registerResourceStateAdapter(name, this); + return configured; + } + + @Override + public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, + ResourceUnavailableException, InsufficientCapacityException { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, + ResourceUnavailableException, InsufficientCapacityException { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, + ResourceUnavailableException { + // TODO Auto-generated method stub + return true; + } + + @Override + public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { + return true; + } + + @Override + public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return true; + } + + @Override + public boolean isReady(PhysicalNetworkServiceProvider provider) { + return true; + } + + @Override + public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, + ResourceUnavailableException { + return true; + } + + @Override + public boolean canEnableIndividualServices() { + return false; + } + + @Override + public boolean verifyServicesCombination(Set services) { + if (services.contains(Service.Connectivity) && services.size() == 1) + return true; + return false; + } + + @Override + public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] startup) { + if (!(startup[0] instanceof StartupOpenDaylightControllerCommand)) { + return null; + } + throw new CloudRuntimeException("createHostVOForConnectedAgent is not implemented for OpendaylightElement"); + } + + @Override + public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map details, List hostTags) { + if (!(startup[0] instanceof StartupOpenDaylightControllerCommand)) { + return null; + } + host.setType(Host.Type.L2Networking); + return host; + } + + @Override + public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { + return new DeleteHostAnswer(true); + } + + private static Map> setCapabilities() { + Map> capabilities = new HashMap>(); + + // L2 Support : SDN provisioning + capabilities.put(Service.Connectivity, null); + + return capabilities; + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightGuestNetworkGuru.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightGuestNetworkGuru.java new file mode 100644 index 00000000000..0b547e76f18 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/OpendaylightGuestNetworkGuru.java @@ -0,0 +1,276 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight; + +import java.util.List; +import java.util.UUID; + +import javax.inject.Inject; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.network.opendaylight.agent.commands.AddHypervisorCommand; +import org.apache.cloudstack.network.opendaylight.agent.commands.ConfigureNetworkCommand; +import org.apache.cloudstack.network.opendaylight.agent.commands.ConfigurePortCommand; +import org.apache.cloudstack.network.opendaylight.agent.commands.DestroyNetworkCommand; +import org.apache.cloudstack.network.opendaylight.agent.commands.DestroyPortCommand; +import org.apache.cloudstack.network.opendaylight.agent.responses.AddHypervisorAnswer; +import org.apache.cloudstack.network.opendaylight.agent.responses.ConfigureNetworkAnswer; +import org.apache.cloudstack.network.opendaylight.agent.responses.ConfigurePortAnswer; +import org.apache.cloudstack.network.opendaylight.agent.responses.DestroyNetworkAnswer; +import org.apache.cloudstack.network.opendaylight.agent.responses.DestroyPortAnswer; +import org.apache.cloudstack.network.opendaylight.dao.OpenDaylightControllerMappingDao; +import org.apache.cloudstack.network.opendaylight.dao.OpenDaylightControllerVO; + +import com.cloud.agent.AgentManager; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenter.NetworkType; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapcityException; +import com.cloud.network.Network; +import com.cloud.network.Network.GuestType; +import com.cloud.network.Network.Provider; +import com.cloud.network.Network.Service; +import com.cloud.network.Network.State; +import com.cloud.network.NetworkModel; +import com.cloud.network.NetworkProfile; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PhysicalNetwork.IsolationMethod; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.guru.GuestNetworkGuru; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.Account; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachineProfile; + +public class OpendaylightGuestNetworkGuru extends GuestNetworkGuru { + private static final Logger s_logger = Logger.getLogger(OpendaylightGuestNetworkGuru.class); + + @Inject + protected NetworkOfferingServiceMapDao ntwkOfferingSrvcDao; + @Inject + PhysicalNetworkDao physicalNetworkDao; + @Inject + OpenDaylightControllerMappingDao openDaylightControllerMappingDao; + @Inject + NetworkModel networkModel; + @Inject + AgentManager agentManager; + @Inject + NetworkDao networkDao; + + public OpendaylightGuestNetworkGuru() { + _isolationMethods = new IsolationMethod[] {IsolationMethod.ODL}; + } + + @Override + protected boolean canHandle(NetworkOffering offering, NetworkType networkType, PhysicalNetwork physicalNetwork) { + if (networkType == NetworkType.Advanced && isMyTrafficType(offering.getTrafficType()) && offering.getGuestType() == Network.GuestType.Isolated && + isMyIsolationMethod(physicalNetwork) && ntwkOfferingSrvcDao.areServicesSupportedByNetworkOffering(offering.getId(), Service.Connectivity) + && ntwkOfferingSrvcDao.isProviderForNetworkOffering(offering.getId(), Provider.Opendaylight)) { + return true; + } else { + s_logger.trace("We only take care of Guest networks of type " + GuestType.Isolated + " in zone of type " + NetworkType.Advanced); + return false; + } + } + + @Override + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + PhysicalNetworkVO physnet = physicalNetworkDao.findById(plan.getPhysicalNetworkId()); + DataCenter dc = _dcDao.findById(plan.getDataCenterId()); + if (!canHandle(offering, dc.getNetworkType(), physnet)) { + s_logger.debug("Refusing to design this network"); + return null; + } + + List devices = openDaylightControllerMappingDao.listByPhysicalNetwork(physnet.getId()); + if (devices.isEmpty()) { + s_logger.error("No Controller on physical network " + physnet.getName()); + return null; + } + s_logger.debug("Controller " + devices.get(0).getUuid() + " found on physical network " + physnet.getId()); + s_logger.debug("Physical isolation type is ODL, asking GuestNetworkGuru to design this network"); + + NetworkVO networkObject = (NetworkVO)super.design(offering, plan, userSpecified, owner); + if (networkObject == null) { + return null; + } + // Override the broadcast domain type + networkObject.setBroadcastDomainType(BroadcastDomainType.OpenDaylight); + + return networkObject; + } + + @Override + public Network implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws InsufficientVirtualNetworkCapcityException { + assert (network.getState() == State.Implementing) : "Why are we implementing " + network; + + long dcId = dest.getDataCenter().getId(); + + //get physical network id + Long physicalNetworkId = network.getPhysicalNetworkId(); + + // physical network id can be null in Guest Network in Basic zone, so locate the physical network + if (physicalNetworkId == null) { + physicalNetworkId = networkModel.findPhysicalNetworkId(dcId, offering.getTags(), offering.getTrafficType()); + } + + NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), network.getBroadcastDomainType(), network.getNetworkOfferingId(), State.Allocated, + network.getDataCenterId(), physicalNetworkId); + + if (network.getGateway() != null) { + implemented.setGateway(network.getGateway()); + } + + if (network.getCidr() != null) { + implemented.setCidr(network.getCidr()); + } + + // Name is either the given name or the uuid + String name = network.getName(); + if (name == null || name.isEmpty()) { + name = ((NetworkVO)network).getUuid(); + } + + List devices = openDaylightControllerMappingDao.listByPhysicalNetwork(physicalNetworkId); + if (devices.isEmpty()) { + s_logger.error("No Controller on physical network " + physicalNetworkId); + return null; + } + OpenDaylightControllerVO controller = devices.get(0); + + ConfigureNetworkCommand cmd = new ConfigureNetworkCommand(name, context.getAccount().getAccountName()); + ConfigureNetworkAnswer answer = (ConfigureNetworkAnswer)agentManager.easySend(controller.getHostId(), cmd); + + if (answer == null || !answer.getResult()) { + s_logger.error("ConfigureNetworkCommand failed"); + return null; + } + + implemented.setBroadcastUri(BroadcastDomainType.OpenDaylight.toUri(answer.getNetworkUuid())); + implemented.setBroadcastDomainType(BroadcastDomainType.OpenDaylight); + s_logger.info("Implemented OK, network linked to = " + implemented.getBroadcastUri().toString()); + + return implemented; + } + + @Override + public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) + throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException { + super.reserve(nic, network, vm, dest, context); + + //get physical network id + Long physicalNetworkId = network.getPhysicalNetworkId(); + + List devices = openDaylightControllerMappingDao.listByPhysicalNetwork(physicalNetworkId); + if (devices.isEmpty()) { + s_logger.error("No Controller on physical network " + physicalNetworkId); + throw new InsufficientVirtualNetworkCapcityException("No OpenDaylight Controller configured for this network", dest.getPod().getId()); + } + OpenDaylightControllerVO controller = devices.get(0); + + AddHypervisorCommand addCmd = new AddHypervisorCommand(dest.getHost().getUuid(), dest.getHost().getPrivateIpAddress()); + AddHypervisorAnswer addAnswer = (AddHypervisorAnswer)agentManager.easySend(controller.getHostId(), addCmd); + if (addAnswer == null || !addAnswer.getResult()) { + s_logger.error("Failed to add " + dest.getHost().getName() + " as a node to the controller"); + throw new InsufficientVirtualNetworkCapcityException("Failed to add destination hypervisor to the OpenDaylight Controller", dest.getPod().getId()); + } + + ConfigurePortCommand cmd = new ConfigurePortCommand(UUID.fromString(nic.getUuid()), UUID.fromString(BroadcastDomainType.getValue(network.getBroadcastUri())), context + .getAccount().getAccountName(), nic.getMacAddress()); + ConfigurePortAnswer answer = (ConfigurePortAnswer)agentManager.easySend(controller.getHostId(), cmd); + + if (answer == null || !answer.getResult()) { + s_logger.error("ConfigureNetworkCommand failed"); + throw new InsufficientVirtualNetworkCapcityException("Failed to configure the port on the OpenDaylight Controller", dest.getPod().getId()); + } + + } + + @Override + public boolean release(NicProfile nic, VirtualMachineProfile vm, String reservationId) { + boolean success = super.release(nic, vm, reservationId); + + if (success) { + //get physical network id + NetworkVO network = _networkDao.findById(nic.getNetworkId()); + Long physicalNetworkId = network.getPhysicalNetworkId(); + + List devices = openDaylightControllerMappingDao.listByPhysicalNetwork(physicalNetworkId); + if (devices.isEmpty()) { + s_logger.error("No Controller on physical network " + physicalNetworkId); + throw new CloudRuntimeException("No OpenDaylight controller on this physical network"); + } + OpenDaylightControllerVO controller = devices.get(0); + + DestroyPortCommand cmd = new DestroyPortCommand(UUID.fromString(nic.getUuid())); + DestroyPortAnswer answer = (DestroyPortAnswer)agentManager.easySend(controller.getHostId(), cmd); + + if (answer == null || !answer.getResult()) { + s_logger.error("DestroyPortCommand failed"); + success = false; + } + } + + return success; + } + + @Override + public void shutdown(NetworkProfile profile, NetworkOffering offering) { + NetworkVO networkObject = networkDao.findById(profile.getId()); + if (networkObject.getBroadcastDomainType() != BroadcastDomainType.OpenDaylight || networkObject.getBroadcastUri() == null) { + s_logger.warn("BroadcastUri is empty or incorrect for guestnetwork " + networkObject.getDisplayText()); + return; + } + + List devices = openDaylightControllerMappingDao.listByPhysicalNetwork(networkObject.getPhysicalNetworkId()); + if (devices.isEmpty()) { + s_logger.error("No Controller on physical network " + networkObject.getPhysicalNetworkId()); + return; + } + OpenDaylightControllerVO controller = devices.get(0); + + DestroyNetworkCommand cmd = new DestroyNetworkCommand(BroadcastDomainType.getValue(networkObject.getBroadcastUri())); + DestroyNetworkAnswer answer = (DestroyNetworkAnswer)agentManager.easySend(controller.getHostId(), cmd); + + if (answer == null || !answer.getResult()) { + s_logger.error("DestroyNetworkCommand failed"); + } + + super.shutdown(profile, offering); + } + + @Override + public boolean trash(Network network, NetworkOffering offering) { + // TODO Auto-generated method stub + return super.trash(network, offering); + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/OpenDaylightControllerResource.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/OpenDaylightControllerResource.java new file mode 100644 index 00000000000..5c1e1e4ba2e --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/OpenDaylightControllerResource.java @@ -0,0 +1,321 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent; + +import java.net.MalformedURLException; +import java.net.URL; +import java.security.InvalidParameterException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; + +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.network.opendaylight.agent.commands.AddHypervisorCommand; +import org.apache.cloudstack.network.opendaylight.agent.commands.ConfigureNetworkCommand; +import org.apache.cloudstack.network.opendaylight.agent.commands.ConfigurePortCommand; +import org.apache.cloudstack.network.opendaylight.agent.commands.DestroyNetworkCommand; +import org.apache.cloudstack.network.opendaylight.agent.commands.DestroyPortCommand; +import org.apache.cloudstack.network.opendaylight.agent.commands.StartupOpenDaylightControllerCommand; +import org.apache.cloudstack.network.opendaylight.agent.responses.AddHypervisorAnswer; +import org.apache.cloudstack.network.opendaylight.agent.responses.ConfigureNetworkAnswer; +import org.apache.cloudstack.network.opendaylight.agent.responses.ConfigurePortAnswer; +import org.apache.cloudstack.network.opendaylight.agent.responses.DestroyNetworkAnswer; +import org.apache.cloudstack.network.opendaylight.agent.responses.DestroyPortAnswer; +import org.apache.cloudstack.network.opendaylight.api.NeutronRestApiException; +import org.apache.cloudstack.network.opendaylight.api.model.NeutronNetwork; +import org.apache.cloudstack.network.opendaylight.api.model.NeutronNetworkWrapper; +import org.apache.cloudstack.network.opendaylight.api.model.NeutronNode; +import org.apache.cloudstack.network.opendaylight.api.model.NeutronNodeWrapper; +import org.apache.cloudstack.network.opendaylight.api.model.NeutronNodesList; +import org.apache.cloudstack.network.opendaylight.api.model.NeutronPort; +import org.apache.cloudstack.network.opendaylight.api.model.NeutronPortWrapper; +import org.apache.cloudstack.network.opendaylight.api.resources.NeutronNetworksNorthboundAction; +import org.apache.cloudstack.network.opendaylight.api.resources.NeutronNodesNorthboundAction; +import org.apache.cloudstack.network.opendaylight.api.resources.NeutronPortsNorthboundAction; + +import com.cloud.agent.IAgentControl; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.MaintainAnswer; +import com.cloud.agent.api.MaintainCommand; +import com.cloud.agent.api.PingCommand; +import com.cloud.agent.api.ReadyAnswer; +import com.cloud.agent.api.ReadyCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.host.Host; +import com.cloud.host.Host.Type; +import com.cloud.resource.ServerResource; + +public class OpenDaylightControllerResource implements ServerResource { + private static final Logger s_logger = Logger.getLogger(OpenDaylightControllerResource.class); + private Map configuration = new HashMap(); + + private URL controllerUrl; + private String controllerUsername; + private String controllerPassword; + + private int runLevel; + + @Override + public String getName() { + if (configuration.containsKey("name")) + return (String)configuration.get("name"); + else + return null; + } + + @Override + public void setName(String name) { + configuration.put("name", name); + } + + @Override + public void setConfigParams(Map params) { + for (Entry entry : params.entrySet()) { + configuration.put(entry.getKey(), entry.getValue()); + } + updateConfiguration(); + } + + @Override + public Map getConfigParams() { + return Collections.unmodifiableMap(configuration); + } + + @Override + public int getRunLevel() { + return runLevel; + } + + @Override + public void setRunLevel(int level) { + runLevel = level; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + for (Entry entry : params.entrySet()) { + configuration.put(entry.getKey(), entry.getValue()); + } + updateConfiguration(); + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public Type getType() { + return Type.L2Networking; + } + + @Override + public StartupCommand[] initialize() { + StartupOpenDaylightControllerCommand sc = new StartupOpenDaylightControllerCommand(); + sc.setGuid((String)configuration.get("guid")); + sc.setName(getName()); + sc.setDataCenter((String)configuration.get("zoneId")); + sc.setPod(""); + sc.setPrivateIpAddress(""); + sc.setStorageIpAddress(""); + sc.setVersion(OpenDaylightControllerResource.class.getPackage().getImplementationVersion()); + return new StartupCommand[] {sc}; + + } + + @Override + public PingCommand getCurrentStatus(long id) { + return new PingCommand(Host.Type.L2Networking, id); + } + + @Override + public Answer executeRequest(Command cmd) { + if (cmd instanceof ConfigureNetworkCommand) { + return executeRequest((ConfigureNetworkCommand)cmd); + } else if (cmd instanceof DestroyNetworkCommand) { + return executeRequest((DestroyNetworkCommand)cmd); + } else if (cmd instanceof ConfigurePortCommand) { + return executeRequest((ConfigurePortCommand)cmd); + } else if (cmd instanceof DestroyPortCommand) { + return executeRequest((DestroyPortCommand)cmd); + } else if (cmd instanceof AddHypervisorCommand) { + return executeRequest((AddHypervisorCommand)cmd); + } else if (cmd instanceof ReadyCommand) { + return executeRequest((ReadyCommand)cmd); + } else if (cmd instanceof MaintainCommand) { + return executeRequest((MaintainCommand)cmd); + } else { + return Answer.createUnsupportedCommandAnswer(cmd); + } + } + + @Override + public void disconnected() { + s_logger.warn("OpenDaylightControllerResource is disconnected from the controller at " + controllerUrl); + + } + + @Override + public IAgentControl getAgentControl() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setAgentControl(IAgentControl agentControl) { + // TODO Auto-generated method stub + + } + + private Answer executeRequest(final ReadyCommand cmd) { + return new ReadyAnswer(cmd); + } + + private Answer executeRequest(final MaintainCommand cmd) { + return new MaintainAnswer(cmd); + } + + private Answer executeRequest(ConfigureNetworkCommand cmd) { + NeutronNetworksNorthboundAction configureNetwork = new NeutronNetworksNorthboundAction(controllerUrl, controllerUsername, controllerPassword); + NeutronNetwork newNetwork = new NeutronNetwork(); + + // Configuration from the command + newNetwork.setName(cmd.getName()); + newNetwork.setTenantId(cmd.getTenantId()); + + // Static configuation + newNetwork.setNetworkType("gre"); + newNetwork.setShared(false); + newNetwork.setSegmentationId(100); + newNetwork.setId(UUID.randomUUID()); + + NeutronNetworkWrapper wrapper = new NeutronNetworkWrapper(); + wrapper.setNetwork(newNetwork); + try { + wrapper = configureNetwork.createNeutronNetwork(wrapper); + } catch (NeutronRestApiException e) { + s_logger.error("createNeutronNetwork failed", e); + return new ConfigureNetworkAnswer(cmd, e); + } + + return new ConfigureNetworkAnswer(cmd, true, null, wrapper.getNetwork().getId().toString()); + } + + private Answer executeRequest(DestroyNetworkCommand cmd) { + NeutronNetworksNorthboundAction configureNetwork = new NeutronNetworksNorthboundAction(controllerUrl, controllerUsername, controllerPassword); + try { + configureNetwork.deleteNeutronNetwork(cmd.getNetworkUuid()); + } catch (NeutronRestApiException e) { + s_logger.error("deleteNeutronNetwork failed", e); + return new DestroyNetworkAnswer(cmd, e); + } + + return new DestroyNetworkAnswer(cmd, true, "Network " + cmd.getNetworkUuid() + " deleted"); + } + + private Answer executeRequest(ConfigurePortCommand cmd) { + NeutronPortsNorthboundAction configurePort = new NeutronPortsNorthboundAction(controllerUrl, controllerUsername, controllerPassword); + NeutronPort newPort = new NeutronPort(); + + // Configuration from the command + newPort.setId(cmd.getPortId()); + newPort.setTenantId(cmd.getTennantId()); + newPort.setAdminStateUp(true); + newPort.setName(cmd.getPortId().toString()); + newPort.setNetworkId(cmd.getNetworkId()); + newPort.setMacAddress(cmd.getMacAddress()); + newPort.setDeviceId(UUID.randomUUID()); + + // Static valus + newPort.setStatus("ACTIVE"); + newPort.setFixedIps(Collections. emptyList()); + + NeutronPortWrapper portWrapper = new NeutronPortWrapper(); + portWrapper.setPort(newPort); + try { + portWrapper = configurePort.createNeutronPort(portWrapper); + } catch (NeutronRestApiException e) { + s_logger.error("createPortCommand failed", e); + return new ConfigurePortAnswer(cmd, e); + } + + return new ConfigurePortAnswer(cmd, true, "Port " + portWrapper.getPort().getId().toString() + " created"); + + } + + private Answer executeRequest(DestroyPortCommand cmd) { + NeutronPortsNorthboundAction configurePort = new NeutronPortsNorthboundAction(controllerUrl, controllerUsername, controllerPassword); + try { + configurePort.deleteNeutronPort(cmd.getPortId().toString()); + } catch (NeutronRestApiException e) { + s_logger.error("deleteNeutronPort failed", e); + return new DestroyPortAnswer(cmd, e); + } + + return new DestroyPortAnswer(cmd, true, "Port " + cmd.getPortId().toString() + " deleted"); + } + + private Answer executeRequest(AddHypervisorCommand cmd) { + NeutronNodesNorthboundAction nodeActions = new NeutronNodesNorthboundAction(controllerUrl, controllerUsername, controllerPassword); + try { + NeutronNodesList nodes = nodeActions.listAllNodes(); + if (nodes.getNodes() != null) { + for (NeutronNodeWrapper nodeWrapper : nodes.getNodes()) { + NeutronNode node = nodeWrapper.getNode(); + if (node.getId().equals(cmd.getHostId())) { + return new AddHypervisorAnswer(cmd, true, "Hypervisor already connected"); + } + } + } + + // Not found in the existing node list, add it + nodeActions.updateNeutronNodeV2("OVS", cmd.getHostId(), cmd.getIpAddress(), 6640); + } catch (NeutronRestApiException e) { + s_logger.error("Call to OpenDaylight failed", e); + return new AddHypervisorAnswer(cmd, e); + } + return new AddHypervisorAnswer(cmd, true, "Hypervisor " + cmd.getHostId() + " added"); + } + + private void updateConfiguration() { + if (!configuration.containsKey("url") || !configuration.containsKey("username") || !configuration.containsKey("password")) + throw new InvalidParameterException("OpenDaylightControllerResource needs a url, username and password."); + try { + controllerUrl = new URL((String)configuration.get("url")); + } catch (MalformedURLException e) { + throw new InvalidParameterException("OpenDaylightControllerResource found an invalid controller url"); + } + controllerUsername = (String)configuration.get("username"); + controllerPassword = (String)configuration.get("password"); + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/OpenDaylightControllerResourceManager.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/OpenDaylightControllerResourceManager.java new file mode 100644 index 00000000000..1bc0e82a82a --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/OpenDaylightControllerResourceManager.java @@ -0,0 +1,34 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent; + +import org.apache.cloudstack.network.opendaylight.api.commands.AddOpenDaylightControllerCmd; +import org.apache.cloudstack.network.opendaylight.api.commands.DeleteOpenDaylightControllerCmd; +import org.apache.cloudstack.network.opendaylight.dao.OpenDaylightControllerVO; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.component.PluggableService; + +public interface OpenDaylightControllerResourceManager extends PluggableService { + + public OpenDaylightControllerVO addController(AddOpenDaylightControllerCmd cmd); + + public void deleteController(DeleteOpenDaylightControllerCmd cmd) throws InvalidParameterValueException; +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/OpenDaylightControllerResourceManagerImpl.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/OpenDaylightControllerResourceManagerImpl.java new file mode 100644 index 00000000000..ad4db158900 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/OpenDaylightControllerResourceManagerImpl.java @@ -0,0 +1,173 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice; +import org.apache.cloudstack.network.opendaylight.api.commands.AddOpenDaylightControllerCmd; +import org.apache.cloudstack.network.opendaylight.api.commands.DeleteOpenDaylightControllerCmd; +import org.apache.cloudstack.network.opendaylight.dao.OpenDaylightControllerMappingDao; +import org.apache.cloudstack.network.opendaylight.dao.OpenDaylightControllerVO; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceState; +import com.cloud.resource.ServerResource; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.exception.CloudRuntimeException; + +public class OpenDaylightControllerResourceManagerImpl implements OpenDaylightControllerResourceManager { + private final static Logger s_logger = Logger.getLogger(OpenDaylightControllerResourceManagerImpl.class); + + @Inject + HostDao hostDao; + @Inject + ResourceManager resourceManager; + @Inject + PhysicalNetworkDao physicalNetworkDao; + @Inject + PhysicalNetworkServiceProviderDao physicalNetworkServiceProviderDao; + @Inject + OpenDaylightControllerMappingDao openDaylightControllerMappingDao; + @Inject + NetworkDao networkDao; + + @Override + public List> getCommands() { + List> commands = new ArrayList>(); + commands.add(AddOpenDaylightControllerCmd.class); + return commands; + } + + @Override + public OpenDaylightControllerVO addController(AddOpenDaylightControllerCmd cmd) { + ServerResource odlController = new OpenDaylightControllerResource(); + + final String deviceName = NetworkDevice.OpenDaylightController.getName(); + NetworkDevice networkDevice = NetworkDevice.getNetworkDevice(deviceName); + final Long physicalNetworkId = cmd.getPhysicalNetworkId(); + PhysicalNetworkVO physicalNetwork = physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork == null) { + throw new InvalidParameterValueException("Could not find phyical network with ID: " + physicalNetworkId); + } + long zoneId = physicalNetwork.getDataCenterId(); + + final PhysicalNetworkServiceProviderVO ntwkSvcProvider = physicalNetworkServiceProviderDao.findByServiceProvider(physicalNetwork.getId(), + networkDevice.getNetworkServiceProvder()); + if (ntwkSvcProvider == null) { + throw new CloudRuntimeException("Network Service Provider: " + networkDevice.getNetworkServiceProvder() + " is not enabled in the physical network: " + + physicalNetworkId + "to add this device"); + } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) { + throw new CloudRuntimeException("Network Service Provider: " + ntwkSvcProvider.getProviderName() + " is in shutdown state in the physical network: " + + physicalNetworkId + "to add this device"); + } + + final Map hostParams = new HashMap(); + hostParams.put("guid", UUID.randomUUID().toString()); + hostParams.put("zoneId", String.valueOf(physicalNetwork.getDataCenterId())); + hostParams.put("physicalNetworkId", String.valueOf(physicalNetwork.getId())); + hostParams.put("name", "ODL Controller - " + hostParams.get("guid")); + hostParams.put("url", cmd.getUrl()); + hostParams.put("username", cmd.getUsername()); + hostParams.put("password", cmd.getPassword()); + + Map hostdetails = new HashMap(); + hostdetails.putAll(hostParams); + + try { + odlController.configure(hostParams.get("name"), hostdetails); + final Host host = resourceManager.addHost(zoneId, odlController, Host.Type.L2Networking, hostParams); + if (host != null) { + return Transaction.execute(new TransactionCallback() { + @Override + public OpenDaylightControllerVO doInTransaction(TransactionStatus status) { + OpenDaylightControllerVO controller = new OpenDaylightControllerVO(host.getId(), physicalNetworkId, ntwkSvcProvider.getProviderName(), hostParams + .get("name")); + openDaylightControllerMappingDao.persist(controller); + return controller; + } + }); + } else { + throw new CloudRuntimeException("Failed to create host object for ODL Controller"); + } + } catch (ConfigurationException e) { + throw new CloudRuntimeException("Failed to add ODL Controller as a resource", e); + } + } + + @Override + public void deleteController(DeleteOpenDaylightControllerCmd cmd) throws InvalidParameterValueException { + OpenDaylightControllerVO controller = openDaylightControllerMappingDao.findById(cmd.getId()); + if (controller == null) { + throw new InvalidParameterValueException("No ODL Controller with id " + cmd.getId()); + } + + // Find the physical network we work for + Long physicalNetworkId = controller.getPhysicalNetworkId(); + PhysicalNetworkVO physicalNetwork = physicalNetworkDao.findById(physicalNetworkId); + if (physicalNetwork != null) { + // Lets see if there are networks that use us + List networkList = networkDao.listByPhysicalNetwork(physicalNetworkId); + + // Networks with broadcast type lswitch are ours + for (NetworkVO network : networkList) { + if (network.getBroadcastDomainType() == Networks.BroadcastDomainType.OpenDaylight) { + if ((network.getState() != Network.State.Shutdown) && (network.getState() != Network.State.Destroy)) { + throw new CloudRuntimeException("This Controller can not be deleted as there are one or more logical networks provisioned by cloudstack."); + } + } + } + } + + HostVO host = hostDao.findById(controller.getHostId()); + Long hostId = host.getId(); + + host.setResourceState(ResourceState.Maintenance); + hostDao.update(hostId, host); + resourceManager.deleteHost(hostId, false, false); + + openDaylightControllerMappingDao.remove(cmd.getId()); + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/AddHypervisorCommand.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/AddHypervisorCommand.java new file mode 100644 index 00000000000..06e94b35390 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/AddHypervisorCommand.java @@ -0,0 +1,58 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.commands; + +import com.cloud.agent.api.Command; + +public class AddHypervisorCommand extends Command { + private String hostId; + private String ipAddress; + + public AddHypervisorCommand() { + } + + public AddHypervisorCommand(String hostId, String ipAddress) { + this.hostId = hostId; + this.ipAddress = ipAddress; + } + + public String getHostId() { + return hostId; + } + + public void setHostId(String hostId) { + this.hostId = hostId; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + @Override + public boolean executeInSequence() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/ConfigureNetworkCommand.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/ConfigureNetworkCommand.java new file mode 100644 index 00000000000..bfbcde4ca43 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/ConfigureNetworkCommand.java @@ -0,0 +1,54 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.commands; + +import com.cloud.agent.api.Command; + +public class ConfigureNetworkCommand extends Command { + private String name; + private String tenantId; + + public ConfigureNetworkCommand(String name, String tenantId) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getTenantId() { + return tenantId; + } + + public void setTenantId(String tennantId) { + tenantId = tennantId; + } + + @Override + public boolean executeInSequence() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/ConfigurePortCommand.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/ConfigurePortCommand.java new file mode 100644 index 00000000000..3d4d2a2a69a --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/ConfigurePortCommand.java @@ -0,0 +1,80 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.commands; + +import java.util.UUID; + +import com.cloud.agent.api.Command; + +public class ConfigurePortCommand extends Command { + private UUID networkId; + private String tennantId; + private String macAddress; + private UUID portId; + + public ConfigurePortCommand() { + } + + public ConfigurePortCommand(UUID portId, UUID networkId, String tennantId, String macAddress) { + this.portId = portId; + this.networkId = networkId; + this.tennantId = tennantId; + this.macAddress = macAddress; + } + + public UUID getNetworkId() { + return networkId; + } + + public void setNetworkId(UUID networkId) { + this.networkId = networkId; + } + + public String getTennantId() { + return tennantId; + } + + public void setTennantId(String tennantId) { + this.tennantId = tennantId; + } + + public String getMacAddress() { + return macAddress; + } + + public void setMacAddress(String macAddress) { + this.macAddress = macAddress; + } + + public UUID getPortId() { + return portId; + } + + public void setPortId(UUID portId) { + this.portId = portId; + } + + @Override + public boolean executeInSequence() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/DestroyNetworkCommand.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/DestroyNetworkCommand.java new file mode 100644 index 00000000000..6d1bc044315 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/DestroyNetworkCommand.java @@ -0,0 +1,45 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.commands; + +import com.cloud.agent.api.Command; + +public class DestroyNetworkCommand extends Command { + private String networkUuid; + + public DestroyNetworkCommand(String networkUuid) { + this.networkUuid = networkUuid; + } + + public String getNetworkUuid() { + return networkUuid; + } + + public void setNetworkUuid(String networkUuid) { + this.networkUuid = networkUuid; + } + + @Override + public boolean executeInSequence() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/DestroyPortCommand.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/DestroyPortCommand.java new file mode 100644 index 00000000000..c0a89371c1a --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/DestroyPortCommand.java @@ -0,0 +1,50 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.commands; + +import java.util.UUID; + +import com.cloud.agent.api.Command; + +public class DestroyPortCommand extends Command { + private UUID portId; + + public DestroyPortCommand() { + } + + public DestroyPortCommand(UUID portId) { + this.portId = portId; + } + + public UUID getPortId() { + return portId; + } + + public void setPortId(UUID portId) { + this.portId = portId; + } + + @Override + public boolean executeInSequence() { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/StartupOpenDaylightControllerCommand.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/StartupOpenDaylightControllerCommand.java new file mode 100644 index 00000000000..de3a7a3b54b --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/commands/StartupOpenDaylightControllerCommand.java @@ -0,0 +1,29 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.commands; + +import com.cloud.agent.api.StartupCommand; +import com.cloud.host.Host; + +public class StartupOpenDaylightControllerCommand extends StartupCommand { + public StartupOpenDaylightControllerCommand() { + super(Host.Type.L2Networking); + } +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/AddHypervisorAnswer.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/AddHypervisorAnswer.java new file mode 100644 index 00000000000..79867051e13 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/AddHypervisorAnswer.java @@ -0,0 +1,35 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.responses; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public class AddHypervisorAnswer extends Answer { + + public AddHypervisorAnswer(Command command, boolean success, String details) { + super(command, success, details); + } + + public AddHypervisorAnswer(Command command, Exception e) { + super(command, e); + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/ConfigureNetworkAnswer.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/ConfigureNetworkAnswer.java new file mode 100644 index 00000000000..81c4a6fd45d --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/ConfigureNetworkAnswer.java @@ -0,0 +1,43 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.responses; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public class ConfigureNetworkAnswer extends Answer { + private String networkUuid; + + public ConfigureNetworkAnswer(Command command, boolean success, String details, String networkUuid) { + this.networkUuid = networkUuid; + } + + public ConfigureNetworkAnswer(Command command, boolean success, String details) { + super(command, success, details); + } + + public ConfigureNetworkAnswer(Command command, Exception e) { + super(command, e); + } + + public String getNetworkUuid() { + return networkUuid; + } +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/ConfigurePortAnswer.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/ConfigurePortAnswer.java new file mode 100644 index 00000000000..cf9acc1d535 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/ConfigurePortAnswer.java @@ -0,0 +1,35 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.responses; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public class ConfigurePortAnswer extends Answer { + + public ConfigurePortAnswer(Command command, boolean success, String details) { + super(command, success, details); + } + + public ConfigurePortAnswer(Command command, Exception e) { + super(command, e); + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/DestroyNetworkAnswer.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/DestroyNetworkAnswer.java new file mode 100644 index 00000000000..10284b4918b --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/DestroyNetworkAnswer.java @@ -0,0 +1,35 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.responses; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public class DestroyNetworkAnswer extends Answer { + + public DestroyNetworkAnswer(Command command, boolean success, String details) { + super(command, success, details); + } + + public DestroyNetworkAnswer(Command command, Exception e) { + super(command, e); + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/DestroyPortAnswer.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/DestroyPortAnswer.java new file mode 100644 index 00000000000..07bb0dbfff3 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/agent/responses/DestroyPortAnswer.java @@ -0,0 +1,35 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.agent.responses; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public class DestroyPortAnswer extends Answer { + + public DestroyPortAnswer(Command command, boolean success, String details) { + super(command, success, details); + } + + public DestroyPortAnswer(Command command, Exception e) { + super(command, e); + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/dao/OpenDaylightControllerMappingDao.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/dao/OpenDaylightControllerMappingDao.java new file mode 100644 index 00000000000..87999821ef8 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/dao/OpenDaylightControllerMappingDao.java @@ -0,0 +1,28 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.dao; + +import java.util.List; + +import com.cloud.utils.db.GenericDao; + +public interface OpenDaylightControllerMappingDao extends GenericDao { + List listByPhysicalNetwork(long physicalNetworkId); +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/dao/OpenDaylightControllerMappingDaoImpl.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/dao/OpenDaylightControllerMappingDaoImpl.java new file mode 100644 index 00000000000..1d0becaef56 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/dao/OpenDaylightControllerMappingDaoImpl.java @@ -0,0 +1,45 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.dao; + +import java.util.List; + +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; + +public class OpenDaylightControllerMappingDaoImpl extends GenericDaoBase implements OpenDaylightControllerMappingDao { + private SearchBuilder physicalNetworkIdSearch; + + public OpenDaylightControllerMappingDaoImpl() { + physicalNetworkIdSearch = createSearchBuilder(); + physicalNetworkIdSearch.and("physicalNetworkId", physicalNetworkIdSearch.entity().getPhysicalNetworkId(), Op.EQ); + physicalNetworkIdSearch.done(); + } + + @Override + public List listByPhysicalNetwork(long physicalNetworkId) { + SearchCriteria sc = physicalNetworkIdSearch.create(); + sc.setParameters("physicalNetworkId", physicalNetworkId); + return search(sc, null); + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/dao/OpenDaylightControllerVO.java b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/dao/OpenDaylightControllerVO.java new file mode 100644 index 00000000000..61d5682bde6 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/java/org/apache/cloudstack/network/opendaylight/dao/OpenDaylightControllerVO.java @@ -0,0 +1,101 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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.apache.cloudstack.network.opendaylight.dao; + +import java.util.UUID; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.apache.cloudstack.api.InternalIdentity; + +@Entity +@Table(name = "external_opendaylight_controllers") +public class OpenDaylightControllerVO implements InternalIdentity { + private static final long serialVersionUID = -575928081553194369L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "host_id") + private long hostId; + + @Column(name = "physical_network_id") + private long physicalNetworkId; + + @Column(name = "provider_name") + private String providerName; + + @Column(name = "device_name") + private String deviceName; + + public OpenDaylightControllerVO() { + uuid = UUID.randomUUID().toString(); + } + + public OpenDaylightControllerVO(final long hostId, final long physicalNetworkId, final String providerName, final String deviceName) { + super(); + this.hostId = hostId; + this.physicalNetworkId = physicalNetworkId; + this.providerName = providerName; + this.deviceName = deviceName; + uuid = UUID.randomUUID().toString(); + } + + @Override + public long getId() { + // TODO Auto-generated method stub + return 0; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public long getPhysicalNetworkId() { + return physicalNetworkId; + } + + public long getHostId() { + return hostId; + } + + public String getProviderName() { + return providerName; + } + + public String getDeviceName() { + return deviceName; + } + +} diff --git a/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/module.properties b/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/module.properties new file mode 100644 index 00000000000..36d2331db5b --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/module.properties @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +name=opendaylight +parent=network diff --git a/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/spring-opendaylight-context.xml b/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/spring-opendaylight-context.xml new file mode 100644 index 00000000000..76b6a920c70 --- /dev/null +++ b/plugins/network-elements/opendaylight/src/main/resources/META-INF/cloudstack/opendaylight/spring-opendaylight-context.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + diff --git a/plugins/pom.xml b/plugins/pom.xml index 8ec6a711376..85a7bbee3ee 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -51,6 +51,7 @@ network-elements/bigswitch-vns network-elements/midonet network-elements/stratosphere-ssp + network-elements/opendaylight storage-allocators/random user-authenticators/ldap user-authenticators/md5