CLOUDSTACK-10109: Enable dedication of public IPs to SSVM and CPVM (#2295)

This feature allow admins to dedicate a range of public IP addresses to the SSVM and CPVM, such that they can be subject to specific external firewall rules. The option to dedicate a public IP range to the System VMs (SSVM & CPVM) is added to the createVlanIpRange API method and the UI.

Solution:
Global setting 'system.vm.public.ip.reservation.mode.strictness' is added to determine if the use of the system VM reservation is strict (when true) or preferred (false), false by default.
When a range has been dedicated to System VMs, CloudStack should apply IPs from that range to
the public interfaces of the CPVM and the SSVM depending on global setting's value:

If the global setting is set to false: then CloudStack will use any unused and unreserved public IP
addresses for system VMs only when the pool of reserved IPs has been exhausted
If the global setting is set to true: then CloudStack will fail to deploy the system VM when the pool
of reserved IPs has been exhausted, citing the lack of available IPs.
UI Changes
Under Infrastructure -> Zone -> Physical Network -> Public -> IP Ranges, button 'Account' label is refactored to 'Set reservation'.

When that button is clicked, dialog displayed is also refactored, including a new checkbox 'System VMs' which indicates if range should be dedicated for CPVM and SSVM, and a note indicating its usage.

When clicking on button for any created range, UI dialog displayed indicates whether IP range is dedicated for system vms or not.
This commit is contained in:
Nicolas Vazquez 2018-01-06 14:44:30 -03:00 committed by Rohit Yadav
parent 45df928e04
commit 90ef67bab9
38 changed files with 428 additions and 44 deletions

View File

@ -112,6 +112,9 @@ public class CreateVlanIpRangeCmd extends BaseCmd {
@Parameter(name = ApiConstants.IP6_CIDR, type = CommandType.STRING, description = "the CIDR of IPv6 network, must be at least /64") @Parameter(name = ApiConstants.IP6_CIDR, type = CommandType.STRING, description = "the CIDR of IPv6 network, must be at least /64")
private String ip6Cidr; private String ip6Cidr;
@Parameter(name = ApiConstants.FOR_SYSTEM_VMS, type = CommandType.BOOLEAN, description = "true if IP range is set to system vms, false if not")
private Boolean forSystemVms;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
/////////////////// Accessors /////////////////////// /////////////////// Accessors ///////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@ -136,6 +139,10 @@ public class CreateVlanIpRangeCmd extends BaseCmd {
return gateway; return gateway;
} }
public Boolean isForSystemVms() {
return forSystemVms == null ? Boolean.FALSE : forSystemVms;
}
public String getNetmask() { public String getNetmask() {
return netmask; return netmask;
} }

View File

@ -116,10 +116,22 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit
@Param(description = "the cidr of IPv6 network") @Param(description = "the cidr of IPv6 network")
private String ip6Cidr; private String ip6Cidr;
@SerializedName(ApiConstants.FOR_SYSTEM_VMS)
@Param(description = "indicates whether VLAN IP range is dedicated to system vms or not")
private Boolean forSystemVms;
public void setId(String id) { public void setId(String id) {
this.id = id; this.id = id;
} }
public Boolean getForSystemVms() {
return forSystemVms;
}
public void setForSystemVms(Boolean forSystemVms) {
this.forSystemVms = forSystemVms;
}
public void setForVirtualNetwork(Boolean forVirtualNetwork) { public void setForVirtualNetwork(Boolean forVirtualNetwork) {
this.forVirtualNetwork = forVirtualNetwork; this.forVirtualNetwork = forVirtualNetwork;
} }

View File

@ -213,7 +213,7 @@ public interface ConfigurationManager {
boolean conserveMode, Map<Service, Map<Capability, String>> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, boolean conserveMode, Map<Service, Map<Capability, String>> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent,
Map<NetworkOffering.Detail, String> details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc); Map<NetworkOffering.Detail, String> details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc);
Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP,
String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr)
throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException;

View File

@ -61,7 +61,7 @@ public interface IpAddressManager {
* @return * @return
* @throws InsufficientAddressCapacityException * @throws InsufficientAddressCapacityException
*/ */
PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem) PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem, boolean forSystemVms)
throws InsufficientAddressCapacityException; throws InsufficientAddressCapacityException;
/** /**

View File

@ -524,6 +524,10 @@ ADD COLUMN `forsystemvms` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'Indicates if
ALTER TABLE `cloud`.`op_dc_ip_address_alloc` ALTER TABLE `cloud`.`op_dc_ip_address_alloc`
ADD COLUMN `vlan` INT(10) UNSIGNED NULL COMMENT 'Vlan the management network range is on'; ADD COLUMN `vlan` INT(10) UNSIGNED NULL COMMENT 'Vlan the management network range is on';
-- CLOUDSTACK-10109: Enable dedication of public IPs to SSVM and CPVM
ALTER TABLE `cloud`.`user_ip_address`
ADD COLUMN `forsystemvms` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'true if IP is set to system vms, false if not';
-- ldap binding on domain level -- ldap binding on domain level
CREATE TABLE IF NOT EXISTS `cloud`.`domain_details` ( CREATE TABLE IF NOT EXISTS `cloud`.`domain_details` (
`id` bigint unsigned NOT NULL auto_increment, `id` bigint unsigned NOT NULL auto_increment,
@ -539,4 +543,3 @@ ALTER TABLE cloud.ldap_trust_map ADD COLUMN account_id BIGINT(20) DEFAULT 0;
ALTER TABLE cloud.ldap_trust_map DROP FOREIGN KEY fk_ldap_trust_map__domain_id; ALTER TABLE cloud.ldap_trust_map DROP FOREIGN KEY fk_ldap_trust_map__domain_id;
DROP INDEX uk_ldap_trust_map__domain_id ON cloud.ldap_trust_map; DROP INDEX uk_ldap_trust_map__domain_id ON cloud.ldap_trust_map;
CREATE UNIQUE INDEX uk_ldap_trust_map__bind_location ON ldap_trust_map (domain_id, account_id); CREATE UNIQUE INDEX uk_ldap_trust_map__bind_location ON ldap_trust_map (domain_id, account_id);

View File

@ -122,6 +122,9 @@ public class IPAddressVO implements IpAddress {
@Column(name = "rule_state") @Column(name = "rule_state")
State ruleState; State ruleState;
@Column(name = "forsystemvms")
private boolean forSystemVms = false;
@Column(name= GenericDao.REMOVED_COLUMN) @Column(name= GenericDao.REMOVED_COLUMN)
private Date removed; private Date removed;
@ -382,4 +385,8 @@ public class IPAddressVO implements IpAddress {
public void setRuleState(State ruleState) { public void setRuleState(State ruleState) {
this.ruleState = ruleState; this.ruleState = ruleState;
} }
public boolean isForSystemVms() {
return forSystemVms;
}
} }

View File

@ -154,7 +154,7 @@ public class BaremetaNetworkGuru extends DirectPodBasedNetworkGuru {
DataCenter dc = _dcDao.findById(pod.getDataCenterId()); DataCenter dc = _dcDao.findById(pod.getDataCenterId());
if (nic.getIPv4Address() == null) { if (nic.getIPv4Address() == null) {
s_logger.debug(String.format("Requiring ip address: %s", nic.getIPv4Address())); s_logger.debug(String.format("Requiring ip address: %s", nic.getIPv4Address()));
PublicIp ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), requiredIp, false); PublicIp ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), requiredIp, false, false);
nic.setIPv4Address(ip.getAddress().toString()); nic.setIPv4Address(ip.getAddress().toString());
nic.setFormat(AddressFormat.Ip4); nic.setFormat(AddressFormat.Ip4);
nic.setIPv4Gateway(ip.getGateway()); nic.setIPv4Gateway(ip.getGateway());

View File

@ -446,7 +446,7 @@ public class LoadBalanceRuleHandler {
public PublicIp doInTransaction(final TransactionStatus status) throws InsufficientAddressCapacityException { public PublicIp doInTransaction(final TransactionStatus status) throws InsufficientAddressCapacityException {
final Network frontEndNetwork = _networkModel.getNetwork(guestNetworkId); final Network frontEndNetwork = _networkModel.getNetwork(guestNetworkId);
final PublicIp ip = _ipAddrMgr.assignPublicIpAddress(frontEndNetwork.getDataCenterId(), null, account, VlanType.DirectAttached, frontEndNetwork.getId(), null, true); final PublicIp ip = _ipAddrMgr.assignPublicIpAddress(frontEndNetwork.getDataCenterId(), null, account, VlanType.DirectAttached, frontEndNetwork.getId(), null, true, false);
final IPAddressVO ipvo = _ipAddressDao.findById(ip.getId()); final IPAddressVO ipvo = _ipAddressDao.findById(ip.getId());
ipvo.setAssociatedWithNetworkId(frontEndNetwork.getId()); ipvo.setAssociatedWithNetworkId(frontEndNetwork.getId());
_ipAddressDao.update(ipvo.getId(), ipvo); _ipAddressDao.update(ipvo.getId(), ipvo);

View File

@ -98,6 +98,7 @@ import com.cloud.network.as.AutoScaleVmProfileVO;
import com.cloud.network.as.Condition; import com.cloud.network.as.Condition;
import com.cloud.network.as.ConditionVO; import com.cloud.network.as.ConditionVO;
import com.cloud.network.as.Counter; import com.cloud.network.as.Counter;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.IPAddressVO;
import com.cloud.network.dao.LoadBalancerVO; import com.cloud.network.dao.LoadBalancerVO;
import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.NetworkVO;
@ -163,6 +164,8 @@ import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils; import com.cloud.utils.StringUtils;
import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.EntityManager;
import com.cloud.utils.net.Dhcp; import com.cloud.utils.net.Dhcp;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.Ip; import com.cloud.utils.net.Ip;
import com.cloud.utils.net.NetUtils; import com.cloud.utils.net.NetUtils;
@ -356,6 +359,8 @@ public class ApiResponseHelper implements ResponseGenerator {
private ResourceTagDao _resourceTagDao; private ResourceTagDao _resourceTagDao;
@Inject @Inject
private NicExtraDhcpOptionDao _nicExtraDhcpOptionDao; private NicExtraDhcpOptionDao _nicExtraDhcpOptionDao;
@Inject
private IPAddressDao userIpAddressDao;
@Override @Override
public UserResponse createUserResponse(User user) { public UserResponse createUserResponse(User user) {
@ -745,6 +750,7 @@ public class ApiResponseHelper implements ResponseGenerator {
vlanResponse.setPhysicalNetworkId(pnw.getUuid()); vlanResponse.setPhysicalNetworkId(pnw.getUuid());
} }
} }
vlanResponse.setForSystemVms(isForSystemVms(vlan.getId()));
vlanResponse.setObjectName("vlan"); vlanResponse.setObjectName("vlan");
return vlanResponse; return vlanResponse;
} catch (InstantiationException | IllegalAccessException e) { } catch (InstantiationException | IllegalAccessException e) {
@ -752,6 +758,20 @@ public class ApiResponseHelper implements ResponseGenerator {
} }
} }
/**
* Return true if vlan IP range is dedicated for system vms (SSVM and CPVM), false if not
* @param vlanId vlan id
* @return true if VLAN IP range is dedicated to system vms
*/
private boolean isForSystemVms(long vlanId){
SearchBuilder<IPAddressVO> sb = userIpAddressDao.createSearchBuilder();
sb.and("vlanId", sb.entity().getVlanId(), SearchCriteria.Op.EQ);
SearchCriteria<IPAddressVO> sc = sb.create();
sc.setParameters("vlanId", vlanId);
IPAddressVO userIpAddresVO = userIpAddressDao.findOneBy(sc);
return userIpAddresVO.isForSystemVms();
}
@Override @Override
public IPAddressResponse createIPAddressResponse(ResponseView view, IpAddress ipAddr) { public IPAddressResponse createIPAddressResponse(ResponseView view, IpAddress ipAddr) {
VlanVO vlan = ApiDBUtils.findVlanById(ipAddr.getVlanId()); VlanVO vlan = ApiDBUtils.findVlanById(ipAddr.getVlanId());

View File

@ -2908,9 +2908,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
String endIPv6 = cmd.getEndIpv6(); String endIPv6 = cmd.getEndIpv6();
final String ip6Gateway = cmd.getIp6Gateway(); final String ip6Gateway = cmd.getIp6Gateway();
final String ip6Cidr = cmd.getIp6Cidr(); final String ip6Cidr = cmd.getIp6Cidr();
final Boolean forSystemVms = cmd.isForSystemVms();
Account vlanOwner = null; Account vlanOwner = null;
if (forSystemVms && accountName != null) {
throw new InvalidParameterValueException("Account name should not be provided when ForSystemVMs is enabled");
}
final boolean ipv4 = startIP != null; final boolean ipv4 = startIP != null;
final boolean ipv6 = startIPv6 != null; final boolean ipv6 = startIPv6 != null;
@ -3118,12 +3123,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
checkOverlapPrivateIpRange(zoneId, startIP, endIP); checkOverlapPrivateIpRange(zoneId, startIP, endIP);
} }
return commitVlan(zoneId, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, forVirtualNetwork, networkId, physicalNetworkId, startIPv6, endIPv6, ip6Gateway, return commitVlan(zoneId, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, forVirtualNetwork, forSystemVms, networkId, physicalNetworkId, startIPv6, endIPv6, ip6Gateway,
ip6Cidr, domain, vlanOwner, network, sameSubnet); ip6Cidr, domain, vlanOwner, network, sameSubnet);
} }
private Vlan commitVlan(final Long zoneId, final Long podId, final String startIP, final String endIP, final String newVlanGatewayFinal, final String newVlanNetmaskFinal, private Vlan commitVlan(final Long zoneId, final Long podId, final String startIP, final String endIP, final String newVlanGatewayFinal, final String newVlanNetmaskFinal,
final String vlanId, final Boolean forVirtualNetwork, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6, final String vlanId, final Boolean forVirtualNetwork, final Boolean forSystemVms, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6,
final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair<Boolean, Pair<String, String>> sameSubnet) { final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair<Boolean, Pair<String, String>> sameSubnet) {
final GlobalLock commitVlanLock = GlobalLock.getInternLock("CommitVlan"); final GlobalLock commitVlanLock = GlobalLock.getInternLock("CommitVlan");
commitVlanLock.lock(5); commitVlanLock.lock(5);
@ -3151,7 +3156,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
newVlanGateway = sameSubnet.second().first(); newVlanGateway = sameSubnet.second().first();
newVlanNetmask = sameSubnet.second().second(); newVlanNetmask = sameSubnet.second().second();
} }
final Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, final Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, forSystemVms, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId,
false, domain, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr); false, domain, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr);
// create an entry in the nic_secondary table. This will be the new // create an entry in the nic_secondary table. This will be the new
// gateway that will be configured on the corresponding routervm. // gateway that will be configured on the corresponding routervm.
@ -3271,7 +3276,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
@Override @Override
@DB @DB
public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final boolean forVirtualNetwork, final Long podId, final String startIP, final String endIP, public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final boolean forVirtualNetwork, final boolean forSystemVms, final Long podId, final String startIP, final String endIP,
final String vlanGateway, final String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, final Account vlanOwner, final String startIPv6, final String endIPv6, final String vlanIp6Gateway, final String vlanIp6Cidr) { final String vlanGateway, final String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, final Account vlanOwner, final String startIPv6, final String endIPv6, final String vlanIp6Gateway, final String vlanIp6Cidr) {
final Network network = _networkModel.getNetwork(networkId); final Network network = _networkModel.getNetwork(networkId);
@ -3521,14 +3526,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
// Everything was fine, so persist the VLAN // Everything was fine, so persist the VLAN
final VlanVO vlan = commitVlanAndIpRange(zoneId, networkId, physicalNetworkId, podId, startIP, endIP, vlanGateway, vlanNetmask, vlanId, domain, vlanOwner, vlanIp6Gateway, vlanIp6Cidr, final VlanVO vlan = commitVlanAndIpRange(zoneId, networkId, physicalNetworkId, podId, startIP, endIP, vlanGateway, vlanNetmask, vlanId, domain, vlanOwner, vlanIp6Gateway, vlanIp6Cidr,
ipv4, zone, vlanType, ipv6Range, ipRange); ipv4, zone, vlanType, ipv6Range, ipRange, forSystemVms);
return vlan; return vlan;
} }
private VlanVO commitVlanAndIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final Long podId, final String startIP, final String endIP, private VlanVO commitVlanAndIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final Long podId, final String startIP, final String endIP,
final String vlanGateway, final String vlanNetmask, final String vlanId, final Domain domain, final Account vlanOwner, final String vlanIp6Gateway, final String vlanIp6Cidr, final String vlanGateway, final String vlanNetmask, final String vlanId, final Domain domain, final Account vlanOwner, final String vlanIp6Gateway, final String vlanIp6Cidr,
final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange) { final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange, final boolean forSystemVms) {
return Transaction.execute(new TransactionCallback<VlanVO>() { return Transaction.execute(new TransactionCallback<VlanVO>() {
@Override @Override
public VlanVO doInTransaction(final TransactionStatus status) { public VlanVO doInTransaction(final TransactionStatus status) {
@ -3539,7 +3544,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
// IPv6 use a used ip map, is different from ipv4, no need to save // IPv6 use a used ip map, is different from ipv4, no need to save
// public ip range // public ip range
if (ipv4) { if (ipv4) {
if (!savePublicIPRange(startIP, endIP, zoneId, vlan.getId(), networkId, physicalNetworkId)) { if (!savePublicIPRange(startIP, endIP, zoneId, vlan.getId(), networkId, physicalNetworkId, forSystemVms)) {
throw new CloudRuntimeException("Failed to save IPv4 range. Please contact Cloud Support."); throw new CloudRuntimeException("Failed to save IPv4 range. Please contact Cloud Support.");
} }
} }
@ -3561,8 +3566,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
_resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, new Long(ips.size())); _resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, new Long(ips.size()));
} else if (domain != null) { } else if (domain != null) {
// This VLAN is domain-wide, so create a DomainVlanMapVO entry // This VLAN is domain-wide, so create a DomainVlanMapVO entry
final DomainVlanMapVO domainVlanMapVO = new DomainVlanMapVO(domain.getId(), vlan.getId()); //final DomainVlanMapVO domainVlanMapVO = new DomainVlanMapVO(domain.getId(), vlan.getId());
_domainVlanMapDao.persist(domainVlanMapVO); //_domainVlanMapDao.persist(domainVlanMapVO);
} else if (podId != null) { } else if (podId != null) {
// This VLAN is pod-wide, so create a PodVlanMapVO entry // This VLAN is pod-wide, so create a PodVlanMapVO entry
final PodVlanMapVO podVlanMapVO = new PodVlanMapVO(podId, vlan.getId()); final PodVlanMapVO podVlanMapVO = new PodVlanMapVO(podId, vlan.getId());
@ -3873,7 +3878,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
} }
@DB @DB
protected boolean savePublicIPRange(final String startIP, final String endIP, final long zoneId, final long vlanDbId, final long sourceNetworkid, final long physicalNetworkId) { protected boolean savePublicIPRange(final String startIP, final String endIP, final long zoneId, final long vlanDbId, final long sourceNetworkid, final long physicalNetworkId, final boolean forSystemVms) {
final long startIPLong = NetUtils.ip2Long(startIP); final long startIPLong = NetUtils.ip2Long(startIP);
final long endIPLong = NetUtils.ip2Long(endIP); final long endIPLong = NetUtils.ip2Long(endIP);
@ -3881,7 +3886,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
@Override @Override
public List<String> doInTransaction(final TransactionStatus status) { public List<String> doInTransaction(final TransactionStatus status) {
final IPRangeConfig config = new IPRangeConfig(); final IPRangeConfig config = new IPRangeConfig();
return config.savePublicIPRange(TransactionLegacy.currentTxn(), startIPLong, endIPLong, zoneId, vlanDbId, sourceNetworkid, physicalNetworkId); return config.savePublicIPRange(TransactionLegacy.currentTxn(), startIPLong, endIPLong, zoneId, vlanDbId, sourceNetworkid, physicalNetworkId, forSystemVms);
} }
}); });

View File

@ -538,7 +538,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase
// acquire a public IP to associate with lb appliance (used as subnet IP to make the appliance part of private network) // acquire a public IP to associate with lb appliance (used as subnet IP to make the appliance part of private network)
PublicIp publicIp = PublicIp publicIp =
_ipAddrMgr.assignPublicIpAddress(guestConfig.getDataCenterId(), null, _accountMgr.getSystemAccount(), VlanType.VirtualNetwork, null, _ipAddrMgr.assignPublicIpAddress(guestConfig.getDataCenterId(), null, _accountMgr.getSystemAccount(), VlanType.VirtualNetwork, null,
null, false); null, false, false);
String publicIPNetmask = publicIp.getVlanNetmask(); String publicIPNetmask = publicIp.getVlanNetmask();
String publicIPgateway = publicIp.getVlanGateway(); String publicIPgateway = publicIp.getVlanGateway();
String publicIP = publicIp.getAddress().toString(); String publicIP = publicIp.getAddress().toString();
@ -813,7 +813,7 @@ public abstract class ExternalLoadBalancerDeviceManagerImpl extends AdapterBase
try { try {
PublicIp directIp = PublicIp directIp =
_ipAddrMgr.assignPublicIpAddress(network.getDataCenterId(), null, _accountDao.findById(network.getAccountId()), VlanType.DirectAttached, _ipAddrMgr.assignPublicIpAddress(network.getDataCenterId(), null, _accountDao.findById(network.getAccountId()), VlanType.DirectAttached,
network.getId(), null, true); network.getId(), null, true, false);
loadBalancingIpAddress = directIp.getAddress().addr(); loadBalancingIpAddress = directIp.getAddress().addr();
} catch (InsufficientCapacityException capException) { } catch (InsufficientCapacityException capException) {
String msg = "Ran out of guest IP addresses from the shared network."; String msg = "Ran out of guest IP addresses from the shared network.";

View File

@ -295,6 +295,10 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
static Boolean rulesContinueOnErrFlag = true; 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.", false, ConfigKey.Scope.Global);
@Override @Override
public boolean configure(String name, Map<String, Object> params) { public boolean configure(String name, Map<String, Object> params) {
// populate providers // populate providers
@ -395,6 +399,9 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ); AssignIpAddressSearch.and("dc", AssignIpAddressSearch.entity().getDataCenterId(), Op.EQ);
AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL); AssignIpAddressSearch.and("allocated", AssignIpAddressSearch.entity().getAllocatedTime(), Op.NULL);
AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN); AssignIpAddressSearch.and("vlanId", AssignIpAddressSearch.entity().getVlanId(), Op.IN);
if (SystemVmPublicIpReservationModeStrictness.value()) {
AssignIpAddressSearch.and("forSystemVms", AssignIpAddressSearch.entity().isForSystemVms(), Op.EQ);
}
SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder(); SearchBuilder<VlanVO> vlanSearch = _vlanDao.createSearchBuilder();
vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ); vlanSearch.and("type", vlanSearch.entity().getVlanType(), Op.EQ);
vlanSearch.and("networkId", vlanSearch.entity().getNetworkId(), Op.EQ); vlanSearch.and("networkId", vlanSearch.entity().getNetworkId(), Op.EQ);
@ -675,20 +682,20 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
} }
@Override @Override
public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem) public PublicIp assignPublicIpAddress(long dcId, Long podId, Account owner, VlanType type, Long networkId, String requestedIp, boolean isSystem, boolean forSystemVms)
throws InsufficientAddressCapacityException { throws InsufficientAddressCapacityException {
return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, isSystem, null, null); return fetchNewPublicIp(dcId, podId, null, owner, type, networkId, false, true, requestedIp, isSystem, null, null, forSystemVms);
} }
@Override @Override
public PublicIp assignPublicIpAddressFromVlans(long dcId, Long podId, Account owner, VlanType type, List<Long> vlanDbIds, Long networkId, String requestedIp, boolean isSystem) public PublicIp assignPublicIpAddressFromVlans(long dcId, Long podId, Account owner, VlanType type, List<Long> vlanDbIds, Long networkId, String requestedIp, boolean isSystem)
throws InsufficientAddressCapacityException { throws InsufficientAddressCapacityException {
return fetchNewPublicIp(dcId, podId, vlanDbIds, owner, type, networkId, false, true, requestedIp, isSystem, null, null); return fetchNewPublicIp(dcId, podId, vlanDbIds, owner, type, networkId, false, true, requestedIp, isSystem, null, null, false);
} }
@DB @DB
public PublicIp fetchNewPublicIp(final long dcId, final Long podId, final List<Long> vlanDbIds, final Account owner, final VlanType vlanUse, final Long guestNetworkId, 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 String requestedIp, final boolean isSystem, final Long vpcId, final Boolean displayIp) final boolean sourceNat, final boolean assign, final String requestedIp, final boolean isSystem, final Long vpcId, final Boolean displayIp, final boolean forSystemVms)
throws InsufficientAddressCapacityException { throws InsufficientAddressCapacityException {
IPAddressVO addr = Transaction.execute(new TransactionCallbackWithException<IPAddressVO, InsufficientAddressCapacityException>() { IPAddressVO addr = Transaction.execute(new TransactionCallbackWithException<IPAddressVO, InsufficientAddressCapacityException>() {
@Override @Override
@ -758,7 +765,13 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
errorMessage.append(": requested ip " + requestedIp + " is not available"); errorMessage.append(": requested ip " + requestedIp + " is not available");
} }
Filter filter = new Filter(IPAddressVO.class, "vlanId", true, 0l, 1l); boolean ascOrder = ! forSystemVms;
Filter filter = new Filter(IPAddressVO.class, "forSystemVms", ascOrder, 0l, 1l);
if (SystemVmPublicIpReservationModeStrictness.value()) {
sc.setParameters("forSystemVms", forSystemVms);
}
filter.addOrderBy(IPAddressVO.class,"vlanId", true);
List<IPAddressVO> addrs = _ipAddressDao.search(sc, filter, false); List<IPAddressVO> addrs = _ipAddressDao.search(sc, filter, false);
@ -951,7 +964,13 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
VpcVO vpc = _vpcDao.findById(vpcId); VpcVO vpc = _vpcDao.findById(vpcId);
displayIp = vpc.isDisplay(); displayIp = vpc.isDisplay();
} }
return fetchNewPublicIp(dcId, null, null, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, true, null, false, vpcId, displayIp); PublicIp ip = fetchNewPublicIp(dcId, null, null, owner, VlanType.VirtualNetwork, guestNtwkId, isSourceNat, false, null, false, vpcId, displayIp, false);
IPAddressVO publicIp = ip.ip();
markPublicIpAsAllocated(publicIp);
_ipAddressDao.update(publicIp.getId(), publicIp);
return ip;
} }
}); });
if (ip.getState() != State.Allocated) { if (ip.getState() != State.Allocated) {
@ -1147,7 +1166,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
ip = Transaction.execute(new TransactionCallbackWithException<PublicIp, InsufficientAddressCapacityException>() { ip = Transaction.execute(new TransactionCallbackWithException<PublicIp, InsufficientAddressCapacityException>() {
@Override @Override
public PublicIp doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException { public PublicIp doInTransaction(TransactionStatus status) throws InsufficientAddressCapacityException {
PublicIp ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, null, isSystem, null, displayIp); PublicIp ip = fetchNewPublicIp(zone.getId(), null, null, ipOwner, vlanType, null, false, assign, null, isSystem, null, displayIp, false);
if (ip == null) { if (ip == null) {
InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zone InsufficientAddressCapacityException ex = new InsufficientAddressCapacityException("Unable to find available public IP addresses", DataCenter.class, zone
@ -2009,7 +2028,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
} }
if (ip == null) { if (ip == null) {
ip = assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv4, false); ip = assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.DirectAttached, network.getId(), requestedIpv4, false, false);
} }
nic.setIPv4Address(ip.getAddress().toString()); nic.setIPv4Address(ip.getAddress().toString());
@ -2142,7 +2161,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
@Override @Override
public String allocatePublicIpForGuestNic(Network network, Long podId, Account owner, String requestedIp) throws InsufficientAddressCapacityException { 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); PublicIp ip = assignPublicIpAddress(network.getDataCenterId(), podId, owner, VlanType.DirectAttached, network.getId(), requestedIp, false, false);
if (ip == null) { if (ip == null) {
s_logger.debug("There is no free public ip address"); s_logger.debug("There is no free public ip address");
return null; return null;
@ -2163,6 +2182,6 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
@Override @Override
public ConfigKey<?>[] getConfigKeys() { public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {UseSystemPublicIps, RulesContinueOnError}; return new ConfigKey<?>[] {UseSystemPublicIps, RulesContinueOnError, SystemVmPublicIpReservationModeStrictness};
} }
} }

View File

@ -1386,7 +1386,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService {
if (_accountMgr.isRootAdmin(caller.getId()) && createVlan && network != null) { if (_accountMgr.isRootAdmin(caller.getId()) && createVlan && network != null) {
// Create vlan ip range // Create vlan ip range
_configMgr.createVlanAndPublicIpRange(pNtwk.getDataCenterId(), network.getId(), physicalNetworkId, false, null, startIP, endIP, gateway, netmask, vlanId, _configMgr.createVlanAndPublicIpRange(pNtwk.getDataCenterId(), network.getId(), physicalNetworkId, false, false, null, startIP, endIP, gateway, netmask, vlanId,
bypassVlanOverlapCheck, null, null, startIPv6, endIPv6, ip6Gateway, ip6Cidr); bypassVlanOverlapCheck, null, null, startIPv6, endIPv6, ip6Gateway, ip6Cidr);
} }
return network; return network;

View File

@ -194,7 +194,7 @@ public class DirectPodBasedNetworkGuru extends DirectNetworkGuru {
} }
if (ip == null) { if (ip == null) {
ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), null, false); ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), null, false, false);
} }
nic.setIPv4Address(ip.getAddress().toString()); nic.setIPv4Address(ip.getAddress().toString());

View File

@ -115,7 +115,11 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru {
protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network) throws InsufficientVirtualNetworkCapacityException, protected void getIp(NicProfile nic, DataCenter dc, VirtualMachineProfile vm, Network network) throws InsufficientVirtualNetworkCapacityException,
InsufficientAddressCapacityException, ConcurrentOperationException { InsufficientAddressCapacityException, ConcurrentOperationException {
if (nic.getIPv4Address() == null) { if (nic.getIPv4Address() == null) {
PublicIp ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.VirtualNetwork, null, null, false); boolean forSystemVms = false;
if (vm.getType().equals(VirtualMachine.Type.ConsoleProxy) || vm.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) {
forSystemVms = true;
}
PublicIp ip = _ipAddrMgr.assignPublicIpAddress(dc.getId(), null, vm.getOwner(), VlanType.VirtualNetwork, null, null, false, forSystemVms);
nic.setIPv4Address(ip.getAddress().toString()); nic.setIPv4Address(ip.getAddress().toString());
nic.setIPv4Gateway(ip.getGateway()); nic.setIPv4Gateway(ip.getGateway());
nic.setIPv4Netmask(ip.getNetmask()); nic.setIPv4Netmask(ip.getNetmask());

View File

@ -290,7 +290,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
long startIPLong = NetUtils.ip2Long(startIp); long startIPLong = NetUtils.ip2Long(startIp);
long endIPLong = NetUtils.ip2Long(endIp); long endIPLong = NetUtils.ip2Long(endIp);
config.savePublicIPRange(TransactionLegacy.currentTxn(), startIPLong, endIPLong, vlan.getDataCenterId(), vlan.getId(), vlan.getNetworkId(), config.savePublicIPRange(TransactionLegacy.currentTxn(), startIPLong, endIPLong, vlan.getDataCenterId(), vlan.getId(), vlan.getNetworkId(),
vlan.getPhysicalNetworkId()); vlan.getPhysicalNetworkId(), false);
} }
}); });

View File

@ -431,7 +431,7 @@ public class IPRangeConfig {
List<String> problemIPs = null; List<String> problemIPs = null;
if (type.equals("public")) { if (type.equals("public")) {
problemIPs = savePublicIPRange(txn, startIPLong, endIPLong, zoneId, vlanDbId, sourceNetworkId, physicalNetworkId); problemIPs = savePublicIPRange(txn, startIPLong, endIPLong, zoneId, vlanDbId, sourceNetworkId, physicalNetworkId, false);
} else if (type.equals("private")) { } else if (type.equals("private")) {
problemIPs = savePrivateIPRange(txn, startIPLong, endIPLong, podId, zoneId); problemIPs = savePrivateIPRange(txn, startIPLong, endIPLong, podId, zoneId);
} }
@ -445,9 +445,9 @@ public class IPRangeConfig {
return problemIPs; return problemIPs;
} }
public Vector<String> savePublicIPRange(TransactionLegacy txn, long startIP, long endIP, long zoneId, long vlanDbId, Long sourceNetworkId, long physicalNetworkId) { public Vector<String> savePublicIPRange(TransactionLegacy txn, long startIP, long endIP, long zoneId, long vlanDbId, Long sourceNetworkId, long physicalNetworkId, boolean forSystemVms) {
String insertSql = String insertSql =
"INSERT INTO `cloud`.`user_ip_address` (public_ip_address, data_center_id, vlan_db_id, mac_address, source_network_id, physical_network_id, uuid) VALUES (?, ?, ?, (select mac_address from `cloud`.`data_center` where id=?), ?, ?, ?)"; "INSERT INTO `cloud`.`user_ip_address` (public_ip_address, data_center_id, vlan_db_id, mac_address, source_network_id, physical_network_id, uuid, forsystemvms) VALUES (?, ?, ?, (select mac_address from `cloud`.`data_center` where id=?), ?, ?, ?, ?)";
String updateSql = "UPDATE `cloud`.`data_center` set mac_address = mac_address+1 where id=?"; String updateSql = "UPDATE `cloud`.`data_center` set mac_address = mac_address+1 where id=?";
Vector<String> problemIPs = new Vector<String>(); Vector<String> problemIPs = new Vector<String>();
@ -468,6 +468,7 @@ public class IPRangeConfig {
insert_stmt.setLong(5, sourceNetworkId); insert_stmt.setLong(5, sourceNetworkId);
insert_stmt.setLong(6, physicalNetworkId); insert_stmt.setLong(6, physicalNetworkId);
insert_stmt.setString(7, UUID.randomUUID().toString()); insert_stmt.setString(7, UUID.randomUUID().toString());
insert_stmt.setBoolean(8, forSystemVms);
insert_stmt.executeUpdate(); insert_stmt.executeUpdate();
update_stmt.setLong(1, zoneId); update_stmt.setLong(1, zoneId);
update_stmt.executeUpdate(); update_stmt.executeUpdate();

View File

@ -459,7 +459,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
* @see com.cloud.configuration.ConfigurationManager#createVlanAndPublicIpRange(long, long, long, boolean, java.lang.Long, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.cloud.user.Account) * @see com.cloud.configuration.ConfigurationManager#createVlanAndPublicIpRange(long, long, long, boolean, java.lang.Long, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, com.cloud.user.Account)
*/ */
@Override @Override
public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, Long podId, String startIP, String endIP, public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP,
String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6)
throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException { throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException {
// TODO Auto-generated method stub // TODO Auto-generated method stub

View File

@ -25,6 +25,8 @@ from marvin.lib.utils import *
from marvin.lib.base import * from marvin.lib.base import *
from marvin.lib.common import * from marvin.lib.common import *
import datetime import datetime
from socket import inet_aton
from struct import unpack
class TestDedicatePublicIPRange(cloudstackTestCase): class TestDedicatePublicIPRange(cloudstackTestCase):
@ -147,3 +149,241 @@ class TestDedicatePublicIPRange(cloudstackTestCase):
return return
@attr(tags = ["advanced", "publiciprange", "dedicate", "release"], required_hardware="false")
def test_dedicate_public_ip_range_for_system_vms(self):
"""Test public IP range dedication for SSVM and CPVM
"""
# Validate the following:
# 1. Create a Public IP range for system vms
# 2. Created IP range should be present and marked as forsystemvms=true, verify with listVlanIpRanges
# 7. Delete the Public IP range
services = {
"gateway":"192.168.99.1",
"netmask":"255.255.255.0",
"startip":"192.168.99.2",
"endip":"192.168.99.200",
"forvirtualnetwork":self.services["forvirtualnetwork"],
"zoneid":self.services["zoneid"],
"vlan":self.services["vlan"]
}
public_ip_range = PublicIpRange.create(
self.apiclient,
services,
forsystemvms = True
)
created_ip_range_response = PublicIpRange.list(
self.apiclient,
id = public_ip_range.vlan.id
)
self.assertEqual(
len(created_ip_range_response),
1,
"Check listVlanIpRanges response"
)
self.assertTrue(
created_ip_range_response[0].forsystemvms,
"Check forsystemvms parameter in created vlan ip range"
)
# Delete range
public_ip_range.delete(self.apiclient)
def get_ip_as_number(self, ip_string):
""" Return numeric value for ip (passed as a string)
"""
packed_ip = inet_aton(ip_string)
return unpack(">L", packed_ip)[0]
def is_ip_in_range(self, start_ip, end_ip, ip_to_test):
""" Check whether ip_to_test belongs to IP range between start_ip and end_ip
"""
start = self.get_ip_as_number(start_ip)
end = self.get_ip_as_number(end_ip)
ip = self.get_ip_as_number(ip_to_test)
return start <= ip and ip <= end
def wait_for_system_vm_start(self, domain_id, srv_timeout, srv_sleep, systemvmtype):
""" Wait until system vm is Running
"""
timeout = srv_timeout
while True:
list_systemvm_response = list_ssvms(
self.apiclient,
systemvmtype=systemvmtype,
domainid=domain_id
)
if isinstance(list_systemvm_response, list):
if list_systemvm_response[0].state == 'Running':
return list_systemvm_response[0].id
if timeout == 0:
raise Exception("List System VM call failed!")
time.sleep(srv_sleep)
timeout = timeout - 1
return None
def base_system_vm(self, services, systemvmtype):
"""
Base for CPVM or SSVM depending on systemvmtype parameter
"""
# Create range for system vms
self.debug("Creating Public IP range for system vms")
public_ip_range = PublicIpRange.create(
self.apiclient,
services,
forsystemvms = True
)
# List Running System VM
list_systemvm_response = list_ssvms(
self.apiclient,
systemvmtype=systemvmtype,
state='Running',
domainid=public_ip_range.vlan.domainid
)
self.assertTrue(
isinstance(list_systemvm_response, list),
"Check list response returns a valid list"
)
self.assertEqual(
len(list_systemvm_response),
1,
"Check list response size"
)
# Delete System VM
systemvm = list_systemvm_response[0]
self.debug("Destroying System VM: %s" % systemvm.id)
cmd = destroySystemVm.destroySystemVmCmd()
cmd.id = systemvm.id
self.apiclient.destroySystemVm(cmd)
# Wait for CPVM to start
systemvm_id = self.wait_for_system_vm_start(
public_ip_range.vlan.domainid,
self.services["timeout"],
self.services["sleep"],
systemvmtype
)
self.assertNotEqual(
systemvm_id,
None,
"Check CPVM id is not none"
)
list_systemvm_response = list_ssvms(
self.apiclient,
id=systemvm_id
)
self.assertEqual(
isinstance(list_systemvm_response, list),
True,
"Check list response returns a valid list"
)
systemvm_response = list_systemvm_response[0]
self.debug("System VM state after debug: %s" % systemvm_response.state)
self.assertEqual(
systemvm_response.state,
'Running',
"Check whether System VM is running or not"
)
# Verify System VM got IP in the created range
startip = services["startip"]
endip = services["endip"]
cpvm_ip = systemvm_response.publicip
self.assertTrue(
self.is_ip_in_range(startip, endip, cpvm_ip),
"Check whether System VM Public IP is in range dedicated to system vms"
)
# Delete System VM and IP range, so System VM can get IP from original ranges
self.debug("Destroying System VM: %s" % systemvm_id)
cmd = destroySystemVm.destroySystemVmCmd()
cmd.id = systemvm_id
self.apiclient.destroySystemVm(cmd)
domain_id = public_ip_range.vlan.domainid
public_ip_range.delete(self.apiclient)
# Wait for System VM to start and check System VM public IP
systemvm_id = self.wait_for_system_vm_start(
domain_id,
self.services["timeout"],
self.services["sleep"],
systemvmtype
)
list_systemvm_response = list_ssvms(
self.apiclient,
id=systemvm_id
)
self.assertFalse(
self.is_ip_in_range(startip, endip, list_systemvm_response[0].publicip),
"Check System VM Public IP is not in range dedicated to system vms"
)
return True
def exists_public_ip_range_for_system_vms(self, zoneid):
"""
Return True if there exists a public IP range dedicated for system vms in zoneid
"""
existing_ip_ranges_response = PublicIpRange.list(
self.apiclient,
zoneid=zoneid
)
for r in existing_ip_ranges_response:
if r.forsystemvms:
return True
return False
@attr(tags = ["advanced", "publiciprange", "dedicate", "release"], required_hardware="false")
def test_dedicate_public_ip_range_for_system_vms_cpvm(self):
"""Test CPVM Public IP
"""
self.debug("Precondition: No public IP range dedicated for system vms in the environment")
if self.exists_public_ip_range_for_system_vms(self.services["zoneid"]):
self.skipTest("An existing IP range defined for system vms, aborting test")
services = {
"gateway":"192.168.100.1",
"netmask":"255.255.255.0",
"startip":"192.168.100.2",
"endip":"192.168.100.200",
"forvirtualnetwork":self.services["forvirtualnetwork"],
"zoneid":self.services["zoneid"],
"vlan":self.services["vlan"]
}
self.base_system_vm(
services,
'consoleproxy'
)
return
@attr(tags = ["advanced", "publiciprange", "dedicate", "release"], required_hardware="false")
def test_dedicate_public_ip_range_for_system_vms_ssvm(self):
"""Test SSVM Public IP
"""
self.debug("Precondition: No public IP range dedicated for system vms in the environment")
if self.exists_public_ip_range_for_system_vms(self.services["zoneid"]):
self.skipTest("An existing IP range defined for system vms, aborting test")
services = {
"gateway":"192.168.200.1",
"netmask":"255.255.255.0",
"startip":"192.168.200.2",
"endip":"192.168.200.200",
"forvirtualnetwork":self.services["forvirtualnetwork"],
"zoneid":self.services["zoneid"],
"vlan":self.services["vlan"]
}
self.base_system_vm(
services,
'secondarystoragevm'
)
return

View File

@ -3383,7 +3383,7 @@ class PublicIpRange:
self.__dict__.update(items) self.__dict__.update(items)
@classmethod @classmethod
def create(cls, apiclient, services, account=None, domainid=None): def create(cls, apiclient, services, account=None, domainid=None, forsystemvms=None):
"""Create VlanIpRange""" """Create VlanIpRange"""
cmd = createVlanIpRange.createVlanIpRangeCmd() cmd = createVlanIpRange.createVlanIpRangeCmd()
@ -3401,6 +3401,8 @@ class PublicIpRange:
cmd.account = account cmd.account = account
if domainid: if domainid:
cmd.domainid = domainid cmd.domainid = domainid
if forsystemvms:
cmd.forsystemvms = forsystemvms
return PublicIpRange(apiclient.createVlanIpRange(cmd).__dict__) return PublicIpRange(apiclient.createVlanIpRange(cmd).__dict__)

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Services", "label.services": "Services",
"label.session.expired": "Session Expired", "label.session.expired": "Session Expired",
"label.set.default.NIC": "Set default NIC", "label.set.default.NIC": "Set default NIC",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Set up zone type", "label.set.up.zone.type": "Set up zone type",
"label.settings": "Settings", "label.settings": "Settings",
"label.setup": "التثبيت", "label.setup": "التثبيت",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Services", "label.services": "Services",
"label.session.expired": "Session Expired", "label.session.expired": "Session Expired",
"label.set.default.NIC": "Set default NIC", "label.set.default.NIC": "Set default NIC",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Set up zone type", "label.set.up.zone.type": "Set up zone type",
"label.settings": "Settings", "label.settings": "Settings",
"label.setup": "Configuració", "label.setup": "Configuració",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Dienste", "label.services": "Dienste",
"label.session.expired": "Sitzung abgelaufen", "label.session.expired": "Sitzung abgelaufen",
"label.set.default.NIC": "Standard-NIC festlegen", "label.set.default.NIC": "Standard-NIC festlegen",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Zonentyp einrichten", "label.set.up.zone.type": "Zonentyp einrichten",
"label.settings": "Einstellungen", "label.settings": "Einstellungen",
"label.setup": "Konfiguration", "label.setup": "Konfiguration",

View File

@ -1528,6 +1528,8 @@ var dictionary = {"ICMP.code":"ICMP Code",
"label.services":"Services", "label.services":"Services",
"label.session.expired":"Session Expired", "label.session.expired":"Session Expired",
"label.set.default.NIC":"Set default NIC", "label.set.default.NIC":"Set default NIC",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type":"Set up zone type", "label.set.up.zone.type":"Set up zone type",
"label.settings":"Settings", "label.settings":"Settings",
"label.setup":"Setup", "label.setup":"Setup",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Servicios", "label.services": "Servicios",
"label.session.expired": "Session Caducada", "label.session.expired": "Session Caducada",
"label.set.default.NIC": "Definir NIC por defecto", "label.set.default.NIC": "Definir NIC por defecto",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Definir tipo de zona", "label.set.up.zone.type": "Definir tipo de zona",
"label.settings": "Configuración", "label.settings": "Configuración",
"label.setup": "Configuración", "label.setup": "Configuración",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Services", "label.services": "Services",
"label.session.expired": "Session expirée", "label.session.expired": "Session expirée",
"label.set.default.NIC": "Définir NIC par défaut", "label.set.default.NIC": "Définir NIC par défaut",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Configurer le type de zone", "label.set.up.zone.type": "Configurer le type de zone",
"label.settings": "Paramètres", "label.settings": "Paramètres",
"label.setup": "Configuration", "label.setup": "Configuration",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Szolgáltatások", "label.services": "Szolgáltatások",
"label.session.expired": "A munkamenet lejárt", "label.session.expired": "A munkamenet lejárt",
"label.set.default.NIC": "Alapértelmezett NIC beállítása", "label.set.default.NIC": "Alapértelmezett NIC beállítása",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Zóna-típus beállítása", "label.set.up.zone.type": "Zóna-típus beállítása",
"label.settings": "Beállítások", "label.settings": "Beállítások",
"label.setup": "Beállítások", "label.setup": "Beállítások",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Services", "label.services": "Services",
"label.session.expired": "Session Expired", "label.session.expired": "Session Expired",
"label.set.default.NIC": "Set default NIC", "label.set.default.NIC": "Set default NIC",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Configurazione del tipo di Zona", "label.set.up.zone.type": "Configurazione del tipo di Zona",
"label.settings": "Settings", "label.settings": "Settings",
"label.setup": "Installazione", "label.setup": "Installazione",

View File

@ -1489,6 +1489,8 @@ var dictionary = {
"label.services": "サービス", "label.services": "サービス",
"label.session.expired": "セッションの有効期限が切れました", "label.session.expired": "セッションの有効期限が切れました",
"label.set.default.NIC": "デフォルト NIC の設定", "label.set.default.NIC": "デフォルト NIC の設定",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "ゾーンの種類のセットアップ", "label.set.up.zone.type": "ゾーンの種類のセットアップ",
"label.settings": "設定", "label.settings": "設定",
"label.setup": "セットアップ", "label.setup": "セットアップ",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Services", "label.services": "Services",
"label.session.expired": "세션 유효기간이 끊어짐", "label.session.expired": "세션 유효기간이 끊어짐",
"label.set.default.NIC": "Set default NIC", "label.set.default.NIC": "Set default NIC",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Zone 종류 설정", "label.set.up.zone.type": "Zone 종류 설정",
"label.settings": "Settings", "label.settings": "Settings",
"label.setup": "설정", "label.setup": "설정",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Tjenester", "label.services": "Tjenester",
"label.session.expired": "Sesjon utløpt", "label.session.expired": "Sesjon utløpt",
"label.set.default.NIC": "Sett som standard NIC", "label.set.default.NIC": "Sett som standard NIC",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Oppsett av sonetype", "label.set.up.zone.type": "Oppsett av sonetype",
"label.settings": "Innstillinger", "label.settings": "Innstillinger",
"label.setup": "Oppsett", "label.setup": "Oppsett",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Diensten", "label.services": "Diensten",
"label.session.expired": "Sessie Verlopen", "label.session.expired": "Sessie Verlopen",
"label.set.default.NIC": "Stel standaard NIC in", "label.set.default.NIC": "Stel standaard NIC in",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Stel zone type in", "label.set.up.zone.type": "Stel zone type in",
"label.settings": "Instellingen", "label.settings": "Instellingen",
"label.setup": "Instellen", "label.setup": "Instellen",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Services", "label.services": "Services",
"label.session.expired": "Session Expired", "label.session.expired": "Session Expired",
"label.set.default.NIC": "Set default NIC", "label.set.default.NIC": "Set default NIC",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Set up zone type", "label.set.up.zone.type": "Set up zone type",
"label.settings": "Settings", "label.settings": "Settings",
"label.setup": "Konfiguracja", "label.setup": "Konfiguracja",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Serviços", "label.services": "Serviços",
"label.session.expired": "Sessão Expirada", "label.session.expired": "Sessão Expirada",
"label.set.default.NIC": "Configurar para NIC padrão", "label.set.default.NIC": "Configurar para NIC padrão",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Configurar tipo de zona", "label.set.up.zone.type": "Configurar tipo de zona",
"label.settings": "Ajustes", "label.settings": "Ajustes",
"label.setup": "Configuração", "label.setup": "Configuração",

View File

@ -1488,6 +1488,8 @@ var dictionary = {
"label.services": "Services", "label.services": "Services",
"label.session.expired": "Сеанс завершен", "label.session.expired": "Сеанс завершен",
"label.set.default.NIC": "Установить NIC по умолчанию", "label.set.default.NIC": "Установить NIC по умолчанию",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "Настроить тип зоны", "label.set.up.zone.type": "Настроить тип зоны",
"label.settings": "Настройки", "label.settings": "Настройки",
"label.setup": "Настройка", "label.setup": "Настройка",

View File

@ -1489,6 +1489,8 @@ var dictionary = {
"label.services": "服务", "label.services": "服务",
"label.session.expired": "会话已过期", "label.session.expired": "会话已过期",
"label.set.default.NIC": "设置默认 NIC", "label.set.default.NIC": "设置默认 NIC",
"label.set.reservation": "Set reservation",
"label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.<br/><br/>System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'",
"label.set.up.zone.type": "设置资源域类型", "label.set.up.zone.type": "设置资源域类型",
"label.settings": "设置", "label.settings": "设置",
"label.setup": "设置", "label.setup": "设置",

View File

@ -1340,5 +1340,8 @@ cloudStack.docs = {
}, },
helpLdapLinkDomainAdmin: { helpLdapLinkDomainAdmin: {
desc: 'domain admin of the linked domain. Specify a username in GROUP/OU of LDAP' desc: 'domain admin of the linked domain. Specify a username in GROUP/OU of LDAP'
},
helpSetReservationSystemVms: {
desc: 'If enabled, IP range reservation is set for SSVM & CPVM. Global setting "system.vm.public.ip.reservation.mode.strictness" is used to control whether reservation is strict or not (preferred)'
} }
}; };

View File

@ -54,6 +54,12 @@
var data = args.data ? args.data: { var data = args.data ? args.data: {
}; };
var fields = { var fields = {
systemvms: {
label: 'label.system.vms',
isBoolean: true,
docID: 'helpSetReservationSystemVms',
defaultValue: data.systemvms
},
account: { account: {
label: 'label.account', label: 'label.account',
defaultValue: data.account defaultValue: data.account
@ -96,22 +102,40 @@
success: function (json) { success: function (json) {
var domain = json.listdomainsresponse.domain[0]; var domain = json.listdomainsresponse.domain[0];
if (data.forSystemVms != null) {
systemvms = '<li>' + _l('label.system.vms') + ': ' + data.forSystemVms + '</li>'
}
if (data.account != null) if (data.account != null)
cloudStack.dialog.notice({ cloudStack.dialog.notice({
message: '<ul><li>' + _l('label.account') + ': ' + data.account + '</li>' + '<li>' + _l('label.domain') + ': ' + domain.path + '</li></ul>' message: '<ul><li>' + _l('label.account') + ': ' + data.account + '</li>' + '<li>' + _l('label.domain') + ': ' + domain.path + '</li>' + systemvms + '</ul>'
}); });
else else
cloudStack.dialog.notice({ cloudStack.dialog.notice({
message: '<ul><li>' + _l('label.domain') + ': ' + domain.path + '</li></ul>' message: '<ul><li>' + _l('label.domain') + ': ' + domain.path + '</li>' + systemvms + '</ul>'
}); });
} }
}); });
} else { } else {
cloudStack.dialog.createForm({ cloudStack.dialog.createForm({
form: { form: {
title: 'label.add.account', title: 'label.set.reservation',
desc: '(optional) Please specify an account to be associated with this IP range.', desc: 'label.set.reservation.desc',
fields: fields fields: fields,
preFilter: function(args) {
var $systemvms = args.$form.find('.form-item[rel=systemvms]');
var $systemvmsCb = $systemvms.find('input[type=checkbox]');
var $account = args.$form.find('.form-item[rel=account]');
var $accountTxt = args.$form.find('input[name=account]');
$systemvmsCb.change(function() {
if ($systemvmsCb.is(':checked')) {
$accountTxt.val('');
$accountTxt.attr('disabled', true);
}
else {
$accountTxt.attr('disabled', false);
}
});
}
}, },
after: function (args) { after: function (args) {
var data = cloudStack.serializeForm(args.$form); var data = cloudStack.serializeForm(args.$form);
@ -438,7 +462,7 @@
'account': { 'account': {
label: 'label.account', label: 'label.account',
custom: { custom: {
buttonLabel: 'label.add.account', buttonLabel: 'label.set.reservation',
action: cloudStack.publicIpRangeAccount.dialog() action: cloudStack.publicIpRangeAccount.dialog()
} }
}, },
@ -466,6 +490,10 @@
if (args.data.account) { if (args.data.account) {
if (args.data.account.account) if (args.data.account.account)
array1.push("&account=" + args.data.account.account); array1.push("&account=" + args.data.account.account);
if (args.data.account.systemvms) {
systvmsval = args.data.account.systemvms == "on" ? "true" : "false"
array1.push("&forsystemvms=" + systvmsval);
}
array1.push("&domainid=" + args.data.account.domainid); array1.push("&domainid=" + args.data.account.domainid);
} }
@ -627,7 +655,8 @@
account: { account: {
_buttonLabel: item.account ? '[' + item.domain + '] ' + item.account: item.domain, _buttonLabel: item.account ? '[' + item.domain + '] ' + item.account: item.domain,
account: item.account, account: item.account,
domainid: item.domainid domainid: item.domainid,
forSystemVms: item.forsystemvms
} }
}); });
}) })