Bug 12777 - Add storage network configuration into CloudStack

create APIs
This commit is contained in:
frank 2011-12-30 17:48:54 -08:00
parent aa8bf6c135
commit 0b01c5dc1a
22 changed files with 1259 additions and 2 deletions

View File

@ -39,6 +39,7 @@ import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.NetworkService;
import com.cloud.network.StorageNetworkService;
import com.cloud.network.VirtualNetworkApplianceService;
import com.cloud.network.firewall.FirewallService;
import com.cloud.network.lb.LoadBalancingRulesService;
@ -126,6 +127,7 @@ public abstract class BaseCmd {
public static DomainService _domainService;
public static ResourceLimitService _resourceLimitService;
public static IdentityService _identityService;
public static StorageNetworkService _storageNetworkService;
static void setComponents(ResponseGenerator generator) {
ComponentLocator locator = ComponentLocator.getLocator(ManagementService.Name);
@ -152,6 +154,7 @@ public abstract class BaseCmd {
_domainService = locator.getManager(DomainService.class);
_resourceLimitService = locator.getManager(ResourceLimitService.class);
_identityService = locator.getManager(IdentityService.class);
_storageNetworkService = locator.getManager(StorageNetworkService.class);
}
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException;

View File

@ -64,6 +64,7 @@ import com.cloud.api.response.ServiceOfferingResponse;
import com.cloud.api.response.ServiceResponse;
import com.cloud.api.response.SnapshotPolicyResponse;
import com.cloud.api.response.SnapshotResponse;
import com.cloud.api.response.StorageNetworkIpRangeResponse;
import com.cloud.api.response.StoragePoolResponse;
import com.cloud.api.response.SwiftResponse;
import com.cloud.api.response.SystemVmInstanceResponse;
@ -85,6 +86,7 @@ import com.cloud.configuration.ResourceCount;
import com.cloud.configuration.ResourceLimit;
import com.cloud.dc.DataCenter;
import com.cloud.dc.Pod;
import com.cloud.dc.StorageNetworkIpRange;
import com.cloud.dc.Vlan;
import com.cloud.domain.Domain;
import com.cloud.event.Event;
@ -271,4 +273,5 @@ public interface ResponseGenerator {
LDAPConfigResponse createLDAPConfigResponse(String hostname, Integer port, Boolean useSSL, String queryFilter, String baseSearch, String dn);
StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result);
}

View File

@ -0,0 +1,121 @@
package com.cloud.api.commands;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseAsyncCmd;
import com.cloud.api.BaseCmd;
import com.cloud.api.IdentityMapper;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.BaseCmd.CommandType;
import com.cloud.api.response.StorageNetworkIpRangeResponse;
import com.cloud.dc.StorageNetworkIpRange;
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;
@Implementation(description="Creates a VLAN IP range.", responseObject=StorageNetworkIpRangeResponse.class)
public class CreateStorageNetworkIpRangeCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(CreateStorageNetworkIpRangeCmd.class);
private static final String s_name = "createstoragenetworkiprangeresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@IdentityMapper(entityTableName="host_pod_ref")
@Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, description="optional parameter. Have to be specified for Direct Untagged vlan only.")
private Long podId;
@Parameter(name=ApiConstants.START_IP, type=CommandType.STRING, required=true, description="the beginning IP address in the VLAN IP range")
private String startIp;
@Parameter(name=ApiConstants.END_IP, type=CommandType.STRING, description="the ending IP address in the VLAN IP range")
private String endIp;
@Parameter(name=ApiConstants.VLAN, type=CommandType.INTEGER, description="the ID or VID of the VLAN. Optional, null means no vlan")
private Integer vlan;
@IdentityMapper(entityTableName="data_center")
@Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="the Zone ID of the VLAN IP range")
private Long zoneId;
@IdentityMapper(entityTableName="networks")
@Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.LONG, description="the network id")
private Long networkID;
@Parameter(name=ApiConstants.NETMASK, type=CommandType.STRING, required=true, description="the netmask for the Pod")
private String netmask;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getEndIp() {
return endIp;
}
public Long getPodId() {
return podId;
}
public String getStartIp() {
return startIp;
}
public Integer getVlan() {
return vlan;
}
public Long getZoneId() {
return zoneId;
}
public Long getNetworkID() {
return networkID;
}
public String getNetmask() {
return netmask;
}
@Override
public String getEventType() {
return EventTypes.EVENT_STORAGE_IP_RANGE_CREATE;
}
@Override
public String getEventDescription() {
return "Creating storage ip range from " + getStartIp() + " to " + getEndIp() + " with vlan " + getVlan();
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException {
try {
StorageNetworkIpRange result = _storageNetworkService.createIpRange(this);
StorageNetworkIpRangeResponse response = _responseGenerator.createStorageNetworkIpRangeResponse(result);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} catch (Exception e) {
s_logger.warn("Create storage network IP range failed", e);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

0
api/src/com/cloud/api/commands/DeleteClusterCmd.java Normal file → Executable file
View File

View File

@ -0,0 +1,76 @@
package com.cloud.api.commands;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseAsyncCmd;
import com.cloud.api.BaseCmd;
import com.cloud.api.IdentityMapper;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.BaseCmd.CommandType;
import com.cloud.api.response.SuccessResponse;
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;
@Implementation(description="Deletes a storage network IP Range.", responseObject=SuccessResponse.class)
public class DeleteStorageNetworkIpRangeCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(DeleteStorageNetworkIpRangeCmd.class);
private static final String s_name = "deletestoragenetworkiprangeresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@IdentityMapper(entityTableName="dc_storage_network_ip_range")
@Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="the storage network IP range ID")
private Long id;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getId() {
return id;
}
@Override
public String getEventType() {
return EventTypes.EVENT_STORAGE_IP_RANGE_DELETE;
}
@Override
public String getEventDescription() {
return "Deleting storage ip range " + getId();
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException {
try {
_storageNetworkService.deleteIpRange(this);
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} catch (Exception e) {
s_logger.warn("Failed to delete storage network ip range " + getId(), e);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,104 @@
package com.cloud.api.commands;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseAsyncCmd;
import com.cloud.api.BaseCmd;
import com.cloud.api.IdentityMapper;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.BaseCmd.CommandType;
import com.cloud.api.response.ListResponse;
import com.cloud.api.response.StorageNetworkIpRangeResponse;
import com.cloud.dc.StorageNetworkIpRange;
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;
@Implementation(description="List a storage network IP range.", responseObject=StorageNetworkIpRangeResponse.class)
public class listStorageNetworkIpRangeCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(listStorageNetworkIpRangeCmd.class);
String s_name = "liststoragenetworkiprangeresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@IdentityMapper(entityTableName="dc_storage_network_ip_range")
@Parameter(name=ApiConstants.ID, type=CommandType.LONG, description="optional parameter. Storaget network IP range id, if specicied, using it to search the range.")
private Long rangeId;
@IdentityMapper(entityTableName="host_pod_ref")
@Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, description="optional parameter. Pod id, if specicied and range id is absent, using it to search the range.")
private Long podId;
@IdentityMapper(entityTableName="data_center")
@Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="optional parameter. Zone id, if specicied and both pod id and range id are absent, using it to search the range.")
private Long zoneId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getRangeId() {
return rangeId;
}
public Long getPodId() {
return podId;
}
public Long getZoneId() {
return zoneId;
}
@Override
public String getEventType() {
return EventTypes.EVENT_STORAGE_IP_RANGE_LIST;
}
@Override
public String getEventDescription() {
return "List storage network IP range";
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
ResourceAllocationException {
try {
List<StorageNetworkIpRange> results = _storageNetworkService.listIpRange(this);
ListResponse<StorageNetworkIpRangeResponse> response = new ListResponse<StorageNetworkIpRangeResponse>();
List<StorageNetworkIpRangeResponse> resList = new ArrayList<StorageNetworkIpRangeResponse>(results.size());
for (StorageNetworkIpRange r : results) {
StorageNetworkIpRangeResponse resp = _responseGenerator.createStorageNetworkIpRangeResponse(r);
resList.add(resp);
}
response.setResponses(resList);
response.setObjectName(getCommandName());
this.setResponseObject(response);
} catch (Exception e) {
s_logger.warn("Failed to list storage network ip range for rangeId=" + getRangeId() + " podId=" + getPodId() + " zoneId=" + getZoneId());
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
}

View File

@ -0,0 +1,57 @@
package com.cloud.api.response;
import com.cloud.api.ApiConstants;
import com.cloud.api.IdentityProxy;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
public class StorageNetworkIpRangeResponse extends BaseResponse {
@SerializedName(ApiConstants.VLAN) @Param(description="the ID of storage network IP range.")
private Long id;
@SerializedName(ApiConstants.VLAN) @Param(description="the ID or VID of the VLAN.")
private Integer vlan;
@SerializedName(ApiConstants.POD_ID) @Param(description="the Pod ID for the VLAN IP range")
private IdentityProxy podId = new IdentityProxy("host_pod_ref");
@SerializedName(ApiConstants.START_IP) @Param(description="the start ip of the VLAN IP range")
private String startIp;
@SerializedName(ApiConstants.END_IP) @Param(description="the end ip of the VLAN IP range")
private String endIp;
@SerializedName(ApiConstants.NETWORK_ID) @Param(description="the network id of vlan range")
private IdentityProxy networkId = new IdentityProxy("networks");
@SerializedName(ApiConstants.ZONE_ID) @Param(description="the Zone ID of the VLAN IP range")
private IdentityProxy zoneId = new IdentityProxy("data_center");
public void setId(Long id) {
this.id = id;
}
public void setZoneId(Long zoneId) {
this.zoneId.setValue(zoneId);
}
public void setVlan(Integer vlan) {
this.vlan = vlan;
}
public void setPodId(Long podId) {
this.podId.setValue(podId);
}
public void setStartIp(String startIp) {
this.startIp = startIp;
}
public void setEndIp(String endIp) {
this.endIp = endIp;
}
public void setNetworkId(Long networkId) {
this.networkId.setValue(networkId);
}
}

View File

@ -0,0 +1,17 @@
package com.cloud.dc;
public interface StorageNetworkIpRange {
long getId();
int getVlan();
long getPodId();
String getStartIp();
String getEndIp();
long getNetworkId();
long getDataCenterId();
}

View File

@ -169,6 +169,10 @@ public class EventTypes {
// VLANs/IP ranges
public static final String EVENT_VLAN_IP_RANGE_CREATE = "VLAN.IP.RANGE.CREATE";
public static final String EVENT_VLAN_IP_RANGE_DELETE = "VLAN.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_LIST = "STORAGE.IP.RANGE.LIST";
// Configuration Table
public static final String EVENT_CONFIGURATION_VALUE_EDIT = "CONFIGURATION.VALUE.EDIT";

View File

@ -0,0 +1,17 @@
package com.cloud.network;
import java.sql.SQLException;
import java.util.List;
import com.cloud.api.commands.CreateStorageNetworkIpRangeCmd;
import com.cloud.api.commands.DeleteStorageNetworkIpRangeCmd;
import com.cloud.api.commands.listStorageNetworkIpRangeCmd;
import com.cloud.dc.StorageNetworkIpRange;
public interface StorageNetworkService {
StorageNetworkIpRange createIpRange(CreateStorageNetworkIpRangeCmd cmd) throws SQLException;
void deleteIpRange(DeleteStorageNetworkIpRangeCmd cmd);
List<StorageNetworkIpRange> listIpRange(listStorageNetworkIpRangeCmd cmd);
}

View File

@ -83,6 +83,7 @@ import com.cloud.api.response.ServiceOfferingResponse;
import com.cloud.api.response.ServiceResponse;
import com.cloud.api.response.SnapshotPolicyResponse;
import com.cloud.api.response.SnapshotResponse;
import com.cloud.api.response.StorageNetworkIpRangeResponse;
import com.cloud.api.response.StoragePoolResponse;
import com.cloud.api.response.SwiftResponse;
import com.cloud.api.response.SystemVmInstanceResponse;
@ -111,6 +112,7 @@ import com.cloud.dc.DataCenter;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.Pod;
import com.cloud.dc.StorageNetworkIpRange;
import com.cloud.dc.Vlan;
import com.cloud.dc.Vlan.VlanType;
import com.cloud.dc.VlanVO;
@ -3236,5 +3238,16 @@ public class ApiResponseHelper implements ResponseGenerator {
return lr;
}
@Override
public StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result) {
StorageNetworkIpRangeResponse response = new StorageNetworkIpRangeResponse();
response.setId(result.getId());
response.setVlan(result.getVlan());
response.setEndIp(result.getEndIp());
response.setStartIp(result.getStartIp());
response.setPodId(result.getPodId());
response.setZoneId(result.getDataCenterId());
response.setNetworkId(result.getNetworkId());
return response;
}
}

View File

@ -0,0 +1,86 @@
package com.cloud.dc;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import com.cloud.network.IpAddress.State;
@Entity
@Table(name="op_dc_storage_network_ip_address")
public class StorageNetworkIpAddressVO {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
long id;
@Column(name = "range_id")
long rangeId;
@Column(name = "cidr_size")
int cidrSize;
@Column(name = "ip_address", updatable = false, nullable = false)
String ipAddress;
@Column(name = "taken")
@Temporal(value = TemporalType.TIMESTAMP)
private Date takenAt;
@Column(name = "mac_address")
long mac;
protected StorageNetworkIpAddressVO() {
}
public Long getId() {
return id;
}
public void setTakenAt(Date takenDate) {
this.takenAt = takenDate;
}
public String getIpAddress() {
return ipAddress;
}
public void setIpAddress(String ip) {
this.ipAddress = ip;
}
public Date getTakenAt() {
return takenAt;
}
public long getRangeId() {
return rangeId;
}
public void setRangeId(long id) {
this.rangeId = id;
}
public long getMac() {
return mac;
}
public void setMac(long mac) {
this.mac = mac;
}
public int getCidrSize() {
return cidrSize;
}
public void setCidrSize(int cidr) {
this.cidrSize =cidr;
}
}

View File

@ -0,0 +1,100 @@
package com.cloud.dc;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="dc_storage_network_ip_range")
public class StorageNetworkIpRangeVO implements StorageNetworkIpRange {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "vlan")
private int vlan;
@Column(name = "data_center_id")
private long dataCenterId;
@Column(name = "pod_id")
private long podId;
@Column(name = "start_ip")
private String startIp;
@Column(name = "end_ip")
private String endIp;
@Column(name = "network_id")
private long networkId;
public StorageNetworkIpRangeVO(long dcId, long podId, long networkId, String startIp, String endIp, int vlan) {
this.dataCenterId = dcId;
this.podId = podId;
this.networkId = networkId;
this.startIp = startIp;
this.endIp = endIp;
this.vlan = vlan;
}
protected StorageNetworkIpRangeVO() {
}
public long getId() {
return id;
}
public long getDataCenterId() {
return dataCenterId;
}
public void setDataCenterId(long dcId) {
this.dataCenterId = dcId;
}
public long getPodId() {
return podId;
}
public void setPodId(long podId) {
this.podId = podId;
}
public long getNetworkId() {
return networkId;
}
public void setNetworkId(long nwId) {
this.networkId = nwId;
}
public int getVlan() {
return vlan;
}
public void setVlan(int vlan) {
this.vlan = vlan;
}
public void setStartIp(String start) {
this.startIp = start;
}
public String getStartIp() {
return startIp;
}
public void setEndIp(String end) {
this.endIp = end;
}
public String getEndIp() {
return endIp;
}
}

View File

@ -0,0 +1,16 @@
package com.cloud.dc.dao;
import java.util.List;
import com.cloud.dc.StorageNetworkIpAddressVO;
import com.cloud.utils.db.GenericDao;
public interface StorageNetworkIpAddressDao extends GenericDao<StorageNetworkIpAddressVO, Long> {
long countInUseIpByRangeId(long rangeId);
List<String> listInUseIpByRangeId(long rangeId);
StorageNetworkIpAddressVO takeIpAddress(long rangeId);
void releaseIpAddress(String ip);
}

View File

@ -0,0 +1,95 @@
package com.cloud.dc.dao;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import com.cloud.dc.DataCenterIpAddressVO;
import com.cloud.dc.StorageNetworkIpAddressVO;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria2;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op;
@Local(value={StorageNetworkIpAddressDao.class})
@DB(txn=false)
public class StorageNetworkIpAddressDaoImpl extends GenericDaoBase<StorageNetworkIpAddressVO, Long> implements StorageNetworkIpAddressDao {
protected final GenericSearchBuilder<StorageNetworkIpAddressVO, Long> countInUserIp;
protected final GenericSearchBuilder<StorageNetworkIpAddressVO, String> listInUseIp;
protected final SearchBuilder<StorageNetworkIpAddressVO> untakenIp;
protected final SearchBuilder<StorageNetworkIpAddressVO> ipSearch;
protected StorageNetworkIpAddressDaoImpl() {
countInUserIp = createSearchBuilder(Long.class);
countInUserIp.select(null, Func.COUNT, null);
countInUserIp.and("rangeId", countInUserIp.entity().getRangeId(), Op.EQ);
countInUserIp.and("taken", countInUserIp.entity().getTakenAt(), Op.NULL);
countInUserIp.done();
listInUseIp = createSearchBuilder(String.class);
listInUseIp.selectField(listInUseIp.entity().getIpAddress());
listInUseIp.and("rangeId", listInUseIp.entity().getRangeId(), Op.EQ);
listInUseIp.and("taken", listInUseIp.entity().getTakenAt(), Op.NULL);
listInUseIp.done();
untakenIp = createSearchBuilder();
untakenIp.and("rangeId", untakenIp.entity().getRangeId(), Op.EQ);
untakenIp.and("taken", untakenIp.entity().getTakenAt(), Op.NULL);
untakenIp.done();
ipSearch = createSearchBuilder();
ipSearch.and("ipAddress", ipSearch.entity().getIpAddress(), Op.EQ);
ipSearch.done();
}
@Override
public long countInUseIpByRangeId(long rangeId) {
SearchCriteria<Long> sc = countInUserIp.create();
sc.setParameters("rangeId", rangeId);
return customSearch(sc, null).get(0);
}
@Override
public List<String> listInUseIpByRangeId(long rangeId) {
SearchCriteria<String> sc = listInUseIp.create();
sc.setParameters("rangeId", rangeId);
return customSearch(sc, null);
}
@Override
@DB
public StorageNetworkIpAddressVO takeIpAddress(long rangeId) {
SearchCriteria<StorageNetworkIpAddressVO> sc = untakenIp.create();
sc.setParameters("rangeId", rangeId);
Transaction txn = Transaction.currentTxn();
txn.start();
StorageNetworkIpAddressVO ip = lockOneRandomRow(sc, true);
if (ip == null) {
txn.rollback();
return null;
}
ip.setTakenAt(new Date());
update(ip.getId(), ip);
txn.commit();
return ip;
}
@Override
public void releaseIpAddress(String ip) {
SearchCriteria<StorageNetworkIpAddressVO> sc = ipSearch.create();
sc.setParameters("ipAddress", ip);
StorageNetworkIpAddressVO vo = createForUpdate();
vo.setTakenAt(null);
update(vo, sc);
}
}

View File

@ -0,0 +1,14 @@
package com.cloud.dc.dao;
import java.util.List;
import com.cloud.dc.StorageNetworkIpRangeVO;
import com.cloud.utils.db.GenericDao;
public interface StorageNetworkIpRangeDao extends GenericDao<StorageNetworkIpRangeVO, Long> {
List<StorageNetworkIpRangeVO> listByRangeId(long rangeId);
List<StorageNetworkIpRangeVO> listByPodId(long podId);
List<StorageNetworkIpRangeVO> listByDataCenterId(long dcId);
}

View File

@ -0,0 +1,41 @@
package com.cloud.dc.dao;
import java.util.List;
import java.util.Map;
import javax.naming.ConfigurationException;
import com.cloud.dc.StorageNetworkIpRangeVO;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria2;
import com.cloud.utils.db.SearchCriteriaService;
import com.cloud.utils.db.SearchCriteria.Op;
public class StorageNetworkIpRangeDaoImpl extends GenericDaoBase<StorageNetworkIpRangeVO, Long> implements StorageNetworkIpRangeDao {
@Override
public List<StorageNetworkIpRangeVO> listByPodId(long podId) {
SearchCriteriaService<StorageNetworkIpRangeVO, StorageNetworkIpRangeVO> sc = SearchCriteria2.create(StorageNetworkIpRangeVO.class);
sc.addAnd(sc.getEntity().getPodId(), Op.EQ, podId);
return sc.list();
}
@Override
public List<StorageNetworkIpRangeVO> listByRangeId(long rangeId) {
SearchCriteriaService<StorageNetworkIpRangeVO, StorageNetworkIpRangeVO> sc = SearchCriteria2.create(StorageNetworkIpRangeVO.class);
sc.addAnd(sc.getEntity().getId(), Op.EQ, rangeId);
return sc.list();
}
@Override
public List<StorageNetworkIpRangeVO> listByDataCenterId(long dcId) {
SearchCriteriaService<StorageNetworkIpRangeVO, StorageNetworkIpRangeVO> sc = SearchCriteria2.create(StorageNetworkIpRangeVO.class);
sc.addAnd(sc.getEntity().getDataCenterId(), Op.EQ, dcId);
return sc.list();
}
}

View File

@ -0,0 +1,12 @@
package com.cloud.network;
import com.cloud.dc.StorageNetworkIpAddressVO;
import com.cloud.utils.component.Manager;
public interface StorageNetworkManager extends Manager {
StorageNetworkIpAddressVO acquireIpAddress(long podId);
void releaseIpAddress(String ip);
boolean isAStorageIpAddress(String ip);
}

View File

@ -0,0 +1,278 @@
package com.cloud.network;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.log4j.Logger;
import com.cloud.api.commands.CreateStorageNetworkIpRangeCmd;
import com.cloud.api.commands.DeleteStorageNetworkIpRangeCmd;
import com.cloud.api.commands.listStorageNetworkIpRangeCmd;
import com.cloud.dc.HostPodVO;
import com.cloud.dc.StorageNetworkIpRange;
import com.cloud.dc.StorageNetworkIpAddressVO;
import com.cloud.dc.StorageNetworkIpRangeVO;
import com.cloud.dc.dao.HostPodDao;
import com.cloud.dc.dao.StorageNetworkIpAddressDao;
import com.cloud.dc.dao.StorageNetworkIpRangeDao;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.dao.NetworkDao;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Inject;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.SearchCriteria2;
import com.cloud.utils.db.SearchCriteriaService;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
@Local(value = {StorageNetworkManager.class, StorageNetworkService.class})
public class StorageNetworkManagerImpl implements StorageNetworkManager, StorageNetworkService {
private static final Logger s_logger = Logger.getLogger(StorageNetworkManagerImpl.class);
String _name;
@Inject
StorageNetworkIpAddressDao _sNwIpDao;
@Inject
StorageNetworkIpRangeDao _sNwIpRangeDao;
@Inject
NetworkDao _networkDao;
@Inject
HostPodDao _podDao;
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
_name = name;
return true;
}
@Override
public boolean start() {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean stop() {
// TODO Auto-generated method stub
return true;
}
@Override
public String getName() {
// TODO Auto-generated method stub
return null;
}
private void checkOverlapPrivateIpRange(long podId, String startIp, String endIp) {
HostPodVO pod = _podDao.findById(podId);
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]);
}
}
private void checkOverlapStorageIpRange(long podId, String startIp, String endIp) {
List<StorageNetworkIpRangeVO> curRanges = _sNwIpRangeDao.listByPodId(podId);
for (StorageNetworkIpRangeVO range : curRanges) {
if (NetUtils.ipRangesOverlap(startIp, endIp, range.getStartIp(), range.getEndIp())) {
throw new InvalidParameterValueException("The Storage network Start IP and endIP address range overlap with private IP :" + range.getStartIp() + ":" + range.getEndIp());
}
}
}
private void createStorageIpEntires(Transaction txn, long rangeId, String startIp, String endIp, String netmask, long zoneId) throws SQLException {
long startIPLong = NetUtils.ip2Long(startIp);
long endIPLong = NetUtils.ip2Long(endIp);
String cidr = NetUtils.ipAndNetMaskToCidr(startIp, netmask);
String[] cidrPair = cidr.split("\\/");
int cidrSize = Integer.parseInt(cidrPair[1]);
String insertSql = "INSERT INTO `cloud`.`op_dc_storage_network_ip_address` (range_id, ip_address, mac_address, cidr_size, taken) VALUES (?, ?, (select mac_address from `cloud`.`data_center` where id=?), ?, ?)";
String updateSql = "UPDATE `cloud`.`data_center` set mac_address = mac_address+1 where id=?";
PreparedStatement stmt = null;
Connection conn = txn.getConnection();
while (startIPLong <= endIPLong) {
stmt = conn.prepareStatement(insertSql);
stmt.setLong(1, rangeId);
stmt.setString(2, NetUtils.long2Ip(startIPLong++));
stmt.setLong(3, zoneId);
stmt.setInt(4, cidrSize);
stmt.setNull(5, java.sql.Types.DATE);
stmt.executeUpdate();
stmt.close();
stmt = txn.prepareStatement(updateSql);
stmt.setLong(1, zoneId);
stmt.executeUpdate();
stmt.close();
}
}
@Override
@DB
public StorageNetworkIpRange createIpRange(CreateStorageNetworkIpRangeCmd cmd) throws SQLException {
Long zoneId = cmd.getZoneId();
Long podId = cmd.getPodId();
String startIp = cmd.getStartIp();
String endIp = cmd.getEndIp();
Integer vlan = cmd.getVlan();
String netmask = cmd.getNetmask();
if (endIp == null) {
endIp = startIp;
}
List<NetworkVO> nws = _networkDao.listByZoneAndTrafficType(zoneId, TrafficType.Storage);
if (nws.size() == 0) {
throw new CloudRuntimeException("Cannot find storage network in zone " + zoneId);
}
if (nws.size() > 1) {
throw new CloudRuntimeException("Find more than one storage network in zone " + zoneId + "," + nws.size() + " found");
}
NetworkVO nw = nws.get(0);
checkOverlapPrivateIpRange(podId, startIp, endIp);
checkOverlapStorageIpRange(podId, startIp, endIp);
Transaction txn = Transaction.currentTxn();
StorageNetworkIpRangeVO range = null;
txn.start();
range = new StorageNetworkIpRangeVO(zoneId, podId, nw.getId(), startIp, endIp, vlan);
_sNwIpRangeDao.persist(range);
try {
createStorageIpEntires(txn, range.getId(), startIp, endIp, netmask, zoneId);
} catch (SQLException e) {
txn.rollback();
StringBuilder err = new StringBuilder();
err.append("Create storage network range failed.");
err.append("startIp=" + startIp);
err.append("endIp=" + endIp);
err.append("netmask=" + netmask);
err.append("zoneId=" + zoneId);
s_logger.debug(err.toString(), e);
throw e;
}
txn.commit();
return range;
}
private String getInUseIpAddress(long rangeId) {
List<String> ips = _sNwIpDao.listInUseIpByRangeId(rangeId);
StringBuilder res = new StringBuilder();
res.append("Below IP of range " + rangeId + " is still in use:");
for (String ip : ips) {
res.append(ip);
}
return res.toString();
}
@Override
@DB
public void deleteIpRange(DeleteStorageNetworkIpRangeCmd cmd) {
long rangeId = cmd.getId();
StorageNetworkIpRangeVO range = _sNwIpRangeDao.findById(rangeId);
if (range == null) {
throw new CloudRuntimeException("Can not find storage network ip range " + rangeId);
}
if (_sNwIpDao.countInUseIpByRangeId(rangeId) > 0) {
throw new CloudRuntimeException(getInUseIpAddress(rangeId));
}
final Transaction txn = Transaction.currentTxn();
txn.start();
try {
range = _sNwIpRangeDao.acquireInLockTable(rangeId);
if (range == null) {
String msg = "Unable to acquire lock on storage network ip range id=" + rangeId + ", delete failed";
s_logger.warn(msg);
throw new CloudRuntimeException(msg);
}
/* entries in op_dc_storage_network_ip_address will be deleted automatically due to fk_storage_ip_address__range_id constraint key */
_sNwIpRangeDao.remove(rangeId);
} finally {
if (range != null) {
_sNwIpRangeDao.releaseFromLockTable(rangeId);
}
}
txn.commit();
}
@Override
public List<StorageNetworkIpRange> listIpRange(listStorageNetworkIpRangeCmd cmd) {
Long rangeId = cmd.getRangeId();
Long podId = cmd.getPodId();
Long zoneId = cmd.getZoneId();
List result = null;
if (rangeId != null) {
result = _sNwIpRangeDao.listByRangeId(rangeId);
} else if (podId != null) {
result = _sNwIpRangeDao.listByPodId(podId);
} else if (zoneId != null) {
result = _sNwIpRangeDao.listByDataCenterId(zoneId);
} else {
result = _sNwIpRangeDao.listAll();
}
return (List<StorageNetworkIpRange>)result;
}
@Override
public void releaseIpAddress(String ip) {
_sNwIpDao.releaseIpAddress(ip);
}
@Override
public StorageNetworkIpAddressVO acquireIpAddress(long podId) {
List<StorageNetworkIpRangeVO> ranges = _sNwIpRangeDao.listByPodId(podId);
for (StorageNetworkIpRangeVO r : ranges) {
try {
r = _sNwIpRangeDao.acquireInLockTable(r.getId());
if (r == null) {
String msg = "Unable to acquire lock on storage network ip range id=" + r.getId() + ", delete failed";
s_logger.warn(msg);
throw new CloudRuntimeException(msg);
}
StorageNetworkIpAddressVO ip = _sNwIpDao.takeIpAddress(r.getId());
if (ip != null) {
return ip;
}
} finally {
if (r != null) {
_sNwIpRangeDao.releaseFromLockTable(r.getId());
}
}
}
return null;
}
@Override
public boolean isAStorageIpAddress(String ip) {
SearchCriteriaService<StorageNetworkIpAddressVO, StorageNetworkIpAddressVO> sc = SearchCriteria2.create(StorageNetworkIpAddressVO.class);
sc.addAnd(sc.getEntity().getIpAddress(), Op.EQ, ip);
return sc.find() == null ? false : true;
}
}

View File

@ -0,0 +1,172 @@
package com.cloud.network.guru;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.dc.Pod;
import com.cloud.dc.StorageNetworkIpAddressVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
import com.cloud.network.Network;
import com.cloud.network.NetworkProfile;
import com.cloud.network.NetworkVO;
import com.cloud.network.Networks.AddressFormat;
import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.Mode;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.StorageNetworkManager;
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.component.Inject;
import com.cloud.utils.net.Ip4Address;
import com.cloud.utils.net.NetUtils;
import com.cloud.vm.NicProfile;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.Nic.ReservationStrategy;
@Local(value = NetworkGuru.class)
public class StorageNetworkGuru extends AdapterBase implements NetworkGuru {
private static final Logger s_logger = Logger.getLogger(StorageNetworkGuru.class);
@Inject StorageNetworkManager _sNwMgr;
@Inject DataCenterDao _dcDao;
protected StorageNetworkGuru() {
super();
}
protected boolean canHandle(NetworkOffering offering) {
if (offering.getTrafficType() == TrafficType.Storage && offering.isSystemOnly()) {
return true;
} else {
s_logger.trace("It's not storage network offering, skip it.");
return false;
}
}
@Override
public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) {
if (!canHandle(offering)) {
return null;
}
NetworkVO config = new NetworkVO(offering.getTrafficType(), Mode.Static, BroadcastDomainType.Native, offering.getId(), Network.State.Setup,
plan.getDataCenterId(), plan.getPhysicalNetworkId());
return config;
}
@Override
public Network implement(Network network, NetworkOffering offering, DeployDestination destination, ReservationContext context)
throws InsufficientVirtualNetworkCapcityException {
assert network.getTrafficType() == TrafficType.Storage : "Why are you sending this configuration to me " + network;
return network;
}
@Override
public NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm)
throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException {
assert network.getTrafficType() == TrafficType.Storage : "Well, I can't take care of this config now can I? " + network;
return new NicProfile(ReservationStrategy.Start, null, null, null, null);
}
@Override
public Ip4Address acquireIp4Address(Network network, String requestedIp, String reservationId) throws InsufficientAddressCapacityException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean releaseIp4Address(Network network, String reservationId) {
// TODO Auto-generated method stub
return false;
}
@Override
public void reserve(NicProfile nic, Network network, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, ReservationContext context)
throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException {
Pod pod = dest.getPod();
String ipAddress = null;
Long macLong = null;
Integer cidrSize = null;
StorageNetworkIpAddressVO ip = _sNwMgr.acquireIpAddress(pod.getId());
if (ip != null) {
ipAddress = ip.getIpAddress();
macLong = ip.getMac();
cidrSize = ip.getCidrSize();
} else {
s_logger.debug("Can not get an ip from storage network ip range for pod " + pod.getId() + ", acquire one from managment ip range");
/* Pick up an ip from management ip range if there is no available in storage ip range because of either user not added it or run out of */
Pair<String, Long>ip1 = _dcDao.allocatePrivateIpAddress(dest.getDataCenter().getId(), pod.getId(), nic.getId(),
context.getReservationId());
if (ip1 == null) {
throw new InsufficientAddressCapacityException("Unable to get a storage network ip address", Pod.class, pod.getId());
}
ipAddress = ip1.first();
macLong = ip1.second();
cidrSize = pod.getCidrSize();
}
nic.setIp4Address(ipAddress);
nic.setMacAddress(NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(macLong)));
nic.setFormat(AddressFormat.Ip4);
nic.setNetmask(NetUtils.getCidrNetmask(cidrSize));
nic.setBroadcastType(BroadcastDomainType.Native);
nic.setBroadcastUri(null);
nic.setIsolationUri(null);
s_logger.debug("Allocated a nic " + nic + " for " + vm);
}
@Override
public boolean release(NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, String reservationId) {
if (_sNwMgr.isAStorageIpAddress(nic.getIp4Address())) {
_sNwMgr.releaseIpAddress(nic.getIp4Address());
s_logger.debug("Release an storage ip " + nic.getIp4Address());
} else {
_dcDao.releasePrivateIpAddress(nic.getId(), nic.getReservationId());
s_logger.debug("Release an storage ip that is from managment ip range " + nic.getIp4Address());
}
nic.deallocate();
return true;
}
@Override
public void deallocate(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm) {
// TODO Auto-generated method stub
}
@Override
public void updateNicProfile(NicProfile profile, Network network) {
// TODO Auto-generated method stub
}
@Override
public void shutdown(NetworkProfile network, NetworkOffering offering) {
// TODO Auto-generated method stub
}
@Override
public boolean trash(Network network, NetworkOffering offering, Account owner) {
// TODO Auto-generated method stub
return false;
}
@Override
public void updateNetworkProfile(NetworkProfile networkProfile) {
// TODO Auto-generated method stub
}
}

3
server/src/com/cloud/test/IPRangeConfig.java Normal file → Executable file
View File

@ -27,6 +27,7 @@ import java.sql.Statement;
import java.util.List;
import java.util.Vector;
import com.cloud.network.IpAddress;
import com.cloud.utils.component.ComponentLocator;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Transaction;
@ -448,7 +449,7 @@ public class IPRangeConfig {
return problemIPs;
}
public Vector<String> savePublicIPRange(Transaction txn, long startIP, long endIP, long zoneId, long vlanDbId, Long sourceNetworkId, long physicalNetworkId) {
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) VALUES (?, ?, ?, (select mac_address from `cloud`.`data_center` where id=?), ?, ?)";
String updateSql = "UPDATE `cloud`.`data_center` set mac_address = mac_address+1 where id=?";

View File

@ -560,6 +560,33 @@ CREATE TABLE `cloud`.`op_dc_link_local_ip_address_alloc` (
INDEX `i_op_dc_link_local_ip_address_alloc__nic_id_reservation_id`(`nic_id`,`reservation_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`dc_storage_network_ip_range` (
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
`start_ip` char(40) NOT NULL COMMENT 'start ip address',
`end_ip` char(40) NOT NULL COMMENT 'end ip address',
`vlan` int unsigned DEFAULT NULL COMMENT 'vlan the storage network on',
`data_center_id` bigint unsigned NOT NULL,
`network_id` bigint unsigned NOT NULL COMMENT 'id of corresponding network offering',
PRIMARY KEY (`id`),
CONSTRAINT `fk_storage_ip_range__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`id`),
CONSTRAINT `fk_storage_ip_range__data_center_id` FOREIGN KEY (`data_center_id`) REFERENCES `data_center`(`id`),
CONSTRAINT `fk_storage_ip_range___network_id` FOREIGN KEY (`physical_network_id`) REFERENCES `physical_network`(`id`)
CONSTRAINT `uc_vlan__uuid` UNIQUE (`uuid`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`op_dc_storage_network_ip_address` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key',
`range_id` bigint unsigned NOT NULL COMMENT 'id of ip range in dc_storage_network_ip_range',
`pod_id` bigint unsigned NOT NULL COMMENT 'pod it belongs to',
`ip_address` char(40) NOT NULL COMMENT 'ip address',
`mac_address` bigint unsigned NOT NULL COMMENT 'mac address for storage ips',
`cidr_size` int unsigned NOT NULL COMMENT 'CIDR size for storage network',
`taken` datetime COMMENT 'Date taken',
PRIMARY KEY (`id`),
CONSTRAINT `fk_storage_ip_address__range_id` FOREIGN KEY (`range_id`) REFERENCES `dc_storage_network_ip_range`(`id`) ON DELETE CASCADE,
CONSTRAINT `fk_storage_ip_address__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `host_pod_ref`(`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`host_pod_ref` (
`id` bigint unsigned NOT NULL UNIQUE auto_increment,
`name` varchar(255),