CLOUDSTACK-9880: Expansion of Management IP Range. (#2048)

At present, The management IP range can only be expanded under the same subnet. According to existing range, either the last IP can be forward extended or the first IP can be backward extended. But we cannot add an entirely different range from the same subnet. So the expansion of range is subnet bound, which is fixed. But when the range gets exhausted and a user wants to deploy more system VMs, then the operation would fail. The purpose of this feature is to expand the range of management network IPs within the existing subnet. It can also delete and list the IP ranges.

Please refer the FS here: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Expansion+of+Management+IP+Range
This commit is contained in:
Nitin Kumar Maharana 2017-12-20 14:06:53 +05:30 committed by dahn
parent 9179bd54d4
commit 8acb0908c4
15 changed files with 837 additions and 194 deletions

View File

@ -19,7 +19,9 @@ package com.cloud.configuration;
import java.util.List;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
@ -160,6 +162,19 @@ public interface ConfigurationService {
*/
Pod createPod(long zoneId, String name, String startIp, String endIp, String gateway, String netmask, String allocationState);
/**
* Creates a mutual exclusive IP range in the pod with same gateway, netmask.
* @param cmd - The command specifying pod ID, start IP, end IP, gateway, netmask.
* @return The new range if successful, null otherwise.
*/
Pod createPodIpRange(CreateManagementNetworkIpRangeCmd cmd);
/**
* Deletes a mutually exclusive IP range in the pod.
* @param cmd - The command specifying pod ID, start IP, end IP.
*/
void deletePodIpRange(DeleteManagementNetworkIpRangeCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException;
/**
* Edits a pod in the database. Will not allow you to edit pods that are being used anywhere in the system.
*

View File

@ -21,20 +21,19 @@ import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
public interface StorageNetworkIpRange extends InfrastructureEntity, InternalIdentity, Identity {
Integer getVlan();
String getPodUuid();
String getGateway();
String getNetmask();
String getStartIp();
String getEndIp();
String getNetworkUuid();
String getZoneUuid();
String getNetmask();
String getPodUuid();
String getGateway();
String getNetworkUuid();
}

View File

@ -296,6 +296,9 @@ public class EventTypes {
public static final String EVENT_VLAN_IP_RANGE_DEDICATE = "VLAN.IP.RANGE.DEDICATE";
public static final String EVENT_VLAN_IP_RANGE_RELEASE = "VLAN.IP.RANGE.RELEASE";
public static final String EVENT_MANAGEMENT_IP_RANGE_CREATE = "MANAGEMENT.IP.RANGE.CREATE";
public static final String EVENT_MANAGEMENT_IP_RANGE_DELETE = "MANAGEMENT.IP.RANGE.DELETE";
public static final String EVENT_STORAGE_IP_RANGE_CREATE = "STORAGE.IP.RANGE.CREATE";
public static final String EVENT_STORAGE_IP_RANGE_DELETE = "STORAGE.IP.RANGE.DELETE";
public static final String EVENT_STORAGE_IP_RANGE_UPDATE = "STORAGE.IP.RANGE.UPDATE";
@ -761,6 +764,9 @@ public class EventTypes {
entityEventDetails.put(EVENT_VLAN_IP_RANGE_DEDICATE, Vlan.class);
entityEventDetails.put(EVENT_VLAN_IP_RANGE_RELEASE, Vlan.class);
entityEventDetails.put(EVENT_MANAGEMENT_IP_RANGE_CREATE, Pod.class);
entityEventDetails.put(EVENT_MANAGEMENT_IP_RANGE_DELETE, Pod.class);
entityEventDetails.put(EVENT_STORAGE_IP_RANGE_CREATE, StorageNetworkIpRange.class);
entityEventDetails.put(EVENT_STORAGE_IP_RANGE_DELETE, StorageNetworkIpRange.class);
entityEventDetails.put(EVENT_STORAGE_IP_RANGE_UPDATE, StorageNetworkIpRange.class);

View File

@ -0,0 +1,145 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.admin.network;
import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.PodResponse;
import com.cloud.dc.Pod;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
@APICommand(name = CreateManagementNetworkIpRangeCmd.APINAME,
description = "Creates a Management network IP range.",
responseObject = PodResponse.class,
since = "4.11.0.0",
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false,
authorized = {RoleType.Admin})
public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(CreateManagementNetworkIpRangeCmd.class);
public static final String APINAME = "createManagementNetworkIpRange";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.POD_ID,
type = CommandType.UUID,
entityType = PodResponse.class,
required = true,
description = "UUID of POD, where the IP range belongs to.",
validations = {ApiArgValidator.PositiveNumber})
private Long podId;
@Parameter(name = ApiConstants.GATEWAY,
type = CommandType.STRING,
required = true,
description = "The gateway for the management network.",
validations = {ApiArgValidator.NotNullOrEmpty})
private String gateway;
@Parameter(name = ApiConstants.NETMASK,
type = CommandType.STRING,
required = true,
description = "The netmask for the management network.",
validations = {ApiArgValidator.NotNullOrEmpty})
private String netmask;
@Parameter(name = ApiConstants.START_IP,
type = CommandType.STRING,
required = true,
description = "The starting IP address.",
validations = {ApiArgValidator.NotNullOrEmpty})
private String startIp;
@Parameter(name = ApiConstants.END_IP,
type = CommandType.STRING,
description = "The ending IP address.")
private String endIp;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getPodId() {
return podId;
}
public String getGateWay() {
return gateway;
}
public String getNetmask() {
return netmask;
}
public String getStartIp() {
return startIp;
}
public String getEndIp() {
return endIp;
}
@Override
public String getEventType() {
return EventTypes.EVENT_MANAGEMENT_IP_RANGE_CREATE;
}
@Override
public String getEventDescription() {
return "Creating management ip range from " + getStartIp() + " to " + getEndIp() + " and gateway=" + getGateWay() + ", netmask=" + getNetmask() + " of pod=" + getPodId();
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException {
Pod result = _configService.createPodIpRange(this);
if (result != null) {
PodResponse response = _responseGenerator.createPodResponse(result, false);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Pod IP Range.");
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,129 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.admin.network;
import org.apache.log4j.Logger;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.ApiArgValidator;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.PodResponse;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
@APICommand(name = DeleteManagementNetworkIpRangeCmd.APINAME,
description = "Deletes a management network IP range. This action is only allowed when no IPs in this range are allocated.",
responseObject = SuccessResponse.class,
since = "4.11.0.0",
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = false,
authorized = {RoleType.Admin})
public class DeleteManagementNetworkIpRangeCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(DeleteManagementNetworkIpRangeCmd.class);
public static final String APINAME = "deleteManagementNetworkIpRange";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.POD_ID,
type = CommandType.UUID,
entityType = PodResponse.class,
required = true,
description = "UUID of POD, where the IP range belongs to.",
validations = ApiArgValidator.PositiveNumber)
private Long podId;
@Parameter(name = ApiConstants.START_IP,
type = CommandType.STRING,
required = true,
description = "The starting IP address.",
validations = ApiArgValidator.NotNullOrEmpty)
private String startIp;
@Parameter(name = ApiConstants.END_IP,
type = CommandType.STRING,
required = true,
description = "The ending IP address.",
validations = ApiArgValidator.NotNullOrEmpty)
private String endIp;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getPodId() {
return podId;
}
public String getStartIp() {
return startIp;
}
public String getEndIp() {
return endIp;
}
@Override
public String getEventType() {
return EventTypes.EVENT_MANAGEMENT_IP_RANGE_DELETE;
}
@Override
public String getEventDescription() {
return "Deleting management ip range from " + getStartIp() + " to " + getEndIp() + " of Pod: " + getPodId();
}
@Override
public void execute() {
try {
_configService.deletePodIpRange(this);
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} catch (ResourceUnavailableException ex) {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
} catch (ConcurrentOperationException ex) {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
} catch (Exception e) {
s_logger.warn("Failed to delete management ip range from " + getStartIp() + " to " + getEndIp() + " of Pod: " + getPodId(), e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -55,11 +55,11 @@ public class PodResponse extends BaseResponse {
@SerializedName("startip")
@Param(description = "the starting IP for the Pod")
private String startIp;
private List<String> startIp;
@SerializedName("endip")
@Param(description = "the ending IP for the Pod")
private String endIp;
private List<String> endIp;
@SerializedName("allocationstate")
@Param(description = "the allocation state of the Pod")
@ -117,19 +117,19 @@ public class PodResponse extends BaseResponse {
this.netmask = netmask;
}
public String getStartIp() {
public List<String> getStartIp() {
return startIp;
}
public void setStartIp(String startIp) {
public void setStartIp(List<String> startIp) {
this.startIp = startIp;
}
public String getEndIp() {
public List<String> getEndIp() {
return endIp;
}
public void setEndIp(String endIp) {
public void setEndIp(List<String> endIp) {
this.endIp = endIp;
}

View File

@ -23,17 +23,17 @@ import com.cloud.utils.db.GenericDao;
public interface DataCenterIpAddressDao extends GenericDao<DataCenterIpAddressVO, Long> {
public DataCenterIpAddressVO takeIpAddress(long dcId, long podId, long instanceId, String reservationId);
DataCenterIpAddressVO takeIpAddress(long dcId, long podId, long instanceId, String reservationId);
public DataCenterIpAddressVO takeDataCenterIpAddress(long dcId, String reservationId);
DataCenterIpAddressVO takeDataCenterIpAddress(long dcId, String reservationId);
public void addIpRange(long dcId, long podId, String start, String end);
void addIpRange(long dcId, long podId, String start, String end);
public void releaseIpAddress(String ipAddress, long dcId, Long instanceId);
void releaseIpAddress(String ipAddress, long dcId, Long instanceId);
public void releaseIpAddress(long nicId, String reservationId);
void releaseIpAddress(long nicId, String reservationId);
public void releaseIpAddress(long nicId);
void releaseIpAddress(long nicId);
boolean mark(long dcId, long podId, String ip);
@ -45,8 +45,11 @@ public interface DataCenterIpAddressDao extends GenericDao<DataCenterIpAddressVO
int countIPs(long dcId, boolean onlyCountAllocated);
int countIpAddressUsage(final String ipAddress, final long podId, final long dcId, final boolean onlyCountAllocated);
boolean deleteIpAddressByPod(long podId);
void releasePodIpAddress(long id);
boolean deleteIpAddressByPodDc(String ipAddress, long podId, long dcId);
}

View File

@ -97,6 +97,16 @@ public class DataCenterIpAddressDaoImpl extends GenericDaoBase<DataCenterIpAddre
return remove(sc) > 0;
}
@Override
public boolean deleteIpAddressByPodDc(String ipAddress, long podId, long dcId) {
SearchCriteria<DataCenterIpAddressVO> sc = AllFieldsSearch.create();
sc.setParameters("ipAddress", ipAddress);
sc.setParameters("pod", podId);
sc.setParameters("dc", dcId);
return remove(sc) > 0;
}
@Override
public boolean mark(long dcId, long podId, String ip) {
SearchCriteria<DataCenterIpAddressVO> sc = AllFieldsSearch.create();
@ -248,6 +258,22 @@ public class DataCenterIpAddressDaoImpl extends GenericDaoBase<DataCenterIpAddre
return count.get(0);
}
@Override
public int countIpAddressUsage(final String ipAddress, final long podId, final long dcId, final boolean onlyCountAllocated) {
SearchCriteria<DataCenterIpAddressVO> sc = createSearchCriteria();
if(onlyCountAllocated) {
sc.addAnd("takenAt", SearchCriteria.Op.NNULL);
}
sc.addAnd("ipAddress", SearchCriteria.Op.EQ, ipAddress);
sc.addAnd("podId", SearchCriteria.Op.EQ, podId);
sc.addAnd("dataCenterId", SearchCriteria.Op.EQ, dcId);
List<DataCenterIpAddressVO> result = listBy(sc);
return result.size();
}
public DataCenterIpAddressDaoImpl() {
super();

View File

@ -945,10 +945,18 @@ public class ApiResponseHelper implements ResponseGenerator {
@Override
public PodResponse createPodResponse(Pod pod, Boolean showCapacities) {
String[] ipRange = new String[2];
List<String> startIp = new ArrayList<String>();
List<String> endIp = new ArrayList<String>();
if (pod.getDescription() != null && pod.getDescription().length() > 0) {
ipRange = pod.getDescription().split("-");
} else {
ipRange[0] = pod.getDescription();
final String[] existingPodIpRanges = pod.getDescription().split(",");
for(String podIpRange: existingPodIpRanges) {
final String[] existingPodIpRange = podIpRange.split("-");
startIp.add(((existingPodIpRange.length > 0) && (existingPodIpRange[0] != null)) ? existingPodIpRange[0] : "");
endIp.add(((existingPodIpRange.length > 1) && (existingPodIpRange[1] != null)) ? existingPodIpRange[1] : "");
}
}
PodResponse podResponse = new PodResponse();
@ -960,8 +968,8 @@ public class ApiResponseHelper implements ResponseGenerator {
podResponse.setZoneName(zone.getName());
}
podResponse.setNetmask(NetUtils.getCidrNetmask(pod.getCidrSize()));
podResponse.setStartIp(ipRange[0]);
podResponse.setEndIp(((ipRange.length > 1) && (ipRange[1] != null)) ? ipRange[1] : "");
podResponse.setStartIp(startIp);
podResponse.setEndIp(endIp);
podResponse.setGateway(pod.getGateway());
podResponse.setAllocationState(pod.getAllocationState().toString());
if (showCapacities != null && showCapacities) {

View File

@ -41,7 +41,9 @@ import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupService;
import org.apache.cloudstack.affinity.dao.AffinityGroupDao;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
@ -224,6 +226,7 @@ import com.cloud.vm.dao.NicSecondaryIpDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
public class ConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService, Configurable {
public static final Logger s_logger = Logger.getLogger(ConfigurationManagerImpl.class);
@ -997,7 +1000,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
checkIpRange(startIp, endIp, cidrAddress, cidrSize);
// Check if the IP range overlaps with the public ip
checkOverlapPublicIpRange(zoneId, startIp, endIp);
if(!Strings.isNullOrEmpty(startIp)) {
checkOverlapPublicIpRange(zoneId, startIp, endIp);
}
// Check if the gateway is a valid IP address
if (!NetUtils.isValidIp(gateway)) {
@ -1090,9 +1095,241 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
return true;
}
@Override
@DB
public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) {
final Account account = CallContext.current().getCallingAccount();
if(!_accountMgr.isRootAdmin(account.getId())) {
throw new PermissionDeniedException("Cannot perform this operation, Calling account is not root admin: " + account.getId());
}
final long podId = cmd.getPodId();
final String gateway = cmd.getGateWay();
final String netmask = cmd.getNetmask();
final String startIp = cmd.getStartIp();
String endIp = cmd.getEndIp();
final HostPodVO pod = _podDao.findById(podId);
if(pod == null) {
throw new InvalidParameterValueException("Unable to find pod by ID: " + podId);
}
final long zoneId = pod.getDataCenterId();
if(!NetUtils.isValidIp(gateway)) {
throw new InvalidParameterValueException("The gateway IP address is invalid.");
}
if(!NetUtils.isValidNetmask(netmask)) {
throw new InvalidParameterValueException("The netmask IP address is invalid.");
}
if(endIp == null) {
endIp = startIp;
}
final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
if(!NetUtils.isValidCIDR(cidr)) {
throw new InvalidParameterValueException("The CIDR is invalid " + cidr);
}
final String cidrAddress = pod.getCidrAddress();
final long cidrSize = pod.getCidrSize();
// Because each pod has only one Gateway and Netmask.
if (!gateway.equals(pod.getGateway())) {
throw new InvalidParameterValueException("Multiple gateways for the POD: " + pod.getId() + " are not allowed. The Gateway should be same as the existing Gateway " + pod.getGateway());
}
if (!netmask.equals(NetUtils.getCidrNetmask(cidrSize))) {
throw new InvalidParameterValueException("Multiple subnets for the POD: " + pod.getId() + " are not allowed. The Netmask should be same as the existing Netmask " + NetUtils.getCidrNetmask(cidrSize));
}
// Check if the IP range is valid.
checkIpRange(startIp, endIp, cidrAddress, cidrSize);
// Check if the IP range overlaps with the public ip.
checkOverlapPublicIpRange(zoneId, startIp, endIp);
// Check if the gateway is in the CIDR subnet
if (!NetUtils.getCidrSubNet(gateway, cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) {
throw new InvalidParameterValueException("The gateway is not in the CIDR subnet.");
}
if (NetUtils.ipRangesOverlap(startIp, endIp, gateway, gateway)) {
throw new InvalidParameterValueException("The gateway shouldn't overlap start/end ip addresses");
}
final String[] existingPodIpRanges = pod.getDescription().split(",");
for(String podIpRange: existingPodIpRanges) {
final String[] existingPodIpRange = podIpRange.split("-");
if (existingPodIpRange.length > 1) {
if (!NetUtils.isValidIp(existingPodIpRange[0]) || !NetUtils.isValidIp(existingPodIpRange[1])) {
continue;
}
// Check if the range overlaps with any existing range.
if (NetUtils.ipRangesOverlap(startIp, endIp, existingPodIpRange[0], existingPodIpRange[1])) {
throw new InvalidParameterValueException("The new range overlaps with existing range. Please add a mutually exclusive range.");
}
}
}
try {
final String endIpFinal = endIp;
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(final TransactionStatus status) {
String ipRange = pod.getDescription();
if(ipRange != null && !ipRange.isEmpty())
ipRange += ("," + startIp + "-" + endIpFinal);
else
ipRange = (startIp + "-" + endIpFinal);
pod.setDescription(ipRange);
HostPodVO lock = null;
try {
lock = _podDao.acquireInLockTable(podId);
if (lock == null) {
String msg = "Unable to acquire lock on table to update the ip range of POD: " + pod.getName() + ", Creation failed.";
s_logger.warn(msg);
throw new CloudRuntimeException(msg);
}
_podDao.update(podId, pod);
} finally {
if (lock != null) {
_podDao.releaseFromLockTable(podId);
}
}
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal);
}
});
} catch (final Exception e) {
s_logger.error("Unable to create Pod IP range due to " + e.getMessage(), e);
throw new CloudRuntimeException("Failed to create Pod IP range. Please contact Cloud Support.");
}
return pod;
}
@Override
@DB
public void deletePodIpRange(final DeleteManagementNetworkIpRangeCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException {
final long podId = cmd.getPodId();
final String startIp = cmd.getStartIp();
final String endIp = cmd.getEndIp();
final HostPodVO pod = _podDao.findById(podId);
if(pod == null) {
throw new InvalidParameterValueException("Unable to find pod by id " + podId);
}
if (startIp == null || !NetUtils.isValidIp(startIp)) {
throw new InvalidParameterValueException("The start address of the IP range is not a valid IP address.");
}
if (endIp == null || !NetUtils.isValidIp(endIp)) {
throw new InvalidParameterValueException("The end address of the IP range is not a valid IP address.");
}
if (NetUtils.ip2Long(startIp) > NetUtils.ip2Long(endIp)) {
throw new InvalidParameterValueException("The start IP address must have a lower value than the end IP address.");
}
for(long ipAddr = NetUtils.ip2Long(startIp); ipAddr <= NetUtils.ip2Long(endIp); ipAddr++) {
if(_privateIpAddressDao.countIpAddressUsage(NetUtils.long2Ip(ipAddr), podId, pod.getDataCenterId(), true) > 0) {
throw new CloudRuntimeException("Some IPs of the range has been allocated, so it cannot be deleted.");
}
}
final String[] existingPodIpRanges = pod.getDescription().split(",");
if(existingPodIpRanges.length == 0) {
throw new InvalidParameterValueException("The IP range cannot be found. As the existing IP range is empty.");
}
final String[] newPodIpRanges = new String[existingPodIpRanges.length-1];
int index = existingPodIpRanges.length-2;
boolean foundRange = false;
for(String podIpRange: existingPodIpRanges) {
final String[] existingPodIpRange = podIpRange.split("-");
if(existingPodIpRange.length > 1) {
if (startIp.equals(existingPodIpRange[0]) && endIp.equals(existingPodIpRange[1])) {
foundRange = true;
} else if (index >= 0) {
newPodIpRanges[index--] = (existingPodIpRange[0] + "-" + existingPodIpRange[1]);
}
}
}
if(!foundRange) {
throw new InvalidParameterValueException("The input IP range: " + startIp + "-" + endIp + " of pod: " + podId + "is not present. Please input an existing range.");
}
final StringBuilder newPodIpRange = new StringBuilder();
boolean first = true;
for (String podIpRange : newPodIpRanges) {
if (first)
first = false;
else
newPodIpRange.append(",");
newPodIpRange.append(podIpRange);
}
try {
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(final TransactionStatus status) {
pod.setDescription(newPodIpRange.toString());
HostPodVO lock = null;
try {
lock = _podDao.acquireInLockTable(podId);
if (lock == null) {
String msg = "Unable to acquire lock on table to update the ip range of POD: " + pod.getName() + ", Deletion failed.";
s_logger.warn(msg);
throw new CloudRuntimeException(msg);
}
_podDao.update(podId, pod);
} finally {
if (lock != null) {
_podDao.releaseFromLockTable(podId);
}
}
for(long ipAddr = NetUtils.ip2Long(startIp); ipAddr <= NetUtils.ip2Long(endIp); ipAddr++) {
if (!_privateIpAddressDao.deleteIpAddressByPodDc(NetUtils.long2Ip(ipAddr), podId, pod.getDataCenterId())) {
throw new CloudRuntimeException("Failed to cleanup private ip address: " + NetUtils.long2Ip(ipAddr) + " of Pod: " + podId + " DC: " + pod.getDataCenterId());
}
}
}
});
} catch (final Exception e) {
s_logger.error("Unable to delete Pod " + podId + "IP range due to " + e.getMessage(), e);
throw new CloudRuntimeException("Failed to delete Pod " + podId + "IP range. Please contact Cloud Support.");
}
}
@Override
public Pod editPod(final UpdatePodCmd cmd) {
return editPod(cmd.getId(), cmd.getPodName(), cmd.getStartIp(), cmd.getEndIp(), cmd.getGateway(), cmd.getNetmask(), cmd.getAllocationState());
return editPod(cmd.getId(), cmd.getPodName(), null, null, cmd.getGateway(), cmd.getNetmask(), cmd.getAllocationState());
}
@Override
@ -1106,16 +1343,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
throw new InvalidParameterValueException("Unable to find pod by id " + id);
}
final String[] existingPodIpRange = pod.getDescription().split("-");
String[] leftRangeToAdd = null;
String[] rightRangeToAdd = null;
boolean allowToDownsize = false;
// If the gateway, CIDR, private IP range is being changed, check if the
// pod has allocated private IP addresses
if (podHasAllocatedPrivateIPs(id)) {
if (netmask != null) {
if (!Strings.isNullOrEmpty(netmask)) {
final long newCidr = NetUtils.getCidrSize(netmask);
final long oldCidr = pod.getCidrSize();
@ -1123,31 +1355,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
throw new CloudRuntimeException("The specified pod has allocated private IP addresses, so its IP address range can be extended only");
}
}
if (startIp != null && !startIp.equals(existingPodIpRange[0])) {
if (NetUtils.ipRangesOverlap(startIp, null, existingPodIpRange[0], existingPodIpRange[1])) {
throw new CloudRuntimeException("The specified pod has allocated private IP addresses, so its IP address range can be extended only");
} else {
leftRangeToAdd = new String[2];
final long endIpForUpdate = NetUtils.ip2Long(existingPodIpRange[0]) - 1;
leftRangeToAdd[0] = startIp;
leftRangeToAdd[1] = NetUtils.long2Ip(endIpForUpdate);
}
}
if (endIp != null && !endIp.equals(existingPodIpRange[1])) {
if (NetUtils.ipRangesOverlap(endIp, endIp, existingPodIpRange[0], existingPodIpRange[1])) {
throw new CloudRuntimeException("The specified pod has allocated private IP addresses, so its IP address range can be extended only");
} else {
rightRangeToAdd = new String[2];
final long startIpForUpdate = NetUtils.ip2Long(existingPodIpRange[1]) + 1;
rightRangeToAdd[0] = NetUtils.long2Ip(startIpForUpdate);
rightRangeToAdd[1] = endIp;
}
}
} else {
allowToDownsize = true;
}
if (gateway == null) {
@ -1163,18 +1370,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
name = oldPodName;
}
if (gateway == null) {
gateway = pod.getGateway();
}
if (startIp == null) {
startIp = existingPodIpRange[0];
}
if (endIp == null) {
endIp = existingPodIpRange[1];
}
if (allocationStateStr == null) {
allocationStateStr = pod.getAllocationState().toString();
}
@ -1182,17 +1377,39 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
// Verify pod's attributes
final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask);
final boolean checkForDuplicates = !oldPodName.equals(name);
checkPodAttributes(id, name, pod.getDataCenterId(), gateway, cidr, startIp, endIp, allocationStateStr, checkForDuplicates, false);
checkPodAttributes(id, name, pod.getDataCenterId(), gateway, cidr, startIp, endIp, allocationStateStr, checkForDuplicates, true);
// Valid check is already done in checkPodAttributes method.
final String cidrAddress = getCidrAddress(cidr);
final long cidrSize = getCidrSize(cidr);
// Check if start IP and end IP of all the ranges lie in the CIDR subnet.
final String[] existingPodIpRanges = pod.getDescription().split(",");
for(String podIpRange: existingPodIpRanges) {
final String[] existingPodIpRange = podIpRange.split("-");
if (existingPodIpRange.length > 1) {
if (!NetUtils.isValidIp(existingPodIpRange[0]) || !NetUtils.isValidIp(existingPodIpRange[1])) {
continue;
}
if (!NetUtils.getCidrSubNet(existingPodIpRange[0], cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) {
throw new InvalidParameterValueException("The start address of the some IP range is not in the CIDR subnet.");
}
if (!NetUtils.getCidrSubNet(existingPodIpRange[1], cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) {
throw new InvalidParameterValueException("The end address of the some IP range is not in the CIDR subnet.");
}
if (NetUtils.ipRangesOverlap(existingPodIpRange[0], existingPodIpRange[1], gateway, gateway)) {
throw new InvalidParameterValueException("The gateway shouldn't overlap some start/end ip addresses");
}
}
}
try {
final String[] existingPodIpRangeFinal = existingPodIpRange;
final String[] leftRangeToAddFinal = leftRangeToAdd;
final String[] rightRangeToAddFinal = rightRangeToAdd;
final boolean allowToDownsizeFinal = allowToDownsize;
final String allocationStateStrFinal = allocationStateStr;
final String startIpFinal = startIp;
final String endIpFinal = endIp;
final String nameFinal = name;
final String gatewayFinal = gateway;
Transaction.execute(new TransactionCallbackNoReturn() {
@ -1200,42 +1417,12 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
public void doInTransactionWithoutResult(final TransactionStatus status) {
final long zoneId = pod.getDataCenterId();
String startIp = startIpFinal;
String endIp = endIpFinal;
if (!allowToDownsizeFinal) {
if (leftRangeToAddFinal != null) {
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), leftRangeToAddFinal[0], leftRangeToAddFinal[1]);
}
if (rightRangeToAddFinal != null) {
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), rightRangeToAddFinal[0], rightRangeToAddFinal[1]);
}
} else {
// delete the old range
_zoneDao.deletePrivateIpAddressByPod(pod.getId());
// add the new one
if (startIp == null) {
startIp = existingPodIpRangeFinal[0];
}
if (endIp == null) {
endIp = existingPodIpRangeFinal[1];
}
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIp);
}
pod.setName(nameFinal);
pod.setDataCenterId(zoneId);
pod.setGateway(gatewayFinal);
pod.setCidrAddress(getCidrAddress(cidr));
pod.setCidrSize(getCidrSize(cidr));
final String ipRange = startIp + "-" + endIp;
pod.setDescription(ipRange);
Grouping.AllocationState allocationState = null;
if (allocationStateStrFinal != null && !allocationStateStrFinal.isEmpty()) {
allocationState = Grouping.AllocationState.valueOf(allocationStateStrFinal);
@ -1297,7 +1484,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
// endIp is an optional parameter; if not specified - default it to the
// end ip of the pod's cidr
if (startIp != null) {
if (!Strings.isNullOrEmpty(startIp)) {
if (endIp == null) {
endIp = NetUtils.getIpRangeEndIpFromCidr(cidrAddress, cidrSize);
}
@ -1308,7 +1495,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
// Create the new pod in the database
String ipRange;
if (startIp != null) {
if (!Strings.isNullOrEmpty(startIp)) {
ipRange = startIp + "-" + endIp;
} else {
throw new InvalidParameterValueException("Start ip is required parameter");
@ -1329,7 +1516,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final HostPodVO pod = _podDao.persist(podFinal);
if (startIp != null) {
if (!Strings.isNullOrEmpty(startIp)) {
_zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal);
}
@ -1448,23 +1635,26 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
}
private void checkIpRange(final String startIp, final String endIp, final String cidrAddress, final long cidrSize) {
if (!NetUtils.isValidIp(startIp)) {
//Checking not null for start IP as well. Previously we assumed to be not null always.
//But the check is required for the change in updatePod API.
if (!Strings.isNullOrEmpty(startIp) && !NetUtils.isValidIp(startIp)) {
throw new InvalidParameterValueException("The start address of the IP range is not a valid IP address.");
}
if (endIp != null && !NetUtils.isValidIp(endIp)) {
if (!Strings.isNullOrEmpty(endIp) && !NetUtils.isValidIp(endIp)) {
throw new InvalidParameterValueException("The end address of the IP range is not a valid IP address.");
}
if (!NetUtils.getCidrSubNet(startIp, cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) {
//Not null check is required for the change in updatePod API.
if (!Strings.isNullOrEmpty(startIp) && !NetUtils.getCidrSubNet(startIp, cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) {
throw new InvalidParameterValueException("The start address of the IP range is not in the CIDR subnet.");
}
if (endIp != null && !NetUtils.getCidrSubNet(endIp, cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) {
if (!Strings.isNullOrEmpty(endIp) && !NetUtils.getCidrSubNet(endIp, cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) {
throw new InvalidParameterValueException("The end address of the IP range is not in the CIDR subnet.");
}
if (endIp != null && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(endIp)) {
if (!Strings.isNullOrEmpty(endIp) && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(endIp)) {
throw new InvalidParameterValueException("The start IP address must have a lower value than the end IP address.");
}
@ -1487,15 +1677,20 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
final List<HostPodVO> podsInZone = _podDao.listByDataCenterId(zoneId);
for (final HostPodVO hostPod : podsInZone) {
final String[] IpRange = hostPod.getDescription().split("-");
if (IpRange[0] == null || IpRange[1] == null) {
continue;
}
if (!NetUtils.isValidIp(IpRange[0]) || !NetUtils.isValidIp(IpRange[1])) {
continue;
}
if (NetUtils.ipRangesOverlap(startIp, endIp, IpRange[0], IpRange[1])) {
throw new InvalidParameterValueException("The Start IP and endIP address range overlap with private IP :" + IpRange[0] + ":" + IpRange[1]);
final String[] existingPodIpRanges = hostPod.getDescription().split(",");
for(String podIpRange: existingPodIpRanges) {
final String[] existingPodIpRange = podIpRange.split("-");
if (existingPodIpRange.length > 1) {
if (!NetUtils.isValidIp(existingPodIpRange[0]) || !NetUtils.isValidIp(existingPodIpRange[1])) {
continue;
}
if (NetUtils.ipRangesOverlap(startIp, endIp, existingPodIpRange[0], existingPodIpRange[1])) {
throw new InvalidParameterValueException("The Start IP and EndIP address range overlap with private IP :" + existingPodIpRange[0] + ":" + existingPodIpRange[1]);
}
}
}
}
}

View File

@ -77,12 +77,21 @@ public class StorageNetworkManagerImpl extends ManagerBase implements StorageNet
if (pod == null) {
throw new CloudRuntimeException("Cannot find pod " + podId);
}
String[] IpRange = pod.getDescription().split("-");
if ((IpRange[0] == null || IpRange[1] == null) || (!NetUtils.isValidIp(IpRange[0]) || !NetUtils.isValidIp(IpRange[1]))) {
return;
}
if (NetUtils.ipRangesOverlap(startIp, endIp, IpRange[0], IpRange[1])) {
throw new InvalidParameterValueException("The Storage network Start IP and endIP address range overlap with private IP :" + IpRange[0] + ":" + IpRange[1]);
final String[] existingPodIpRanges = pod.getDescription().split(",");
for(String podIpRange: existingPodIpRanges) {
final String[] existingPodIpRange = podIpRange.split("-");
if (existingPodIpRange.length > 1) {
if (!NetUtils.isValidIp(existingPodIpRange[0]) || !NetUtils.isValidIp(existingPodIpRange[1])) {
continue;
}
if (NetUtils.ipRangesOverlap(startIp, endIp, existingPodIpRange[0], existingPodIpRange[1])) {
throw new InvalidParameterValueException("The Storage network Start IP and endIP address range overlap with private IP :" + existingPodIpRange[0] + ":" + existingPodIpRange[1]);
}
}
}
}

View File

@ -105,11 +105,13 @@ import org.apache.cloudstack.api.command.admin.iso.RegisterIsoCmdByAdmin;
import org.apache.cloudstack.api.command.admin.loadbalancer.ListLoadBalancerRuleInstancesCmdByAdmin;
import org.apache.cloudstack.api.command.admin.network.AddNetworkDeviceCmd;
import org.apache.cloudstack.api.command.admin.network.AddNetworkServiceProviderCmd;
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkCmdByAdmin;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.CreatePhysicalNetworkCmd;
import org.apache.cloudstack.api.command.admin.network.CreateStorageNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.DedicateGuestVlanRangeCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkDeviceCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkServiceProviderCmd;
@ -3010,6 +3012,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(UpdateLBHealthCheckPolicyCmd.class);
cmdList.add(GetUploadParamsForTemplateCmd.class);
cmdList.add(GetUploadParamsForVolumeCmd.class);
cmdList.add(AcquirePodIpCmdByAdmin.class);
cmdList.add(ReleasePodIpCmdByAdmin.class);
cmdList.add(CreateManagementNetworkIpRangeCmd.class);
cmdList.add(DeleteManagementNetworkIpRangeCmd.class);
// Out-of-band management APIs for admins
cmdList.add(EnableOutOfBandManagementForHostCmd.class);
cmdList.add(DisableOutOfBandManagementForHostCmd.class);
@ -3022,9 +3029,6 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(ChangeOutOfBandManagementPasswordCmd.class);
cmdList.add(GetUserKeysCmd.class);
cmdList.add(AcquirePodIpCmdByAdmin.class);
cmdList.add(ReleasePodIpCmdByAdmin.class);
return cmdList;
}

View File

@ -24,7 +24,9 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
@ -159,6 +161,24 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu
return null;
}
/* (non-Javadoc)
* @see com.cloud.configuration.ConfigurationService#createPodIpRange(org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd)
*/
@Override
public Pod createPodIpRange(CreateManagementNetworkIpRangeCmd cmd) {
// TODO Auto-generated method stub
return null;
}
/* (non-Javadoc)
* @see com.cloud.configuration.ConfigurationService#deletePodIpRange(org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd)
*/
@Override
public void deletePodIpRange(DeleteManagementNetworkIpRangeCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException {
// TODO Auto-generated method stub
return;
}
/* (non-Javadoc)
* @see com.cloud.configuration.ConfigurationService#editPod(org.apache.cloudstack.api.commands.UpdatePodCmd)
*/

View File

@ -343,6 +343,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
"label.add.ldap.account":"Add LDAP account",
"label.add.list.name":"ACL List Name",
"label.add.load.balancer":"Add Load Balancer",
"label.add.management.ip.range":"Add Management IP Range",
"label.add.more":"Add More",
"label.add.netScaler.device":"Add Netscaler device",
"label.add.network":"Add Network",
@ -1401,6 +1402,7 @@ var dictionary = {"ICMP.code":"ICMP Code",
"label.remove.ingress.rule":"Remove ingress rule",
"label.remove.ip.range":"Remove IP range",
"label.remove.ldap":"Remove LDAP",
"label.remove.management.ip.range":"Remove Management IP Range",
"label.remove.network.offering":"Remove network offering",
"label.remove.pf":"Remove port forwarding rule",
"label.remove.project.account":"Remove account from project",

View File

@ -936,56 +936,154 @@
});
}
},
ipAddresses: {
//read-only listView (no actions) filled with pod info (not VlanIpRange info)
title: 'label.ip.ranges',
listView: {
fields: {
name: {
label: 'label.pod'
},
//pod name
gateway: {
label: 'label.gateway'
},
//'Reserved system gateway' is too long and causes a visual format bug (2 lines overlay)
netmask: {
label: 'label.netmask'
},
//'Reserved system netmask' is too long and causes a visual format bug (2 lines overlay)
startip: {
label: 'label.start.IP'
},
//'Reserved system start IP' is too long and causes a visual format bug (2 lines overlay)
endip: {
label: 'label.end.IP'
}
//'Reserved system end IP' is too long and causes a visual format bug (2 lines overlay)
},
dataProvider: function (args) {
var array1 =[];
if (args.filterBy != null) {
if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) {
switch (args.filterBy.search.by) {
case "name":
if (args.filterBy.search.value.length > 0)
array1.push("&keyword=" + args.filterBy.search.value);
break;
custom: function (args) {
return $('<div></div>').multiEdit({
context: args.context,
noSelect: true,
fields: {
'podid': {
label: 'label.pod',
select: function (args) {
$.ajax({
url: createURL("listPods&zoneid=" + selectedZoneObj.id),
dataType: "json",
success: function (json) {
var items =[];
var pods = json.listpodsresponse.pod;
$(pods).each(function () {
items.push({
name: this.id,
description: this.name
});
});
args.response.success({
data: items
});
}
});
}
},
'gateway': {
edit: true,
label: 'label.gateway'
},
'netmask': {
edit: true,
label: 'label.netmask'
},
'startip': {
edit: true,
label: 'label.start.IP'
},
'endip': {
edit: true,
label: 'label.end.IP',
validation: {
required: false
}
},
'add-rule': {
label: 'label.add',
addButton: true
}
}
$.ajax({
url: createURL("listPods&zoneid=" + selectedZoneObj.id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("")),
dataType: "json",
async: true,
success: function (json) {
var items = json.listpodsresponse.pod;
args.response.success({
data: items
},
add: {
label: 'label.add',
action: function (args) {
var array1 =[];
array1.push("&podid=" + args.data.podid);
array1.push("&gateway=" + args.data.gateway);
array1.push("&netmask=" + args.data.netmask);
array1.push("&startip=" + args.data.startip);
if (args.data.endip != null && args.data.endip.length > 0)
array1.push("&endip=" + args.data.endip);
$.ajax({
url: createURL("createManagementNetworkIpRange" + array1.join("")),
dataType: "json",
success: function (json) {
args.response.success({
_custom: {
jobId: json.createmanagementnetworkiprangeresponse.jobid
},
notification: {
label: 'label.add.management.ip.range',
poll: pollAsyncJobResult
}
});
},
error: function (XMLHttpResponse) {
var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
args.response.error(errorMsg);
}
});
}
});
}
},
actions: {
destroy: {
label: 'label.delete',
action: function (args) {
var array1 =[];
array1.push("&podid=" + args.context.multiRule[0].podid);
array1.push("&startip=" + args.context.multiRule[0].startip);
array1.push("&endip=" + args.context.multiRule[0].endip);
$.ajax({
url: createURL('deleteManagementNetworkIpRange' + array1.join("")),
dataType: 'json',
async: true,
success: function (json) {
args.response.success({
_custom: {
jobId: json.deletemanagementnetworkiprangeresponse.jobid
},
notification: {
label: 'label.remove.management.ip.range',
poll: pollAsyncJobResult
}
});
},
error: function (XMLHttpResponse) {
var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
args.response.error(errorMsg);
}
});
}
}
},
dataProvider: function (args) {
$.ajax({
url: createURL("listPods&zoneid=" + selectedZoneObj.id),
dataType: "json",
async: true,
success: function (json) {
var items =[];
var pods = json.listpodsresponse.pod;
$(pods).each(function () {
for (var i = 0; i < this.startip.length; i++) {
items.push({
podid: this.id,
gateway: this.gateway,
netmask: this.netmask,
startip: this.startip[i],
endip: this.endip[i]
});
}
});
args.response.success({
data: items
});
}
});
}
});
}
}
}
@ -13465,11 +13563,10 @@
label: 'label.edit',
action: function (args) {
var array1 =[];
array1.push("&name=" + todb(args.data.name));
array1.push("&netmask=" + todb(args.data.netmask));
array1.push("&startIp=" + todb(args.data.startip));
if (args.data.endip != null && args.data.endip.length > 0)
array1.push("&endIp=" + todb(args.data.endip));
if (args.data.gateway != null && args.data.gateway.length > 0)
array1.push("&gateway=" + todb(args.data.gateway));
@ -13730,17 +13827,6 @@
required: true
}
},
startip: {
label: 'label.start.IP',
isEditable: true,
validation: {
required: true
}
},
endip: {
label: 'label.end.IP',
isEditable: true
},
gateway: {
label: 'label.gateway',
isEditable: true,
@ -13756,7 +13842,6 @@
label: 'label.allocation.state'
}
}, {
isdedicated: {
label: 'label.dedicated'
},
@ -13766,13 +13851,10 @@
}],
dataProvider: function (args) {
$.ajax({
url: createURL("listPods&id=" + args.context.pods[0].id),
success: function (json) {
var item = json.listpodsresponse.pod[0];
$.ajax({
url: createURL("listDedicatedPods&podid=" + args.context.pods[0].id),
success: function (json) {