blob: 9882ed503532ca3e6977cd4b7dae291a5d5e9753 [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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.UUID;
import java.util.Collections;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.response.AcquirePodIpCmdResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
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.messagebus.MessageBus;
import org.apache.cloudstack.framework.messagebus.PublishScope;
import org.apache.cloudstack.region.PortableIp;
import org.apache.cloudstack.region.PortableIpDao;
import org.apache.cloudstack.region.PortableIpVO;
import org.apache.cloudstack.region.Region;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import com.cloud.agent.AgentManager;
import com.cloud.alert.AlertManager;
import com.cloud.api.ApiDBUtils;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.configuration.Resource.ResourceType;
import com.cloud.dc.AccountVlanMapVO;
import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.dc.DataCenterIpAddressVO;
import com.cloud.dc.DomainVlanMapVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.Pod;
import com.cloud.dc.PodVlanMapVO;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.VlanVO;
import com.cloud.dc.dao.AccountVlanMapDao;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.dc.dao.DataCenterIpAddressDao;
import com.cloud.dc.dao.DataCenterVnetDao;
import com.cloud.dc.dao.DomainVlanMapDao;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.PodVlanMapDao;
import com.cloud.dc.dao.VlanDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.domain.Domain;
import com.cloud.domain.dao.DomainDao;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventTypes;
import com.cloud.event.UsageEventUtils;
import com.cloud.event.dao.UsageEventDao;
import com.cloud.exception.AccountLimitException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.host.dao.HostDao;
import com.cloud.network.IpAddress.State;
import com.cloud.network.Network.Capability;
import com.cloud.network.Network.GuestType;
import com.cloud.network.Network.Provider;
import com.cloud.network.Network.Service;
import com.cloud.network.Networks.AddressFormat;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.IsolationType;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.addr.PublicIp;
import com.cloud.network.dao.AccountGuestVlanMapDao;
import com.cloud.network.dao.FirewallRulesDao;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.LoadBalancerDao;
import com.cloud.network.dao.NetworkAccountDao;
import com.cloud.network.dao.NetworkDao;
import com.cloud.network.dao.NetworkDetailsDao;
import com.cloud.network.dao.NetworkDetailVO;
import com.cloud.network.dao.NetworkDomainDao;
import com.cloud.network.dao.NetworkServiceMapDao;
import com.cloud.network.dao.PhysicalNetworkDao;
import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
import com.cloud.network.dao.PhysicalNetworkTrafficTypeDao;
import com.cloud.network.dao.UserIpv6AddressDao;
import com.cloud.network.element.IpDeployer;
import com.cloud.network.element.IpDeployingRequester;
import com.cloud.network.element.NetworkElement;
import com.cloud.network.element.StaticNatServiceProvider;
import com.cloud.network.guru.NetworkGuru;
import com.cloud.network.lb.LoadBalancingRulesManager;
import com.cloud.network.rules.FirewallManager;
import com.cloud.network.rules.FirewallRule;
import com.cloud.network.rules.FirewallRule.Purpose;
import com.cloud.network.rules.FirewallRuleVO;
import com.cloud.network.rules.RulesManager;
import com.cloud.network.rules.StaticNat;
import com.cloud.network.rules.dao.PortForwardingRulesDao;
import com.cloud.network.vpc.NetworkACLManager;
import com.cloud.network.vpc.VpcManager;
import com.cloud.network.vpc.VpcVO;
import com.cloud.network.vpc.dao.PrivateIpDao;
import com.cloud.network.vpc.dao.VpcDao;
import com.cloud.network.vpc.dao.VpcOfferingDao;
import com.cloud.network.vpn.RemoteAccessVpnService;
import com.cloud.offering.NetworkOffering;
import com.cloud.offering.NetworkOffering.Availability;
import com.cloud.offerings.NetworkOfferingVO;
import com.cloud.offerings.dao.NetworkOfferingDao;
import com.cloud.offerings.dao.NetworkOfferingDetailsDao;
import com.cloud.offerings.dao.NetworkOfferingServiceMapDao;
import com.cloud.org.Grouping;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.ResourceLimitService;
import com.cloud.user.User;
import com.cloud.user.UserVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.user.dao.UserDao;
import com.cloud.utils.Journal;
import com.cloud.utils.Pair;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.db.JoinBuilder.JoinType;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionCallbackWithException;
import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.exception.ExceptionUtil;
import com.cloud.utils.net.Ip;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.Nic;
import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.ReservationContextImpl;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicIpAliasDao;
import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
public class IpAddressManagerImpl extends ManagerBase implements IpAddressManager, Configurable {
private static final Logger s_logger = Logger.getLogger(IpAddressManagerImpl.class);
@Inject
NetworkOrchestrationService _networkMgr;
@Inject
EntityManager _entityMgr;
@Inject
DataCenterDao _dcDao;
@Inject
VlanDao _vlanDao;
@Inject
IPAddressDao _ipAddressDao;
@Inject
AccountDao _accountDao;
@Inject
DomainDao _domainDao;
@Inject
UserDao _userDao;
@Inject
ConfigurationDao _configDao;
@Inject
UserVmDao _userVmDao;
@Inject
AlertManager _alertMgr;
@Inject
AccountManager _accountMgr;
@Inject
ConfigurationManager _configMgr;
@Inject
AccountVlanMapDao _accountVlanMapDao;
@Inject
DomainVlanMapDao _domainVlanMapDao;
@Inject
NetworkOfferingDao _networkOfferingDao;
@Inject
NetworkDao _networksDao;
@Inject
NetworkDetailsDao _networkDetailsDao;
@Inject
NicDao _nicDao;
@Inject
RulesManager _rulesMgr;
@Inject
LoadBalancingRulesManager _lbMgr;
@Inject
RemoteAccessVpnService _vpnMgr;
@Inject
PodVlanMapDao _podVlanMapDao;
@Inject
NetworkOfferingDetailsDao _ntwkOffDetailsDao;
@Inject
AccountGuestVlanMapDao _accountGuestVlanMapDao;
@Inject
DataCenterVnetDao _datacenterVnetDao;
@Inject
NetworkAccountDao _networkAccountDao;
@Inject
protected NicIpAliasDao _nicIpAliasDao;
@Inject
protected IPAddressDao _publicIpAddressDao;
@Inject
NetworkDomainDao _networkDomainDao;
@Inject
VMInstanceDao _vmDao;
@Inject
FirewallManager _firewallMgr;
@Inject
FirewallRulesDao _firewallDao;
@Inject
ResourceLimitService _resourceLimitMgr;
@Inject
NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao;
@Inject
PhysicalNetworkDao _physicalNetworkDao;
@Inject
PhysicalNetworkServiceProviderDao _pNSPDao;
@Inject
PortForwardingRulesDao _portForwardingRulesDao;
@Inject
LoadBalancerDao _lbDao;
@Inject
PhysicalNetworkTrafficTypeDao _pNTrafficTypeDao;
@Inject
AgentManager _agentMgr;
@Inject
HostDao _hostDao;
@Inject
NetworkServiceMapDao _ntwkSrvcDao;
@Inject
StorageNetworkManager _stnwMgr;
@Inject
VpcManager _vpcMgr;
@Inject
PrivateIpDao _privateIpDao;
@Inject
NetworkACLManager _networkACLMgr;
@Inject
UsageEventDao _usageEventDao;
@Inject
NetworkModel _networkModel;
@Inject
NicSecondaryIpDao _nicSecondaryIpDao;
@Inject
UserIpv6AddressDao _ipv6Dao;
@Inject
Ipv6AddressManager _ipv6Mgr;
@Inject
PortableIpDao _portableIpDao;
@Inject
VpcDao _vpcDao;
@Inject
VpcOfferingDao vpcOfferingDao;
@Inject
DataCenterIpAddressDao _privateIPAddressDao;
@Inject
HostPodDao _hpDao;
@Inject
private AnnotationDao annotationDao;
@Inject
MessageBus messageBus;
SearchBuilder<IPAddressVO> AssignIpAddressSearch;
SearchBuilder<IPAddressVO> AssignIpAddressFromPodVlanSearch;
private static final Object allocatedLock = new Object();
static Boolean rulesContinueOnErrFlag = true;
private static final ConfigKey<Boolean> SystemVmPublicIpReservationModeStrictness = new ConfigKey<Boolean>("Advanced",
Boolean.class, "system.vm.public.ip.reservation.mode.strictness", "false",
"If enabled, the use of System VMs public IP reservation is strict, preferred if not.", true, ConfigKey.Scope.Global);
private Random rand = new Random(System.currentTimeMillis());
private List<Long> getIpv6SupportingVlanRangeIds(long dcId) throws InsufficientAddressCapacityException {
List<VlanVO> vlans = _vlanDao.listIpv6SupportingVlansByZone(dcId);
if (CollectionUtils.isEmpty(vlans)) {
s_logger.error("Unable to find VLAN IP range that support both IPv4 and IPv6");
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
throw ex;
}
return vlans.stream().map(VlanVO::getId).collect(Collectors.toList());
}
@DB
private IPAddressVO assignAndAllocateIpAddressEntry(final Account owner, final VlanType vlanUse, final Long guestNetworkId,
final boolean sourceNat, final boolean allocate, final boolean isSystem,
final Long vpcId, final Boolean displayIp,
final List<IPAddressVO> addressVOS) throws CloudRuntimeException {
return Transaction.execute((TransactionCallbackWithException<IPAddressVO, CloudRuntimeException>) status -> {
IPAddressVO finalAddress = null;
for (IPAddressVO possibleAddr : addressVOS) {
if (possibleAddr.getState() != State.Free) {
continue;
}
possibleAddr.setSourceNat(sourceNat);
possibleAddr.setAllocatedTime(new Date());
possibleAddr.setAllocatedInDomainId(owner.getDomainId());
possibleAddr.setAllocatedToAccountId(owner.getId());
possibleAddr.setSystem(isSystem);
if (displayIp != null) {
possibleAddr.setDisplay(displayIp);
}
if (vlanUse != VlanType.DirectAttached) {
possibleAddr.setAssociatedWithNetworkId(guestNetworkId);
possibleAddr.setVpcId(vpcId);
}
if (_ipAddressDao.lockRow(possibleAddr.getId(), true) != null) {
final IPAddressVO userIp = _ipAddressDao.findById(possibleAddr.getId());
if (userIp.getState() == State.Free) {
possibleAddr.setState(State.Allocating);
if (_ipAddressDao.update(possibleAddr.getId(), possibleAddr)) {
finalAddress = possibleAddr;
break;
}
}
}
}
if (finalAddress == null) {
s_logger.error("Failed to fetch any free public IP address");
throw new CloudRuntimeException("Failed to fetch any free public IP address");
}
if (allocate) {
markPublicIpAsAllocated(finalAddress);
}
final State expectedAddressState = allocate ? State.Allocated : State.Allocating;
if (finalAddress.getState() != expectedAddressState) {
s_logger.error("Failed to fetch new public IP and get in expected state=" + expectedAddressState);
throw new CloudRuntimeException("Failed to fetch new public IP with expected state " + expectedAddressState);
}
return finalAddress;
});
}
@Override
public boolean configure(String name, Map<String, Object> params) {
// populate providers
Map<Network.Service, Set<Network.Provider>> defaultSharedNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
Set<Network.Provider> defaultProviders = new HashSet<Network.Provider>();
defaultProviders.add(Network.Provider.VirtualRouter);
defaultSharedNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
defaultSharedNetworkOfferingProviders.put(Service.Dns, defaultProviders);
defaultSharedNetworkOfferingProviders.put(Service.UserData, defaultProviders);
Map<Network.Service, Set<Network.Provider>> defaultIsolatedNetworkOfferingProviders = defaultSharedNetworkOfferingProviders;
defaultIsolatedNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
defaultIsolatedNetworkOfferingProviders.put(Service.Dns, defaultProviders);
defaultIsolatedNetworkOfferingProviders.put(Service.UserData, defaultProviders);
defaultIsolatedNetworkOfferingProviders.put(Service.Firewall, defaultProviders);
defaultIsolatedNetworkOfferingProviders.put(Service.Gateway, defaultProviders);
defaultIsolatedNetworkOfferingProviders.put(Service.Lb, defaultProviders);
defaultIsolatedNetworkOfferingProviders.put(Service.StaticNat, defaultProviders);
defaultIsolatedNetworkOfferingProviders.put(Service.PortForwarding, defaultProviders);
defaultIsolatedNetworkOfferingProviders.put(Service.Vpn, defaultProviders);
Map<Network.Service, Set<Network.Provider>> defaultSharedSGEnabledNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
defaultSharedSGEnabledNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
defaultSharedSGEnabledNetworkOfferingProviders.put(Service.Dns, defaultProviders);
defaultSharedSGEnabledNetworkOfferingProviders.put(Service.UserData, defaultProviders);
Set<Provider> sgProviders = new HashSet<Provider>();
sgProviders.add(Provider.SecurityGroupProvider);
defaultSharedSGEnabledNetworkOfferingProviders.put(Service.SecurityGroup, sgProviders);
Map<Network.Service, Set<Network.Provider>> defaultIsolatedSourceNatEnabledNetworkOfferingProviders = new HashMap<Network.Service, Set<Network.Provider>>();
defaultProviders.clear();
defaultProviders.add(Network.Provider.VirtualRouter);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dhcp, defaultProviders);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Dns, defaultProviders);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.UserData, defaultProviders);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Firewall, defaultProviders);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Gateway, defaultProviders);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Lb, defaultProviders);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.SourceNat, defaultProviders);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.StaticNat, defaultProviders);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.PortForwarding, defaultProviders);
defaultIsolatedSourceNatEnabledNetworkOfferingProviders.put(Service.Vpn, defaultProviders);
Map<Network.Service, Set<Network.Provider>> defaultVPCOffProviders = new HashMap<Network.Service, Set<Network.Provider>>();
defaultProviders.clear();
defaultProviders.add(Network.Provider.VirtualRouter);
defaultVPCOffProviders.put(Service.Dhcp, defaultProviders);
defaultVPCOffProviders.put(Service.Dns, defaultProviders);
defaultVPCOffProviders.put(Service.UserData, defaultProviders);
defaultVPCOffProviders.put(Service.NetworkACL, defaultProviders);
defaultVPCOffProviders.put(Service.Gateway, defaultProviders);
defaultVPCOffProviders.put(Service.Lb, defaultProviders);
defaultVPCOffProviders.put(Service.SourceNat, defaultProviders);
defaultVPCOffProviders.put(Service.StaticNat, defaultProviders);
defaultVPCOffProviders.put(Service.PortForwarding, defaultProviders);
defaultVPCOffProviders.put(Service.Vpn, defaultProviders);
//#8 - network offering with internal lb service
Map<Network.Service, Set<Network.Provider>> internalLbOffProviders = new HashMap<Network.Service, Set<Network.Provider>>();
Set<Network.Provider> defaultVpcProvider = new HashSet<Network.Provider>();
defaultVpcProvider.add(Network.Provider.VPCVirtualRouter);
Set<Network.Provider> defaultInternalLbProvider = new HashSet<Network.Provider>();
defaultInternalLbProvider.add(Network.Provider.InternalLbVm);
internalLbOffProviders.put(Service.Dhcp, defaultVpcProvider);
internalLbOffProviders.put(Service.Dns, defaultVpcProvider);
internalLbOffProviders.put(Service.UserData, defaultVpcProvider);
internalLbOffProviders.put(Service.NetworkACL, defaultVpcProvider);
internalLbOffProviders.put(Service.Gateway, defaultVpcProvider);
internalLbOffProviders.put(Service.Lb, defaultInternalLbProvider);
internalLbOffProviders.put(Service.SourceNat, defaultVpcProvider);
Map<Network.Service, Set<Network.Provider>> netscalerServiceProviders = new HashMap<Network.Service, Set<Network.Provider>>();
Set<Network.Provider> vrProvider = new HashSet<Network.Provider>();
vrProvider.add(Provider.VirtualRouter);
Set<Network.Provider> sgProvider = new HashSet<Network.Provider>();
sgProvider.add(Provider.SecurityGroupProvider);
Set<Network.Provider> nsProvider = new HashSet<Network.Provider>();
nsProvider.add(Provider.Netscaler);
netscalerServiceProviders.put(Service.Dhcp, vrProvider);
netscalerServiceProviders.put(Service.Dns, vrProvider);
netscalerServiceProviders.put(Service.UserData, vrProvider);
netscalerServiceProviders.put(Service.SecurityGroup, sgProvider);
netscalerServiceProviders.put(Service.StaticNat, nsProvider);
netscalerServiceProviders.put(Service.Lb, nsProvider);
Map<Service, Map<Capability, String>> serviceCapabilityMap = new HashMap<Service, Map<Capability, String>>();
Map<Capability, String> elb = new HashMap<Capability, String>();
elb.put(Capability.ElasticLb, "true");
Map<Capability, String> eip = new HashMap<Capability, String>();
eip.put(Capability.ElasticIp, "true");
serviceCapabilityMap.put(Service.Lb, elb);
serviceCapabilityMap.put(Service.StaticNat, eip);
AssignIpAddressSearch = _ipAddressDao.createSearchBuilder();
AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ);
AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL);
AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN);
AssignIpAddressSearch.and("forSystemVms", AssignIpAddressSearch.entity().isForSystemVms(), Op.EQ);
SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder();
vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ);
vlanSearch.and("networkId", vlanSearch.entity().getNetworkId(), Op.EQ);
vlanSearch.and("vlanGateway", vlanSearch.entity().getVlanGateway(), Op.EQ);
AssignIpAddressSearch.join("vlan", vlanSearch, vlanSearch.entity().getId(), AssignIpAddressSearch.entity().getVlanId(), JoinType.INNER);
AssignIpAddressSearch.done();
AssignIpAddressFromPodVlanSearch = _ipAddressDao.createSearchBuilder();
AssignIpAddressFromPodVlanSearch.and("dc", AssignIpAddressFromPodVlanSearch.entity().getDataCenterId(), Op.EQ);
AssignIpAddressFromPodVlanSearch.and("allocated", AssignIpAddressFromPodVlanSearch.entity().getAllocatedTime(), Op.NULL);
AssignIpAddressFromPodVlanSearch.and("vlanId", AssignIpAddressFromPodVlanSearch.entity().getVlanId(), Op.IN);
SearchBuilder<VlanVO> podVlanSearch = _vlanDao.createSearchBuilder();
podVlanSearch.and("type", podVlanSearch.entity().getVlanType(), Op.EQ);
podVlanSearch.and("networkId", podVlanSearch.entity().getNetworkId(), Op.EQ);
podVlanSearch.and("vlanGateway", podVlanSearch.entity().getVlanGateway(), Op.EQ);
SearchBuilder<PodVlanMapVO> podVlanMapSB = _podVlanMapDao.createSearchBuilder();
podVlanMapSB.and("podId", podVlanMapSB.entity().getPodId(), Op.EQ);
AssignIpAddressFromPodVlanSearch.join("podVlanMapSB", podVlanMapSB, podVlanMapSB.entity().getVlanDbId(), AssignIpAddressFromPodVlanSearch.entity().getVlanId(),
JoinType.INNER);
AssignIpAddressFromPodVlanSearch.join("vlan", podVlanSearch, podVlanSearch.entity().getId(), AssignIpAddressFromPodVlanSearch.entity().getVlanId(), JoinType.INNER);
AssignIpAddressFromPodVlanSearch.done();
Network.State.getStateMachine().registerListener(new NetworkStateListener(_configDao));
if (RulesContinueOnError.value() != null) {
rulesContinueOnErrFlag = RulesContinueOnError.value();
}
s_logger.info("IPAddress Manager is configured.");
return true;
}
private IpAddress allocateIP(Account ipOwner, boolean isSystem, long zoneId) throws ResourceAllocationException, InsufficientAddressCapacityException,
ConcurrentOperationException {
Account caller = CallContext.current().getCallingAccount();
long callerUserId = CallContext.current().getCallingUserId();
// check permissions
_accountMgr.checkAccess(caller, null, false, ipOwner);
DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId);
return allocateIp(ipOwner, isSystem, caller, callerUserId, zone, null, null);
}
// An IP association is required in below cases
// 1.there is at least one public IP associated with the network on which first rule (PF/static NAT/LB) is being applied.
// 2.last rule (PF/static NAT/LB) on the public IP has been revoked. So the public IP should not be associated with any provider
boolean checkIfIpAssocRequired(Network network, boolean postApplyRules, List<PublicIp> publicIps) {
if (network.getState() == Network.State.Implementing) {
return true;
}
for (PublicIp ip : publicIps) {
if (ip.isSourceNat()) {
continue;
} else if (ip.isOneToOneNat()) {
continue;
} else {
Long totalCount = null;
Long revokeCount = null;
Long activeCount = null;
Long addCount = null;
totalCount = _firewallDao.countRulesByIpId(ip.getId());
if (postApplyRules) {
revokeCount = _firewallDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Revoke);
} else {
activeCount = _firewallDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Active);
addCount = _firewallDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Add);
}
if (totalCount == null || totalCount.longValue() == 0L) {
continue;
}
if (postApplyRules) {
if (revokeCount != null && revokeCount.longValue() == totalCount.longValue()) {
s_logger.trace("All rules are in Revoke state, have to dis-assiciate IP from the backend");
return true;
}
} else {
if (activeCount != null && activeCount > 0) {
if (network.getVpcId() != null) {
// If there are more than one ip in the vpc tier network and services configured on it.
// restart network with cleanup case, on network reprogramming this needs to be return true
// because on the VR ips has removed. In VPC case restart tier network with cleanup will not
// reboot the VR. So ipassoc is needed.
return true;
}
continue;
} else if (addCount != null && addCount.longValue() == totalCount.longValue()) {
s_logger.trace("All rules are in Add state, have to assiciate IP with the backend");
return true;
} else {
continue;
}
}
}
}
// there are no IP's corresponding to this network that need to be associated with provider
return false;
}
@Override
public boolean applyRules(List<? extends FirewallRule> rules, FirewallRule.Purpose purpose, NetworkRuleApplier applier, boolean continueOnError)
throws ResourceUnavailableException {
if (rules == null || rules.size() == 0) {
s_logger.debug("There are no rules to forward to the network elements");
return true;
}
boolean success = true;
Network network = _networksDao.findById(rules.get(0).getNetworkId());
FirewallRuleVO.TrafficType trafficType = rules.get(0).getTrafficType();
List<PublicIp> publicIps = new ArrayList<PublicIp>();
if (!(rules.get(0).getPurpose() == FirewallRule.Purpose.Firewall && trafficType == FirewallRule.TrafficType.Egress)) {
// get the list of public ip's owned by the network
List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
if (userIps != null && !userIps.isEmpty()) {
for (IPAddressVO userIp : userIps) {
PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
publicIps.add(publicIp);
}
}
}
// rules can not programmed unless IP is associated with network service provider, so run IP assoication for
// the network so as to ensure IP is associated before applying rules (in add state)
if (checkIfIpAssocRequired(network, false, publicIps)) {
applyIpAssociations(network, false, continueOnError, publicIps);
}
try {
applier.applyRules(network, purpose, rules);
} catch (ResourceUnavailableException e) {
if (!continueOnError) {
throw e;
}
s_logger.warn("Problems with applying " + purpose + " rules but pushing on", e);
success = false;
}
// if there are no active rules associated with a public IP, then public IP need not be associated with a provider.
// This IPAssoc ensures, public IP is dis-associated after last active rule is revoked.
if (checkIfIpAssocRequired(network, true, publicIps)) {
applyIpAssociations(network, true, continueOnError, publicIps);
}
return success;
}
protected boolean cleanupIpResources(long ipId, long userId, Account caller) {
boolean success = true;
// Revoke all firewall rules for the ip
try {
s_logger.debug("Revoking all " + Purpose.Firewall + "rules as a part of public IP id=" + ipId + " release...");
if (!_firewallMgr.revokeFirewallRulesForIp(ipId, userId, caller)) {
s_logger.warn("Unable to revoke all the firewall rules for ip id=" + ipId + " as a part of ip release");
success = false;
}
} catch (ResourceUnavailableException e) {
s_logger.warn("Unable to revoke all firewall rules for ip id=" + ipId + " as a part of ip release", e);
success = false;
}
// Revoke all PF/Static nat rules for the ip
try {
s_logger.debug("Revoking all " + Purpose.PortForwarding + "/" + Purpose.StaticNat + " rules as a part of public IP id=" + ipId + " release...");
if (!_rulesMgr.revokeAllPFAndStaticNatRulesForIp(ipId, userId, caller)) {
s_logger.warn("Unable to revoke all the port forwarding rules for ip id=" + ipId + " as a part of ip release");
success = false;
}
} catch (ResourceUnavailableException e) {
s_logger.warn("Unable to revoke all the port forwarding rules for ip id=" + ipId + " as a part of ip release", e);
success = false;
}
s_logger.debug("Revoking all " + Purpose.LoadBalancing + " rules as a part of public IP id=" + ipId + " release...");
if (!_lbMgr.removeAllLoadBalanacersForIp(ipId, caller, userId)) {
s_logger.warn("Unable to revoke all the load balancer rules for ip id=" + ipId + " as a part of ip release");
success = false;
}
// remote access vpn can be enabled only for static nat ip, so this part should never be executed under normal
// conditions
// only when ip address failed to be cleaned up as a part of account destroy and was marked as Releasing, this part of
// the code would be triggered
s_logger.debug("Cleaning up remote access vpns as a part of public IP id=" + ipId + " release...");
try {
_vpnMgr.destroyRemoteAccessVpnForIp(ipId, caller,false);
} catch (ResourceUnavailableException e) {
s_logger.warn("Unable to destroy remote access vpn for ip id=" + ipId + " as a part of ip release", e);
success = false;
}
return success;
}
@Override
@DB
public boolean disassociatePublicIpAddress(long addrId, long userId, Account caller) {
boolean success = true;
// Cleanup all ip address resources - PF/LB/Static nat rules
if (!cleanupIpResources(addrId, userId, caller)) {
success = false;
s_logger.warn("Failed to release resources for ip address id=" + addrId);
}
IPAddressVO ip = markIpAsUnavailable(addrId);
if (ip == null) {
return true;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Releasing ip id=" + addrId + "; sourceNat = " + ip.isSourceNat());
}
if (ip.getAssociatedWithNetworkId() != null) {
Network network = _networksDao.findById(ip.getAssociatedWithNetworkId());
try {
if (!applyIpAssociations(network, rulesContinueOnErrFlag)) {
s_logger.warn("Unable to apply ip address associations for " + network);
success = false;
}
} catch (ResourceUnavailableException e) {
throw new CloudRuntimeException("We should never get to here because we used true when applyIpAssociations", e);
}
} else {
if (ip.getState() == IpAddress.State.Releasing) {
_ipAddressDao.unassignIpAddress(ip.getId());
}
}
annotationDao.removeByEntityType(AnnotationService.EntityType.PUBLIC_IP_ADDRESS.name(), ip.getUuid());
if (success) {
if (ip.isPortable()) {
releasePortableIpAddress(addrId);
}
s_logger.debug("Released a public ip id=" + addrId);
}
return success;
}
@DB
@Override
public boolean releasePortableIpAddress(final long addrId) {
final GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange");
try {
return Transaction.execute(new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(TransactionStatus status) {
portableIpLock.lock(5);
IPAddressVO ip = _ipAddressDao.findById(addrId);
// unassign portable IP
PortableIpVO portableIp = _portableIpDao.findByIpAddress(ip.getAddress().addr());
_portableIpDao.unassignIpAddress(portableIp.getId());
// removed the provisioned vlan
VlanVO vlan = _vlanDao.findById(ip.getVlanId());
_vlanDao.remove(vlan.getId());
// remove the provisioned public ip address
_ipAddressDao.remove(ip.getId());
return true;
}
});
} finally {
portableIpLock.releaseRef();
}
}
@Override
public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem, boolean forSystemVms)
throws InsufficientAddressCapacityException {
return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, null, isSystem, null, null, forSystemVms);
}
@Override
public PublicIp assignSourceNatPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem, boolean forSystemVms)
throws InsufficientAddressCapacityException {
IPAddressVO networkPublicIp = _ipAddressDao.findByIpAndNetworkIdAndDcId(networkId, dcId, requestedIp);
if(networkPublicIp != null)
return null;
IPAddressVO ipAddressVO = _ipAddressDao.findByIpAndDcId(dcId, requestedIp);
if (ipAddressVO.getState() != State.Free) {
throw new InsufficientAddressCapacityException("can not assign to this network", Network.class, networkId);
}
return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, true, true, requestedIp, null, isSystem, null, null, forSystemVms);
}
@Override
public PublicIp assignPublicIpAddressFromVlans(long dcId, Long podId, Account owner, VlanType type, List<Long> vlanDbIds, Long networkId, String requestedIp, String requestedGateway, boolean isSystem)
throws InsufficientAddressCapacityException {
return fetchNewPublicIp(dcId, podId, vlanDbIds, owner, type, networkId, false, true, requestedIp, requestedGateway, isSystem, null, null, false);
}
@Override
public PublicIp getAvailablePublicIpAddressFromVlans(long dcId, Long podId, Account owner, VlanType type, List<Long> vlanDbIds, Long networkId, String requestedIp, boolean isSystem)
throws InsufficientAddressCapacityException {
return fetchNewPublicIp(dcId, podId, vlanDbIds, owner, type, networkId, false, false, false, requestedIp, null, isSystem, null, null, false);
}
@DB
public PublicIp fetchNewPublicIp(final long dcId, final Long podId, final List<Long> vlanDbIds, final Account owner, final VlanType vlanUse, final Long guestNetworkId,
final boolean sourceNat, final boolean allocate, final String requestedIp, final String requestedGateway, final boolean isSystem, final Long vpcId, final Boolean displayIp, final boolean forSystemVms)
throws InsufficientAddressCapacityException {
return fetchNewPublicIp(dcId, podId, vlanDbIds, owner, vlanUse, guestNetworkId,
sourceNat, true, allocate, requestedIp, requestedGateway, isSystem, vpcId, displayIp, forSystemVms);
}
@DB
public PublicIp fetchNewPublicIp(final long dcId, final Long podId, final List<Long> vlanDbIds, final Account owner, final VlanType vlanUse, final Long guestNetworkId,
final boolean sourceNat, final boolean assign, final boolean allocate, final String requestedIp, final String requestedGateway, final boolean isSystem, final Long vpcId, final Boolean displayIp, final boolean forSystemVms)
throws InsufficientAddressCapacityException {
List<IPAddressVO> addrs = listAvailablePublicIps(dcId, podId, vlanDbIds, owner, vlanUse, guestNetworkId, sourceNat, assign, allocate, requestedIp, requestedGateway, isSystem, vpcId, displayIp, forSystemVms, true);
IPAddressVO addr = addrs.get(0);
if (assign) {
addr = assignAndAllocateIpAddressEntry(owner, vlanUse, guestNetworkId, sourceNat, allocate,
isSystem,vpcId, displayIp, addrs);
}
if (vlanUse == VlanType.VirtualNetwork) {
_firewallMgr.addSystemFirewallRules(addr, owner);
}
return PublicIp.createFromAddrAndVlan(addr, _vlanDao.findById(addr.getVlanId()));
}
@Override
public List<IPAddressVO> listAvailablePublicIps(final long dcId, final Long podId, final List<Long> vlanDbIds, final Account owner, final VlanType vlanUse, final Long guestNetworkId,
final boolean sourceNat, final boolean assign, final boolean allocate, final String requestedIp, final String requestedGateway, final boolean isSystem,
final Long vpcId, final Boolean displayIp, final boolean forSystemVms, final boolean lockOneRow) throws InsufficientAddressCapacityException {
StringBuilder errorMessage = new StringBuilder("Unable to get ip address in ");
boolean fetchFromDedicatedRange = false;
List<Long> dedicatedVlanDbIds = new ArrayList<Long>();
List<Long> nonDedicatedVlanDbIds = new ArrayList<Long>();
DataCenter zone = _entityMgr.findById(DataCenter.class, dcId);
SearchCriteria<IPAddressVO> sc = null;
if (podId != null) {
sc = AssignIpAddressFromPodVlanSearch.create();
sc.setJoinParameters("podVlanMapSB", "podId", podId);
errorMessage.append(" pod id=" + podId);
} else {
sc = AssignIpAddressSearch.create();
errorMessage.append(" zone id=" + dcId);
}
sc.setParameters("dc", dcId);
// for direct network take ip addresses only from the vlans belonging to the network
if (vlanUse == VlanType.DirectAttached) {
sc.setJoinParameters("vlan", "networkId", guestNetworkId);
errorMessage.append(", network id=" + guestNetworkId);
}
if (requestedGateway != null) {
sc.setJoinParameters("vlan", "vlanGateway", requestedGateway);
errorMessage.append(", requested gateway=" + requestedGateway);
}
sc.setJoinParameters("vlan", "type", vlanUse);
Network network = _networksDao.findById(guestNetworkId);
String routerIpAddress = null;
if (network != null) {
NetworkDetailVO routerIpDetail = _networkDetailsDao.findDetail(network.getId(), ApiConstants.ROUTER_IP);
routerIpAddress = routerIpDetail != null ? routerIpDetail.getValue() : null;
}
if (requestedIp != null) {
sc.addAnd("address", SearchCriteria.Op.EQ, requestedIp);
errorMessage.append(": requested ip " + requestedIp + " is not available");
} else if (routerIpAddress != null) {
sc.addAnd("address", Op.NEQ, routerIpAddress);
}
boolean ascOrder = ! forSystemVms;
Filter filter = new Filter(IPAddressVO.class, "forSystemVms", ascOrder, 0l, 1l);
filter.addOrderBy(IPAddressVO.class,"vlanId", true);
List<IPAddressVO> addrs = new ArrayList<>();
if (forSystemVms) {
// Get Public IPs for system vms in dedicated ranges
sc.setParameters("forSystemVms", true);
if (lockOneRow) {
addrs = _ipAddressDao.lockRows(sc, filter, true);
} else {
addrs = new ArrayList<>(_ipAddressDao.search(sc, null));
}
}
if ((!lockOneRow || (lockOneRow && CollectionUtils.isEmpty(addrs))) &&
!(forSystemVms && SystemVmPublicIpReservationModeStrictness.value())) {
sc.setParameters("forSystemVms", false);
// If owner has dedicated Public IP ranges, fetch IP from the dedicated range
// Otherwise fetch IP from the system pool
// Checking if network is null in the case of system VM's. At the time of allocation of IP address to systemVm, no network is present.
if (network == null || !(network.getGuestType() == GuestType.Shared && zone.getNetworkType() == NetworkType.Advanced)) {
List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByAccount(owner.getId());
for (AccountVlanMapVO map : maps) {
if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
dedicatedVlanDbIds.add(map.getVlanDbId());
}
}
List<DomainVlanMapVO> domainMaps = _domainVlanMapDao.listDomainVlanMapsByDomain(owner.getDomainId());
for (DomainVlanMapVO map : domainMaps) {
if (vlanDbIds == null || vlanDbIds.contains(map.getVlanDbId()))
dedicatedVlanDbIds.add(map.getVlanDbId());
}
List<VlanVO> nonDedicatedVlans = _vlanDao.listZoneWideNonDedicatedVlans(dcId);
for (VlanVO nonDedicatedVlan : nonDedicatedVlans) {
if (vlanDbIds == null || vlanDbIds.contains(nonDedicatedVlan.getId()))
nonDedicatedVlanDbIds.add(nonDedicatedVlan.getId());
}
if (vlanUse == VlanType.VirtualNetwork) {
if (!dedicatedVlanDbIds.isEmpty()) {
fetchFromDedicatedRange = true;
sc.setParameters("vlanId", dedicatedVlanDbIds.toArray());
errorMessage.append(", vlanId id=" + Arrays.toString(dedicatedVlanDbIds.toArray()));
} else if (!nonDedicatedVlanDbIds.isEmpty()) {
sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
} else {
if (podId != null) {
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid());
throw ex;
}
s_logger.warn(errorMessage.toString());
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
throw ex;
}
}
if (lockOneRow) {
addrs = _ipAddressDao.lockRows(sc, filter, true);
} else {
addrs = new ArrayList<>(_ipAddressDao.search(sc, null));
}
// If all the dedicated IPs of the owner are in use fetch an IP from the system pool
if ((!lockOneRow || (lockOneRow && addrs.size() == 0)) && fetchFromDedicatedRange && vlanUse == VlanType.VirtualNetwork) {
// Verify if account is allowed to acquire IPs from the system
boolean useSystemIps = UseSystemPublicIps.valueIn(owner.getId());
if (useSystemIps && !nonDedicatedVlanDbIds.isEmpty()) {
fetchFromDedicatedRange = false;
sc.setParameters("vlanId", nonDedicatedVlanDbIds.toArray());
errorMessage.append(", vlanId id=" + Arrays.toString(nonDedicatedVlanDbIds.toArray()));
if (lockOneRow) {
addrs = _ipAddressDao.lockRows(sc, filter, true);
} else {
addrs.addAll(_ipAddressDao.search(sc, null));
}
}
}
}
if (lockOneRow && addrs.size() == 0) {
if (podId != null) {
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", Pod.class, podId);
// for now, we hardcode the table names, but we should ideally do a lookup for the tablename from the VO object.
ex.addProxyObject(ApiDBUtils.findPodById(podId).getUuid());
throw ex;
}
s_logger.warn(errorMessage.toString());
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Insufficient address capacity", DataCenter.class, dcId);
ex.addProxyObject(ApiDBUtils.findZoneById(dcId).getUuid());
throw ex;
}
if (lockOneRow) {
assert (addrs.size() == 1) : "Return size is incorrect: " + addrs.size();
}
if (assign && !fetchFromDedicatedRange && VlanType.VirtualNetwork.equals(vlanUse)) {
// Check that the maximum number of public IPs for the given accountId will not be exceeded
try {
_resourceLimitMgr.checkResourceLimit(owner, ResourceType.public_ip);
} catch (ResourceAllocationException ex) {
s_logger.warn("Failed to allocate resource of type " + ex.getResourceType() + " for account " + owner);
throw new AccountLimitException("Maximum number of public IP addresses for account: " + owner.getAccountName() + " has been exceeded.");
}
}
return addrs;
}
@DB
@Override
public void markPublicIpAsAllocated(final IPAddressVO addr) {
synchronized (allocatedLock) {
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
Account owner = _accountMgr.getAccount(addr.getAllocatedToAccountId());
if (_ipAddressDao.lockRow(addr.getId(), true) != null) {
final IPAddressVO userIp = _ipAddressDao.findById(addr.getId());
if (userIp.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Free || addr.getState() == IpAddress.State.Reserved) {
boolean shouldUpdateIpResourceCount = checkIfIpResourceCountShouldBeUpdated(addr);
addr.setState(IpAddress.State.Allocated);
if (_ipAddressDao.update(addr.getId(), addr)) {
// Save usage event
if (owner.getAccountId() != Account.ACCOUNT_ID_SYSTEM) {
VlanVO vlan = _vlanDao.findById(addr.getVlanId());
String guestType = vlan.getVlanType().toString();
if (!isIpDedicated(addr)) {
final boolean usageHidden = isUsageHidden(addr);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, owner.getId(), addr.getDataCenterId(), addr.getId(),
addr.getAddress().toString(), addr.isSourceNat(), guestType, addr.getSystem(), usageHidden,
addr.getClass().getName(), addr.getUuid());
}
if (shouldUpdateIpResourceCount) {
_resourceLimitMgr.incrementResourceCount(owner.getId(), ResourceType.public_ip);
}
}
} else {
s_logger.error("Failed to mark public IP as allocated with id=" + addr.getId() + " address=" + addr.getAddress());
}
}
} else {
s_logger.error("Failed to acquire row lock to mark public IP as allocated with id=" + addr.getId() + " address=" + addr.getAddress());
}
}
});
}
}
protected boolean isIpDedicated(IPAddressVO addr) {
List<AccountVlanMapVO> maps = _accountVlanMapDao.listAccountVlanMapsByVlan(addr.getVlanId());
if (maps != null && !maps.isEmpty())
return true;
return false;
}
@Override
public PublicIp assignSourceNatIpAddressToGuestNetwork(Account owner, Network guestNetwork) throws InsufficientAddressCapacityException, ConcurrentOperationException {
assert(guestNetwork.getTrafficType() != null) : "You're asking for a source nat but your network "
+ "can't participate in source nat. What do you have to say for yourself?";
long dcId = guestNetwork.getDataCenterId();
IPAddressVO sourceNatIp = getExistingSourceNatInNetwork(owner.getId(), guestNetwork.getId());
PublicIp ipToReturn = null;
if (sourceNatIp != null) {
ipToReturn = PublicIp.createFromAddrAndVlan(sourceNatIp, _vlanDao.findById(sourceNatIp.getVlanId()));
} else {
ipToReturn = assignDedicateIpAddress(owner, guestNetwork.getId(), null, dcId, true);
}
return ipToReturn;
}
@DB
@Override
public PublicIp assignDedicateIpAddress(Account owner, final Long guestNtwkId, final Long vpcId, final long dcId, final boolean isSourceNat)
throws ConcurrentOperationException, InsufficientAddressCapacityException {
final long ownerId = owner.getId();
PublicIp ip = null;
try {
ip = Transaction.execute(new TransactionCallbackWithException<PublicIp, InsufficientAddressCapacityException>() {
@Override
public PublicIp doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
Account owner = _accountDao.acquireInLockTable(ownerId);
if (owner == null) {
// this ownerId comes from owner or type Account. See the class "AccountVO" and the annotations in that class
// to get the table name and field name that is queried to fill this ownerid.
ConcurrentOperationException ex = new ConcurrentOperationException("Unable to lock account");
throw ex;
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("lock account " + ownerId + " is acquired");
}
List<Long> vlanDbIds = null;
boolean displayIp = true;
if (guestNtwkId != null) {
Network ntwk = _networksDao.findById(guestNtwkId);
if (_networkOfferingDao.isIpv6Supported(ntwk.getNetworkOfferingId())) {
vlanDbIds = getIpv6SupportingVlanRangeIds(dcId);
}
displayIp = ntwk.getDisplayNetwork();
} else if (vpcId != null) {
VpcVO vpc = _vpcDao.findById(vpcId);
if (vpcOfferingDao.isIpv6Supported(vpc.getVpcOfferingId())) {
vlanDbIds = getIpv6SupportingVlanRangeIds(dcId);
}
displayIp = vpc.isDisplay();
}
return fetchNewPublicIp(dcId, null, vlanDbIds, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, true, null, null, false, vpcId, displayIp, false);
}
});
if (ip.getState() != State.Allocated) {
s_logger.error("Failed to fetch new IP and allocate it for ip with id=" + ip.getId() + ", address=" + ip.getAddress());
}
return ip;
} finally {
if (owner != null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Releasing lock account " + ownerId);
}
_accountDao.releaseFromLockTable(ownerId);
}
if (ip == null) {
s_logger.error("Unable to get source nat ip address for account " + ownerId);
}
}
}
@Override
public boolean applyIpAssociations(Network network, boolean continueOnError) throws ResourceUnavailableException {
List<IPAddressVO> userIps = _ipAddressDao.listByAssociatedNetwork(network.getId(), null);
boolean success = true;
// CloudStack will take a lazy approach to associate an acquired public IP to a network service provider as
// it will not know what service an acquired IP will be used for. An IP is actually associated with a provider when first
// rule is applied. Similarly when last rule on the acquired IP is revoked, IP is not associated with any provider
// but still be associated with the account. At this point just mark IP as allocated or released.
for (IPAddressVO addr : userIps) {
if (addr.getState() == IpAddress.State.Allocating || addr.getState() == IpAddress.State.Reserved) {
addr.setAssociatedWithNetworkId(network.getId());
markPublicIpAsAllocated(addr);
} else if (addr.getState() == IpAddress.State.Releasing) {
// Cleanup all the resources for ip address if there are any, and only then un-assign ip in the system
if (cleanupIpResources(addr.getId(), Account.ACCOUNT_ID_SYSTEM, _accountMgr.getSystemAccount())) {
_ipAddressDao.unassignIpAddress(addr.getId());
messageBus.publish(_name, MESSAGE_RELEASE_IPADDR_EVENT, PublishScope.LOCAL, addr);
} else {
success = false;
s_logger.warn("Failed to release resources for ip address id=" + addr.getId());
}
}
}
return success;
}
// CloudStack will take a lazy approach to associate an acquired public IP to a network service provider as
// it will not know what a acquired IP will be used for. An IP is actually associated with a provider when first
// rule is applied. Similarly when last rule on the acquired IP is revoked, IP is not associated with any provider
// but still be associated with the account. Its up to caller of this function to decide when to invoke IPAssociation
@Override
public boolean applyIpAssociations(Network network, boolean postApplyRules, boolean continueOnError, List<? extends PublicIpAddress> publicIps)
throws ResourceUnavailableException {
boolean success = true;
Map<PublicIpAddress, Set<Service>> ipToServices = _networkModel.getIpToServices(publicIps, postApplyRules, true);
Map<Provider, ArrayList<PublicIpAddress>> providerToIpList = _networkModel.getProviderToIpList(network, ipToServices);
for (Provider provider : providerToIpList.keySet()) {
try {
ArrayList<PublicIpAddress> ips = providerToIpList.get(provider);
if (ips == null || ips.isEmpty()) {
continue;
}
IpDeployer deployer = null;
NetworkElement element = _networkModel.getElementImplementingProvider(provider.getName());
if (!(element instanceof IpDeployingRequester)) {
throw new CloudRuntimeException("Element " + element + " is not a IpDeployingRequester!");
}
deployer = ((IpDeployingRequester)element).getIpDeployer(network);
if (deployer == null) {
throw new CloudRuntimeException("Fail to get ip deployer for element: " + element);
}
Set<Service> services = new HashSet<Service>();
for (PublicIpAddress ip : ips) {
if (!ipToServices.containsKey(ip)) {
continue;
}
services.addAll(ipToServices.get(ip));
}
deployer.applyIps(network, ips, services);
} catch (ResourceUnavailableException e) {
success = false;
if (!continueOnError) {
throw e;
} else {
s_logger.debug("Resource is not available: " + provider.getName(), e);
}
}
}
return success;
}
private String generateErrorMessageForOperationOnDisabledZone(String operation, DataCenter zone) {
return String.format("Cannot %s, %s is currently disabled.", operation, zone);
}
@DB
@Override
public AcquirePodIpCmdResponse allocatePodIp(String zoneId, String podId) throws ConcurrentOperationException, ResourceAllocationException {
DataCenter zone = _entityMgr.findByUuid(DataCenter.class, zoneId);
Account caller = CallContext.current().getCallingAccount();
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) {
ResourceAllocationException ex = new ResourceAllocationException(
generateErrorMessageForOperationOnDisabledZone("allocate Pod IP addresses", zone), ResourceType.network);
throw ex;
}
DataCenterIpAddressVO vo = null;
if (podId == null)
throw new ResourceAllocationException("Please do not provide NULL podId", ResourceType.network);
HostPodVO podvo = null;
podvo = _hpDao.findByUuid(podId);
if (podvo == null)
throw new ResourceAllocationException("No such pod exists", ResourceType.network);
vo = _privateIPAddressDao.takeIpAddress(zone.getId(), podvo.getId(), 0, caller.getId() + "", false);
if(vo == null)
throw new ResourceAllocationException("Unable to allocate IP from this Pod", ResourceType.network);
if (vo.getIpAddress() == null)
throw new ResourceAllocationException("Unable to allocate IP from this Pod", ResourceType.network);
HostPodVO pod_vo = _hpDao.findById(vo.getPodId());
AcquirePodIpCmdResponse ret = new AcquirePodIpCmdResponse();
ret.setCidrAddress(pod_vo.getCidrAddress());
ret.setGateway(pod_vo.getGateway());
ret.setInstanceId(vo.getInstanceId());
ret.setIpAddress(vo.getIpAddress());
ret.setMacAddress(vo.getMacAddress());
ret.setPodId(vo.getPodId());
ret.setId(vo.getId());
return ret;
}
@DB
@Override
public void releasePodIp(Long id) throws CloudRuntimeException {
// Verify input parameters
DataCenterIpAddressVO ipVO = _privateIPAddressDao.findById(id);
if (ipVO == null) {
throw new CloudRuntimeException("Unable to find ip address by id:" + id);
}
if (ipVO.getTakenAt() == null) {
s_logger.debug("Ip Address with id= " + id + " is not allocated, so do nothing.");
throw new CloudRuntimeException("Ip Address with id= " + id + " is not allocated, so do nothing.");
}
// Verify permission
DataCenter zone = _entityMgr.findById(DataCenter.class, ipVO.getDataCenterId());
Account caller = CallContext.current().getCallingAccount();
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) {
throw new CloudRuntimeException(generateErrorMessageForOperationOnDisabledZone("release Pod IP", zone));
}
try {
_privateIPAddressDao.releasePodIpAddress(id);
} catch (Exception e) {
new CloudRuntimeException(e.getMessage());
}
}
@DB
@Override
public IpAddress allocateIp(final Account ipOwner, final boolean isSystem, Account caller, long callerUserId, final DataCenter zone, final Boolean displayIp, final String ipaddress)
throws ConcurrentOperationException,
ResourceAllocationException, InsufficientAddressCapacityException {
final VlanType vlanType = VlanType.VirtualNetwork;
final boolean assign = false;
if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) {
// zone is of type DataCenter. See DataCenterVO.java.
PermissionDeniedException ex = new PermissionDeniedException(generateErrorMessageForOperationOnDisabledZone("allocate IP addresses", zone));
ex.addProxyObject(zone.getUuid(), "zoneId");
throw ex;
}
PublicIp ip = null;
Account accountToLock = null;
try {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Associate IP address called by the user " + callerUserId + " account " + ipOwner.getId());
}
accountToLock = _accountDao.acquireInLockTable(ipOwner.getId());
if (accountToLock == null) {
s_logger.warn("Unable to lock account: " + ipOwner.getId());
throw new ConcurrentOperationException("Unable to acquire account lock");
}
if (s_logger.isDebugEnabled()) {
s_logger.debug("Associate IP address lock acquired");
}
if (ipaddress != null) {
IPAddressVO ipAddr = _ipAddressDao.findByAccountIdAndZoneIdAndStateAndIpAddress(ipOwner.getId(), zone.getId(), State.Reserved, ipaddress);
if (ipAddr != null) {
return PublicIp.createFromAddrAndVlan(ipAddr, _vlanDao.findById(ipAddr.getVlanId()));
}
}
ip = Transaction.execute(new TransactionCallbackWithException<PublicIp, InsufficientAddressCapacityException>() {
@Override
public PublicIp doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
PublicIp ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, ipaddress, null, isSystem, null, displayIp, false);
if (ip == null) {
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zone
.getId());
ex.addProxyObject(ApiDBUtils.findZoneById(zone.getId()).getUuid());
throw ex;
}
CallContext.current().setEventDetails("Ip Id: " + ip.getId());
Ip ipAddress = ip.getAddress();
s_logger.debug("Got " + ipAddress + " to assign for account " + ipOwner.getId() + " in zone " + zone.getId());
return ip;
}
});
messageBus.publish(_name, MESSAGE_ASSIGN_IPADDR_EVENT, PublishScope.LOCAL, ip.ip());
} finally {
if (accountToLock != null) {
if (s_logger.isDebugEnabled()) {
s_logger.debug("Releasing lock account " + ipOwner);
}
_accountDao.releaseFromLockTable(ipOwner.getId());
s_logger.debug("Associate IP address lock released");
}
}
return ip;
}
@Override
@DB
public IpAddress allocatePortableIp(final Account ipOwner, Account caller, final long dcId, final Long networkId, final Long vpcID)
throws ConcurrentOperationException,
ResourceAllocationException, InsufficientAddressCapacityException {
GlobalLock portableIpLock = GlobalLock.getInternLock("PortablePublicIpRange");
IPAddressVO ipaddr;
try {
portableIpLock.lock(5);
ipaddr = Transaction.execute(new TransactionCallbackWithException<IPAddressVO, InsufficientAddressCapacityException>() {
@Override
public IPAddressVO doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
PortableIpVO allocatedPortableIp;
List<PortableIpVO> portableIpVOs = _portableIpDao.listByRegionIdAndState(1, PortableIp.State.Free);
if (portableIpVOs == null || portableIpVOs.isEmpty()) {
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Unable to find available portable IP addresses", Region.class,
new Long(1));
throw ex;
}
// allocate first portable IP to the user
allocatedPortableIp = portableIpVOs.get(0);
allocatedPortableIp.setAllocatedTime(new Date());
allocatedPortableIp.setAllocatedToAccountId(ipOwner.getAccountId());
allocatedPortableIp.setAllocatedInDomainId(ipOwner.getDomainId());
allocatedPortableIp.setState(PortableIp.State.Allocated);
_portableIpDao.update(allocatedPortableIp.getId(), allocatedPortableIp);
// To make portable IP available as a zone level resource we need to emulate portable IP's (which are
// provisioned at region level) as public IP provisioned in a zone. user_ip_address and vlan combo give the
// identity of a public IP in zone. Create entry for portable ip in these tables.
// provision portable IP range VLAN into the zone
long physicalNetworkId = _networkModel.getDefaultPhysicalNetworkByZoneAndTrafficType(dcId, TrafficType.Public).getId();
Network network = _networkModel.getSystemNetworkByZoneAndTrafficType(dcId, TrafficType.Public);
String range = allocatedPortableIp.getAddress() + "-" + allocatedPortableIp.getAddress();
VlanVO vlan = new VlanVO(VlanType.VirtualNetwork, allocatedPortableIp.getVlan(), allocatedPortableIp.getGateway(), allocatedPortableIp.getNetmask(), dcId,
range, network.getId(), physicalNetworkId, null, null, null);
vlan = _vlanDao.persist(vlan);
// provision the portable IP in to user_ip_address table
IPAddressVO ipaddr = new IPAddressVO(new Ip(allocatedPortableIp.getAddress()), dcId, networkId, vpcID, physicalNetworkId, network.getId(), vlan.getId(), true);
ipaddr.setState(State.Allocated);
ipaddr.setAllocatedTime(new Date());
ipaddr.setAllocatedInDomainId(ipOwner.getDomainId());
ipaddr.setAllocatedToAccountId(ipOwner.getId());
ipaddr = _ipAddressDao.persist(ipaddr);
final boolean usageHidden = isUsageHidden(ipaddr);
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_PORTABLE_IP_ASSIGN, ipaddr.getId(), ipaddr.getDataCenterId(), ipaddr.getId(),
ipaddr.getAddress().toString(), ipaddr.isSourceNat(), null, ipaddr.getSystem(), usageHidden, ipaddr.getClass().getName(), ipaddr.getUuid());
return ipaddr;
}
});
} finally {
portableIpLock.unlock();
}
return ipaddr;
}
protected IPAddressVO getExistingSourceNatInNetwork(long ownerId, Long networkId) {
List<? extends IpAddress> addrs;
Network guestNetwork = _networksDao.findById(networkId);
if (guestNetwork.getGuestType() == GuestType.Shared) {
// ignore the account id for the shared network
addrs = _networkModel.listPublicIpsAssignedToGuestNtwk(networkId, true);
} else {
addrs = _networkModel.listPublicIpsAssignedToGuestNtwk(ownerId, networkId, true);
}
IPAddressVO sourceNatIp = null;
if (addrs.isEmpty()) {
return null;
} else {
// Account already has ip addresses
for (IpAddress addr : addrs) {
if (addr.isSourceNat()) {
sourceNatIp = _ipAddressDao.findById(addr.getId());
return sourceNatIp;
}
}
assert(sourceNatIp != null) : "How do we get a bunch of ip addresses but none of them are source nat? " + "account=" + ownerId + "; networkId=" + networkId;
}
return sourceNatIp;
}
@DB
@Override
public IPAddressVO associateIPToGuestNetwork(long ipId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException,
InsufficientAddressCapacityException, ConcurrentOperationException {
Account caller = CallContext.current().getCallingAccount();
Account owner = null;
IPAddressVO ipToAssoc = _ipAddressDao.findById(ipId);
if (ipToAssoc != null) {
Network network = _networksDao.findById(networkId);
if (network == null) {
throw new InvalidParameterValueException("Invalid network id is given");
}
DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
if (zone.getNetworkType() == NetworkType.Advanced) {
if (network.getGuestType() == Network.GuestType.Shared) {
if (isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) {
_accountMgr.checkAccess(CallContext.current().getCallingAccount(), AccessType.UseEntry, false,
network);
} else {
throw new InvalidParameterValueException("IP can be associated with guest network of 'shared' type only if "
+ "network services Source Nat, Static Nat, Port Forwarding, Load balancing, firewall are enabled in the network");
}
}
} else {
_accountMgr.checkAccess(caller, null, true, ipToAssoc);
}
owner = _accountMgr.getAccount(ipToAssoc.getAllocatedToAccountId());
} else {
s_logger.debug("Unable to find ip address by id: " + ipId);
return null;
}
if (ipToAssoc.getAssociatedWithNetworkId() != null) {
s_logger.debug("IP " + ipToAssoc + " is already associated with network id=" + networkId);
return ipToAssoc;
}
Network network = _networksDao.findById(networkId);
if (network != null) {
_accountMgr.checkAccess(owner, AccessType.UseEntry, false, network);
} else {
s_logger.debug("Unable to find ip address by id: " + ipId);
return null;
}
DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
// allow associating IP addresses to guest network only
if (network.getTrafficType() != TrafficType.Guest) {
throw new InvalidParameterValueException("Ip address can be associated to the network with trafficType " + TrafficType.Guest);
}
// Check that network belongs to IP owner - skip this check
// - if zone is basic zone as there is just one guest network,
// - if shared network in Advanced zone
// - and it belongs to the system
if (network.getAccountId() != owner.getId()) {
if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) {
throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP");
}
}
if (zone.getNetworkType() == NetworkType.Advanced) {
// In Advance zone allow to do IP assoc only for Isolated networks with source nat service enabled
if (network.getGuestType() == GuestType.Isolated && !(_networkModel.areServicesSupportedInNetwork(network.getId(), Service.SourceNat))) {
if (releaseOnFailure && ipToAssoc != null) {
s_logger.warn("Failed to associate ip address, so unassigning ip from the database " + ipToAssoc);
_ipAddressDao.unassignIpAddress(ipToAssoc.getId());
}
throw new InvalidParameterValueException("In zone of type " + NetworkType.Advanced + " ip address can be associated only to the network of guest type "
+ GuestType.Isolated + " with the " + Service.SourceNat.getName() + " enabled");
}
// In Advance zone allow to do IP assoc only for shared networks with source nat/static nat/lb/pf services enabled
if (network.getGuestType() == GuestType.Shared && !isSharedNetworkOfferingWithServices(network.getNetworkOfferingId())) {
if (releaseOnFailure && ipToAssoc != null) {
s_logger.warn("Failed to associate ip address, so unassigning ip from the database " + ipToAssoc);
_ipAddressDao.unassignIpAddress(ipToAssoc.getId());
}
throw new InvalidParameterValueException("In zone of type " + NetworkType.Advanced + " ip address can be associated with network of guest type " + GuestType.Shared
+ "only if at " + "least one of the services " + Service.SourceNat.getName() + "/" + Service.StaticNat.getName() + "/" + Service.Lb.getName() + "/"
+ Service.PortForwarding.getName() + " is enabled");
}
}
boolean isSourceNat = isSourceNatAvailableForNetwork(owner, ipToAssoc, network);
s_logger.debug("Associating ip " + ipToAssoc + " to network " + network);
IPAddressVO ip = _ipAddressDao.findById(ipId);
//update ip address with networkId
ip.setAssociatedWithNetworkId(networkId);
ip.setSourceNat(isSourceNat);
_ipAddressDao.update(ipId, ip);
boolean success = false;
try {
success = applyIpAssociations(network, false);
if (success) {
s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " to network " + network);
} else {
s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network);
}
return _ipAddressDao.findById(ipId);
} finally {
if (!success && releaseOnFailure) {
if (ip != null) {
try {
s_logger.warn("Failed to associate ip address, so releasing ip from the database " + ip);
_ipAddressDao.markAsUnavailable(ip.getId());
if (!applyIpAssociations(network, true)) {
// if fail to apply ip associations again, unassign ip address without updating resource
// count and generating usage event as there is no need to keep it in the db
_ipAddressDao.unassignIpAddress(ip.getId());
}
} catch (Exception e) {
s_logger.warn("Unable to disassociate ip address for recovery", e);
}
}
}
}
}
/**
* Prevents associating an IP address to an allocated (unimplemented network) network, throws an Exception otherwise
* @param owner Used to check if the user belongs to the Network
* @param ipToAssoc IP address to be associated to a Network, can only be associated to an implemented network for Source NAT
* @param network Network to which IP address is to be associated with, must not be in allocated state for Source NAT Network/IP association
* @return true if IP address can be successfully associated with Source NAT network
*/
protected boolean isSourceNatAvailableForNetwork(Account owner, IPAddressVO ipToAssoc, Network network) {
NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
boolean sharedSourceNat = offering.isSharedSourceNat();
boolean isSourceNat = false;
if (!sharedSourceNat) {
if (getExistingSourceNatInNetwork(owner.getId(), network.getId()) == null) {
if (network.getGuestType() == GuestType.Isolated && network.getVpcId() == null && !ipToAssoc.isPortable()) {
isSourceNat = true;
}
}
}
return isSourceNat;
}
protected boolean isSharedNetworkOfferingWithServices(long networkOfferingId) {
NetworkOfferingVO networkOffering = _networkOfferingDao.findById(networkOfferingId);
if ((networkOffering.getGuestType() == Network.GuestType.Shared)
&& (_networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.SourceNat)
|| _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.StaticNat)
|| _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.Firewall)
|| _networkModel.areServicesSupportedByNetworkOffering(networkOfferingId, Service.PortForwarding) || _networkModel.areServicesSupportedByNetworkOffering(
networkOfferingId, Service.Lb))) {
return true;
}
return false;
}
@Override
public IPAddressVO associatePortableIPToGuestNetwork(long ipAddrId, long networkId, boolean releaseOnFailure) throws ResourceAllocationException, ResourceUnavailableException,
InsufficientAddressCapacityException, ConcurrentOperationException {
return associateIPToGuestNetwork(ipAddrId, networkId, releaseOnFailure);
}
@DB
@Override
public IPAddressVO disassociatePortableIPToGuestNetwork(long ipId, long networkId) throws ResourceAllocationException, ResourceUnavailableException,
InsufficientAddressCapacityException, ConcurrentOperationException {
Account caller = CallContext.current().getCallingAccount();
Account owner = null;
Network network = _networksDao.findById(networkId);
if (network == null) {
throw new InvalidParameterValueException("Invalid network id is given");
}
IPAddressVO ipToAssoc = _ipAddressDao.findById(ipId);
if (ipToAssoc != null) {
if (ipToAssoc.getAssociatedWithNetworkId() == null) {
throw new InvalidParameterValueException("IP " + ipToAssoc + " is not associated with any network");
}
if (ipToAssoc.getAssociatedWithNetworkId() != network.getId()) {
throw new InvalidParameterValueException("IP " + ipToAssoc + " is not associated with network id" + networkId);
}
DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
if (zone.getNetworkType() == NetworkType.Advanced) {
if (network.getGuestType() == Network.GuestType.Shared) {
assert(isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()));
_accountMgr.checkAccess(CallContext.current().getCallingAccount(), AccessType.UseEntry, false,
network);
}
} else {
_accountMgr.checkAccess(caller, null, true, ipToAssoc);
}
owner = _accountMgr.getAccount(ipToAssoc.getAllocatedToAccountId());
} else {
s_logger.debug("Unable to find ip address by id: " + ipId);
return null;
}
DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
// Check that network belongs to IP owner - skip this check
// - if zone is basic zone as there is just one guest network,
// - if shared network in Advanced zone
// - and it belongs to the system
if (network.getAccountId() != owner.getId()) {
if (zone.getNetworkType() != NetworkType.Basic && !(zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() == Network.GuestType.Shared)) {
throw new InvalidParameterValueException("The owner of the network is not the same as owner of the IP");
}
}
// Check if IP has any services (rules) associated in the network
List<PublicIpAddress> ipList = new ArrayList<PublicIpAddress>();
PublicIp publicIp = PublicIp.createFromAddrAndVlan(ipToAssoc, _vlanDao.findById(ipToAssoc.getVlanId()));
ipList.add(publicIp);
Map<PublicIpAddress, Set<Service>> ipToServices = _networkModel.getIpToServices(ipList, false, true);
if (!ipToServices.isEmpty()) {
Set<Service> services = ipToServices.get(publicIp);
if (services != null && !services.isEmpty()) {
throw new InvalidParameterValueException("IP " + ipToAssoc + " has services and rules associated in the network " + networkId);
}
}
IPAddressVO ip = _ipAddressDao.findById(ipId);
ip.setAssociatedWithNetworkId(null);
_ipAddressDao.update(ipId, ip);
try {
boolean success = applyIpAssociations(network, false);
if (success) {
s_logger.debug("Successfully associated ip address " + ip.getAddress().addr() + " to network " + network);
} else {
s_logger.warn("Failed to associate ip address " + ip.getAddress().addr() + " to network " + network);
}
return ip;
} finally {
}
}
@Override
public boolean isPortableIpTransferableFromNetwork(long ipAddrId, long networkId) {
Network network = _networksDao.findById(networkId);
if (network == null) {
throw new InvalidParameterValueException("Invalid network id is given");
}
IPAddressVO ip = _ipAddressDao.findById(ipAddrId);
if (ip == null) {
throw new InvalidParameterValueException("Invalid network id is given");
}
// Check if IP has any services (rules) associated in the network
List<PublicIpAddress> ipList = new ArrayList<PublicIpAddress>();
PublicIp publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId()));
ipList.add(publicIp);
Map<PublicIpAddress, Set<Service>> ipToServices = _networkModel.getIpToServices(ipList, false, true);
if (!ipToServices.isEmpty()) {
Set<Service> ipServices = ipToServices.get(publicIp);
if (ipServices != null && !ipServices.isEmpty()) {
return false;
}
}
return true;
}
@DB
@Override
public void transferPortableIP(final long ipAddrId, long currentNetworkId, long newNetworkId) throws ResourceAllocationException, ResourceUnavailableException,
InsufficientAddressCapacityException, ConcurrentOperationException {
Network srcNetwork = _networksDao.findById(currentNetworkId);
if (srcNetwork == null) {
throw new InvalidParameterValueException("Invalid source network id " + currentNetworkId + " is given");
}
final Network dstNetwork = _networksDao.findById(newNetworkId);
if (dstNetwork == null) {
throw new InvalidParameterValueException("Invalid source network id " + newNetworkId + " is given");
}
final IPAddressVO ip = _ipAddressDao.findById(ipAddrId);
if (ip == null) {
throw new InvalidParameterValueException("Invalid portable ip address id is given");
}
assert(isPortableIpTransferableFromNetwork(ipAddrId, currentNetworkId));
// disassociate portable IP with current network/VPC network
if (srcNetwork.getVpcId() != null) {
_vpcMgr.unassignIPFromVpcNetwork(ipAddrId, currentNetworkId);
} else {
disassociatePortableIPToGuestNetwork(ipAddrId, currentNetworkId);
}
// If portable IP need to be transferred across the zones, then mark the entry corresponding to portable ip
// in user_ip_address and vlan tables so as to emulate portable IP as provisioned in destination data center
if (srcNetwork.getDataCenterId() != dstNetwork.getDataCenterId()) {
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
long physicalNetworkId = _networkModel.getDefaultPhysicalNetworkByZoneAndTrafficType(dstNetwork.getDataCenterId(), TrafficType.Public).getId();
long publicNetworkId = _networkModel.getSystemNetworkByZoneAndTrafficType(dstNetwork.getDataCenterId(), TrafficType.Public).getId();
ip.setDataCenterId(dstNetwork.getDataCenterId());
ip.setPhysicalNetworkId(physicalNetworkId);
ip.setSourceNetworkId(publicNetworkId);
_ipAddressDao.update(ipAddrId, ip);
VlanVO vlan = _vlanDao.findById(ip.getVlanId());
vlan.setPhysicalNetworkId(physicalNetworkId);
vlan.setNetworkId(publicNetworkId);
vlan.setDataCenterId(dstNetwork.getDataCenterId());
_vlanDao.update(ip.getVlanId(), vlan);
}
});
}
// associate portable IP with new network/VPC network
associatePortableIPToGuestNetwork(ipAddrId, newNetworkId, false);
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
if (dstNetwork.getVpcId() != null) {
ip.setVpcId(dstNetwork.getVpcId());
} else {
ip.setVpcId(null);
}
_ipAddressDao.update(ipAddrId, ip);
}
});
// trigger an action event for the transfer of portable IP across the networks, so that external entities
// monitoring for this event can initiate the route advertisement for the availability of IP from the zoe
ActionEventUtils.onActionEvent(User.UID_SYSTEM, Account.ACCOUNT_ID_SYSTEM, Domain.ROOT_DOMAIN, EventTypes.EVENT_PORTABLE_IP_TRANSFER,
"Portable IP associated is transferred from network " + currentNetworkId + " to " + newNetworkId, newNetworkId, ApiCommandResourceType.Network.toString());
}
protected List<? extends Network> getIsolatedNetworksWithSourceNATOwnedByAccountInZone(long zoneId, Account owner) {
return _networksDao.listSourceNATEnabledNetworks(owner.getId(), zoneId, Network.GuestType.Isolated);
}
@Override
@DB
public boolean associateIpAddressListToAccount(long userId, final long accountId, final long zoneId, final Long vlanId, final Network guestNetworkFinal)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, ResourceAllocationException {
final Account owner = _accountMgr.getActiveAccountById(accountId);
if (guestNetworkFinal != null && guestNetworkFinal.getTrafficType() != TrafficType.Guest) {
throw new InvalidParameterValueException("Network " + guestNetworkFinal + " is not of a type " + TrafficType.Guest);
}
Ternary<Boolean, List<NetworkOfferingVO>, Network> pair = null;
try {
pair = Transaction.execute(new TransactionCallbackWithException<Ternary<Boolean, List<NetworkOfferingVO>, Network>, Exception>() {
@Override
public Ternary<Boolean, List<NetworkOfferingVO>, Network> doInTransaction(TransactionStatus status) throws InsufficientCapacityException,
ResourceAllocationException {
boolean createNetwork = false;
Network guestNetwork = guestNetworkFinal;
if (guestNetwork == null) {
List<? extends Network> networks = getIsolatedNetworksWithSourceNATOwnedByAccountInZone(zoneId, owner);
if (networks.size() == 0) {
createNetwork = true;
} else if (networks.size() == 1) {
guestNetwork = networks.get(0);
} else {
throw new InvalidParameterValueException("Error, more than 1 Guest Isolated Networks with SourceNAT "
+ "service enabled found for this account, cannot assosiate the IP range, please provide the network ID");
}
}
// create new Virtual network (Isolated with SourceNAT) for the user if it doesn't exist
List<NetworkOfferingVO> requiredOfferings = _networkOfferingDao.listByAvailability(Availability.Required, false);
if (requiredOfferings.size() < 1) {
throw new CloudRuntimeException("Unable to find network offering with availability=" + Availability.Required
+ " to automatically create the network as part of createVlanIpRange");
}
if (createNetwork) {
if (requiredOfferings.get(0).getState() == NetworkOffering.State.Enabled) {
long physicalNetworkId = _networkModel.findPhysicalNetworkId(zoneId, requiredOfferings.get(0).getTags(), requiredOfferings.get(0).getTrafficType());
// Validate physical network
PhysicalNetwork physicalNetwork = _physicalNetworkDao.findById(physicalNetworkId);
if (physicalNetwork == null) {
throw new InvalidParameterValueException("Unable to find physical network with id: " + physicalNetworkId + " and tag: "
+ requiredOfferings.get(0).getTags());
}
s_logger.debug("Creating network for account " + owner + " from the network offering id=" + requiredOfferings.get(0).getId()
+ " as a part of createVlanIpRange process");
guestNetwork = _networkMgr.createGuestNetwork(requiredOfferings.get(0).getId(), owner.getAccountName() + "-network", owner.getAccountName()
+ "-network", null, null, null, false, null, owner, null, physicalNetwork, zoneId, ACLType.Account, null, null, null, null, true, null, null, null, null, null,
null, null, null, null, null);
if (guestNetwork == null) {
s_logger.warn("Failed to create default Virtual network for the account " + accountId + "in zone " + zoneId);
throw new CloudRuntimeException("Failed to create a Guest Isolated Networks with SourceNAT "
+ "service enabled as a part of createVlanIpRange, for the account " + accountId + "in zone " + zoneId);
}
} else {
throw new CloudRuntimeException("Required network offering id=" + requiredOfferings.get(0).getId() + " is not in " + NetworkOffering.State.Enabled);
}
}
// Check if there is a source nat ip address for this account; if not - we have to allocate one
boolean allocateSourceNat = false;
List<IPAddressVO> sourceNat = _ipAddressDao.listByAssociatedNetwork(guestNetwork.getId(), true);
if (sourceNat.isEmpty()) {
allocateSourceNat = true;
}
// update all ips with a network id, mark them as allocated and update resourceCount/usage
List<IPAddressVO> ips = _ipAddressDao.listByVlanId(vlanId);
boolean isSourceNatAllocated = false;
for (IPAddressVO addr : ips) {
if (addr.getState() != State.Allocated) {
if (!isSourceNatAllocated && allocateSourceNat) {
addr.setSourceNat(true);
isSourceNatAllocated = true;
} else {
addr.setSourceNat(false);
}
addr.setAssociatedWithNetworkId(guestNetwork.getId());
addr.setVpcId(guestNetwork.getVpcId());
addr.setAllocatedTime(new Date());
addr.setAllocatedInDomainId(owner.getDomainId());
addr.setAllocatedToAccountId(owner.getId());
addr.setSystem(false);
addr.setState(IpAddress.State.Allocating);
markPublicIpAsAllocated(addr);
}
}
return new Ternary<Boolean, List<NetworkOfferingVO>, Network>(createNetwork, requiredOfferings, guestNetwork);
}
});
} catch (Exception e1) {
ExceptionUtil.rethrowRuntime(e1);
ExceptionUtil.rethrow(e1, InsufficientCapacityException.class);
ExceptionUtil.rethrow(e1, ResourceAllocationException.class);
throw new IllegalStateException(e1);
}
boolean createNetwork = pair.first();
List<NetworkOfferingVO> requiredOfferings = pair.second();
Network guestNetwork = pair.third();
// if the network offering has persistent set to true, implement the network
if (createNetwork && requiredOfferings.get(0).isPersistent()) {
DataCenter zone = _dcDao.findById(zoneId);
DeployDestination dest = new DeployDestination(zone, null, null, null);
Account callerAccount = CallContext.current().getCallingAccount();
UserVO callerUser = _userDao.findById(CallContext.current().getCallingUserId());
Journal journal = new Journal.LogJournal("Implementing " + guestNetwork, s_logger);
ReservationContext context = new ReservationContextImpl(UUID.randomUUID().toString(), journal, callerUser, callerAccount);
s_logger.debug("Implementing network " + guestNetwork + " as a part of network provision for persistent network");
try {
Pair<? extends NetworkGuru, ? extends Network> implementedNetwork = _networkMgr.implementNetwork(guestNetwork.getId(), dest, context);
if (implementedNetwork == null || implementedNetwork.first() == null) {
s_logger.warn("Failed to implement the network " + guestNetwork);
}
if (implementedNetwork != null) {
guestNetwork = implementedNetwork.second();
}
} catch (Exception ex) {
s_logger.warn("Failed to implement network " + guestNetwork + " elements and resources as a part of" + " network provision due to ", ex);
CloudRuntimeException e = new CloudRuntimeException("Failed to implement network (with specified id)"
+ " elements and resources as a part of network provision for persistent network");
e.addProxyObject(guestNetwork.getUuid(), "networkId");
throw e;
}
}
return true;
}
@DB
@Override
public IPAddressVO markIpAsUnavailable(final long addrId) {
final IPAddressVO ip = _ipAddressDao.findById(addrId);
if (ip.getAllocatedToAccountId() == null && ip.getAllocatedTime() == null) {
s_logger.trace("Ip address id=" + addrId + " is already released");
return ip;
}
if (ip.getState() != State.Releasing) {
return Transaction.execute(new TransactionCallback<IPAddressVO>() {
@Override
public IPAddressVO doInTransaction(TransactionStatus status) {
if (checkIfIpResourceCountShouldBeUpdated(ip)) {
_resourceLimitMgr.decrementResourceCount(_ipAddressDao.findById(addrId).getAllocatedToAccountId(), ResourceType.public_ip);
}
// Save usage event
if (ip.getAllocatedToAccountId() != null && ip.getAllocatedToAccountId() != Account.ACCOUNT_ID_SYSTEM) {
VlanVO vlan = _vlanDao.findById(ip.getVlanId());
String guestType = vlan.getVlanType().toString();
if (!isIpDedicated(ip)) {
String eventType = ip.isPortable() ? EventTypes.EVENT_PORTABLE_IP_RELEASE : EventTypes.EVENT_NET_IP_RELEASE;
final boolean usageHidden = isUsageHidden(ip);
UsageEventUtils.publishUsageEvent(eventType, ip.getAllocatedToAccountId(), ip.getDataCenterId(), addrId, ip.getAddress().addr(), ip.isSourceNat(),
guestType, ip.getSystem(), usageHidden, ip.getClass().getName(), ip.getUuid());
}
}
return _ipAddressDao.markAsUnavailable(addrId);
}
});
}
return ip;
}
protected boolean checkIfIpResourceCountShouldBeUpdated(IPAddressVO ip) {
boolean isDirectIp = ip.getAssociatedWithNetworkId() == null && ip.getVpcId() == null;
if (isDirectIp) {
s_logger.debug(String.format("IP address [%s] is direct; therefore, the resource count should not be updated.", ip));
return false;
}
if (isIpDedicated(ip)) {
s_logger.debug(String.format("IP address [%s] is dedicated; therefore, the resource count should not be updated.", ip));
return false;
}
boolean isReservedIp = ip.getState() == IpAddress.State.Reserved;
if (isReservedIp) {
s_logger.debug(String.format("IP address [%s] is reserved; therefore, the resource count should not be updated.", ip));
return false;
}
s_logger.debug(String.format("IP address [%s] is not direct, dedicated or reserved; therefore, the resource count should be updated.", ip));
return true;
}
@Override
@DB
public String acquireGuestIpAddress(Network network, String requestedIp) {
if (requestedIp != null && requestedIp.equals(network.getGateway())) {
s_logger.warn("Requested ip address " + requestedIp + " is used as a gateway address in network " + network);
return null;
}
if (_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty() && network.getCidr() == null) {
return null;
}
Set<Long> availableIps = _networkModel.getAvailableIps(network, requestedIp);
if (availableIps == null || availableIps.isEmpty()) {
s_logger.debug("There are no free ips in the network " + network);
return null;
}
Long[] array = availableIps.toArray(new Long[availableIps.size()]);
if (requestedIp != null) {
// check that requested ip has the same cidr
String[] cidr = network.getCidr().split("/");
boolean isSameCidr = NetUtils.sameSubnetCIDR(requestedIp, NetUtils.long2Ip(array[0]), Integer.parseInt(cidr[1]));
if (!isSameCidr) {
s_logger.warn("Requested ip address " + requestedIp + " doesn't belong to the network " + network + " cidr");
return null;
} else if (NetUtils.IsIpEqualToNetworkOrBroadCastIp(requestedIp, cidr[0], Integer.parseInt(cidr[1]))) {
s_logger.warn("Requested ip address " + requestedIp + " is equal to the to the network/broadcast ip of the network" + network);
return null;
}
return requestedIp;
}
return NetUtils.long2Ip(array[rand.nextInt(array.length)]);
}
@Override
public String acquireFirstGuestIpAddress(Network network) {
if (_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty() && network.getCidr() == null) {
return null;
}
Set<Long> availableIps = _networkModel.getAvailableIps(network, null);
if (availableIps == null || availableIps.isEmpty()) {
s_logger.debug("There are no free ips in the network " + network);
return null;
}
return NetUtils.long2Ip(availableIps.iterator().next());
}
@Override
public String acquireLastGuestIpAddress(Network network) {
if (_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty() && network.getCidr() == null) {
return null;
}
Set<Long> availableIps = _networkModel.getAvailableIps(network, null);
if (availableIps == null || availableIps.isEmpty()) {
s_logger.debug("There are no free ips in the network " + network);
return null;
}
List<Long> availableIpsReverse = new ArrayList(availableIps);
Collections.sort(availableIpsReverse, Collections.reverseOrder());
return NetUtils.long2Ip(availableIpsReverse.iterator().next());
}
@Override
public String acquireGuestIpAddressByPlacement(Network network, String requestedIp) {
if (requestedIp != null) {
return this.acquireGuestIpAddress(network, requestedIp);
}
String placementConfig = VrouterRedundantTiersPlacement.valueIn(network.getAccountId());
IpPlacement ipPlacement = IpPlacement.fromString(placementConfig);
switch (ipPlacement) {
case Last:
return this.acquireLastGuestIpAddress(network);
case First:
return this.acquireFirstGuestIpAddress(network);
}
return this.acquireGuestIpAddress(network, null);
}
/**
* Get the list of public IPs that need to be applied for a static NAT enable/disable operation.
* Manipulating only these ips prevents concurrency issues when disabling static nat at the same time.
* @param staticNats
* @return The list of IPs that need to be applied for the static NAT to work.
*/
public List<IPAddressVO> getStaticNatSourceIps(List<? extends StaticNat> staticNats) {
List<IPAddressVO> userIps = new ArrayList<>();
for (StaticNat snat : staticNats) {
userIps.add(_ipAddressDao.findById(snat.getSourceIpAddressId()));
}
return userIps;
}
@Override
public boolean applyStaticNats(List<? extends StaticNat> staticNats, boolean continueOnError, boolean forRevoke) throws ResourceUnavailableException {
if (staticNats == null || staticNats.size() == 0) {
s_logger.debug("There are no static nat rules for the network elements");
return true;
}
Network network = _networksDao.findById(staticNats.get(0).getNetworkId());
boolean success = true;
// Check if the StaticNat service is supported
if (!_networkModel.areServicesSupportedInNetwork(network.getId(), Service.StaticNat)) {
s_logger.debug("StaticNat service is not supported in specified network id");
return true;
}
List<IPAddressVO> userIps = getStaticNatSourceIps(staticNats);
List<PublicIp> publicIps = new ArrayList<PublicIp>();
if (userIps != null && !userIps.isEmpty()) {
for (IPAddressVO userIp : userIps) {
PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
publicIps.add(publicIp);
}
}
// static NAT rules can not programmed unless IP is associated with source NAT service provider, so run IP
// association for the network so as to ensure IP is associated before applying rules
if (checkStaticNatIPAssocRequired(network, false, forRevoke, publicIps)) {
applyIpAssociations(network, false, continueOnError, publicIps);
}
// get provider
StaticNatServiceProvider element = _networkMgr.getStaticNatProviderForNetwork(network);
try {
success = element.applyStaticNats(network, staticNats);
} catch (ResourceUnavailableException e) {
if (!continueOnError) {
throw e;
}
s_logger.warn("Problems with " + element.getName() + " but pushing on", e);
success = false;
}
// For revoked static nat IP, set the vm_id to null, indicate it should be revoked
for (StaticNat staticNat : staticNats) {
if (staticNat.isForRevoke()) {
for (PublicIp publicIp : publicIps) {
if (publicIp.getId() == staticNat.getSourceIpAddressId()) {
publicIps.remove(publicIp);
IPAddressVO ip = _ipAddressDao.findByIdIncludingRemoved(staticNat.getSourceIpAddressId());
// ip can't be null, otherwise something wrong happened
ip.setAssociatedWithVmId(null);
publicIp = PublicIp.createFromAddrAndVlan(ip, _vlanDao.findById(ip.getVlanId()));
publicIps.add(publicIp);
break;
}
}
}
}
// if the static NAT rules configured on public IP is revoked then, dis-associate IP with static NAT service provider
if (checkStaticNatIPAssocRequired(network, true, forRevoke, publicIps)) {
applyIpAssociations(network, true, continueOnError, publicIps);
}
return success;
}
// checks if there are any public IP assigned to network, that are marked for one-to-one NAT that
// needs to be associated/dis-associated with static-nat provider
boolean checkStaticNatIPAssocRequired(Network network, boolean postApplyRules, boolean forRevoke, List<PublicIp> publicIps) {
for (PublicIp ip : publicIps) {
if (ip.isOneToOneNat()) {
Long activeFwCount = null;
activeFwCount = _firewallDao.countRulesByIpIdAndState(ip.getId(), FirewallRule.State.Active);
if (!postApplyRules && !forRevoke) {
if (activeFwCount > 0) {
continue;
} else {
return true;
}
} else if (postApplyRules && forRevoke) {
return true;
}
} else {
continue;
}
}
return false;
}
@Override
public IpAddress assignSystemIp(long networkId, Account owner, boolean forElasticLb, boolean forElasticIp) throws InsufficientAddressCapacityException {
Network guestNetwork = _networksDao.findById(networkId);
NetworkOffering off = _entityMgr.findById(NetworkOffering.class, guestNetwork.getNetworkOfferingId());
IpAddress ip = null;
if ((off.isElasticLb() && forElasticLb) || (off.isElasticIp() && forElasticIp)) {
try {
s_logger.debug("Allocating system IP address for load balancer rule...");
// allocate ip
ip = allocateIP(owner, true, guestNetwork.getDataCenterId());
// apply ip associations
ip = associateIPToGuestNetwork(ip.getId(), networkId, true);
;
} catch (ResourceAllocationException ex) {
throw new CloudRuntimeException("Failed to allocate system ip due to ", ex);
} catch (ConcurrentOperationException ex) {
throw new CloudRuntimeException("Failed to allocate system lb ip due to ", ex);
} catch (ResourceUnavailableException ex) {
throw new CloudRuntimeException("Failed to allocate system lb ip due to ", ex);
}
if (ip == null) {
throw new CloudRuntimeException("Failed to allocate system ip");
}
}
return ip;
}
@Override
public boolean handleSystemIpRelease(IpAddress ip) {
boolean success = true;
Long networkId = ip.getAssociatedWithNetworkId();
if (networkId != null) {
if (ip.getSystem()) {
CallContext ctx = CallContext.current();
if (!disassociatePublicIpAddress(ip.getId(), ctx.getCallingUserId(), ctx.getCallingAccount())) {
s_logger.warn("Unable to release system ip address id=" + ip.getId());
success = false;
} else {
s_logger.warn("Successfully released system ip address id=" + ip.getId());
}
}
}
return success;
}
@Override
@DB
public void allocateDirectIp(final NicProfile nic, final DataCenter dc, final VirtualMachineProfile vm, final Network network, final String requestedIpv4,
final String requestedIpv6) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException {
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientAddressCapacityException>() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) throws InsufficientAddressCapacityException {
//This method allocates direct ip for the Shared network in Advance zones
boolean ipv4 = false;
if (network.getGateway() != null) {
if (nic.getIPv4Address() == null) {
PublicIp ip = null;
//Get ip address from the placeholder and don't allocate a new one
if (requestedIpv4 != null && vm.getType() == VirtualMachine.Type.DomainRouter) {
Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(network, null);
if (placeholderNic != null) {
IPAddressVO userIp = _ipAddressDao.findByIpAndSourceNetworkId(network.getId(), placeholderNic.getIPv4Address());
ip = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId()));
s_logger.debug("Nic got an ip address " + placeholderNic.getIPv4Address() + " stored in placeholder nic for the network " + network);
}
}
if (ip == null) {
ip = assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv4, false, false);
}
nic.setIPv4Address(ip.getAddress().toString());
nic.setIPv4Gateway(ip.getGateway());
nic.setIPv4Netmask(ip.getNetmask());
nic.setIsolationUri(IsolationType.Vlan.toUri(ip.getVlanTag()));
nic.setBroadcastType(network.getBroadcastDomainType());
if (network.getBroadcastUri() != null)
nic.setBroadcastUri(network.getBroadcastUri());
else
nic.setBroadcastUri(BroadcastDomainType.Vlan.toUri(ip.getVlanTag()));
nic.setFormat(AddressFormat.Ip4);
nic.setReservationId(String.valueOf(ip.getVlanTag()));
if(nic.getMacAddress() == null) {
nic.setMacAddress(ip.getMacAddress());
}
}
Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
nic.setIPv4Dns1(dns.first());
nic.setIPv4Dns2(dns.second());
}
_ipv6Mgr.setNicIp6Address(nic, dc, network);
}
});
}
@Override
@DB
public void allocateNicValues(final NicProfile nic, final DataCenter dc, final VirtualMachineProfile vm, final Network network, final String requestedIpv4,
final String requestedIpv6) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException {
Transaction.execute(new TransactionCallbackWithExceptionNoReturn<InsufficientAddressCapacityException>() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) throws InsufficientAddressCapacityException {
//This method allocates direct ip for the Shared network in Advance zones
boolean ipv4 = false;
if (network.getGateway() != null) {
if (nic.getIPv4Address() == null) {
ipv4 = true;
// PublicIp ip = null;
//Get ip address from the placeholder and don't allocate a new one
if (requestedIpv4 != null && vm.getType() == VirtualMachine.Type.DomainRouter) {
s_logger.debug("There won't be nic assignment for VR id " + vm.getId() + " in this network " + network);
}
// nic ip address is not set here. Because the DHCP is external to cloudstack
nic.setIPv4Gateway(network.getGateway());
nic.setIPv4Netmask(NetUtils.getCidrNetmask(network.getCidr()));
List<VlanVO> vlan = _vlanDao.listVlansByNetworkId(network.getId());
//TODO: get vlan tag for the ntwork
if (vlan != null && !vlan.isEmpty()) {
nic.setIsolationUri(IsolationType.Vlan.toUri(vlan.get(0).getVlanTag()));
}
nic.setBroadcastType(BroadcastDomainType.Vlan);
nic.setBroadcastType(network.getBroadcastDomainType());
nic.setBroadcastUri(network.getBroadcastUri());
nic.setFormat(AddressFormat.Ip4);
if(nic.getMacAddress() == null) {
nic.setMacAddress(_networkModel.getNextAvailableMacAddressInNetwork(network.getId()));
}
}
Pair<String, String> dns = _networkModel.getNetworkIp4Dns(network, dc);
nic.setIPv4Dns1(dns.first());
nic.setIPv4Dns2(dns.second());
}
_ipv6Mgr.setNicIp6Address(nic, dc, network);
}
});
}
@Override
public int getRuleCountForIp(Long addressId, FirewallRule.Purpose purpose, FirewallRule.State state) {
List<FirewallRuleVO> rules = _firewallDao.listByIpAndPurposeWithState(addressId, purpose, state);
if (rules == null) {
return 0;
}
return rules.size();
}
@Override
public String allocatePublicIpForGuestNic(Network network, Long podId, Account owner, String requestedIp) throws InsufficientAddressCapacityException {
PublicIp ip = assignPublicIpAddress(network.getDataCenterId(), podId, owner, VlanType.DirectAttached, network.getId(), requestedIp, false, false);
if (ip == null) {
s_logger.debug("There is no free public ip address");
return null;
}
Ip ipAddr = ip.getAddress();
return ipAddr.addr();
}
@Override
public String allocateGuestIP(Network network, String requestedIp) throws InsufficientAddressCapacityException {
return acquireGuestIpAddress(network, requestedIp);
}
@Override
public String getConfigComponentName() {
return IpAddressManager.class.getSimpleName();
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {UseSystemPublicIps, RulesContinueOnError, SystemVmPublicIpReservationModeStrictness, VrouterRedundantTiersPlacement, AllowUserListAvailableIpsOnSharedNetwork};
}
/**
* Returns true if the given IP address is equals the gateway or there is no network offerrings for the given network
*/
@Override
public boolean isIpEqualsGatewayOrNetworkOfferingsEmpty(Network network, String requestedIp) {
if (requestedIp.equals(network.getGateway()) || requestedIp.equals(network.getIp6Gateway())) {
return true;
}
if (_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty() && network.getCidr() == null) {
return true;
}
return false;
}
@Override
public boolean isUsageHidden(IPAddressVO ip) {
Long networkId = ip.getAssociatedWithNetworkId();
if (networkId == null) {
networkId = ip.getSourceNetworkId();
}
if (networkId == null) {
throw new CloudRuntimeException("No network for IP " + ip.getId());
}
NetworkDetailVO networkDetail = _networkDetailsDao.findDetail(networkId, Network.hideIpAddressUsage);
return networkDetail != null && "true".equals(networkDetail.getValue());
}
public static ConfigKey<Boolean> getSystemvmpublicipreservationmodestrictness() {
return SystemVmPublicIpReservationModeStrictness;
}
}