| // 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.contrail.management; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.inject.Inject; |
| |
| import org.apache.cloudstack.network.contrail.api.command.CreateServiceInstanceCmd; |
| import org.apache.cloudstack.network.contrail.model.InstanceIpModel; |
| import org.apache.cloudstack.network.contrail.model.VMInterfaceModel; |
| import org.apache.cloudstack.network.contrail.model.VirtualMachineModel; |
| import org.apache.cloudstack.network.contrail.model.VirtualNetworkModel; |
| import org.apache.log4j.Logger; |
| import org.springframework.stereotype.Component; |
| |
| import com.cloud.deploy.DeployDestination; |
| import com.cloud.exception.ConcurrentOperationException; |
| import com.cloud.exception.InsufficientCapacityException; |
| import com.cloud.exception.ResourceUnavailableException; |
| import com.cloud.network.IpAddress; |
| 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.Networks.TrafficType; |
| import com.cloud.network.PhysicalNetworkServiceProvider; |
| import com.cloud.network.PublicIpAddress; |
| import com.cloud.network.dao.NetworkDao; |
| import com.cloud.network.dao.NetworkVO; |
| import com.cloud.network.element.DhcpServiceProvider; |
| import com.cloud.network.element.IpDeployer; |
| import com.cloud.network.element.SourceNatServiceProvider; |
| import com.cloud.network.element.StaticNatServiceProvider; |
| import com.cloud.network.rules.StaticNat; |
| import com.cloud.offering.NetworkOffering; |
| import com.cloud.resource.ResourceManager; |
| import com.cloud.server.ConfigurationServer; |
| import com.cloud.server.ConfigurationServerImpl; |
| import com.cloud.utils.component.AdapterBase; |
| import com.cloud.vm.NicProfile; |
| import com.cloud.vm.NicVO; |
| import com.cloud.vm.ReservationContext; |
| import com.cloud.vm.VMInstanceVO; |
| import com.cloud.vm.VirtualMachineProfile; |
| import com.cloud.vm.dao.NicDao; |
| |
| @Component |
| |
| public class ContrailElementImpl extends AdapterBase |
| implements ContrailElement, StaticNatServiceProvider, IpDeployer, SourceNatServiceProvider, DhcpServiceProvider { |
| private final Map<Service, Map<Capability, String>> _capabilities = InitCapabilities(); |
| |
| @Inject |
| ResourceManager _resourceMgr; |
| @Inject |
| ConfigurationServer _configServer; |
| @Inject |
| NetworkDao _networksDao; |
| @Inject |
| ContrailManager _manager; |
| @Inject |
| NicDao _nicDao; |
| @Inject |
| ServerDBSync _dbSync; |
| private static final Logger s_logger = Logger.getLogger(ContrailElement.class); |
| |
| // PluggableService |
| @Override |
| public List<Class<?>> getCommands() { |
| List<Class<?>> cmdList = new ArrayList<Class<?>>(); |
| cmdList.add(CreateServiceInstanceCmd.class); |
| return cmdList; |
| } |
| |
| // NetworkElement API |
| @Override |
| public Provider getProvider() { |
| return Provider.JuniperContrailRouter; |
| } |
| |
| private static Map<Service, Map<Capability, String>> InitCapabilities() { |
| Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>(); |
| capabilities.put(Service.Connectivity, null); |
| capabilities.put(Service.Dhcp, new HashMap<Capability, String>()); |
| capabilities.put(Service.StaticNat, null); |
| capabilities.put(Service.SourceNat, null); |
| |
| return capabilities; |
| } |
| |
| @Override |
| public Map<Service, Map<Capability, String>> getCapabilities() { |
| return _capabilities; |
| } |
| |
| /** |
| * Network add/update. |
| */ |
| @Override |
| public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException, InsufficientCapacityException { |
| s_logger.debug("NetworkElement implement: " + network.getName() + ", traffic type: " + network.getTrafficType()); |
| if (network.getTrafficType() == TrafficType.Guest) { |
| s_logger.debug("ignore network " + network.getName()); |
| return true; |
| } |
| VirtualNetworkModel vnModel = _manager.getDatabase().lookupVirtualNetwork(network.getUuid(), _manager.getCanonicalName(network), network.getTrafficType()); |
| |
| if (vnModel == null) { |
| vnModel = new VirtualNetworkModel(network, network.getUuid(), _manager.getCanonicalName(network), network.getTrafficType()); |
| vnModel.setProperties(_manager.getModelController(), network); |
| } |
| try { |
| if (!vnModel.verify(_manager.getModelController())) { |
| vnModel.update(_manager.getModelController()); |
| } |
| _manager.getDatabase().getVirtualNetworks().add(vnModel); |
| } catch (Exception ex) { |
| s_logger.warn("virtual-network update: ", ex); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean prepare(Network network, NicProfile nicProfile, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) |
| throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { |
| |
| s_logger.debug("NetworkElement prepare: " + network.getName() + ", traffic type: " + network.getTrafficType()); |
| |
| if (network.getTrafficType() == TrafficType.Guest) { |
| s_logger.debug("ignore network " + network.getName()); |
| return true; |
| } |
| |
| s_logger.debug("network: " + network.getId()); |
| |
| VirtualNetworkModel vnModel = _manager.getDatabase().lookupVirtualNetwork(network.getUuid(), _manager.getCanonicalName(network), network.getTrafficType()); |
| |
| if (vnModel == null) { |
| // There is no notification after a physical network is associated with the VRouter NetworkOffering |
| // this may be the first time we see this network. |
| return false; |
| } |
| |
| VirtualMachineModel vmModel = _manager.getDatabase().lookupVirtualMachine(vm.getUuid()); |
| if (vmModel == null) { |
| VMInstanceVO vmVo = (VMInstanceVO)vm.getVirtualMachine(); |
| vmModel = new VirtualMachineModel(vmVo, vm.getUuid()); |
| vmModel.setProperties(_manager.getModelController(), vmVo); |
| } |
| |
| NicVO nic = _nicDao.findById(nicProfile.getId()); |
| assert nic != null; |
| |
| VMInterfaceModel vmiModel = vmModel.getVMInterface(nic.getUuid()); |
| if (vmiModel == null) { |
| vmiModel = new VMInterfaceModel(nic.getUuid()); |
| vmiModel.addToVirtualMachine(vmModel); |
| vmiModel.addToVirtualNetwork(vnModel); |
| } |
| |
| try { |
| vmiModel.build(_manager.getModelController(), (VMInstanceVO)vm.getVirtualMachine(), nic); |
| } catch (IOException ex) { |
| s_logger.warn("vm interface set", ex); |
| return false; |
| } |
| |
| InstanceIpModel ipModel = vmiModel.getInstanceIp(); |
| if (ipModel == null) { |
| ipModel = new InstanceIpModel(vm.getInstanceName(), nic.getDeviceId()); |
| ipModel.addToVMInterface(vmiModel); |
| } |
| ipModel.setAddress(nicProfile.getIPv4Address()); |
| |
| try { |
| vmModel.update(_manager.getModelController()); |
| } catch (Exception ex) { |
| s_logger.warn("virtual-machine-update", ex); |
| return false; |
| } |
| _manager.getDatabase().getVirtualMachines().add(vmModel); |
| |
| return true; |
| } |
| |
| @Override |
| public boolean release(Network network, NicProfile nicProfile, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException { |
| if (network.getTrafficType() == TrafficType.Guest) { |
| return true; |
| } else if (!_manager.isManagedPhysicalNetwork(network)) { |
| s_logger.debug("release ignore network " + network.getId()); |
| return true; |
| } |
| |
| NicVO nic = _nicDao.findById(nicProfile.getId()); |
| assert nic != null; |
| |
| VirtualMachineModel vmModel = _manager.getDatabase().lookupVirtualMachine(vm.getUuid()); |
| if (vmModel == null) { |
| s_logger.debug("vm " + vm.getInstanceName() + " not in local database"); |
| return true; |
| } |
| VMInterfaceModel vmiModel = vmModel.getVMInterface(nic.getUuid()); |
| if (vmiModel != null) { |
| try { |
| vmiModel.destroy(_manager.getModelController()); |
| } catch (IOException ex) { |
| s_logger.warn("virtual-machine-interface delete", ex); |
| } |
| vmModel.removeSuccessor(vmiModel); |
| } |
| |
| if (!vmModel.hasDescendents()) { |
| _manager.getDatabase().getVirtualMachines().remove(vmModel); |
| try { |
| vmModel.delete(_manager.getModelController()); |
| } catch (IOException e) { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| /** |
| * Network disable |
| */ |
| @Override |
| public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { |
| s_logger.debug("NetworkElement shutdown"); |
| return true; |
| } |
| |
| /** |
| * Network delete |
| */ |
| @Override |
| public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { |
| s_logger.debug("NetworkElement destroy"); |
| return true; |
| } |
| |
| @Override |
| public boolean isReady(PhysicalNetworkServiceProvider provider) { |
| Map<String, String> serviceMap = ((ConfigurationServerImpl)_configServer).getServicesAndProvidersForNetwork( _manager.getRouterOffering().getId()); |
| List<TrafficType> types = new ArrayList<TrafficType>(); |
| types.add(TrafficType.Control); |
| types.add(TrafficType.Management); |
| types.add(TrafficType.Storage); |
| List<NetworkVO> systemNets = _manager.findSystemNetworks(types); |
| if (systemNets != null && !systemNets.isEmpty()) { |
| for (NetworkVO net: systemNets) { |
| s_logger.debug("update system network service: " + net.getName() + "; service provider: " + serviceMap); |
| _networksDao.update(net.getId(), net, serviceMap); |
| } |
| } else { |
| s_logger.debug("no system networks created yet"); |
| } |
| serviceMap = ((ConfigurationServerImpl)_configServer).getServicesAndProvidersForNetwork( _manager.getPublicRouterOffering().getId()); |
| types = new ArrayList<TrafficType>(); |
| types.add(TrafficType.Public); |
| systemNets = _manager.findSystemNetworks(types); |
| if (systemNets != null && !systemNets.isEmpty()) { |
| for (NetworkVO net: systemNets) { |
| s_logger.debug("update system network service: " + net.getName() + "; service provider: " + serviceMap); |
| _networksDao.update(net.getId(), net, serviceMap); |
| } |
| } else { |
| s_logger.debug("no system networks created yet"); |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, |
| ResourceUnavailableException { |
| s_logger.debug("NetworkElement shutdown ProviderInstances"); |
| return true; |
| } |
| |
| @Override |
| public boolean canEnableIndividualServices() { |
| return true; |
| } |
| |
| @Override |
| public boolean verifyServicesCombination(Set<Service> services) { |
| // TODO Auto-generated method stub |
| s_logger.debug("NetworkElement verifyServices"); |
| s_logger.debug("Services: " + services); |
| return true; |
| } |
| |
| @Override |
| public IpDeployer getIpDeployer(Network network) { |
| return this; |
| } |
| |
| @Override |
| public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Service> services) throws ResourceUnavailableException { |
| |
| for (PublicIpAddress ip : ipAddress) { |
| if (ip.isSourceNat()) { |
| continue; |
| } |
| if (isFloatingIpCreate(ip)) { |
| if (_manager.createFloatingIp(ip)) { |
| s_logger.debug("Successfully created floating ip: " + ip.getAddress().addr()); |
| } |
| } else { |
| if (_manager.deleteFloatingIp(ip)) { |
| s_logger.debug("Successfully deleted floating ip: " + ip.getAddress().addr()); |
| } |
| } |
| } |
| return true; |
| } |
| |
| @Override |
| public boolean applyStaticNats(Network config, List<? extends StaticNat> rules) throws ResourceUnavailableException { |
| return true; |
| } |
| |
| private boolean isFloatingIpCreate(PublicIpAddress ip) { |
| if (ip.getState() == IpAddress.State.Allocated && ip.getAssociatedWithVmId() != null && !ip.isSourceNat()) { |
| return true; |
| } |
| return false; |
| } |
| |
| @Override |
| public boolean addDhcpEntry(Network network, NicProfile nic, |
| VirtualMachineProfile vm, |
| DeployDestination dest, ReservationContext context) |
| throws ConcurrentOperationException, InsufficientCapacityException, |
| ResourceUnavailableException { |
| return false; |
| } |
| |
| @Override |
| public boolean configDhcpSupportForSubnet(Network network, NicProfile nic, |
| VirtualMachineProfile vm, |
| DeployDestination dest, ReservationContext context) |
| throws ConcurrentOperationException, InsufficientCapacityException, |
| ResourceUnavailableException { |
| return false; |
| } |
| |
| @Override |
| public boolean removeDhcpSupportForSubnet(Network network) |
| throws ResourceUnavailableException { |
| return false; |
| } |
| |
| @Override |
| public boolean setExtraDhcpOptions(Network network, long nicId, Map<Integer, String> dhcpOptions) { |
| return false; |
| } |
| |
| @Override |
| public boolean removeDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile vmProfile) { |
| return false; |
| } |
| } |