// // 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.util; import com.cloud.dc.Vlan; import com.cloud.dc.VlanVO; 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.network.Network; import com.cloud.network.NetworkModel; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.manager.NuageVspManager; import com.cloud.network.rules.FirewallRule; import com.cloud.network.vpc.NetworkACLItem; import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.user.AccountVO; import com.cloud.user.dao.AccountDao; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.dao.VMInstanceDao; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import net.nuage.vsp.acs.client.api.model.VspAclRule; import net.nuage.vsp.acs.client.api.model.VspDhcpDomainOption; import net.nuage.vsp.acs.client.api.model.VspAddressRange; import net.nuage.vsp.acs.client.api.model.VspDhcpVMOption; 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.VspNetwork; import net.nuage.vsp.acs.client.api.model.VspNic; import net.nuage.vsp.acs.client.api.model.VspStaticNat; import net.nuage.vsp.acs.client.api.model.VspVm; import net.nuage.vsp.acs.client.common.model.Pair; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import javax.annotation.Nullable; import javax.inject.Inject; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; public class NuageVspEntityBuilder { private static final Logger s_logger = Logger.getLogger(NuageVspEntityBuilder.class); @Inject NetworkDao _networkDao; @Inject VpcDao _vpcDao; @Inject DomainDao _domainDao; @Inject AccountDao _accountDao; @Inject NetworkOfferingDao _networkOfferingDao; @Inject NetworkOfferingServiceMapDao _networkOfferingServiceMapDao; @Inject NetworkModel _networkModel; @Inject VlanDao _vlanDao; @Inject VlanDetailsDao _vlanDetailsDao; @Inject ConfigurationDao _configurationDao; @Inject IPAddressDao _ipAddressDao; @Inject NetworkDetailsDao _networkDetailsDao; @Inject VMInstanceDao _vmInstanceDao; @Inject NuageVspManager _nuageVspManager; @Inject NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao; public VspDomain buildVspDomain(Domain domain) { return new VspDomain.Builder() .uuid(domain.getUuid()) .name(domain.getName()) .path(domain.getPath()) .build(); } public VspDomainCleanUp buildVspDomainCleanUp(Domain domain) { VspDomainCleanUp.Builder vspDomainCleanUpBuilder = new VspDomainCleanUp.Builder().uuid(domain.getUuid()); Map<String, List<String>> sharedNetworkUuids = Maps.newHashMap(); List<NetworkVO> allSharedNetworks = _networkDao.listByGuestType(Network.GuestType.Shared); for (NetworkVO sharedNetwork : allSharedNetworks) { if (_networkModel.isNetworkAvailableInDomain(sharedNetwork.getId(), domain.getId())) { NetworkOffering networkOffering = _networkOfferingDao.findById(sharedNetwork.getNetworkOfferingId()); String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configurationDao, _networkDetailsDao, sharedNetwork, networkOffering); if (!sharedNetworkUuids.containsKey(preConfiguredDomainTemplateName)) { sharedNetworkUuids.put(preConfiguredDomainTemplateName, Lists.<String>newArrayList()); } sharedNetworkUuids.get(preConfiguredDomainTemplateName).add(sharedNetwork.getUuid()); } } vspDomainCleanUpBuilder.sharedNetworkUuids(sharedNetworkUuids); return vspDomainCleanUpBuilder.build(); } public VspNetwork buildVspNetwork(Network network) { return buildVspNetwork(network.getDomainId(), network); } public VspNetwork buildVspNetwork(long domainId, Network network) { VspNetwork.Builder vspNetworkBuilder = new VspNetwork.Builder() .id(network.getId()) .uuid(network.getUuid()) .name(network.getName()) .cidr(network.getCidr()) .gateway(network.getGateway()); DomainVO domain = _domainDao.findById(domainId); VspDomain vspDomain = buildVspDomain(domain); vspNetworkBuilder.domain(vspDomain); AccountVO account = _accountDao.findById(network.getAccountId()); if (account != null) { vspNetworkBuilder.accountUuid(account.getUuid()).accountName(account.getAccountName()); } NetworkOfferingVO networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); vspNetworkBuilder.egressDefaultPolicy(networkOffering.getEgressDefaultPolicy()).publicAccess(networkOffering.getSupportsPublicAccess()); if (network.getVpcId() != null) { VpcVO vpc = _vpcDao.findById(network.getVpcId()); vspNetworkBuilder.vpcUuid(vpc.getUuid()) .vpcName(vpc.getName()) .networkType(VspNetwork.NetworkType.Vpc); } else { if (networkOffering.getGuestType() == Network.GuestType.Shared) { List<VlanVO> vlans = _vlanDao.listVlansByNetworkIdIncludingRemoved(network.getId()); List<VspAddressRange> vspAddressRanges = Lists.transform(vlans, new Function<VlanVO, VspAddressRange>() { @Nullable @Override public VspAddressRange apply(VlanVO vlanVO) { return new VspAddressRange.Builder().gateway(vlanVO.getVlanGateway()).netmask(vlanVO.getVlanNetmask()).build(); } }); vspNetworkBuilder.networkType(VspNetwork.NetworkType.Shared).addressRanges(vspAddressRanges); } else if (_networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.SourceNat) || _networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.StaticNat)) { vspNetworkBuilder.networkType(VspNetwork.NetworkType.L3); } else { vspNetworkBuilder.networkType(VspNetwork.NetworkType.L2); } } boolean firewallServiceSupported = _networkModel.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Network.Service.Firewall); vspNetworkBuilder.firewallServiceSupported(firewallServiceSupported); String preConfiguredDomainTemplateName = NuageVspUtil.getPreConfiguredDomainTemplateName(_configurationDao, _networkDetailsDao, network, networkOffering); vspNetworkBuilder.domainTemplateName(preConfiguredDomainTemplateName); if (usesVirtualRouter(networkOffering.getId())) { try { List<Pair<String, String>> ipAddressRanges = networkOffering.getGuestType() == Network.GuestType.Shared ? getSharedIpAddressRanges(network.getId()) : getIpAddressRanges(network); String virtualRouterIp = getVirtualRouterIP(network, ipAddressRanges); vspNetworkBuilder.virtualRouterIp(virtualRouterIp); } catch (InsufficientVirtualNetworkCapacityException ex) { s_logger.error("There is an insufficient network capacity in network " + network.getId(), ex); throw new CloudRuntimeException("There is an insufficient network capacity in network " + network.getId(), ex); } } return vspNetworkBuilder.build(); } public boolean usesVirtualRouter(long networkOfferingId) { return _networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.VirtualRouter) || _networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.VPCVirtualRouter); } public VspNetwork updateVspNetworkByPublicIp(VspNetwork vspNetwork, Network network, String publicIp) { List<VlanVO> vlans = _vlanDao.listVlansByNetworkId(network.getId()); final long ip = NetUtils.ip2Long(publicIp); VlanVO matchingVlan = Iterables.find(vlans, new Predicate<VlanVO>() { @Override public boolean apply(@Nullable VlanVO vlan) { Pair<String, String> ipAddressRange = getIpAddressRange(vlan); long startIp = NetUtils.ip2Long(ipAddressRange.getLeft()); long endIp = NetUtils.ip2Long(ipAddressRange.getRight()); return startIp <= ip && ip <= endIp; } }); return new VspNetwork.Builder().fromObject(vspNetwork) .gateway(matchingVlan.getVlanGateway()) .cidr(NetUtils.getCidrFromGatewayAndNetmask(matchingVlan.getVlanGateway(), matchingVlan.getVlanNetmask())) .build(); } 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 = 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; } public Pair<String, String> getIpAddressRange(Vlan vlan) { boolean isIpv4 = StringUtils.isNotBlank(vlan.getIpRange()); String[] range = isIpv4 ? vlan.getIpRange().split("-") : vlan.getIp6Range().split("-"); if (range.length == 2) { return Pair.of(range[0], range[1]); } return null; } private String getVirtualRouterIP(Network network, List<Pair<String, String>> ipAddressRanges) throws InsufficientVirtualNetworkCapacityException { if (network.getBroadcastUri() != null) { return network.getBroadcastUri().getPath().substring(1); } Pair<String, String> lowestIpAddressRange = null; long ipCount = 0; if (ipAddressRanges.size() == 1) { lowestIpAddressRange = Iterables.getOnlyElement(ipAddressRanges); ipCount = NetUtils.ip2Long(lowestIpAddressRange.getRight()) - NetUtils.ip2Long(lowestIpAddressRange.getLeft()) + 1; } else { for (Pair<String, String> ipAddressRange : ipAddressRanges) { if (lowestIpAddressRange == null || NetUtils.ip2Long(ipAddressRange.getLeft()) < NetUtils.ip2Long(lowestIpAddressRange.getLeft())) { lowestIpAddressRange = ipAddressRange; } ipCount += NetUtils.ip2Long(ipAddressRange.getRight()) - NetUtils.ip2Long(ipAddressRange.getLeft()) + 1; } } 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()); } String virtualRouterIp = lowestIpAddressRange.getLeft(); long lowestIp = NetUtils.ip2Long(lowestIpAddressRange.getLeft()); lowestIp = lowestIp + 1; lowestIpAddressRange.setLeft(NetUtils.long2Ip(lowestIp)); return virtualRouterIp; } public VspVm buildVspVm(VirtualMachine vm, Network network) { VspVm.Builder vspVmBuilder = new VspVm.Builder() .uuid(vm.getUuid()) .name(vm.getInstanceName()); switch (vm.getState()) { case Starting: vspVmBuilder.state(VspVm.State.Starting); break; case Running: vspVmBuilder.state(VspVm.State.Running); break; case Stopping: vspVmBuilder.state(VspVm.State.Stopping); break; case Stopped: vspVmBuilder.state(VspVm.State.Stopped); break; case Destroyed: vspVmBuilder.state(VspVm.State.Destroyed); break; case Expunging: vspVmBuilder.state(VspVm.State.Expunging); break; case Migrating: vspVmBuilder.state(VspVm.State.Migrating); break; case Error: vspVmBuilder.state(VspVm.State.Error); break; case Shutdowned: vspVmBuilder.state(VspVm.State.Shutdowned); break; default: vspVmBuilder.state(VspVm.State.Unknown); } boolean isDomainRouter = vm.getType().equals(VirtualMachine.Type.DomainRouter); vspVmBuilder.domainRouter(isDomainRouter); if (network.getBroadcastUri() != null) { String domainRouterIp = network.getBroadcastUri().getPath().substring(1); vspVmBuilder.domainRouterIp(domainRouterIp); } return vspVmBuilder.build(); } public VspNic buildVspNic(String nicUuid, NicProfile nicProfile) { return buildVspNic(nicUuid, nicProfile.getMacAddress(), nicProfile.getIPv4Address(), nicProfile.getNetworkId()); } public VspNic buildVspNic(NicVO nic) { return buildVspNic(nic.getUuid(), nic.getMacAddress(), nic.getIPv4Address(), nic.getNetworkId()); } private VspNic buildVspNic(String uuid, String macAddress, String ip, long networkId) { VspNic.Builder vspNicBuilder = new VspNic.Builder() .uuid(uuid) .macAddress(macAddress) .useStaticIp(true) .ip(ip); Network network = _networkDao.findById(networkId); NetworkOffering networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); return vspNicBuilder.build(); } public VspStaticNat buildVspStaticNat(Boolean forRevoke, IPAddressVO staticNatIp, VlanVO staticNatVlan, NicVO nic) { VspStaticNat.Builder vspStaticNatBuilder = new VspStaticNat.Builder() .ipUuid(staticNatIp.getUuid()) .ipAddress(staticNatIp.getAddress().addr()) .revoke(forRevoke) .oneToOneNat(staticNatIp.isOneToOneNat()) .vlanUuid(staticNatVlan.getUuid()) .vlanGateway(staticNatVlan.getVlanGateway()) .vlanNetmask(staticNatVlan.getVlanNetmask()) .vlanUnderlay(NuageVspUtil.isUnderlayEnabledForVlan(_vlanDetailsDao, staticNatVlan)); if (nic != null) { VspNic vspNic = buildVspNic(nic); vspStaticNatBuilder.nic(vspNic); } return vspStaticNatBuilder.build(); } public VspAclRule buildVspAclRule(FirewallRule firewallRule, Network network) { VspAclRule.Builder vspAclRuleBuilder = new VspAclRule.Builder() .uuid(firewallRule.getUuid()) .protocol(firewallRule.getProtocol()) .startPort(firewallRule.getSourcePortStart()) .endPort(firewallRule.getSourcePortEnd()) .sourceCidrList(firewallRule.getSourceCidrList()) .priority(-1) .type(VspAclRule.ACLType.Firewall); switch (firewallRule.getState()) { case Active: vspAclRuleBuilder.state(VspAclRule.ACLState.Active); break; case Add: vspAclRuleBuilder.state(VspAclRule.ACLState.Add); break; case Revoke: vspAclRuleBuilder.state(VspAclRule.ACLState.Revoke); } switch (firewallRule.getTrafficType()) { case Ingress: vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Ingress); break; case Egress: vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Egress); } NetworkOfferingVO networkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId()); if (firewallRule.getTrafficType() == FirewallRule.TrafficType.Egress && networkOffering.getEgressDefaultPolicy()) { vspAclRuleBuilder.action(VspAclRule.ACLAction.Deny); } else { vspAclRuleBuilder.action(VspAclRule.ACLAction.Allow); } if (firewallRule.getSourceIpAddressId() != null) { IPAddressVO ipAddress = _ipAddressDao.findById(firewallRule.getSourceIpAddressId()); if (ipAddress != null) { vspAclRuleBuilder.sourceIpAddress(ipAddress.getVmIp() + "/32"); } } return vspAclRuleBuilder.build(); } public VspAclRule buildVspAclRule(NetworkACLItem networkAcl) { VspAclRule.Builder vspAclRuleBuilder = new VspAclRule.Builder() .uuid(networkAcl.getUuid()) .protocol(networkAcl.getProtocol()) .startPort(networkAcl.getSourcePortStart()) .endPort(networkAcl.getSourcePortEnd()) .sourceIpAddress(null) .sourceCidrList(networkAcl.getSourceCidrList()) .priority(networkAcl.getNumber()) .type(VspAclRule.ACLType.NetworkACL); switch (networkAcl.getState()) { case Active: vspAclRuleBuilder.state(VspAclRule.ACLState.Active); break; case Add: vspAclRuleBuilder.state(VspAclRule.ACLState.Add); break; case Revoke: vspAclRuleBuilder.state(VspAclRule.ACLState.Revoke); } switch (networkAcl.getTrafficType()) { case Ingress: vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Ingress); break; case Egress: vspAclRuleBuilder.trafficType(VspAclRule.ACLTrafficType.Egress); } switch (networkAcl.getAction()) { case Allow: vspAclRuleBuilder.action(VspAclRule.ACLAction.Allow); break; case Deny: vspAclRuleBuilder.action(VspAclRule.ACLAction.Deny); } return vspAclRuleBuilder.build(); } /** Build VspDhcpVMOption to put on the VM interface */ public VspDhcpVMOption buildVmDhcpOption (NicVO userNic, boolean defaultHasDns, boolean networkHasDns) { VMInstanceVO userVm = _vmInstanceDao.findById(userNic.getInstanceId()); VspDhcpVMOption.Builder vspDhcpVMOptionBuilder = new VspDhcpVMOption.Builder() .nicUuid(userNic.getUuid()) .defaultHasDns(defaultHasDns) .hostname(userVm.getHostName()) .networkHasDns(networkHasDns) .isDefaultInterface(userNic.isDefaultNic()) .domainRouter(VirtualMachine.Type.DomainRouter.equals(userNic.getVmType())); return vspDhcpVMOptionBuilder.build(); } /** Build VspDhcpVMOption to put on the subnet */ public VspDhcpDomainOption buildNetworkDhcpOption(Network network, NetworkOffering offering) { List<String> dnsProvider = _ntwkOfferingSrvcDao.listProvidersForServiceForNetworkOffering(offering.getId(), Network.Service.Dns); boolean isVrDnsProvider = dnsProvider.contains("VirtualRouter") || dnsProvider.contains("VpcVirtualRouter"); VspDhcpDomainOption.Builder vspDhcpDomainBuilder = new VspDhcpDomainOption.Builder() .dnsServers(_nuageVspManager.getDnsDetails(network.getDataCenterId())) .vrIsDnsProvider(isVrDnsProvider); if (isVrDnsProvider) { vspDhcpDomainBuilder.networkDomain(network.getVpcId() != null ? _vpcDao.findById(network.getVpcId()).getNetworkDomain() : network.getNetworkDomain()); } return vspDhcpDomainBuilder.build(); } }