bug CS-14862: EIP/ELB - SSVM and CPVM should be given an ip address from the public ip address range.

With this fix  both SSVM and CPVM will get public IP's in case of basic zone with EIP service.
A static NAT rule is implicitly configured on the EIP service provider to map public IP to a
guest IP address associated with SSVM/CPVM
This commit is contained in:
Murali reddy 2012-05-21 20:08:46 +05:30
parent ed0b98ee75
commit a4b0759c52
10 changed files with 119 additions and 36 deletions

View File

@ -168,7 +168,7 @@ public class AssociateIPAddrCmd extends BaseAsyncCreateCmd {
@Override @Override
public void create() throws ResourceAllocationException{ public void create() throws ResourceAllocationException{
try { try {
IpAddress ip = _networkService.allocateIP(getNetworkId(), _accountService.getAccount(getEntityOwnerId()), false); IpAddress ip = _networkService.allocateIP(getNetworkId(), _accountService.getAccount(getEntityOwnerId()));
if (ip != null) { if (ip != null) {
this.setEntityId(ip.getId()); this.setEntityId(ip.getId());
} else { } else {

View File

@ -78,7 +78,7 @@ public class EnableStaticNatCmd extends BaseCmd{
@Override @Override
public void execute() throws ResourceUnavailableException{ public void execute() throws ResourceUnavailableException{
try { try {
boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId); boolean result = _rulesService.enableStaticNat(ipAddressId, virtualMachineId, false);
if (result) { if (result) {
SuccessResponse response = new SuccessResponse(getCommandName()); SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response); this.setResponseObject(response);

View File

@ -37,7 +37,7 @@ public interface NetworkService {
List<? extends Network> getIsolatedNetworksOwnedByAccountInZone(long zoneId, Account owner); List<? extends Network> getIsolatedNetworksOwnedByAccountInZone(long zoneId, Account owner);
IpAddress allocateIP(long networkId, Account ipOwner, boolean isSystem) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException; IpAddress allocateIP(long networkId, Account ipOwner) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException;
/** /**
* Associates a public IP address for a router. * Associates a public IP address for a router.

View File

@ -60,7 +60,7 @@ public interface RulesService {
boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException; boolean applyPortForwardingRules(long ipAdddressId, Account caller) throws ResourceUnavailableException;
boolean enableStaticNat(long ipAddressId, long vmId) throws NetworkRuleConflictException, ResourceUnavailableException; boolean enableStaticNat(long ipAddressId, long vmId, boolean isSystemVm) throws NetworkRuleConflictException, ResourceUnavailableException;
PortForwardingRule getPortForwardigRule(long ruleId); PortForwardingRule getPortForwardigRule(long ruleId);

View File

@ -81,10 +81,13 @@ import com.cloud.info.RunningHostInfoAgregator.ZoneHostInfo;
import com.cloud.keystore.KeystoreDao; import com.cloud.keystore.KeystoreDao;
import com.cloud.keystore.KeystoreManager; import com.cloud.keystore.KeystoreManager;
import com.cloud.keystore.KeystoreVO; import com.cloud.keystore.KeystoreVO;
import com.cloud.network.IPAddressVO;
import com.cloud.network.NetworkManager; import com.cloud.network.NetworkManager;
import com.cloud.network.NetworkVO; import com.cloud.network.NetworkVO;
import com.cloud.network.Networks.TrafficType; import com.cloud.network.Networks.TrafficType;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkDao;
import com.cloud.network.rules.RulesManager;
import com.cloud.offering.ServiceOffering; import com.cloud.offering.ServiceOffering;
import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.NetworkOfferingVO;
import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingDao;
@ -108,6 +111,7 @@ import com.cloud.storage.dao.VMTemplateHostDao;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountManager; import com.cloud.user.AccountManager;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.user.UserContext;
import com.cloud.utils.DateUtil; import com.cloud.utils.DateUtil;
import com.cloud.utils.NumbersUtil; import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
@ -129,6 +133,7 @@ import com.cloud.uuididentity.dao.IdentityDao;
import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.ConsoleProxyVO;
import com.cloud.vm.NicProfile; import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContext;
import com.cloud.vm.SecondaryStorageVmVO;
import com.cloud.vm.SystemVmLoadScanHandler; import com.cloud.vm.SystemVmLoadScanHandler;
import com.cloud.vm.SystemVmLoadScanner; import com.cloud.vm.SystemVmLoadScanner;
import com.cloud.vm.SystemVmLoadScanner.AfterScanAction; import com.cloud.vm.SystemVmLoadScanner.AfterScanAction;
@ -214,7 +219,11 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
IdentityDao _identityDao; IdentityDao _identityDao;
@Inject @Inject
NetworkDao _networkDao; NetworkDao _networkDao;
@Inject
RulesManager _rulesMgr;
@Inject
IPAddressDao _ipAddressDao;
private ConsoleProxyListener _listener; private ConsoleProxyListener _listener;
private ServiceOfferingVO _serviceOffering; private ServiceOfferingVO _serviceOffering;
@ -1677,6 +1686,21 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
return false; return false;
} }
try {
//get system ip and create static nat rule for the vm in case of basic networking with EIP/ELB
_rulesMgr.getSystemIpAndEnableStaticNatForVm(profile.getVirtualMachine(), false);
IPAddressVO ipaddr = _ipAddressDao.findByAssociatedVmId(profile.getVirtualMachine().getId());
if (ipaddr != null && ipaddr.getSystem()) {
ConsoleProxyVO consoleVm = profile.getVirtualMachine();
// override CPVM guest IP with EIP, so that console url's will be prepared with EIP
consoleVm.setPublicIpAddress(ipaddr.getAddress().addr());
_consoleProxyDao.update(consoleVm.getId(), consoleVm);
}
} catch (Exception ex) {
s_logger.warn("Failed to get system ip and enable static nat for the vm " + profile.getVirtualMachine() + " due to exception ", ex);
return false;
}
return true; return true;
} }
@ -1757,6 +1781,16 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx
@Override @Override
public void finalizeStop(VirtualMachineProfile<ConsoleProxyVO> profile, StopAnswer answer) { public void finalizeStop(VirtualMachineProfile<ConsoleProxyVO> profile, StopAnswer answer) {
//release elastic IP here if assigned
IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(profile.getId());
if (ip != null && ip.getSystem()) {
UserContext ctx = UserContext.current();
try {
_rulesMgr.disableStaticNat(ip.getId(), ctx.getCaller(), ctx.getCallerUserId(), true);
} catch (Exception ex) {
s_logger.warn("Failed to disable static nat and release system ip " + ip + " as a part of vm " + profile.getVirtualMachine() + " stop due to exception ", ex);
}
}
} }
@Override @Override

View File

@ -972,8 +972,12 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
} }
@Override @Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "allocating Ip", create = true) @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "allocating Ip", create = true)
public IpAddress allocateIP(long networkId, Account ipOwner) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException {
return allocateIP(networkId, ipOwner, false);
}
@DB
public IpAddress allocateIP(long networkId, Account ipOwner, boolean isSystem) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException { public IpAddress allocateIP(long networkId, Account ipOwner, boolean isSystem) throws ResourceAllocationException, InsufficientAddressCapacityException, ConcurrentOperationException {
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
long userId = UserContext.current().getCallerUserId(); long userId = UserContext.current().getCallerUserId();
@ -1080,9 +1084,13 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag
} }
@Override @Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "associating Ip", async = true) @ActionEvent(eventType = EventTypes.EVENT_NET_IP_ASSIGN, eventDescription = "associating Ip", async = true)
public IpAddress associateIP(long ipId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException { public IpAddress associateIP(long ipId) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException {
return associateIP(ipId, false);
}
@DB
private IpAddress associateIP(long ipId, boolean isSystem) throws ResourceAllocationException, ResourceUnavailableException, InsufficientAddressCapacityException, ConcurrentOperationException {
Account caller = UserContext.current().getCaller(); Account caller = UserContext.current().getCaller();
Account owner = null; Account owner = null;

View File

@ -20,6 +20,7 @@ import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.IpAddress; import com.cloud.network.IpAddress;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.uservm.UserVm; import com.cloud.uservm.UserVm;
import com.cloud.vm.VirtualMachine;
/** /**
* Rules Manager manages the network rules created for different networks. * Rules Manager manages the network rules created for different networks.
@ -69,7 +70,7 @@ public interface RulesManager extends RulesService {
boolean applyStaticNatsForNetwork(long networkId, boolean continueOnError, Account caller); boolean applyStaticNatsForNetwork(long networkId, boolean continueOnError, Account caller);
void getSystemIpAndEnableStaticNatForVm(UserVm vm, boolean getNewIp) throws InsufficientAddressCapacityException; void getSystemIpAndEnableStaticNatForVm(VirtualMachine vm, boolean getNewIp) throws InsufficientAddressCapacityException;
boolean disableStaticNat(long ipAddressId, Account caller, long callerUserId, boolean releaseIpIfElastic) throws ResourceUnavailableException; boolean disableStaticNat(long ipAddressId, Account caller, long callerUserId, boolean releaseIpIfElastic) throws ResourceUnavailableException;

View File

@ -69,6 +69,7 @@ import com.cloud.utils.AnnotationHelper;
import com.cloud.vm.Nic; import com.cloud.vm.Nic;
import com.cloud.vm.UserVmVO; import com.cloud.vm.UserVmVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.dao.NicDao; import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDao;
@ -322,23 +323,24 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
} }
@Override @Override
public boolean enableStaticNat(long ipId, long vmId) throws NetworkRuleConflictException, ResourceUnavailableException { public boolean enableStaticNat(long ipId, long vmId, boolean isSystemVm) throws NetworkRuleConflictException, ResourceUnavailableException {
UserContext ctx = UserContext.current(); UserContext ctx = UserContext.current();
Account caller = ctx.getCaller(); Account caller = ctx.getCaller();
// Verify input parameters
UserVmVO vm = _vmDao.findById(vmId);
if (vm == null) {
throw new InvalidParameterValueException("Can't enable static nat for the address id=" + ipId + ", invalid virtual machine id specified (" + vmId + ").");
}
IPAddressVO ipAddress = _ipAddressDao.findById(ipId); IPAddressVO ipAddress = _ipAddressDao.findById(ipId);
if (ipAddress == null) { if (ipAddress == null) {
throw new InvalidParameterValueException("Unable to find ip address by id " + ipId); throw new InvalidParameterValueException("Unable to find ip address by id " + ipId);
} }
// Check permissions // Verify input parameters
checkIpAndUserVm(ipAddress, vm, caller); if (!isSystemVm) {
UserVmVO vm = _vmDao.findById(vmId);
if (vm == null) {
throw new InvalidParameterValueException("Can't enable static nat for the address id=" + ipId + ", invalid virtual machine id specified (" + vmId + ").");
}
// Check permissions
checkIpAndUserVm(ipAddress, vm, caller);
}
// Verify that the ip is associated with the network and static nat service is supported for the network // Verify that the ip is associated with the network and static nat service is supported for the network
Long networkId = ipAddress.getAssociatedWithNetworkId(); Long networkId = ipAddress.getAssociatedWithNetworkId();
@ -1188,7 +1190,7 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
} }
@Override @Override
public void getSystemIpAndEnableStaticNatForVm(UserVm vm, boolean getNewIp) throws InsufficientAddressCapacityException { public void getSystemIpAndEnableStaticNatForVm(VirtualMachine vm, boolean getNewIp) throws InsufficientAddressCapacityException {
boolean success = true; boolean success = true;
// enable static nat if eIp capability is supported // enable static nat if eIp capability is supported
@ -1212,8 +1214,9 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager {
s_logger.debug("Allocated system ip " + ip + ", now enabling static nat on it for vm " + vm); s_logger.debug("Allocated system ip " + ip + ", now enabling static nat on it for vm " + vm);
boolean isSystemVM = (vm.getType() == Type.ConsoleProxy || vm.getType() == Type.SecondaryStorageVm);
try { try {
success = enableStaticNat(ip.getId(), vm.getId()); success = enableStaticNat(ip.getId(), vm.getId(), isSystemVM);
} catch (NetworkRuleConflictException ex) { } catch (NetworkRuleConflictException ex) {
s_logger.warn("Failed to enable static nat as a part of enabling elasticIp and staticNat for vm " + vm + " in guest network " + guestNetwork + " due to exception ", ex); s_logger.warn("Failed to enable static nat as a part of enabling elasticIp and staticNat for vm " + vm + " in guest network " + guestNetwork + " due to exception ", ex);
success = false; success = false;

View File

@ -68,10 +68,13 @@ import com.cloud.info.RunningHostCountInfo;
import com.cloud.info.RunningHostInfoAgregator; import com.cloud.info.RunningHostInfoAgregator;
import com.cloud.info.RunningHostInfoAgregator.ZoneHostInfo; import com.cloud.info.RunningHostInfoAgregator.ZoneHostInfo;
import com.cloud.keystore.KeystoreManager; import com.cloud.keystore.KeystoreManager;
import com.cloud.network.IPAddressVO;
import com.cloud.network.NetworkManager; import com.cloud.network.NetworkManager;
import com.cloud.network.NetworkVO; import com.cloud.network.NetworkVO;
import com.cloud.network.Networks.TrafficType; import com.cloud.network.Networks.TrafficType;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkDao;
import com.cloud.network.rules.RulesManager;
import com.cloud.offering.ServiceOffering; import com.cloud.offering.ServiceOffering;
import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.NetworkOfferingVO;
import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingDao;
@ -96,6 +99,7 @@ import com.cloud.storage.template.TemplateConstants;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.user.AccountService; import com.cloud.user.AccountService;
import com.cloud.user.User; import com.cloud.user.User;
import com.cloud.user.UserContext;
import com.cloud.utils.DateUtil; import com.cloud.utils.DateUtil;
import com.cloud.utils.NumbersUtil; import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
@ -215,8 +219,11 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V
NetworkDao _networkDao; NetworkDao _networkDao;
@Inject @Inject
NetworkOfferingDao _networkOfferingDao; NetworkOfferingDao _networkOfferingDao;
@Inject
protected IPAddressDao _ipAddressDao = null;
@Inject
protected RulesManager _rulesMgr;
@Inject @Inject
KeystoreManager _keystoreMgr; KeystoreManager _keystoreMgr;
private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL; private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL;
@ -1181,11 +1188,36 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V
return false; return false;
} }
try {
//get system ip and create static nat rule for the vm in case of basic networking with EIP/ELB
_rulesMgr.getSystemIpAndEnableStaticNatForVm(profile.getVirtualMachine(), false);
IPAddressVO ipaddr = _ipAddressDao.findByAssociatedVmId(profile.getVirtualMachine().getId());
if (ipaddr != null && ipaddr.getSystem()) {
SecondaryStorageVmVO secVm = profile.getVirtualMachine();
// override SSVM guest IP with EIP, so that download url's with be prepared with EIP
secVm.setPublicIpAddress(ipaddr.getAddress().addr());
_secStorageVmDao.update(secVm.getId(), secVm);
}
} catch (Exception ex) {
s_logger.warn("Failed to get system ip and enable static nat for the vm " + profile.getVirtualMachine() + " due to exception ", ex);
return false;
}
return true; return true;
} }
@Override @Override
public void finalizeStop(VirtualMachineProfile<SecondaryStorageVmVO> profile, StopAnswer answer) { public void finalizeStop(VirtualMachineProfile<SecondaryStorageVmVO> profile, StopAnswer answer) {
//release elastic IP here
IPAddressVO ip = _ipAddressDao.findByAssociatedVmId(profile.getId());
if (ip != null && ip.getSystem()) {
UserContext ctx = UserContext.current();
try {
_rulesMgr.disableStaticNat(ip.getId(), ctx.getCaller(), ctx.getCallerUserId(), true);
} catch (Exception ex) {
s_logger.warn("Failed to disable static nat and release system ip " + ip + " as a part of vm " + profile.getVirtualMachine() + " stop due to exception ", ex);
}
}
} }
@Override @Override

View File

@ -279,12 +279,7 @@ public class UploadMonitorImpl implements UploadMonitor {
uploadJob.setUploadState(Status.DOWNLOAD_URL_NOT_CREATED); uploadJob.setUploadState(Status.DOWNLOAD_URL_NOT_CREATED);
uploadJob.setLastUpdated(new Date()); uploadJob.setLastUpdated(new Date());
_uploadDao.update(uploadJob.getId(), uploadJob); _uploadDao.update(uploadJob.getId(), uploadJob);
List<SecondaryStorageVmVO> ssVms = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, dataCenterId, State.Running);
if (ssVms.size() == 0){
errorString = "Couldnt find a running SSVM in the zone" + dataCenterId+ ". Couldnt create the extraction URL.";
throw new CloudRuntimeException(errorString);
}
// Create Symlink at ssvm // Create Symlink at ssvm
String uuid = UUID.randomUUID().toString() + path.substring(path.length() - 4) ; // last 4 characters of the path specify the format like .vhd String uuid = UUID.randomUUID().toString() + path.substring(path.length() - 4) ; // last 4 characters of the path specify the format like .vhd
HostVO secStorage = ApiDBUtils.findHostById(ApiDBUtils.findUploadById(uploadId).getHostId()); HostVO secStorage = ApiDBUtils.findHostById(ApiDBUtils.findUploadById(uploadId).getHostId());
@ -303,16 +298,26 @@ public class UploadMonitorImpl implements UploadMonitor {
throw new CloudRuntimeException(errorString); throw new CloudRuntimeException(errorString);
} }
//Construct actual URL locally now that the symlink exists at SSVM List<SecondaryStorageVmVO> ssVms = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, dataCenterId, State.Running);
String extractURL = generateCopyUrl(ssvm.getPublicIpAddress(), uuid); if (ssVms.size() > 0) {
UploadVO vo = _uploadDao.createForUpdate(); SecondaryStorageVmVO ssVm = ssVms.get(0);
vo.setLastUpdated(new Date()); if (ssVm.getPublicIpAddress() == null) {
vo.setUploadUrl(extractURL); errorString = "A running secondary storage vm has a null public ip?";
vo.setUploadState(Status.DOWNLOAD_URL_CREATED); s_logger.error(errorString);
_uploadDao.update(uploadId, vo); throw new CloudRuntimeException(errorString);
success = true; }
return; //Construct actual URL locally now that the symlink exists at SSVM
String extractURL = generateCopyUrl(ssVm.getPublicIpAddress(), uuid);
UploadVO vo = _uploadDao.createForUpdate();
vo.setLastUpdated(new Date());
vo.setUploadUrl(extractURL);
vo.setUploadState(Status.DOWNLOAD_URL_CREATED);
_uploadDao.update(uploadId, vo);
success = true;
return;
}
errorString = "Couldnt find a running SSVM in the zone" + dataCenterId+ ". Couldnt create the extraction URL.";
throw new CloudRuntimeException(errorString);
}finally{ }finally{
if(!success){ if(!success){
UploadVO uploadJob = _uploadDao.createForUpdate(uploadId); UploadVO uploadJob = _uploadDao.createForUpdate(uploadId);