blob: 44cbc6c305f04ff5efd089ffb2e89728c13d634b [file] [log] [blame]
// 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.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;
// 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 {
logger.debug("NetworkElement implement: " + network.getName() + ", traffic type: " + network.getTrafficType());
if (network.getTrafficType() == TrafficType.Guest) {
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) {
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 {
logger.debug("NetworkElement prepare: " + network.getName() + ", traffic type: " + network.getTrafficType());
if (network.getTrafficType() == TrafficType.Guest) {
logger.debug("ignore network " + network.getName());
return true;
}
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) {
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) {
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)) {
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) {
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) {
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 {
logger.debug("NetworkElement shutdown");
return true;
}
/**
* Network delete
*/
@Override
public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
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) {
logger.debug("update system network service: " + net.getName() + "; service provider: " + serviceMap);
_networksDao.update(net.getId(), net, serviceMap);
}
} else {
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) {
logger.debug("update system network service: " + net.getName() + "; service provider: " + serviceMap);
_networksDao.update(net.getId(), net, serviceMap);
}
} else {
logger.debug("no system networks created yet");
}
return true;
}
@Override
public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException,
ResourceUnavailableException {
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
logger.debug("NetworkElement verifyServices");
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)) {
logger.debug("Successfully created floating ip: " + ip.getAddress().addr());
}
} else {
if (_manager.deleteFloatingIp(ip)) {
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;
}
}