mirror of https://github.com/apache/cloudstack.git
Removed the async create status for volume now that our customers don't use it
This commit is contained in:
parent
304d1cbb55
commit
9d158dc060
|
|
@ -171,7 +171,6 @@ import com.cloud.storage.Storage;
|
|||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.StorageLayer;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.template.Processor;
|
||||
import com.cloud.storage.template.Processor.FormatInfo;
|
||||
import com.cloud.storage.template.QCOW2Processor;
|
||||
|
|
@ -1708,7 +1707,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
/*setup disks, e.g for iso*/
|
||||
VolumeTO[] volumes = vm.getDisks();
|
||||
for (VolumeTO volume : volumes) {
|
||||
if (volume.getType() == Volume.VolumeType.ISO) {
|
||||
if (volume.getType() == Volume.Type.ISO) {
|
||||
getVolumePath(conn, volume);
|
||||
}
|
||||
}
|
||||
|
|
@ -2109,7 +2108,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
}
|
||||
|
||||
private String getVolumePath(Connect conn, VolumeTO volume) throws LibvirtException, URISyntaxException {
|
||||
if (volume.getType() == Volume.VolumeType.ISO && volume.getPath() != null) {
|
||||
if (volume.getType() == Volume.Type.ISO && volume.getPath() != null) {
|
||||
StorageVol vol = _storageResource.getVolumeFromURI(conn, volume.getPath());
|
||||
return vol.getPath();
|
||||
} else {
|
||||
|
|
@ -2123,7 +2122,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
|
||||
DiskDef.diskBus diskBusType = getGuestDiskModel(vmSpec.getOs());
|
||||
DiskDef disk = new DiskDef();
|
||||
if (volume.getType() == VolumeType.ISO) {
|
||||
if (volume.getType() == Volume.Type.ISO) {
|
||||
if (volPath == null) {
|
||||
/*Add iso as placeholder*/
|
||||
disk.defISODisk(null);
|
||||
|
|
@ -2137,7 +2136,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
}
|
||||
|
||||
//Centos doesn't support scsi hotplug. For other host OSes, we attach the disk after the vm is running, so that we can hotplug it.
|
||||
if (volume.getType() == VolumeType.DATADISK && diskBusType != DiskDef.diskBus.VIRTIO) {
|
||||
if (volume.getType() == Volume.Type.DATADISK && diskBusType != DiskDef.diskBus.VIRTIO) {
|
||||
disk.setAttachDeferred(true);
|
||||
}
|
||||
|
||||
|
|
@ -2155,7 +2154,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
}
|
||||
}
|
||||
|
||||
private VolumeTO getVolume(VirtualMachineTO vmSpec, VolumeType type) {
|
||||
private VolumeTO getVolume(VirtualMachineTO vmSpec, Volume.Type type) {
|
||||
VolumeTO volumes[] = vmSpec.getDisks();
|
||||
for (VolumeTO volume : volumes) {
|
||||
if (volume.getType() == type) {
|
||||
|
|
@ -2169,7 +2168,7 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
|
||||
List<DiskDef> disks = vm.getDevices().getDisks();
|
||||
DiskDef rootDisk = disks.get(0);
|
||||
VolumeTO rootVol = getVolume(vmSpec, VolumeType.ROOT);
|
||||
VolumeTO rootVol = getVolume(vmSpec, Volume.Type.ROOT);
|
||||
StoragePool pool = _storageResource.getStoragePool(conn, rootVol.getPoolUuid());
|
||||
StorageVol tmplVol = _storageResource.createTmplDataDisk(conn, pool, 10L * 1024 * 1024);
|
||||
String datadiskPath = tmplVol.getKey();
|
||||
|
|
@ -3258,8 +3257,9 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv
|
|||
cmd.add("--vmmac", mac);
|
||||
cmd.add("--vif", vif);
|
||||
cmd.add("--brname", brname);
|
||||
if (rules != null)
|
||||
cmd.add("--rules", newRules);
|
||||
if (rules != null) {
|
||||
cmd.add("--rules", newRules);
|
||||
}
|
||||
String result = cmd.execute();
|
||||
if (result != null) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public class VolumeTO {
|
|||
private String mountPoint;
|
||||
private String path;
|
||||
private long size;
|
||||
private Volume.VolumeType type;
|
||||
private Volume.Type type;
|
||||
private Storage.StorageResourceType resourceType;
|
||||
private StoragePoolType storagePoolType;
|
||||
private String storagePoolUuid;
|
||||
|
|
@ -39,7 +39,7 @@ public class VolumeTO {
|
|||
private String chainInfo;
|
||||
private String guestOsType;
|
||||
|
||||
public VolumeTO(long id, Volume.VolumeType type, Storage.StorageResourceType resourceType, StoragePoolType poolType,
|
||||
public VolumeTO(long id, Volume.Type type, Storage.StorageResourceType resourceType, StoragePoolType poolType,
|
||||
String poolUuid, String name, String mountPoint, String path, long size, String chainInfo) {
|
||||
this.id = id;
|
||||
this.name= name;
|
||||
|
|
@ -53,7 +53,7 @@ public class VolumeTO {
|
|||
this.chainInfo = chainInfo;
|
||||
}
|
||||
|
||||
public VolumeTO(long id, Volume.VolumeType type, Storage.StorageResourceType resourceType, StoragePoolType poolType,
|
||||
public VolumeTO(long id, Volume.Type type, Storage.StorageResourceType resourceType, StoragePoolType poolType,
|
||||
String poolUuid, String name, String mountPoint, String path, long size, String chainInfo, String guestOsType) {
|
||||
this.id = id;
|
||||
this.name= name;
|
||||
|
|
@ -107,7 +107,7 @@ public class VolumeTO {
|
|||
return size;
|
||||
}
|
||||
|
||||
public Volume.VolumeType getType() {
|
||||
public Volume.Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,14 +22,13 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import com.cloud.acl.ControlledEntity;
|
||||
import com.cloud.async.AsyncInstanceCreateStatus;
|
||||
import com.cloud.template.BasedOn;
|
||||
import com.cloud.utils.fsm.FiniteState;
|
||||
import com.cloud.utils.fsm.StateMachine;
|
||||
|
||||
|
||||
public interface Volume extends ControlledEntity, BasedOn {
|
||||
enum VolumeType {UNKNOWN, ROOT, SWAP, DATADISK, ISO};
|
||||
enum Type {UNKNOWN, ROOT, SWAP, DATADISK, ISO};
|
||||
|
||||
enum State implements FiniteState<State, Event> {
|
||||
Allocated("The volume is allocated but has not been created yet."),
|
||||
|
|
@ -119,7 +118,7 @@ public interface Volume extends ControlledEntity, BasedOn {
|
|||
|
||||
long getDataCenterId();
|
||||
|
||||
VolumeType getVolumeType();
|
||||
Type getVolumeType();
|
||||
|
||||
Storage.StorageResourceType getStorageResourceType();
|
||||
|
||||
|
|
@ -132,7 +131,6 @@ public interface Volume extends ControlledEntity, BasedOn {
|
|||
Long getDeviceId();
|
||||
|
||||
Date getCreated();
|
||||
AsyncInstanceCreateStatus getStatus();
|
||||
|
||||
long getDiskOfferingId();
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import com.cloud.storage.Volume;
|
|||
public class DiskProfile {
|
||||
private long size;
|
||||
private String[] tags;
|
||||
private Volume.VolumeType type;
|
||||
private Volume.Type type;
|
||||
private String name;
|
||||
private boolean useLocalStorage;
|
||||
private boolean recreatable;
|
||||
|
|
@ -43,7 +43,7 @@ public class DiskProfile {
|
|||
protected DiskProfile() {
|
||||
}
|
||||
|
||||
public DiskProfile(long volumeId, Volume.VolumeType type, String name, long diskOfferingId, long size, String[] tags, boolean useLocalStorage, boolean recreatable, Long templateId) {
|
||||
public DiskProfile(long volumeId, Volume.Type type, String name, long diskOfferingId, long size, String[] tags, boolean useLocalStorage, boolean recreatable, Long templateId) {
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
|
|
@ -91,7 +91,7 @@ public class DiskProfile {
|
|||
/**
|
||||
* @return type of volume.
|
||||
*/
|
||||
public Volume.VolumeType getType() {
|
||||
public Volume.Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,7 +175,6 @@ import com.cloud.storage.Storage;
|
|||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.resource.StoragePoolResource;
|
||||
import com.cloud.storage.template.TemplateInfo;
|
||||
|
|
@ -292,8 +291,9 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
for (Map.Entry<VM, VM.Record> entry : vms.entrySet()) {
|
||||
VM vm = entry.getKey();
|
||||
VM.Record vmRec = entry.getValue();
|
||||
if ( vmRec.isATemplate || vmRec.isControlDomain )
|
||||
if ( vmRec.isATemplate || vmRec.isControlDomain ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (VmPowerState.HALTED.equals(vmRec.powerState) && vmRec.affinity.equals(host)) {
|
||||
try {
|
||||
|
|
@ -690,7 +690,7 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
}
|
||||
|
||||
protected VDI mount(Connection conn, String vmName, VolumeTO volume) throws XmlRpcException, XenAPIException {
|
||||
if (volume.getType() == VolumeType.ISO) {
|
||||
if (volume.getType() == Volume.Type.ISO) {
|
||||
|
||||
String isopath = volume.getPath();
|
||||
if (isopath == null) {
|
||||
|
|
@ -721,7 +721,7 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
}
|
||||
|
||||
protected VBD createVbd(Connection conn, VolumeTO volume, String vmName, VM vm, BootloaderType bootLoaderType) throws XmlRpcException, XenAPIException {
|
||||
VolumeType type = volume.getType();
|
||||
Volume.Type type = volume.getType();
|
||||
|
||||
VDI vdi = mount(conn, vmName, volume);
|
||||
|
||||
|
|
@ -732,17 +732,17 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
} else {
|
||||
vbdr.empty = true;
|
||||
}
|
||||
if (type == VolumeType.ROOT && bootLoaderType == BootloaderType.PyGrub) {
|
||||
if (type == Volume.Type.ROOT && bootLoaderType == BootloaderType.PyGrub) {
|
||||
vbdr.bootable = true;
|
||||
}else if(type == VolumeType.ISO && bootLoaderType == BootloaderType.CD) {
|
||||
}else if(type == Volume.Type.ISO && bootLoaderType == BootloaderType.CD) {
|
||||
vbdr.bootable = true;
|
||||
}
|
||||
|
||||
vbdr.userdevice = Long.toString(volume.getDeviceId());
|
||||
if (volume.getType() == VolumeType.ISO) {
|
||||
if (volume.getType() == Volume.Type.ISO) {
|
||||
vbdr.mode = Types.VbdMode.RO;
|
||||
vbdr.type = Types.VbdType.CD;
|
||||
} else if (volume.getType() == VolumeType.ROOT) {
|
||||
} else if (volume.getType() == Volume.Type.ROOT) {
|
||||
vbdr.mode = Types.VbdMode.RW;
|
||||
vbdr.type = Types.VbdType.DISK;
|
||||
vbdr.unpluggable = false;
|
||||
|
|
@ -825,7 +825,7 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
if (vmSpec.getBootloader() == BootloaderType.CD) {
|
||||
VolumeTO [] disks = vmSpec.getDisks();
|
||||
for (VolumeTO disk : disks) {
|
||||
if (disk.getType() == Volume.VolumeType.ISO && disk.getOsType() != null) {
|
||||
if (disk.getType() == Volume.Type.ISO && disk.getOsType() != null) {
|
||||
String isoGuestOsName = getGuestOsType(disk.getOsType(), vmSpec.getBootloader() == BootloaderType.CD);
|
||||
if (!isoGuestOsName.equals(guestOsTypeName)) {
|
||||
vmSpec.setBootloader(BootloaderType.PyGrub);
|
||||
|
|
@ -970,8 +970,9 @@ public abstract class CitrixResourceBase implements ServerResource {
|
|||
c = c.startsWith("/") ? c.substring(1) : c;
|
||||
c = c.endsWith("/") ? c.substring(0, c.length() - 1) : c;
|
||||
String[] p = c.split(";");
|
||||
if (p.length != 2)
|
||||
if (p.length != 2) {
|
||||
continue;
|
||||
}
|
||||
if (p[0].equalsIgnoreCase("vlans")) {
|
||||
p[1] = p[1].replace("@", "[");
|
||||
p[1] = p[1].replace("#", "]");
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ import javax.persistence.TableGenerator;
|
|||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import com.cloud.async.AsyncInstanceCreateStatus;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.utils.NumbersUtil;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
|
@ -72,9 +71,6 @@ public class VolumeVO implements Volume {
|
|||
@Column(name="path")
|
||||
String path;
|
||||
|
||||
@Column(name="iscsi_name")
|
||||
String iscsiName;
|
||||
|
||||
@Column(name="pod_id")
|
||||
Long podId;
|
||||
|
||||
|
|
@ -102,7 +98,7 @@ public class VolumeVO implements Volume {
|
|||
|
||||
@Column(name="volume_type")
|
||||
@Enumerated(EnumType.STRING)
|
||||
VolumeType volumeType = Volume.VolumeType.UNKNOWN;
|
||||
Type volumeType = Volume.Type.UNKNOWN;
|
||||
|
||||
@Column(name="pool_type")
|
||||
@Enumerated(EnumType.STRING)
|
||||
|
|
@ -115,10 +111,6 @@ public class VolumeVO implements Volume {
|
|||
@Enumerated(EnumType.STRING)
|
||||
Storage.StorageResourceType storageResourceType;
|
||||
|
||||
@Column(name="status", updatable = true, nullable=false)
|
||||
@Enumerated(value=EnumType.STRING)
|
||||
private AsyncInstanceCreateStatus status;
|
||||
|
||||
@Column(name="updated")
|
||||
@Temporal(value=TemporalType.TIMESTAMP)
|
||||
Date updated;
|
||||
|
|
@ -144,7 +136,7 @@ public class VolumeVO implements Volume {
|
|||
* @param domainId
|
||||
* @param size
|
||||
*/
|
||||
public VolumeVO(VolumeType type, long instanceId, String name, long dcId, long podId, long accountId, long domainId, long size) {
|
||||
public VolumeVO(Type type, long instanceId, String name, long dcId, long podId, long accountId, long domainId, long size) {
|
||||
this.volumeType = type;
|
||||
this.name = name;
|
||||
this.dataCenterId = dcId;
|
||||
|
|
@ -153,14 +145,13 @@ public class VolumeVO implements Volume {
|
|||
this.domainId = domainId;
|
||||
this.instanceId = instanceId;
|
||||
this.size = size;
|
||||
this.status = AsyncInstanceCreateStatus.Creating;
|
||||
this.templateId = null;
|
||||
this.storageResourceType = Storage.StorageResourceType.STORAGE_POOL;
|
||||
this.poolType = null;
|
||||
}
|
||||
|
||||
// Real Constructor
|
||||
public VolumeVO(VolumeType type, String name, long dcId, long domainId, long accountId, long diskOfferingId, long size) {
|
||||
public VolumeVO(Type type, String name, long dcId, long domainId, long accountId, long diskOfferingId, long size) {
|
||||
this.volumeType = type;
|
||||
this.name = name;
|
||||
this.dataCenterId = dcId;
|
||||
|
|
@ -168,7 +159,6 @@ public class VolumeVO implements Volume {
|
|||
this.domainId = domainId;
|
||||
this.size = size;
|
||||
this.diskOfferingId = diskOfferingId;
|
||||
this.status = AsyncInstanceCreateStatus.Creating;
|
||||
this.state = State.Allocated;
|
||||
}
|
||||
|
||||
|
|
@ -184,14 +174,14 @@ public class VolumeVO implements Volume {
|
|||
* @param accountId
|
||||
* @param domainId
|
||||
*/
|
||||
public VolumeVO(VolumeType type, long instanceId, long templateId, String name, long dcId, long podId, long accountId, long domainId, boolean recreatable) {
|
||||
public VolumeVO(Type type, long instanceId, long templateId, String name, long dcId, long podId, long accountId, long domainId, boolean recreatable) {
|
||||
this(type, instanceId, name, dcId, podId, accountId, domainId, 0l);
|
||||
this.templateId = templateId;
|
||||
this.recreatable = recreatable;
|
||||
}
|
||||
|
||||
|
||||
public VolumeVO(String name, long dcId, long podId, long accountId, long domainId, Long instanceId, String folder, String path, long size, Volume.VolumeType vType) {
|
||||
public VolumeVO(String name, long dcId, long podId, long accountId, long domainId, Long instanceId, String folder, String path, long size, Volume.Type vType) {
|
||||
this.name = name;
|
||||
this.accountId = accountId;
|
||||
this.domainId = domainId;
|
||||
|
|
@ -202,7 +192,6 @@ public class VolumeVO implements Volume {
|
|||
this.podId = podId;
|
||||
this.dataCenterId = dcId;
|
||||
this.volumeType = vType;
|
||||
this.status = AsyncInstanceCreateStatus.Created;
|
||||
this.recreatable = false;
|
||||
}
|
||||
|
||||
|
|
@ -215,10 +204,6 @@ public class VolumeVO implements Volume {
|
|||
this.recreatable = recreatable;
|
||||
}
|
||||
|
||||
public String getIscsiName() {
|
||||
return iscsiName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getId() {
|
||||
return id;
|
||||
|
|
@ -294,7 +279,7 @@ public class VolumeVO implements Volume {
|
|||
}
|
||||
|
||||
@Override
|
||||
public VolumeType getVolumeType() {
|
||||
public Type getVolumeType() {
|
||||
return volumeType;
|
||||
}
|
||||
|
||||
|
|
@ -330,10 +315,6 @@ public class VolumeVO implements Volume {
|
|||
this.hostip = hostip;
|
||||
}
|
||||
|
||||
public void setIscsiName(String iscsiName) {
|
||||
this.iscsiName = iscsiName;
|
||||
}
|
||||
|
||||
public void setPodId(Long podId) {
|
||||
this.podId = podId;
|
||||
}
|
||||
|
|
@ -342,7 +323,7 @@ public class VolumeVO implements Volume {
|
|||
this.dataCenterId = dataCenterId;
|
||||
}
|
||||
|
||||
public void setVolumeType(VolumeType type) {
|
||||
public void setVolumeType(Type type) {
|
||||
volumeType = type;
|
||||
}
|
||||
|
||||
|
|
@ -403,15 +384,6 @@ public class VolumeVO implements Volume {
|
|||
this.poolId = poolId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsyncInstanceCreateStatus getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(AsyncInstanceCreateStatus status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public Date getUpdated() {
|
||||
return updated;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ import com.cloud.host.dao.HostDao;
|
|||
import com.cloud.storage.dao.VolumeDao;
|
||||
import com.cloud.utils.db.GlobalLock;
|
||||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.dao.VMInstanceDao;
|
||||
|
||||
public class AgentMonitor extends Thread implements Listener {
|
||||
|
|
@ -135,21 +134,7 @@ public class AgentMonitor extends Thread implements Listener {
|
|||
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "Migration Complete for host " + hostDesc, "Host [" + hostDesc + "] is ready for maintenance");
|
||||
_hostDao.updateStatus(host, Event.PreparationComplete, _msId);
|
||||
}
|
||||
} else {
|
||||
List<Long> ids = _volDao.findVmsStoredOnHost(hostId);
|
||||
boolean stillWorking = false;
|
||||
for (Long id : ids) {
|
||||
VMInstanceVO instance = _vmDao.findById(id);
|
||||
if (instance != null && (instance.getState() == VirtualMachine.State.Starting || instance.getState() == VirtualMachine.State.Stopping || instance.getState() == VirtualMachine.State.Running || instance.getState() == VirtualMachine.State.Migrating)) {
|
||||
stillWorking = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!stillWorking) {
|
||||
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, host.getDataCenterId(), host.getPodId(), "All VMs Stopped for host " + hostDesc, "Host [" + hostDesc + "] is ready for maintenance");
|
||||
_hostDao.updateStatus(host, Event.PreparationComplete, _msId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
s_logger.error("Caught the following exception: ", th);
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ import com.cloud.storage.StorageStats;
|
|||
import com.cloud.storage.UploadVO;
|
||||
import com.cloud.storage.VMTemplateHostVO;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
import com.cloud.storage.dao.GuestOSCategoryDao;
|
||||
|
|
@ -374,7 +374,7 @@ public class ApiDBUtils {
|
|||
}
|
||||
|
||||
public static VolumeVO findRootVolume(long vmId) {
|
||||
List<VolumeVO> volumes = _volumeDao.findByInstanceAndType(vmId, VolumeType.ROOT);
|
||||
List<VolumeVO> volumes = _volumeDao.findByInstanceAndType(vmId, Type.ROOT);
|
||||
if (volumes != null && volumes.size() == 1) {
|
||||
return volumes.get(0);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -818,14 +818,14 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
}
|
||||
|
||||
volResponse.setStorageType(storageType);
|
||||
if (volume.getVolumeType().equals(Volume.VolumeType.ROOT)) {
|
||||
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
|
||||
volResponse.setServiceOfferingId(volume.getDiskOfferingId());
|
||||
} else {
|
||||
volResponse.setDiskOfferingId(volume.getDiskOfferingId());
|
||||
}
|
||||
|
||||
DiskOfferingVO diskOffering = ApiDBUtils.findDiskOfferingById(volume.getDiskOfferingId());
|
||||
if (volume.getVolumeType().equals(Volume.VolumeType.ROOT)) {
|
||||
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
|
||||
volResponse.setServiceOfferingName(diskOffering.getName());
|
||||
volResponse.setServiceOfferingDisplayText(diskOffering.getDisplayText());
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import java.util.Date;
|
|||
|
||||
import com.cloud.async.AsyncInstanceCreateStatus;
|
||||
import com.cloud.serializer.Param;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.storage.upload.UploadState;
|
||||
|
||||
public class ExtractJobResultObject {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import com.cloud.migration.DiskOffering21VO.Type;
|
|||
import com.cloud.network.Network;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.StoragePoolVO;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.StoragePoolDao;
|
||||
import com.cloud.storage.dao.VolumeDao;
|
||||
|
|
@ -674,11 +674,11 @@ public class Db20to21MigrationUtil {
|
|||
List<VolumeVO> volumes = _volumeDao.searchIncludingRemoved(sc2, null, false, false);
|
||||
deviceId = 1; // reset for each VM iteration
|
||||
for(VolumeVO vol : volumes) {
|
||||
if(vol.getVolumeType() == VolumeType.ROOT) {
|
||||
if(vol.getVolumeType() == Volume.Type.ROOT) {
|
||||
System.out.println("Setting root volume device id to zero, vol: " + vol.getName() + ", instance: " + vm.getName());
|
||||
|
||||
vol.setDeviceId(0L);
|
||||
} else if(vol.getVolumeType() == VolumeType.DATADISK) {
|
||||
} else if(vol.getVolumeType() == Volume.Type.DATADISK) {
|
||||
System.out.println("Setting data volume device id, vol: " + vol.getName() + ", instance: " + vm.getName() + ", device id: " + deviceId);
|
||||
|
||||
vol.setDeviceId(deviceId);
|
||||
|
|
|
|||
|
|
@ -2422,9 +2422,6 @@ public class ManagementServerImpl implements ManagementServer {
|
|||
sb.and("domPNameLabel", sb.entity().getName(), SearchCriteria.Op.NLIKE);
|
||||
sb.and("domSNameLabel", sb.entity().getName(), SearchCriteria.Op.NLIKE);
|
||||
|
||||
// Only return Volumes that are in the "Created" state
|
||||
sb.and("status", sb.entity().getStatus(), SearchCriteria.Op.EQ);
|
||||
|
||||
// Only return volumes that are not destroyed
|
||||
sb.and("state", sb.entity().getState(), SearchCriteria.Op.NEQ);
|
||||
|
||||
|
|
@ -4322,7 +4319,7 @@ public class ManagementServerImpl implements ManagementServer {
|
|||
@Override
|
||||
public VolumeVO getRootVolume(Long instanceId)
|
||||
{
|
||||
return _volumeDao.findByInstanceAndType(instanceId, Volume.VolumeType.ROOT).get(0);
|
||||
return _volumeDao.findByInstanceAndType(instanceId, Volume.Type.ROOT).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import com.cloud.host.Host;
|
|||
import com.cloud.host.HostVO;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.service.ServiceOfferingVO;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.user.Account;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.component.Manager;
|
||||
|
|
@ -170,8 +170,8 @@ public interface StorageManager extends Manager {
|
|||
* @param account
|
||||
* @return VolumeVO a persisted volume.
|
||||
*/
|
||||
<T extends VMInstanceVO> DiskProfile allocateRawVolume(VolumeType type, String name, DiskOfferingVO offering, Long size, T vm, Account owner);
|
||||
<T extends VMInstanceVO> DiskProfile allocateTemplatedVolume(VolumeType type, String name, DiskOfferingVO offering, VMTemplateVO template, T vm, Account owner);
|
||||
<T extends VMInstanceVO> DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, T vm, Account owner);
|
||||
<T extends VMInstanceVO> DiskProfile allocateTemplatedVolume(Type type, String name, DiskOfferingVO offering, VMTemplateVO template, T vm, Account owner);
|
||||
|
||||
void createCapacityEntry(StoragePoolVO storagePool, long allocated);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Formatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
|
@ -72,7 +71,6 @@ import com.cloud.api.commands.DeletePoolCmd;
|
|||
import com.cloud.api.commands.DeleteVolumeCmd;
|
||||
import com.cloud.api.commands.PreparePrimaryStorageForMaintenanceCmd;
|
||||
import com.cloud.api.commands.UpdateStoragePoolCmd;
|
||||
import com.cloud.async.AsyncInstanceCreateStatus;
|
||||
import com.cloud.async.AsyncJobManager;
|
||||
import com.cloud.capacity.Capacity;
|
||||
import com.cloud.capacity.CapacityVO;
|
||||
|
|
@ -126,7 +124,7 @@ import com.cloud.service.dao.ServiceOfferingDao;
|
|||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.Storage.StorageResourceType;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.storage.allocator.StoragePoolAllocator;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
import com.cloud.storage.dao.SnapshotDao;
|
||||
|
|
@ -177,7 +175,6 @@ import com.cloud.vm.UserVmVO;
|
|||
import com.cloud.vm.VMInstanceVO;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.VirtualMachine.Type;
|
||||
import com.cloud.vm.VirtualMachineManager;
|
||||
import com.cloud.vm.VirtualMachineProfile;
|
||||
import com.cloud.vm.dao.ConsoleProxyDao;
|
||||
|
|
@ -243,7 +240,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
protected Adapters<StoragePoolDiscoverer> _discoverers;
|
||||
|
||||
protected SearchBuilder<VMTemplateHostVO> HostTemplateStatesSearch;
|
||||
protected SearchBuilder<StoragePoolVO> PoolsUsedByVmSearch;
|
||||
protected GenericSearchBuilder<StoragePoolHostVO, Long> UpHostsInPoolSearch;
|
||||
|
||||
ScheduledExecutorService _executor = null;
|
||||
|
|
@ -262,7 +258,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
public boolean share(VMInstanceVO vm, List<VolumeVO> vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException {
|
||||
|
||||
// if pool is in maintenance and it is the ONLY pool available; reject
|
||||
List<VolumeVO> rootVolForGivenVm = _volsDao.findByInstanceAndType(vm.getId(), VolumeType.ROOT);
|
||||
List<VolumeVO> rootVolForGivenVm = _volsDao.findByInstanceAndType(vm.getId(), Type.ROOT);
|
||||
if (rootVolForGivenVm != null && rootVolForGivenVm.size() > 0) {
|
||||
boolean isPoolAvailable = isPoolAvailable(rootVolForGivenVm.get(0).getPoolId());
|
||||
if (!isPoolAvailable) {
|
||||
|
|
@ -384,7 +380,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
}
|
||||
|
||||
protected DiskProfile createDiskCharacteristics(VolumeVO volume, VMTemplateVO template, DataCenterVO dc, DiskOfferingVO diskOffering) {
|
||||
if (volume.getVolumeType() == VolumeType.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
|
||||
if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
|
||||
SearchCriteria<VMTemplateHostVO> sc = HostTemplateStatesSearch.create();
|
||||
sc.setParameters("id", template.getId());
|
||||
sc.setParameters("state", com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
|
||||
|
|
@ -494,7 +490,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
createdVolume = _volsDao.findById(volumeId);
|
||||
|
||||
if (success) {
|
||||
createdVolume.setStatus(AsyncInstanceCreateStatus.Created);
|
||||
createdVolume.setPodId(pod.first().getId());
|
||||
createdVolume.setPoolId(pool.getId());
|
||||
createdVolume.setPoolType(pool.getPoolType());
|
||||
|
|
@ -503,7 +498,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
createdVolume.setDomainId(account.getDomainId());
|
||||
createdVolume.setState(Volume.State.Ready);
|
||||
} else {
|
||||
createdVolume.setStatus(AsyncInstanceCreateStatus.Corrupted);
|
||||
createdVolume.setState(Volume.State.Destroy);
|
||||
}
|
||||
|
||||
|
|
@ -617,7 +611,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
diskOffering.setDiskSize(size);
|
||||
}
|
||||
DiskProfile dskCh = null;
|
||||
if (volume.getVolumeType() == VolumeType.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
|
||||
if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
|
||||
dskCh = createDiskCharacteristics(volume, template, dc, offering);
|
||||
} else {
|
||||
dskCh = createDiskCharacteristics(volume, template, dc, diskOffering);
|
||||
|
|
@ -652,7 +646,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
VMTemplateStoragePoolVO tmpltStoredOn = null;
|
||||
|
||||
for(int i = 0; i < 2; i++) {
|
||||
if (volume.getVolumeType() == VolumeType.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
|
||||
if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
|
||||
tmpltStoredOn = _tmpltMgr.prepareTemplateForCreate(template, pool);
|
||||
if (tmpltStoredOn == null) {
|
||||
continue;
|
||||
|
|
@ -696,14 +690,12 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Unable to create a volume for " + volume);
|
||||
}
|
||||
volume.setStatus(AsyncInstanceCreateStatus.Failed);
|
||||
volume.setState(Volume.State.Destroy);
|
||||
_volsDao.persist(volume);
|
||||
_volsDao.remove(volume.getId());
|
||||
volume = null;
|
||||
|
||||
} else {
|
||||
volume.setStatus(AsyncInstanceCreateStatus.Created);
|
||||
volume.setFolder(pool.getPath());
|
||||
volume.setPath(created.getPath());
|
||||
volume.setSize(created.getSize());
|
||||
|
|
@ -788,15 +780,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
String maxVolumeSizeInGbString = configDao.getValue("storage.max.volume.size");
|
||||
_maxVolumeSizeInGb = NumbersUtil.parseInt(maxVolumeSizeInGbString, 2000);
|
||||
|
||||
PoolsUsedByVmSearch = _storagePoolDao.createSearchBuilder();
|
||||
SearchBuilder<VolumeVO> volSearch = _volsDao.createSearchBuilder();
|
||||
PoolsUsedByVmSearch.join("volumes", volSearch, volSearch.entity().getPoolId(), PoolsUsedByVmSearch.entity().getId(),
|
||||
JoinBuilder.JoinType.INNER);
|
||||
volSearch.and("vm", volSearch.entity().getInstanceId(), SearchCriteria.Op.EQ);
|
||||
volSearch.and("status", volSearch.entity().getStatus(), SearchCriteria.Op.EQ);
|
||||
volSearch.done();
|
||||
PoolsUsedByVmSearch.done();
|
||||
|
||||
HostTemplateStatesSearch = _vmTemplateHostDao.createSearchBuilder();
|
||||
HostTemplateStatesSearch.and("id", HostTemplateStatesSearch.entity().getTemplateId(), SearchCriteria.Op.EQ);
|
||||
HostTemplateStatesSearch.and("state", HostTemplateStatesSearch.entity().getDownloadState(), SearchCriteria.Op.EQ);
|
||||
|
|
@ -822,13 +805,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
return true;
|
||||
}
|
||||
|
||||
public String getVolumeFolder(String parentDir, long accountId, String diskFolderName) {
|
||||
StringBuilder diskFolderBuilder = new StringBuilder();
|
||||
Formatter diskFolderFormatter = new Formatter(diskFolderBuilder);
|
||||
diskFolderFormatter.format("%s/u%06d/%s", parentDir, accountId, diskFolderName);
|
||||
return diskFolderBuilder.toString();
|
||||
}
|
||||
|
||||
public String getRandomVolumeName() {
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
|
@ -1566,7 +1542,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
userSpecifiedName = getRandomVolumeName();
|
||||
}
|
||||
|
||||
VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.VolumeType.DATADISK);
|
||||
VolumeVO volume = new VolumeVO(userSpecifiedName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK);
|
||||
volume.setPoolId(null);
|
||||
volume.setDataCenterId(zoneId);
|
||||
volume.setPodId(null);
|
||||
|
|
@ -1577,7 +1553,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
volume.setStorageResourceType(StorageResourceType.STORAGE_POOL);
|
||||
volume.setInstanceId(null);
|
||||
volume.setUpdated(new Date());
|
||||
volume.setStatus(AsyncInstanceCreateStatus.Creating);
|
||||
volume.setDomainId((account == null) ? Domain.ROOT_DOMAIN : account.getDomainId());
|
||||
volume.setState(Volume.State.Allocated);
|
||||
volume = _volsDao.persist(volume);
|
||||
|
|
@ -1604,14 +1579,12 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
if (cmd.getSnapshotId() != null) {
|
||||
return createVolumeFromSnapshot(volume, cmd.getSnapshotId());
|
||||
} else {
|
||||
|
||||
volume.setStatus(AsyncInstanceCreateStatus.Created);
|
||||
_volsDao.update(volume.getId(), volume);
|
||||
}
|
||||
|
||||
return _volsDao.findById(volume.getId());
|
||||
} finally {
|
||||
if (volume.getStatus() != AsyncInstanceCreateStatus.Created) {
|
||||
if (volume.getState() != Volume.State.Ready) {
|
||||
s_logger.trace("Decrementing volume resource count for account id=" + volume.getAccountId() + " as volume failed to create on the backend");
|
||||
_accountMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume);
|
||||
}
|
||||
|
|
@ -2340,7 +2313,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T extends VMInstanceVO> DiskProfile allocateRawVolume(VolumeType type, String name, DiskOfferingVO offering, Long size, T vm,
|
||||
public <T extends VMInstanceVO> DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, T vm,
|
||||
Account owner) {
|
||||
if (size == null) {
|
||||
size = offering.getDiskSizeInBytes();
|
||||
|
|
@ -2352,7 +2325,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
vol.setInstanceId(vm.getId());
|
||||
}
|
||||
|
||||
if (type.equals(VolumeType.ROOT)) {
|
||||
if (type.equals(Type.ROOT)) {
|
||||
vol.setDeviceId(0l);
|
||||
} else {
|
||||
vol.setDeviceId(1l);
|
||||
|
|
@ -2373,7 +2346,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
}
|
||||
|
||||
@Override
|
||||
public <T extends VMInstanceVO> DiskProfile allocateTemplatedVolume(VolumeType type, String name, DiskOfferingVO offering, VMTemplateVO template,
|
||||
public <T extends VMInstanceVO> DiskProfile allocateTemplatedVolume(Type type, String name, DiskOfferingVO offering, VMTemplateVO template,
|
||||
T vm, Account owner) {
|
||||
assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really....";
|
||||
|
||||
|
|
@ -2394,9 +2367,9 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
}
|
||||
vol.setTemplateId(template.getId());
|
||||
|
||||
if (type.equals(VolumeType.ROOT)) {
|
||||
if (type.equals(Type.ROOT)) {
|
||||
vol.setDeviceId(0l);
|
||||
if (!vm.getType().equals(Type.User)) {
|
||||
if (!vm.getType().equals(VirtualMachine.Type.User)) {
|
||||
vol.setRecreatable(true);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -2441,7 +2414,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
Pair<String, String> isoPathPair = getAbsoluteIsoPath(userVM.getIsoId(), userVM.getDataCenterId());
|
||||
if (isoPathPair != null) {
|
||||
String isoPath = isoPathPair.first();
|
||||
VolumeTO iso = new VolumeTO(vm.getId(), Volume.VolumeType.ISO, StorageResourceType.STORAGE_POOL, StoragePoolType.ISO, null, null, null, isoPath,
|
||||
VolumeTO iso = new VolumeTO(vm.getId(), Volume.Type.ISO, StorageResourceType.STORAGE_POOL, StoragePoolType.ISO, null, null, null, isoPath,
|
||||
0, null, null);
|
||||
vm.addDisk(iso);
|
||||
}
|
||||
|
|
@ -2531,7 +2504,6 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
throw new StorageUnavailableException("Unable to create " + newVol, poolId == null ? -1L : poolId);
|
||||
}
|
||||
created.first().setDeviceId(newVol.getDeviceId().intValue());
|
||||
newVol.setStatus(AsyncInstanceCreateStatus.Created);
|
||||
newVol.setFolder(created.second().getPath());
|
||||
newVol.setPath(created.first().getPath());
|
||||
newVol.setSize(created.first().getSize());
|
||||
|
|
@ -2636,7 +2608,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
s_logger.debug("Expunging " + vol);
|
||||
}
|
||||
String vmName = null;
|
||||
if (vol.getVolumeType() == VolumeType.ROOT && vol.getInstanceId() != null) {
|
||||
if (vol.getVolumeType() == Type.ROOT && vol.getInstanceId() != null) {
|
||||
VirtualMachine vm = _vmInstanceDao.findByIdIncludingRemoved(vol.getInstanceId());
|
||||
if (vm != null) {
|
||||
vmName = vm.getInstanceName();
|
||||
|
|
@ -2688,7 +2660,7 @@ public class StorageManagerImpl implements StorageManager, StorageService, Manag
|
|||
Transaction txn = Transaction.currentTxn();
|
||||
txn.start();
|
||||
for (VolumeVO vol : volumesForVm) {
|
||||
if (vol.getVolumeType().equals(VolumeType.ROOT)) {
|
||||
if (vol.getVolumeType().equals(Type.ROOT)) {
|
||||
//This check is for VM in Error state (volume is already destroyed)
|
||||
if(!vol.getState().equals(Volume.State.Destroy)){
|
||||
destroyVolume(vol);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ import com.cloud.storage.VMTemplateStoragePoolVO;
|
|||
import com.cloud.storage.VMTemplateStorageResourceAssoc;
|
||||
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.storage.dao.StoragePoolDao;
|
||||
import com.cloud.storage.dao.StoragePoolHostDao;
|
||||
import com.cloud.storage.dao.VMTemplateDao;
|
||||
|
|
@ -144,7 +144,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement
|
|||
}
|
||||
return false;
|
||||
}
|
||||
if(dskCh.getType().equals(VolumeType.ROOT) && pool.getPoolType().equals(StoragePoolType.Iscsi)){
|
||||
if(dskCh.getType().equals(Type.ROOT) && pool.getPoolType().equals(StoragePoolType.Iscsi)){
|
||||
if (s_logger.isDebugEnabled()) {
|
||||
s_logger.debug("Disk needed for ROOT volume, but StoragePoolType is Iscsi, skipping this and trying other available pools");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import com.cloud.deploy.DeploymentPlan;
|
|||
import com.cloud.deploy.DeploymentPlanner.ExcludeList;
|
||||
import com.cloud.host.Host;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.template.VirtualMachineTemplate;
|
||||
import com.cloud.utils.component.ComponentLocator;
|
||||
import com.cloud.vm.DiskProfile;
|
||||
|
|
@ -70,9 +70,9 @@ public class UseLocalForRootAllocator extends LocalStoragePoolAllocator implemen
|
|||
|
||||
@Override
|
||||
protected boolean localStorageAllocationNeeded(DiskProfile dskCh) {
|
||||
if (dskCh.getType() == VolumeType.ROOT) {
|
||||
if (dskCh.getType() == Type.ROOT) {
|
||||
return true;
|
||||
} else if (dskCh.getType() == VolumeType.DATADISK) {
|
||||
} else if (dskCh.getType() == Type.DATADISK) {
|
||||
return false;
|
||||
} else {
|
||||
return super.localStorageAllocationNeeded(dskCh);
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ import java.util.List;
|
|||
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
||||
|
|
@ -32,11 +32,10 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long> {
|
|||
List<VolumeVO> findByAccount(long accountId);
|
||||
Pair<Long, Long> getCountAndTotalByPool(long poolId);
|
||||
List<VolumeVO> findByInstance(long id);
|
||||
List<VolumeVO> findByInstanceAndType(long id, Volume.VolumeType vType);
|
||||
List<VolumeVO> findByInstanceAndType(long id, Volume.Type vType);
|
||||
List<VolumeVO> findByInstanceIdDestroyed(long vmId);
|
||||
List<VolumeVO> findByAccountAndPod(long accountId, long podId);
|
||||
List<VolumeVO> findByTemplateAndZone(long templateId, long zoneId);
|
||||
List<Long> findVmsStoredOnHost(long hostId);
|
||||
void deleteVolumesByInstance(long instanceId);
|
||||
void attachVolume(long volumeId, long vmId, long deviceId);
|
||||
void detachVolume(long volumeId);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package com.cloud.storage.dao;
|
|||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -28,14 +27,11 @@ import javax.ejb.Local;
|
|||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.async.AsyncInstanceCreateStatus;
|
||||
import com.cloud.dc.ClusterVO;
|
||||
import com.cloud.exception.ConcurrentOperationException;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.storage.StoragePool;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.Storage.ImageFormat;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.utils.Pair;
|
||||
import com.cloud.utils.db.Attribute;
|
||||
|
|
@ -63,31 +59,8 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
protected final Attribute _stateAttr;
|
||||
|
||||
protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?";
|
||||
protected static final String SELECT_VM_ID_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ?";
|
||||
protected static final String SELECT_HYPERTYPE_FROM_VOLUME = "SELECT c.hypervisor_type from volumes v, storage_pool s, cluster c where v.pool_id = s.id and s.cluster_id = c.id and v.id = ?";
|
||||
|
||||
@Override @DB
|
||||
public List<Long> findVmsStoredOnHost(long hostId) {
|
||||
Transaction txn = Transaction.currentTxn();
|
||||
PreparedStatement pstmt = null;
|
||||
List<Long> result = new ArrayList<Long>();
|
||||
|
||||
try {
|
||||
String sql = SELECT_VM_ID_SQL;
|
||||
pstmt = txn.prepareAutoCloseStatement(sql);
|
||||
pstmt.setLong(1, hostId);
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
while (rs.next()) {
|
||||
result.add(rs.getLong(1));
|
||||
}
|
||||
return result;
|
||||
} catch (SQLException e) {
|
||||
throw new CloudRuntimeException("DB Exception on: " + SELECT_VM_SQL, e);
|
||||
} catch (Throwable e) {
|
||||
throw new CloudRuntimeException("Caught: " + SELECT_VM_SQL, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VolumeVO> findDetachedByAccount(long accountId) {
|
||||
SearchCriteria<VolumeVO> sc = DetachedAccountIdSearch.create();
|
||||
|
|
@ -124,7 +97,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("poolId", poolId);
|
||||
sc.setParameters("notDestroyed", Volume.State.Destroy);
|
||||
sc.setParameters("vType", Volume.VolumeType.ROOT.toString());
|
||||
sc.setParameters("vType", Volume.Type.ROOT.toString());
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
|
|
@ -132,8 +105,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
public List<VolumeVO> findCreatedByInstance(long id) {
|
||||
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("instanceId", id);
|
||||
sc.setParameters("status", AsyncInstanceCreateStatus.Created);
|
||||
sc.setParameters("notDestroyed", Volume.State.Destroy);
|
||||
sc.setParameters("state", Volume.State.Ready);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
|
|
@ -147,7 +119,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<VolumeVO> findByInstanceAndType(long id, VolumeType vType) {
|
||||
public List<VolumeVO> findByInstanceAndType(long id, Type vType) {
|
||||
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("instanceId", id);
|
||||
sc.setParameters("vType", vType.toString());
|
||||
|
|
@ -159,7 +131,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("instanceId", vmId);
|
||||
sc.setParameters("destroyed", Volume.State.Destroy);
|
||||
return listIncludingRemovedBy(sc);
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -167,8 +139,8 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("instanceId", instanceId);
|
||||
sc.setParameters("state", Volume.State.Ready);
|
||||
sc.setParameters("vType", Volume.VolumeType.ROOT.toString());
|
||||
return listIncludingRemovedBy(sc);
|
||||
sc.setParameters("vType", Volume.Type.ROOT.toString());
|
||||
return listBy(sc);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -176,8 +148,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
|
||||
sc.setParameters("accountId", accountId);
|
||||
sc.setParameters("pod", podId);
|
||||
sc.setParameters("notDestroyed", Volume.State.Destroy);
|
||||
sc.setParameters("status", AsyncInstanceCreateStatus.Created);
|
||||
sc.setParameters("state", Volume.State.Ready);
|
||||
|
||||
return listIncludingRemovedBy(sc);
|
||||
}
|
||||
|
|
@ -295,7 +266,6 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
|
|||
AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ);
|
||||
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ);
|
||||
AllFieldsSearch.and("pod", AllFieldsSearch.entity().getPodId(), Op.EQ);
|
||||
AllFieldsSearch.and("status", AllFieldsSearch.entity().getStatus(), Op.EQ);
|
||||
AllFieldsSearch.and("instanceId", AllFieldsSearch.entity().getInstanceId(), Op.EQ);
|
||||
AllFieldsSearch.and("deviceId", AllFieldsSearch.entity().getDeviceId(), Op.EQ);
|
||||
AllFieldsSearch.and("poolId", AllFieldsSearch.entity().getPoolId(), Op.EQ);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ import com.cloud.api.commands.DeleteSnapshotPoliciesCmd;
|
|||
import com.cloud.api.commands.ListRecurringSnapshotScheduleCmd;
|
||||
import com.cloud.api.commands.ListSnapshotPoliciesCmd;
|
||||
import com.cloud.api.commands.ListSnapshotsCmd;
|
||||
import com.cloud.async.AsyncInstanceCreateStatus;
|
||||
import com.cloud.async.AsyncJobManager;
|
||||
import com.cloud.configuration.ResourceCount.ResourceType;
|
||||
import com.cloud.configuration.dao.ConfigurationDao;
|
||||
|
|
@ -1164,8 +1163,8 @@ public class SnapshotManagerImpl implements SnapshotManager, SnapshotService, Ma
|
|||
if (volume == null) {
|
||||
throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volumeId + " doesn't exist");
|
||||
}
|
||||
if (volume.getStatus() != AsyncInstanceCreateStatus.Created) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in Created state but " + volume.getStatus() + ". Cannot take snapshot.");
|
||||
if (volume.getState() != Volume.State.Ready) {
|
||||
throw new InvalidParameterValueException("VolumeId: " + volumeId + " is not in Created state but " + volume.getState() + ". Cannot take snapshot.");
|
||||
}
|
||||
StoragePoolVO storagePoolVO = _storagePoolDao.findById(volume.getPoolId());
|
||||
if (storagePoolVO == null) {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ import com.cloud.api.commands.ResetVMPasswordCmd;
|
|||
import com.cloud.api.commands.StartVMCmd;
|
||||
import com.cloud.api.commands.UpdateVMCmd;
|
||||
import com.cloud.api.commands.UpgradeVMCmd;
|
||||
import com.cloud.async.AsyncInstanceCreateStatus;
|
||||
import com.cloud.async.AsyncJobExecutor;
|
||||
import com.cloud.async.AsyncJobManager;
|
||||
import com.cloud.async.AsyncJobVO;
|
||||
|
|
@ -149,7 +148,6 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
|
|||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.VMTemplateZoneVO;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.DiskOfferingDao;
|
||||
import com.cloud.storage.dao.GuestOSCategoryDao;
|
||||
|
|
@ -195,7 +193,6 @@ import com.cloud.utils.exception.CloudRuntimeException;
|
|||
import com.cloud.utils.exception.ExecutionException;
|
||||
import com.cloud.utils.net.NetUtils;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.VirtualMachine.Type;
|
||||
import com.cloud.vm.dao.DomainRouterDao;
|
||||
import com.cloud.vm.dao.InstanceGroupDao;
|
||||
import com.cloud.vm.dao.InstanceGroupVMMapDao;
|
||||
|
|
@ -416,7 +413,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
// Check that the volume ID is valid
|
||||
VolumeVO volume = _volsDao.findById(volumeId);
|
||||
// Check that the volume is a data volume
|
||||
if (volume == null || volume.getVolumeType() != VolumeType.DATADISK) {
|
||||
if (volume == null || volume.getVolumeType() != Volume.Type.DATADISK) {
|
||||
throw new InvalidParameterValueException("Please specify a valid data volume.");
|
||||
}
|
||||
|
||||
|
|
@ -454,7 +451,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
}
|
||||
|
||||
// Check that the VM has less than 6 data volumes attached
|
||||
List<VolumeVO> existingDataVolumes = _volsDao.findByInstanceAndType(vmId, VolumeType.DATADISK);
|
||||
List<VolumeVO> existingDataVolumes = _volsDao.findByInstanceAndType(vmId, Volume.Type.DATADISK);
|
||||
if (existingDataVolumes.size() >= 6) {
|
||||
throw new InvalidParameterValueException("The specified VM already has the maximum number of data disks (6). Please specify another VM.");
|
||||
}
|
||||
|
|
@ -488,7 +485,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
}
|
||||
|
||||
VolumeVO rootVolumeOfVm = null;
|
||||
List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, VolumeType.ROOT);
|
||||
List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, Volume.Type.ROOT);
|
||||
if (rootVolumesOfVm.size() != 1) {
|
||||
throw new CloudRuntimeException("The VM " + vm.getName() + " has more than one ROOT volume and is in an invalid state. Please contact Cloud Support.");
|
||||
} else {
|
||||
|
|
@ -686,7 +683,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
}
|
||||
|
||||
// Check that the volume is a data volume
|
||||
if (volume.getVolumeType() != VolumeType.DATADISK) {
|
||||
if (volume.getVolumeType() != Volume.Type.DATADISK) {
|
||||
throw new InvalidParameterValueException("Please specify a data volume.");
|
||||
}
|
||||
|
||||
|
|
@ -1025,7 +1022,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
// Recover the VM's disks
|
||||
List<VolumeVO> volumes = _volsDao.findByInstance(vmId);
|
||||
for (VolumeVO volume : volumes) {
|
||||
if (volume.getVolumeType().equals(VolumeType.ROOT)) {
|
||||
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
|
||||
// Create an event
|
||||
Long templateId = volume.getTemplateId();
|
||||
Long diskOfferingId = volume.getDiskOfferingId();
|
||||
|
|
@ -1078,7 +1075,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
|
||||
_executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("UserVm-Scavenger"));
|
||||
|
||||
_itMgr.registerGuru(Type.User, this);
|
||||
_itMgr.registerGuru(VirtualMachine.Type.User, this);
|
||||
|
||||
s_logger.info("User VM Manager is configured.");
|
||||
|
||||
|
|
@ -1539,7 +1536,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
for(VolumeVO volume : volumesForThisVm) {
|
||||
try {
|
||||
_storageMgr.destroyVolume(volume);
|
||||
if (volume.getStatus() == AsyncInstanceCreateStatus.Created) {
|
||||
if (volume.getState() == Volume.State.Ready) {
|
||||
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(),
|
||||
volume.getName());
|
||||
_usageEventDao.persist(usageEvent);
|
||||
|
|
@ -2434,14 +2431,14 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
if (guestOS != null) {
|
||||
displayName = guestOS.getDisplayName();
|
||||
}
|
||||
VolumeTO iso = new VolumeTO(profile.getId(), Volume.VolumeType.ISO, StorageResourceType.STORAGE_POOL, StoragePoolType.ISO, null, template.getName(), null, isoPath,
|
||||
VolumeTO iso = new VolumeTO(profile.getId(), Volume.Type.ISO, StorageResourceType.STORAGE_POOL, StoragePoolType.ISO, null, template.getName(), null, isoPath,
|
||||
0, null, displayName);
|
||||
|
||||
iso.setDeviceId(3);
|
||||
profile.addDisk(iso);
|
||||
} else {
|
||||
/*create a iso placeholder*/
|
||||
VolumeTO iso = new VolumeTO(profile.getId(), Volume.VolumeType.ISO, StorageResourceType.STORAGE_POOL, StoragePoolType.ISO, null, template.getName(), null, null,
|
||||
VolumeTO iso = new VolumeTO(profile.getId(), Volume.Type.ISO, StorageResourceType.STORAGE_POOL, StoragePoolType.ISO, null, template.getName(), null, null,
|
||||
0, null);
|
||||
iso.setDeviceId(3);
|
||||
profile.addDisk(iso);
|
||||
|
|
@ -2607,7 +2604,7 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
// Mark the account's volumes as destroyed
|
||||
List<VolumeVO> volumes = _volsDao.findByInstance(vmId);
|
||||
for (VolumeVO volume : volumes) {
|
||||
if (volume.getVolumeType().equals(VolumeType.ROOT)) {
|
||||
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
|
||||
UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(),
|
||||
volume.getName());
|
||||
_usageEventDao.persist(usageEvent);
|
||||
|
|
@ -2941,10 +2938,12 @@ public class UserVmManagerImpl implements UserVmManager, UserVmService, Manager
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserVm getUserVm(long vmId){
|
||||
return _vmDao.findById(vmId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserVm migrateVirtualMachine(UserVm vm, Host destinationHost) throws ResourceUnavailableException, ConcurrentOperationException, ManagementServerException{
|
||||
//access check - only root admin can migrate VM
|
||||
Account caller = UserContext.current().getCaller();
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import javax.naming.ConfigurationException;
|
|||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
|
||||
import com.cloud.agent.AgentManager;
|
||||
import com.cloud.agent.AgentManager.OnError;
|
||||
import com.cloud.agent.Listener;
|
||||
|
|
@ -83,7 +82,6 @@ import com.cloud.exception.ConcurrentOperationException;
|
|||
import com.cloud.exception.ConnectionException;
|
||||
import com.cloud.exception.InsufficientCapacityException;
|
||||
import com.cloud.exception.InsufficientServerCapacityException;
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
import com.cloud.exception.ManagementServerException;
|
||||
import com.cloud.exception.OperationTimedoutException;
|
||||
import com.cloud.exception.ResourceUnavailableException;
|
||||
|
|
@ -108,7 +106,7 @@ import com.cloud.storage.StorageManager;
|
|||
import com.cloud.storage.StoragePoolVO;
|
||||
import com.cloud.storage.VMTemplateVO;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.storage.Volume.VolumeType;
|
||||
import com.cloud.storage.Volume.Type;
|
||||
import com.cloud.storage.VolumeVO;
|
||||
import com.cloud.storage.dao.GuestOSCategoryDao;
|
||||
import com.cloud.storage.dao.GuestOSDao;
|
||||
|
|
@ -136,7 +134,6 @@ import com.cloud.utils.fsm.StateMachine2;
|
|||
import com.cloud.vm.ItWorkVO.Step;
|
||||
import com.cloud.vm.VirtualMachine.Event;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
import com.cloud.vm.VirtualMachine.Type;
|
||||
import com.cloud.vm.dao.ConsoleProxyDao;
|
||||
import com.cloud.vm.dao.DomainRouterDao;
|
||||
import com.cloud.vm.dao.NicDao;
|
||||
|
|
@ -256,14 +253,14 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
}
|
||||
|
||||
if (template.getFormat() == ImageFormat.ISO) {
|
||||
_storageMgr.allocateRawVolume(VolumeType.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner);
|
||||
_storageMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner);
|
||||
} else if (template.getFormat() == ImageFormat.BAREMETAL) {
|
||||
}else {
|
||||
_storageMgr.allocateTemplatedVolume(VolumeType.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner);
|
||||
_storageMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner);
|
||||
}
|
||||
|
||||
for (Pair<DiskOfferingVO, Long> offering : dataDiskOfferings) {
|
||||
_storageMgr.allocateRawVolume(VolumeType.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner);
|
||||
_storageMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner);
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
|
|
@ -309,7 +306,7 @@ public class VirtualMachineManagerImpl implements VirtualMachineManager, Listene
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends VMInstanceVO> VirtualMachineGuru<T> getBareMetalVmGuru(T vm) {
|
||||
return (VirtualMachineGuru<T>)_vmGurus.get(Type.UserBareMetal);
|
||||
return (VirtualMachineGuru<T>)_vmGurus.get(VirtualMachine.Type.UserBareMetal);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Reference in New Issue