Create DB view for Volume to speed up ListVolumesCmd.

Signed-off-by: Min Chen <min.chen@citrix.com>
This commit is contained in:
Min Chen 2012-12-25 17:08:50 -08:00
parent 78d70d349b
commit 21c1623a03
17 changed files with 1703 additions and 271 deletions

View File

@ -115,7 +115,6 @@ public interface StorageService{
Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException;
Pair<List<? extends Volume>, Integer> searchForVolumes(ListVolumesCmd cmd);
/**
* Uploads the volume to secondary storage

View File

@ -116,17 +116,7 @@ public class ListVolumesCmd extends BaseListTaggedResourcesCmd {
@Override
public void execute(){
Pair<List<? extends Volume>, Integer> volumes = _storageService.searchForVolumes(this);
ListResponse<VolumeResponse> response = new ListResponse<VolumeResponse>();
List<VolumeResponse> volResponses = new ArrayList<VolumeResponse>();
for (Volume volume : volumes.first()) {
VolumeResponse volResponse = _responseGenerator.createVolumeResponse(volume);
volResponse.setObjectName("volume");
volResponses.add(volResponse);
}
response.setResponses(volResponses, volumes.second());
ListResponse<VolumeResponse> response = _queryService.searchForVolumes(this);
response.setResponseName(getCommandName());
this.setResponseObject(response);
}

View File

@ -17,7 +17,9 @@
package org.apache.cloudstack.api.response;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.cloud.storage.Volume;
import org.apache.cloudstack.api.ApiConstants;
@ -28,7 +30,7 @@ import org.apache.cloudstack.api.Entity;
@Entity(value=Volume.class)
@SuppressWarnings("unused")
public class VolumeResponse extends BaseResponse implements ControlledEntityResponse{
public class VolumeResponse extends BaseResponse implements ControlledViewEntityResponse{
@SerializedName(ApiConstants.ID)
@Param(description = "ID of the disk volume")
private String id;
@ -156,9 +158,11 @@ public class VolumeResponse extends BaseResponse implements ControlledEntityResp
private String status;
@SerializedName(ApiConstants.TAGS) @Param(description="the list of resource tags associated with volume", responseObject = ResourceTagResponse.class)
private List<ResourceTagResponse> tags;
private Set<ResourceTagResponse> tags;
public VolumeResponse(){
tags = new HashSet<ResourceTagResponse>();
}
@Override
public String getObjectId() {
@ -304,7 +308,11 @@ public class VolumeResponse extends BaseResponse implements ControlledEntityResp
this.projectName = projectName;
}
public void setTags(List<ResourceTagResponse> tags) {
public void setTags(Set<ResourceTagResponse> tags) {
this.tags = tags;
}
public void addTag(ResourceTagResponse tag){
this.tags.add(tag);
}
}

View File

@ -27,6 +27,7 @@ import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCm
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
import org.apache.cloudstack.api.response.DomainRouterResponse;
import org.apache.cloudstack.api.response.EventResponse;
import org.apache.cloudstack.api.response.HostResponse;
@ -39,11 +40,11 @@ import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import com.cloud.async.AsyncJob;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.storage.Snapshot;
/**
* Service used for list api query.
@ -73,4 +74,6 @@ public interface QueryService {
public ListResponse<ProjectAccountResponse> listProjectAccounts(ListProjectAccountsCmd cmd);
public ListResponse<HostResponse> searchForServers(ListHostsCmd cmd);
public ListResponse<VolumeResponse> searchForVolumes(ListVolumesCmd cmd);
}

View File

@ -35,6 +35,7 @@ import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import com.cloud.api.query.dao.DomainRouterJoinDao;
import com.cloud.api.query.dao.HostJoinDao;
@ -45,6 +46,7 @@ import com.cloud.api.query.dao.ProjectJoinDao;
import com.cloud.api.query.dao.ResourceTagJoinDao;
import com.cloud.api.query.dao.SecurityGroupJoinDao;
import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.api.query.dao.VolumeJoinDao;
import com.cloud.api.query.vo.DomainRouterJoinVO;
import com.cloud.api.query.vo.EventJoinVO;
import com.cloud.api.query.vo.HostJoinVO;
@ -56,6 +58,7 @@ import com.cloud.api.query.vo.ResourceTagJoinVO;
import com.cloud.api.query.vo.SecurityGroupJoinVO;
import com.cloud.api.query.vo.UserAccountJoinVO;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.async.AsyncJob;
import com.cloud.async.AsyncJobManager;
import com.cloud.async.AsyncJobVO;
@ -180,6 +183,7 @@ import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.VMTemplateS3VO;
import com.cloud.storage.VMTemplateSwiftVO;
import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume;
import com.cloud.storage.Volume.Type;
import com.cloud.storage.VolumeHostVO;
import com.cloud.storage.VolumeVO;
@ -313,6 +317,7 @@ public class ApiDBUtils {
private static ProjectAccountJoinDao _projectAccountJoinDao;
private static ProjectInvitationJoinDao _projectInvitationJoinDao;
private static HostJoinDao _hostJoinDao;
private static VolumeJoinDao _volJoinDao;
private static PhysicalNetworkTrafficTypeDao _physicalNetworkTrafficTypeDao;
private static PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao;
@ -400,6 +405,7 @@ public class ApiDBUtils {
_projectAccountJoinDao = locator.getDao(ProjectAccountJoinDao.class);
_projectInvitationJoinDao = locator.getDao(ProjectInvitationJoinDao.class);
_hostJoinDao = locator.getDao(HostJoinDao.class);
_volJoinDao = locator.getDao(VolumeJoinDao.class);
_physicalNetworkTrafficTypeDao = locator.getDao(PhysicalNetworkTrafficTypeDao.class);
_physicalNetworkServiceProviderDao = locator.getDao(PhysicalNetworkServiceProviderDao.class);
@ -1324,4 +1330,18 @@ public class ApiDBUtils {
public static List<HostJoinVO> newHostView(Host vr){
return _hostJoinDao.newHostView(vr);
}
public static VolumeResponse newVolumeResponse(VolumeJoinVO vr) {
return _volJoinDao.newVolumeResponse(vr);
}
public static VolumeResponse fillVolumeDetails(VolumeResponse vrData, VolumeJoinVO vr){
return _volJoinDao.setVolumeResponse(vrData, vr);
}
public static List<VolumeJoinVO> newVolumeView(Volume vr){
return _volJoinDao.newVolumeView(vr);
}
}

View File

@ -57,6 +57,7 @@ import com.cloud.api.query.vo.ResourceTagJoinVO;
import com.cloud.api.query.vo.SecurityGroupJoinVO;
import com.cloud.api.query.vo.UserAccountJoinVO;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.api.response.ApiResponseSerializer;
import org.apache.cloudstack.api.response.AsyncJobResponse;
import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
@ -1019,138 +1020,10 @@ public class ApiResponseHelper implements ResponseGenerator {
@Override
public VolumeResponse createVolumeResponse(Volume volume) {
VolumeResponse volResponse = new VolumeResponse();
volResponse.setId(volume.getUuid());
if (volume.getName() != null) {
volResponse.setName(volume.getName());
} else {
volResponse.setName("");
}
DataCenter zone = ApiDBUtils.findZoneById(volume.getDataCenterId());
if (zone != null) {
volResponse.setZoneId(zone.getUuid());
volResponse.setZoneName(zone.getName());
}
volResponse.setVolumeType(volume.getVolumeType().toString());
volResponse.setDeviceId(volume.getDeviceId());
Long instanceId = volume.getInstanceId();
if (instanceId != null && volume.getState() != Volume.State.Destroy) {
VMInstanceVO vm = ApiDBUtils.findVMInstanceById(instanceId);
if (vm != null) {
volResponse.setVirtualMachineId(vm.getUuid());
volResponse.setVirtualMachineName(vm.getHostName());
volResponse.setVirtualMachineState(vm.getState().toString());
UserVm userVm = ApiDBUtils.findUserVmById(vm.getId());
if (userVm != null) {
if (userVm.getDisplayName() != null) {
volResponse.setVirtualMachineDisplayName(userVm.getDisplayName());
}
} else {
s_logger.error("User Vm with Id: " + instanceId + " does not exist for volume " + volume.getId());
}
} else {
s_logger.error("Vm with Id: " + instanceId + " does not exist for volume " + volume.getId());
}
}
// Show the virtual size of the volume
volResponse.setSize(volume.getSize());
volResponse.setCreated(volume.getCreated());
volResponse.setState(volume.getState().toString());
if(volume.getState() == Volume.State.UploadOp){
com.cloud.storage.VolumeHostVO volumeHostRef = ApiDBUtils.findVolumeHostRef(volume.getId(), volume.getDataCenterId());
volResponse.setSize(volumeHostRef.getSize());
volResponse.setCreated(volumeHostRef.getCreated());
Account caller = UserContext.current().getCaller();
if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN)
volResponse.setHypervisor(ApiDBUtils.getHypervisorTypeFromFormat(volumeHostRef.getFormat()).toString());
if (volumeHostRef.getDownloadState() != Status.DOWNLOADED) {
String volumeStatus = "Processing";
if (volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) {
if (volumeHostRef.getDownloadPercent() == 100) {
volumeStatus = "Checking Volume";
} else {
volumeStatus = volumeHostRef.getDownloadPercent() + "% Uploaded";
}
volResponse.setState("Uploading");
} else {
volumeStatus = volumeHostRef.getErrorString();
if(volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.NOT_DOWNLOADED){
volResponse.setState("UploadNotStarted");
}else {
volResponse.setState("UploadError");
}
}
volResponse.setStatus(volumeStatus);
} else if (volumeHostRef.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) {
volResponse.setStatus("Upload Complete");
volResponse.setState("Uploaded");
} else {
volResponse.setStatus("Successfully Installed");
}
}
populateOwner(volResponse, volume);
DiskOfferingVO diskOffering = ApiDBUtils.findDiskOfferingById(volume.getDiskOfferingId());
if (diskOffering != null) {
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
volResponse.setServiceOfferingId(diskOffering.getUuid());
} else {
volResponse.setDiskOfferingId(diskOffering.getUuid());
}
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
volResponse.setServiceOfferingName(diskOffering.getName());
volResponse.setServiceOfferingDisplayText(diskOffering.getDisplayText());
} else {
volResponse.setDiskOfferingName(diskOffering.getName());
volResponse.setDiskOfferingDisplayText(diskOffering.getDisplayText());
}
volResponse.setStorageType(diskOffering.getUseLocalStorage() ? ServiceOffering.StorageType.local.toString()
: ServiceOffering.StorageType.shared.toString());
}
Long poolId = volume.getPoolId();
String poolName = (poolId == null) ? "none" : ApiDBUtils.findStoragePoolById(poolId).getName();
volResponse.setStoragePoolName(poolName);
// volResponse.setSourceId(volume.getSourceId());
// if (volume.getSourceType() != null) {
// volResponse.setSourceType(volume.getSourceType().toString());
// }
// return hypervisor for ROOT and Resource domain only
Account caller = UserContext.current().getCaller();
if ((caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) && volume.getState() != Volume.State.UploadOp) {
volResponse.setHypervisor(ApiDBUtils.getVolumeHyperType(volume.getId()).toString());
}
volResponse.setAttached(volume.getAttached());
volResponse.setDestroyed(volume.getState() == Volume.State.Destroy);
boolean isExtractable = true;
if (volume.getVolumeType() != Volume.Type.DATADISK) { // Datadisk dont have any template dependence.
VMTemplateVO template = ApiDBUtils.findTemplateById(volume.getTemplateId());
if (template != null) { // For ISO based volumes template = null and we allow extraction of all ISO based volumes
isExtractable = template.isExtractable() && template.getTemplateType() != Storage.TemplateType.SYSTEM;
}
}
//set tag information
List<? extends ResourceTag> tags = ApiDBUtils.listByResourceTypeAndId(TaggedResourceType.Volume, volume.getId());
List<ResourceTagResponse> tagResponses = new ArrayList<ResourceTagResponse>();
for (ResourceTag tag : tags) {
ResourceTagResponse tagResponse = createResourceTagResponse(tag, true);
tagResponses.add(tagResponse);
}
volResponse.setTags(tagResponses);
volResponse.setExtractable(isExtractable);
volResponse.setObjectName("volume");
return volResponse;
List<VolumeJoinVO> viewVrs = ApiDBUtils.newVolumeView(volume);
List<VolumeResponse> listVrs = ViewResponseHelper.createVolumeResponse(viewVrs.toArray(new VolumeJoinVO[viewVrs.size()]));
assert listVrs != null && listVrs.size() == 1 : "There should be one volume returned";
return listVrs.get(0);
}
@Override

View File

@ -55,6 +55,7 @@ import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.ConnectionClosedException;
@ -464,7 +465,8 @@ public class ApiServer implements HttpRequestHandler {
&& !(cmdObj instanceof ListProjectsCmd)
&& !(cmdObj instanceof ListProjectAccountsCmd)
&& !(cmdObj instanceof ListProjectInvitationsCmd)
&& !(cmdObj instanceof ListHostsCmd)) {
&& !(cmdObj instanceof ListHostsCmd)
&& !(cmdObj instanceof ListVolumesCmd)) {
buildAsyncListResponse((BaseListCmd) cmdObj, caller);
}

View File

@ -39,6 +39,7 @@ import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCm
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
import org.apache.cloudstack.api.response.DomainRouterResponse;
import org.apache.cloudstack.api.response.EventResponse;
import org.apache.cloudstack.api.response.HostResponse;
@ -51,6 +52,7 @@ import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.query.QueryService;
import org.apache.log4j.Logger;
@ -65,6 +67,7 @@ import com.cloud.api.query.dao.ProjectJoinDao;
import com.cloud.api.query.dao.ResourceTagJoinDao;
import com.cloud.api.query.dao.SecurityGroupJoinDao;
import com.cloud.api.query.dao.UserVmJoinDao;
import com.cloud.api.query.dao.VolumeJoinDao;
import com.cloud.api.query.vo.DomainRouterJoinVO;
import com.cloud.api.query.vo.EventJoinVO;
import com.cloud.api.query.vo.HostJoinVO;
@ -76,6 +79,7 @@ import com.cloud.api.query.vo.ResourceTagJoinVO;
import com.cloud.api.query.vo.SecurityGroupJoinVO;
import com.cloud.api.query.vo.UserAccountJoinVO;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.async.AsyncJob;
import com.cloud.domain.Domain;
import com.cloud.domain.DomainVO;
@ -98,7 +102,12 @@ import com.cloud.projects.ProjectService;
import com.cloud.projects.dao.ProjectAccountDao;
import com.cloud.projects.dao.ProjectDao;
import com.cloud.server.Criteria;
import com.cloud.server.ResourceTag.TaggedResourceType;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.Snapshot;
import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO;
import com.cloud.tags.ResourceTagVO;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountManagerImpl;
@ -119,6 +128,8 @@ import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.vm.UserVmVO;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.UserVmDao;
/**
@ -188,6 +199,9 @@ public class QueryManagerImpl implements QueryService, Manager {
@Inject
private HostJoinDao _hostJoinDao;
@Inject
private VolumeJoinDao _volumeJoinDao;
@Inject
private HighAvailabilityManager _haMgr;
@ -1371,9 +1385,9 @@ public class QueryManagerImpl implements QueryService, Manager {
if ((Boolean) haHosts) {
sb.and("tag", sb.entity().getTag(), SearchCriteria.Op.EQ);
} else {
sb.and("tag", sb.entity().getTag(), SearchCriteria.Op.NEQ);
//FIXME: should we have another condition say tag = null?
//hostTagSearch.or("tagNull", hostTagSearch.entity().getTag(), SearchCriteria.Op.NULL);
sb.and().op("tag", sb.entity().getTag(), SearchCriteria.Op.NEQ);
sb.or("tagNull", sb.entity().getTag(), SearchCriteria.Op.NULL);
sb.cp();
}
}
@ -1439,4 +1453,142 @@ public class QueryManagerImpl implements QueryService, Manager {
}
@Override
public ListResponse<VolumeResponse> searchForVolumes(ListVolumesCmd cmd) {
Pair<List<VolumeJoinVO>, Integer> result = searchForVolumesInternal(cmd);
ListResponse<VolumeResponse> response = new ListResponse<VolumeResponse>();
List<VolumeResponse> routerResponses = ViewResponseHelper.createVolumeResponse(result.first().toArray(new VolumeJoinVO[result.first().size()]));
response.setResponses(routerResponses, result.second());
return response;
}
private Pair<List<VolumeJoinVO>, Integer> searchForVolumesInternal(ListVolumesCmd cmd) {
Account caller = UserContext.current().getCaller();
List<Long> permittedAccounts = new ArrayList<Long>();
Long id = cmd.getId();
Long vmInstanceId = cmd.getVirtualMachineId();
String name = cmd.getVolumeName();
String keyword = cmd.getKeyword();
String type = cmd.getType();
Map<String, String> tags = cmd.getTags();
Long zoneId = cmd.getZoneId();
Long podId = null;
if (_accountMgr.isAdmin(caller.getType())) {
podId = cmd.getPodId();
}
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
_accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second();
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
Filter searchFilter = new Filter(VolumeJoinVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal());
// hack for now, this should be done better but due to needing a join I opted to
// do this quickly and worry about making it pretty later
SearchBuilder<VolumeJoinVO> sb = _volumeJoinDao.createSearchBuilder();
sb.select(null, Func.DISTINCT, sb.entity().getId()); // select distinct
// ids to get
// number of
// records with
// pagination
_accountMgr.buildACLViewSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
sb.and("volumeType", sb.entity().getVolumeType(), SearchCriteria.Op.LIKE);
sb.and("instanceId", sb.entity().getVmId(), SearchCriteria.Op.EQ);
sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ);
sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ);
// Only return volumes that are not destroyed
sb.and("state", sb.entity().getState(), SearchCriteria.Op.NEQ);
sb.and("systemUse", sb.entity().isSystemUse(), SearchCriteria.Op.NEQ);
// display UserVM volumes only
sb.and().op("type", sb.entity().getVmType(), SearchCriteria.Op.NIN);
sb.or("nulltype", sb.entity().getVmType(), SearchCriteria.Op.NULL);
sb.cp();
if (tags != null && !tags.isEmpty()) {
for (int count=0; count < tags.size(); count++) {
sb.or().op("key" + String.valueOf(count), sb.entity().getTagKey(), SearchCriteria.Op.EQ);
sb.and("value" + String.valueOf(count), sb.entity().getTagValue(), SearchCriteria.Op.EQ);
sb.cp();
}
}
// now set the SC criteria...
SearchCriteria<VolumeJoinVO> sc = sb.create();
_accountMgr.buildACLViewSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
if (keyword != null) {
SearchCriteria<VolumeJoinVO> ssc = _volumeJoinDao.createSearchCriteria();
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
ssc.addOr("volumeType", SearchCriteria.Op.LIKE, "%" + keyword + "%");
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
}
if (name != null) {
sc.setParameters("name", "%" + name + "%");
}
sc.setParameters("systemUse", 1);
if (tags != null && !tags.isEmpty()) {
int count = 0;
for (String key : tags.keySet()) {
sc.setParameters("key" + String.valueOf(count), key);
sc.setParameters("value" + String.valueOf(count), tags.get(key));
count++;
}
}
if (id != null) {
sc.setParameters("id", id);
}
if (type != null) {
sc.setParameters("volumeType", "%" + type + "%");
}
if (vmInstanceId != null) {
sc.setParameters("instanceId", vmInstanceId);
}
if (zoneId != null) {
sc.setParameters("dataCenterId", zoneId);
}
if (podId != null) {
sc.setParameters("podId", podId);
}
// Don't return DomR and ConsoleProxy volumes
sc.setParameters("type", VirtualMachine.Type.ConsoleProxy, VirtualMachine.Type.SecondaryStorageVm, VirtualMachine.Type.DomainRouter);
// Only return volumes that are not destroyed
sc.setParameters("state", Volume.State.Destroy);
// search Volume details by ids
Pair<List<VolumeJoinVO>, Integer> uniqueVolPair = _volumeJoinDao.searchAndCount(sc, searchFilter);
Integer count = uniqueVolPair.second();
if (count.intValue() == 0) {
// empty result
return uniqueVolPair;
}
List<VolumeJoinVO> uniqueVols = uniqueVolPair.first();
Long[] vrIds = new Long[uniqueVols.size()];
int i = 0;
for (VolumeJoinVO v : uniqueVols) {
vrIds[i++] = v.getId();
}
List<VolumeJoinVO> vrs = _volumeJoinDao.searchByIds(vrIds);
return new Pair<List<VolumeJoinVO>, Integer>(vrs, count);
}
}

View File

@ -34,6 +34,7 @@ import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.log4j.Logger;
import com.cloud.api.ApiDBUtils;
@ -48,6 +49,7 @@ import com.cloud.api.query.vo.ResourceTagJoinVO;
import com.cloud.api.query.vo.SecurityGroupJoinVO;
import com.cloud.api.query.vo.UserAccountJoinVO;
import com.cloud.api.query.vo.UserVmJoinVO;
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
@ -214,4 +216,21 @@ public class ViewResponseHelper {
}
return new ArrayList<HostResponse>(vrDataList.values());
}
public static List<VolumeResponse> createVolumeResponse(VolumeJoinVO... volumes) {
Hashtable<Long, VolumeResponse> vrDataList = new Hashtable<Long, VolumeResponse>();
for (VolumeJoinVO vr : volumes) {
VolumeResponse vrData = vrDataList.get(vr.getId());
if ( vrData == null ){
// first time encountering this volume
vrData = ApiDBUtils.newVolumeResponse(vr);
}
else{
// update tags
vrData = ApiDBUtils.fillVolumeDetails(vrData, vr);
}
vrDataList.put(vr.getId(), vrData);
}
return new ArrayList<VolumeResponse>(vrDataList.values());
}
}

View File

@ -0,0 +1,37 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.api.query.dao;
import java.util.List;
import org.apache.cloudstack.api.response.VolumeResponse;
import com.cloud.api.query.vo.VolumeJoinVO;
import com.cloud.storage.Volume;
import com.cloud.utils.db.GenericDao;
public interface VolumeJoinDao extends GenericDao<VolumeJoinVO, Long> {
VolumeResponse newVolumeResponse(VolumeJoinVO vol);
VolumeResponse setVolumeResponse(VolumeResponse volData, VolumeJoinVO vol);
List<VolumeJoinVO> newVolumeView(Volume vol);
List<VolumeJoinVO> searchByIds(Long... ids);
}

View File

@ -0,0 +1,230 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.api.query.dao;
import java.util.List;
import javax.ejb.Local;
import org.apache.log4j.Logger;
import com.cloud.api.ApiDBUtils;
import com.cloud.api.ApiResponseHelper;
import com.cloud.api.query.vo.ResourceTagJoinVO;
import com.cloud.api.query.vo.VolumeJoinVO;
import org.apache.cloudstack.api.response.VolumeResponse;
import com.cloud.offering.ServiceOffering;
import com.cloud.storage.Storage;
import com.cloud.storage.VMTemplateHostVO;
import com.cloud.storage.Volume;
import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@Local(value={VolumeJoinDao.class})
public class VolumeJoinDaoImpl extends GenericDaoBase<VolumeJoinVO, Long> implements VolumeJoinDao {
public static final Logger s_logger = Logger.getLogger(VolumeJoinDaoImpl.class);
private SearchBuilder<VolumeJoinVO> volSearch;
private SearchBuilder<VolumeJoinVO> volIdSearch;
protected VolumeJoinDaoImpl() {
volSearch = createSearchBuilder();
volSearch.and("idIN", volSearch.entity().getId(), SearchCriteria.Op.IN);
volSearch.done();
volIdSearch = createSearchBuilder();
volIdSearch.and("id", volIdSearch.entity().getId(), SearchCriteria.Op.EQ);
volIdSearch.done();
this._count = "select count(distinct id) from volume_view WHERE ";
}
@Override
public VolumeResponse newVolumeResponse(VolumeJoinVO volume) {
Account caller = UserContext.current().getCaller();
VolumeResponse volResponse = new VolumeResponse();
volResponse.setId(volume.getUuid());
if (volume.getName() != null) {
volResponse.setName(volume.getName());
} else {
volResponse.setName("");
}
volResponse.setZoneId(volume.getDataCenterUuid());
volResponse.setZoneName(volume.getDataCenterName());
volResponse.setVolumeType(volume.getVolumeType().toString());
volResponse.setDeviceId(volume.getDeviceId());
long instanceId = volume.getVmId();
if (instanceId > 0 && volume.getState() != Volume.State.Destroy) {
volResponse.setVirtualMachineId(volume.getVmUuid());
volResponse.setVirtualMachineName(volume.getVmName());
volResponse.setVirtualMachineState(volume.getVmState().toString());
volResponse.setVirtualMachineDisplayName(volume.getVmDisplayName());
}
// Show the virtual size of the volume
volResponse.setSize(volume.getSize());
volResponse.setCreated(volume.getCreated());
volResponse.setState(volume.getState().toString());
if (volume.getState() == Volume.State.UploadOp) {
// com.cloud.storage.VolumeHostVO volumeHostRef =
// ApiDBUtils.findVolumeHostRef(volume.getId(),
// volume.getDataCenterId());
volResponse.setSize(volume.getVolumeHostSize());
volResponse.setCreated(volume.getVolumeHostCreated());
if (caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN)
volResponse.setHypervisor(ApiDBUtils.getHypervisorTypeFromFormat(volume.getFormat()).toString());
if (volume.getDownloadState() != Status.DOWNLOADED) {
String volumeStatus = "Processing";
if (volume.getDownloadState() == VMTemplateHostVO.Status.DOWNLOAD_IN_PROGRESS) {
if (volume.getDownloadPercent() == 100) {
volumeStatus = "Checking Volume";
} else {
volumeStatus = volume.getDownloadPercent() + "% Uploaded";
}
volResponse.setState("Uploading");
} else {
volumeStatus = volume.getErrorString();
if (volume.getDownloadState() == VMTemplateHostVO.Status.NOT_DOWNLOADED) {
volResponse.setState("UploadNotStarted");
} else {
volResponse.setState("UploadError");
}
}
volResponse.setStatus(volumeStatus);
} else if (volume.getDownloadState() == VMTemplateHostVO.Status.DOWNLOADED) {
volResponse.setStatus("Upload Complete");
volResponse.setState("Uploaded");
} else {
volResponse.setStatus("Successfully Installed");
}
}
// populate owner.
ApiResponseHelper.populateOwner(volResponse, volume);
// DiskOfferingVO diskOffering =
// ApiDBUtils.findDiskOfferingById(volume.getDiskOfferingId());
if (volume.getDiskOfferingId() > 0) {
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
volResponse.setServiceOfferingId(volume.getDiskOfferingUuid());
} else {
volResponse.setDiskOfferingId(volume.getDiskOfferingUuid());
}
if (volume.getVolumeType().equals(Volume.Type.ROOT)) {
volResponse.setServiceOfferingName(volume.getDiskOfferingName());
volResponse.setServiceOfferingDisplayText(volume.getDiskOfferingDisplayText());
} else {
volResponse.setDiskOfferingName(volume.getDiskOfferingName());
volResponse.setDiskOfferingDisplayText(volume.getDiskOfferingDisplayText());
}
volResponse.setStorageType(volume.isUseLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared
.toString());
}
Long poolId = volume.getPoolId();
String poolName = (poolId == null) ? "none" : volume.getPoolName();
volResponse.setStoragePoolName(poolName);
// return hypervisor for ROOT and Resource domain only
if ((caller.getType() == Account.ACCOUNT_TYPE_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN)
&& volume.getState() != Volume.State.UploadOp && volume.getHypervisorType() != null) {
volResponse.setHypervisor(volume.getHypervisorType().toString());
}
volResponse.setAttached(volume.getAttached());
volResponse.setDestroyed(volume.getState() == Volume.State.Destroy);
boolean isExtractable = true;
if (volume.getVolumeType() != Volume.Type.DATADISK) { // Datadisk dont
// have any
// template
// dependence.
if (volume.getTemplateId() > 0) { // For ISO based volumes template
// = null and we allow extraction
// of all ISO based volumes
isExtractable = volume.isExtractable() && volume.getTemplateType() != Storage.TemplateType.SYSTEM;
}
}
// update tag information
long tag_id = volume.getTagId();
if (tag_id > 0) {
ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id);
if (vtag != null) {
volResponse.addTag(ApiDBUtils.newResourceTagResponse(vtag, false));
}
}
volResponse.setExtractable(isExtractable);
volResponse.setObjectName("volume");
return volResponse;
}
@Override
public VolumeResponse setVolumeResponse(VolumeResponse volData, VolumeJoinVO vol) {
long tag_id = vol.getTagId();
if (tag_id > 0) {
ResourceTagJoinVO vtag = ApiDBUtils.findResourceTagViewById(tag_id);
if ( vtag != null ){
volData.addTag(ApiDBUtils.newResourceTagResponse(vtag, false));
}
}
return volData;
}
@Override
public List<VolumeJoinVO> newVolumeView(Volume vol) {
SearchCriteria<VolumeJoinVO> sc = volIdSearch.create();
sc.setParameters("id", vol.getId());
return searchIncludingRemoved(sc, null, null, false);
}
@Override
public List<VolumeJoinVO> searchByIds(Long... ids) {
SearchCriteria<VolumeJoinVO> sc = volSearch.create();
sc.setParameters("idIN", ids);
return searchIncludingRemoved(sc, null, null, false);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,7 @@ import com.cloud.api.query.dao.ResourceTagJoinDaoImpl;
import com.cloud.api.query.dao.SecurityGroupJoinDaoImpl;
import com.cloud.api.query.dao.UserVmJoinDaoImpl;
import com.cloud.api.query.dao.HostJoinDaoImpl;
import com.cloud.api.query.dao.VolumeJoinDaoImpl;
import com.cloud.async.AsyncJobExecutorContextImpl;
import com.cloud.async.AsyncJobManagerImpl;
import com.cloud.async.SyncQueueManagerImpl;
@ -222,6 +223,7 @@ import com.cloud.vm.dao.VMInstanceDaoImpl;
import com.cloud.event.dao.EventJoinDaoImpl;
public class DefaultComponentLibrary extends ComponentLibraryBase implements ComponentLibrary {
protected void populateDaos() {
addDao("StackMaidDao", StackMaidDaoImpl.class);
@ -241,6 +243,7 @@ public class DefaultComponentLibrary extends ComponentLibraryBase implements Com
addDao("ProjectAccountJoinDao", ProjectAccountJoinDaoImpl.class);
addDao("ProjectInvitationJoinDao", ProjectInvitationJoinDaoImpl.class);
addDao("HostJoinDao", HostJoinDaoImpl.class);
addDao("VolumeJoinDao", VolumeJoinDaoImpl.class);
ComponentInfo<? extends GenericDao<?, ? extends Serializable>> info = addDao("ServiceOfferingDao", ServiceOfferingDaoImpl.class);
info.addParameter("cache.size", "50");
info.addParameter("cache.time.to.live", "600");

View File

@ -3859,124 +3859,7 @@ public class StorageManagerImpl implements StorageManager, Manager, ClusterManag
return secHost;
}
@Override
public Pair<List<? extends Volume>, Integer> searchForVolumes(ListVolumesCmd cmd) {
Account caller = UserContext.current().getCaller();
List<Long> permittedAccounts = new ArrayList<Long>();
Long id = cmd.getId();
Long vmInstanceId = cmd.getVirtualMachineId();
String name = cmd.getVolumeName();
String keyword = cmd.getKeyword();
String type = cmd.getType();
Map<String, String> tags = cmd.getTags();
Long zoneId = cmd.getZoneId();
Long podId = null;
// Object host = null; TODO
if (_accountMgr.isAdmin(caller.getType())) {
podId = cmd.getPodId();
// host = cmd.getHostId(); TODO
}
Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
_accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
Long domainId = domainIdRecursiveListProject.first();
Boolean isRecursive = domainIdRecursiveListProject.second();
ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
Filter searchFilter = new Filter(VolumeVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal());
// hack for now, this should be done better but due to needing a join I opted to
// do this quickly and worry about making it pretty later
SearchBuilder<VolumeVO> sb = _volumeDao.createSearchBuilder();
_accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
sb.and("volumeType", sb.entity().getVolumeType(), SearchCriteria.Op.LIKE);
sb.and("instanceId", sb.entity().getInstanceId(), SearchCriteria.Op.EQ);
sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ);
sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ);
// Only return volumes that are not destroyed
sb.and("state", sb.entity().getState(), SearchCriteria.Op.NEQ);
SearchBuilder<DiskOfferingVO> diskOfferingSearch = _diskOfferingDao.createSearchBuilder();
diskOfferingSearch.and("systemUse", diskOfferingSearch.entity().getSystemUse(), SearchCriteria.Op.NEQ);
sb.join("diskOfferingSearch", diskOfferingSearch, sb.entity().getDiskOfferingId(), diskOfferingSearch.entity().getId(), JoinBuilder.JoinType.LEFTOUTER);
// display UserVM volumes only
SearchBuilder<VMInstanceVO> vmSearch = _vmInstanceDao.createSearchBuilder();
vmSearch.and("type", vmSearch.entity().getType(), SearchCriteria.Op.NIN);
vmSearch.or("nulltype", vmSearch.entity().getType(), SearchCriteria.Op.NULL);
sb.join("vmSearch", vmSearch, sb.entity().getInstanceId(), vmSearch.entity().getId(), JoinBuilder.JoinType.LEFTOUTER);
if (tags != null && !tags.isEmpty()) {
SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder();
for (int count=0; count < tags.size(); count++) {
tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ);
tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ);
tagSearch.cp();
}
tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
sb.groupBy(sb.entity().getId());
sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER);
}
// now set the SC criteria...
SearchCriteria<VolumeVO> sc = sb.create();
_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
if (keyword != null) {
SearchCriteria<VolumeVO> ssc = _volumeDao.createSearchCriteria();
ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
ssc.addOr("volumeType", SearchCriteria.Op.LIKE, "%" + keyword + "%");
sc.addAnd("name", SearchCriteria.Op.SC, ssc);
}
if (name != null) {
sc.setParameters("name", "%" + name + "%");
}
sc.setJoinParameters("diskOfferingSearch", "systemUse", 1);
if (tags != null && !tags.isEmpty()) {
int count = 0;
sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.Volume.toString());
for (String key : tags.keySet()) {
sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key);
sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key));
count++;
}
}
if (id != null) {
sc.setParameters("id", id);
}
if (type != null) {
sc.setParameters("volumeType", "%" + type + "%");
}
if (vmInstanceId != null) {
sc.setParameters("instanceId", vmInstanceId);
}
if (zoneId != null) {
sc.setParameters("dataCenterId", zoneId);
}
if (podId != null) {
sc.setParameters("podId", podId);
}
// Don't return DomR and ConsoleProxy volumes
sc.setJoinParameters("vmSearch", "type", VirtualMachine.Type.ConsoleProxy, VirtualMachine.Type.SecondaryStorageVm, VirtualMachine.Type.DomainRouter);
// Only return volumes that are not destroyed
sc.setParameters("state", Volume.State.Destroy);
Pair<List<VolumeVO>, Integer> volumes = _volumeDao.searchAndCount(sc, searchFilter);
return new Pair<List<? extends Volume>, Integer>(volumes.first(), volumes.second());
}
@Override
public String getSupportedImageFormatForCluster(Long clusterId) {

View File

@ -106,4 +106,18 @@ public class ListPerfTest extends APITest {
System.out.println("Time taken to list Hosts: " + (after - before) + " ms");
}
@Test
public void testListVolumes(){
// issue list Hosts calls
HashMap<String, String> params = new HashMap<String, String>();
params.put("response", "json");
params.put("listAll", "true");
params.put("sessionkey", sessionKey);
long before = System.currentTimeMillis();
String result = this.sendRequest("listVolumes", params);
long after = System.currentTimeMillis();
System.out.println("Time taken to list Volumes: " + (after - before) + " ms");
}
}

View File

@ -3062,4 +3062,86 @@ left join op_host_capacity mem_caps on host.id = mem_caps.host_id and mem_caps.c
left join op_host_capacity cpu_caps on host.id = cpu_caps.host_id and cpu_caps.capacity_type = 1
left join async_job on async_job.instance_id = host.id and async_job.instance_type = "Host" and async_job.job_status = 0;
DROP VIEW IF EXISTS `cloud`.`volume_view`;
CREATE VIEW volume_view AS
select
volumes.id,
volumes.uuid,
volumes.name,
volumes.device_id,
volumes.volume_type,
volumes.size,
volumes.created,
volumes.state,
volumes.attached,
volumes.removed,
volumes.pod_id,
account.id account_id,
account.uuid account_uuid,
account.account_name account_name,
account.type account_type,
domain.id domain_id,
domain.uuid domain_uuid,
domain.name domain_name,
domain.path domain_path,
projects.id project_id,
projects.uuid project_uuid,
projects.name project_name,
data_center.id data_center_id,
data_center.uuid data_center_uuid,
data_center.name data_center_name,
vm_instance.id vm_id,
vm_instance.uuid vm_uuid,
vm_instance.name vm_name,
vm_instance.state vm_state,
vm_instance.vm_type,
user_vm.display_name vm_display_name,
volume_host_ref.size volume_host_size,
volume_host_ref.created volume_host_created,
volume_host_ref.format,
volume_host_ref.download_pct,
volume_host_ref.download_state,
volume_host_ref.error_str,
disk_offering.id disk_offering_id,
disk_offering.uuid disk_offering_uuid,
disk_offering.name disk_offering_name,
disk_offering.display_text disk_offering_display_text,
disk_offering.use_local_storage,
disk_offering.system_use,
storage_pool.id pool_id,
storage_pool.uuid pool_uuid,
storage_pool.name pool_name,
cluster.hypervisor_type,
vm_template.id template_id,
vm_template.uuid template_uuid,
vm_template.extractable,
vm_template.type template_type,
resource_tags.id tag_id,
resource_tags.uuid tag_uuid,
resource_tags.key tag_key,
resource_tags.value tag_value,
resource_tags.domain_id tag_domain_id,
resource_tags.account_id tag_account_id,
resource_tags.resource_id tag_resource_id,
resource_tags.resource_uuid tag_resource_uuid,
resource_tags.resource_type tag_resource_type,
resource_tags.customer tag_customer,
async_job.id job_id,
async_job.uuid job_uuid,
async_job.job_status job_status,
async_job.account_id job_account_id
from volumes
inner join account on volumes.account_id=account.id
inner join domain on volumes.domain_id=domain.id
left join projects on projects.project_account_id = account.id
left join data_center on volumes.data_center_id = data_center.id
left join vm_instance on volumes.instance_id = vm_instance.id
left join user_vm on user_vm.id = vm_instance.id
left join volume_host_ref on volumes.id = volume_host_ref.volume_id and volumes.data_center_id = volume_host_ref.zone_id
left join disk_offering on volumes.disk_offering_id = disk_offering.id
left join storage_pool on volumes.pool_id = storage_pool.id
left join cluster on storage_pool.cluster_id = cluster.id
left join vm_template on volumes.template_id = vm_template.id
left join resource_tags on resource_tags.resource_id = volumes.id and resource_tags.resource_type = "Volume"
left join async_job on async_job.instance_id = volumes.id and async_job.instance_type = "Volume" and async_job.job_status = 0;

View File

@ -637,3 +637,88 @@ left join host_tags on host_tags.host_id = host.id
left join op_host_capacity mem_caps on host.id = mem_caps.host_id and mem_caps.capacity_type = 0
left join op_host_capacity cpu_caps on host.id = cpu_caps.host_id and cpu_caps.capacity_type = 1
left join async_job on async_job.instance_id = host.id and async_job.instance_type = "Host" and async_job.job_status = 0;
DROP VIEW IF EXISTS `cloud`.`volume_view`;
CREATE VIEW volume_view AS
select
volumes.id,
volumes.uuid,
volumes.name,
volumes.device_id,
volumes.volume_type,
volumes.size,
volumes.created,
volumes.state,
volumes.attached,
volumes.removed,
volumes.pod_id,
account.id account_id,
account.uuid account_uuid,
account.account_name account_name,
account.type account_type,
domain.id domain_id,
domain.uuid domain_uuid,
domain.name domain_name,
domain.path domain_path,
projects.id project_id,
projects.uuid project_uuid,
projects.name project_name,
data_center.id data_center_id,
data_center.uuid data_center_uuid,
data_center.name data_center_name,
vm_instance.id vm_id,
vm_instance.uuid vm_uuid,
vm_instance.name vm_name,
vm_instance.state vm_state,
vm_instance.vm_type,
user_vm.display_name vm_display_name,
volume_host_ref.size volume_host_size,
volume_host_ref.created volume_host_created,
volume_host_ref.format,
volume_host_ref.download_pct,
volume_host_ref.download_state,
volume_host_ref.error_str,
disk_offering.id disk_offering_id,
disk_offering.uuid disk_offering_uuid,
disk_offering.name disk_offering_name,
disk_offering.display_text disk_offering_display_text,
disk_offering.use_local_storage,
disk_offering.system_use,
storage_pool.id pool_id,
storage_pool.uuid pool_uuid,
storage_pool.name pool_name,
cluster.hypervisor_type,
vm_template.id template_id,
vm_template.uuid template_uuid,
vm_template.extractable,
vm_template.type template_type,
resource_tags.id tag_id,
resource_tags.uuid tag_uuid,
resource_tags.key tag_key,
resource_tags.value tag_value,
resource_tags.domain_id tag_domain_id,
resource_tags.account_id tag_account_id,
resource_tags.resource_id tag_resource_id,
resource_tags.resource_uuid tag_resource_uuid,
resource_tags.resource_type tag_resource_type,
resource_tags.customer tag_customer,
async_job.id job_id,
async_job.uuid job_uuid,
async_job.job_status job_status,
async_job.account_id job_account_id
from volumes
inner join account on volumes.account_id=account.id
inner join domain on volumes.domain_id=domain.id
left join projects on projects.project_account_id = account.id
left join data_center on volumes.data_center_id = data_center.id
left join vm_instance on volumes.instance_id = vm_instance.id
left join user_vm on user_vm.id = vm_instance.id
left join volume_host_ref on volumes.id = volume_host_ref.volume_id and volumes.data_center_id = volume_host_ref.zone_id
left join disk_offering on volumes.disk_offering_id = disk_offering.id
left join storage_pool on volumes.pool_id = storage_pool.id
left join cluster on storage_pool.cluster_id = cluster.id
left join vm_template on volumes.template_id = vm_template.id
left join resource_tags on resource_tags.resource_id = volumes.id and resource_tags.resource_type = "Volume"
left join async_job on async_job.instance_id = volumes.id and async_job.instance_type = "Volume" and async_job.job_status = 0;