CLOUDSTACK-10126: Separate Subnet for SSVM and CPVM (#2368)

This extends work presented on #2048 on which the ability to extend the management range is provided.

Aim
This PR allows separating the management network subnet on which SSVM and CPVM are from the virtual routers management subnet.

Detailed use case
PCI compliance requires that network elements are defined as ‘in scope’ or ‘out of scope’, for compliance purposes. The SSVM and CPVM are both in scope as they allow public HTTP or HTTPS connections. The virtual routers have been defined as out of scope as they have been placed entirely in a firewalled network's segment. However, all of the system VM types share management network. As SSVM and CPVM are both in scope this would bring the virtual routers into scope as well, requiring individual audits of every virtual router. As this is not practical, the ‘management network’ which the SSVM and CPVM are on, and the management network which the virtual routers are on, must be separated by a firewall.

Description
By this feature it is possible to dedicate a created range for SSVM and CPVM (system vms) and provide a VLAN ID for its range.

A new boolean global configuration is added: system.vm.management.ip.reservation.mode.strictness. If enabled, the use of System VMs management IP reservation is strict, preferred if not. Default value is false (preferred).

Strict reservation: System VMs should try to get a private IP from a range marked for system vms. If not available, deployment fails
Preferred reservation: System VMS will try to get a private IP from a range marked for system vms. If not available, IP for range not marked for system vms is taken.
This commit is contained in:
Nicolas Vazquez 2018-01-05 04:49:03 -03:00 committed by Rohit Yadav
parent b26d798868
commit bf4f1bbb90
18 changed files with 288 additions and 33 deletions

View File

@ -125,6 +125,7 @@ public class ApiConstants {
public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage";
public static final String FORMAT = "format";
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
public static final String FOR_SYSTEM_VMS = "forsystemvms";
public static final String GATEWAY = "gateway";
public static final String IP6_GATEWAY = "ip6gateway";
public static final String GROUP = "group";

View File

@ -85,6 +85,16 @@ public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd {
description = "The ending IP address.")
private String endIp;
@Parameter(name = ApiConstants.FOR_SYSTEM_VMS,
type = CommandType.BOOLEAN,
description = "Specify if range is dedicated for CPVM and SSVM.")
private Boolean forSystemVms;
@Parameter(name = ApiConstants.VLAN,
type = CommandType.STRING,
description = "Optional. The vlan id the ip range sits on, default to Null when it is not specificed which means you network is not on any Vlan")
private String vlan;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -109,6 +119,17 @@ public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd {
return endIp;
}
public Boolean isForSystemVms() {
return forSystemVms == null ? Boolean.FALSE : forSystemVms;
}
public String getVlan() {
if (vlan == null || vlan.isEmpty()) {
vlan = "untagged";
}
return vlan;
}
@Override
public String getEventType() {
return EventTypes.EVENT_MANAGEMENT_IP_RANGE_CREATE;

View File

@ -72,6 +72,12 @@ public class DeleteManagementNetworkIpRangeCmd extends BaseAsyncCmd {
validations = ApiArgValidator.NotNullOrEmpty)
private String endIp;
@Parameter(name = ApiConstants.VLAN,
type = CommandType.STRING,
required = true,
description = "The vlan id the ip range sits on")
private String vlan;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -88,6 +94,10 @@ public class DeleteManagementNetworkIpRangeCmd extends BaseAsyncCmd {
return endIp;
}
public String getVlan() {
return vlan;
}
@Override
public String getEventType() {
return EventTypes.EVENT_MANAGEMENT_IP_RANGE_DELETE;

View File

@ -61,6 +61,14 @@ public class PodResponse extends BaseResponse {
@Param(description = "the ending IP for the Pod")
private List<String> endIp;
@SerializedName("forsystemvms")
@Param(description = "indicates if range is dedicated for CPVM and SSVM")
private List<String> forSystemVms;
@SerializedName("vlanid")
@Param(description = "indicates Vlan ID for the range")
private List<String> vlanId;
@SerializedName("allocationstate")
@Param(description = "the allocation state of the Pod")
private String allocationState;
@ -133,6 +141,22 @@ public class PodResponse extends BaseResponse {
this.endIp = endIp;
}
public void setForSystemVms(List<String> forSystemVms) {
this.forSystemVms = forSystemVms;
}
public List<String> getForSystemVms() {
return forSystemVms;
}
public List<String> getVlanId() {
return vlanId;
}
public void setVlanId(List<String> vlanId) {
this.vlanId = vlanId;
}
public String getAllocationState() {
return allocationState;
}

View File

@ -516,3 +516,10 @@ UPDATE `cloud`.`vm_template` SET guest_os_id=99 WHERE id=8;
-- Network External Ids
ALTER TABLE `cloud`.`networks` ADD `external_id` varchar(255);
-- Separate Subnet for CPVM and SSVM (system vms)
ALTER TABLE `cloud`.`op_dc_ip_address_alloc`
ADD COLUMN `forsystemvms` TINYINT(1) NOT NULL DEFAULT '0' COMMENT 'Indicates if IP is dedicated for CPVM or SSVM';
ALTER TABLE `cloud`.`op_dc_ip_address_alloc`
ADD COLUMN `vlan` INT(10) UNSIGNED NULL COMMENT 'Vlan the management network range is on';

View File

@ -60,6 +60,12 @@ public class DataCenterIpAddressVO implements InternalIdentity {
@Column(name = "mac_address")
long macAddress;
@Column(name = "forsystemvms")
private boolean forSystemVms;
@Column(name = "vlan")
private Integer vlan;
protected DataCenterIpAddressVO() {
}
@ -113,4 +119,12 @@ public class DataCenterIpAddressVO implements InternalIdentity {
public long getMacAddress() {
return macAddress;
}
public boolean isForSystemVms() {
return forSystemVms;
}
public Integer getVlan() {
return vlan;
}
}

View File

@ -21,10 +21,35 @@ import java.util.List;
import com.cloud.dc.DataCenterIpAddressVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.DataCenterVnetVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
public interface DataCenterDao extends GenericDao<DataCenterVO, Long> {
class PrivateAllocationData {
private String ipAddress;
private Long macAddress;
private Integer vlan;
public PrivateAllocationData(final String ipAddress, final Long macAddress, final Integer vlan) {
this.ipAddress = ipAddress;
this.macAddress = macAddress;
this.vlan = vlan;
}
public String getIpAddress() {
return ipAddress;
}
public Long getMacAddress() {
return macAddress;
}
public Integer getVlan() {
return vlan;
}
}
DataCenterVO findByName(String name);
/**
@ -35,7 +60,7 @@ public interface DataCenterDao extends GenericDao<DataCenterVO, Long> {
String[] getNextAvailableMacAddressPair(long id, long mask);
Pair<String, Long> allocatePrivateIpAddress(long id, long podId, long instanceId, String reservationId);
PrivateAllocationData allocatePrivateIpAddress(long id, long podId, long instanceId, String reservationId, boolean forSystemVms);
DataCenterIpAddressVO allocatePrivateIpAddress(long id, String reservationId);
@ -57,7 +82,7 @@ public interface DataCenterDao extends GenericDao<DataCenterVO, Long> {
boolean deleteLinkLocalIpAddressByPod(long podId);
void addPrivateIpAddress(long dcId, long podId, String start, String end);
void addPrivateIpAddress(long dcId, long podId, String start, String end, boolean forSystemVms, Integer vlan);
void addLinkLocalIpAddress(long dcId, long podId, String start, String end);

View File

@ -38,7 +38,6 @@ import com.cloud.network.dao.AccountGuestVlanMapDao;
import com.cloud.network.dao.AccountGuestVlanMapVO;
import com.cloud.org.Grouping;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
@ -247,13 +246,13 @@ public class DataCenterDaoImpl extends GenericDaoBase<DataCenterVO, Long> implem
}
@Override
public Pair<String, Long> allocatePrivateIpAddress(long dcId, long podId, long instanceId, String reservationId) {
public PrivateAllocationData allocatePrivateIpAddress(long dcId, long podId, long instanceId, String reservationId, boolean forSystemVms) {
_ipAllocDao.releaseIpAddress(instanceId);
DataCenterIpAddressVO vo = _ipAllocDao.takeIpAddress(dcId, podId, instanceId, reservationId);
DataCenterIpAddressVO vo = _ipAllocDao.takeIpAddress(dcId, podId, instanceId, reservationId, forSystemVms);
if (vo == null) {
return null;
}
return new Pair<String, Long>(vo.getIpAddress(), vo.getMacAddress());
return new PrivateAllocationData(vo.getIpAddress(), vo.getMacAddress(), vo.getVlan());
}
@Override
@ -287,8 +286,8 @@ public class DataCenterDaoImpl extends GenericDaoBase<DataCenterVO, Long> implem
}
@Override
public void addPrivateIpAddress(long dcId, long podId, String start, String end) {
_ipAllocDao.addIpRange(dcId, podId, start, end);
public void addPrivateIpAddress(long dcId, long podId, String start, String end, boolean forSystemVms, Integer vlan) {
_ipAllocDao.addIpRange(dcId, podId, start, end, forSystemVms, vlan);
}
@Override

View File

@ -23,11 +23,11 @@ import com.cloud.utils.db.GenericDao;
public interface DataCenterIpAddressDao extends GenericDao<DataCenterIpAddressVO, Long> {
DataCenterIpAddressVO takeIpAddress(long dcId, long podId, long instanceId, String reservationId);
DataCenterIpAddressVO takeIpAddress(long dcId, long podId, long instanceId, String reservationId, boolean forSystemVms);
DataCenterIpAddressVO takeDataCenterIpAddress(long dcId, String reservationId);
void addIpRange(long dcId, long podId, String start, String end);
void addIpRange(long dcId, long podId, String start, String end, boolean forSystemVms, Integer vlan);
void releaseIpAddress(String ipAddress, long dcId, Long instanceId);

View File

@ -22,6 +22,8 @@ import java.util.Date;
import java.util.List;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -38,7 +40,7 @@ import com.cloud.utils.net.NetUtils;
@Component
@DB
public class DataCenterIpAddressDaoImpl extends GenericDaoBase<DataCenterIpAddressVO, Long> implements DataCenterIpAddressDao {
public class DataCenterIpAddressDaoImpl extends GenericDaoBase<DataCenterIpAddressVO, Long> implements DataCenterIpAddressDao, Configurable {
private static final Logger s_logger = Logger.getLogger(DataCenterIpAddressDaoImpl.class);
private final SearchBuilder<DataCenterIpAddressVO> AllFieldsSearch;
@ -47,16 +49,26 @@ public class DataCenterIpAddressDaoImpl extends GenericDaoBase<DataCenterIpAddre
private final GenericSearchBuilder<DataCenterIpAddressVO, Integer> AllAllocatedIpCount;
private final GenericSearchBuilder<DataCenterIpAddressVO, Integer> AllAllocatedIpCountForDc;
private static final ConfigKey<Boolean> SystemVmManagementIpReservationModeStrictness = new ConfigKey<Boolean>("Advanced",
Boolean.class, "system.vm.management.ip.reservation.mode.strictness", "false","If enabled, the use of System VMs management IP reservation is strict, preferred if not.", false, ConfigKey.Scope.Global);
@Override
@DB
public DataCenterIpAddressVO takeIpAddress(long dcId, long podId, long instanceId, String reservationId) {
public DataCenterIpAddressVO takeIpAddress(long dcId, long podId, long instanceId, String reservationId, boolean forSystemVms) {
SearchCriteria<DataCenterIpAddressVO> sc = AllFieldsSearch.create();
sc.setParameters("pod", podId);
sc.setParameters("taken", (Date)null);
sc.setParameters("forSystemVms", forSystemVms);
TransactionLegacy txn = TransactionLegacy.currentTxn();
txn.start();
DataCenterIpAddressVO vo = lockOneRandomRow(sc, true);
// If there is no explicitly created range for system vms and reservation mode is preferred (strictness = false)
if (forSystemVms && vo == null && !SystemVmManagementIpReservationModeStrictness.value()) {
sc.setParameters("forSystemVms", false);
vo = lockOneRandomRow(sc, true);
}
if (vo == null) {
txn.rollback();
return null;
@ -121,10 +133,10 @@ public class DataCenterIpAddressDaoImpl extends GenericDaoBase<DataCenterIpAddre
@Override
@DB
public void addIpRange(long dcId, long podId, String start, String end) {
public void addIpRange(long dcId, long podId, String start, String end, boolean forSystemVms, Integer vlan) {
TransactionLegacy txn = TransactionLegacy.currentTxn();
String insertSql = "INSERT INTO `cloud`.`op_dc_ip_address_alloc` (ip_address, data_center_id, pod_id, mac_address) " +
"VALUES (?, ?, ?, (select mac_address from `cloud`.`data_center` where id=?))";
String insertSql = "INSERT INTO `cloud`.`op_dc_ip_address_alloc` (ip_address, data_center_id, pod_id, mac_address, forsystemvms" + (vlan == null ? ") " : ", vlan) ") +
"VALUES (?, ?, ?, (select mac_address from `cloud`.`data_center` where id=?), ?" + (vlan == null ? ")" : ", ?)");
String updateSql = "UPDATE `cloud`.`data_center` set mac_address = mac_address+1 where id=?";
long startIP = NetUtils.ip2Long(start);
@ -139,6 +151,10 @@ public class DataCenterIpAddressDaoImpl extends GenericDaoBase<DataCenterIpAddre
insertPstmt.setLong(2, dcId);
insertPstmt.setLong(3, podId);
insertPstmt.setLong(4, dcId);
insertPstmt.setBoolean(5, forSystemVms);
if (vlan != null) {
insertPstmt.setInt(6, vlan);
}
insertPstmt.executeUpdate();
}
try(PreparedStatement updatePstmt = txn.prepareStatement(updateSql);) {
@ -285,6 +301,7 @@ public class DataCenterIpAddressDaoImpl extends GenericDaoBase<DataCenterIpAddre
AllFieldsSearch.and("ipAddress", AllFieldsSearch.entity().getIpAddress(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("reservation", AllFieldsSearch.entity().getReservationId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("taken", AllFieldsSearch.entity().getTakenAt(), SearchCriteria.Op.EQ);
AllFieldsSearch.and("forSystemVms", AllFieldsSearch.entity().isForSystemVms(), SearchCriteria.Op.EQ);
AllFieldsSearch.done();
AllIpCount = createSearchBuilder(Integer.class);
@ -309,4 +326,14 @@ public class DataCenterIpAddressDaoImpl extends GenericDaoBase<DataCenterIpAddre
AllAllocatedIpCountForDc.and("removed", AllAllocatedIpCountForDc.entity().getTakenAt(), SearchCriteria.Op.NNULL);
AllAllocatedIpCountForDc.done();
}
@Override
public String getConfigComponentName() {
return DataCenterIpAddressDao.class.getSimpleName();
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {SystemVmManagementIpReservationModeStrictness};
}
}

View File

@ -947,6 +947,8 @@ public class ApiResponseHelper implements ResponseGenerator {
String[] ipRange = new String[2];
List<String> startIp = new ArrayList<String>();
List<String> endIp = new ArrayList<String>();
List<String> forSystemVms = new ArrayList<String>();
List<String> vlanIds = new ArrayList<String>();
if (pod.getDescription() != null && pod.getDescription().length() > 0) {
final String[] existingPodIpRanges = pod.getDescription().split(",");
@ -956,6 +958,11 @@ public class ApiResponseHelper implements ResponseGenerator {
startIp.add(((existingPodIpRange.length > 0) && (existingPodIpRange[0] != null)) ? existingPodIpRange[0] : "");
endIp.add(((existingPodIpRange.length > 1) && (existingPodIpRange[1] != null)) ? existingPodIpRange[1] : "");
forSystemVms.add((existingPodIpRange.length > 2) && (existingPodIpRange[2] != null) ? existingPodIpRange[2] : "0");
vlanIds.add((existingPodIpRange.length > 3) &&
(existingPodIpRange[3] != null && !existingPodIpRange.equals("untagged")) ?
BroadcastDomainType.Vlan.toUri(existingPodIpRange[3]).toString() :
BroadcastDomainType.Vlan.toUri(Vlan.UNTAGGED).toString());
}
}
@ -970,6 +977,8 @@ public class ApiResponseHelper implements ResponseGenerator {
podResponse.setNetmask(NetUtils.getCidrNetmask(pod.getCidrSize()));
podResponse.setStartIp(startIp);
podResponse.setEndIp(endIp);
podResponse.setForSystemVms(forSystemVms);
podResponse.setVlanId(vlanIds);
podResponse.setGateway(pod.getGateway());
podResponse.setAllocationState(pod.getAllocationState().toString());
if (showCapacities != null && showCapacities) {

View File

@ -17,6 +17,7 @@
package com.cloud.configuration;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.util.ArrayList;
@ -363,6 +364,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
public static final ConfigKey<Boolean> SystemVMUseLocalStorage = new ConfigKey<Boolean>(Boolean.class, "system.vm.use.local.storage", "Advanced", "false",
"Indicates whether to use local storage pools or shared storage pools for system VMs.", false, ConfigKey.Scope.Zone, null);
private static final String DefaultForSystemVmsForPodIpRange = "0";
private static final String DefaultVlanForPodIpRange = Vlan.UNTAGGED.toString();
private static final Set<Provider> VPC_ONLY_PROVIDERS = Sets.newHashSet(Provider.VPCVirtualRouter, Provider.JuniperContrailVpcRouter, Provider.InternalLbVm);
@Override
@ -1095,6 +1099,25 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
return true;
}
/**
* Get vlan number from vlan uri
* @param vlan
* @return
*/
protected String getVlanNumberFromUri(String vlan) {
URI uri;
try {
uri = new URI(vlan);
String vlanId = BroadcastDomainType.getValue(uri);
if (vlanId == null || !uri.getScheme().equalsIgnoreCase("vlan")) {
throw new CloudRuntimeException("Vlan parameter : " + vlan + " is not in valid format");
}
return vlanId;
} catch (URISyntaxException e) {
throw new CloudRuntimeException("Invalid vlan parameter: " + vlan + " can't get vlan number from it due to: " + e.getMessage());
}
}
@Override
@DB
public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) {
@ -1110,6 +1133,14 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final String netmask = cmd.getNetmask();
final String startIp = cmd.getStartIp();
String endIp = cmd.getEndIp();
final boolean forSystemVms = cmd.isForSystemVms();
String vlan = cmd.getVlan();
if (!(Strings.isNullOrEmpty(vlan) || vlan.startsWith(BroadcastDomainType.Vlan.scheme()))) {
vlan = BroadcastDomainType.Vlan.toUri(vlan).toString();
}
String vlanNumberFromUri = getVlanNumberFromUri(vlan);
final Integer vlanId = vlanNumberFromUri.equals(Vlan.UNTAGGED.toString()) ? null : Integer.parseInt(vlanNumberFromUri);
final HostPodVO pod = _podDao.findById(podId);
@ -1188,10 +1219,15 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
public void doInTransactionWithoutResult(final TransactionStatus status) {
String ipRange = pod.getDescription();
/*
* POD Description is refactored to:
* <START_IP>-<END_IP>-<FOR_SYSTEM_VMS>-<VLAN>,<START_IP>-<END_IP>-<FOR_SYSTEM_VMS>-<VLAN>,...
*/
String range = startIp + "-" + endIpFinal + "-" + (forSystemVms ? "1" : "0") + "-" + (vlanId == null ? DefaultVlanForPodIpRange : vlanId);
if(ipRange != null && !ipRange.isEmpty())
ipRange += ("," + startIp + "-" + endIpFinal);
ipRange += ("," + range);
else
ipRange = (startIp + "-" + endIpFinal);
ipRange = (range);
pod.setDescription(ipRange);
@ -1212,7 +1248,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
}
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal);
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal, forSystemVms, vlanId);
}
});
} catch (final Exception e) {
@ -1229,6 +1265,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final long podId = cmd.getPodId();
final String startIp = cmd.getStartIp();
final String endIp = cmd.getEndIp();
String vlan = cmd.getVlan();
try {
vlan = BroadcastDomainType.getValue(vlan);
} catch (URISyntaxException e) {
throw new CloudRuntimeException("Incorrect vlan " + vlan);
}
final HostPodVO pod = _podDao.findById(podId);
@ -1268,10 +1310,13 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final String[] existingPodIpRange = podIpRange.split("-");
if(existingPodIpRange.length > 1) {
if (startIp.equals(existingPodIpRange[0]) && endIp.equals(existingPodIpRange[1])) {
if (startIp.equals(existingPodIpRange[0]) && endIp.equals(existingPodIpRange[1]) &&
(existingPodIpRange.length > 3 ? vlan.equals(existingPodIpRange[3]) : vlan.equals(DefaultVlanForPodIpRange))) {
foundRange = true;
} else if (index >= 0) {
newPodIpRanges[index--] = (existingPodIpRange[0] + "-" + existingPodIpRange[1]);
newPodIpRanges[index--] = (existingPodIpRange[0] + "-" + existingPodIpRange[1] + "-" +
(existingPodIpRange.length > 2 ? existingPodIpRange[2] : DefaultForSystemVmsForPodIpRange) + "-" +
(existingPodIpRange.length > 3 ? existingPodIpRange[3] : DefaultVlanForPodIpRange));
}
}
}
@ -1495,8 +1540,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
// Create the new pod in the database
String ipRange;
if (!Strings.isNullOrEmpty(startIp)) {
ipRange = startIp + "-" + endIp;
ipRange = startIp + "-" + endIp + "-" + DefaultForSystemVmsForPodIpRange + "-" + DefaultVlanForPodIpRange;
} else {
throw new InvalidParameterValueException("Start ip is required parameter");
}
@ -1517,7 +1563,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final HostPodVO pod = _podDao.persist(podFinal);
if (!Strings.isNullOrEmpty(startIp)) {
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal);
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal, false, null);
}
final String[] linkLocalIpRanges = getLinkLocalIPRange();

View File

@ -1065,7 +1065,7 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
if (podvo == null)
throw new ResourceAllocationException("No sush pod exists", ResourceType.network);
vo = _privateIPAddressDao.takeIpAddress(zone.getId(), podvo.getId(), 0, caller.getId() + "");
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)

View File

@ -16,6 +16,8 @@
// under the License.
package com.cloud.network.guru;
import com.cloud.dc.dao.DataCenterDao.PrivateAllocationData;
import com.cloud.vm.VirtualMachine;
import java.util.Random;
import javax.inject.Inject;
@ -39,7 +41,6 @@ import com.cloud.network.StorageNetworkManager;
import com.cloud.network.dao.NetworkVO;
import com.cloud.offering.NetworkOffering;
import com.cloud.user.Account;
import com.cloud.utils.Pair;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
@ -119,19 +120,25 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru {
throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException {
Pod pod = dest.getPod();
Pair<String, Long> ip = _dcDao.allocatePrivateIpAddress(dest.getDataCenter().getId(), dest.getPod().getId(), nic.getId(), context.getReservationId());
if (ip == null) {
boolean forSystemVms = vm.getType().equals(VirtualMachine.Type.ConsoleProxy) || vm.getType().equals(VirtualMachine.Type.SecondaryStorageVm);
PrivateAllocationData result = _dcDao.allocatePrivateIpAddress(dest.getDataCenter().getId(), dest.getPod().getId(), nic.getId(), context.getReservationId(), forSystemVms);
if (result == null) {
throw new InsufficientAddressCapacityException("Unable to get a management ip address", Pod.class, pod.getId());
}
Integer vlan = result.getVlan();
nic.setIPv4Address(ip.first());
nic.setMacAddress(NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ip.second(), NetworkModel.MACIdentifier.value())));
nic.setIPv4Address(result.getIpAddress());
nic.setMacAddress(NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(result.getMacAddress(), NetworkModel.MACIdentifier.value())));
nic.setIPv4Gateway(pod.getGateway());
nic.setFormat(AddressFormat.Ip4);
String netmask = NetUtils.getCidrNetmask(pod.getCidrSize());
nic.setIPv4Netmask(netmask);
nic.setBroadcastType(BroadcastDomainType.Native);
nic.setBroadcastUri(null);
if (vlan != null) {
nic.setBroadcastUri(BroadcastDomainType.Native.toUri(vlan));
} else {
nic.setBroadcastUri(null);
}
nic.setIsolationUri(null);
s_logger.debug("Allocated a nic " + nic + " for " + vm);

View File

@ -902,7 +902,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
}
if (startIp != null) {
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal);
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal, false, null);
}
String ipNums = _configDao.getValue("linkLocalIp.nums");

View File

@ -891,4 +891,24 @@ public class ConfigurationManagerTest {
result = configurationMgr.hasSameSubnet(false, null, null, null, null, null, null, true, null, null, "2001:db8:0:f101::2", "2001:db8:0:f101::a", ipV6Network);
Assert.assertTrue(result);
}
@Test(expected = CloudRuntimeException.class)
public void testGetVlanNumberFromUriInvalidParameter() {
configurationMgr.getVlanNumberFromUri("vlan");
}
@Test(expected = CloudRuntimeException.class)
public void testGetVlanNumberFromUriInvalidSintax() {
configurationMgr.getVlanNumberFromUri("xxx://7");
}
@Test
public void testGetVlanNumberFromUriVlan() {
Assert.assertEquals("7", configurationMgr.getVlanNumberFromUri("vlan://7"));
}
@Test
public void testGetVlanNumberFromUriUntagged() {
Assert.assertEquals("untagged", configurationMgr.getVlanNumberFromUri("vlan://untagged"));
}
}

View File

@ -974,6 +974,13 @@
edit: true,
label: 'label.netmask'
},
'vlan': {
edit: true,
label: 'label.vlan',
validation: {
required: false
}
},
'startip': {
edit: true,
label: 'label.start.IP'
@ -985,6 +992,10 @@
required: false
}
},
'systemvms' : {
isBoolean: true,
label: 'label.system.vms'
},
'add-rule': {
label: 'label.add',
addButton: true
@ -1003,6 +1014,13 @@
if (args.data.endip != null && args.data.endip.length > 0)
array1.push("&endip=" + args.data.endip);
if (args.data.systemvms) {
array1.push("&forsystemvms=" + (args.data.systemvms == "on" ? "true" : "false"));
}
if (args.data.vlan != null && args.data.vlan.length > 0)
array1.push("&vlan=" + todb(args.data.vlan));
$.ajax({
url: createURL("createManagementNetworkIpRange" + array1.join("")),
dataType: "json",
@ -1032,6 +1050,7 @@
array1.push("&podid=" + args.context.multiRule[0].podid);
array1.push("&startip=" + args.context.multiRule[0].startip);
array1.push("&endip=" + args.context.multiRule[0].endip);
array1.push("&vlan=" + args.context.multiRule[0].vlan);
$.ajax({
url: createURL('deleteManagementNetworkIpRange' + array1.join("")),
@ -1067,12 +1086,15 @@
var pods = json.listpodsresponse.pod;
$(pods).each(function () {
for (var i = 0; i < this.startip.length; i++) {
var systemvmsValue = this.forsystemvms[i] == "1" ? true : false;
items.push({
podid: this.id,
gateway: this.gateway,
netmask: this.netmask,
startip: this.startip[i],
endip: this.endip[i]
endip: this.endip[i],
systemvms: systemvmsValue,
vlan: this.vlanid[i]
});
}
});

View File

@ -179,6 +179,19 @@
}
$td.attr('title', data[fieldName]);
}
} else if (field.isBoolean) {
var $checkbox = $('<input>');
$checkbox.attr({
disabled: true,
name: fieldName,
type: 'checkbox'
});
if (_s(data[fieldName])) {
$checkbox.attr({
checked: true
});
}
$checkbox.appendTo($td);
} else if (field.select) {
// Get matching option text
var $matchingSelect = $multi.find('select')
@ -980,6 +993,12 @@
error: function(args) {}
}
});
} else if (field.isBoolean) {
var $input = $('<input>')
.attr({
name: fieldName,
type: 'checkbox'
}).appendTo($td);
} else if (field.edit && field.edit != 'ignore') {
if (field.range) {
var $range = $('<div>').addClass('range').appendTo($td);
@ -1118,7 +1137,11 @@
$multi.find('input').each(function() {
var $input = $(this);
if ($input.data('multi-default-value')) {
if ($input.is(":checkbox")) {
$input.attr({
checked: false
});
} else if ($input.data('multi-default-value')) {
$input.val($input.data('multi-default-value'));
} else {
$input.val('');