Bug 12777 - Add storage network configuration into CloudStack

most finish
This commit is contained in:
frank 2012-01-04 13:32:49 -08:00
parent 0b01c5dc1a
commit f72940e041
24 changed files with 223 additions and 108 deletions

View File

@ -19,7 +19,7 @@ import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account; import com.cloud.user.Account;
@Implementation(description="Creates a VLAN IP range.", responseObject=StorageNetworkIpRangeResponse.class) @Implementation(description="Creates a Storage network IP range.", responseObject=StorageNetworkIpRangeResponse.class)
public class CreateStorageNetworkIpRangeCmd extends BaseAsyncCmd { public class CreateStorageNetworkIpRangeCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(CreateStorageNetworkIpRangeCmd.class); public static final Logger s_logger = Logger.getLogger(CreateStorageNetworkIpRangeCmd.class);
@ -29,27 +29,23 @@ public class CreateStorageNetworkIpRangeCmd extends BaseAsyncCmd {
//////////////// API parameters ///////////////////// //////////////// API parameters /////////////////////
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@IdentityMapper(entityTableName="host_pod_ref") @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.") @Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, description="UUID of pod where the ip range belongs to")
private Long podId; private Long podId;
@Parameter(name=ApiConstants.START_IP, type=CommandType.STRING, required=true, description="the beginning IP address in the VLAN IP range") @Parameter(name=ApiConstants.START_IP, type=CommandType.STRING, required=true, description="the beginning IP address")
private String startIp; private String startIp;
@Parameter(name=ApiConstants.END_IP, type=CommandType.STRING, description="the ending IP address in the VLAN IP range") @Parameter(name=ApiConstants.END_IP, type=CommandType.STRING, description="the ending IP address")
private String endIp; private String endIp;
@Parameter(name=ApiConstants.VLAN, type=CommandType.INTEGER, description="the ID or VID of the VLAN. Optional, null means no vlan") @Parameter(name=ApiConstants.VLAN, type=CommandType.INTEGER, description="Optional. the vlan the ip range sits on")
private Integer vlan; private Integer vlan;
@IdentityMapper(entityTableName="data_center") @IdentityMapper(entityTableName="data_center")
@Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="the Zone ID of the VLAN IP range") @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="The uuid of zone")
private Long zoneId; private Long zoneId;
@IdentityMapper(entityTableName="networks") @Parameter(name=ApiConstants.NETMASK, type=CommandType.STRING, required=true, description="the netmask for storage network")
@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; private String netmask;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@ -76,10 +72,6 @@ public class CreateStorageNetworkIpRangeCmd extends BaseAsyncCmd {
return zoneId; return zoneId;
} }
public Long getNetworkID() {
return networkID;
}
public String getNetmask() { public String getNetmask() {
return netmask; return netmask;
} }

View File

@ -29,7 +29,7 @@ public class DeleteStorageNetworkIpRangeCmd extends BaseAsyncCmd {
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@IdentityMapper(entityTableName="dc_storage_network_ip_range") @IdentityMapper(entityTableName="dc_storage_network_ip_range")
@Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="the storage network IP range ID") @Parameter(name=ApiConstants.ID, type=CommandType.LONG, required=true, description="the uuid of the storage network ip range")
private Long id; private Long id;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////

View File

@ -34,15 +34,15 @@ public class listStorageNetworkIpRangeCmd extends BaseAsyncCmd {
///////////////////////////////////////////////////// /////////////////////////////////////////////////////
@IdentityMapper(entityTableName="dc_storage_network_ip_range") @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.") @Parameter(name=ApiConstants.ID, type=CommandType.LONG, description="optional parameter. Storaget network IP range uuid, if specicied, using it to search the range.")
private Long rangeId; private Long rangeId;
@IdentityMapper(entityTableName="host_pod_ref") @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.") @Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, description="optional parameter. Pod uuid, if specicied and range uuid is absent, using it to search the range.")
private Long podId; private Long podId;
@IdentityMapper(entityTableName="data_center") @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.") @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, description="optional parameter. Zone uuid, if specicied and both pod uuid and range uuid are absent, using it to search the range.")
private Long zoneId; private Long zoneId;
///////////////////////////////////////////////////// /////////////////////////////////////////////////////

View File

@ -6,14 +6,14 @@ import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
public class StorageNetworkIpRangeResponse extends BaseResponse { public class StorageNetworkIpRangeResponse extends BaseResponse {
@SerializedName(ApiConstants.VLAN) @Param(description="the ID of storage network IP range.") @SerializedName(ApiConstants.VLAN) @Param(description="the uuid of storage network IP range.")
private Long id; private String uuid;
@SerializedName(ApiConstants.VLAN) @Param(description="the ID or VID of the VLAN.") @SerializedName(ApiConstants.VLAN) @Param(description="the ID or VID of the VLAN.")
private Integer vlan; private Integer vlan;
@SerializedName(ApiConstants.POD_ID) @Param(description="the Pod ID for the VLAN IP range") @SerializedName(ApiConstants.POD_ID) @Param(description="the Pod uuid for the VLAN IP range")
private IdentityProxy podId = new IdentityProxy("host_pod_ref"); private String podUuid;
@SerializedName(ApiConstants.START_IP) @Param(description="the start ip of the VLAN IP range") @SerializedName(ApiConstants.START_IP) @Param(description="the start ip of the VLAN IP range")
private String startIp; private String startIp;
@ -21,26 +21,26 @@ public class StorageNetworkIpRangeResponse extends BaseResponse {
@SerializedName(ApiConstants.END_IP) @Param(description="the end ip of the VLAN IP range") @SerializedName(ApiConstants.END_IP) @Param(description="the end ip of the VLAN IP range")
private String endIp; private String endIp;
@SerializedName(ApiConstants.NETWORK_ID) @Param(description="the network id of vlan range") @SerializedName(ApiConstants.NETWORK_ID) @Param(description="the network uuid of vlan range")
private IdentityProxy networkId = new IdentityProxy("networks"); private String networkUuid;
@SerializedName(ApiConstants.ZONE_ID) @Param(description="the Zone ID of the VLAN IP range") @SerializedName(ApiConstants.ZONE_ID) @Param(description="the Zone uuid of the VLAN IP range")
private IdentityProxy zoneId = new IdentityProxy("data_center"); private String zoneUuid;
public void setId(Long id) { public void setUuid(String uuId) {
this.id = id; this.uuid = uuid;
} }
public void setZoneId(Long zoneId) { public void setZoneUuid(String zoneUuid) {
this.zoneId.setValue(zoneId); this.zoneUuid = zoneUuid;
} }
public void setVlan(Integer vlan) { public void setVlan(Integer vlan) {
this.vlan = vlan; this.vlan = vlan;
} }
public void setPodId(Long podId) { public void setPodUuid(String podUuid) {
this.podId.setValue(podId); this.podUuid = podUuid;
} }
public void setStartIp(String startIp) { public void setStartIp(String startIp) {
@ -51,7 +51,7 @@ public class StorageNetworkIpRangeResponse extends BaseResponse {
this.endIp = endIp; this.endIp = endIp;
} }
public void setNetworkId(Long networkId) { public void setNetworkUuid(String networkUuid) {
this.networkId.setValue(networkId); this.networkUuid = networkUuid;
} }
} }

View File

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

1
api/src/com/cloud/network/Networks.java Normal file → Executable file
View File

@ -61,6 +61,7 @@ public class Networks {
Vswitch("vs", String.class), Vswitch("vs", String.class),
LinkLocal(null, null), LinkLocal(null, null),
Vnet("vnet", Long.class), Vnet("vnet", Long.class),
Storage("storage", Integer.class),
UnDecided(null, null); UnDecided(null, null);
private String scheme; private String scheme;

View File

@ -317,3 +317,10 @@ addTrafficType=com.cloud.api.commands.AddTrafficTypeCmd;1
deleteTrafficType=com.cloud.api.commands.DeleteTrafficTypeCmd;1 deleteTrafficType=com.cloud.api.commands.DeleteTrafficTypeCmd;1
listTrafficTypes=com.cloud.api.commands.ListTrafficTypesCmd;1 listTrafficTypes=com.cloud.api.commands.ListTrafficTypesCmd;1
updateTrafficType=com.cloud.api.commands.UpdateTrafficTypeCmd;1 updateTrafficType=com.cloud.api.commands.UpdateTrafficTypeCmd;1
#### Storage Network commands
createStorageNetworkIpRange=com.cloud.api.commands.CreateStorageNetworkIpRangeCmd;1
deleteStorageNetworkIpRange=com.cloud.api.commands.DeleteStorageNetworkIpRangeCmd;1
listStorageNetworkIpRange=com.cloud.api.commands.listStorageNetworkIpRangeCmd;1

View File

@ -59,6 +59,7 @@
<adapter name="ControlNetworkGuru" class="com.cloud.network.guru.ControlNetworkGuru"/> <adapter name="ControlNetworkGuru" class="com.cloud.network.guru.ControlNetworkGuru"/>
<adapter name="DirectNetworkGuru" class="com.cloud.network.guru.DirectNetworkGuru"/> <adapter name="DirectNetworkGuru" class="com.cloud.network.guru.DirectNetworkGuru"/>
<adapter name="DirectPodBasedNetworkGuru" class="com.cloud.network.guru.DirectPodBasedNetworkGuru"/> <adapter name="DirectPodBasedNetworkGuru" class="com.cloud.network.guru.DirectPodBasedNetworkGuru"/>
<adapter name="StorageNetworkGuru" class="com.cloud.network.guru.StorageNetworkGuru"/>
</adapters> </adapters>
<adapters key="com.cloud.cluster.ClusterServiceAdapter"> <adapters key="com.cloud.cluster.ClusterServiceAdapter">
<adapter name="ClusterService" class="com.cloud.cluster.ClusterServiceServletAdapter"/> <adapter name="ClusterService" class="com.cloud.cluster.ClusterServiceServletAdapter"/>

View File

@ -650,6 +650,14 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
long account = Long.parseLong(nic.getBroadcastUri().getHost()); long account = Long.parseLong(nic.getBroadcastUri().getHost());
return createTunnelNetwork(conn, account); return createTunnelNetwork(conn, account);
} }
} else if (nic.getBroadcastType() == BroadcastDomainType.Storage) {
URI broadcastUri = nic.getBroadcastUri();
if (broadcastUri == null) {
return network.getNetwork();
} else {
long vlan = Long.parseLong(broadcastUri.getHost());
return enableVlanNetwork(conn, vlan, network);
}
} }
throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri()); throw new CloudRuntimeException("Unable to support this type of network broadcast domain: " + nic.getBroadcastUri());

View File

@ -589,10 +589,26 @@ setup_dhcpsrvr() {
fi fi
} }
setup_storage_network() {
if [ x"$STORAGE_IP" == "x" -o x"$STORAGE_NETMASK" == "x" ]
then
log_it "Incompleted parameters STORAGE_IP:$STORAGE_IP, STORAGE_NETMASK:$STORAGE_NETMASK, STORAGE_CIDR:$STORAGE_CIDR. Cannot setup storage network"
return
fi
echo "" >> /etc/network/interfaces
echo "auto eth3" >> /etc/network/interfaces
setup_interface "3" "$STORAGE_IP" "$STORAGE_NETMASK"
#ip route add "$STORAGE_CIDR" via "$STORAGE_IP"
log_it "Successfully setup storage network with STORAGE_IP:$STORAGE_IP, STORAGE_NETMASK:$STORAGE_NETMASK, STORAGE_CIDR:$STORAGE_CIDR"
}
setup_secstorage() { setup_secstorage() {
log_it "Setting up secondary storage system vm" log_it "Setting up secondary storage system vm"
local hyp=$1 local hyp=$1
setup_common eth0 eth1 eth2 setup_common eth0 eth1 eth2
setup_storage_network
[ -n "$MTU" ] && ifconfig eth1 mtu $MTU [ -n "$MTU" ] && ifconfig eth1 mtu $MTU
sed -i /gateway/d /etc/hosts sed -i /gateway/d /etc/hosts
public_ip=$ETH2_IP public_ip=$ETH2_IP
@ -719,6 +735,9 @@ CMDLINE=$(cat /var/cache/cloud/cmdline)
TYPE="unknown" TYPE="unknown"
BOOTPROTO="static" BOOTPROTO="static"
DISABLE_RP_FILTER="false" DISABLE_RP_FILTER="false"
STORAGE_IP=""
STORAGE_NETMASK=""
STORAGE_CIDR=""
for i in $CMDLINE for i in $CMDLINE
do do
@ -825,6 +844,15 @@ for i in $CMDLINE
mtu) mtu)
MTU=$VALUE MTU=$VALUE
;; ;;
storageip)
STORAGE_IP=$VALUE
;;
storagenetmask)
STORAGE_NETMASK=$VALUE
;;
storagecidr)
STORAGE_CIDR=$VALUE
;;
esac esac
done done
} }

View File

@ -3241,13 +3241,13 @@ public class ApiResponseHelper implements ResponseGenerator {
@Override @Override
public StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result) { public StorageNetworkIpRangeResponse createStorageNetworkIpRangeResponse(StorageNetworkIpRange result) {
StorageNetworkIpRangeResponse response = new StorageNetworkIpRangeResponse(); StorageNetworkIpRangeResponse response = new StorageNetworkIpRangeResponse();
response.setId(result.getId()); response.setUuid(result.getUuid());
response.setVlan(result.getVlan()); response.setVlan(result.getVlan());
response.setEndIp(result.getEndIp()); response.setEndIp(result.getEndIp());
response.setStartIp(result.getStartIp()); response.setStartIp(result.getStartIp());
response.setPodId(result.getPodId()); response.setPodUuid(result.getPodUuid());
response.setZoneId(result.getDataCenterId()); response.setZoneUuid(result.getZoneUuid());
response.setNetworkId(result.getNetworkId()); response.setNetworkUuid(result.getNetworkUuid());
return response; return response;
} }
} }

View File

@ -55,6 +55,8 @@ import com.cloud.dc.dao.DataCenterIpAddressDaoImpl;
import com.cloud.dc.dao.DcDetailsDaoImpl; import com.cloud.dc.dao.DcDetailsDaoImpl;
import com.cloud.dc.dao.HostPodDaoImpl; import com.cloud.dc.dao.HostPodDaoImpl;
import com.cloud.dc.dao.PodVlanMapDaoImpl; import com.cloud.dc.dao.PodVlanMapDaoImpl;
import com.cloud.dc.dao.StorageNetworkIpAddressDaoImpl;
import com.cloud.dc.dao.StorageNetworkIpRangeDaoImpl;
import com.cloud.dc.dao.VlanDaoImpl; import com.cloud.dc.dao.VlanDaoImpl;
import com.cloud.domain.dao.DomainDaoImpl; import com.cloud.domain.dao.DomainDaoImpl;
import com.cloud.event.dao.EventDaoImpl; import com.cloud.event.dao.EventDaoImpl;
@ -71,6 +73,7 @@ import com.cloud.keystore.KeystoreManagerImpl;
import com.cloud.maint.UpgradeManagerImpl; import com.cloud.maint.UpgradeManagerImpl;
import com.cloud.maint.dao.AgentUpgradeDaoImpl; import com.cloud.maint.dao.AgentUpgradeDaoImpl;
import com.cloud.network.NetworkManagerImpl; import com.cloud.network.NetworkManagerImpl;
import com.cloud.network.StorageNetworkManagerImpl;
import com.cloud.network.dao.ExternalFirewallDeviceDaoImpl; import com.cloud.network.dao.ExternalFirewallDeviceDaoImpl;
import com.cloud.network.dao.ExternalLoadBalancerDeviceDaoImpl; import com.cloud.network.dao.ExternalLoadBalancerDeviceDaoImpl;
import com.cloud.network.dao.FirewallRulesCidrsDaoImpl; import com.cloud.network.dao.FirewallRulesCidrsDaoImpl;
@ -327,6 +330,8 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
addDao("NetworkExternalFirewallDao", NetworkExternalFirewallDaoImpl.class); addDao("NetworkExternalFirewallDao", NetworkExternalFirewallDaoImpl.class);
addDao("PhysicalNetworkTrafficTypeDao", PhysicalNetworkTrafficTypeDaoImpl.class); addDao("PhysicalNetworkTrafficTypeDao", PhysicalNetworkTrafficTypeDaoImpl.class);
addDao("NetworkServiceMapDao", NetworkServiceMapDaoImpl.class); addDao("NetworkServiceMapDao", NetworkServiceMapDaoImpl.class);
addDao("StorageNetworkIpAddressDao", StorageNetworkIpAddressDaoImpl.class);
addDao("StorageNetworkIpRangeDao", StorageNetworkIpRangeDaoImpl.class);
} }
@Override @Override
@ -382,6 +387,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
addManager("ProjectManager", ProjectManagerImpl.class); addManager("ProjectManager", ProjectManagerImpl.class);
addManager("ElasticLoadBalancerManager", ElasticLoadBalancerManagerImpl.class); addManager("ElasticLoadBalancerManager", ElasticLoadBalancerManagerImpl.class);
addManager("SwiftManager", SwiftManagerImpl.class); addManager("SwiftManager", SwiftManagerImpl.class);
addManager("StorageNetworkManager", StorageNetworkManagerImpl.class);
} }
@Override @Override

View File

@ -7,6 +7,9 @@ import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.SecondaryTables;
import javax.persistence.Table; import javax.persistence.Table;
import javax.persistence.Temporal; import javax.persistence.Temporal;
import javax.persistence.TemporalType; import javax.persistence.TemporalType;
@ -15,6 +18,7 @@ import com.cloud.network.IpAddress.State;
@Entity @Entity
@Table(name="op_dc_storage_network_ip_address") @Table(name="op_dc_storage_network_ip_address")
@SecondaryTables({@SecondaryTable(name = "dc_storage_network_ip_range", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "range_id", referencedColumnName = "id")})})
public class StorageNetworkIpAddressVO { public class StorageNetworkIpAddressVO {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@ -37,6 +41,9 @@ public class StorageNetworkIpAddressVO {
@Column(name = "mac_address") @Column(name = "mac_address")
long mac; long mac;
@Column(name = "vlan", table = "dc_storage_network_ip_range", insertable = false, updatable = false)
Integer vlan;
protected StorageNetworkIpAddressVO() { protected StorageNetworkIpAddressVO() {
} }
@ -83,4 +90,8 @@ public class StorageNetworkIpAddressVO {
public void setCidrSize(int cidr) { public void setCidrSize(int cidr) {
this.cidrSize =cidr; this.cidrSize =cidr;
} }
public Integer getVlan() {
return vlan;
}
} }

View File

@ -1,22 +1,34 @@
package com.cloud.dc; package com.cloud.dc;
import java.util.UUID;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType; import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.SecondaryTables;
import javax.persistence.Table; import javax.persistence.Table;
@Entity @Entity
@Table(name="dc_storage_network_ip_range") @Table(name="dc_storage_network_ip_range")
@SecondaryTables({@SecondaryTable(name="networks", pkJoinColumns={@PrimaryKeyJoinColumn(name="network_id", referencedColumnName="id")}),
@SecondaryTable(name="host_pod_ref", pkJoinColumns={@PrimaryKeyJoinColumn(name="pod_id", referencedColumnName="id")}),
@SecondaryTable(name="data_center", pkJoinColumns={@PrimaryKeyJoinColumn(name="data_center_id", referencedColumnName="id")}),
})
public class StorageNetworkIpRangeVO implements StorageNetworkIpRange { public class StorageNetworkIpRangeVO implements StorageNetworkIpRange {
@Id @Id
@GeneratedValue(strategy = GenerationType.IDENTITY) @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id") @Column(name = "id")
private long id; private long id;
@Column(name = "uuid")
String uuid;
@Column(name = "vlan") @Column(name = "vlan")
private int vlan; private Integer vlan;
@Column(name = "data_center_id") @Column(name = "data_center_id")
private long dataCenterId; private long dataCenterId;
@ -33,7 +45,17 @@ public class StorageNetworkIpRangeVO implements StorageNetworkIpRange {
@Column(name = "network_id") @Column(name = "network_id")
private long networkId; private long networkId;
public StorageNetworkIpRangeVO(long dcId, long podId, long networkId, String startIp, String endIp, int vlan) { @Column(name = "uuid", table = "networks", insertable = false, updatable = false)
String networkUuid;
@Column(name = "uuid", table = "host_pod_ref", insertable = false, updatable = false)
String podUuid;
@Column(name = "uuid", table = "data_center", insertable = false, updatable = false)
String zoneUuid;
public StorageNetworkIpRangeVO(long dcId, long podId, long networkId, String startIp, String endIp, Integer vlan) {
this();
this.dataCenterId = dcId; this.dataCenterId = dcId;
this.podId = podId; this.podId = podId;
this.networkId = networkId; this.networkId = networkId;
@ -43,7 +65,7 @@ public class StorageNetworkIpRangeVO implements StorageNetworkIpRange {
} }
protected StorageNetworkIpRangeVO() { protected StorageNetworkIpRangeVO() {
this.uuid = UUID.randomUUID().toString();
} }
public long getId() { public long getId() {
@ -74,7 +96,7 @@ public class StorageNetworkIpRangeVO implements StorageNetworkIpRange {
this.networkId = nwId; this.networkId = nwId;
} }
public int getVlan() { public Integer getVlan() {
return vlan; return vlan;
} }
@ -97,4 +119,24 @@ public class StorageNetworkIpRangeVO implements StorageNetworkIpRange {
public String getEndIp() { public String getEndIp() {
return endIp; return endIp;
} }
@Override
public String getUuid() {
return uuid;
}
@Override
public String getPodUuid() {
return podUuid;
}
@Override
public String getNetworkUuid() {
return networkUuid;
}
@Override
public String getZoneUuid() {
return zoneUuid;
}
} }

View File

@ -33,13 +33,13 @@ public class StorageNetworkIpAddressDaoImpl extends GenericDaoBase<StorageNetwor
countInUserIp = createSearchBuilder(Long.class); countInUserIp = createSearchBuilder(Long.class);
countInUserIp.select(null, Func.COUNT, null); countInUserIp.select(null, Func.COUNT, null);
countInUserIp.and("rangeId", countInUserIp.entity().getRangeId(), Op.EQ); countInUserIp.and("rangeId", countInUserIp.entity().getRangeId(), Op.EQ);
countInUserIp.and("taken", countInUserIp.entity().getTakenAt(), Op.NULL); countInUserIp.and("taken", countInUserIp.entity().getTakenAt(), Op.NNULL);
countInUserIp.done(); countInUserIp.done();
listInUseIp = createSearchBuilder(String.class); listInUseIp = createSearchBuilder(String.class);
listInUseIp.selectField(listInUseIp.entity().getIpAddress()); listInUseIp.selectField(listInUseIp.entity().getIpAddress());
listInUseIp.and("rangeId", listInUseIp.entity().getRangeId(), Op.EQ); listInUseIp.and("rangeId", listInUseIp.entity().getRangeId(), Op.EQ);
listInUseIp.and("taken", listInUseIp.entity().getTakenAt(), Op.NULL); listInUseIp.and("taken", listInUseIp.entity().getTakenAt(), Op.NNULL);
listInUseIp.done(); listInUseIp.done();
untakenIp = createSearchBuilder(); untakenIp = createSearchBuilder();

View File

@ -11,4 +11,6 @@ public interface StorageNetworkIpRangeDao extends GenericDao<StorageNetworkIpRan
List<StorageNetworkIpRangeVO> listByPodId(long podId); List<StorageNetworkIpRangeVO> listByPodId(long podId);
List<StorageNetworkIpRangeVO> listByDataCenterId(long dcId); List<StorageNetworkIpRangeVO> listByDataCenterId(long dcId);
long countRanges();
} }

View File

@ -3,9 +3,11 @@ package com.cloud.dc.dao;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.ejb.Local;
import javax.naming.ConfigurationException; import javax.naming.ConfigurationException;
import com.cloud.dc.StorageNetworkIpRangeVO; import com.cloud.dc.StorageNetworkIpRangeVO;
import com.cloud.utils.db.DB;
import com.cloud.utils.db.Filter; import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder; import com.cloud.utils.db.GenericSearchBuilder;
@ -13,9 +15,19 @@ import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria2; import com.cloud.utils.db.SearchCriteria2;
import com.cloud.utils.db.SearchCriteriaService; import com.cloud.utils.db.SearchCriteriaService;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria.Op;
@Local(value={StorageNetworkIpRangeDao.class})
@DB(txn=false)
public class StorageNetworkIpRangeDaoImpl extends GenericDaoBase<StorageNetworkIpRangeVO, Long> implements StorageNetworkIpRangeDao { public class StorageNetworkIpRangeDaoImpl extends GenericDaoBase<StorageNetworkIpRangeVO, Long> implements StorageNetworkIpRangeDao {
protected final GenericSearchBuilder<StorageNetworkIpRangeVO, Long> countRanges;
protected StorageNetworkIpRangeDaoImpl() {
countRanges = createSearchBuilder(Long.class);
countRanges.select(null, Func.COUNT, null);
countRanges.done();
}
@Override @Override
public List<StorageNetworkIpRangeVO> listByPodId(long podId) { public List<StorageNetworkIpRangeVO> listByPodId(long podId) {
@ -38,4 +50,10 @@ public class StorageNetworkIpRangeDaoImpl extends GenericDaoBase<StorageNetworkI
return sc.list(); return sc.list();
} }
@Override
public long countRanges() {
SearchCriteria<Long> sc = countRanges.create();
return customSearch(sc, null).get(0);
}
} }

View File

@ -8,5 +8,5 @@ public interface StorageNetworkManager extends Manager {
void releaseIpAddress(String ip); void releaseIpAddress(String ip);
boolean isAStorageIpAddress(String ip); boolean isStorageIpRangeAvailable();
} }

View File

@ -91,7 +91,7 @@ public class StorageNetworkManagerImpl implements StorageNetworkManager, Storage
List<StorageNetworkIpRangeVO> curRanges = _sNwIpRangeDao.listByPodId(podId); List<StorageNetworkIpRangeVO> curRanges = _sNwIpRangeDao.listByPodId(podId);
for (StorageNetworkIpRangeVO range : curRanges) { for (StorageNetworkIpRangeVO range : curRanges) {
if (NetUtils.ipRangesOverlap(startIp, endIp, range.getStartIp(), range.getEndIp())) { 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()); throw new InvalidParameterValueException("The Storage network Start IP and endIP address range overlap with private IP :" + range.getStartIp() + " - " + range.getEndIp());
} }
} }
} }
@ -180,7 +180,7 @@ public class StorageNetworkManagerImpl implements StorageNetworkManager, Storage
StringBuilder res = new StringBuilder(); StringBuilder res = new StringBuilder();
res.append("Below IP of range " + rangeId + " is still in use:"); res.append("Below IP of range " + rangeId + " is still in use:");
for (String ip : ips) { for (String ip : ips) {
res.append(ip); res.append(ip).append(",");
} }
return res.toString(); return res.toString();
} }
@ -269,10 +269,8 @@ public class StorageNetworkManagerImpl implements StorageNetworkManager, Storage
} }
@Override @Override
public boolean isAStorageIpAddress(String ip) { public boolean isStorageIpRangeAvailable() {
SearchCriteriaService<StorageNetworkIpAddressVO, StorageNetworkIpAddressVO> sc = SearchCriteria2.create(StorageNetworkIpAddressVO.class); return _sNwIpRangeDao.countRanges() > 0;
sc.addAnd(sc.getEntity().getIpAddress(), Op.EQ, ip);
return sc.find() == null ? false : true;
} }
} }

View File

@ -40,6 +40,7 @@ import com.cloud.network.Networks.AddressFormat;
import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.Networks.BroadcastDomainType;
import com.cloud.network.Networks.Mode; import com.cloud.network.Networks.Mode;
import com.cloud.network.Networks.TrafficType; import com.cloud.network.Networks.TrafficType;
import com.cloud.network.StorageNetworkManager;
import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering;
import com.cloud.user.Account; import com.cloud.user.Account;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
@ -58,6 +59,7 @@ import com.cloud.vm.VirtualMachineProfile;
public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru { public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru {
private static final Logger s_logger = Logger.getLogger(PodBasedNetworkGuru.class); private static final Logger s_logger = Logger.getLogger(PodBasedNetworkGuru.class);
@Inject DataCenterDao _dcDao; @Inject DataCenterDao _dcDao;
@Inject StorageNetworkManager _sNwMgr;
Random _rand = new Random(System.currentTimeMillis()); Random _rand = new Random(System.currentTimeMillis());
@Override @Override
@ -68,6 +70,11 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru {
return null; return null;
} }
if (type == TrafficType.Storage && _sNwMgr.isStorageIpRangeAvailable()) {
s_logger.debug("There is some storage ip available, let StorageNetworkGuru to handle storage traffic type, not me");
return null;
}
NetworkVO config = new NetworkVO(type, Mode.Static, BroadcastDomainType.Native, offering.getId(), Network.State.Setup, plan.getDataCenterId(), plan.getPhysicalNetworkId()); NetworkVO config = new NetworkVO(type, Mode.Static, BroadcastDomainType.Native, offering.getId(), Network.State.Setup, plan.getDataCenterId(), plan.getPhysicalNetworkId());
return config; return config;
} }
@ -84,7 +91,7 @@ public class PodBasedNetworkGuru extends AdapterBase implements NetworkGuru {
public NicProfile allocate(Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm) throws InsufficientVirtualNetworkCapcityException, public NicProfile allocate(Network config, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm) throws InsufficientVirtualNetworkCapcityException,
InsufficientAddressCapacityException { InsufficientAddressCapacityException {
TrafficType trafficType = config.getTrafficType(); TrafficType trafficType = config.getTrafficType();
assert (trafficType == TrafficType.Storage || trafficType == TrafficType.Management) : "Well, I can't take care of this config now can I? " + config; assert trafficType == TrafficType.Management || trafficType == TrafficType.Storage: "Well, I can't take care of this config now can I? " + config;
if (nic != null) { if (nic != null) {
if (nic.getRequestedIp() != null) { if (nic.getRequestedIp() != null) {

View File

@ -37,7 +37,6 @@ import com.cloud.vm.Nic.ReservationStrategy;
public class StorageNetworkGuru extends AdapterBase implements NetworkGuru { public class StorageNetworkGuru extends AdapterBase implements NetworkGuru {
private static final Logger s_logger = Logger.getLogger(StorageNetworkGuru.class); private static final Logger s_logger = Logger.getLogger(StorageNetworkGuru.class);
@Inject StorageNetworkManager _sNwMgr; @Inject StorageNetworkManager _sNwMgr;
@Inject DataCenterDao _dcDao;
protected StorageNetworkGuru() { protected StorageNetworkGuru() {
super(); super();
@ -45,7 +44,12 @@ public class StorageNetworkGuru extends AdapterBase implements NetworkGuru {
protected boolean canHandle(NetworkOffering offering) { protected boolean canHandle(NetworkOffering offering) {
if (offering.getTrafficType() == TrafficType.Storage && offering.isSystemOnly()) { if (offering.getTrafficType() == TrafficType.Storage && offering.isSystemOnly()) {
if (_sNwMgr.isStorageIpRangeAvailable()) {
return true; return true;
} else {
s_logger.debug("No storage network ip range availabe, let PodBasedNetworkGuru to handle storage traffic type, not me");
return false;
}
} else { } else {
s_logger.trace("It's not storage network offering, skip it."); s_logger.trace("It's not storage network offering, skip it.");
return false; return false;
@ -93,48 +97,32 @@ public class StorageNetworkGuru extends AdapterBase implements NetworkGuru {
public void reserve(NicProfile nic, Network network, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, ReservationContext context) public void reserve(NicProfile nic, Network network, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, ReservationContext context)
throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException { throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException {
Pod pod = dest.getPod(); Pod pod = dest.getPod();
String ipAddress = null; Integer vlan = null;
Long macLong = null;
Integer cidrSize = null;
StorageNetworkIpAddressVO ip = _sNwMgr.acquireIpAddress(pod.getId()); StorageNetworkIpAddressVO ip = _sNwMgr.acquireIpAddress(pod.getId());
if (ip != null) { 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()); 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); vlan = ip.getVlan();
nic.setMacAddress(NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(macLong))); nic.setIp4Address(ip.getIpAddress());
nic.setMacAddress(NetUtils.long2Mac(NetUtils.createSequenceBasedMacAddress(ip.getMac())));
nic.setFormat(AddressFormat.Ip4); nic.setFormat(AddressFormat.Ip4);
nic.setNetmask(NetUtils.getCidrNetmask(cidrSize)); nic.setNetmask(NetUtils.getCidrNetmask(ip.getCidrSize()));
nic.setBroadcastType(BroadcastDomainType.Native); nic.setBroadcastType(BroadcastDomainType.Storage);
if (vlan != null) {
nic.setBroadcastUri(BroadcastDomainType.Storage.toUri(vlan));
} else {
nic.setBroadcastUri(null); nic.setBroadcastUri(null);
}
nic.setIsolationUri(null); nic.setIsolationUri(null);
s_logger.debug("Allocated a nic " + nic + " for " + vm); s_logger.debug("Allocated a storage nic " + nic + " for " + vm);
} }
@Override @Override
public boolean release(NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, String reservationId) { public boolean release(NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, String reservationId) {
if (_sNwMgr.isAStorageIpAddress(nic.getIp4Address())) {
_sNwMgr.releaseIpAddress(nic.getIp4Address()); _sNwMgr.releaseIpAddress(nic.getIp4Address());
s_logger.debug("Release an storage ip " + 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(); nic.deallocate();
return true; return true;
} }

View File

@ -79,6 +79,7 @@ import com.cloud.network.guru.ControlNetworkGuru;
import com.cloud.network.guru.DirectPodBasedNetworkGuru; import com.cloud.network.guru.DirectPodBasedNetworkGuru;
import com.cloud.network.guru.PodBasedNetworkGuru; import com.cloud.network.guru.PodBasedNetworkGuru;
import com.cloud.network.guru.PublicNetworkGuru; import com.cloud.network.guru.PublicNetworkGuru;
import com.cloud.network.guru.StorageNetworkGuru;
import com.cloud.offering.NetworkOffering; import com.cloud.offering.NetworkOffering;
import com.cloud.offering.NetworkOffering.Availability; import com.cloud.offering.NetworkOffering.Availability;
import com.cloud.offerings.NetworkOfferingServiceMapVO; import com.cloud.offerings.NetworkOfferingServiceMapVO;
@ -953,7 +954,7 @@ public class ConfigurationServerImpl implements ConfigurationServer {
guruNames.put(TrafficType.Public, PublicNetworkGuru.class.getSimpleName()); guruNames.put(TrafficType.Public, PublicNetworkGuru.class.getSimpleName());
guruNames.put(TrafficType.Management, PodBasedNetworkGuru.class.getSimpleName()); guruNames.put(TrafficType.Management, PodBasedNetworkGuru.class.getSimpleName());
guruNames.put(TrafficType.Control, ControlNetworkGuru.class.getSimpleName()); guruNames.put(TrafficType.Control, ControlNetworkGuru.class.getSimpleName());
guruNames.put(TrafficType.Storage, PodBasedNetworkGuru.class.getSimpleName()); guruNames.put(TrafficType.Storage, StorageNetworkGuru.class.getSimpleName());
guruNames.put(TrafficType.Guest, DirectPodBasedNetworkGuru.class.getSimpleName()); guruNames.put(TrafficType.Guest, DirectPodBasedNetworkGuru.class.getSimpleName());
for (DataCenterVO zone : zones) { for (DataCenterVO zone : zones) {
@ -978,7 +979,7 @@ public class ConfigurationServerImpl implements ConfigurationServer {
TrafficType trafficType= offering.getTrafficType(); TrafficType trafficType= offering.getTrafficType();
boolean isNetworkDefault = false; boolean isNetworkDefault = false;
if (trafficType == TrafficType.Management || trafficType == TrafficType.Storage) { if (trafficType == TrafficType.Management) {
broadcastDomainType = BroadcastDomainType.Native; broadcastDomainType = BroadcastDomainType.Native;
} else if (trafficType == TrafficType.Control) { } else if (trafficType == TrafficType.Control) {
broadcastDomainType = BroadcastDomainType.LinkLocal; broadcastDomainType = BroadcastDomainType.LinkLocal;
@ -997,6 +998,8 @@ public class ConfigurationServerImpl implements ConfigurationServer {
} }
networkDomain = "cs" + Long.toHexString(Account.ACCOUNT_ID_SYSTEM) + _domainSuffix; networkDomain = "cs" + Long.toHexString(Account.ACCOUNT_ID_SYSTEM) + _domainSuffix;
} else if (offering.getTrafficType() == TrafficType.Storage) {
broadcastDomainType = BroadcastDomainType.Storage;
} }
if (broadcastDomainType != null) { if (broadcastDomainType != null) {

View File

@ -525,7 +525,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V
NetworkVO defaultNetwork = defaultNetworks.get(0); NetworkVO defaultNetwork = defaultNetworks.get(0);
List<NetworkOfferingVO> offerings = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemControlNetwork, NetworkOfferingVO.SystemManagementNetwork); List<NetworkOfferingVO> offerings = _networkMgr.getSystemAccountNetworkOfferings(NetworkOfferingVO.SystemControlNetwork, NetworkOfferingVO.SystemManagementNetwork, NetworkOfferingVO.SystemStorageNetwork);
List<Pair<NetworkVO, NicProfile>> networks = new ArrayList<Pair<NetworkVO, NicProfile>>(offerings.size() + 1); List<Pair<NetworkVO, NicProfile>> networks = new ArrayList<Pair<NetworkVO, NicProfile>>(offerings.size() + 1);
NicProfile defaultNic = new NicProfile(); NicProfile defaultNic = new NicProfile();
defaultNic.setDefaultNic(true); defaultNic.setDefaultNic(true);
@ -1034,6 +1034,9 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V
buf.append(" private.network.device=").append("eth").append(deviceId); buf.append(" private.network.device=").append("eth").append(deviceId);
} else if (nic.getTrafficType() == TrafficType.Public) { } else if (nic.getTrafficType() == TrafficType.Public) {
buf.append(" public.network.device=").append("eth").append(deviceId); buf.append(" public.network.device=").append("eth").append(deviceId);
} else if (nic.getTrafficType() == TrafficType.Storage) {
buf.append(" storageip=").append(nic.getIp4Address());
buf.append(" storagenetmask=").append(nic.getNetmask());
} }
} }

View File

@ -562,29 +562,29 @@ CREATE TABLE `cloud`.`op_dc_link_local_ip_address_alloc` (
CREATE TABLE `cloud`.`dc_storage_network_ip_range` ( CREATE TABLE `cloud`.`dc_storage_network_ip_range` (
`id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT, `id` bigint unsigned NOT NULL UNIQUE AUTO_INCREMENT,
`uuid` varchar(40),
`start_ip` char(40) NOT NULL COMMENT 'start ip address', `start_ip` char(40) NOT NULL COMMENT 'start ip address',
`end_ip` char(40) NOT NULL COMMENT 'end ip address', `end_ip` char(40) NOT NULL COMMENT 'end ip address',
`vlan` int unsigned DEFAULT NULL COMMENT 'vlan the storage network on', `vlan` int unsigned DEFAULT NULL COMMENT 'vlan the storage network on',
`data_center_id` bigint unsigned NOT NULL, `data_center_id` bigint unsigned NOT NULL,
`pod_id` bigint unsigned NOT NULL COMMENT 'pod it belongs to',
`network_id` bigint unsigned NOT NULL COMMENT 'id of corresponding network offering', `network_id` bigint unsigned NOT NULL COMMENT 'id of corresponding network offering',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),
CONSTRAINT `fk_storage_ip_range__network_id` FOREIGN KEY (`network_id`) REFERENCES `networks`(`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__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 `fk_storage_ip_range__pod_id` FOREIGN KEY (`pod_id`) REFERENCES `host_pod_ref`(`id`),
CONSTRAINT `uc_vlan__uuid` UNIQUE (`uuid`), CONSTRAINT `uc_storage_ip_range__uuid` UNIQUE (`uuid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`op_dc_storage_network_ip_address` ( CREATE TABLE `cloud`.`op_dc_storage_network_ip_address` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'primary key', `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', `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', `ip_address` char(40) NOT NULL COMMENT 'ip address',
`mac_address` bigint unsigned NOT NULL COMMENT 'mac address for storage ips', `mac_address` bigint unsigned NOT NULL COMMENT 'mac address for storage ips',
`cidr_size` int unsigned NOT NULL COMMENT 'CIDR size for storage network', `cidr_size` int unsigned NOT NULL COMMENT 'CIDR size for storage network',
`taken` datetime COMMENT 'Date taken', `taken` datetime COMMENT 'Date taken',
PRIMARY KEY (`id`), 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__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; ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cloud`.`host_pod_ref` ( CREATE TABLE `cloud`.`host_pod_ref` (