blob: d5f9acba702fc3b64b5f5bcff5dd40fe10c97b48 [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 com.cloud.network.manager;
import static com.cloud.agent.api.sync.SyncNuageVspCmsIdCommand.SyncType;
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import net.nuage.vsp.acs.client.api.NuageVspPluginClientLoader;
import net.nuage.vsp.acs.client.api.model.VspApiDefaults;
import net.nuage.vsp.acs.client.api.model.VspDomain;
import net.nuage.vsp.acs.client.api.model.VspDomainCleanUp;
import net.nuage.vsp.acs.client.api.model.VspDomainTemplate;
import net.nuage.vsp.acs.client.api.model.VspHost;
import net.nuage.vsp.acs.client.common.NuageVspApiVersion;
import net.nuage.vsp.acs.client.common.NuageVspConstants;
import net.nuage.vsp.acs.client.common.model.Pair;
import net.nuage.vsp.acs.client.exception.NuageVspException;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.framework.config.impl.ConfigurationVO;
import org.apache.cloudstack.framework.messagebus.MessageBus;
import org.apache.cloudstack.network.ExternalNetworkDeviceManager;
import org.apache.cloudstack.resourcedetail.VpcDetailVO;
import org.apache.cloudstack.resourcedetail.dao.VpcDetailsDao;
import com.cloud.agent.AgentManager;
import com.cloud.agent.Listener;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.PingNuageVspCommand;
import com.cloud.agent.api.manager.CleanUpDomainCommand;
import com.cloud.agent.api.manager.EntityExistsCommand;
import com.cloud.agent.api.manager.GetApiDefaultsAnswer;
import com.cloud.agent.api.manager.GetApiDefaultsCommand;
import com.cloud.agent.api.manager.ListVspDomainTemplatesAnswer;
import com.cloud.agent.api.manager.ListVspDomainTemplatesCommand;
import com.cloud.agent.api.manager.SupportedApiVersionCommand;
import com.cloud.agent.api.manager.UpdateNuageVspDeviceCommand;
import com.cloud.agent.api.sync.SyncDomainCommand;
import com.cloud.agent.api.sync.SyncNuageVspCmsIdAnswer;
import com.cloud.agent.api.sync.SyncNuageVspCmsIdCommand;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.commands.AddNuageVspDeviceCmd;
import com.cloud.api.commands.AssociateNuageVspDomainTemplateCmd;
import com.cloud.api.commands.DeleteNuageVspDeviceCmd;
import com.cloud.api.commands.DisableNuageUnderlayVlanIpRangeCmd;
import com.cloud.api.commands.EnableNuageUnderlayVlanIpRangeCmd;
import com.cloud.api.commands.ListNuageUnderlayVlanIpRangesCmd;
import com.cloud.api.commands.ListNuageVspDevicesCmd;
import com.cloud.api.commands.ListNuageVspDomainTemplatesCmd;
import com.cloud.api.commands.ListNuageVspGlobalDomainTemplateCmd;
import com.cloud.api.commands.UpdateNuageVspDeviceCmd;
import com.cloud.api.response.NuageVlanIpRangeResponse;
import com.cloud.api.response.NuageVspDeviceResponse;
import com.cloud.api.response.NuageVspDomainTemplateResponse;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.Vlan;
import com.cloud.dc.VlanDetailsVO;
import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.dc.dao.VlanDetailsDao;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.DetailVO;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
import com.cloud.host.dao.HostDao;
import com.cloud.host.dao.HostDetailsDao;
import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.network.Networks;
import com.cloud.network.NuageVspDeviceVO;
import com.cloud.network.PhysicalNetwork;
import com.cloud.network.PhysicalNetworkServiceProvider;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkDetailVO;
import com.cloud.network.dao.NetworkDetailsDao;
import com.cloud.network.dao.NetworkVO;
import com.cloud.network.dao.NuageVspDao;
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.network.resource.NuageVspResource;
import com.cloud.network.resource.NuageVspResourceConfiguration;
import com.cloud.network.vpc.VpcOffering;
import com.cloud.network.vpc.VpcOfferingServiceMapVO;
import com.cloud.network.vpc.VpcOfferingVO;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.network.vpc.dao.VpcOfferingDao;
import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao;
import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
import com.cloud.resource.ResourceManager;
import com.cloud.resource.ResourceState;
import com.cloud.user.DomainManager;
import com.cloud.util.NuageVspEntityBuilder;
import com.cloud.util.NuageVspUtil;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.fsm.StateListener;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.VMInstanceDao;
public class NuageVspManagerImpl extends ManagerBase implements NuageVspManager, Configurable, StateListener<Status, Status.Event, Host> {
private static final Logger s_logger = Logger.getLogger(NuageVspManagerImpl.class);
public static final Multimap<Network.Service, Network.Provider> DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP;
public static final Multimap<Network.Service, Network.Provider> SUPPORTED_NUAGE_VSP_VPC_SERVICE_MAP;
private static final ConfigKey[] NUAGE_VSP_CONFIG_KEYS = new ConfigKey<?>[] { NuageVspConfigDns, NuageVspDnsExternal, NuageVspConfigGateway,
NuageVspSharedNetworkDomainTemplateName, NuageVspVpcDomainTemplateName, NuageVspIsolatedNetworkDomainTemplateName };
@Inject
ResourceManager _resourceMgr;
@Inject
HostDetailsDao _hostDetailsDao;
@Inject
HostDao _hostDao;
@Inject
PhysicalNetworkDao _physicalNetworkDao;
@Inject
PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao;
@Inject
NetworkDao _networkDao;
@Inject
NetworkDetailsDao _networkDetailsDao;
@Inject
VpcOfferingDao _vpcOffDao;
@Inject
VpcOfferingServiceMapDao _vpcOffSvcMapDao;
@Inject
VpcDao _vpcDao;
@Inject
private VpcDetailsDao _vpcDetailsDao;
@Inject
NuageVspDao _nuageVspDao;
@Inject
DataCenterDao _dataCenterDao;
@Inject
ConfigurationDao _configDao;
@Inject
AgentManager _agentMgr;
@Inject
private DomainDao _domainDao;
@Inject
NetworkOfferingDao _networkOfferingDao;
@Inject
NetworkOfferingServiceMapDao _networkOfferingServiceMapDao;
@Inject
NuageVspEntityBuilder _nuageVspEntityBuilder;
@Inject
VlanDao _vlanDao;
@Inject
VlanDetailsDao _vlanDetailsDao;
@Inject
ResponseGenerator _responseGenerator;
@Inject
MessageBus _messageBus;
@Inject
VMInstanceDao _vmInstanceDao;
@Inject
NicDao _nicDao;
@Inject
NetworkModel _networkModel;
static {
Set<Network.Provider> nuageVspProviders = ImmutableSet.of(Network.Provider.NuageVsp);
Set<Network.Provider> vrProviders = ImmutableSet.of(Network.Provider.VPCVirtualRouter);
Set<Network.Provider> defaultLbProviders = ImmutableSet.of(Network.Provider.InternalLbVm);
Set<Network.Provider> supportedLbProviders = ImmutableSet.of(Network.Provider.InternalLbVm);
Set<Network.Provider> supportedUserDataProviders = ImmutableSet.of(Network.Provider.VPCVirtualRouter, Network.Provider.ConfigDrive);
DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP = ImmutableMultimap.<Network.Service, Network.Provider>builder()
.putAll(Network.Service.Connectivity, nuageVspProviders)
.putAll(Network.Service.Gateway, nuageVspProviders)
.putAll(Network.Service.Dhcp, nuageVspProviders)
.putAll(Network.Service.StaticNat, nuageVspProviders)
.putAll(Network.Service.SourceNat, nuageVspProviders)
.putAll(Network.Service.NetworkACL, nuageVspProviders)
.putAll(Network.Service.UserData, vrProviders)
.putAll(Network.Service.Lb, defaultLbProviders)
.putAll(Network.Service.Dns, vrProviders)
.build();
Multimap<Network.Service, Network.Provider> builder = HashMultimap.create(DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP);
builder.putAll(Network.Service.UserData, supportedUserDataProviders);
builder.putAll(Network.Service.Lb, supportedLbProviders);
SUPPORTED_NUAGE_VSP_VPC_SERVICE_MAP = ImmutableMultimap.copyOf(builder);
}
private Listener _nuageVspResourceListener;
@Override
public List<Class<?>> getCommands() {
return Lists.<Class<?>>newArrayList(
AddNuageVspDeviceCmd.class,
DeleteNuageVspDeviceCmd.class,
UpdateNuageVspDeviceCmd.class,
ListNuageVspDevicesCmd.class,
DisableNuageUnderlayVlanIpRangeCmd.class,
EnableNuageUnderlayVlanIpRangeCmd.class,
ListNuageUnderlayVlanIpRangesCmd.class,
ListNuageVspDomainTemplatesCmd.class,
ListNuageVspGlobalDomainTemplateCmd.class,
AssociateNuageVspDomainTemplateCmd.class
);
}
@Override
public NuageVspDeviceVO addNuageVspDevice(AddNuageVspDeviceCmd cmd) {
final NuageVspResource resource = new NuageVspResource();
final String deviceName = Network.Provider.NuageVsp.getName();
ExternalNetworkDeviceManager.NetworkDevice networkDevice = ExternalNetworkDeviceManager.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");
}
if (_nuageVspDao.listByPhysicalNetwork(physicalNetworkId).size() != 0) {
throw new CloudRuntimeException("A NuageVsp device is already configured on this physical network");
}
// While the default VSD port is 8443, clustering via HAProxy will go over port 443 (CLOUD-58)
int port = cmd.getPort() > 0 ? cmd.getPort() : 443;
try {
String apiVersion = null;
String cmsUserPasswordBase64 = NuageVspUtil.encodePassword(cmd.getPassword());
NuageVspResourceConfiguration resourceConfiguration = new NuageVspResourceConfiguration()
.guid(UUID.randomUUID().toString())
.zoneId(String.valueOf(physicalNetwork.getDataCenterId()))
.hostName(cmd.getHostName())
.cmsUser(cmd.getUserName())
.cmsUserPassword(cmsUserPasswordBase64)
.port(String.valueOf(port))
.apiVersion(NuageVspApiVersion.CURRENT.toString())
.retryCount(NuageVspConstants.DEFAULT_API_RETRY_COUNT.toString())
.retryInterval(NuageVspConstants.DEFAULT_API_RETRY_INTERVAL.toString())
.apiRelativePath("/nuage");
VspHost vspHost = resourceConfiguration.buildVspHost();
NuageVspPluginClientLoader clientLoader = NuageVspPluginClientLoader.getClientLoader(vspHost);
VspApiDefaults apiDefaults = clientLoader.getNuageVspManagerClient().getApiDefaults();
if (StringUtils.isNotBlank(cmd.getApiVersion())){
apiVersion = cmd.getApiVersion();
if (!clientLoader.getNuageVspManagerClient().isSupportedApiVersion(apiVersion)){
throw new CloudRuntimeException("Unsupported API version : " + cmd.getApiVersion());
}
} else {
List<NuageVspApiVersion> supportedVsdVersions = clientLoader.getNuageVspManagerClient().getSupportedVersionList();
supportedVsdVersions.retainAll(Arrays.asList(NuageVspApiVersion.SUPPORTED_VERSIONS));
if(supportedVsdVersions.isEmpty()) {
throw new CloudRuntimeException("No supported API version found!");
}
supportedVsdVersions.sort(Comparator.reverseOrder());
apiVersion = supportedVsdVersions.get(0).toString();
}
String retryCount = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryCount(), apiDefaults.getRetryCount()));
String retryInterval = String.valueOf(MoreObjects.firstNonNull(cmd.getApiRetryInterval(), apiDefaults.getRetryInterval()));
resourceConfiguration
.apiVersion(apiVersion)
.apiRelativePath("/nuage/api/" + apiVersion)
.retryCount(retryCount)
.retryInterval(retryInterval);
Map<String, String> hostDetails = resourceConfiguration.build();
resource.configure("Nuage VSD - " + cmd.getHostName(), Maps.<String, Object>newHashMap(hostDetails));
Host host = _resourceMgr.addHost(zoneId, resource, Host.Type.L2Networking, hostDetails);
if (host == null) {
throw new CloudRuntimeException("Failed to add Nuage Vsp Device due to internal error.");
}
NuageVspDeviceVO nuageVspDevice = new NuageVspDeviceVO(host.getId(), physicalNetworkId, ntwkSvcProvider.getProviderName(), deviceName);
_nuageVspDao.persist(nuageVspDevice);
DetailVO detail = new DetailVO(host.getId(), "nuagevspdeviceid", String.valueOf(nuageVspDevice.getId()));
_hostDetailsDao.persist(detail);
NuageVspDeviceVO matchingNuageVspDevice = findMatchingNuageVspDevice(nuageVspDevice);
String cmsId;
if (matchingNuageVspDevice != null) {
cmsId = findNuageVspCmsIdForDeviceOrHost(matchingNuageVspDevice.getId(), matchingNuageVspDevice.getHostId());
} else {
SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.REGISTER, null);
SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd);
if (answer != null && answer.getSuccess()) {
cmsId = answer.getNuageVspCmsId();
} else {
throw new CloudRuntimeException("Failed to register CMS ID");
}
}
host = findNuageVspHost(nuageVspDevice.getHostId());
registerNewNuageVspDevice(host.getId(), cmsId);
resourceConfiguration.nuageVspCmsId(cmsId);
resource.configure(cmd.getHostName(), Maps.<String, Object>newHashMap(resourceConfiguration.build()));
if (matchingNuageVspDevice == null) {
auditDomainsOnVsp((HostVO) host, true);
}
return nuageVspDevice;
} catch (ConfigurationException e) {
s_logger.error("Failed to configure Nuage VSD resource " + cmd.getHostName(), e);
throw new CloudRuntimeException("Failed to configure Nuage VSD resource " + cmd.getHostName(), e);
} catch (NuageVspException ee) {
s_logger.error("Failed to add Nuage VSP device " + cmd.getHostName(), ee);
throw new CloudRuntimeException("Failed to add Nuage VSP device " + cmd.getHostName(), ee);
}
}
@Override
public NuageVspDeviceVO updateNuageVspDevice(UpdateNuageVspDeviceCmd command) {
NuageVspResource resource = new NuageVspResource();
final String deviceName = Network.Provider.NuageVsp.getName();
ExternalNetworkDeviceManager.NetworkDevice networkDevice = ExternalNetworkDeviceManager.NetworkDevice.getNetworkDevice(deviceName);
final Long physicalNetworkId = command.getPhysicalNetworkId();
PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId);
if (physicalNetwork == null) {
throw new InvalidParameterValueException("Could not find phyical network with ID: " + physicalNetworkId);
}
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");
}
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");
}
HostVO nuageVspHost = null;
NuageVspDeviceVO nuageVspDevice = null;
List<NuageVspDeviceVO> nuageVspDevices = _nuageVspDao.listByPhysicalNetwork(physicalNetworkId);
if (nuageVspDevices == null || nuageVspDevices.isEmpty()) {
throw new CloudRuntimeException("Nuage VSD is not configured on physical network " + physicalNetworkId);
} else {
nuageVspDevice = nuageVspDevices.iterator().next();
nuageVspHost = _hostDao.findById(nuageVspDevice.getHostId());
_hostDao.loadDetails(nuageVspHost);
}
boolean resourceConfigurationChanged = false;
NuageVspResourceConfiguration resourceConfiguration = NuageVspResourceConfiguration.fromConfiguration(nuageVspHost.getDetails());
if (!Strings.isNullOrEmpty(command.getHostName()) &&
!command.getHostName().equals(resourceConfiguration.hostName())) {
resourceConfiguration.hostName(command.getHostName());
resourceConfigurationChanged = true;
}
if (!Strings.isNullOrEmpty(command.getUserName()) &&
!command.getUserName().equals(resourceConfiguration.cmsUser())) {
resourceConfiguration.cmsUser(command.getUserName());
resourceConfigurationChanged = true;
}
if (!Strings.isNullOrEmpty(command.getPassword())) {
String encodedNewPassword = NuageVspUtil.encodePassword(command.getPassword());
if (!encodedNewPassword.equals(resourceConfiguration.cmsUserPassword())) {
resourceConfiguration.cmsUserPassword(encodedNewPassword);
resourceConfigurationChanged = true;
}
}
if (command.getPort() != null &&
command.getPort() != Integer.parseInt(resourceConfiguration.port())) {
resourceConfiguration.port(String.valueOf(command.getPort()));
resourceConfigurationChanged = true;
}
String apiVersion = MoreObjects.firstNonNull(command.getApiVersion(), resourceConfiguration.apiVersion());
NuageVspApiVersion apiVersionObj = NuageVspApiVersion.fromString(apiVersion);
NuageVspApiVersion apiVersionCurrent = null;
try {
apiVersionCurrent = resourceConfiguration.getApiVersion();
} catch (ConfigurationException e){
throw new CloudRuntimeException("Current version is not configured correctly");
}
if(command.getApiVersion() != null){
if(apiVersionObj.compareTo(apiVersionCurrent) < 0) {
throw new CloudRuntimeException("Downgrading is not supported");
}
GetApiDefaultsCommand apiDefaultsCmd = new GetApiDefaultsCommand();
GetApiDefaultsAnswer apiDefaultsAnswer = (GetApiDefaultsAnswer) _agentMgr.easySend(nuageVspHost.getId(), apiDefaultsCmd);
SupportedApiVersionCommand supportedApiVersionCmd = new SupportedApiVersionCommand(apiVersion);
Answer supportedApiVersionAnswer = _agentMgr.easySend(nuageVspHost.getId(), supportedApiVersionCmd);
if (!supportedApiVersionAnswer.getResult()) {
throw new CloudRuntimeException("Incorrect API version: Nuage plugin only supports " + apiDefaultsAnswer.getApiDefaults().getVersion());
}
String apiRelativePath = "/nuage/api/" + apiVersion;
if (!apiRelativePath.equals(resourceConfiguration.apiRelativePath())) {
resourceConfiguration.apiVersion(apiVersion);
resourceConfiguration.apiRelativePath(apiRelativePath);
resourceConfigurationChanged = true;
}
}
if (command.getApiRetryCount() != null && resourceConfiguration.retryCount() != null) {
final int retryCount = Integer.parseInt(resourceConfiguration.retryCount());
if (command.getApiRetryCount() != retryCount) {
resourceConfiguration.retryCount(String.valueOf(command.getApiRetryCount()));
resourceConfigurationChanged = true;
}
}
if (command.getApiRetryInterval() != null && resourceConfiguration.retryInterval() != null) {
final int apiRetryInterval = Integer.parseInt(resourceConfiguration.retryInterval());
if (command.getApiRetryInterval() != apiRetryInterval) {
resourceConfiguration.retryInterval(String.valueOf(command.getApiRetryInterval()));
resourceConfigurationChanged = true;
}
}
if (!resourceConfigurationChanged) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("No change in the NuageVsp device parameters. None of the NuageVsp device parameters are modified");
}
return nuageVspDevice;
}
Map<String, String> config = resourceConfiguration.build();
try {
resource.validate(config);
UpdateNuageVspDeviceCommand cmd = new UpdateNuageVspDeviceCommand(resourceConfiguration);
Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd);
if (answer == null || !answer.getResult()) {
s_logger.error("UpdateNuageVspDeviceCommand failed");
if ((null != answer) && (null != answer.getDetails())) {
throw new CloudRuntimeException(answer.getDetails());
}
}
_hostDetailsDao.persist(nuageVspDevice.getHostId(), config);
} catch (ConfigurationException e) {
throw new CloudRuntimeException("Failed to update Nuage VSP device " + nuageVspDevice.getId() + " with parameters " + resourceConfiguration, e);
}
return nuageVspDevice;
}
@Override
public NuageVspDeviceResponse createNuageVspDeviceResponse(NuageVspDeviceVO nuageVspDeviceVO) {
HostVO nuageVspHost = _hostDao.findById(nuageVspDeviceVO.getHostId());
_hostDao.loadDetails(nuageVspHost);
NuageVspResourceConfiguration resourceConfiguration = NuageVspResourceConfiguration.fromConfiguration(nuageVspHost.getDetails());
NuageVspDeviceResponse response = new NuageVspDeviceResponse();
response.setDeviceName(nuageVspDeviceVO.getDeviceName());
PhysicalNetwork pnw = ApiDBUtils.findPhysicalNetworkById(nuageVspDeviceVO.getPhysicalNetworkId());
if (pnw != null) {
response.setPhysicalNetworkId(pnw.getUuid());
}
response.setId(nuageVspDeviceVO.getUuid());
response.setProviderName(nuageVspDeviceVO.getProviderName());
response.setHostName(resourceConfiguration.hostName());
response.setPort(Integer.parseInt(resourceConfiguration.port()));
String apiRelativePath = resourceConfiguration.apiRelativePath();
response.setApiVersion(apiRelativePath.substring(apiRelativePath.lastIndexOf('/') + 1));
response.setApiRetryCount(Integer.parseInt(resourceConfiguration.retryCount()));
response.setApiRetryInterval(Long.parseLong(resourceConfiguration.retryInterval()));
response.setCmsId(resourceConfiguration.nuageVspCmsId());
response.setObjectName("nuagevspdevice");
return response;
}
@Override
public boolean deleteNuageVspDevice(DeleteNuageVspDeviceCmd cmd) {
Long nuageDeviceId = cmd.getNuageVspDeviceId();
NuageVspDeviceVO nuageVspDevice = _nuageVspDao.findById(nuageDeviceId);
if (nuageVspDevice == null) {
throw new InvalidParameterValueException("Could not find a Nuage Vsp device with id " + nuageDeviceId);
}
// Find the physical network we work for
Long physicalNetworkId = nuageVspDevice.getPhysicalNetworkId();
PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId);
if (physicalNetwork != null) {
// Lets see if there are networks that use us
// Find the nuage networks on this physical network
List<NetworkVO> networkList = _networkDao.listByPhysicalNetwork(physicalNetworkId);
// Networks with broadcast type lswitch are ours
for (NetworkVO network : networkList) {
if (network.getBroadcastDomainType() == Networks.BroadcastDomainType.Vsp) {
if ((network.getState() != Network.State.Shutdown) && (network.getState() != Network.State.Destroy)) {
throw new CloudRuntimeException("This Nuage Vsp device can not be deleted as there are one or more logical networks provisioned by Cloudstack.");
}
}
}
}
NuageVspDeviceVO matchingNuageVspDevice = findMatchingNuageVspDevice(nuageVspDevice);
String nuageVspCmsId = findNuageVspCmsIdForDeviceOrHost(nuageVspDevice.getId(), nuageVspDevice.getHostId());
if (matchingNuageVspDevice == null) {
HostVO host = findNuageVspHost(nuageVspDevice.getHostId());
if (!auditDomainsOnVsp(host, false)) {
return false;
}
SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.UNREGISTER, nuageVspCmsId);
SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd);
if (answer == null || !answer.getSuccess()) {
return false;
}
}
removeLegacyNuageVspDeviceCmsId(nuageVspDevice.getId());
HostVO nuageHost = _hostDao.findById(nuageVspDevice.getHostId());
Long hostId = nuageHost.getId();
nuageHost.setResourceState(ResourceState.Maintenance);
_hostDao.update(hostId, nuageHost);
_resourceMgr.deleteHost(hostId, false, false);
_nuageVspDao.remove(nuageDeviceId);
return true;
}
private NuageVspDeviceVO findMatchingNuageVspDevice(NuageVspDeviceVO nuageVspDevice) {
DetailVO nuageVspDeviceHost = _hostDetailsDao.findDetail(nuageVspDevice.getHostId(), "hostname");
String nuageVspDeviceHostName = (nuageVspDeviceHost != null) ? nuageVspDeviceHost.getValue(): null;
List<NuageVspDeviceVO> otherNuageVspDevices = _nuageVspDao.listAll();
for (NuageVspDeviceVO otherNuageVspDevice : otherNuageVspDevices) {
if (otherNuageVspDevice.getId() == nuageVspDevice.getId()) continue;
DetailVO otherNuageVspDeviceHostName = _hostDetailsDao.findDetail(otherNuageVspDevice.getHostId(), "hostname");
if (otherNuageVspDeviceHostName != null && nuageVspDeviceHostName.equals(otherNuageVspDeviceHostName.getValue())) {
return otherNuageVspDevice;
}
}
return null;
}
@Override
public List<NuageVspDeviceVO> listNuageVspDevices(ListNuageVspDevicesCmd cmd) {
Long physicalNetworkId = cmd.getPhysicalNetworkId();
Long nuageVspDeviceId = cmd.getNuageVspDeviceId();
List<NuageVspDeviceVO> responseList = new ArrayList<NuageVspDeviceVO>();
if (physicalNetworkId == null && nuageVspDeviceId == null) {
throw new InvalidParameterValueException("Either physical network Id or Nuage device Id must be specified");
}
if (nuageVspDeviceId != null) {
NuageVspDeviceVO nuageVspDevice = _nuageVspDao.findById(nuageVspDeviceId);
if (nuageVspDevice == null) {
throw new InvalidParameterValueException("Could not find Nuage Vsp device with id: " + nuageVspDeviceId);
}
responseList.add(nuageVspDevice);
} else {
PhysicalNetworkVO physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId);
if (physicalNetwork == null) {
throw new InvalidParameterValueException("Could not find a physical network with id: " + physicalNetworkId);
}
responseList = _nuageVspDao.listByPhysicalNetwork(physicalNetworkId);
}
return responseList;
}
private void registerNewNuageVspDevice(long hostId, String cmsId) {
DetailVO detail = new DetailVO(hostId, "nuagevspcmsid", cmsId);
_hostDetailsDao.persist(detail);
}
@Deprecated
private void removeLegacyNuageVspDeviceCmsId(long deviceId) {
ConfigurationVO cmsIdConfig = _configDao.findByName(CMSID_CONFIG_KEY);
if (cmsIdConfig != null) {
if (!cmsIdConfig.getValue().contains(";") && cmsIdConfig.getValue().startsWith(deviceId + ":")) {
_configDao.update(CMSID_CONFIG_KEY, "Advanced", "");
} else {
String newValue = cmsIdConfig.getValue().replace(String.format("(^|;)%d:[0-9a-f\\-]+;?", deviceId), ";");
_configDao.update(CMSID_CONFIG_KEY, "Advanced", newValue);
}
}
}
public boolean executeSyncCmsId(NuageVspDeviceVO nuageVspDevice, SyncType syncType) {
NuageVspDeviceVO matchingNuageVspDevice = findMatchingNuageVspDevice(nuageVspDevice);
if (syncType == SyncType.REGISTER && matchingNuageVspDevice != null) {
String cmsId = findNuageVspCmsIdForDeviceOrHost(matchingNuageVspDevice.getId(), matchingNuageVspDevice.getHostId());
registerNewNuageVspDevice(nuageVspDevice.getHostId(), cmsId);
return true;
}
String cmsId = findNuageVspCmsIdForDeviceOrHost(nuageVspDevice.getId(), nuageVspDevice.getHostId());
SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(syncType, cmsId);
SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd);
if (answer != null) {
if (answer.getSuccess()) {
if (syncType == SyncType.REGISTER || answer.getSyncType() == SyncType.REGISTER) {
registerNewNuageVspDevice(nuageVspDevice.getHostId(), answer.getNuageVspCmsId());
} else if (syncType == SyncType.UNREGISTER) {
removeLegacyNuageVspDeviceCmsId(nuageVspDevice.getId());
}
} else if (syncType == SyncType.AUDIT || syncType == SyncType.AUDIT_ONLY) {
s_logger.fatal("Nuage VSP Device with ID " + nuageVspDevice.getId() + " is configured with an unknown CMS ID!");
}
}
return answer != null && answer.getSuccess();
}
void auditHost(long hostId) {
Host host = _hostDao.findById(hostId);
auditHost((HostVO)host);
}
void auditHost(HostVO host) {
if (host == null) return;
_hostDao.loadDetails(host);
boolean validateDomains = true;
List<NuageVspDeviceVO> nuageVspDevices = _nuageVspDao.listByHost(host.getId());
if (!CollectionUtils.isEmpty(nuageVspDevices)) {
for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) {
String nuageVspCmsId = findNuageVspCmsIdForDeviceOrHost(nuageVspDevice.getId(), nuageVspDevice.getHostId());
SyncNuageVspCmsIdCommand syncCmd = new SyncNuageVspCmsIdCommand(SyncType.AUDIT, nuageVspCmsId);
SyncNuageVspCmsIdAnswer answer = (SyncNuageVspCmsIdAnswer) _agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd);
if (answer != null && !answer.getSuccess()) {
s_logger.error("Nuage VSP Device with ID " + nuageVspDevice.getId() + " is configured with an unknown CMS ID!");
validateDomains = false;
} else if (answer != null && answer.getSyncType() == SyncType.REGISTER) {
registerNewNuageVspDevice(nuageVspDevice.getHostId(), answer.getNuageVspCmsId());
}
}
}
if (validateDomains) {
auditDomainsOnVsp(host, true);
}
}
private boolean auditDomainsOnVsp(HostVO host, boolean add) {
List<NuageVspDeviceVO> nuageVspDevices = _nuageVspDao.listByHost(host.getId());
if (CollectionUtils.isEmpty(nuageVspDevices)) {
return true;
}
final SyncDomainCommand.Type action = add ? SyncDomainCommand.Type.ADD : SyncDomainCommand.Type.REMOVE;
_hostDao.loadDetails(host);
List<DomainVO> allDomains = _domainDao.listAll();
for (DomainVO domain : allDomains) {
if (action == SyncDomainCommand.Type.REMOVE) {
VspDomainCleanUp vspDomainCleanUp = _nuageVspEntityBuilder.buildVspDomainCleanUp(domain);
CleanUpDomainCommand cmd = new CleanUpDomainCommand(vspDomainCleanUp);
Answer answer = _agentMgr.easySend(host.getId(), cmd);
if (!answer.getResult()) {
return false;
}
}
VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain);
SyncDomainCommand cmd = new SyncDomainCommand(vspDomain, action);
Answer answer = _agentMgr.easySend(host.getId(), cmd);
if (!answer.getResult()) {
return false;
}
}
return true;
}
private String findNuageVspCmsIdForDeviceOrHost(long deviceId, long hostId) {
String cmsId = findNuageVspCmsIdForHostDevice(hostId);
if(cmsId == null) {
cmsId = findNuageVspCmsIdForDevice(deviceId);
if (cmsId != null) {
// Upgrade
registerNewNuageVspDevice(hostId, cmsId);
removeLegacyNuageVspDeviceCmsId(deviceId);
}
}
return cmsId;
}
private String findNuageVspCmsIdForHostDevice(long hostId) {
final DetailVO cmsIdDetailVO = _hostDetailsDao.findDetail(hostId, "nuagevspcmsid");
if (cmsIdDetailVO != null) {
return cmsIdDetailVO.getValue();
}
return null;
}
@Deprecated
private String findNuageVspCmsIdForDevice(long deviceId) {
ConfigurationVO cmsIdConfig = _configDao.findByName(CMSID_CONFIG_KEY);
if(cmsIdConfig != null) {
String configValue = cmsIdConfig.getValue();
if (!Strings.isNullOrEmpty(configValue)) {
String[] configuredNuageVspDevices = configValue.split(";");
for (String configuredNuageVspDevice : configuredNuageVspDevices) {
if (configuredNuageVspDevice.startsWith(deviceId + ":")) {
String[] split = configuredNuageVspDevice.split(":");
if (split.length != 2 || (split.length > 1 && Strings.isNullOrEmpty(split[1]))) {
throw new IllegalArgumentException("The configured CMS ID for Nuage VSP device " + deviceId + " is in an incorrect format");
}
return split[1];
}
}
}
}
return null;
}
public List<String> getDnsDetails(long dataCenterId) {
Boolean configureDns = Boolean.valueOf(_configDao.getValue(NuageVspManager.NuageVspConfigDns.key()));
if (!configureDns) {
return Lists.newArrayList();
}
Boolean configureExternalDns = Boolean.valueOf(_configDao.getValue(NuageVspManager.NuageVspDnsExternal.key()));
DataCenterVO dc = _dataCenterDao.findById(dataCenterId);
List<String> dnsServers = new ArrayList<String>();
if (configureExternalDns) {
if (!Strings.isNullOrEmpty(dc.getDns1())) {
dnsServers.add(dc.getDns1());
}
if (!Strings.isNullOrEmpty(dc.getDns2())) {
dnsServers.add(dc.getDns2());
}
} else {
if (!Strings.isNullOrEmpty(dc.getInternalDns1())) {
dnsServers.add(dc.getInternalDns1());
}
if (!Strings.isNullOrEmpty(dc.getInternalDns2())) {
dnsServers.add(dc.getInternalDns2());
}
}
return dnsServers;
}
public List<String> getGatewaySystemIds() {
String gatewaySystemIds = String.valueOf(_configDao.getValue(NuageVspManager.NuageVspConfigGateway.key()));
if (!Strings.isNullOrEmpty(gatewaySystemIds)) {
return Lists.newArrayList(gatewaySystemIds.split(","));
}
return Lists.newArrayList();
}
@Override
public List<NuageVspDomainTemplateResponse> listNuageVspDomainTemplates(ListNuageVspDomainTemplatesCmd cmd){
long domainId;
if (cmd.getDomainId() != null) {
domainId = cmd.getDomainId();
} else {
domainId = CallContext.current().getCallingAccount().getDomainId();
}
return listNuageVspDomainTemplates(domainId, cmd.getKeyword(), cmd.getZoneId(), cmd.getPhysicalNetworkId());
}
@Override
public List<NuageVspDomainTemplateResponse> listNuageVspDomainTemplates(long domainId, String keyword, Long zoneId, Long passedPhysicalNetworkId) {
Optional<Long> physicalNetworkId;
Domain domain = _domainDao.findById(domainId);
VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain);
if (passedPhysicalNetworkId != null) {
physicalNetworkId = Optional.of(passedPhysicalNetworkId);
} else if (zoneId != null) {
physicalNetworkId = Optional.ofNullable(getPhysicalNetworkBasedOnZone(zoneId));
} else {
throw new InvalidParameterValueException("No zoneid or physicalnetworkid specified.");
}
if (!physicalNetworkId.isPresent()) {
return new LinkedList<>();
}
Long hostId = getNuageVspHostId(physicalNetworkId.get());
if (hostId == null) {
return new LinkedList<>();
}
ListVspDomainTemplatesCommand agentCmd = new ListVspDomainTemplatesCommand(vspDomain, keyword);
ListVspDomainTemplatesAnswer answer = (ListVspDomainTemplatesAnswer) _agentMgr.easySend(hostId, agentCmd);
List<VspDomainTemplate> domainTemplates = answer.getDomainTemplates();
return domainTemplates.stream()
.map(NuageVspManagerImpl::createDomainTemplateResponse)
.collect(Collectors.toList());
}
private static NuageVspDomainTemplateResponse createDomainTemplateResponse(VspDomainTemplate dt) {
return new NuageVspDomainTemplateResponse(dt.getName(), dt.getDescription());
}
/**
* Returns the PhysicalNetworkId based on a zoneId
* @param zoneId != null, the zone id for which we need to retrieve the PhysicalNetworkId
* @return the physical network id if it's found otherwise null
*/
private Long getPhysicalNetworkBasedOnZone(Long zoneId){
Long physicalNetworkId = null;
List<PhysicalNetworkVO> physicalNetworkVOs = _physicalNetworkDao.listByZoneAndTrafficType(zoneId, Networks.TrafficType.Guest);
for (PhysicalNetworkVO physicalNetwok : physicalNetworkVOs) {
if (physicalNetwok.getIsolationMethods().contains(NUAGE_VSP_ISOLATION)) {
physicalNetworkId = physicalNetwok.getId();
break;
}
}
return physicalNetworkId;
}
@Override
public void associateNuageVspDomainTemplate(AssociateNuageVspDomainTemplateCmd cmd){
VpcVO vpc = _vpcDao.findById(cmd.getVpcId());
Long physicalNetworkId;
if (cmd.getPhysicalNetworkId() != null) {
physicalNetworkId = cmd.getPhysicalNetworkId();
} else if (cmd.getZoneId() != null) {
physicalNetworkId = getPhysicalNetworkBasedOnZone(cmd.getZoneId());
} else {
throw new InvalidParameterValueException("No zoneid or physicalnetworkid specified.");
}
EntityExistsCommand entityCmd = new EntityExistsCommand(VpcVO.class, vpc.getUuid());
boolean exists = entityExist(entityCmd, physicalNetworkId);
if (exists) {
throw new CloudRuntimeException("Failed to associate domain template, VPC is already pushed to the Nuage VSP device.");
}
if (!checkIfDomainTemplateExist(vpc.getDomainId(), cmd.getDomainTemplate(), cmd.getZoneId(), cmd.getPhysicalNetworkId())) {
throw new InvalidParameterValueException("Could not find a Domain Template with name: " + cmd.getDomainTemplate());
}
setPreConfiguredDomainTemplateName(cmd.getVpcId(), cmd.getDomainTemplate());
}
@Override
public boolean checkIfDomainTemplateExist(Long domainId, String domainTemplate, Long zoneId, Long physicalNetworkId){
List<NuageVspDomainTemplateResponse> domainTemplateList = listNuageVspDomainTemplates(domainId, domainTemplate, zoneId, physicalNetworkId);
if (domainTemplateList != null) {
for (NuageVspDomainTemplateResponse val : domainTemplateList) {
if (val.getName().equals(domainTemplate)) {
return true;
}
}
}
return false;
}
@Override
public void updateBroadcastUri(Network network) throws InsufficientVirtualNetworkCapacityException {
NetworkVO updatedNetwork = _networkDao.createForUpdate(network.getId());
URI broadcastUri = calculateBroadcastUri(network);
if (!broadcastUri.equals(network.getBroadcastUri())) {
updatedNetwork.setBroadcastUri(broadcastUri);
_networkDao.update(network.getId(), updatedNetwork);
}
}
@Override
public URI calculateBroadcastUri(Network network) throws InsufficientVirtualNetworkCapacityException {
String vrIp = calculateVirtualRouterIp(network);
return Networks.BroadcastDomainType.Vsp.toUri(network.getUuid() + "/" + vrIp);
}
private boolean usesVirtualRouter(long networkOfferingId) {
return _networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.VirtualRouter) ||
_networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.VPCVirtualRouter);
}
private String calculateVirtualRouterIp(Network network)
throws InsufficientVirtualNetworkCapacityException {
if (!usesVirtualRouter(network.getNetworkOfferingId())) {
return null;
}
List<Pair<String, String>> ipAddressRanges =
network.getGuestType() == Network.GuestType.Shared ? getSharedIpAddressRanges(network.getId()) : getIpAddressRanges(network);
//check if a vr might be present already or not? CLOUD-1216 - before we always picked .2
List<VMInstanceVO> vrs =_vmInstanceDao.listNonRemovedVmsByTypeAndNetwork(network.getId(), VirtualMachine.Type.DomainRouter);
for (VMInstanceVO vr : vrs) {
return _nicDao.listByVmIdAndNicIdAndNtwkId(vr.getId(), null, network.getId()).get(0).getIPv4Address();
}
ensureIpCapacity(network, ipAddressRanges);
if(network.getGuestType() == Network.GuestType.Shared) {
return ipAddressRanges.stream()
.sorted(Comparator.comparingLong(p -> NetUtils.ip2Long(p.getLeft())))
.findFirst()
.map(Pair::getLeft)
.orElseThrow(() -> new IllegalArgumentException("Shared network without ip ranges? How can this happen?"));
}
Network networkToCheck;
if (isMigratingNetwork(network)) {
networkToCheck = _networkDao.findById(network.getRelated());
} else {
networkToCheck = network;
}
Long freeIp = _networkModel.getAvailableIps(networkToCheck, null)
.stream()
.findFirst()
.orElseThrow(() -> new InsufficientVirtualNetworkCapacityException("There is no free ip available for the VirtualRouter.",
Network.class,
network.getId()));
return NetUtils.long2Ip(freeIp);
}
private List<Pair<String, String>> getSharedIpAddressRanges(long networkId) {
List<VlanVO> vlans = _vlanDao.listVlansByNetworkId(networkId);
List<Pair<String, String>> ipAddressRanges = Lists.newArrayList();
for (VlanVO vlan : vlans) {
Pair<String, String> ipAddressRange = NuageVspUtil.getIpAddressRange(vlan);
if (ipAddressRange != null) {
ipAddressRanges.add(ipAddressRange);
}
}
return ipAddressRanges;
}
private List<Pair<String, String>> getIpAddressRanges(Network network) {
List<Pair<String, String>> ipAddressRanges = Lists.newArrayList();
String subnet = NetUtils.getCidrSubNet(network.getCidr());
String netmask = NetUtils.getCidrNetmask(network.getCidr());
long cidrSize = NetUtils.getCidrSize(netmask);
Set<Long> allIPsInCidr = NetUtils.getAllIpsFromCidr(subnet, cidrSize, new HashSet<Long>());
if (allIPsInCidr == null || !(allIPsInCidr instanceof TreeSet)) {
throw new IllegalStateException("The IPs in CIDR for subnet " + subnet + " where null or returned in a non-ordered set.");
}
Iterator<Long> ipIterator = allIPsInCidr.iterator();
long ip = ipIterator.next();
long gatewayIp = NetUtils.ip2Long(network.getGateway());
String lastIp = NetUtils.getIpRangeEndIpFromCidr(subnet, cidrSize);
if (gatewayIp == ip) {
ip = ipIterator.next();
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), lastIp));
} else if (!network.getGateway().equals(lastIp)) {
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), NetUtils.long2Ip(gatewayIp - 1)));
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(gatewayIp + 1), lastIp));
} else {
ipAddressRanges.add(Pair.of(NetUtils.long2Ip(ip), NetUtils.long2Ip(gatewayIp - 1)));
}
return ipAddressRanges;
}
private void ensureIpCapacity(Network network, List<Pair<String, String>> ipAddressRanges) throws InsufficientVirtualNetworkCapacityException {
long ipCount = ipAddressRanges.stream()
.mapToLong(this::getIpCount)
.sum();
if (ipCount == 0) {
throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " But no ip address ranges are specified", Network.class,
network.getId());
} else if (ipCount < 3) {
throw new InsufficientVirtualNetworkCapacityException("VSP allocates an IP for VirtualRouter." + " So, subnet should have atleast minimum 3 hosts", Network.class,
network.getId());
}
}
private boolean isMigratingNetwork(Network network) {
return network.getRelated() != network.getId();
}
private long getIpCount(Pair<String, String> ipAddressRange) {
return NetUtils.ip2Long(ipAddressRange.getRight()) - NetUtils.ip2Long(ipAddressRange.getLeft()) + 1;
}
@Override
public boolean entityExist(EntityExistsCommand cmd, Long physicalNetworkId){
Long hostId = getNuageVspHostId(physicalNetworkId);
if (hostId == null) {
throw new CloudRuntimeException("There is no Nuage VSP device configured on physical network " + physicalNetworkId);
}
Answer answer = _agentMgr.easySend(hostId, cmd);
if (answer != null) {
return answer.getResult();
}
throw new CloudRuntimeException("No answer received from the client");
}
/**
* Sets the preconfigured domain template of a vpc to the given value.
* @param vpcId
* @param domainTemplateName
*/
private void setPreConfiguredDomainTemplateName(long vpcId, String domainTemplateName) {
//remove the previous nuageDomainTemplate if it is present.
if (_vpcDetailsDao.findDetail(vpcId, NuageVspManager.nuageDomainTemplateDetailName) != null) {
_vpcDetailsDao.removeDetail(vpcId, NuageVspManager.nuageDomainTemplateDetailName);
}
VpcDetailVO vpcDetail = new VpcDetailVO(vpcId, NuageVspManager.nuageDomainTemplateDetailName, domainTemplateName, false);
_vpcDetailsDao.persist(vpcDetail);
}
@Override
public void setPreConfiguredDomainTemplateName(Network network, String domainTemplateName) {
if (network.getVpcId() != null) {
setPreConfiguredDomainTemplateName(network.getVpcId(), domainTemplateName);
} else {
NetworkDetailVO networkDetail = new NetworkDetailVO(network.getId(), NuageVspManager.nuageDomainTemplateDetailName, domainTemplateName, false);
_networkDetailsDao.persist(networkDetail);
}
}
@Override
public String getPreConfiguredDomainTemplateName(Network network) {
if (network.getVpcId() != null) {
VpcDetailVO domainTemplateNetworkDetail = _vpcDetailsDao.findDetail(network.getVpcId(), NuageVspManager.nuageDomainTemplateDetailName);
if (domainTemplateNetworkDetail != null) {
return domainTemplateNetworkDetail.getValue();
}
return NuageVspVpcDomainTemplateName.value();
} else {
NetworkDetailVO domainTemplateNetworkDetail = _networkDetailsDao.findDetail(network.getId(), NuageVspManager.nuageDomainTemplateDetailName);
if (domainTemplateNetworkDetail != null) {
return domainTemplateNetworkDetail.getValue();
}
if (network.getGuestType() == Network.GuestType.Shared) {
return NuageVspSharedNetworkDomainTemplateName.value();
}
return NuageVspIsolatedNetworkDomainTemplateName.value();
}
}
@Override
public HostVO getNuageVspHost(long physicalNetworkId) {
HostVO nuageVspHost;
List<NuageVspDeviceVO> nuageVspDevices = _nuageVspDao.listByPhysicalNetwork(physicalNetworkId);
if (CollectionUtils.isEmpty(nuageVspDevices)) {
// Perhaps another physical network is passed from within the same zone, find the VSP physical network in that case
PhysicalNetwork physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId);
List<PhysicalNetworkVO> physicalNetworksInZone = _physicalNetworkDao.listByZone(physicalNetwork.getDataCenterId());
for (PhysicalNetworkVO physicalNetworkInZone : physicalNetworksInZone) {
if (physicalNetworkInZone.getIsolationMethods().contains(NUAGE_VSP_ISOLATION)) {
nuageVspDevices = _nuageVspDao.listByPhysicalNetwork(physicalNetworkInZone.getId());
break;
}
}
}
if (CollectionUtils.isNotEmpty(nuageVspDevices)) {
NuageVspDeviceVO config = nuageVspDevices.iterator().next();
nuageVspHost = _hostDao.findById(config.getHostId());
_hostDao.loadDetails(nuageVspHost);
} else {
throw new CloudRuntimeException("There is no Nuage VSP device configured on physical network " + physicalNetworkId);
}
return nuageVspHost;
}
@Override
public boolean updateNuageUnderlayVlanIpRange(long vlanIpRangeId, boolean enabled) {
VlanVO staticNatVlan = _vlanDao.findById(vlanIpRangeId);
HostVO nuageVspHost = getNuageVspHost(staticNatVlan.getPhysicalNetworkId());
EntityExistsCommand<Vlan> cmd = new EntityExistsCommand<Vlan>(Vlan.class, staticNatVlan.getUuid());
Answer answer = _agentMgr.easySend(nuageVspHost.getId(), cmd);
if (answer != null && !answer.getResult()) {
_vlanDetailsDao.addDetail(staticNatVlan.getId(), NuageVspManager.nuageUnderlayVlanIpRangeDetailKey, String.valueOf(enabled), false);
return true;
}
return false;
}
@Override
public List<NuageVlanIpRangeResponse> filterNuageVlanIpRanges(List<? extends Vlan> vlanIpRanges, Boolean underlay) {
List<NuageVlanIpRangeResponse> nuageVlanIpRanges = Lists.newArrayList();
for (Vlan vlanIpRange : vlanIpRanges) {
NuageVlanIpRangeResponse nuageVlanIpRange = (NuageVlanIpRangeResponse) _responseGenerator.createVlanIpRangeResponse(NuageVlanIpRangeResponse.class, vlanIpRange);
VlanDetailsVO nuageUnderlayDetail = _vlanDetailsDao.findDetail(vlanIpRange.getId(), NuageVspManager.nuageUnderlayVlanIpRangeDetailKey);
boolean underlayEnabled = nuageUnderlayDetail != null && nuageUnderlayDetail.getValue().equalsIgnoreCase(String.valueOf(true));
nuageVlanIpRange.setUnderlay(underlayEnabled);
if (underlay == null || underlayEnabled == underlay) {
nuageVlanIpRanges.add(nuageVlanIpRange);
}
nuageVlanIpRange.setObjectName("nuagevlaniprange");
}
return nuageVlanIpRanges;
}
@Override
public boolean preStateTransitionEvent(Status oldState, Status.Event event, Status newState, Host host, boolean status, Object opaque) {
return true;
}
@Override
public boolean postStateTransitionEvent(StateMachine2.Transition<Status, Status.Event> transition, Host vo, boolean status, Object opaque) {
// Whenever a Nuage VSP Host comes up, check if all CS domains are present and check if the CMS ID is valid
if (transition.getToState() == Status.Up && vo instanceof HostVO) {
auditHost((HostVO) vo);
}
return true;
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
initMessageBusListeners();
initNuageVspResourceListeners();
initNuageVspVpcOffering();
Status.getStateMachine().registerListener(this);
return true;
}
@DB
private void initMessageBusListeners() {
// Create corresponding enterprise and profile in VSP when creating a CS Domain
_messageBus.subscribe(DomainManager.MESSAGE_ADD_DOMAIN_EVENT, (senderAddress, subject, args) -> {
Long domainId = (Long) args;
Domain domain = _domainDao.findById(domainId);
try {
_domainDao.acquireInLockTable(domain.getId());
List<NuageVspDeviceVO> nuageVspDevices = _nuageVspDao.listAll();
for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) {
VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain);
SyncDomainCommand cmd = new SyncDomainCommand(vspDomain, SyncDomainCommand.Type.ADD);
_agentMgr.easySend(nuageVspDevice.getHostId(), cmd);
}
} finally {
_domainDao.releaseFromLockTable(domain.getId());
}
});
// Clean up corresponding resources in VSP when deleting a CS Domain
_messageBus.subscribe(DomainManager.MESSAGE_PRE_REMOVE_DOMAIN_EVENT, (senderAddress, subject, args) -> {
DomainVO domain = (DomainVO) args;
List<NuageVspDeviceVO> nuageVspDevices = _nuageVspDao.listAll();
for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) {
VspDomainCleanUp vspDomainCleanUp = _nuageVspEntityBuilder.buildVspDomainCleanUp(domain);
CleanUpDomainCommand cmd = new CleanUpDomainCommand(vspDomainCleanUp);
_agentMgr.easySend(nuageVspDevice.getHostId(), cmd);
}
});
// Delete corresponding enterprise and profile in VSP when deleting a CS Domain
_messageBus.subscribe(DomainManager.MESSAGE_REMOVE_DOMAIN_EVENT, (senderAddress, subject, args) -> {
DomainVO domain = (DomainVO) args;
List<NuageVspDeviceVO> nuageVspDevices = _nuageVspDao.listAll();
for (NuageVspDeviceVO nuageVspDevice : nuageVspDevices) {
VspDomain vspDomain = _nuageVspEntityBuilder.buildVspDomain(domain);
SyncDomainCommand syncCmd = new SyncDomainCommand(vspDomain, SyncDomainCommand.Type.REMOVE);
_agentMgr.easySend(nuageVspDevice.getHostId(), syncCmd);
}
});
}
private class NuageVspResourceListener extends AbstractListener {
@Override
public boolean processCommands(long agentId, long seq, Command[] commands) {
if (commands != null && commands.length == 1) {
Command command = commands[0];
if (command instanceof PingNuageVspCommand) {
PingNuageVspCommand pingNuageVspCommand = (PingNuageVspCommand)command;
if (pingNuageVspCommand.shouldAudit()) {
auditHost(pingNuageVspCommand.getHostId());
}
}
}
return true;
}
}
@DB
private void initNuageVspResourceListeners() {
_agentMgr.registerForHostEvents(new NuageVspResourceListener(), false, true, false);
}
private Long getNuageVspHostId(long physicalNetworkId) {
List<NuageVspDeviceVO> nuageVspDevices = _nuageVspDao.listByPhysicalNetwork(physicalNetworkId);
if (nuageVspDevices != null && (!nuageVspDevices.isEmpty())) {
NuageVspDeviceVO config = nuageVspDevices.iterator().next();
return config.getHostId();
}
return null;
}
@DB
private void initNuageVspVpcOffering() {
//configure default Nuage VSP vpc offering
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
VpcOffering offering = _vpcOffDao.findByUniqueName(nuageVPCOfferingName);
if (offering == null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Creating default Nuage VPC offering " + nuageVPCOfferingName);
}
createVpcOffering(nuageVPCOfferingName, nuageVPCOfferingDisplayText, DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP, true, VpcOffering.State.Enabled, null);
} else {
updateVpcOffering(offering, DEFAULT_NUAGE_VSP_VPC_SERVICE_MAP);
}
}
});
}
@DB
protected VpcOffering createVpcOffering(final String name, final String displayText, final Multimap<Network.Service, Network.Provider> svcProviderMap, final boolean isDefault,
final VpcOffering.State state, final Long serviceOfferingId) {
return Transaction.execute((TransactionCallback<VpcOffering>)status -> createVpcOfferingInTransaction(name, displayText, svcProviderMap, isDefault, state, serviceOfferingId));
}
private VpcOffering createVpcOfferingInTransaction(String name, String displayText, Multimap<Network.Service, Network.Provider> svcProviderMap, boolean isDefault,
VpcOffering.State state, Long serviceOfferingId) {
// create vpc offering object
VpcOfferingVO offering = new VpcOfferingVO(name, displayText, isDefault, serviceOfferingId, false, false);
if (state != null) {
offering.setState(state);
}
if (s_logger.isDebugEnabled()) {
s_logger.debug(String.format("Adding vpc offering %s", offering));
}
offering = _vpcOffDao.persist(offering);
// populate services and providers
if (svcProviderMap != null) {
for (Map.Entry<Network.Service, Network.Provider> entry : svcProviderMap.entries()) {
Network.Service service = entry.getKey();
Network.Provider provider = entry.getValue();
VpcOfferingServiceMapVO offService = new VpcOfferingServiceMapVO(offering.getId(), service, provider);
_vpcOffSvcMapDao.persist(offService);
if (s_logger.isTraceEnabled()) {
s_logger.trace(String.format("Added service for the vpc offering: %s with provider %s", offService, provider.getName()));
}
}
}
return offering;
}
@DB
protected void updateVpcOffering(final VpcOffering offering, final Multimap<Network.Service, Network.Provider> svcProviderMap) {
Transaction.execute((TransactionCallback<VpcOffering>)status -> updateVpcOfferingInTransaction(offering, svcProviderMap));
}
@Nonnull
private VpcOffering updateVpcOfferingInTransaction(VpcOffering offering, Multimap<Network.Service, Network.Provider> svcProviderMap) {
if (s_logger.isDebugEnabled()) {
s_logger.debug(String.format("Updating vpc offering %s", offering));
}
List<VpcOfferingServiceMapVO> currentVpcOfferingServices = _vpcOffSvcMapDao.listByVpcOffId(offering.getId());
Multimap<Network.Service, Network.Provider> currentSvcProviderMap = HashMultimap.create();
for (VpcOfferingServiceMapVO vpcOfferingService : currentVpcOfferingServices) {
Network.Service service = Network.Service.getService(vpcOfferingService.getService());
Network.Provider provider = Network.Provider.getProvider(vpcOfferingService.getProvider());
currentSvcProviderMap.put(service, provider);
}
for (Map.Entry<Network.Service, Network.Provider> entry : svcProviderMap.entries()) {
Network.Service service = entry.getKey();
Network.Provider provider = entry.getValue();
if (!currentSvcProviderMap.containsEntry(service, provider)) {
VpcOfferingServiceMapVO offService = new VpcOfferingServiceMapVO(offering.getId(), service, provider);
_vpcOffSvcMapDao.persist(offService);
if (s_logger.isDebugEnabled()) {
s_logger.debug(String.format("Added service for the vpc offering: %s", offService));
}
}
}
return offering;
}
private HostVO findNuageVspHost(long hostId) {
HostVO host = _hostDao.findById(hostId);
_hostDao.loadDetails(host);
return host;
}
@Override
public String getConfigComponentName() {
return NuageVspManager.class.getSimpleName();
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return Arrays.copyOf(NUAGE_VSP_CONFIG_KEYS, NUAGE_VSP_CONFIG_KEYS.length);
}
}