diff --git a/api/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java b/api/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java index a19d34436f7..fbf6121f543 100644 --- a/api/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java +++ b/api/src/com/cloud/agent/api/CreateVolumeFromSnapshotCommand.java @@ -18,6 +18,7 @@ package com.cloud.agent.api; import com.cloud.storage.StoragePool; + /** * This currently assumes that both primary and secondary storage are mounted on the XenServer. */ diff --git a/api/src/com/cloud/storage/StoragePool.java b/api/src/com/cloud/storage/StoragePool.java index f517927eac1..091eef182cc 100644 --- a/api/src/com/cloud/storage/StoragePool.java +++ b/api/src/com/cloud/storage/StoragePool.java @@ -99,10 +99,7 @@ public interface StoragePool extends Identity, InternalIdentity { /** * @return */ - String getStorageProvider(); - - /** - * @return - */ - String getStorageType(); + Long getStorageProviderId(); + + boolean isInMaintenance(); } diff --git a/api/src/com/cloud/storage/StoragePoolStatus.java b/api/src/com/cloud/storage/StoragePoolStatus.java index 94dd686a8f0..a35f706d702 100644 --- a/api/src/com/cloud/storage/StoragePoolStatus.java +++ b/api/src/com/cloud/storage/StoragePoolStatus.java @@ -17,11 +17,6 @@ package com.cloud.storage; public enum StoragePoolStatus { - Creating, - Up, - PrepareForMaintenance, - ErrorInMaintenance, - CancelMaintenance, - Maintenance, - Removed; + Initial, Initialized, Creating, Attaching, Up, PrepareForMaintenance, + ErrorInMaintenance, CancelMaintenance, Maintenance, Removed; } diff --git a/api/src/com/cloud/storage/StorageService.java b/api/src/com/cloud/storage/StorageService.java index bd7dfd3a67a..63c5023ee91 100644 --- a/api/src/com/cloud/storage/StorageService.java +++ b/api/src/com/cloud/storage/StorageService.java @@ -22,17 +22,10 @@ import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaint import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd; -import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; -import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.PermissionDeniedException; -import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceInUseException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.user.Account; public interface StorageService{ /** @@ -51,37 +44,6 @@ public interface StorageService{ StoragePool createPool(CreateStoragePoolCmd cmd) throws ResourceInUseException, IllegalArgumentException, UnknownHostException, ResourceUnavailableException; - /** - * Creates the database object for a volume based on the given criteria - * - * @param cmd - * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, - * name) - * @return the volume object - * @throws PermissionDeniedException - */ - Volume allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationException; - - /** - * Creates the volume based on the given criteria - * - * @param cmd - * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, - * name) - * @return the volume object - */ - Volume createVolume(CreateVolumeCmd cmd); - - - /** - * Resizes the volume based on the given criteria - * - * @param cmd - * the API command wrapping the criteria - * @return the volume object - */ - Volume resizeVolume(ResizeVolumeCmd cmd); - /** * Delete the storage pool * @@ -120,19 +82,4 @@ public interface StorageService{ public StoragePool updateStoragePool(UpdateStoragePoolCmd cmd) throws IllegalArgumentException; public StoragePool getStoragePool(long id); - - Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException; - - - /** - * Uploads the volume to secondary storage - * - * @param UploadVolumeCmd cmd - * - * @return Volume object - */ - Volume uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException; - - boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException; - } diff --git a/api/src/com/cloud/storage/Volume.java b/api/src/com/cloud/storage/Volume.java index 284c83d9e93..4903594f0af 100755 --- a/api/src/com/cloud/storage/Volume.java +++ b/api/src/com/cloud/storage/Volume.java @@ -39,9 +39,12 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba Snapshotting("There is a snapshot created on this volume, not backed up to secondary storage yet"), Resizing("The volume is being resized"), Expunging("The volume is being expunging"), + Expunged("The volume is being expunging"), Destroy("The volume is destroyed, and can't be recovered."), Destroying("The volume is destroying, and can't be recovered."), - UploadOp ("The volume upload operation is in progress or in short the volume is on secondary storage"); + UploadOp ("The volume upload operation is in progress or in short the volume is on secondary storage"), + Uploading("volume is uploading"), + Uploaded("volume is uploaded"); String _description; @@ -70,12 +73,15 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba s_fsm.addTransition(Resizing, Event.OperationSucceeded, Ready); s_fsm.addTransition(Resizing, Event.OperationFailed, Ready); s_fsm.addTransition(Allocated, Event.UploadRequested, UploadOp); - s_fsm.addTransition(UploadOp, Event.CopyRequested, Creating);// CopyRequested for volume from sec to primary storage + s_fsm.addTransition(Uploaded, Event.CopyRequested, Creating);// CopyRequested for volume from sec to primary storage s_fsm.addTransition(Creating, Event.CopySucceeded, Ready); - s_fsm.addTransition(Creating, Event.CopyFailed, UploadOp);// Copying volume from sec to primary failed. + s_fsm.addTransition(Creating, Event.CopyFailed, Uploaded);// Copying volume from sec to primary failed. s_fsm.addTransition(UploadOp, Event.DestroyRequested, Destroy); s_fsm.addTransition(Ready, Event.DestroyRequested, Destroy); s_fsm.addTransition(Destroy, Event.ExpungingRequested, Expunging); + s_fsm.addTransition(Expunging, Event.ExpungingRequested, Expunging); + s_fsm.addTransition(Expunging, Event.OperationSucceeded, Expunged); + s_fsm.addTransition(Expunging, Event.OperationFailed, Expunging); s_fsm.addTransition(Ready, Event.SnapshotRequested, Snapshotting); s_fsm.addTransition(Snapshotting, Event.OperationSucceeded, Ready); s_fsm.addTransition(Snapshotting, Event.OperationFailed, Ready); @@ -83,6 +89,9 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba s_fsm.addTransition(Migrating, Event.OperationSucceeded, Ready); s_fsm.addTransition(Migrating, Event.OperationFailed, Ready); s_fsm.addTransition(Destroy, Event.OperationSucceeded, Destroy); + s_fsm.addTransition(UploadOp, Event.OperationSucceeded, Uploaded); + s_fsm.addTransition(UploadOp, Event.OperationFailed, Allocated); + s_fsm.addTransition(Uploaded, Event.DestroyRequested, Destroy); } } @@ -110,7 +119,7 @@ public interface Volume extends ControlledEntity, Identity, InternalIdentity, Ba /** * @return total size of the partition */ - long getSize(); + Long getSize(); /** * @return the vm instance id diff --git a/api/src/com/cloud/storage/VolumeApiService.java b/api/src/com/cloud/storage/VolumeApiService.java new file mode 100644 index 00000000000..92880f4184d --- /dev/null +++ b/api/src/com/cloud/storage/VolumeApiService.java @@ -0,0 +1,80 @@ +/* + * 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.storage; + +import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.user.Account; + +public interface VolumeApiService { + /** + * Creates the database object for a volume based on the given criteria + * + * @param cmd + * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, + * name) + * @return the volume object + * @throws PermissionDeniedException + */ + Volume allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationException; + + /** + * Creates the volume based on the given criteria + * + * @param cmd + * the API command wrapping the criteria (account/domainId [admin only], zone, diskOffering, snapshot, + * name) + * @return the volume object + */ + Volume createVolume(CreateVolumeCmd cmd); + + + /** + * Resizes the volume based on the given criteria + * + * @param cmd + * the API command wrapping the criteria + * @return the volume object + */ + Volume resizeVolume(ResizeVolumeCmd cmd); + + Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException; + + /** + * Uploads the volume to secondary storage + * + * @param UploadVolumeCmd cmd + * + * @return Volume object + */ + Volume uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException; + + boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException; + + Volume attachVolumeToVM(AttachVolumeCmd command); + + Volume detachVolumeFromVM(DetachVolumeCmd cmmd); +} diff --git a/api/src/com/cloud/template/TemplateService.java b/api/src/com/cloud/template/TemplateService.java index 11475d46b8a..7e831fb0055 100755 --- a/api/src/com/cloud/template/TemplateService.java +++ b/api/src/com/cloud/template/TemplateService.java @@ -25,6 +25,7 @@ import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.ExtractIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.CopyTemplateCmd; +import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; @@ -32,6 +33,8 @@ import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import com.cloud.exception.InternalErrorException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.user.Account; +import com.cloud.utils.exception.CloudRuntimeException; public interface TemplateService { @@ -87,4 +90,11 @@ public interface TemplateService { List listTemplatePermissions(BaseListTemplateOrIsoPermissionsCmd cmd); boolean updateTemplateOrIsoPermissions(BaseUpdateTemplateOrIsoPermissionsCmd cmd); + + VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, + Account templateOwner) throws ResourceAllocationException; + + VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) + throws CloudRuntimeException; + } diff --git a/api/src/com/cloud/vm/UserVmService.java b/api/src/com/cloud/vm/UserVmService.java index fb574fa5848..ea89eda89d2 100755 --- a/api/src/com/cloud/vm/UserVmService.java +++ b/api/src/com/cloud/vm/UserVmService.java @@ -23,7 +23,6 @@ import javax.naming.InsufficientResourcesException; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; @@ -103,24 +102,6 @@ public interface UserVmService { */ UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException; - /** - * Attaches the specified volume to the specified VM - * - * @param cmd - * - the command specifying volumeId and vmId - * @return the Volume object if attach worked successfully. - */ - Volume attachVolumeToVM(AttachVolumeCmd cmd); - - /** - * Detaches the specified volume from the VM it is currently attached to. - * - * @param cmd - * - the command specifying volumeId - * @return the Volume object if detach worked successfully. - */ - Volume detachVolumeFromVM(DetachVolumeCmd cmmd); - UserVm startVirtualMachine(StartVMCmd cmd) throws StorageUnavailableException, ExecutionException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException; @@ -151,28 +132,6 @@ public interface UserVmService { UserVm recoverVirtualMachine(RecoverVMCmd cmd) throws ResourceAllocationException; - /** - * Create a template database record in preparation for creating a private template. - * - * @param cmd - * the command object that defines the name, display text, snapshot/volume, bits, public/private, etc. - * for the - * private template - * @param templateOwner - * TODO - * @return the vm template object if successful, null otherwise - * @throws ResourceAllocationException - */ - VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException; - - /** - * Creates a private template from a snapshot of a VM - * - * @param cmd - * - the command specifying snapshotId, name, description - * @return a template if successfully created, null otherwise - */ - VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd cmd); /** * Creates a Basic Zone User VM in the database and returns the VM to the caller. diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java index 35a11dd7a53..252e31d82a5 100755 --- a/api/src/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/org/apache/cloudstack/api/ApiConstants.java @@ -444,6 +444,7 @@ public class ApiConstants { public static final String VM_SNAPSHOT_ID = "vmsnapshotid"; public static final String VM_SNAPSHOT_DISK_IDS = "vmsnapshotdiskids"; public static final String VM_SNAPSHOT_MEMORY = "snapshotmemory"; + public static final String IMAGE_STORE_UUID = "imagestoreuuid"; public enum HostDetails { all, capacity, events, stats, min; diff --git a/api/src/org/apache/cloudstack/api/BaseCmd.java b/api/src/org/apache/cloudstack/api/BaseCmd.java index 17f789f88fa..816b6deed77 100644 --- a/api/src/org/apache/cloudstack/api/BaseCmd.java +++ b/api/src/org/apache/cloudstack/api/BaseCmd.java @@ -62,6 +62,7 @@ import com.cloud.resource.ResourceService; import com.cloud.server.ManagementService; import com.cloud.server.TaggedResourceService; import com.cloud.storage.StorageService; +import com.cloud.storage.VolumeApiService; import com.cloud.storage.snapshot.SnapshotService; import com.cloud.template.TemplateService; import com.cloud.user.Account; @@ -69,7 +70,6 @@ import com.cloud.user.AccountService; import com.cloud.user.DomainService; import com.cloud.user.ResourceLimitService; import com.cloud.utils.Pair; -import com.cloud.vm.BareMetalVmService; import com.cloud.vm.UserVmService; import com.cloud.vm.snapshot.VMSnapshotService; @@ -102,6 +102,7 @@ public abstract class BaseCmd { @Inject public UserVmService _userVmService; @Inject public ManagementService _mgr; @Inject public StorageService _storageService; + @Inject public VolumeApiService _volumeService; @Inject public ResourceService _resourceService; @Inject public NetworkService _networkService; @Inject public TemplateService _templateService; diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java index a3497a89f98..cae58886015 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/storage/CreateStoragePoolCmd.java @@ -36,6 +36,7 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.storage.StoragePool; import com.cloud.user.Account; + @SuppressWarnings("rawtypes") @APICommand(name = "createStoragePool", description="Creates a storage pool.", responseObject=StoragePoolResponse.class) public class CreateStoragePoolCmd extends BaseCmd { @@ -70,6 +71,14 @@ public class CreateStoragePoolCmd extends BaseCmd { @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class, required=true, description="the Zone ID for the storage pool") private Long zoneId; + + @Parameter(name=ApiConstants.PROVIDER, type=CommandType.UUID, + required=false, description="the storage provider uuid") + private String storageProviderUuid; + + @Parameter(name=ApiConstants.SCOPE, type=CommandType.STRING, + required=false, description="the scope of the storage: cluster or zone") + private String scope; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -102,6 +111,14 @@ public class CreateStoragePoolCmd extends BaseCmd { public Long getZoneId() { return zoneId; } + + public String getStorageProviderUuid() { + return this.storageProviderUuid; + } + + public String getScope() { + return this.scope; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java index a4a37c8fd58..5bc4d6e6a79 100644 --- a/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/iso/RegisterIsoCmd.java @@ -88,6 +88,10 @@ public class RegisterIsoCmd extends BaseCmd { @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, description="Register iso for the project") private Long projectId; + + @Parameter(name=ApiConstants.IMAGE_STORE_UUID, type=CommandType.UUID, + description="Image store uuid") + private String imageStoreUuid; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -140,6 +144,10 @@ public class RegisterIsoCmd extends BaseCmd { public String getChecksum() { return checksum; } + + public String getImageStoreUuid() { + return this.imageStoreUuid; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java index 84fa197d12c..ba1f924fe02 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/CreateTemplateCmd.java @@ -240,7 +240,7 @@ import com.cloud.user.UserContext; @Override public void create() throws ResourceAllocationException { VirtualMachineTemplate template = null; - template = _userVmService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); + template = this._templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); if (template != null) { this.setEntityId(template.getId()); this.setEntityUuid(template.getUuid()); @@ -255,7 +255,7 @@ import com.cloud.user.UserContext; public void execute() { UserContext.current().setEventDetails("Template Id: "+getEntityId()+((getSnapshotId() == null) ? " from volume Id: " + getVolumeId() : " from snapshot Id: " + getSnapshotId())); VirtualMachineTemplate template = null; - template = _userVmService.createPrivateTemplate(this); + template = this._templateService.createPrivateTemplate(this); if (template != null){ List templateResponses; diff --git a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java index 3e98ca624ab..ed719671587 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java @@ -110,7 +110,11 @@ public class RegisterTemplateCmd extends BaseCmd { @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, description="Register template for the project") private Long projectId; - + + @Parameter(name=ApiConstants.IMAGE_STORE_UUID, type=CommandType.UUID, + description="Image store uuid") + private String imageStoreUuid; + @Parameter(name=ApiConstants.DETAILS, type=CommandType.MAP, description="Template details in key/value pairs.") protected Map details; @@ -189,6 +193,10 @@ public class RegisterTemplateCmd extends BaseCmd { public String getTemplateTag() { return templateTag; } + + public String getImageStoreUuid() { + return this.imageStoreUuid; + } public Map getDetails() { if (details == null || details.isEmpty()) { diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/AttachVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/AttachVolumeCmd.java index 4d82534c2b2..e577e35795e 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/AttachVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/AttachVolumeCmd.java @@ -119,7 +119,7 @@ public class AttachVolumeCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("Volume Id: "+getId()+" VmId: "+getVirtualMachineId()); - Volume result = _userVmService.attachVolumeToVM(this); + Volume result = _volumeService.attachVolumeToVM(this); if (result != null) { VolumeResponse response = _responseGenerator.createVolumeResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java index 2f77862b3b9..5db06bcd47f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java @@ -153,7 +153,7 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException{ - Volume volume = _storageService.allocVolume(this); + Volume volume = this._volumeService.allocVolume(this); if (volume != null) { this.setEntityId(volume.getId()); this.setEntityUuid(volume.getUuid()); @@ -165,7 +165,7 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd { @Override public void execute(){ UserContext.current().setEventDetails("Volume Id: "+getEntityId()+((getSnapshotId() == null) ? "" : " from snapshot: " + getSnapshotId())); - Volume volume = _storageService.createVolume(this); + Volume volume = _volumeService.createVolume(this); if (volume != null) { VolumeResponse response = _responseGenerator.createVolumeResponse(volume); //FIXME - have to be moved to ApiResponseHelper diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java index 39c3de3fac9..394b0092123 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/DeleteVolumeCmd.java @@ -80,7 +80,7 @@ public class DeleteVolumeCmd extends BaseCmd { @Override public void execute() throws ConcurrentOperationException { UserContext.current().setEventDetails("Volume Id: "+getId()); - boolean result = _storageService.deleteVolume(id, UserContext.current().getCaller()); + boolean result = this._volumeService.deleteVolume(id, UserContext.current().getCaller()); if (result) { SuccessResponse response = new SuccessResponse(getCommandName()); this.setResponseObject(response); diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/DetachVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/DetachVolumeCmd.java index 6153e17448b..9a5929eccca 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/DetachVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/DetachVolumeCmd.java @@ -130,7 +130,7 @@ public class DetachVolumeCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("Volume Id: "+getId()+" VmId: "+getVirtualMachineId()); - Volume result = _userVmService.detachVolumeFromVM(this); + Volume result = _volumeService.detachVolumeFromVM(this); if (result != null){ VolumeResponse response = _responseGenerator.createVolumeResponse(result); response.setResponseName("volume"); diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java index d43ad5500e1..8c09f8fbb72 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java @@ -92,7 +92,7 @@ public class MigrateVolumeCmd extends BaseAsyncCmd { public void execute(){ Volume result; try { - result = _storageService.migrateVolume(getVolumeId(), getStoragePoolId()); + result = _volumeService.migrateVolume(getVolumeId(), getStoragePoolId()); if (result != null) { VolumeResponse response = _responseGenerator.createVolumeResponse(result); response.setResponseName(getCommandName()); diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/ResizeVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/ResizeVolumeCmd.java index 52863444507..955727a7d82 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/ResizeVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/ResizeVolumeCmd.java @@ -133,7 +133,7 @@ public class ResizeVolumeCmd extends BaseAsyncCmd { @Override public void execute(){ UserContext.current().setEventDetails("Volume Id: " + getEntityId() + " to size " + getSize() + "G"); - Volume volume = _storageService.resizeVolume(this); + Volume volume = _volumeService.resizeVolume(this); if (volume != null) { VolumeResponse response = _responseGenerator.createVolumeResponse(volume); //FIXME - have to be moved to ApiResponseHelper diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java index 107d938b106..94c3d38e5a4 100644 --- a/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/volume/UploadVolumeCmd.java @@ -67,6 +67,10 @@ public class UploadVolumeCmd extends BaseAsyncCmd { @Parameter(name=ApiConstants.CHECKSUM, type=CommandType.STRING, description="the MD5 checksum value of this volume") private String checksum; + + @Parameter(name=ApiConstants.IMAGE_STORE_UUID, type=CommandType.UUID, + description="Image store uuid") + private String imageStoreUuid; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -99,6 +103,10 @@ public class UploadVolumeCmd extends BaseAsyncCmd { public String getChecksum() { return checksum; } + + public String getImageStoreUuid() { + return this.imageStoreUuid; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// @@ -110,7 +118,7 @@ public class UploadVolumeCmd extends BaseAsyncCmd { ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { - Volume volume = _storageService.uploadVolume(this); + Volume volume = _volumeService.uploadVolume(this); if (volume != null){ VolumeResponse response = _responseGenerator.createVolumeResponse(volume); response.setResponseName(getCommandName()); diff --git a/api/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java b/api/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java index 7836b6d6e8e..71004977d89 100644 --- a/api/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java +++ b/api/test/org/apache/cloudstack/api/agent/test/BackupSnapshotCommandTest.java @@ -133,15 +133,15 @@ public class BackupSnapshotCommandTest { } @Override - public String getStorageProvider() { + public Long getStorageProviderId() { // TODO Auto-generated method stub return null; } @Override - public String getStorageType() { + public boolean isInMaintenance() { // TODO Auto-generated method stub - return null; + return false; }; }; diff --git a/api/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java b/api/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java index 3545d0f1c29..767d7c37c5e 100644 --- a/api/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java +++ b/api/test/org/apache/cloudstack/api/agent/test/SnapshotCommandTest.java @@ -115,16 +115,16 @@ public class SnapshotCommandTest { } @Override - public String getStorageProvider() { + public Long getStorageProviderId() { // TODO Auto-generated method stub return null; } - @Override - public String getStorageType() { - // TODO Auto-generated method stub - return null; - }; + @Override + public boolean isInMaintenance() { + // TODO Auto-generated method stub + return false; + }; }; SnapshotCommand ssc = new SnapshotCommand(pool, diff --git a/api/test/src/com/cloud/agent/api/test/ResizeVolumeCommandTest.java b/api/test/src/com/cloud/agent/api/test/ResizeVolumeCommandTest.java index 7f5540fa4d3..852e52b1b86 100644 --- a/api/test/src/com/cloud/agent/api/test/ResizeVolumeCommandTest.java +++ b/api/test/src/com/cloud/agent/api/test/ResizeVolumeCommandTest.java @@ -134,15 +134,15 @@ public class ResizeVolumeCommandTest { } @Override - public String getStorageProvider() { + public Long getStorageProviderId() { // TODO Auto-generated method stub return null; } @Override - public String getStorageType() { + public boolean isInMaintenance() { // TODO Auto-generated method stub - return null; + return false; }; }; diff --git a/client/pom.xml b/client/pom.xml index 178ddc6d128..108cc3ac05c 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -282,7 +282,8 @@ - + + diff --git a/core/pom.xml b/core/pom.xml index acc742fd964..0da69529400 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -31,7 +31,11 @@ cloud-api ${project.version} - + + org.apache.cloudstack + cloud-engine-api + ${project.version} + commons-httpclient commons-httpclient diff --git a/core/src/com/cloud/storage/StoragePoolDiscoverer.java b/core/src/com/cloud/storage/StoragePoolDiscoverer.java index 816e899f941..c7dd362a5c3 100644 --- a/core/src/com/cloud/storage/StoragePoolDiscoverer.java +++ b/core/src/com/cloud/storage/StoragePoolDiscoverer.java @@ -19,6 +19,8 @@ package com.cloud.storage; import java.net.URI; import java.util.Map; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.exception.DiscoveryException; import com.cloud.utils.component.Adapter; diff --git a/core/src/com/cloud/storage/StoragePoolVO.java b/core/src/com/cloud/storage/StoragePoolVO.java deleted file mode 100644 index af6e4e2905c..00000000000 --- a/core/src/com/cloud/storage/StoragePoolVO.java +++ /dev/null @@ -1,346 +0,0 @@ -// 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.storage; - -import java.util.Date; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.TableGenerator; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; - -import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.utils.db.GenericDao; - -@Entity -@Table(name="storage_pool") -public class StoragePoolVO implements StoragePool { - @Id - @TableGenerator(name="storage_pool_sq", table="sequence", pkColumnName="name", valueColumnName="value", pkColumnValue="storage_pool_seq", allocationSize=1) - @Column(name="id", updatable=false, nullable = false) - private long id; - - @Column(name="name", updatable=false, nullable=false, length=255) - private String name = null; - - @Column(name="uuid", length=255) - private String uuid = null; - - @Column(name="pool_type", updatable=false, nullable=false, length=32) - @Enumerated(value=EnumType.STRING) - private StoragePoolType poolType; - - @Column(name=GenericDao.CREATED_COLUMN) - Date created; - - @Column(name=GenericDao.REMOVED_COLUMN) - private Date removed; - - @Column(name="update_time", updatable=true) - @Temporal(value=TemporalType.TIMESTAMP) - private Date updateTime; - - @Column(name="data_center_id", updatable=true, nullable=false) - private long dataCenterId; - - @Column(name="pod_id", updatable=true) - private Long podId; - - @Column(name="available_bytes", updatable=true, nullable=true) - private long availableBytes; - - @Column(name="capacity_bytes", updatable=true, nullable=true) - private long capacityBytes; - - @Column(name="status", updatable=true, nullable=false) - @Enumerated(value=EnumType.STRING) - private StoragePoolStatus status; - - // TODO, disable persisency of storageProvider and storageType, javelin new code not - // sync with the schema! - - // @Column(name="storage_provider", updatable=true, nullable=false) - @Transient private String storageProvider; - - // Column(name="storage_type", nullable=false) - @Transient private String storageType; - - @Override - public long getId() { - return id; - } - - @Override - public StoragePoolStatus getStatus() { - return status; - } - - public StoragePoolVO() { - // TODO Auto-generated constructor stub - } - - @Override - public String getName() { - return name; - } - - @Override - public String getUuid() { - return uuid; - } - - @Override - public StoragePoolType getPoolType() { - return poolType; - } - - @Override - public Date getCreated() { - return created; - } - - public Date getRemoved() { - return removed; - } - - @Override - public Date getUpdateTime() { - return updateTime; - } - - @Override - public long getDataCenterId() { - return dataCenterId; - } - - @Override - public long getAvailableBytes() { - return availableBytes; - } - - @Override - public String getStorageProvider() { - return storageProvider; - } - - public void setStorageProvider(String provider) { - storageProvider = provider; - } - - @Override - public String getStorageType() { - return storageType; - } - - public void setStorageType(String type) { - storageType = type; - } - - @Override - public long getCapacityBytes() { - return capacityBytes; - } - - public void setAvailableBytes(long available) { - availableBytes = available; - } - - public void setCapacityBytes(long capacity) { - capacityBytes = capacity; - } - - @Column(name="host_address") - private String hostAddress; - - @Column(name="path") - private String path; - - @Column(name="port") - private int port; - - @Column(name="user_info") - private String userInfo; - - @Column(name="cluster_id") - private Long clusterId; - - - @Override - public Long getClusterId() { - return clusterId; - } - - public void setClusterId(Long clusterId) { - this.clusterId = clusterId; - } - - @Override - public String getHostAddress() { - return hostAddress; - } - - @Override - public String getPath() { - return path; - } - - @Override - public String getUserInfo() { - return userInfo; - } - - public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type, - long dataCenterId, Long podId, long availableBytes, long capacityBytes, String hostAddress, int port, String hostPath) { - this.name = name; - this.id = poolId; - this.uuid = uuid; - this.poolType = type; - this.dataCenterId = dataCenterId; - this.availableBytes = availableBytes; - this.capacityBytes = capacityBytes; - this.hostAddress = hostAddress; - this.path = hostPath; - this.port = port; - this.podId = podId; - this.setStatus(StoragePoolStatus.Creating); - } - - public StoragePoolVO(StoragePoolVO that) { - this(that.id, that.name, that.uuid, that.poolType, that.dataCenterId, that.podId, that.availableBytes, that.capacityBytes, that.hostAddress, that.port, that.path); - } - - public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path) { - this.poolType = type; - this.hostAddress = hostAddress; - this.port = port; - this.path = path; - this.setStatus(StoragePoolStatus.Creating); - this.uuid = UUID.randomUUID().toString(); - } - - public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path, String userInfo) { - this.poolType = type; - this.hostAddress = hostAddress; - this.port = port; - this.path = path; - this.userInfo = userInfo; - this.setStatus(StoragePoolStatus.Creating); - this.uuid = UUID.randomUUID().toString(); - } - - public void setStatus(StoragePoolStatus status) - { - this.status = status; - } - - public void setId(long id) { - this.id = id; - } - - public void setDataCenterId(long dcId) { - this.dataCenterId = dcId; - } - - public void setPodId(Long podId) { - this.podId = podId; - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public void setPath(String path) { - this.path = path; - } - - public void setUserInfo(String userInfo) { - this.userInfo = userInfo; - } - - @Override - public int getPort() { - return port; - } - - @Override - public boolean isShared() { - return poolType.isShared(); - } - - @Override - public boolean isLocal() { - return !poolType.isShared(); - } - - @Transient - public String toUri() { - /* - URI uri = new URI(); - try { - if (type == StoragePoolType.Filesystem) { - uri.setScheme("file"); - } else if (type == StoragePoolType.NetworkFilesystem) { - uri.setScheme("nfs"); - } else if (type == StoragePoolType.IscsiLUN) { - } - } catch (MalformedURIException e) { - throw new VmopsRuntimeException("Unable to form the uri " + id); - } - return uri.toString(); - */ - return null; - } - - @Override - public Long getPodId() { - return podId; - } - - public void setName(String name) { - this.name = name; - } - - public boolean isInMaintenance() { - return status == StoragePoolStatus.PrepareForMaintenance || status == StoragePoolStatus.Maintenance || status == StoragePoolStatus.ErrorInMaintenance || removed != null; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof StoragePoolVO) || obj == null) { - return false; - } - StoragePoolVO that = (StoragePoolVO)obj; - return this.id == that.id; - } - - @Override - public int hashCode() { - return new Long(id).hashCode(); - } - - @Override - public String toString() { - return new StringBuilder("Pool[").append(id).append("|").append(poolType).append("]").toString(); - } -} diff --git a/core/src/com/cloud/storage/VMTemplateHostVO.java b/core/src/com/cloud/storage/VMTemplateHostVO.java index 9eae1a00303..b8dfc41d51b 100755 --- a/core/src/com/cloud/storage/VMTemplateHostVO.java +++ b/core/src/com/cloud/storage/VMTemplateHostVO.java @@ -29,8 +29,10 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.utils.db.GenericDaoBase; -import org.apache.cloudstack.api.InternalIdentity; /** * Join table for storage hosts and templates @@ -38,7 +40,7 @@ import org.apache.cloudstack.api.InternalIdentity; */ @Entity @Table(name="template_host_ref") -public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc { +public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc, DataObjectInStore { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) Long id; @@ -90,6 +92,18 @@ public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc { @Column(name="destroyed") boolean destroyed = false; + @Column(name="update_count", updatable = true, nullable=false) + protected long updatedCount; + + @Column(name = "updated") + @Temporal(value = TemporalType.TIMESTAMP) + Date updated; + + @Column(name = "state") + @Enumerated(EnumType.STRING) + ObjectInDataStoreStateMachine.State state; + + @Override public String getInstallPath() { return installPath; @@ -162,6 +176,7 @@ public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc { super(); this.hostId = hostId; this.templateId = templateId; + this.state = ObjectInDataStoreStateMachine.State.Allocated; } public VMTemplateHostVO(long hostId, long templateId, Date lastUpdated, @@ -282,4 +297,26 @@ public class VMTemplateHostVO implements VMTemplateStorageResourceAssoc { return new StringBuilder("TmplHost[").append(id).append("-").append(templateId).append("-").append(hostId).append(installPath).append("]").toString(); } + @Override + public ObjectInDataStoreStateMachine.State getState() { + // TODO Auto-generated method stub + return this.state; + } + + public long getUpdatedCount() { + return this.updatedCount; + } + + public void incrUpdatedCount() { + this.updatedCount++; + } + + public void decrUpdatedCount() { + this.updatedCount--; + } + + public Date getUpdated() { + return updated; + } + } diff --git a/core/src/com/cloud/storage/VMTemplateStoragePoolVO.java b/core/src/com/cloud/storage/VMTemplateStoragePoolVO.java index 32c9dd2ece5..9b761764359 100644 --- a/core/src/com/cloud/storage/VMTemplateStoragePoolVO.java +++ b/core/src/com/cloud/storage/VMTemplateStoragePoolVO.java @@ -29,8 +29,11 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; + import com.cloud.utils.db.GenericDaoBase; -import org.apache.cloudstack.api.InternalIdentity; /** * Join table for storage pools and templates @@ -38,7 +41,7 @@ import org.apache.cloudstack.api.InternalIdentity; */ @Entity @Table(name="template_spool_ref") -public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc { +public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc, DataObjectInStore { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) long id; @@ -69,7 +72,18 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc { @Column (name="template_size") long templateSize; @Column (name="marked_for_gc") boolean markedForGC; - + + @Column(name="update_count", updatable = true, nullable=false) + protected long updatedCount; + + @Column(name = "updated") + @Temporal(value = TemporalType.TIMESTAMP) + Date updated; + + @Column(name = "state") + @Enumerated(EnumType.STRING) + ObjectInDataStoreStateMachine.State state; + @Override public String getInstallPath() { return installPath; @@ -148,6 +162,7 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc { this.poolId = poolId; this.templateId = templateId; this.downloadState = Status.NOT_DOWNLOADED; + this.state = ObjectInDataStoreStateMachine.State.Allocated; this.markedForGC = false; } @@ -235,4 +250,26 @@ public class VMTemplateStoragePoolVO implements VMTemplateStorageResourceAssoc { return new StringBuilder("TmplPool[").append(id).append("-").append(templateId).append("-").append("poolId").append("-").append(installPath).append("]").toString(); } + @Override + public State getState() { + return this.state; + } + + public long getUpdatedCount() { + return this.updatedCount; + } + + public void incrUpdatedCount() { + this.updatedCount++; + } + + public void decrUpdatedCount() { + this.updatedCount--; + } + + public Date getUpdated() { + return updated; + } + + } diff --git a/core/src/com/cloud/storage/VMTemplateVO.java b/core/src/com/cloud/storage/VMTemplateVO.java index fcfdd0067e1..e643d75bf1e 100755 --- a/core/src/com/cloud/storage/VMTemplateVO.java +++ b/core/src/com/cloud/storage/VMTemplateVO.java @@ -31,17 +31,18 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; -import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; + import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.template.VirtualMachineTemplate; import com.cloud.utils.db.GenericDao; -import org.apache.cloudstack.api.InternalIdentity; +import com.cloud.utils.fsm.StateObject; @Entity @Table(name="vm_template") -public class VMTemplateVO implements VirtualMachineTemplate { +public class VMTemplateVO implements VirtualMachineTemplate, StateObject { @Id @TableGenerator(name="vm_template_sq", table="sequence", pkColumnName="name", valueColumnName="value", pkColumnValue="vm_template_seq", allocationSize=1) @Column(name="id", nullable = false) @@ -127,6 +128,22 @@ public class VMTemplateVO implements VirtualMachineTemplate { @Column(name="enable_sshkey") private boolean enableSshKey; + + @Column(name = "image_data_store_id") + private long imageDataStoreId; + + @Column(name = "size") + private Long size; + + @Column(name = "state") + private TemplateState state; + + @Column(name="update_count", updatable = true) + protected long updatedCount; + + @Column(name = "updated") + @Temporal(value = TemporalType.TIMESTAMP) + Date updated; @Transient Map details; @@ -140,8 +157,9 @@ public class VMTemplateVO implements VirtualMachineTemplate { this.uniqueName = uniqueName; } - protected VMTemplateVO() { + public VMTemplateVO() { this.uuid = UUID.randomUUID().toString(); + this.state = TemplateState.Allocated; } /** @@ -150,12 +168,14 @@ public class VMTemplateVO implements VirtualMachineTemplate { public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType, Map details) { this(id, generateUniqueName(id, accountId, name), name, format, isPublic, featured, isExtractable, type, url, null, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType, details); this.uuid = UUID.randomUUID().toString(); + this.state = TemplateState.Allocated; } public VMTemplateVO(long id, String name, ImageFormat format, boolean isPublic, boolean featured, boolean isExtractable, TemplateType type, String url, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType, String templateTag, Map details, boolean sshKeyEnabled) { this(id, name, format, isPublic, featured, isExtractable, type, url, requiresHvm, bits, accountId, cksum, displayText, enablePassword, guestOSId, bootable, hyperType, details); this.templateTag = templateTag; this.uuid = UUID.randomUUID().toString(); + this.state = TemplateState.Allocated; this.enableSshKey = sshKeyEnabled; } @@ -179,6 +199,7 @@ public class VMTemplateVO implements VirtualMachineTemplate { this.bootable = bootable; this.hypervisorType = hyperType; this.uuid = UUID.randomUUID().toString(); + this.state = TemplateState.Allocated; } // Has an extra attribute - isExtractable @@ -468,5 +489,46 @@ public class VMTemplateVO implements VirtualMachineTemplate { public void setEnableSshKey(boolean enable) { enableSshKey = enable; } + + public Long getImageDataStoreId() { + return this.imageDataStoreId; + } + + public void setImageDataStoreId(long dataStoreId) { + this.imageDataStoreId = dataStoreId; + } + + public void setSize(Long size) { + this.size = size; + } + + public Long getSize() { + return this.size; + } + + public TemplateState getState() { + return this.state; + } + + public long getUpdatedCount() { + return this.updatedCount; + } + + public void incrUpdatedCount() { + this.updatedCount++; + } + + public void decrUpdatedCount() { + this.updatedCount--; + } + + public Date getUpdated() { + return updated; + } + + public void setUpdated(Date updated) { + this.updated = updated; + } + } diff --git a/core/src/com/cloud/storage/VolumeHostVO.java b/core/src/com/cloud/storage/VolumeHostVO.java index f4fc7abc4ee..40bae499122 100755 --- a/core/src/com/cloud/storage/VolumeHostVO.java +++ b/core/src/com/cloud/storage/VolumeHostVO.java @@ -29,11 +29,13 @@ import javax.persistence.Table; import javax.persistence.Temporal; import javax.persistence.TemporalType; -//import com.cloud.storage.VMVolumeStorageResourceAssoc.Status; +import org.apache.cloudstack.api.InternalIdentity; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.utils.db.GenericDaoBase; -import org.apache.cloudstack.api.InternalIdentity; /** * Join table for storage hosts and volumes @@ -41,7 +43,7 @@ import org.apache.cloudstack.api.InternalIdentity; */ @Entity @Table(name="volume_host_ref") -public class VolumeHostVO implements InternalIdentity { +public class VolumeHostVO implements InternalIdentity, DataObjectInStore { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) Long id; @@ -99,6 +101,16 @@ public class VolumeHostVO implements InternalIdentity { @Column(name="destroyed") boolean destroyed = false; + @Column(name="update_count", updatable = true, nullable=false) + protected long updatedCount; + + @Column(name = "updated") + @Temporal(value = TemporalType.TIMESTAMP) + Date updated; + + @Column(name = "state") + @Enumerated(EnumType.STRING) + ObjectInDataStoreStateMachine.State state; public String getInstallPath() { return installPath; @@ -187,6 +199,7 @@ public class VolumeHostVO implements InternalIdentity { super(); this.hostId = hostId; this.volumeId = volumeId; + this.state = ObjectInDataStoreStateMachine.State.Allocated; } public VolumeHostVO(long hostId, long volumeId, long zoneId, Date lastUpdated, @@ -308,5 +321,27 @@ public class VolumeHostVO implements InternalIdentity { public String toString() { return new StringBuilder("VolumeHost[").append(id).append("-").append(volumeId).append("-").append(hostId).append(installPath).append("]").toString(); } + + public long getUpdatedCount() { + return this.updatedCount; + } + + public void incrUpdatedCount() { + this.updatedCount++; + } + + public void decrUpdatedCount() { + this.updatedCount--; + } + + public Date getUpdated() { + return updated; + } + + @Override + public ObjectInDataStoreStateMachine.State getState() { + // TODO Auto-generated method stub + return this.state; + } } diff --git a/core/src/com/cloud/storage/VolumeVO.java b/core/src/com/cloud/storage/VolumeVO.java index defc841e1e3..a287c26348b 100755 --- a/core/src/com/cloud/storage/VolumeVO.java +++ b/core/src/com/cloud/storage/VolumeVO.java @@ -32,11 +32,9 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; -import org.apache.cloudstack.api.Identity; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.db.GenericDao; -import org.apache.cloudstack.api.InternalIdentity; @Entity @Table(name = "volumes") @@ -69,7 +67,7 @@ public class VolumeVO implements Volume { Long deviceId = null; @Column(name = "size") - long size; + Long size; @Column(name = "folder") String folder; @@ -257,11 +255,11 @@ public class VolumeVO implements Volume { } @Override - public long getSize() { + public Long getSize() { return size; } - public void setSize(long size) { + public void setSize(Long size) { this.size = size; } diff --git a/engine/api/pom.xml b/engine/api/pom.xml index ca03e590286..7fc612f5d6c 100644 --- a/engine/api/pom.xml +++ b/engine/api/pom.xml @@ -32,7 +32,7 @@ org.apache.cloudstack - cloud-framework-ipc + cloud-framework-api ${project.version} diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java index 812db48cf8c..0827cf6b674 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java @@ -28,4 +28,5 @@ public interface DataObject { public DataObjectType getType(); public DiskFormat getFormat(); public String getUuid(); + public void processEvent(ObjectInDataStoreStateMachine.Event event); } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectInStore.java similarity index 51% rename from engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManager.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectInStore.java index f27753dd2d7..60dfb9fb71f 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectInStore.java @@ -16,30 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.volume; +package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeProfile; -import org.apache.cloudstack.storage.volume.db.VolumeVO; +import com.cloud.utils.fsm.StateObject; -import com.cloud.storage.Volume; -import com.cloud.storage.Volume.Event; -import com.cloud.storage.Volume.State; -import com.cloud.utils.fsm.NoTransitionException; -import com.cloud.utils.fsm.StateMachine2; -public interface VolumeManager { - VolumeVO allocateDuplicateVolume(VolumeVO oldVol); - - VolumeVO processEvent(Volume vol, Volume.Event event) throws NoTransitionException; - - VolumeProfile getProfile(long volumeId); - - VolumeVO getVolume(long volumeId); - - VolumeVO updateVolume(VolumeVO volume); - - /** - * @return - */ - StateMachine2 getStateMachine(); +public interface DataObjectInStore extends StateObject { + public String getInstallPath(); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStore.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStore.java index 03f2b0408ae..f101f243047 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStore.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStore.java @@ -20,6 +20,9 @@ public interface DataStore { DataStoreDriver getDriver(); DataStoreRole getRole(); long getId(); + String getUuid(); String getUri(); Scope getScope(); + DataObject create(DataObject obj); + boolean delete(DataObject obj); } diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java index ef578a7b0d8..95e3d0b2ef8 100644 --- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreLifeCycle.java @@ -20,23 +20,23 @@ package org.apache.cloudstack.engine.subsystem.api.storage; import java.util.Map; +import com.cloud.agent.api.StoragePoolInfo; + public interface DataStoreLifeCycle { - public DataStore initialize(Map dsInfos); + public DataStore initialize(Map dsInfos); public boolean attachCluster(DataStore store, ClusterScope scope); - + public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo); boolean attachZone(DataStore dataStore, ZoneScope scope); public boolean dettach(); public boolean unmanaged(); - public boolean maintain(); - - public boolean cancelMaintain(); - - public boolean deleteDataStore(); + public boolean maintain(long storeId); + public boolean cancelMaintain(long storeId); + public boolean deleteDataStore(long storeId); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java similarity index 79% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManager.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java index 829be506ccc..15e49e133fb 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreManager.java @@ -16,14 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.datastore; +package org.apache.cloudstack.engine.subsystem.api.storage; +import java.util.List; import java.util.Map; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; public interface DataStoreManager { public DataStore getDataStore(long storeId, DataStoreRole role); + public DataStore getPrimaryDataStore(long storeId); + public DataStore getDataStore(String uuid, DataStoreRole role); + public List getImageStores(Scope scope); public DataStore registerDataStore(Map params, String providerUuid); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProvider.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java similarity index 83% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProvider.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java index 0d38f34f1c7..d29c4828713 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProvider.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProvider.java @@ -16,12 +16,10 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.datastore.provider; +package org.apache.cloudstack.engine.subsystem.api.storage; import java.util.Map; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; public interface DataStoreProvider { public DataStoreLifeCycle getLifeCycle(); diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManager.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java similarity index 90% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManager.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java index cbe045c5bc8..94998133196 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManager.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreProviderManager.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.datastore.provider; +package org.apache.cloudstack.engine.subsystem.api.storage; import java.util.List; @@ -26,5 +26,6 @@ public interface DataStoreProviderManager extends Manager { public DataStoreProvider getDataStoreProviderByUuid(String uuid); public DataStoreProvider getDataStoreProviderById(long id); public DataStoreProvider getDataStoreProvider(String name); + public DataStoreProvider getDefaultPrimaryDataStoreProvider(); public List getDataStoreProviders(); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreStatus.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreStatus.java similarity index 94% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreStatus.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreStatus.java index 23551e4d0ac..2388795410c 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreStatus.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreStatus.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.datastore; +package org.apache.cloudstack.engine.subsystem.api.storage; public enum DataStoreStatus { Initial, Initialized, Creating, Attaching, Up, PrepareForMaintenance, ErrorInMaintenance, CancelMaintenance, Maintenance, Removed; diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java new file mode 100644 index 00000000000..3ac17598bb0 --- /dev/null +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/HypervisorHostListener.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.engine.subsystem.api.storage; + +public interface HypervisorHostListener { + boolean hostConnect(long hostId, long poolId); + boolean hostDisconnected(long hostId, long poolId); +} diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/ImageDataFactory.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageDataFactory.java similarity index 84% rename from engine/storage/src/org/apache/cloudstack/storage/image/ImageDataFactory.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageDataFactory.java index 7c7c2a8c530..f0d69887c7d 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/ImageDataFactory.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageDataFactory.java @@ -16,10 +16,11 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.image; +package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; public interface ImageDataFactory { TemplateInfo getTemplate(long templateId, DataStore store); + TemplateInfo getTemplate(DataObject obj, DataStore store); + TemplateInfo getTemplate(long templateId); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageService.java similarity index 77% rename from engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageService.java index 319406d5001..119f3b1d32f 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/ImageService.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ImageService.java @@ -16,13 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.image; +package org.apache.cloudstack.engine.subsystem.api.storage; -import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.framework.async.AsyncCallFuture; public interface ImageService { AsyncCallFuture createTemplateAsync(TemplateInfo template, DataStore store); + AsyncCallFuture createTemplateFromSnapshotAsync(SnapshotInfo snapshot, TemplateInfo template, DataStore store); + AsyncCallFuture createTemplateFromVolumeAsync(VolumeInfo volume, TemplateInfo template, DataStore store); AsyncCallFuture deleteTemplateAsync(TemplateInfo template); + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/ObjectInDataStoreStateMachine.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java similarity index 95% rename from engine/storage/src/org/apache/cloudstack/storage/volume/ObjectInDataStoreStateMachine.java rename to engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java index d0530d1934a..af9974e1118 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/ObjectInDataStoreStateMachine.java +++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/ObjectInDataStoreStateMachine.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.cloudstack.storage.volume; +package org.apache.cloudstack.engine.subsystem.api.storage; import com.cloud.utils.fsm.StateObject; @@ -49,6 +49,7 @@ public interface ObjectInDataStoreStateMachine extends StateObject createVolumeAsync(VolumeInfo volume, long dataStoreId); + AsyncCallFuture createVolumeAsync(VolumeInfo volume, DataStore store); /** * Delete volume @@ -61,7 +53,7 @@ public interface VolumeService { * @return * @throws ConcurrentOperationException */ - AsyncCallFuture deleteVolumeAsync(VolumeInfo volume); + AsyncCallFuture expungeVolumeAsync(VolumeInfo volume); /** * @@ -71,21 +63,16 @@ public interface VolumeService { /** * */ - boolean createVolumeFromSnapshot(long volumeId, long snapshotId); + AsyncCallFuture createVolumeFromSnapshot(VolumeInfo volume, DataStore store, SnapshotInfo snapshot); - /** - * - */ - String grantAccess(VolumeInfo volume, EndPoint endpointId); - - TemplateOnPrimaryDataStoreInfo grantAccess(TemplateOnPrimaryDataStoreInfo template, EndPoint endPoint); - - /** - * - */ - boolean rokeAccess(long volumeId, long endpointId); VolumeEntity getVolumeEntity(long volumeId); AsyncCallFuture createVolumeFromTemplateAsync(VolumeInfo volume, long dataStoreId, TemplateInfo template); + AsyncCallFuture copyVolume(VolumeInfo srcVolume, DataStore destStore); + + boolean destroyVolume(long volumeId) throws ConcurrentOperationException; + + AsyncCallFuture registerVolume(VolumeInfo volume, DataStore store); + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDao.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDao.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDao.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDao.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDaoImpl.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDaoImpl.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDaoImpl.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderDaoImpl.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderVO.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderVO.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/DataStoreProviderVO.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java similarity index 65% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java index 24a5c790688..1530ced30fd 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java +++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDao.java @@ -21,23 +21,23 @@ package org.apache.cloudstack.storage.datastore.db; import java.util.List; import java.util.Map; -import org.apache.cloudstack.storage.datastore.DataStoreStatus; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreStatus; import com.cloud.utils.db.GenericDao; -public interface PrimaryDataStoreDao extends GenericDao { +public interface PrimaryDataStoreDao extends GenericDao { /** * @param datacenterId * -- the id of the datacenter (availability zone) */ - List listByDataCenterId(long datacenterId); + List listByDataCenterId(long datacenterId); /** * @param datacenterId * -- the id of the datacenter (availability zone) */ - List listBy(long datacenterId, long podId, Long clusterId); + List listBy(long datacenterId, long podId, Long clusterId); /** * Set capacity of storage pool in bytes @@ -59,7 +59,7 @@ public interface PrimaryDataStoreDao extends GenericDao details); + StoragePoolVO persist(StoragePoolVO pool, Map details); /** * Find pool by name. @@ -68,7 +68,7 @@ public interface PrimaryDataStoreDao extends GenericDao findPoolByName(String name); + List findPoolByName(String name); /** * Find pools by the pod that matches the details. @@ -79,9 +79,9 @@ public interface PrimaryDataStoreDao extends GenericDao findPoolsByDetails(long dcId, long podId, Long clusterId, Map details); + List findPoolsByDetails(long dcId, long podId, Long clusterId, Map details); - List findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, Boolean shared); + List findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, Boolean shared); /** * Find pool by UUID. @@ -90,13 +90,13 @@ public interface PrimaryDataStoreDao extends GenericDao listByStorageHost(String hostFqdnOrIp); + List listByStorageHost(String hostFqdnOrIp); - PrimaryDataStoreVO findPoolByHostPath(long dcId, Long podId, String host, String path, String uuid); + StoragePoolVO findPoolByHostPath(long dcId, Long podId, String host, String path, String uuid); - List listPoolByHostPath(String host, String path); + List listPoolByHostPath(String host, String path); void updateDetails(long poolId, Map details); @@ -104,13 +104,13 @@ public interface PrimaryDataStoreDao extends GenericDao searchForStoragePoolDetails(long poolId, String value); - List findIfDuplicatePoolsExistByUUID(String uuid); + List findIfDuplicatePoolsExistByUUID(String uuid); - List listByStatus(DataStoreStatus status); + List listByStatus(DataStoreStatus status); long countPoolsByStatus(DataStoreStatus... statuses); - List listByStatusInZone(long dcId, DataStoreStatus status); + List listByStatusInZone(long dcId, DataStoreStatus status); - List listPoolsByCluster(long clusterId); + List listPoolsByCluster(long clusterId); } \ No newline at end of file diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java similarity index 77% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java index faca54b569a..023b42bda9d 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java +++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDaoImpl.java @@ -29,7 +29,7 @@ import java.util.Map; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.storage.datastore.DataStoreStatus; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreStatus; import org.springframework.stereotype.Component; import com.cloud.utils.db.DB; @@ -43,12 +43,12 @@ import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; @Component -public class PrimaryDataStoreDaoImpl extends GenericDaoBase implements PrimaryDataStoreDao { - protected final SearchBuilder AllFieldSearch; - protected final SearchBuilder DcPodSearch; - protected final SearchBuilder DcPodAnyClusterSearch; - protected final SearchBuilder DeleteLvmSearch; - protected final GenericSearchBuilder StatusCountSearch; +public class PrimaryDataStoreDaoImpl extends GenericDaoBase implements PrimaryDataStoreDao { + protected final SearchBuilder AllFieldSearch; + protected final SearchBuilder DcPodSearch; + protected final SearchBuilder DcPodAnyClusterSearch; + protected final SearchBuilder DeleteLvmSearch; + protected final GenericSearchBuilder StatusCountSearch; @Inject protected PrimaryDataStoreDetailsDao _detailsDao; @@ -99,73 +99,73 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase findPoolByName(String name) { - SearchCriteria sc = AllFieldSearch.create(); + public List findPoolByName(String name) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("name", name); return listIncludingRemovedBy(sc); } @Override - public PrimaryDataStoreVO findPoolByUUID(String uuid) { - SearchCriteria sc = AllFieldSearch.create(); + public StoragePoolVO findPoolByUUID(String uuid) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("uuid", uuid); return findOneIncludingRemovedBy(sc); } @Override - public List findIfDuplicatePoolsExistByUUID(String uuid) { - SearchCriteria sc = AllFieldSearch.create(); + public List findIfDuplicatePoolsExistByUUID(String uuid) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("uuid", uuid); return listBy(sc); } @Override - public List listByDataCenterId(long datacenterId) { - SearchCriteria sc = AllFieldSearch.create(); + public List listByDataCenterId(long datacenterId) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("datacenterId", datacenterId); return listBy(sc); } @Override public void updateAvailable(long id, long available) { - PrimaryDataStoreVO pool = createForUpdate(id); + StoragePoolVO pool = createForUpdate(id); pool.setAvailableBytes(available); update(id, pool); } @Override public void updateCapacity(long id, long capacity) { - PrimaryDataStoreVO pool = createForUpdate(id); + StoragePoolVO pool = createForUpdate(id); pool.setCapacityBytes(capacity); update(id, pool); } @Override - public List listByStorageHost(String hostFqdnOrIp) { - SearchCriteria sc = AllFieldSearch.create(); + public List listByStorageHost(String hostFqdnOrIp) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("hostAddress", hostFqdnOrIp); return listIncludingRemovedBy(sc); } @Override - public List listByStatus(DataStoreStatus status) { - SearchCriteria sc = AllFieldSearch.create(); + public List listByStatus(DataStoreStatus status) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("status", status); return listBy(sc); } @Override - public List listByStatusInZone(long dcId, DataStoreStatus status) { - SearchCriteria sc = AllFieldSearch.create(); + public List listByStatusInZone(long dcId, DataStoreStatus status) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("status", status); sc.setParameters("datacenterId", dcId); return listBy(sc); } @Override - public PrimaryDataStoreVO findPoolByHostPath(long datacenterId, Long podId, String host, String path, String uuid) { - SearchCriteria sc = AllFieldSearch.create(); + public StoragePoolVO findPoolByHostPath(long datacenterId, Long podId, String host, String path, String uuid) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("hostAddress", host); sc.setParameters("path", path); sc.setParameters("datacenterId", datacenterId); @@ -176,16 +176,16 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase listBy(long datacenterId, long podId, Long clusterId) { + public List listBy(long datacenterId, long podId, Long clusterId) { if (clusterId != null) { - SearchCriteria sc = DcPodSearch.create(); + SearchCriteria sc = DcPodSearch.create(); sc.setParameters("datacenterId", datacenterId); sc.setParameters("podId", podId); sc.setParameters("cluster", clusterId); return listBy(sc); } else { - SearchCriteria sc = DcPodAnyClusterSearch.create(); + SearchCriteria sc = DcPodAnyClusterSearch.create(); sc.setParameters("datacenterId", datacenterId); sc.setParameters("podId", podId); return listBy(sc); @@ -193,16 +193,16 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase listPoolByHostPath(String host, String path) { - SearchCriteria sc = AllFieldSearch.create(); + public List listPoolByHostPath(String host, String path) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("hostAddress", host); sc.setParameters("path", path); return listBy(sc); } - public PrimaryDataStoreVO listById(Integer id) { - SearchCriteria sc = AllFieldSearch.create(); + public StoragePoolVO listById(Integer id) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("id", id); return findOneIncludingRemovedBy(sc); @@ -210,7 +210,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase details) { + public StoragePoolVO persist(StoragePoolVO pool, Map details) { Transaction txn = Transaction.currentTxn(); txn.start(); pool = super.persist(pool); @@ -226,7 +226,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase findPoolsByDetails(long dcId, long podId, Long clusterId, Map details) { + public List findPoolsByDetails(long dcId, long podId, Long clusterId, Map details) { StringBuilder sql = new StringBuilder(DetailsSqlPrefix); if (clusterId != null) { sql.append("storage_pool.cluster_id = ? OR storage_pool.cluster_id IS NULL) AND ("); @@ -248,7 +248,7 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase pools = new ArrayList(); + List pools = new ArrayList(); while (rs.next()) { pools.add(toEntityBean(rs, false)); } @@ -267,8 +267,8 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, Boolean shared) { - List storagePools = null; + public List findPoolsByTags(long dcId, long podId, Long clusterId, String[] tags, Boolean shared) { + List storagePools = null; if (tags == null || tags.length == 0) { storagePools = listBy(dcId, podId, clusterId); } else { @@ -279,8 +279,8 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase filteredStoragePools = new ArrayList(storagePools); - for (PrimaryDataStoreVO pool : storagePools) { + List filteredStoragePools = new ArrayList(storagePools); + for (StoragePoolVO pool : storagePools) { /* * if (shared != pool.isShared()) { * filteredStoragePools.remove(pool); } @@ -351,8 +351,8 @@ public class PrimaryDataStoreDaoImpl extends GenericDaoBase listPoolsByCluster(long clusterId) { - SearchCriteria sc = AllFieldSearch.create(); + public List listPoolsByCluster(long clusterId) { + SearchCriteria sc = AllFieldSearch.create(); sc.setParameters("clusterId", clusterId); return listBy(sc); diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailVO.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailVO.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailVO.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java similarity index 95% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java index 906742bb3f0..c2b109a959e 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java +++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDao.java @@ -18,7 +18,6 @@ package org.apache.cloudstack.storage.datastore.db; import java.util.Map; -import com.cloud.storage.StoragePoolDetailVO; import com.cloud.utils.db.GenericDao; public interface PrimaryDataStoreDetailsDao extends GenericDao { diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDaoImpl.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDaoImpl.java similarity index 100% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDaoImpl.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreDetailsDaoImpl.java diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreVO.java b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java similarity index 64% rename from engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreVO.java rename to engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java index 3e37ec7abe8..1782f16a4c1 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/db/PrimaryDataStoreVO.java +++ b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolVO.java @@ -1,24 +1,23 @@ -/* - * 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. - */ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. package org.apache.cloudstack.storage.datastore.db; import java.util.Date; +import java.util.UUID; import javax.persistence.Column; import javax.persistence.Entity; @@ -30,15 +29,15 @@ import javax.persistence.TableGenerator; import javax.persistence.Temporal; import javax.persistence.TemporalType; -import org.apache.cloudstack.api.Identity; import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; -import org.apache.cloudstack.storage.datastore.DataStoreStatus; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePoolStatus; import com.cloud.utils.db.GenericDao; @Entity -@Table(name = "storage_pool") -public class PrimaryDataStoreVO implements Identity { +@Table(name="storage_pool") +public class StoragePoolVO { @Id @TableGenerator(name = "storage_pool_sq", table = "sequence", pkColumnName = "name", valueColumnName = "value", pkColumnValue = "storage_pool_seq", allocationSize = 1) @Column(name = "id", updatable = false, nullable = false) @@ -51,7 +50,8 @@ public class PrimaryDataStoreVO implements Identity { private String uuid = null; @Column(name = "pool_type", updatable = false, nullable = false, length = 32) - private String poolType; + @Enumerated(value = EnumType.STRING) + private StoragePoolType poolType; @Column(name = GenericDao.CREATED_COLUMN) Date created; @@ -77,7 +77,7 @@ public class PrimaryDataStoreVO implements Identity { @Column(name = "status", updatable = true, nullable = false) @Enumerated(value = EnumType.STRING) - private DataStoreStatus status; + private StoragePoolStatus status; @Column(name = "storage_provider_id", updatable = true, nullable = false) private Long storageProviderId; @@ -105,28 +105,57 @@ public class PrimaryDataStoreVO implements Identity { return id; } - public DataStoreStatus getStatus() { + public StoragePoolStatus getStatus() { return status; } - public PrimaryDataStoreVO() { - this.status = DataStoreStatus.Initial; + public StoragePoolVO() { + this.status = StoragePoolStatus.Initial; } + + public StoragePoolVO(long poolId, String name, String uuid, StoragePoolType type, + long dataCenterId, Long podId, long availableBytes, long capacityBytes, String hostAddress, int port, String hostPath) { + this.name = name; + this.id = poolId; + this.uuid = uuid; + this.poolType = type; + this.dataCenterId = dataCenterId; + this.availableBytes = availableBytes; + this.capacityBytes = capacityBytes; + this.hostAddress = hostAddress; + this.path = hostPath; + this.port = port; + this.podId = podId; + this.setStatus(StoragePoolStatus.Initial); + } + + public StoragePoolVO(StoragePoolVO that) { + this(that.id, that.name, that.uuid, that.poolType, that.dataCenterId, that.podId, that.availableBytes, that.capacityBytes, that.hostAddress, that.port, that.path); + } + + public StoragePoolVO(StoragePoolType type, String hostAddress, int port, String path) { + this.poolType = type; + this.hostAddress = hostAddress; + this.port = port; + this.path = path; + this.setStatus(StoragePoolStatus.Initial); + this.uuid = UUID.randomUUID().toString(); + } + public String getName() { return name; } - @Override public String getUuid() { return uuid; } - public String getPoolType() { + public StoragePoolType getPoolType() { return poolType; } - public void setPoolType(String protocol) { + public void setPoolType(StoragePoolType protocol) { this.poolType = protocol; } @@ -194,7 +223,7 @@ public class PrimaryDataStoreVO implements Identity { return userInfo; } - public void setStatus(DataStoreStatus status) { + public void setStatus(StoragePoolStatus status) { this.status = status; } @@ -248,10 +277,10 @@ public class PrimaryDataStoreVO implements Identity { @Override public boolean equals(Object obj) { - if (!(obj instanceof PrimaryDataStoreVO) || obj == null) { + if (!(obj instanceof StoragePoolVO) || obj == null) { return false; } - PrimaryDataStoreVO that = (PrimaryDataStoreVO) obj; + StoragePoolVO that = (StoragePoolVO) obj; return this.id == that.id; } @@ -264,4 +293,12 @@ public class PrimaryDataStoreVO implements Identity { public String toString() { return new StringBuilder("Pool[").append(id).append("|").append(poolType).append("]").toString(); } -} \ No newline at end of file + + public boolean isShared() { + return this.scope == ScopeType.HOST ? false : true; + } + + public boolean isLocal() { + return !isShared(); + } +} diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java index b91a2cabd62..ee08cf3b0c7 100644 --- a/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java +++ b/engine/orchestration/src/org/apache/cloudstack/engine/cloud/entity/api/VMEntityManagerImpl.java @@ -20,7 +20,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import javax.inject.Inject; @@ -28,6 +27,7 @@ import org.apache.cloudstack.engine.cloud.entity.api.db.VMEntityVO; import org.apache.cloudstack.engine.cloud.entity.api.db.VMReservationVO; import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMEntityDao; import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMReservationDao; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.springframework.stereotype.Component; import com.cloud.dc.DataCenter; @@ -45,22 +45,18 @@ import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.dao.NetworkDao; import com.cloud.org.Cluster; import com.cloud.service.dao.ServiceOfferingDao; -import com.cloud.storage.StoragePoolVO; +import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VolumeDao; -import com.cloud.user.Account; -import com.cloud.user.User; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; import com.cloud.utils.component.ComponentContext; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachineManager; -import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.VirtualMachineProfileImpl; import com.cloud.vm.dao.VMInstanceDao; @@ -104,6 +100,8 @@ public class VMEntityManagerImpl implements VMEntityManager { @Inject protected StoragePoolDao _storagePoolDao; + @Inject + DataStoreManager dataStoreMgr; @Override public VMEntityVO loadVirtualMachine(String vmId) { @@ -134,7 +132,8 @@ public class VMEntityManagerImpl implements VMEntityManager { List vols = _volsDao.findReadyRootVolumesByInstance(vm.getId()); if(!vols.isEmpty()){ VolumeVO vol = vols.get(0); - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); + StoragePool pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(vol.getPoolId()); + if (!pool.isInMaintenance()) { long rootVolDcId = pool.getDataCenterId(); Long rootVolPodId = pool.getPodId(); diff --git a/engine/storage/backup/src/org/apache/cloudstack/storage/backup/BackupService.java b/engine/storage/backup/src/org/apache/cloudstack/storage/backup/BackupService.java index e4cb0c7031e..67924d2ce73 100644 --- a/engine/storage/backup/src/org/apache/cloudstack/storage/backup/BackupService.java +++ b/engine/storage/backup/src/org/apache/cloudstack/storage/backup/BackupService.java @@ -18,7 +18,7 @@ */ package org.apache.cloudstack.storage.backup; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; public interface BackupService { public boolean backupSnapshot(SnapshotInfo snapshot, long backupStoreId); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java index b6a45b5f6bb..616e4789a27 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageDataFactoryImpl.java @@ -20,38 +20,74 @@ package org.apache.cloudstack.storage.image; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.storage.datastore.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.db.ImageDataDao; -import org.apache.cloudstack.storage.image.db.ImageDataVO; import org.apache.cloudstack.storage.image.store.TemplateObject; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplatePoolDao; + @Component public class ImageDataFactoryImpl implements ImageDataFactory { + private static final Logger s_logger = Logger + .getLogger(ImageDataFactoryImpl.class); @Inject - ImageDataDao imageDataDao; + VMTemplateDao imageDataDao; @Inject ObjectInDataStoreManager objMap; @Inject DataStoreManager storeMgr; + @Inject + VMTemplatePoolDao templatePoolDao; @Override public TemplateInfo getTemplate(long templateId, DataStore store) { - ImageDataVO templ = imageDataDao.findById(templateId); + VMTemplateVO templ = imageDataDao.findById(templateId); if (store == null) { TemplateObject tmpl = TemplateObject.getTemplate(templ, null); return tmpl; } - ObjectInDataStoreVO obj = objMap.findObject(templateId, DataObjectType.TEMPLATE, store.getId(), store.getRole()); - if (obj == null) { - TemplateObject tmpl = TemplateObject.getTemplate(templ, null); - return tmpl; + boolean found = false; + if (store.getRole() == DataStoreRole.Primary) { + VMTemplateStoragePoolVO templatePoolVO = templatePoolDao.findByPoolTemplate(store.getId(), templateId); + if (templatePoolVO != null) { + found = true; + } + } else { + DataObjectInStore obj = objMap.findObject(templ.getUuid(), DataObjectType.TEMPLATE, store.getUuid(), store.getRole()); + if (obj != null) { + found = true; + } + } + + if (!found) { + s_logger.debug("template " + templateId + " is not in store:" + store.getId() + ", type:" + store.getRole()); } TemplateObject tmpl = TemplateObject.getTemplate(templ, store); return tmpl; } + @Override + public TemplateInfo getTemplate(long templateId) { + VMTemplateVO templ = imageDataDao.findById(templateId); + if (templ.getImageDataStoreId() == null) { + return this.getTemplate(templateId, null); + } + DataStore store = this.storeMgr.getDataStore(templ.getImageDataStoreId(), DataStoreRole.Image); + return this.getTemplate(templateId, store); + } + @Override + public TemplateInfo getTemplate(DataObject obj, DataStore store) { + return this.getTemplate(obj.getId(), store); + } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java index 82d0d71db9c..5898b1b0794 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/ImageServiceImpl.java @@ -22,15 +22,21 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.storage.datastore.DataObjectManager; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; import org.apache.cloudstack.storage.image.store.TemplateObject; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -41,21 +47,25 @@ public class ImageServiceImpl implements ImageService { private static final Logger s_logger = Logger.getLogger(ImageServiceImpl.class); @Inject ObjectInDataStoreManager objectInDataStoreMgr; + @Inject + DataObjectManager dataObjectMgr; class CreateTemplateContext extends AsyncRpcConext { final TemplateInfo srcTemplate; - final TemplateInfo templateOnStore; + final DataStore store; final AsyncCallFuture future; - final ObjectInDataStoreVO obj; + final DataObject templateOnStore; + public CreateTemplateContext(AsyncCompletionCallback callback, TemplateInfo srcTemplate, - TemplateInfo templateOnStore, AsyncCallFuture future, - ObjectInDataStoreVO obj) { + DataStore store, + DataObject templateOnStore + ) { super(callback); this.srcTemplate = srcTemplate; - this.templateOnStore = templateOnStore; this.future = future; - this.obj = obj; + this.store = store; + this.templateOnStore = templateOnStore; } } @@ -74,31 +84,15 @@ public class ImageServiceImpl implements ImageService { return future; } - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject(template.getId(), template.getType(), store.getId(), store.getRole()); - TemplateInfo templateOnStore = null; - if (obj == null) { - templateOnStore = (TemplateInfo)objectInDataStoreMgr.create(template, store); - obj = objectInDataStoreMgr.findObject(template.getId(), template.getType(), store.getId(), store.getRole()); - } else { - CommandResult result = new CommandResult(); - result.setResult("duplicate template on the storage"); - future.complete(result); - return future; - } + DataObject templateOnStore = store.create(template); + templateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.CreateOnlyRequested); - try { - objectInDataStoreMgr.update(obj, Event.CreateOnlyRequested); - } catch (NoTransitionException e) { - s_logger.debug("failed to transit", e); - CommandResult result = new CommandResult(); - result.setResult(e.toString()); - future.complete(result); - return future; - } CreateTemplateContext context = new CreateTemplateContext(null, - template, templateOnStore, + template, future, - obj); + store, + templateOnStore + ); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().createTemplateCallback(null, null)) .setContext(context); @@ -108,42 +102,25 @@ public class ImageServiceImpl implements ImageService { protected Void createTemplateCallback(AsyncCallbackDispatcher callback, CreateTemplateContext context) { - - TemplateInfo templateOnStore = context.templateOnStore; TemplateObject template = (TemplateObject)context.srcTemplate; AsyncCallFuture future = context.future; CommandResult result = new CommandResult(); - + DataObject templateOnStore = context.templateOnStore; CreateCmdResult callbackResult = callback.getResult(); if (callbackResult.isFailed()) { try { - objectInDataStoreMgr.update(templateOnStore, Event.OperationFailed); + templateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.OperationFailed); + template.stateTransit(TemplateEvent.OperationFailed); } catch (NoTransitionException e) { - s_logger.debug("failed to transit state", e); + s_logger.debug("Failed to update template state", e); } result.setResult(callbackResult.getResult()); future.complete(result); return null; } - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject(templateOnStore.getId(), templateOnStore.getType(), templateOnStore.getDataStore().getId(), templateOnStore.getDataStore().getRole()); - obj.setInstallPath(callbackResult.getPath()); - - if (callbackResult.getSize() != null) { - obj.setSize(callbackResult.getSize()); - } try { - objectInDataStoreMgr.update(obj, Event.OperationSuccessed); - } catch (NoTransitionException e) { - s_logger.debug("Failed to transit state", e); - result.setResult(e.toString()); - future.complete(result); - return null; - } - - template.setImageStoreId(templateOnStore.getDataStore().getId()); - template.setSize(callbackResult.getSize()); - try { + templateOnStore.processEvent(ObjectInDataStoreStateMachine.Event.OperationSuccessed); template.stateTransit(TemplateEvent.OperationSucceeded); } catch (NoTransitionException e) { s_logger.debug("Failed to transit state", e); @@ -162,4 +139,18 @@ public class ImageServiceImpl implements ImageService { // TODO Auto-generated method stub return null; } + + @Override + public AsyncCallFuture createTemplateFromSnapshotAsync( + SnapshotInfo snapshot, TemplateInfo template, DataStore store) { + // TODO Auto-generated method stub + return null; + } + + @Override + public AsyncCallFuture createTemplateFromVolumeAsync( + VolumeInfo volume, TemplateInfo template, DataStore store) { + // TODO Auto-generated method stub + return null; + } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java index adb247afd0f..af572d49a5e 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/downloader/ImageDownloader.java @@ -18,7 +18,7 @@ */ package org.apache.cloudstack.storage.image.downloader; -import org.apache.cloudstack.storage.image.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; public interface ImageDownloader { public void downloadImage(TemplateInfo template); diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java new file mode 100644 index 00000000000..2c19c7fc039 --- /dev/null +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/AncientImageDataStoreDriverImpl.java @@ -0,0 +1,187 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.image.driver; + +import java.util.List; +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.framework.async.AsyncRpcConext; +import org.apache.cloudstack.storage.image.ImageDataStoreDriver; +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.storage.DeleteVolumeCommand; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.storage.RegisterVolumePayload; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplateZoneDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; +import com.cloud.storage.download.DownloadMonitor; +import com.cloud.utils.exception.CloudRuntimeException; + +public class AncientImageDataStoreDriverImpl implements ImageDataStoreDriver { + private static final Logger s_logger = Logger + .getLogger(AncientImageDataStoreDriverImpl.class); + @Inject + VMTemplateZoneDao templateZoneDao; + @Inject + VMTemplateDao templateDao; + @Inject DownloadMonitor _downloadMonitor; + @Inject + VMTemplateHostDao _vmTemplateHostDao; + @Inject VolumeDao volumeDao; + @Inject VolumeHostDao volumeHostDao; + @Inject HostDao hostDao; + @Inject AgentManager agentMgr; + @Override + public String grantAccess(DataObject data, EndPoint ep) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean revokeAccess(DataObject data, EndPoint ep) { + // TODO Auto-generated method stub + return false; + } + + @Override + public Set listObjects(DataStore store) { + // TODO Auto-generated method stub + return null; + } + + class CreateContext extends AsyncRpcConext { + final DataObject data; + public CreateContext(AsyncCompletionCallback callback, DataObject data) { + super(callback); + this.data = data; + } + } + + @Override + public void createAsync(DataObject data, + AsyncCompletionCallback callback) { + if (data.getType() == DataObjectType.TEMPLATE) { + List templateZones = this.templateZoneDao.listByTemplateId(data.getId()); + for (VMTemplateZoneVO templateZone : templateZones) { + VMTemplateVO template = this.templateDao.findById(data.getId()); + _downloadMonitor.downloadTemplateToStorage(template, templateZone.getZoneId()); + } + } else if (data.getType() == DataObjectType.VOLUME) { + VolumeVO vol = this.volumeDao.findById(data.getId()); + VolumeInfo volInfo = (VolumeInfo)data; + RegisterVolumePayload payload = (RegisterVolumePayload)volInfo.getpayload(); + _downloadMonitor.downloadVolumeToStorage(vol, vol.getDataCenterId(), payload.getUrl(), + payload.getChecksum(), ImageFormat.valueOf(payload.getFormat().toUpperCase())); + } + + CreateCmdResult result = new CreateCmdResult(null, null); + callback.complete(result); + } + + private void deleteVolume(DataObject data, AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + VolumeVO vol = volumeDao.findById(data.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Expunging " + vol); + } + + // Find out if the volume is present on secondary storage + VolumeHostVO volumeHost = volumeHostDao.findByVolumeId(vol.getId()); + if (volumeHost != null) { + if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { + HostVO ssHost = hostDao.findById(volumeHost.getHostId()); + DeleteVolumeCommand dtCommand = new DeleteVolumeCommand( + ssHost.getStorageUrl(), volumeHost.getInstallPath()); + Answer answer = agentMgr.sendToSecStorage(ssHost, dtCommand); + if (answer == null || !answer.getResult()) { + s_logger.debug("Failed to delete " + + volumeHost + + " due to " + + ((answer == null) ? "answer is null" : answer + .getDetails())); + return; + } + } else if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) { + s_logger.debug("Volume: " + vol.getName() + + " is currently being uploaded; cant' delete it."); + throw new CloudRuntimeException( + "Please specify a volume that is not currently being uploaded."); + } + volumeHostDao.remove(volumeHost.getId()); + volumeDao.remove(vol.getId()); + CommandResult result = new CommandResult(); + callback.complete(result); + return; + } + } + + private void deleteTemplate(DataObject data, AsyncCompletionCallback callback) { + + } + + @Override + public void deleteAsync(DataObject data, + AsyncCompletionCallback callback) { + if (data.getType() == DataObjectType.VOLUME) { + deleteVolume(data, callback); + } else if (data.getType() == DataObjectType.TEMPLATE) { + deleteTemplate(data, callback); + } + + + + } + + @Override + public void copyAsync(DataObject srcdata, DataObject destData, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + + @Override + public boolean canCopy(DataObject srcData, DataObject destData) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java index dce5a939413..1a506fa782b 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/driver/DefaultImageDataStoreDriverImpl.java @@ -34,15 +34,15 @@ import org.apache.cloudstack.storage.command.CreateObjectAnswer; import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.endpoint.EndPointSelector; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; -import org.apache.cloudstack.storage.image.db.ImageDataDao; -import org.apache.cloudstack.storage.image.db.ImageDataVO; + +import com.cloud.storage.dao.VMTemplateDao; //http-read-only based image store public class DefaultImageDataStoreDriverImpl implements ImageDataStoreDriver { @Inject EndPointSelector selector; @Inject - ImageDataDao imageDataDao; + VMTemplateDao imageDataDao; public DefaultImageDataStoreDriverImpl() { } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManager.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManager.java index e5a6863a58b..e1fd46b76df 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManager.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManager.java @@ -18,13 +18,13 @@ */ package org.apache.cloudstack.storage.image.manager; -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateState; -import org.apache.cloudstack.storage.image.db.ImageDataVO; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; +import com.cloud.storage.VMTemplateVO; import com.cloud.utils.fsm.StateMachine2; public interface ImageDataManager { - StateMachine2 getStateMachine(); + StateMachine2 getStateMachine(); } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java index d90f2b64e24..83e98878158 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataManagerImpl.java @@ -18,17 +18,17 @@ */ package org.apache.cloudstack.storage.image.manager; -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateState; -import org.apache.cloudstack.storage.image.db.ImageDataVO; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; import org.springframework.stereotype.Component; +import com.cloud.storage.VMTemplateVO; import com.cloud.utils.fsm.StateMachine2; @Component public class ImageDataManagerImpl implements ImageDataManager { - private final StateMachine2 - stateMachine = new StateMachine2(); + private final StateMachine2 + stateMachine = new StateMachine2(); public ImageDataManagerImpl() { stateMachine.addTransition(TemplateState.Allocated, TemplateEvent.CreateRequested, TemplateState.Creating); @@ -44,7 +44,7 @@ public class ImageDataManagerImpl implements ImageDataManager { } @Override - public StateMachine2 getStateMachine() { + public StateMachine2 getStateMachine() { return stateMachine; } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataStoreManagerImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataStoreManagerImpl.java index 68a2770c549..2771f78e381 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataStoreManagerImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/manager/ImageDataStoreManagerImpl.java @@ -18,38 +18,48 @@ */ package org.apache.cloudstack.storage.image.manager; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import javax.annotation.PostConstruct; import javax.inject.Inject; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; import org.apache.cloudstack.storage.datastore.provider.ImageDataStoreProvider; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; import org.apache.cloudstack.storage.image.datastore.ImageDataStore; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; -import org.apache.cloudstack.storage.image.db.ImageDataDao; import org.apache.cloudstack.storage.image.db.ImageDataStoreDao; import org.apache.cloudstack.storage.image.db.ImageDataStoreVO; -import org.apache.cloudstack.storage.image.store.HttpDataStoreImpl; +import org.apache.cloudstack.storage.image.store.DefaultImageDataStoreImpl; import org.springframework.stereotype.Component; +import com.cloud.storage.dao.VMTemplateDao; + @Component public class ImageDataStoreManagerImpl implements ImageDataStoreManager { @Inject ImageDataStoreDao dataStoreDao; @Inject - ImageDataDao imageDataDao; + VMTemplateDao imageDataDao; @Inject DataStoreProviderManager providerManager; - Map driverMaps = new HashMap(); + Map driverMaps; + @PostConstruct + public void config() { + driverMaps = new HashMap(); + } + @Override public ImageDataStore getImageDataStore(long dataStoreId) { ImageDataStoreVO dataStore = dataStoreDao.findById(dataStoreId); long providerId = dataStore.getProvider(); ImageDataStoreProvider provider = (ImageDataStoreProvider)providerManager.getDataStoreProviderById(providerId); - ImageDataStore imgStore = HttpDataStoreImpl.getDataStore(dataStore, + ImageDataStore imgStore = DefaultImageDataStoreImpl.getDataStore(dataStore, driverMaps.get(provider.getUuid()), provider ); // TODO Auto-generated method stub @@ -65,4 +75,20 @@ public class ImageDataStoreManagerImpl implements ImageDataStoreManager { return true; } + @Override + public ImageDataStore getImageDataStore(String uuid) { + ImageDataStoreVO dataStore = dataStoreDao.findByUuid(uuid); + return getImageDataStore(dataStore.getId()); + } + + @Override + public List getList() { + List stores = dataStoreDao.listAll(); + List imageStores = new ArrayList(); + for (ImageDataStoreVO store : stores) { + imageStores.add(getImageDataStore(store.getId())); + } + return imageStores; + } + } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/AncientImageDataStoreProvider.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/AncientImageDataStoreProvider.java new file mode 100644 index 00000000000..b2ee9ab853d --- /dev/null +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/AncientImageDataStoreProvider.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.image.store; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.storage.datastore.provider.ImageDataStoreProvider; +import org.apache.cloudstack.storage.image.ImageDataStoreDriver; +import org.apache.cloudstack.storage.image.datastore.ImageDataStoreHelper; +import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; +import org.apache.cloudstack.storage.image.driver.AncientImageDataStoreDriverImpl; +import org.apache.cloudstack.storage.image.store.lifecycle.DefaultImageDataStoreLifeCycle; +import org.apache.cloudstack.storage.image.store.lifecycle.ImageDataStoreLifeCycle; +import org.springframework.stereotype.Component; + +import com.cloud.utils.component.ComponentContext; + +@Component +public class AncientImageDataStoreProvider implements ImageDataStoreProvider { + + private final String name = "ancient image data store"; + protected ImageDataStoreLifeCycle lifeCycle; + protected ImageDataStoreDriver driver; + @Inject + ImageDataStoreManager storeMgr; + @Inject + ImageDataStoreHelper helper; + long id; + String uuid; + @Override + public DataStoreLifeCycle getLifeCycle() { + return lifeCycle; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getUuid() { + return this.uuid; + } + + @Override + public long getId() { + return this.id; + } + + @Override + public boolean configure(Map params) { + lifeCycle = ComponentContext.inject(DefaultImageDataStoreLifeCycle.class); + driver = ComponentContext.inject(AncientImageDataStoreDriverImpl.class); + uuid = (String)params.get("uuid"); + id = (Long)params.get("id"); + storeMgr.registerDriver(uuid, driver); + + Map infos = new HashMap(); + String dataStoreName = UUID.nameUUIDFromBytes(this.name.getBytes()).toString(); + infos.put("name", dataStoreName); + infos.put("uuid", dataStoreName); + infos.put("protocol", "http"); + infos.put("scope", ScopeType.GLOBAL); + infos.put("provider", this.getId()); + DataStoreLifeCycle lifeCycle = this.getLifeCycle(); + lifeCycle.initialize(infos); + return true; + } + +} diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreImpl.java similarity index 79% rename from engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java rename to engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreImpl.java index 34b4ff27f1a..d159f741584 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/HttpDataStoreImpl.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreImpl.java @@ -26,24 +26,24 @@ import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.provider.ImageDataStoreProvider; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.image.datastore.ImageDataStore; -import org.apache.cloudstack.storage.image.db.ImageDataDao; import org.apache.cloudstack.storage.image.db.ImageDataStoreVO; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; +import com.cloud.storage.dao.VMTemplateDao; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.storage.encoding.EncodingType; -public class HttpDataStoreImpl implements ImageDataStore { +public class DefaultImageDataStoreImpl implements ImageDataStore { @Inject - ImageDataDao imageDao; + VMTemplateDao imageDao; @Inject private ObjectInDataStoreManager objectInStoreMgr; protected ImageDataStoreDriver driver; @@ -51,7 +51,7 @@ public class HttpDataStoreImpl implements ImageDataStore { protected ImageDataStoreProvider provider; boolean needDownloadToCacheStorage = false; - protected HttpDataStoreImpl() { + protected DefaultImageDataStoreImpl() { } @@ -62,9 +62,9 @@ public class HttpDataStoreImpl implements ImageDataStore { this.provider = provider; } - public static HttpDataStoreImpl getDataStore(ImageDataStoreVO dataStoreVO, ImageDataStoreDriver imageDataStoreDriver, + public static ImageDataStore getDataStore(ImageDataStoreVO dataStoreVO, ImageDataStoreDriver imageDataStoreDriver, ImageDataStoreProvider provider) { - HttpDataStoreImpl instance = (HttpDataStoreImpl)ComponentContext.inject(HttpDataStoreImpl.class); + DefaultImageDataStoreImpl instance = (DefaultImageDataStoreImpl)ComponentContext.inject(DefaultImageDataStoreImpl.class); instance.configure(dataStoreVO, imageDataStoreDriver, provider); return instance; } @@ -81,24 +81,17 @@ public class HttpDataStoreImpl implements ImageDataStore { return this.driver; } - - @Override public DataStoreRole getRole() { // TODO Auto-generated method stub return DataStoreRole.Image; } - - - @Override public long getId() { // TODO Auto-generated method stub return this.imageDataStoreVO.getId(); } - - @Override public String getUri() { return this.imageDataStoreVO.getProtocol() + "://" + "?" + EncodingType.ROLE + "=" + this.getRole(); @@ -106,39 +99,47 @@ public class HttpDataStoreImpl implements ImageDataStore { @Override public Scope getScope() { - // TODO Auto-generated method stub return new ZoneScope(imageDataStoreVO.getDcId()); } - - @Override public TemplateInfo getTemplate(long templateId) { // TODO Auto-generated method stub return null; } - - @Override public VolumeInfo getVolume(long volumeId) { // TODO Auto-generated method stub return null; } - - @Override public SnapshotInfo getSnapshot(long snapshotId) { // TODO Auto-generated method stub return null; } - - @Override public boolean exists(DataObject object) { - return (objectInStoreMgr.findObject(object.getId(), object.getType(), - this.getId(), this.getRole()) != null) ? true : false; + return (objectInStoreMgr.findObject(object, + this) != null) ? true : false; + } + + @Override + public String getUuid() { + return this.imageDataStoreVO.getUuid(); + } + + @Override + public DataObject create(DataObject obj) { + DataObject object = objectInStoreMgr.create(obj, this); + return object; + } + + @Override + public boolean delete(DataObject obj) { + // TODO Auto-generated method stub + return false; } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreProvider.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreProvider.java index 3569fe803d5..efbb999bdcf 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreProvider.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/DefaultImageDataStoreProvider.java @@ -29,11 +29,9 @@ import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; import org.apache.cloudstack.storage.image.driver.DefaultImageDataStoreDriverImpl; import org.apache.cloudstack.storage.image.store.lifecycle.DefaultImageDataStoreLifeCycle; import org.apache.cloudstack.storage.image.store.lifecycle.ImageDataStoreLifeCycle; -import org.springframework.stereotype.Component; import com.cloud.utils.component.ComponentContext; -@Component public class DefaultImageDataStoreProvider implements ImageDataStoreProvider { private final String name = "default image data store"; protected ImageDataStoreLifeCycle lifeCycle; diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java index 1b0661c7691..85bc0c118a0 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java @@ -20,44 +20,48 @@ package org.apache.cloudstack.storage.image.store; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.image.db.ImageDataDao; -import org.apache.cloudstack.storage.image.db.ImageDataVO; import org.apache.cloudstack.storage.image.manager.ImageDataManager; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; import org.apache.log4j.Logger; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplatePoolDao; import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.storage.encoding.EncodingType; public class TemplateObject implements TemplateInfo { private static final Logger s_logger = Logger .getLogger(TemplateObject.class); - private ImageDataVO imageVO; + private VMTemplateVO imageVO; private DataStore dataStore; @Inject ImageDataManager imageMgr; @Inject - ImageDataDao imageDao; + VMTemplateDao imageDao; @Inject ObjectInDataStoreManager ojbectInStoreMgr; + @Inject VMTemplatePoolDao templatePoolDao; protected TemplateObject() { } - protected void configure(ImageDataVO template, DataStore dataStore) { + protected void configure(VMTemplateVO template, DataStore dataStore) { this.imageVO = template; this.dataStore = dataStore; } - public static TemplateObject getTemplate(ImageDataVO vo, DataStore store) { + public static TemplateObject getTemplate(VMTemplateVO vo, DataStore store) { TemplateObject to = ComponentContext.inject(TemplateObject.class); to.configure(vo, store); return to; @@ -66,12 +70,12 @@ public class TemplateObject implements TemplateInfo { public void setImageStoreId(long id) { this.imageVO.setImageDataStoreId(id); } - + public void setSize(Long size) { this.imageVO.setSize(size); } - public ImageDataVO getImage() { + public VMTemplateVO getImage() { return this.imageVO; } @@ -87,23 +91,20 @@ public class TemplateObject implements TemplateInfo { @Override public String getUuid() { - // TODO Auto-generated method stub - return null; + return this.imageVO.getUuid(); } @Override public String getUri() { - ImageDataVO image = imageDao.findById(this.imageVO.getId()); + VMTemplateVO image = imageDao.findById(this.imageVO.getId()); if (this.dataStore == null) { return image.getUrl(); } else { - ObjectInDataStoreVO obj = ojbectInStoreMgr.findObject( - this.imageVO.getId(), DataObjectType.TEMPLATE, - this.dataStore.getId(), this.dataStore.getRole()); + DataObjectInStore obj = ojbectInStoreMgr.findObject(this, this.dataStore); StringBuilder builder = new StringBuilder(); if (obj.getState() == ObjectInDataStoreStateMachine.State.Ready || obj.getState() == ObjectInDataStoreStateMachine.State.Copying) { - + builder.append(this.dataStore.getUri()); builder.append("&" + EncodingType.OBJTYPE + "=" + DataObjectType.TEMPLATE); builder.append("&" + EncodingType.PATH + "=" + obj.getInstallPath()); @@ -124,10 +125,33 @@ public class TemplateObject implements TemplateInfo { if (this.dataStore == null) { return this.imageVO.getSize(); } - ObjectInDataStoreVO obj = ojbectInStoreMgr.findObject( - this.imageVO.getId(), DataObjectType.TEMPLATE, - this.dataStore.getId(), this.dataStore.getRole()); - return obj.getSize(); + + /* + +// If the template that was passed into this allocator is not installed in the storage pool, + // add 3 * (template size on secondary storage) to the running total + VMTemplateHostVO templateHostVO = _storageMgr.findVmTemplateHost(templateForVmCreation.getId(), null); + + if (templateHostVO == null) { + VMTemplateSwiftVO templateSwiftVO = _swiftMgr.findByTmpltId(templateForVmCreation.getId()); + if (templateSwiftVO != null) { + long templateSize = templateSwiftVO.getPhysicalSize(); + if (templateSize == 0) { + templateSize = templateSwiftVO.getSize(); + } + totalAllocatedSize += (templateSize + _extraBytesPerVolume); + } + } else { + long templateSize = templateHostVO.getPhysicalSize(); + if ( templateSize == 0 ){ + templateSize = templateHostVO.getSize(); + } + totalAllocatedSize += (templateSize + _extraBytesPerVolume); + } + + */ + VMTemplateVO image = imageDao.findById(this.imageVO.getId()); + return image.getSize(); } @Override @@ -137,7 +161,7 @@ public class TemplateObject implements TemplateInfo { @Override public DiskFormat getFormat() { - return DiskFormat.getFormat(this.imageVO.getFormat()); + return DiskFormat.valueOf(this.imageVO.getFormat().toString()); } public boolean stateTransit(TemplateEvent e) throws NoTransitionException { @@ -146,4 +170,14 @@ public class TemplateObject implements TemplateInfo { this.imageVO = imageDao.findById(this.imageVO.getId()); return result; } + + @Override + public void processEvent(Event event) { + try { + ojbectInStoreMgr.update(this, event); + } catch (NoTransitionException e) { + s_logger.debug("failed to update state", e); + throw new CloudRuntimeException("Failed to update state" + e.toString()); + } + } } diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java index 07d52b40682..17aabca3921 100644 --- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java +++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/lifecycle/DefaultImageDataStoreLifeCycle.java @@ -22,12 +22,15 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreHelper; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; import org.apache.cloudstack.storage.image.db.ImageDataStoreDao; import org.apache.cloudstack.storage.image.db.ImageDataStoreVO; +import com.cloud.agent.api.StoragePoolInfo; + public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle { @Inject protected ImageDataStoreDao imageStoreDao; @@ -40,7 +43,7 @@ public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle { @Override - public DataStore initialize(Map dsInfos) { + public DataStore initialize(Map dsInfos) { ImageDataStoreVO ids = imageStoreHelper.createImageDataStore(dsInfos); return imageStoreMgr.getImageDataStore(ids.getId()); } @@ -53,6 +56,14 @@ public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle { } + @Override + public boolean attachHost(DataStore store, HostScope scope, + StoragePoolInfo existingInfo) { + // TODO Auto-generated method stub + return false; + } + + @Override public boolean attachZone(DataStore dataStore, ZoneScope scope) { // TODO Auto-generated method stub @@ -75,23 +86,27 @@ public class DefaultImageDataStoreLifeCycle implements ImageDataStoreLifeCycle { @Override - public boolean maintain() { + public boolean maintain(long storeId) { // TODO Auto-generated method stub return false; } @Override - public boolean cancelMaintain() { + public boolean cancelMaintain(long storeId) { // TODO Auto-generated method stub return false; } @Override - public boolean deleteDataStore() { + public boolean deleteDataStore(long storeId) { // TODO Auto-generated method stub return false; } + + + + } diff --git a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java index 390b0fd7e34..561c1cb288f 100644 --- a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java +++ b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/DefaultImageMotionStrategy.java @@ -23,7 +23,6 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; @@ -32,12 +31,11 @@ import org.apache.cloudstack.storage.command.CopyCmd; import org.apache.cloudstack.storage.command.CopyCmdAnswer; import org.apache.cloudstack.storage.endpoint.EndPointSelector; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; -import org.springframework.stereotype.Component; import com.cloud.agent.api.Answer; //At least one of datastore is coming from image store or image cache store -@Component + public class DefaultImageMotionStrategy implements ImageMotionStrategy { @Inject EndPointSelector selector; @@ -86,14 +84,15 @@ public class DefaultImageMotionStrategy implements ImageMotionStrategy { @Override public boolean canHandle(DataObject srcData, DataObject destData) { + /* DataStore destStore = destData.getDataStore(); DataStore srcStore = srcData.getDataStore(); if (destStore.getRole() == DataStoreRole.Image || destStore.getRole() == DataStoreRole.ImageCache || srcStore.getRole() == DataStoreRole.Image || srcStore.getRole() == DataStoreRole.ImageCache) { return true; - } - return true; + }*/ + return false; } @Override diff --git a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java index 0e3636e3886..93ba4a5ad64 100644 --- a/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java +++ b/engine/storage/imagemotion/src/org/apache/cloudstack/storage/image/motion/ImageMotionServiceImpl.java @@ -23,18 +23,12 @@ import java.util.List; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.ImageService; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; -import org.apache.cloudstack.storage.volume.VolumeService; -import org.springframework.stereotype.Component; -import com.cloud.utils.exception.CloudRuntimeException; -@Component public class ImageMotionServiceImpl implements ImageMotionService { @Inject List motionStrategies; diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java index 9c30a2e8269..2ad52159afc 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/ChildTestConfiguration.java @@ -16,14 +16,25 @@ // under the License. package org.apache.cloudstack.storage.test; +import java.io.IOException; + import org.apache.cloudstack.acl.APIChecker; import org.apache.cloudstack.engine.service.api.OrchestrationService; import org.apache.cloudstack.storage.HostEndpointRpcServer; import org.apache.cloudstack.storage.endpoint.EndPointSelector; +import org.apache.cloudstack.storage.test.ChildTestConfiguration.Library; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.filter.TypeFilter; import com.cloud.agent.AgentManager; +import com.cloud.alert.AlertManager; import com.cloud.cluster.ClusteredAgentRebalanceService; import com.cloud.cluster.agentlb.dao.HostTransferMapDao; import com.cloud.cluster.agentlb.dao.HostTransferMapDaoImpl; @@ -50,11 +61,35 @@ import com.cloud.host.dao.HostTagsDaoImpl; import com.cloud.server.auth.UserAuthenticator; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.StoragePoolHostDaoImpl; +import com.cloud.storage.dao.VMTemplateDaoImpl; import com.cloud.storage.dao.VMTemplateDetailsDao; import com.cloud.storage.dao.VMTemplateDetailsDaoImpl; +import com.cloud.storage.dao.VMTemplateHostDaoImpl; +import com.cloud.storage.dao.VMTemplatePoolDaoImpl; import com.cloud.storage.dao.VMTemplateZoneDao; import com.cloud.storage.dao.VMTemplateZoneDaoImpl; - +import com.cloud.storage.dao.VolumeDaoImpl; +import com.cloud.storage.dao.VolumeHostDaoImpl; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.tags.dao.ResourceTagsDaoImpl; +import com.cloud.utils.component.SpringComponentScanUtils; +import com.cloud.vm.dao.NicDaoImpl; +import com.cloud.vm.dao.VMInstanceDaoImpl; +@Configuration +@ComponentScan(basePackageClasses={ + NicDaoImpl.class, + VMInstanceDaoImpl.class, + VMTemplateHostDaoImpl.class, + VolumeHostDaoImpl.class, + VolumeDaoImpl.class, + VMTemplatePoolDaoImpl.class, + ResourceTagsDaoImpl.class, + VMTemplateDaoImpl.class, + MockStorageMotionStrategy.class +}, +includeFilters={@Filter(value=Library.class, type=FilterType.CUSTOM)}, +useDefaultFilters=false +) public class ChildTestConfiguration extends TestConfiguration { @Override @@ -148,6 +183,27 @@ public class ChildTestConfiguration extends TestConfiguration { public APIChecker apiChecker() { return Mockito.mock(APIChecker.class); } + + @Bean + public SnapshotManager snapshotMgr() { + return Mockito.mock(SnapshotManager.class); + } + + @Bean + public AlertManager alertMgr() { + return Mockito.mock(AlertManager.class); + } + + public static class Library implements TypeFilter { + + @Override + public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { + mdr.getClassMetadata().getClassName(); + ComponentScan cs = ChildTestConfiguration.class.getAnnotation(ComponentScan.class); + return SpringComponentScanUtils.includedInBasePackageClasses(mdr.getClassMetadata().getClassName(), cs); + } + + } /* @Override @Bean public PrimaryDataStoreDao primaryDataStoreDao() { diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java new file mode 100644 index 00000000000..e2e8f9439c5 --- /dev/null +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/MockStorageMotionStrategy.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.test; + +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.motion.DataMotionStrategy; + +public class MockStorageMotionStrategy implements DataMotionStrategy { + + @Override + public boolean canHandle(DataObject srcData, DataObject destData) { + // TODO Auto-generated method stub + return true; + } + + @Override + public Void copyAsync(DataObject srcData, DataObject destData, + AsyncCompletionCallback callback) { + CopyCommandResult result = new CopyCommandResult("something"); + callback.complete(result); + return null; + } + +} diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java index 0e88f733e08..85421a53b56 100644 --- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java +++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/volumeServiceTest.java @@ -28,33 +28,30 @@ import java.util.UUID; import java.util.concurrent.ExecutionException; import javax.inject.Inject; -import javax.naming.ConfigurationException; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.type.RootDisk; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.storage.HypervisorHostEndPoint; -import org.apache.cloudstack.storage.datastore.VolumeDataFactory; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProvider; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProviderManager; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.endpoint.EndPointSelector; -import org.apache.cloudstack.storage.image.ImageDataFactory; -import org.apache.cloudstack.storage.image.ImageService; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.image.db.ImageDataDao; -import org.apache.cloudstack.storage.image.db.ImageDataVO; -import org.apache.cloudstack.storage.volume.VolumeService; -import org.apache.cloudstack.storage.volume.VolumeService.VolumeApiResult; import org.apache.cloudstack.storage.volume.db.VolumeDao2; import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.mockito.Mockito; @@ -78,7 +75,11 @@ import com.cloud.org.Cluster.ClusterType; import com.cloud.org.Managed.ManagedState; import com.cloud.resource.ResourceState; import com.cloud.storage.Storage; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.TemplateType; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.utils.component.ComponentContext; @ContextConfiguration(locations={"classpath:/storageContext.xml"}) public class volumeServiceTest extends CloudStackTestNGBase { @@ -89,7 +90,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { @Inject VolumeService volumeService; @Inject - ImageDataDao imageDataDao; + VMTemplateDao imageDataDao; @Inject VolumeDao2 volumeDao; @Inject @@ -121,12 +122,13 @@ public class volumeServiceTest extends CloudStackTestNGBase { @Test(priority = -1) public void setUp() { - try { + ComponentContext.initComponentsLifeCycle(); + /* try { dataStoreProviderMgr.configure(null, new HashMap()); } catch (ConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); - } + }*/ host = hostDao.findByGuid(this.getHostGuid()); if (host != null) { dcId = host.getDataCenterId(); @@ -205,18 +207,17 @@ public class volumeServiceTest extends CloudStackTestNGBase { Mockito.when(selector.select(Mockito.any(DataObject.class), Mockito.any(DataObject.class))).thenReturn(eps.get(0)); } - private ImageDataVO createImageData() { - ImageDataVO image = new ImageDataVO(); + private VMTemplateVO createImageData() { + VMTemplateVO image = new VMTemplateVO(); image.setTemplateType(TemplateType.USER); image.setUrl(this.getTemplateUrl()); image.setUniqueName(UUID.randomUUID().toString()); image.setName(UUID.randomUUID().toString()); image.setPublicTemplate(true); image.setFeatured(true); - image.setRequireHvm(true); + image.setRequiresHvm(true); image.setBits(64); - image.setFormat(Storage.ImageFormat.VHD.toString()); - image.setAccountId(1); + image.setFormat(Storage.ImageFormat.VHD); image.setEnablePassword(true); image.setEnableSshKey(true); image.setGuestOSId(1); @@ -234,13 +235,13 @@ public class volumeServiceTest extends CloudStackTestNGBase { private TemplateInfo createTemplate() { try { DataStore store = createImageStore(); - ImageDataVO image = createImageData(); + VMTemplateVO image = createImageData(); TemplateInfo template = imageDataFactory.getTemplate(image.getId(), store); AsyncCallFuture future = imageService.createTemplateAsync(template, store); future.get(); template = imageDataFactory.getTemplate(image.getId(), store); /*imageProviderMgr.configure("image Provider", new HashMap()); - ImageDataVO image = createImageData(); + VMTemplateVO image = createImageData(); ImageDataStoreProvider defaultProvider = imageProviderMgr.getProvider("DefaultProvider"); ImageDataStoreLifeCycle lifeCycle = defaultProvider.getLifeCycle(); ImageDataStore store = lifeCycle.registerDataStore("defaultHttpStore", new HashMap()); @@ -262,7 +263,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { @Test public void testCreatePrimaryStorage() { DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("default primary data store provider"); - Map params = new HashMap(); + Map params = new HashMap(); URI uri = null; try { uri = new URI(this.getPrimaryStorageUrl()); @@ -273,7 +274,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { params.put("url", this.getPrimaryStorageUrl()); params.put("server", uri.getHost()); params.put("path", uri.getPath()); - params.put("protocol", uri.getScheme()); + params.put("protocol", StoragePoolType.NetworkFilesystem); params.put("dcId", dcId.toString()); params.put("clusterId", clusterId.toString()); params.put("name", this.primaryName); @@ -290,7 +291,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { private DataStore createImageStore() { DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("default image data store"); - Map params = new HashMap(); + Map params = new HashMap(); String name = UUID.randomUUID().toString(); params.put("name", name); params.put("uuid", name); @@ -310,12 +311,12 @@ public class volumeServiceTest extends CloudStackTestNGBase { public DataStore createPrimaryDataStore() { try { DataStoreProvider provider = dataStoreProviderMgr.getDataStoreProvider("default primary data store provider"); - Map params = new HashMap(); + Map params = new HashMap(); URI uri = new URI(this.getPrimaryStorageUrl()); params.put("url", this.getPrimaryStorageUrl()); params.put("server", uri.getHost()); params.put("path", uri.getPath()); - params.put("protocol", uri.getScheme()); + params.put("protocol", Storage.StoragePoolType.NetworkFilesystem); params.put("dcId", dcId.toString()); params.put("clusterId", clusterId.toString()); params.put("name", this.primaryName); @@ -390,7 +391,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { DataStore primaryStore = this.primaryStore; VolumeVO volume = createVolume(null, primaryStore.getId()); VolumeInfo vol = volumeFactory.getVolume(volume.getId(), primaryStore); - AsyncCallFuture future = volumeService.createVolumeAsync(vol, primaryStore.getId()); + AsyncCallFuture future = volumeService.createVolumeAsync(vol, primaryStore); try { future.get(); } catch (InterruptedException e) { @@ -407,7 +408,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { DataStore primaryStore = this.primaryStore; VolumeVO volume = createVolume(null, primaryStore.getId()); VolumeInfo vol = volumeFactory.getVolume(volume.getId(), primaryStore); - AsyncCallFuture future = volumeService.createVolumeAsync(vol, primaryStore.getId()); + AsyncCallFuture future = volumeService.createVolumeAsync(vol, primaryStore); try { future.get(); } catch (InterruptedException e) { @@ -420,7 +421,7 @@ public class volumeServiceTest extends CloudStackTestNGBase { //delete the volume vol = volumeFactory.getVolume(volume.getId(), primaryStore); - future = volumeService.deleteVolumeAsync(vol); + future = volumeService.expungeVolumeAsync(vol); try { future.get(); } catch (InterruptedException e) { @@ -434,9 +435,9 @@ public class volumeServiceTest extends CloudStackTestNGBase { //@Test(priority=3) public void tearDown() { - List ds = primaryStoreDao.findPoolByName(this.primaryName); + List ds = primaryStoreDao.findPoolByName(this.primaryName); for (int i = 0; i < ds.size(); i++) { - PrimaryDataStoreVO store = ds.get(i); + StoragePoolVO store = ds.get(i); store.setUuid(null); primaryStoreDao.remove(ds.get(i).getId()); primaryStoreDao.expunge(ds.get(i).getId()); diff --git a/engine/storage/integration-test/test/resource/component.xml b/engine/storage/integration-test/test/resource/component.xml new file mode 100644 index 00000000000..0368ad41425 --- /dev/null +++ b/engine/storage/integration-test/test/resource/component.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/engine/storage/integration-test/test/resource/storageContext.xml b/engine/storage/integration-test/test/resource/storageContext.xml index 0127c96a734..4f55e243bac 100644 --- a/engine/storage/integration-test/test/resource/storageContext.xml +++ b/engine/storage/integration-test/test/resource/storageContext.xml @@ -45,6 +45,7 @@ + diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java index 487e2d53eff..095320907c7 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotDataFactoryImpl.java @@ -20,11 +20,14 @@ package org.apache.cloudstack.storage.snapshot; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.storage.datastore.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; import org.apache.cloudstack.storage.snapshot.db.SnapshotDao2; import org.apache.cloudstack.storage.snapshot.db.SnapshotVO; import org.springframework.stereotype.Component; @@ -40,8 +43,21 @@ public class SnapshotDataFactoryImpl implements SnapshotDataFactory { @Override public SnapshotInfo getSnapshot(long snapshotId, DataStore store) { SnapshotVO snapshot = snapshotDao.findById(snapshotId); - ObjectInDataStoreVO obj = objMap.findObject(snapshotId, DataObjectType.SNAPSHOT, store.getId(), store.getRole()); + DataObjectInStore obj = objMap.findObject(snapshot.getUuid(), DataObjectType.SNAPSHOT, store.getUuid(), store.getRole()); + if (obj == null) { + return null; + } SnapshotObject so = new SnapshotObject(snapshot, store); return so; } + @Override + public SnapshotInfo getSnapshot(long snapshotId) { + // TODO Auto-generated method stub + return null; + } + @Override + public SnapshotInfo getSnapshot(DataObject obj, DataStore store) { + // TODO Auto-generated method stub + return null; + } } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java index 6ce17973375..d9fc8aabfe8 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java @@ -20,6 +20,8 @@ package org.apache.cloudstack.storage.snapshot; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import org.apache.cloudstack.storage.snapshot.db.SnapshotVO; @@ -97,4 +99,10 @@ public class SnapshotObject implements SnapshotInfo { return null; } + @Override + public void processEvent(Event event) { + // TODO Auto-generated method stub + + } + } diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java index 80b1918665d..bd3caf4c0bc 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.storage.snapshot; import org.apache.cloudstack.engine.cloud.entity.api.SnapshotEntity; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.springframework.stereotype.Component; @Component diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/HypervisorBasedSnapshot.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/HypervisorBasedSnapshot.java index 7f18200cd3d..8ef09275bcd 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/HypervisorBasedSnapshot.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/HypervisorBasedSnapshot.java @@ -16,7 +16,7 @@ // under the License. package org.apache.cloudstack.storage.snapshot.strategy; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.storage.snapshot.SnapshotStrategy; import org.springframework.stereotype.Component; diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/StorageBasedSnapshot.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/StorageBasedSnapshot.java index fa9c5aeaa08..7af395acb96 100644 --- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/StorageBasedSnapshot.java +++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/strategy/StorageBasedSnapshot.java @@ -16,7 +16,7 @@ // under the License. package org.apache.cloudstack.storage.snapshot.strategy; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.storage.snapshot.SnapshotStrategy; public class StorageBasedSnapshot implements SnapshotStrategy { diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java index 657d32c7877..218f9013a17 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataObjectManagerImpl.java @@ -24,14 +24,14 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcConext; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; import org.apache.cloudstack.storage.motion.DataMotionService; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -52,7 +52,7 @@ public class DataObjectManagerImpl implements DataObjectManager { protected DataObject waitingForCreated(DataObject dataObj, DataStore dataStore) { long retries = this.waitingRetries; - ObjectInDataStoreVO obj = null; + DataObjectInStore obj = null; do { try { Thread.sleep(waitingTime); @@ -61,8 +61,8 @@ public class DataObjectManagerImpl implements DataObjectManager { throw new CloudRuntimeException("sleep interrupted", e); } - obj = objectInDataStoreMgr.findObject(dataObj.getId(), - dataObj.getType(), dataStore.getId(), dataStore.getRole()); + obj = objectInDataStoreMgr.findObject(dataObj, + dataStore); if (obj == null) { s_logger.debug("can't find object in db, maybe it's cleaned up already, exit waiting"); break; @@ -92,11 +92,10 @@ public class DataObjectManagerImpl implements DataObjectManager { } @Override - public void createAsync(DataObject data, DataStore store, + public void createAsync(DataObject data, DataStore store, AsyncCompletionCallback callback, boolean noCopy) { - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - data.getId(), data.getType(), store.getId(), - store.getRole()); + DataObjectInStore obj = objectInDataStoreMgr.findObject( + data, store); DataObject objInStore = null; boolean freshNewTemplate = false; if (obj == null) { @@ -105,8 +104,8 @@ public class DataObjectManagerImpl implements DataObjectManager { data, store); freshNewTemplate = true; } catch (Throwable e) { - obj = objectInDataStoreMgr.findObject(data.getId(), - data.getType(), store.getId(), store.getRole()); + obj = objectInDataStoreMgr.findObject(data, + store); if (obj == null) { CreateCmdResult result = new CreateCmdResult( null, null); @@ -184,20 +183,12 @@ public class DataObjectManagerImpl implements DataObjectManager { return null; } - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - objInStrore.getId(), objInStrore - .getType(), objInStrore.getDataStore() - .getId(), objInStrore.getDataStore() - .getRole()); - - obj.setInstallPath(result.getPath()); - obj.setSize(result.getSize()); try { - objectInDataStoreMgr.update(obj, + objectInDataStoreMgr.update(objInStrore, ObjectInDataStoreStateMachine.Event.OperationSuccessed); } catch (NoTransitionException e) { try { - objectInDataStoreMgr.update(obj, + objectInDataStoreMgr.update(objInStrore, ObjectInDataStoreStateMachine.Event.OperationFailed); } catch (NoTransitionException e1) { s_logger.debug("failed to change state", e1); @@ -259,14 +250,10 @@ public class DataObjectManagerImpl implements DataObjectManager { CopyContext context) { CopyCommandResult result = callback.getResult(); DataObject destObj = context.destObj; - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - destObj.getId(), destObj - .getType(), destObj.getDataStore() - .getId(), destObj.getDataStore() - .getRole()); + if (result.isFailed()) { try { - objectInDataStoreMgr.update(obj, Event.OperationFailed); + objectInDataStoreMgr.update(destObj, Event.OperationFailed); } catch (NoTransitionException e) { s_logger.debug("Failed to update copying state", e); } @@ -276,10 +263,8 @@ public class DataObjectManagerImpl implements DataObjectManager { context.getParentCallback().complete(res); } - obj.setInstallPath(result.getPath()); - try { - objectInDataStoreMgr.update(obj, + objectInDataStoreMgr.update(destObj, ObjectInDataStoreStateMachine.Event.OperationSuccessed); } catch (NoTransitionException e) { s_logger.debug("Failed to update copying state: ", e); @@ -311,11 +296,8 @@ public class DataObjectManagerImpl implements DataObjectManager { @Override public void deleteAsync(DataObject data, AsyncCompletionCallback callback) { - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - data.getId(), data.getType(), data.getDataStore().getId(), - data.getDataStore().getRole()); try { - objectInDataStoreMgr.update(obj, Event.DestroyRequested); + objectInDataStoreMgr.update(data, Event.DestroyRequested); } catch (NoTransitionException e) { s_logger.debug("destroy failed", e); CreateCmdResult res = new CreateCmdResult( @@ -338,23 +320,18 @@ public class DataObjectManagerImpl implements DataObjectManager { protected Void deleteAsynCallback(AsyncCallbackDispatcher callback, DeleteContext context) { DataObject destObj = context.obj; - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - destObj.getId(), destObj - .getType(), destObj.getDataStore() - .getId(), destObj.getDataStore() - .getRole()); - + CommandResult res = callback.getResult(); if (res.isFailed()) { try { - objectInDataStoreMgr.update(obj, Event.OperationFailed); + objectInDataStoreMgr.update(destObj, Event.OperationFailed); } catch (NoTransitionException e) { s_logger.debug("delete failed", e); } } else { try { - objectInDataStoreMgr.update(obj, Event.OperationSuccessed); + objectInDataStoreMgr.update(destObj, Event.OperationSuccessed); } catch (NoTransitionException e) { s_logger.debug("delete failed", e); } @@ -366,9 +343,8 @@ public class DataObjectManagerImpl implements DataObjectManager { @Override public DataObject createInternalStateOnly(DataObject data, DataStore store) { - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - data.getId(), data.getType(), store.getId(), - store.getRole()); + DataObjectInStore obj = objectInDataStoreMgr.findObject( + data, store); DataObject objInStore = null; if (obj == null) { objInStore = objectInDataStoreMgr.create( @@ -391,12 +367,6 @@ public class DataObjectManagerImpl implements DataObjectManager { @Override public void update(DataObject data, String path, Long size) { - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - data.getId(), data.getType(), data.getDataStore().getId(), - data.getDataStore().getRole()); - - obj.setInstallPath(path); - obj.setSize(size); - objectInDataStoreMgr.update(obj); + throw new CloudRuntimeException("not implemented"); } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java index f857ac5db1a..a2fd08d1e8f 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/DataStoreManagerImpl.java @@ -18,12 +18,15 @@ */ package org.apache.cloudstack.storage.datastore; +import java.util.List; import java.util.Map; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreManager; import org.springframework.stereotype.Component; @@ -50,5 +53,22 @@ public class DataStoreManagerImpl implements DataStoreManager { String providerUuid) { return null; } + @Override + public DataStore getDataStore(String uuid, DataStoreRole role) { + if (role == DataStoreRole.Primary) { + return primaryStorMgr.getPrimaryDataStore(uuid); + } else if (role == DataStoreRole.Image) { + return imageDataStoreMgr.getImageDataStore(uuid); + } + throw new CloudRuntimeException("un recognized type" + role); + } + @Override + public List getImageStores(Scope scope) { + return imageDataStoreMgr.getList(); + } + @Override + public DataStore getPrimaryDataStore(long storeId) { + return primaryStorMgr.getPrimaryDataStore(storeId); + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java index e707de6b8bd..d170f5c707a 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java @@ -17,26 +17,20 @@ package org.apache.cloudstack.storage.datastore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; import com.cloud.utils.fsm.NoTransitionException; public interface ObjectInDataStoreManager { public DataObject create(DataObject template, DataStore dataStore); - public VolumeInfo create(VolumeInfo volume, DataStore dataStore); - public SnapshotInfo create(SnapshotInfo snapshot, DataStore dataStore); - public ObjectInDataStoreVO findObject(long objectId, DataObjectType type, - long dataStoreId, DataStoreRole role); public DataObject get(DataObject dataObj, DataStore store); public boolean update(DataObject vo, Event event) throws NoTransitionException; - boolean update(ObjectInDataStoreVO obj, Event event) - throws NoTransitionException; - - boolean update(ObjectInDataStoreVO obj); + DataObjectInStore findObject(String uuid, DataObjectType type, + String dataStoreUuid, DataStoreRole role); + DataObjectInStore findObject(DataObject obj, DataStore store); + DataStore findStore(String objUuid, DataObjectType type, DataStoreRole role); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java index 7eb4932348f..87ba1d216c5 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java @@ -19,19 +19,25 @@ package org.apache.cloudstack.storage.datastore; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.storage.db.ObjectInDataStoreDao; import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.ImageDataFactory; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.State; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VolumeHostDao; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.SearchCriteria2; import com.cloud.utils.db.SearchCriteriaService; @@ -41,16 +47,28 @@ import com.cloud.utils.fsm.StateMachine2; @Component public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager { + private static final Logger s_logger = Logger + .getLogger(ObjectInDataStoreManagerImpl.class); @Inject ImageDataFactory imageFactory; @Inject + DataStoreManager storeMgr; + @Inject VolumeDataFactory volumeFactory; @Inject ObjectInDataStoreDao objectDataStoreDao; - protected StateMachine2 stateMachines; + @Inject + VolumeHostDao volumeHostDao; + @Inject + VMTemplateHostDao templateHostDao; + @Inject + VMTemplatePoolDao templatePoolDao; + @Inject + SnapshotDataFactory snapshotFactory; + protected StateMachine2 stateMachines; public ObjectInDataStoreManagerImpl() { - stateMachines = new StateMachine2(); + stateMachines = new StateMachine2(); stateMachines.addTransition(State.Allocated, Event.CreateRequested, State.Creating); stateMachines.addTransition(State.Creating, Event.OperationSuccessed, @@ -76,101 +94,122 @@ public class ObjectInDataStoreManagerImpl implements ObjectInDataStoreManager { stateMachines.addTransition(State.Allocated, Event.CreateOnlyRequested, State.Creating2); stateMachines.addTransition(State.Creating2, Event.OperationFailed, - State.Failed); + State.Allocated); stateMachines.addTransition(State.Creating2, Event.OperationSuccessed, State.Ready); } @Override public DataObject create(DataObject obj, DataStore dataStore) { - - ObjectInDataStoreVO vo = new ObjectInDataStoreVO(); - vo.setDataStoreId(dataStore.getId()); - vo.setDataStoreRole(dataStore.getRole()); - vo.setObjectId(obj.getId()); - vo.setSize(obj.getSize()); - - vo.setObjectType(obj.getType()); - vo = objectDataStoreDao.persist(vo); + if (obj.getType() == DataObjectType.TEMPLATE && dataStore.getRole() == DataStoreRole.Primary) { + VMTemplateStoragePoolVO vo = new VMTemplateStoragePoolVO(dataStore.getId(), obj.getId()); + vo = templatePoolDao.persist(vo); + } else { + ObjectInDataStoreVO vo = new ObjectInDataStoreVO(); + vo.setDataStoreRole(dataStore.getRole()); + vo.setDataStoreUuid(dataStore.getUuid()); + vo.setObjectType(obj.getType()); + vo.setObjectUuid(obj.getUuid()); + vo = objectDataStoreDao.persist(vo); + } if (obj.getType() == DataObjectType.TEMPLATE) { - return imageFactory.getTemplate(obj.getId(), dataStore); + return imageFactory.getTemplate(obj, dataStore); } else if (obj.getType() == DataObjectType.VOLUME) { - return volumeFactory.getVolume(obj.getId(), dataStore); + return volumeFactory.getVolume(obj, dataStore); + } else if (obj.getType() == DataObjectType.SNAPSHOT) { + return snapshotFactory.getSnapshot(obj, dataStore); } throw new CloudRuntimeException("unknown type"); } - - @Override - public VolumeInfo create(VolumeInfo volume, DataStore dataStore) { - ObjectInDataStoreVO vo = new ObjectInDataStoreVO(); - vo.setDataStoreId(dataStore.getId()); - vo.setDataStoreRole(dataStore.getRole()); - vo.setObjectId(volume.getId()); - vo.setObjectType(volume.getType()); - vo = objectDataStoreDao.persist(vo); - - return volumeFactory.getVolume(volume.getId(), dataStore); - } - - @Override - public SnapshotInfo create(SnapshotInfo snapshot, DataStore dataStore) { - // TODO Auto-generated method stub - return null; - } - - @Override - public ObjectInDataStoreVO findObject(long objectId, DataObjectType type, - long dataStoreId, DataStoreRole role) { - SearchCriteriaService sc = SearchCriteria2 - .create(ObjectInDataStoreVO.class); - sc.addAnd(sc.getEntity().getObjectId(), Op.EQ, objectId); - sc.addAnd(sc.getEntity().getDataStoreId(), Op.EQ, dataStoreId); - sc.addAnd(sc.getEntity().getObjectType(), Op.EQ, type); - sc.addAnd(sc.getEntity().getDataStoreRole(), Op.EQ, role); - sc.addAnd(sc.getEntity().getState(), Op.NIN, - ObjectInDataStoreStateMachine.State.Destroyed, - ObjectInDataStoreStateMachine.State.Failed); - ObjectInDataStoreVO objectStoreVO = sc.find(); - return objectStoreVO; - - } - + @Override public boolean update(DataObject data, Event event) throws NoTransitionException { - ObjectInDataStoreVO obj = this.findObject(data.getId(), data.getType(), - data.getDataStore().getId(), data.getDataStore().getRole()); + DataObjectInStore obj = this.findObject(data, data.getDataStore()); if (obj == null) { throw new CloudRuntimeException( "can't find mapping in ObjectInDataStore table for: " + data); } - return this.stateMachines.transitTo(obj, event, null, - objectDataStoreDao); - - } - - @Override - public boolean update(ObjectInDataStoreVO obj, Event event) - throws NoTransitionException { - return this.stateMachines.transitTo(obj, event, null, - objectDataStoreDao); - + + if (data.getType() == DataObjectType.TEMPLATE && data.getDataStore().getRole() == DataStoreRole.Primary) { + try { + this.stateMachines.transitTo(obj, event, null, + templatePoolDao); + } catch (NoTransitionException e) { + if (event == Event.CreateOnlyRequested || event == Event.OperationSuccessed) { + s_logger.debug("allow muliple create requests"); + } else { + throw e; + } + } + } else { + this.stateMachines.transitTo(obj, event, null, objectDataStoreDao); + } + return true; } @Override public DataObject get(DataObject dataObj, DataStore store) { if (dataObj.getType() == DataObjectType.TEMPLATE) { - return imageFactory.getTemplate(dataObj.getId(), store); + return imageFactory.getTemplate(dataObj, store); } else if (dataObj.getType() == DataObjectType.VOLUME) { - return volumeFactory.getVolume(dataObj.getId(), store); + return volumeFactory.getVolume(dataObj, store); } throw new CloudRuntimeException("unknown type"); } @Override - public boolean update(ObjectInDataStoreVO obj) { - return objectDataStoreDao.update(obj.getId(), obj); + public DataObjectInStore findObject(DataObject obj, DataStore store) { + DataObjectInStore vo = null; + SearchCriteriaService sc = SearchCriteria2.create(ObjectInDataStoreVO.class); + + if (store.getRole() == DataStoreRole.Image) { + sc.addAnd(sc.getEntity().getDataStoreUuid(), Op.EQ, store.getUuid()); + sc.addAnd(sc.getEntity().getDataStoreRole(), Op.EQ, store.getRole()); + sc.addAnd(sc.getEntity().getObjectUuid(), Op.EQ, obj.getUuid()); + sc.addAnd(sc.getEntity().getObjectType(), Op.EQ, obj.getType()); + vo = sc.find(); + } else if (obj.getType() == DataObjectType.TEMPLATE && store.getRole() == DataStoreRole.Primary) { + vo = templatePoolDao.findByPoolTemplate(store.getId(), obj.getId()); + } else { + s_logger.debug("unknown type: " + obj.getType() + " " + store.getRole()); + throw new CloudRuntimeException("unknown type"); + } + return vo; } + + @Override + public DataObjectInStore findObject(String uuid, DataObjectType type, + String dataStoreUuid, DataStoreRole role) { + DataObjectInStore vo = null; + SearchCriteriaService sc = SearchCriteria2.create(ObjectInDataStoreVO.class); + + if (role == DataStoreRole.Image) { + sc.addAnd(sc.getEntity().getDataStoreUuid(), Op.EQ, dataStoreUuid); + sc.addAnd(sc.getEntity().getDataStoreRole(), Op.EQ, role); + sc.addAnd(sc.getEntity().getObjectUuid(), Op.EQ, uuid); + sc.addAnd(sc.getEntity().getObjectType(), Op.EQ, type); + vo = sc.find(); + } + return vo; + } + + @Override + public DataStore findStore(String objUuid, DataObjectType type, DataStoreRole role) { + DataStore store = null; + if (role == DataStoreRole.Image) { + SearchCriteriaService sc = SearchCriteria2.create(ObjectInDataStoreVO.class); + sc.addAnd(sc.getEntity().getDataStoreRole(), Op.EQ, role); + sc.addAnd(sc.getEntity().getObjectUuid(), Op.EQ, objUuid); + sc.addAnd(sc.getEntity().getObjectType(), Op.EQ, type); + ObjectInDataStoreVO vo = sc.find(); + if (vo != null) { + store = this.storeMgr.getDataStore(vo.getDataStoreUuid(), vo.getDataStoreRole()); + } + } + return store; + } + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java index a6ba9bc1f60..fdaaace49d7 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStore.java @@ -20,31 +20,19 @@ package org.apache.cloudstack.storage.datastore; import java.util.List; -import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; -import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; -import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; public interface PrimaryDataStore extends DataStore, PrimaryDataStoreInfo { VolumeInfo getVolume(long id); List getVolumes(); -/* void deleteVolumeAsync(VolumeInfo volume, AsyncCompletionCallback callback); - - void createVolumeAsync(VolumeInfo vo, VolumeDiskType diskType, AsyncCompletionCallback callback); - - void createVoluemFromBaseImageAsync(VolumeInfo volume, TemplateInfo templateStore, AsyncCompletionCallback callback); - */ - boolean exists(DataObject data); TemplateInfo getTemplate(long templateId); @@ -53,13 +41,4 @@ public interface PrimaryDataStore extends DataStore, PrimaryDataStoreInfo { DiskFormat getDefaultDiskType(); - -/* void takeSnapshot(SnapshotInfo snapshot, - AsyncCompletionCallback callback); - - void revertSnapshot(SnapshotInfo snapshot, - AsyncCompletionCallback callback); - - void deleteSnapshot(SnapshotInfo snapshot, - AsyncCompletionCallback callback);*/ } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java index 0ac57f445aa..e70f803ee81 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreEntityImpl.java @@ -26,8 +26,8 @@ import java.util.Map; import org.apache.cloudstack.engine.datacenter.entity.api.StorageEntity; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; -import com.cloud.storage.StoragePoolStatus; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePoolStatus; public class PrimaryDataStoreEntityImpl implements StorageEntity { private PrimaryDataStoreInfo dataStore; @@ -132,7 +132,8 @@ public class PrimaryDataStoreEntityImpl implements StorageEntity { @Override public State getState() { - return this.dataStore.getManagedState(); + //return this.dataStore.getManagedState(); + return null; } @Override @@ -229,13 +230,7 @@ public class PrimaryDataStoreEntityImpl implements StorageEntity { return null; } - @Override - public String getStorageProvider() { - // TODO Auto-generated method stub - return null; - } - @Override public String getStorageType() { // TODO Auto-generated method stub return null; @@ -247,4 +242,16 @@ public class PrimaryDataStoreEntityImpl implements StorageEntity { } + @Override + public Long getStorageProviderId() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isInMaintenance() { + // TODO Auto-generated method stub + return false; + } + } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreProviderManager.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreProviderManager.java index a60ec7a6e65..664c2d1c216 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreProviderManager.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreProviderManager.java @@ -18,11 +18,14 @@ */ package org.apache.cloudstack.storage.datastore; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; public interface PrimaryDataStoreProviderManager { public PrimaryDataStore getPrimaryDataStore(long dataStoreId); + public PrimaryDataStore getPrimaryDataStore(String uuid); boolean registerDriver(String uuid, PrimaryDataStoreDriver driver); + boolean registerHostListener(String uuid, HypervisorHostListener listener); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java index 3634b52908a..96d2da357f5 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/DataStoreProviderManagerImpl.java @@ -26,14 +26,19 @@ import java.util.UUID; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; import org.apache.cloudstack.storage.datastore.db.DataStoreProviderDao; import org.apache.cloudstack.storage.datastore.db.DataStoreProviderVO; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.utils.component.ManagerBase; @Component public class DataStoreProviderManagerImpl extends ManagerBase implements DataStoreProviderManager { + private static final Logger s_logger = Logger + .getLogger(DataStoreProviderManagerImpl.class); @Inject List providers; @Inject @@ -59,8 +64,8 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto @Override public boolean configure(String name, Map params) throws ConfigurationException { - -/* + Map copyParams = new HashMap(params); + //TODO: hold global lock List providerVos = providerDao.listAll(); for (DataStoreProvider provider : providers) { @@ -83,12 +88,20 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto } else { uuid = providerVO.getUuid(); } - params.put("uuid", uuid); - params.put("id", providerVO.getId()); - provider.configure(params); + copyParams.put("uuid", uuid); + copyParams.put("id", providerVO.getId()); providerMap.put(uuid, provider); + try { + boolean registrationResult = provider.configure(copyParams); + if (!registrationResult) { + providerMap.remove(uuid); + } + } catch(Exception e) { + s_logger.debug("configure provider failed", e); + providerMap.remove(uuid); + } } - */ + return true; } @@ -97,4 +110,9 @@ public class DataStoreProviderManagerImpl extends ManagerBase implements DataSto DataStoreProviderVO provider = providerDao.findById(id); return providerMap.get(provider.getUuid()); } + + @Override + public DataStoreProvider getDefaultPrimaryDataStoreProvider() { + return this.getDataStoreProvider("ancient primary data store provider"); + } } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/ImageDataStoreProvider.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/ImageDataStoreProvider.java index 502158cdaaa..d44a40e971f 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/ImageDataStoreProvider.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/ImageDataStoreProvider.java @@ -18,6 +18,8 @@ */ package org.apache.cloudstack.storage.datastore.provider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; + public interface ImageDataStoreProvider extends DataStoreProvider { } diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProvider.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProvider.java index dbca549212c..fdf5958f1ab 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProvider.java +++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/provider/PrimaryDataStoreProvider.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.storage.datastore.provider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; + public interface PrimaryDataStoreProvider extends DataStoreProvider { } diff --git a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDao.java b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDao.java index 08f9182f237..fb7dec0fa41 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDao.java +++ b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDao.java @@ -16,10 +16,12 @@ // under the License. package org.apache.cloudstack.storage.db; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.utils.db.GenericDao; import com.cloud.utils.fsm.StateDao; -public interface ObjectInDataStoreDao extends GenericDao, StateDao { +public interface ObjectInDataStoreDao extends GenericDao, StateDao { } diff --git a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java index 4a5a913adca..50dc984d49b 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreDaoImpl.java @@ -20,17 +20,17 @@ import java.util.Map; import javax.naming.ConfigurationException; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.State; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.storage.VolumeVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.UpdateBuilder; @Component public class ObjectInDataStoreDaoImpl extends GenericDaoBase implements ObjectInDataStoreDao { @@ -47,7 +47,8 @@ public class ObjectInDataStoreDaoImpl extends GenericDaoBase { +public class ObjectInDataStoreVO implements StateObject, DataObjectInStore { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) long id; - @Column(name = "datastore_id") - private long dataStoreId; + @Column(name = "datastore_uuid") + private String dataStoreUuid; @Column(name = "datastore_role") @Enumerated(EnumType.STRING) private DataStoreRole dataStoreRole; - @Column(name = "object_id") - long objectId; + @Column(name = "object_uuid") + String objectUuid; @Column(name = "object_type") @Enumerated(EnumType.STRING) @@ -74,6 +76,15 @@ public class ObjectInDataStoreVO implements StateObject params) { - ImageDataStoreVO store = imageStoreDao.findByUuid(params.get("uuid")); + public ImageDataStoreVO createImageDataStore(Map params) { + ImageDataStoreVO store = imageStoreDao.findByUuid((String)params.get("uuid")); if (store != null) { - throw new CloudRuntimeException("duplicate uuid"); + return store; } store = new ImageDataStoreVO(); - store.setName(params.get("name")); - store.setProtocol(params.get("protocol")); - store.setProvider(Long.parseLong(params.get("provider"))); - store.setScope(Enum.valueOf(ScopeType.class, params.get("scope"))); - store.setUuid(params.get("uuid")); + store.setName((String)params.get("name")); + store.setProtocol((String)params.get("protocol")); + store.setProvider((Long)params.get("provider")); + store.setScope((ScopeType)params.get("scope")); + store.setUuid((String)params.get("uuid")); store = imageStoreDao.persist(store); return store; } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageDataStoreManager.java b/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageDataStoreManager.java index 2bd361f05e9..b6d84cdcef2 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageDataStoreManager.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/datastore/ImageDataStoreManager.java @@ -18,9 +18,14 @@ */ package org.apache.cloudstack.storage.image.datastore; +import java.util.List; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.storage.image.ImageDataStoreDriver; public interface ImageDataStoreManager { ImageDataStore getImageDataStore(long dataStoreId); + ImageDataStore getImageDataStore(String uuid); + List getList(); boolean registerDriver(String uuid, ImageDataStoreDriver driver); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java deleted file mode 100644 index b5db164055d..00000000000 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDao.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cloudstack.storage.image.db; - -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateState; - -import com.cloud.domain.DomainVO; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.projects.Project.ListProjectResourcesCriteria; -import com.cloud.template.VirtualMachineTemplate.TemplateFilter; -import com.cloud.user.Account; -import com.cloud.utils.Pair; -import com.cloud.utils.db.GenericDao; -import com.cloud.utils.fsm.StateDao; - -public interface ImageDataDao extends GenericDao, StateDao { - public List listByPublic(); - - public ImageDataVO findByName(String templateName); - - public ImageDataVO findByTemplateName(String templateName); - - // public void update(ImageDataVO template); - - public List listAllSystemVMTemplates(); - - public List listDefaultBuiltinTemplates(); - - public String getRoutingTemplateUniqueName(); - - public List findIsosByIdAndPath(Long domainId, Long accountId, String path); - - public List listReadyTemplates(); - - public List listByAccountId(long accountId); - - public Set> searchTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, - Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, - ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags); - - public Set> searchSwiftTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, - Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, Map tags); - - public long addTemplateToZone(ImageDataVO tmplt, long zoneId); - - public List listAllInZone(long dataCenterId); - - public List listByHypervisorType(List hyperTypes); - - public List publicIsoSearch(Boolean bootable, boolean listRemoved, Map tags); - - public List userIsoSearch(boolean listRemoved); - - ImageDataVO findSystemVMTemplate(long zoneId); - - ImageDataVO findSystemVMTemplate(long zoneId, HypervisorType hType); - - ImageDataVO findRoutingTemplate(HypervisorType type); - - List listPrivateTemplatesByHost(Long hostId); - - public Long countTemplatesForAccount(long accountId); - -} diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java deleted file mode 100644 index 301b5861f8c..00000000000 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataDaoImpl.java +++ /dev/null @@ -1,975 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cloudstack.storage.image.db; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.storage.image.TemplateEvent; -import org.apache.cloudstack.storage.image.TemplateState; -import org.apache.cloudstack.storage.image.format.ISO; -import org.apache.log4j.Logger; -import org.springframework.stereotype.Component; - -import com.cloud.configuration.dao.ConfigurationDao; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.domain.DomainVO; -import com.cloud.domain.dao.DomainDao; -import com.cloud.host.Host; -import com.cloud.host.HostVO; -import com.cloud.host.dao.HostDao; -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.projects.Project.ListProjectResourcesCriteria; -import com.cloud.server.ResourceTag.TaggedResourceType; -import com.cloud.storage.Storage; -import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.VMTemplateZoneVO; -import com.cloud.storage.dao.VMTemplateDaoImpl; -import com.cloud.storage.dao.VMTemplateDetailsDao; -import com.cloud.storage.dao.VMTemplateZoneDao; -import com.cloud.tags.ResourceTagVO; -import com.cloud.tags.dao.ResourceTagsDaoImpl; -import com.cloud.template.VirtualMachineTemplate.TemplateFilter; -import com.cloud.user.Account; -import com.cloud.utils.Pair; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.Filter; -import com.cloud.utils.db.GenericDaoBase; -import com.cloud.utils.db.GenericSearchBuilder; -import com.cloud.utils.db.JoinBuilder; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.SearchCriteria.Func; -import com.cloud.utils.db.SearchCriteria.Op; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.UpdateBuilder; -import com.cloud.utils.exception.CloudRuntimeException; - -@Component -public class ImageDataDaoImpl extends GenericDaoBase implements ImageDataDao { - private static final Logger s_logger = Logger.getLogger(VMTemplateDaoImpl.class); - - @Inject - VMTemplateZoneDao templateZoneDao; - @Inject - VMTemplateDetailsDao templateDetailsDao; - - @Inject - ConfigurationDao configDao; - @Inject - HostDao hostDao; - @Inject - DomainDao domainDao; - @Inject - DataCenterDao dcDao; - - private final String SELECT_TEMPLATE_HOST_REF = "SELECT t.id, h.data_center_id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " - + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t"; - - private final String SELECT_TEMPLATE_ZONE_REF = "SELECT t.id, tzr.zone_id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " - + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t INNER JOIN template_zone_ref tzr on (t.id = tzr.template_id) "; - - private final String SELECT_TEMPLATE_SWIFT_REF = "SELECT t.id, t.unique_name, t.name, t.public, t.featured, t.type, t.hvm, t.bits, t.url, t.format, t.created, t.account_id, " - + "t.checksum, t.display_text, t.enable_password, t.guest_os_id, t.bootable, t.prepopulate, t.cross_zones, t.hypervisor_type FROM vm_template t"; - protected SearchBuilder TemplateNameSearch; - protected SearchBuilder UniqueNameSearch; - protected SearchBuilder tmpltTypeSearch; - protected SearchBuilder tmpltTypeHyperSearch; - protected SearchBuilder tmpltTypeHyperSearch2; - - protected SearchBuilder AccountIdSearch; - protected SearchBuilder NameSearch; - protected SearchBuilder TmpltsInZoneSearch; - private SearchBuilder PublicSearch; - private SearchBuilder NameAccountIdSearch; - private SearchBuilder PublicIsoSearch; - private SearchBuilder UserIsoSearch; - private GenericSearchBuilder CountTemplatesByAccount; - private SearchBuilder updateStateSearch; - - //ResourceTagsDaoImpl _tagsDao = ComponentInject.inject(ResourceTagsDaoImpl.class); - @Inject - ResourceTagsDaoImpl _tagsDao = null; - private String routerTmpltName; - private String consoleProxyTmpltName; - - protected ImageDataDaoImpl() { - } - - @Override - public List listByPublic() { - SearchCriteria sc = PublicSearch.create(); - sc.setParameters("public", 1); - return listBy(sc); - } - - @Override - public ImageDataVO findByName(String templateName) { - SearchCriteria sc = UniqueNameSearch.create(); - sc.setParameters("uniqueName", templateName); - return findOneIncludingRemovedBy(sc); - } - - @Override - public ImageDataVO findByTemplateName(String templateName) { - SearchCriteria sc = NameSearch.create(); - sc.setParameters("name", templateName); - return findOneIncludingRemovedBy(sc); - } - - @Override - public List publicIsoSearch(Boolean bootable, boolean listRemoved, Map tags) { - - SearchBuilder sb = null; - if (tags == null || tags.isEmpty()) { - sb = PublicIsoSearch; - } else { - sb = createSearchBuilder(); - sb.and("public", sb.entity().isPublicTemplate(), SearchCriteria.Op.EQ); - sb.and("format", sb.entity().getFormat(), SearchCriteria.Op.EQ); - sb.and("type", sb.entity().getTemplateType(), SearchCriteria.Op.EQ); - sb.and("bootable", sb.entity().isBootable(), SearchCriteria.Op.EQ); - sb.and("removed", sb.entity().getRemoved(), SearchCriteria.Op.EQ); - - SearchBuilder tagSearch = _tagsDao.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); - } - - SearchCriteria sc = sb.create(); - - sc.setParameters("public", 1); - sc.setParameters("format", "ISO"); - sc.setParameters("type", TemplateType.PERHOST.toString()); - if (bootable != null) { - sc.setParameters("bootable", bootable); - } - - if (!listRemoved) { - sc.setParameters("removed", (Object) null); - } - - if (tags != null && !tags.isEmpty()) { - int count = 0; - sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.ISO.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++; - } - } - - return listBy(sc); - } - - @Override - public List userIsoSearch(boolean listRemoved) { - - SearchBuilder sb = null; - sb = UserIsoSearch; - SearchCriteria sc = sb.create(); - - sc.setParameters("format", Storage.ImageFormat.ISO); - sc.setParameters("type", TemplateType.USER.toString()); - - if (!listRemoved) { - sc.setParameters("removed", (Object) null); - } - - return listBy(sc); - } - - @Override - public List listAllSystemVMTemplates() { - SearchCriteria sc = tmpltTypeSearch.create(); - sc.setParameters("templateType", Storage.TemplateType.SYSTEM); - - Filter filter = new Filter(ImageDataVO.class, "id", false, null, null); - return listBy(sc, filter); - } - - @Override - public List listPrivateTemplatesByHost(Long hostId) { - - String sql = "select * from template_host_ref as thr INNER JOIN vm_template as t ON t.id=thr.template_id " - + "where thr.host_id=? and t.public=0 and t.featured=0 and t.type='USER' and t.removed is NULL"; - - List l = new ArrayList(); - - Transaction txn = Transaction.currentTxn(); - - PreparedStatement pstmt = null; - try { - pstmt = txn.prepareAutoCloseStatement(sql); - pstmt.setLong(1, hostId); - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) { - l.add(rs.getLong(1)); - } - } catch (SQLException e) { - } catch (Throwable e) { - } - return l; - } - - @Override - public List listReadyTemplates() { - SearchCriteria sc = createSearchCriteria(); - sc.addAnd("ready", SearchCriteria.Op.EQ, true); - sc.addAnd("format", SearchCriteria.Op.NEQ, Storage.ImageFormat.ISO); - return listIncludingRemovedBy(sc); - } - - @Override - public List findIsosByIdAndPath(Long domainId, Long accountId, String path) { - SearchCriteria sc = createSearchCriteria(); - sc.addAnd("iso", SearchCriteria.Op.EQ, true); - if (domainId != null) { - sc.addAnd("domainId", SearchCriteria.Op.EQ, domainId); - } - if (accountId != null) { - sc.addAnd("accountId", SearchCriteria.Op.EQ, accountId); - } - if (path != null) { - sc.addAnd("path", SearchCriteria.Op.EQ, path); - } - return listIncludingRemovedBy(sc); - } - - @Override - public List listByAccountId(long accountId) { - SearchCriteria sc = AccountIdSearch.create(); - sc.setParameters("accountId", accountId); - return listBy(sc); - } - - @Override - public List listByHypervisorType(List hyperTypes) { - SearchCriteria sc = createSearchCriteria(); - hyperTypes.add(HypervisorType.None); - sc.addAnd("hypervisorType", SearchCriteria.Op.IN, hyperTypes.toArray()); - return listBy(sc); - } - - @Override - public boolean configure(String name, Map params) throws ConfigurationException { - boolean result = super.configure(name, params); - - PublicSearch = createSearchBuilder(); - PublicSearch.and("public", PublicSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); - - routerTmpltName = (String) params.get("routing.uniquename"); - - s_logger.debug("Found parameter routing unique name " + routerTmpltName); - if (routerTmpltName == null) { - routerTmpltName = "routing"; - } - - consoleProxyTmpltName = (String) params.get("consoleproxy.uniquename"); - if (consoleProxyTmpltName == null) { - consoleProxyTmpltName = "routing"; - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Use console proxy template : " + consoleProxyTmpltName); - } - - UniqueNameSearch = createSearchBuilder(); - UniqueNameSearch.and("uniqueName", UniqueNameSearch.entity().getUniqueName(), SearchCriteria.Op.EQ); - NameSearch = createSearchBuilder(); - NameSearch.and("name", NameSearch.entity().getName(), SearchCriteria.Op.EQ); - - NameAccountIdSearch = createSearchBuilder(); - NameAccountIdSearch.and("name", NameAccountIdSearch.entity().getName(), SearchCriteria.Op.EQ); - NameAccountIdSearch.and("accountId", NameAccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); - - PublicIsoSearch = createSearchBuilder(); - PublicIsoSearch.and("public", PublicIsoSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); - PublicIsoSearch.and("format", PublicIsoSearch.entity().getFormat(), SearchCriteria.Op.EQ); - PublicIsoSearch.and("type", PublicIsoSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); - PublicIsoSearch.and("bootable", PublicIsoSearch.entity().isBootable(), SearchCriteria.Op.EQ); - PublicIsoSearch.and("removed", PublicIsoSearch.entity().getRemoved(), SearchCriteria.Op.EQ); - - UserIsoSearch = createSearchBuilder(); - UserIsoSearch.and("format", UserIsoSearch.entity().getFormat(), SearchCriteria.Op.EQ); - UserIsoSearch.and("type", UserIsoSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); - UserIsoSearch.and("removed", UserIsoSearch.entity().getRemoved(), SearchCriteria.Op.EQ); - - tmpltTypeHyperSearch = createSearchBuilder(); - tmpltTypeHyperSearch.and("templateType", tmpltTypeHyperSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); - SearchBuilder hostHyperSearch = hostDao.createSearchBuilder(); - hostHyperSearch.and("type", hostHyperSearch.entity().getType(), SearchCriteria.Op.EQ); - hostHyperSearch.and("zoneId", hostHyperSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); - hostHyperSearch.groupBy(hostHyperSearch.entity().getHypervisorType()); - - tmpltTypeHyperSearch.join("tmplHyper", hostHyperSearch, hostHyperSearch.entity().getHypervisorType(), tmpltTypeHyperSearch.entity().getHypervisorType(), JoinBuilder.JoinType.INNER); - hostHyperSearch.done(); - tmpltTypeHyperSearch.done(); - - tmpltTypeHyperSearch2 = createSearchBuilder(); - tmpltTypeHyperSearch2.and("templateType", tmpltTypeHyperSearch2.entity().getTemplateType(), SearchCriteria.Op.EQ); - tmpltTypeHyperSearch2.and("hypervisorType", tmpltTypeHyperSearch2.entity().getHypervisorType(), SearchCriteria.Op.EQ); - - tmpltTypeSearch = createSearchBuilder(); - tmpltTypeSearch.and("removed", tmpltTypeSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - tmpltTypeSearch.and("templateType", tmpltTypeSearch.entity().getTemplateType(), SearchCriteria.Op.EQ); - - AccountIdSearch = createSearchBuilder(); - AccountIdSearch.and("accountId", AccountIdSearch.entity().getAccountId(), SearchCriteria.Op.EQ); - AccountIdSearch.and("publicTemplate", AccountIdSearch.entity().isPublicTemplate(), SearchCriteria.Op.EQ); - AccountIdSearch.done(); - - SearchBuilder tmpltZoneSearch = templateZoneDao.createSearchBuilder(); - tmpltZoneSearch.and("removed", tmpltZoneSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - tmpltZoneSearch.and("zoneId", tmpltZoneSearch.entity().getZoneId(), SearchCriteria.Op.EQ); - - TmpltsInZoneSearch = createSearchBuilder(); - TmpltsInZoneSearch.and("removed", TmpltsInZoneSearch.entity().getRemoved(), SearchCriteria.Op.NULL); - TmpltsInZoneSearch.and().op("avoidtype", TmpltsInZoneSearch.entity().getTemplateType(), SearchCriteria.Op.NEQ); - TmpltsInZoneSearch.or("templateType", TmpltsInZoneSearch.entity().getTemplateType(), SearchCriteria.Op.NULL); - TmpltsInZoneSearch.cp(); - TmpltsInZoneSearch.join("tmpltzone", tmpltZoneSearch, tmpltZoneSearch.entity().getTemplateId(), TmpltsInZoneSearch.entity().getId(), JoinBuilder.JoinType.INNER); - tmpltZoneSearch.done(); - TmpltsInZoneSearch.done(); - - CountTemplatesByAccount = createSearchBuilder(Long.class); - CountTemplatesByAccount.select(null, Func.COUNT, null); - CountTemplatesByAccount.and("account", CountTemplatesByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); - CountTemplatesByAccount.and("removed", CountTemplatesByAccount.entity().getRemoved(), SearchCriteria.Op.NULL); - CountTemplatesByAccount.done(); - - updateStateSearch = this.createSearchBuilder(); - updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); - updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); - updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); - updateStateSearch.done(); - return result; - } - - @Override - public String getRoutingTemplateUniqueName() { - return routerTmpltName; - } - - @Override - public Set> searchSwiftTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, - Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, Map tags) { - - StringBuilder builder = new StringBuilder(); - if (!permittedAccounts.isEmpty()) { - for (Account permittedAccount : permittedAccounts) { - builder.append(permittedAccount.getAccountId() + ","); - } - } - - String permittedAccountsStr = builder.toString(); - - if (permittedAccountsStr.length() > 0) { - // chop the "," off - permittedAccountsStr = permittedAccountsStr.substring(0, permittedAccountsStr.length() - 1); - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - Set> templateZonePairList = new HashSet>(); - PreparedStatement pstmt = null; - ResultSet rs = null; - String sql = SELECT_TEMPLATE_SWIFT_REF; - try { - String joinClause = ""; - String whereClause = " WHERE t.removed IS NULL"; - - if (isIso) { - whereClause += " AND t.format = 'ISO'"; - if (!hyperType.equals(HypervisorType.None)) { - joinClause = " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) "; - whereClause += " AND goh.hypervisor_type = '" + hyperType.toString() + "'"; - } - } else { - whereClause += " AND t.format <> 'ISO'"; - if (hypers.isEmpty()) { - return templateZonePairList; - } else { - StringBuilder relatedHypers = new StringBuilder(); - for (HypervisorType hyper : hypers) { - relatedHypers.append("'"); - relatedHypers.append(hyper.toString()); - relatedHypers.append("'"); - relatedHypers.append(","); - } - relatedHypers.setLength(relatedHypers.length() - 1); - whereClause += " AND t.hypervisor_type IN (" + relatedHypers + ")"; - } - } - joinClause += " INNER JOIN template_swift_ref tsr on (t.id = tsr.template_id)"; - if (keyword != null) { - whereClause += " AND t.name LIKE \"%" + keyword + "%\""; - } else if (name != null) { - whereClause += " AND t.name LIKE \"%" + name + "%\""; - } - - if (bootable != null) { - whereClause += " AND t.bootable = " + bootable; - } - - if (!showDomr) { - whereClause += " AND t.type != '" + Storage.TemplateType.SYSTEM.toString() + "'"; - } - - if (templateFilter == TemplateFilter.featured) { - whereClause += " AND t.public = 1 AND t.featured = 1"; - } else if ((templateFilter == TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { - if (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) { - joinClause += " INNER JOIN account a on (t.account_id = a.id) INNER JOIN domain d on (a.domain_id = d.id)"; - whereClause += " AND d.path LIKE '" + domain.getPath() + "%'"; - } else { - whereClause += " AND t.account_id IN (" + permittedAccountsStr + ")"; - } - } else if (templateFilter == TemplateFilter.sharedexecutable && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { - if (caller.getType() == Account.ACCOUNT_TYPE_NORMAL) { - joinClause += " LEFT JOIN launch_permission lp ON t.id = lp.template_id WHERE" + " (t.account_id IN (" + permittedAccountsStr + ") OR" + " lp.account_id IN (" - + permittedAccountsStr + "))"; - } else { - joinClause += " INNER JOIN account a on (t.account_id = a.id) "; - } - } else if (templateFilter == TemplateFilter.executable && !permittedAccounts.isEmpty()) { - whereClause += " AND (t.public = 1 OR t.account_id IN (" + permittedAccountsStr + "))"; - } else if (templateFilter == TemplateFilter.community) { - whereClause += " AND t.public = 1 AND t.featured = 0"; - } else if (templateFilter == TemplateFilter.all && caller.getType() == Account.ACCOUNT_TYPE_ADMIN) { - } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { - return templateZonePairList; - } - - sql += joinClause + whereClause + getOrderByLimit(pageSize, startIndex); - pstmt = txn.prepareStatement(sql); - rs = pstmt.executeQuery(); - while (rs.next()) { - Pair templateZonePair = new Pair(rs.getLong(1), -1L); - templateZonePairList.add(templateZonePair); - } - - } catch (Exception e) { - s_logger.warn("Error listing templates", e); - } finally { - try { - if (rs != null) { - rs.close(); - } - if (pstmt != null) { - pstmt.close(); - } - txn.commit(); - } catch (SQLException sqle) { - s_logger.warn("Error in cleaning up", sqle); - } - } - - return templateZonePairList; - } - - @Override - public Set> searchTemplates(String name, String keyword, TemplateFilter templateFilter, boolean isIso, List hypers, Boolean bootable, DomainVO domain, - Long pageSize, Long startIndex, Long zoneId, HypervisorType hyperType, boolean onlyReady, boolean showDomr, List permittedAccounts, Account caller, - ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags) { - StringBuilder builder = new StringBuilder(); - if (!permittedAccounts.isEmpty()) { - for (Account permittedAccount : permittedAccounts) { - builder.append(permittedAccount.getAccountId() + ","); - } - } - - String permittedAccountsStr = builder.toString(); - - if (permittedAccountsStr.length() > 0) { - // chop the "," off - permittedAccountsStr = permittedAccountsStr.substring(0, permittedAccountsStr.length() - 1); - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - /* Use LinkedHashSet here to guarantee iteration order */ - Set> templateZonePairList = new LinkedHashSet>(); - PreparedStatement pstmt = null; - ResultSet rs = null; - StringBuilder relatedDomainIds = new StringBuilder(); - String sql = SELECT_TEMPLATE_ZONE_REF; - String groupByClause = ""; - try { - // short accountType; - // String accountId = null; - String guestOSJoin = ""; - StringBuilder templateHostRefJoin = new StringBuilder(); - String dataCenterJoin = "", lpjoin = ""; - String tagsJoin = ""; - - if (isIso && !hyperType.equals(HypervisorType.None)) { - guestOSJoin = " INNER JOIN guest_os guestOS on (guestOS.id = t.guest_os_id) INNER JOIN guest_os_hypervisor goh on ( goh.guest_os_id = guestOS.id) "; - } - if (onlyReady) { - templateHostRefJoin.append(" INNER JOIN template_host_ref thr on (t.id = thr.template_id) INNER JOIN host h on (thr.host_id = h.id)"); - sql = SELECT_TEMPLATE_HOST_REF; - groupByClause = " GROUP BY t.id, h.data_center_id "; - } - if ((templateFilter == TemplateFilter.featured) || (templateFilter == TemplateFilter.community)) { - dataCenterJoin = " INNER JOIN data_center dc on (h.data_center_id = dc.id)"; - } - - if (templateFilter == TemplateFilter.sharedexecutable) { - lpjoin = " INNER JOIN launch_permission lp ON t.id = lp.template_id "; - } - - if (tags != null && !tags.isEmpty()) { - tagsJoin = " INNER JOIN resource_tags r ON t.id = r.resource_id "; - } - - sql += guestOSJoin + templateHostRefJoin + dataCenterJoin + lpjoin + tagsJoin; - String whereClause = ""; - - // All joins have to be made before we start setting the condition - // settings - if ((listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources || (!permittedAccounts.isEmpty() && !(templateFilter == TemplateFilter.community || templateFilter == TemplateFilter.featured))) - && !(caller.getType() != Account.ACCOUNT_TYPE_NORMAL && templateFilter == TemplateFilter.all)) { - whereClause += " INNER JOIN account a on (t.account_id = a.id)"; - if ((templateFilter == TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) - && (caller.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN || caller.getType() == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN)) { - whereClause += " INNER JOIN domain d on (a.domain_id = d.id) WHERE d.path LIKE '" + domain.getPath() + "%'"; - if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) { - whereClause += " AND a.type != " + Account.ACCOUNT_TYPE_PROJECT; - } - } else if (listProjectResourcesCriteria == ListProjectResourcesCriteria.SkipProjectResources) { - whereClause += " WHERE a.type != " + Account.ACCOUNT_TYPE_PROJECT; - } - } - - if (!permittedAccounts.isEmpty()) { - for (Account account : permittedAccounts) { - // accountType = account.getType(); - // accountId = Long.toString(account.getId()); - DomainVO accountDomain = domainDao.findById(account.getDomainId()); - - // get all parent domain ID's all the way till root domain - DomainVO domainTreeNode = accountDomain; - while (true) { - relatedDomainIds.append(domainTreeNode.getId()); - relatedDomainIds.append(","); - if (domainTreeNode.getParent() != null) { - domainTreeNode = domainDao.findById(domainTreeNode.getParent()); - } else { - break; - } - } - - // get all child domain ID's - if (isAdmin(account.getType())) { - List allChildDomains = domainDao.findAllChildren(accountDomain.getPath(), accountDomain.getId()); - for (DomainVO childDomain : allChildDomains) { - relatedDomainIds.append(childDomain.getId()); - relatedDomainIds.append(","); - } - } - relatedDomainIds.setLength(relatedDomainIds.length() - 1); - } - } - - String attr = " AND "; - if (whereClause.endsWith(" WHERE ")) { - attr += " WHERE "; - } - - if (!isIso) { - if (hypers.isEmpty()) { - return templateZonePairList; - } else { - StringBuilder relatedHypers = new StringBuilder(); - for (HypervisorType hyper : hypers) { - relatedHypers.append("'"); - relatedHypers.append(hyper.toString()); - relatedHypers.append("'"); - relatedHypers.append(","); - } - relatedHypers.setLength(relatedHypers.length() - 1); - whereClause += attr + " t.hypervisor_type IN (" + relatedHypers + ")"; - } - } - - if (!permittedAccounts.isEmpty() && !(templateFilter == TemplateFilter.featured || templateFilter == TemplateFilter.community || templateFilter == TemplateFilter.executable) - && !isAdmin(caller.getType())) { - whereClause += attr + "t.account_id IN (" + permittedAccountsStr + ")"; - } - - if (templateFilter == TemplateFilter.featured) { - whereClause += attr + "t.public = 1 AND t.featured = 1"; - if (!permittedAccounts.isEmpty()) { - whereClause += attr + "(dc.domain_id IN (" + relatedDomainIds + ") OR dc.domain_id is NULL)"; - } - } else if (templateFilter == TemplateFilter.self || templateFilter == TemplateFilter.selfexecutable) { - whereClause += " AND t.account_id IN (" + permittedAccountsStr + ")"; - } else if (templateFilter == TemplateFilter.sharedexecutable) { - whereClause += " AND " + " (t.account_id IN (" + permittedAccountsStr + ") OR" + " lp.account_id IN (" + permittedAccountsStr + "))"; - } else if (templateFilter == TemplateFilter.executable && !permittedAccounts.isEmpty()) { - whereClause += attr + "(t.public = 1 OR t.account_id IN (" + permittedAccountsStr + "))"; - } else if (templateFilter == TemplateFilter.community) { - whereClause += attr + "t.public = 1 AND t.featured = 0"; - if (!permittedAccounts.isEmpty()) { - whereClause += attr + "(dc.domain_id IN (" + relatedDomainIds + ") OR dc.domain_id is NULL)"; - } - } else if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && !isIso) { - return templateZonePairList; - } - - if (tags != null && !tags.isEmpty()) { - whereClause += " AND ("; - boolean first = true; - for (String key : tags.keySet()) { - if (!first) { - whereClause += " OR "; - } - whereClause += "(r.key=\"" + key + "\" and r.value=\"" + tags.get(key) + "\")"; - first = false; - } - whereClause += ")"; - } - - if (whereClause.equals("")) { - whereClause += " WHERE "; - } else if (!whereClause.equals(" WHERE ")) { - whereClause += " AND "; - } - - sql += whereClause + getExtrasWhere(templateFilter, name, keyword, isIso, bootable, hyperType, zoneId, onlyReady, showDomr) + groupByClause + getOrderByLimit(pageSize, startIndex); - - pstmt = txn.prepareStatement(sql); - rs = pstmt.executeQuery(); - - while (rs.next()) { - Pair templateZonePair = new Pair(rs.getLong(1), rs.getLong(2)); - templateZonePairList.add(templateZonePair); - } - // for now, defaulting pageSize to a large val if null; may need to - // revisit post 2.2RC2 - if (isIso && - templateZonePairList.size() < (pageSize != null ? pageSize : 500) && - templateFilter != TemplateFilter.community && - !(templateFilter == TemplateFilter.self) /* TODO: Fix this! && !BaseCmd.isRootAdmin(caller.getType())*/) { // evaluates - // to - // true - // If - // root - // admin - // and - // filter=self - - List publicIsos = publicIsoSearch(bootable, false, tags); - List userIsos = userIsoSearch(false); - - // Listing the ISOs according to the page size.Restricting the - // total no. of ISOs on a page - // to be less than or equal to the pageSize parameter - - int i = 0; - - if (startIndex > userIsos.size()) { - i = (int) (startIndex - userIsos.size()); - } - - for (; i < publicIsos.size(); i++) { - if (templateZonePairList.size() >= pageSize) { - break; - } else { - if (keyword != null && publicIsos.get(i).getName().contains(keyword)) { - templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); - continue; - } else if (name != null && publicIsos.get(i).getName().contains(name)) { - templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); - continue; - } else if (keyword == null && name == null) { - templateZonePairList.add(new Pair(publicIsos.get(i).getId(), null)); - } - } - } - } - } catch (Exception e) { - s_logger.warn("Error listing templates", e); - } finally { - try { - if (rs != null) { - rs.close(); - } - if (pstmt != null) { - pstmt.close(); - } - txn.commit(); - } catch (SQLException sqle) { - s_logger.warn("Error in cleaning up", sqle); - } - } - - return templateZonePairList; - } - - private String getExtrasWhere(TemplateFilter templateFilter, String name, String keyword, boolean isIso, Boolean bootable, HypervisorType hyperType, Long zoneId, boolean onlyReady, - boolean showDomr) { - String sql = ""; - if (keyword != null) { - sql += " t.name LIKE \"%" + keyword + "%\" AND"; - } else if (name != null) { - sql += " t.name LIKE \"%" + name + "%\" AND"; - } - - if (isIso) { - sql += " t.format = 'ISO'"; - if (!hyperType.equals(HypervisorType.None)) { - sql += " AND goh.hypervisor_type = '" + hyperType.toString() + "'"; - } - } else { - sql += " t.format <> 'ISO'"; - if (!hyperType.equals(HypervisorType.None)) { - sql += " AND t.hypervisor_type = '" + hyperType.toString() + "'"; - } - } - - if (bootable != null) { - sql += " AND t.bootable = " + bootable; - } - - if (onlyReady) { - sql += " AND thr.download_state = '" + Status.DOWNLOADED.toString() + "'" + " AND thr.destroyed=0 "; - if (zoneId != null) { - sql += " AND h.data_center_id = " + zoneId; - } - } else if (zoneId != null) { - sql += " AND tzr.zone_id = " + zoneId + " AND tzr.removed is null"; - } else { - sql += " AND tzr.removed is null "; - } - if (!showDomr) { - sql += " AND t.type != '" + Storage.TemplateType.SYSTEM.toString() + "'"; - } - - sql += " AND t.removed IS NULL"; - - return sql; - } - - private String getOrderByLimit(Long pageSize, Long startIndex) { - Boolean isAscending = Boolean.parseBoolean(configDao.getValue("sortkey.algorithm")); - isAscending = (isAscending == null ? true : isAscending); - - String sql; - if (isAscending) { - sql = " ORDER BY t.sort_key ASC"; - } else { - sql = " ORDER BY t.sort_key DESC"; - } - - if ((pageSize != null) && (startIndex != null)) { - sql += " LIMIT " + startIndex.toString() + "," + pageSize.toString(); - } - return sql; - } - - @Override - @DB - public long addTemplateToZone(ImageDataVO tmplt, long zoneId) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - ImageDataVO tmplt2 = findById(tmplt.getId()); - if (tmplt2 == null) { - if (persist(tmplt) == null) { - throw new CloudRuntimeException("Failed to persist the template " + tmplt); - } - if (tmplt.getDetails() != null) { - templateDetailsDao.persist(tmplt.getId(), tmplt.getDetails()); - } - } - VMTemplateZoneVO tmpltZoneVO = templateZoneDao.findByZoneTemplate(zoneId, tmplt.getId()); - if (tmpltZoneVO == null) { - tmpltZoneVO = new VMTemplateZoneVO(zoneId, tmplt.getId(), new Date()); - templateZoneDao.persist(tmpltZoneVO); - } else { - tmpltZoneVO.setRemoved(null); - tmpltZoneVO.setLastUpdated(new Date()); - templateZoneDao.update(tmpltZoneVO.getId(), tmpltZoneVO); - } - txn.commit(); - - return tmplt.getId(); - } - - @Override - @DB - public List listAllInZone(long dataCenterId) { - SearchCriteria sc = TmpltsInZoneSearch.create(); - sc.setParameters("avoidtype", TemplateType.PERHOST.toString()); - sc.setJoinParameters("tmpltzone", "zoneId", dataCenterId); - return listBy(sc); - } - - @Override - public List listDefaultBuiltinTemplates() { - SearchCriteria sc = tmpltTypeSearch.create(); - sc.setParameters("templateType", Storage.TemplateType.BUILTIN); - return listBy(sc); - } - - @Override - public ImageDataVO findSystemVMTemplate(long zoneId) { - SearchCriteria sc = tmpltTypeHyperSearch.create(); - sc.setParameters("templateType", Storage.TemplateType.SYSTEM); - sc.setJoinParameters("tmplHyper", "type", Host.Type.Routing); - sc.setJoinParameters("tmplHyper", "zoneId", zoneId); - - // order by descending order of id and select the first (this is going - // to be the latest) - List tmplts = listBy(sc, new Filter(ImageDataVO.class, "id", false, null, 1l)); - - if (tmplts.size() > 0) { - return tmplts.get(0); - } else { - return null; - } - } - - @Override - public ImageDataVO findSystemVMTemplate(long zoneId, HypervisorType hType) { - SearchCriteria sc = tmpltTypeHyperSearch.create(); - sc.setParameters("templateType", Storage.TemplateType.SYSTEM); - sc.setJoinParameters("tmplHyper", "type", Host.Type.Routing); - sc.setJoinParameters("tmplHyper", "zoneId", zoneId); - - // order by descending order of id - List tmplts = listBy(sc, new Filter(ImageDataVO.class, "id", false, null, null)); - - for (ImageDataVO tmplt : tmplts) { - if (tmplt.getHypervisorType() == hType) { - return tmplt; - } - } - if (tmplts.size() > 0 && hType == HypervisorType.Any) { - return tmplts.get(0); - } - return null; - } - - @Override - public ImageDataVO findRoutingTemplate(HypervisorType hType) { - SearchCriteria sc = tmpltTypeHyperSearch2.create(); - sc.setParameters("templateType", Storage.TemplateType.SYSTEM); - sc.setParameters("hypervisorType", hType); - - // order by descending order of id and select the first (this is going - // to be the latest) - List tmplts = listBy(sc, new Filter(ImageDataVO.class, "id", false, null, 1l)); - - if (tmplts.size() > 0) { - return tmplts.get(0); - } else { - return null; - } - } - - @Override - public Long countTemplatesForAccount(long accountId) { - SearchCriteria sc = CountTemplatesByAccount.create(); - sc.setParameters("account", accountId); - return customSearch(sc, null).get(0); - } - - @Override - @DB - public boolean remove(Long id) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - ImageDataVO template = createForUpdate(); - template.setRemoved(new Date()); - - ImageDataVO vo = findById(id); - if (vo != null) { - if (vo.getFormat().equalsIgnoreCase(new ISO().toString())) { - _tagsDao.removeByIdAndType(id, TaggedResourceType.ISO); - } else { - _tagsDao.removeByIdAndType(id, TaggedResourceType.Template); - } - } - - boolean result = update(id, template); - txn.commit(); - return result; - } - - private boolean isAdmin(short accountType) { - return ((accountType == Account.ACCOUNT_TYPE_ADMIN) || (accountType == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) || (accountType == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) || (accountType == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)); - } - - @Override - public boolean updateState(TemplateState currentState, TemplateEvent event, - TemplateState nextState, ImageDataVO vo, Object data) { - Long oldUpdated = vo.getUpdatedCount(); - Date oldUpdatedTime = vo.getUpdated(); - - - SearchCriteria sc = updateStateSearch.create(); - sc.setParameters("id", vo.getId()); - sc.setParameters("state", currentState); - sc.setParameters("updatedCount", vo.getUpdatedCount()); - - vo.incrUpdatedCount(); - - UpdateBuilder builder = getUpdateBuilder(vo); - builder.set(vo, "state", nextState); - builder.set(vo, "updated", new Date()); - - int rows = update((ImageDataVO) vo, sc); - if (rows == 0 && s_logger.isDebugEnabled()) { - ImageDataVO dbVol = findByIdIncludingRemoved(vo.getId()); - if (dbVol != null) { - StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); - str.append(": DB Data={id=").append(dbVol.getId()).append("; state=").append(dbVol.getState()).append("; updatecount=").append(dbVol.getUpdatedCount()).append(";updatedTime=") - .append(dbVol.getUpdated()); - str.append(": New Data={id=").append(vo.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(vo.getUpdatedCount()) - .append("; updatedTime=").append(vo.getUpdated()); - str.append(": stale Data={id=").append(vo.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated) - .append("; updatedTime=").append(oldUpdatedTime); - } else { - s_logger.debug("Unable to update objectIndatastore: id=" + vo.getId() + ", as there is no such object exists in the database anymore"); - } - } - return rows > 0; - } -} \ No newline at end of file diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java b/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java deleted file mode 100644 index e3ddaed721a..00000000000 --- a/engine/storage/src/org/apache/cloudstack/storage/image/db/ImageDataVO.java +++ /dev/null @@ -1,450 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cloudstack.storage.image.db; - -import java.util.Date; -import java.util.Map; -import java.util.UUID; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.Id; -import javax.persistence.Table; -import javax.persistence.TableGenerator; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; - -import org.apache.cloudstack.api.Identity; -import org.apache.cloudstack.storage.image.TemplateState; - -import com.cloud.hypervisor.Hypervisor.HypervisorType; -import com.cloud.storage.Storage; -import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateVO; -import com.cloud.utils.db.GenericDao; -import com.cloud.utils.fsm.StateObject; - -@Entity -@Table(name = "vm_template") -public class ImageDataVO implements Identity, StateObject { - @Id - @TableGenerator(name = "vm_template_sq", table = "sequence", pkColumnName = "name", valueColumnName = "value", pkColumnValue = "vm_template_seq", allocationSize = 1) - @Column(name = "id", nullable = false) - private long id; - - @Column(name = "format") - private String format; - - @Column(name = "unique_name") - private String uniqueName; - - @Column(name = "name") - private String name = null; - - @Column(name = "public") - private boolean publicTemplate = true; - - @Column(name = "featured") - private boolean featured; - - @Column(name = "type") - private Storage.TemplateType templateType; - - @Column(name = "url") - private String url = null; - - @Column(name = "hvm") - private boolean requiresHvm; - - @Column(name = "bits") - private int bits; - - @Temporal(value = TemporalType.TIMESTAMP) - @Column(name = GenericDao.CREATED_COLUMN) - private Date created = null; - - @Column(name = GenericDao.REMOVED) - @Temporal(TemporalType.TIMESTAMP) - private Date removed; - - @Column(name = "account_id") - private long accountId; - - @Column(name = "checksum") - private String checksum; - - @Column(name = "display_text", length = 4096) - private String displayText; - - @Column(name = "enable_password") - private boolean enablePassword; - - @Column(name = "guest_os_id") - private long guestOSId; - - @Column(name = "bootable") - private boolean bootable = true; - - @Column(name = "prepopulate") - private boolean prepopulate = false; - - @Column(name = "cross_zones") - private boolean crossZones = false; - - @Column(name = "hypervisor_type") - @Enumerated(value = EnumType.STRING) - private HypervisorType hypervisorType; - - @Column(name = "extractable") - private boolean extractable = true; - - @Column(name = "source_template_id") - private Long sourceTemplateId; - - @Column(name = "template_tag") - private String templateTag; - - @Column(name = "uuid") - private String uuid; - - @Column(name = "sort_key") - private int sortKey; - - @Column(name = "enable_sshkey") - private boolean enableSshKey; - - @Column(name = "image_data_store_id") - private long imageDataStoreId; - - @Column(name = "size") - private Long size; - - @Column(name = "state") - private TemplateState state; - - @Column(name="update_count", updatable = true) - protected long updatedCount; - - @Column(name = "updated") - @Temporal(value = TemporalType.TIMESTAMP) - Date updated; - - @Transient - Map details; - - public String getUniqueName() { - return uniqueName; - } - - public void setUniqueName(String uniqueName) { - this.uniqueName = uniqueName; - } - - public ImageDataVO() { - this.uuid = UUID.randomUUID().toString(); - this.state = TemplateState.Allocated; - this.created = new Date(); - } - - public boolean getEnablePassword() { - return enablePassword; - } - - public String getFormat() { - return format; - } - - public void setEnablePassword(boolean enablePassword) { - this.enablePassword = enablePassword; - } - - public void setFormat(String format) { - this.format = format; - } - - public long getId() { - return id; - } - - public TemplateType getTemplateType() { - return templateType; - } - - public void setTemplateType(TemplateType type) { - this.templateType = type; - } - - public boolean requiresHvm() { - return requiresHvm; - } - - public void setRequireHvm(boolean hvm) { - this.requiresHvm = hvm; - } - - public int getBits() { - return bits; - } - - public void setBits(int bits) { - this.bits = bits; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Date getRemoved() { - return removed; - } - - public boolean isPublicTemplate() { - return publicTemplate; - } - - public void setPublicTemplate(boolean publicTemplate) { - this.publicTemplate = publicTemplate; - } - - public boolean isFeatured() { - return featured; - } - - public void setFeatured(boolean featured) { - this.featured = featured; - } - - public Date getCreated() { - return created; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } - - public long getAccountId() { - return accountId; - } - - public void setAccountId(long accountId) { - this.accountId = accountId; - } - - public String getChecksum() { - return checksum; - } - - public void setChecksum(String checksum) { - this.checksum = checksum; - } - - public String getDisplayText() { - return displayText; - } - - public void setDisplayText(String displayText) { - this.displayText = displayText; - } - - public long getGuestOSId() { - return guestOSId; - } - - public void setGuestOSId(long guestOSId) { - this.guestOSId = guestOSId; - } - - public boolean isBootable() { - return bootable; - } - - public void setBootable(boolean bootable) { - this.bootable = bootable; - } - - public void setPrepopulate(boolean prepopulate) { - this.prepopulate = prepopulate; - } - - public boolean isPrepopulate() { - return prepopulate; - } - - public void setCrossZones(boolean crossZones) { - this.crossZones = crossZones; - } - - public boolean isCrossZones() { - return crossZones; - } - - public HypervisorType getHypervisorType() { - return hypervisorType; - } - - public void setHypervisorType(HypervisorType hyperType) { - hypervisorType = hyperType; - } - - public boolean isExtractable() { - return extractable; - } - - public void setExtractable(boolean extractable) { - this.extractable = extractable; - } - - public Long getSourceTemplateId() { - return sourceTemplateId; - } - - public void setSourceTemplateId(Long sourceTemplateId) { - this.sourceTemplateId = sourceTemplateId; - } - - public String getTemplateTag() { - return templateTag; - } - - public void setTemplateTag(String templateTag) { - this.templateTag = templateTag; - } - - public long getDomainId() { - return -1; - } - - @Override - public String getUuid() { - return this.uuid; - } - - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public Map getDetails() { - return this.details; - } - - public void setDetails(Map details) { - this.details = details; - } - - @Override - public boolean equals(Object that) { - if (this == that) { - return true; - } - if (!(that instanceof VMTemplateVO)) { - return false; - } - VMTemplateVO other = (VMTemplateVO) that; - - return ((this.getUniqueName().equals(other.getUniqueName()))); - } - - @Override - public int hashCode() { - return uniqueName.hashCode(); - } - - @Transient - String toString; - - @Override - public String toString() { - if (toString == null) { - toString = new StringBuilder("Tmpl[").append(id).append("-").append(format).append("-").append(uniqueName).toString(); - } - return toString; - } - - public void setRemoved(Date removed) { - this.removed = removed; - } - - public void setSortKey(int key) { - sortKey = key; - } - - public int getSortKey() { - return sortKey; - } - - public boolean getEnableSshKey() { - return enableSshKey; - } - - public void setEnableSshKey(boolean enable) { - enableSshKey = enable; - } - - public Long getImageDataStoreId() { - return this.imageDataStoreId; - } - - public void setImageDataStoreId(long dataStoreId) { - this.imageDataStoreId = dataStoreId; - } - - public void setSize(Long size) { - this.size = size; - } - - public Long getSize() { - return this.size; - } - - public TemplateState getState() { - return this.state; - } - - public long getUpdatedCount() { - return this.updatedCount; - } - - public void incrUpdatedCount() { - this.updatedCount++; - } - - public void decrUpdatedCount() { - this.updatedCount--; - } - - public Date getUpdated() { - return updated; - } - - public void setUpdated(Date updated) { - this.updated = updated; - } - -} diff --git a/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java b/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java index 422bc066211..908d6d52c20 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java +++ b/engine/storage/src/org/apache/cloudstack/storage/image/motion/ImageMotionService.java @@ -19,9 +19,9 @@ package org.apache.cloudstack.storage.image.motion; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.volume.TemplateOnPrimaryDataStoreInfo; public interface ImageMotionService { diff --git a/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java new file mode 100644 index 00000000000..d686336a7d7 --- /dev/null +++ b/engine/storage/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java @@ -0,0 +1,581 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.motion; + +import java.util.Date; +import java.util.List; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; +import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; +import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer; +import com.cloud.agent.api.CreateVolumeFromSnapshotCommand; +import com.cloud.agent.api.UpgradeSnapshotCommand; +import com.cloud.agent.api.storage.CopyVolumeAnswer; +import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.CreateAnswer; +import com.cloud.agent.api.storage.CreateCommand; +import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.configuration.Config; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.template.TemplateManager; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.DiskProfile; + +@Component +public class AncientDataMotionStrategy implements DataMotionStrategy { + private static final Logger s_logger = Logger + .getLogger(AncientDataMotionStrategy.class); + @Inject + TemplateManager templateMgr; + @Inject + VolumeHostDao volumeHostDao; + @Inject + HostDao hostDao; + @Inject + ConfigurationDao configDao; + @Inject + StorageManager storagMgr; + @Inject + VolumeDao volDao; + @Inject + VMTemplateDao templateDao; + @Inject + SnapshotManager snapshotMgr; + @Inject + SnapshotDao snapshotDao; + @Inject + PrimaryDataStoreDao primaryDataStoreDao; + @Inject + DataStoreManager dataStoreMgr; + @Inject + VMTemplateHostDao templateHostDao; + @Inject DiskOfferingDao diskOfferingDao; + @Inject VMTemplatePoolDao templatePoolDao; + @Inject + VolumeManager volumeMgr; + + @Override + public boolean canHandle(DataObject srcData, DataObject destData) { + // TODO Auto-generated method stub + return true; + } + + @DB + protected String copyVolumeFromImage(DataObject srcData, DataObject destData) { + String value = configDao.getValue(Config.RecreateSystemVmEnabled.key()); + int _copyvolumewait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); + + VolumeHostVO volumeHostVO = volumeHostDao.findByVolumeId(srcData + .getId()); + HostVO secStorage = hostDao.findById(volumeHostVO.getHostId()); + String secondaryStorageURL = secStorage.getStorageUrl(); + String[] volumePath = volumeHostVO.getInstallPath().split("/"); + String volumeUUID = volumePath[volumePath.length - 1].split("\\.")[0]; + StoragePool destPool = (StoragePool) destData.getDataStore(); + CopyVolumeCommand cvCmd = new CopyVolumeCommand(srcData.getId(), + volumeUUID, destPool, secondaryStorageURL, false, + _copyvolumewait); + CopyVolumeAnswer cvAnswer = null; + String errMsg = null; + try { + cvAnswer = (CopyVolumeAnswer) this.storagMgr.sendToPool(destPool, + cvCmd); + } catch (StorageUnavailableException e1) { + s_logger.debug("Failed to copy volume " + srcData.getId() + " to " + + destData.getId(), e1); + errMsg = e1.toString(); + } + + if (cvAnswer == null || !cvAnswer.getResult()) { + errMsg = cvAnswer.getDetails(); + } + + VolumeVO vol = this.volDao.findById(destData.getId()); + Transaction txn = Transaction.currentTxn(); + txn.start(); + vol.setPath(cvAnswer.getVolumePath()); + vol.setFolder(destPool.getPath()); + vol.setPodId(destPool.getPodId()); + vol.setPoolId(destPool.getId()); + vol.setPodId(destPool.getPodId()); + + this.volDao.update(vol.getId(), vol); + volumeHostDao.remove(volumeHostVO.getId()); + txn.commit(); + return errMsg; + } + + private void copyTemplate(DataObject srcData, DataObject destData) { + VMTemplateVO template = this.templateDao.findById(srcData.getId()); + templateMgr.prepareTemplateForCreate(template, + (StoragePool) destData.getDataStore()); + } + + protected String copyFromSnapshot(DataObject snapObj, DataObject volObj) { + SnapshotVO snapshot = this.snapshotDao.findById(snapObj.getId()); + StoragePool pool = (StoragePool) volObj.getDataStore(); + String vdiUUID = null; + Long snapshotId = snapshot.getId(); + Long volumeId = snapshot.getVolumeId(); + Long dcId = snapshot.getDataCenterId(); + String secondaryStoragePoolUrl = this.snapshotMgr + .getSecondaryStorageURL(snapshot); + long accountId = snapshot.getAccountId(); + + String backedUpSnapshotUuid = snapshot.getBackupSnapshotId(); + snapshot = snapshotDao.findById(snapshotId); + if (snapshot.getVersion().trim().equals("2.1")) { + VolumeVO volume = this.volDao.findByIdIncludingRemoved(volumeId); + if (volume == null) { + throw new CloudRuntimeException("failed to upgrade snapshot " + + snapshotId + " due to unable to find orignal volume:" + + volumeId + ", try it later "); + } + if (volume.getTemplateId() == null) { + snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); + } else { + VMTemplateVO template = templateDao + .findByIdIncludingRemoved(volume.getTemplateId()); + if (template == null) { + throw new CloudRuntimeException( + "failed to upgrade snapshot " + + snapshotId + + " due to unalbe to find orignal template :" + + volume.getTemplateId() + + ", try it later "); + } + Long templateId = template.getId(); + Long tmpltAccountId = template.getAccountId(); + if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { + throw new CloudRuntimeException( + "failed to upgrade snapshot " + + snapshotId + + " due to this snapshot is being used, try it later "); + } + UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null, + secondaryStoragePoolUrl, dcId, accountId, volumeId, + templateId, tmpltAccountId, null, + snapshot.getBackupSnapshotId(), snapshot.getName(), + "2.1"); + Answer answer = null; + try { + answer = this.storagMgr.sendToPool(pool, cmd); + } catch (StorageUnavailableException e) { + } finally { + snapshotDao.unlockFromLockTable(snapshotId.toString()); + } + if ((answer != null) && answer.getResult()) { + snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); + } else { + return "Unable to upgrade snapshot from 2.1 to 2.2 for " + + snapshot.getId(); + } + } + } + String basicErrMsg = "Failed to create volume from " + + snapshot.getName() + " on pool " + pool; + + try { + if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) { + snapshotMgr.downloadSnapshotsFromSwift(snapshot); + } else if (snapshot.getS3Id() != null && snapshot.getS3Id() != 0) { + snapshotMgr.downloadSnapshotsFromS3(snapshot); + } + String value = configDao + .getValue(Config.CreateVolumeFromSnapshotWait.toString()); + int _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CreateVolumeFromSnapshotWait + .getDefaultValue())); + CreateVolumeFromSnapshotCommand createVolumeFromSnapshotCommand = new CreateVolumeFromSnapshotCommand( + pool, secondaryStoragePoolUrl, dcId, accountId, volumeId, + backedUpSnapshotUuid, snapshot.getName(), + _createVolumeFromSnapshotWait); + CreateVolumeFromSnapshotAnswer answer; + if (!snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { + throw new CloudRuntimeException("failed to create volume from " + + snapshotId + + " due to this snapshot is being used, try it later "); + } + answer = (CreateVolumeFromSnapshotAnswer) this.storagMgr + .sendToPool(pool, createVolumeFromSnapshotCommand); + if (answer != null && answer.getResult()) { + vdiUUID = answer.getVdi(); + VolumeVO vol = this.volDao.findById(volObj.getId()); + vol.setPath(vdiUUID); + this.volDao.update(vol.getId(), vol); + return null; + } else { + s_logger.error(basicErrMsg + " due to " + + ((answer == null) ? "null" : answer.getDetails())); + throw new CloudRuntimeException(basicErrMsg); + } + } catch (StorageUnavailableException e) { + s_logger.error(basicErrMsg, e); + throw new CloudRuntimeException(basicErrMsg); + } finally { + if (snapshot.getSwiftId() != null) { + snapshotMgr.deleteSnapshotsDirForVolume( + secondaryStoragePoolUrl, dcId, accountId, volumeId); + } + snapshotDao.unlockFromLockTable(snapshotId.toString()); + } + } + + protected String cloneVolume(DataObject template, DataObject volume) { + + DiskOfferingVO offering = diskOfferingDao.findById(volume.getId()); + VMTemplateStoragePoolVO tmpltStoredOn = templatePoolDao.findByPoolTemplate(template.getDataStore().getId(), template.getId()); + VolumeInfo volInfo = (VolumeInfo)volume; + DiskProfile diskProfile = new DiskProfile(volInfo, offering, + null); + CreateCommand cmd = new CreateCommand(diskProfile, + tmpltStoredOn.getLocalDownloadPath(), + new StorageFilerTO((StoragePool)template.getDataStore())); + Answer answer = null; + StoragePool pool = (StoragePool)volume.getDataStore(); + String errMsg = null; + try { + answer = storagMgr.sendToPool(pool, null, cmd); + } catch (StorageUnavailableException e) { + s_logger.debug("Failed to send to storage pool", e); + errMsg = e.toString(); + return errMsg; + } + + if (answer.getResult()) { + VolumeVO vol = this.volDao.findById(volume.getId()); + CreateAnswer createAnswer = (CreateAnswer) answer; + vol.setFolder(pool.getPath()); + vol.setPath(createAnswer.getVolume().getPath()); + vol.setSize(createAnswer.getVolume().getSize()); + vol.setPoolType(pool.getPoolType()); + vol.setPoolId(pool.getId()); + vol.setPodId(pool.getPodId()); + this.volDao.update(vol.getId(), vol); + + } else { + if (tmpltStoredOn != null + && (answer instanceof CreateAnswer) + && ((CreateAnswer) answer) + .templateReloadRequested()) { + if (!templateMgr + .resetTemplateDownloadStateOnPool(tmpltStoredOn + .getId())) { + + } + } + errMsg = answer.getDetails(); + } + + return errMsg; + } + + @Override + public Void copyAsync(DataObject srcData, DataObject destData, + AsyncCompletionCallback callback) { + String errMsg = null; + try { + if (destData.getType() == DataObjectType.VOLUME + && srcData.getType() == DataObjectType.VOLUME) { + errMsg = copyVolumeFromImage(srcData, destData); + } else if (destData.getType() == DataObjectType.TEMPLATE + && srcData.getType() == DataObjectType.TEMPLATE) { + copyTemplate(srcData, destData); + } else if (srcData.getType() == DataObjectType.SNAPSHOT + && destData.getType() == DataObjectType.VOLUME) { + errMsg = copyFromSnapshot(srcData, destData); + } else if (srcData.getType() == DataObjectType.SNAPSHOT + && destData.getType() == DataObjectType.TEMPLATE) { + errMsg = createTemplateFromSnashot(srcData, destData); + } else if (srcData.getType() == DataObjectType.VOLUME + && destData.getType() == DataObjectType.TEMPLATE) { + errMsg = createTemplateFromVolume(srcData, destData); + } else if (srcData.getType() == DataObjectType.TEMPLATE + && destData.getType() == DataObjectType.VOLUME) { + errMsg = cloneVolume(srcData, destData); + } + } catch (Exception e) { + s_logger.debug("copy failed", e); + errMsg = e.toString(); + } + CopyCommandResult result = new CopyCommandResult(null); + result.setResult(errMsg); + callback.complete(result); + + return null; + } + + @DB + protected String createTemplateFromSnashot(DataObject srcData, + DataObject destData) { + long snapshotId = srcData.getId(); + SnapshotVO snapshot = snapshotDao.findById(snapshotId); + if (snapshot == null) { + throw new CloudRuntimeException("Unable to find Snapshot for Id " + + srcData.getId()); + } + Long zoneId = snapshot.getDataCenterId(); + HostVO secondaryStorageHost = this.templateMgr + .getSecondaryStorageHost(zoneId); + String secondaryStorageURL = snapshotMgr + .getSecondaryStorageURL(snapshot); + VMTemplateVO template = this.templateDao.findById(destData.getId()); + String name = template.getName(); + String backupSnapshotUUID = snapshot.getBackupSnapshotId(); + if (backupSnapshotUUID == null) { + throw new CloudRuntimeException( + "Unable to create private template from snapshot " + + snapshotId + + " due to there is no backupSnapshotUUID for this snapshot"); + } + + Long dcId = snapshot.getDataCenterId(); + Long accountId = snapshot.getAccountId(); + Long volumeId = snapshot.getVolumeId(); + + String origTemplateInstallPath = null; + List pools = this.storagMgr + .ListByDataCenterHypervisor(zoneId, + snapshot.getHypervisorType()); + if (pools == null || pools.size() == 0) { + throw new CloudRuntimeException( + "Unable to find storage pools in zone " + zoneId); + } + StoragePoolVO poolvo = pools.get(0); + StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore( + poolvo.getId(), DataStoreRole.Primary); + if (snapshot.getVersion() != null + && snapshot.getVersion().equalsIgnoreCase("2.1")) { + VolumeVO volume = this.volDao.findByIdIncludingRemoved(volumeId); + if (volume == null) { + throw new CloudRuntimeException("failed to upgrade snapshot " + + snapshotId + " due to unable to find orignal volume:" + + volumeId + ", try it later "); + } + if (volume.getTemplateId() == null) { + snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); + } else { + template = templateDao.findByIdIncludingRemoved(volume + .getTemplateId()); + if (template == null) { + throw new CloudRuntimeException( + "failed to upgrade snapshot " + + snapshotId + + " due to unalbe to find orignal template :" + + volume.getTemplateId() + + ", try it later "); + } + Long origTemplateId = template.getId(); + Long origTmpltAccountId = template.getAccountId(); + if (!this.volDao.lockInLockTable(volumeId.toString(), 10)) { + throw new CloudRuntimeException( + "failed to upgrade snapshot " + snapshotId + + " due to volume:" + volumeId + + " is being used, try it later "); + } + UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null, + secondaryStorageURL, dcId, accountId, volumeId, + origTemplateId, origTmpltAccountId, null, + snapshot.getBackupSnapshotId(), snapshot.getName(), + "2.1"); + if (!this.volDao.lockInLockTable(volumeId.toString(), 10)) { + throw new CloudRuntimeException( + "Creating template failed due to volume:" + + volumeId + + " is being used, try it later "); + } + Answer answer = null; + try { + answer = this.storagMgr.sendToPool(pool, cmd); + cmd = null; + } catch (StorageUnavailableException e) { + } finally { + this.volDao.unlockFromLockTable(volumeId.toString()); + } + if ((answer != null) && answer.getResult()) { + snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); + } else { + throw new CloudRuntimeException( + "Unable to upgrade snapshot"); + } + } + } + if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) { + snapshotMgr.downloadSnapshotsFromSwift(snapshot); + } + String value = configDao + .getValue(Config.CreatePrivateTemplateFromSnapshotWait + .toString()); + int _createprivatetemplatefromsnapshotwait = NumbersUtil.parseInt( + value, Integer + .parseInt(Config.CreatePrivateTemplateFromSnapshotWait + .getDefaultValue())); + + CreatePrivateTemplateFromSnapshotCommand cmd = new CreatePrivateTemplateFromSnapshotCommand( + pool, secondaryStorageURL, dcId, accountId, + snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(), + origTemplateInstallPath, template.getId(), name, + _createprivatetemplatefromsnapshotwait); + + return sendCommand(cmd, pool, template.getId(), dcId, + secondaryStorageHost.getId()); + } + + @DB + protected String sendCommand(Command cmd, StoragePool pool, + long templateId, long zoneId, long hostId) { + + CreatePrivateTemplateAnswer answer = null; + try { + answer = (CreatePrivateTemplateAnswer) this.storagMgr.sendToPool( + pool, cmd); + } catch (StorageUnavailableException e) { + throw new CloudRuntimeException( + "Failed to execute CreatePrivateTemplateFromSnapshotCommand", + e); + } + + if (answer == null) { + return "Failed to execute CreatePrivateTemplateFromSnapshotCommand"; + } else if (!answer.getResult()) { + return "Failed to execute CreatePrivateTemplateFromSnapshotCommand" + + answer.getDetails(); + } + + VMTemplateVO privateTemplate = templateDao.findById(templateId); + String answerUniqueName = answer.getUniqueName(); + if (answerUniqueName != null) { + privateTemplate.setUniqueName(answerUniqueName); + } + ImageFormat format = answer.getImageFormat(); + if (format != null) { + privateTemplate.setFormat(format); + } else { + // This never occurs. + // Specify RAW format makes it unusable for snapshots. + privateTemplate.setFormat(ImageFormat.RAW); + } + + String checkSum = this.templateMgr + .getChecksum(hostId, answer.getPath()); + + Transaction txn = Transaction.currentTxn(); + + txn.start(); + + privateTemplate.setChecksum(checkSum); + templateDao.update(privateTemplate.getId(), privateTemplate); + + // add template zone ref for this template + templateDao.addTemplateToZone(privateTemplate, zoneId); + VMTemplateHostVO templateHostVO = new VMTemplateHostVO(hostId, + privateTemplate.getId()); + templateHostVO.setDownloadPercent(100); + templateHostVO.setDownloadState(Status.DOWNLOADED); + templateHostVO.setInstallPath(answer.getPath()); + templateHostVO.setLastUpdated(new Date()); + templateHostVO.setSize(answer.getVirtualSize()); + templateHostVO.setPhysicalSize(answer.getphysicalSize()); + templateHostDao.persist(templateHostVO); + txn.close(); + return null; + } + + private String createTemplateFromVolume(DataObject srcObj, + DataObject destObj) { + long volumeId = srcObj.getId(); + VolumeVO volume = this.volDao.findById(volumeId); + if (volume == null) { + throw new CloudRuntimeException("Unable to find volume for Id " + + volumeId); + } + long accountId = volume.getAccountId(); + + String vmName = this.volumeMgr.getVmNameOnVolume(volume); + Long zoneId = volume.getDataCenterId(); + HostVO secondaryStorageHost = this.templateMgr + .getSecondaryStorageHost(zoneId); + if (secondaryStorageHost == null) { + throw new CloudRuntimeException( + "Can not find the secondary storage for zoneId " + zoneId); + } + String secondaryStorageURL = secondaryStorageHost.getStorageUrl(); + VMTemplateVO template = this.templateDao.findById(destObj.getId()); + StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore( + volume.getPoolId(), DataStoreRole.Primary); + String value = configDao + .getValue(Config.CreatePrivateTemplateFromVolumeWait.toString()); + int _createprivatetemplatefromvolumewait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CreatePrivateTemplateFromVolumeWait + .getDefaultValue())); + + CreatePrivateTemplateFromVolumeCommand cmd = new CreatePrivateTemplateFromVolumeCommand( + pool, secondaryStorageURL, destObj.getId(), accountId, + template.getName(), template.getUniqueName(), volume.getPath(), + vmName, _createprivatetemplatefromvolumewait); + + return sendCommand(cmd, pool, template.getId(), zoneId, + secondaryStorageHost.getId()); + } + +} diff --git a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotService.java b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotService.java index d50c9a0c8f3..f3e5c4aea50 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotService.java +++ b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotService.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.storage.snapshot; import org.apache.cloudstack.engine.cloud.entity.api.SnapshotEntity; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; public interface SnapshotService { public SnapshotEntity getSnapshotEntity(long snapshotId); diff --git a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategy.java b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategy.java index 4e311862e50..8c4c815eb7d 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategy.java +++ b/engine/storage/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategy.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.storage.snapshot; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; + public interface SnapshotStrategy { public boolean takeSnapshot(SnapshotInfo snapshot); public boolean revertSnapshot(SnapshotInfo snapshot); diff --git a/engine/storage/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/engine/storage/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java index cd67b97b02c..aa47e8f4977 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java @@ -21,12 +21,12 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; public class PrimaryDataStoreTO { private final String uuid; private final String name; - private final String type; + private String type; private final long id; public PrimaryDataStoreTO(PrimaryDataStoreInfo dataStore) { this.uuid = dataStore.getUuid(); this.name = dataStore.getName(); - this.type = dataStore.getType(); + // this.type = dataStore.getType(); this.id = dataStore.getId(); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/to/TemplateTO.java b/engine/storage/src/org/apache/cloudstack/storage/to/TemplateTO.java index ed5990986e5..bc55ea8c3ea 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/to/TemplateTO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/to/TemplateTO.java @@ -16,8 +16,8 @@ // under the License. package org.apache.cloudstack.storage.to; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.image.datastore.ImageDataStoreInfo; public class TemplateTO { diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/PrimaryDataStoreDriver.java b/engine/storage/src/org/apache/cloudstack/storage/volume/PrimaryDataStoreDriver.java index 60db60b2364..2b49eee4b86 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/PrimaryDataStoreDriver.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/PrimaryDataStoreDriver.java @@ -20,8 +20,8 @@ package org.apache.cloudstack.storage.volume; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; public interface PrimaryDataStoreDriver extends DataStoreDriver { public void takeSnapshot(SnapshotInfo snapshot, AsyncCompletionCallback callback); diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/TemplateOnPrimaryDataStoreInfo.java b/engine/storage/src/org/apache/cloudstack/storage/volume/TemplateOnPrimaryDataStoreInfo.java index 368c33a32bf..b8d0857d495 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/TemplateOnPrimaryDataStoreInfo.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/TemplateOnPrimaryDataStoreInfo.java @@ -18,8 +18,8 @@ */ package org.apache.cloudstack.storage.volume; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; -import org.apache.cloudstack.storage.image.TemplateInfo; public interface TemplateOnPrimaryDataStoreInfo { public String getPath(); diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java index 20ceaa303fc..c6ca90d1641 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java @@ -23,40 +23,38 @@ import java.util.Map; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; -import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; -import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.utils.exception.CloudRuntimeException; @Component public class PrimaryDataStoreHelper { @Inject private PrimaryDataStoreDao dataStoreDao; - public PrimaryDataStoreVO createPrimaryDataStore(Map params) { - PrimaryDataStoreVO dataStoreVO = dataStoreDao.findPoolByUUID(params.get("uuid")); + public StoragePoolVO createPrimaryDataStore(Map params) { + StoragePoolVO dataStoreVO = dataStoreDao.findPoolByUUID((String)params.get("uuid")); if (dataStoreVO != null) { throw new CloudRuntimeException("duplicate uuid: " + params.get("uuid")); } - dataStoreVO = new PrimaryDataStoreVO(); - dataStoreVO.setStorageProviderId(Long.parseLong(params.get("providerId"))); - dataStoreVO.setHostAddress(params.get("server")); - dataStoreVO.setPath(params.get("path")); - dataStoreVO.setPoolType(params.get("protocol")); - dataStoreVO.setPort(Integer.parseInt(params.get("port"))); - dataStoreVO.setName(params.get("name")); - dataStoreVO.setUuid(params.get("uuid")); + dataStoreVO = new StoragePoolVO(); + dataStoreVO.setStorageProviderId(Long.parseLong((String)params.get("providerId"))); + dataStoreVO.setHostAddress((String)params.get("server")); + dataStoreVO.setPath((String)params.get("path")); + dataStoreVO.setPoolType((StoragePoolType)params.get("protocol")); + dataStoreVO.setPort(Integer.parseInt((String)params.get("port"))); + dataStoreVO.setName((String)params.get("name")); + dataStoreVO.setUuid((String)params.get("uuid")); dataStoreVO = dataStoreDao.persist(dataStoreVO); return dataStoreVO; } public boolean deletePrimaryDataStore(long id) { - PrimaryDataStoreVO dataStoreVO = dataStoreDao.findById(id); + StoragePoolVO dataStoreVO = dataStoreDao.findById(id); if (dataStoreVO == null) { throw new CloudRuntimeException("can't find store: " + id); } diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDao.java b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDao.java index 45ff1ec2258..63cdb16c596 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDao.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDao.java @@ -18,7 +18,7 @@ */ package org.apache.cloudstack.storage.volume.db; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import com.cloud.utils.db.GenericDao; import com.cloud.utils.fsm.StateDao; diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDaoImpl.java b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDaoImpl.java index b47f08881e1..ad561502266 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDaoImpl.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreDaoImpl.java @@ -20,9 +20,9 @@ package org.apache.cloudstack.storage.volume.db; import java.util.Date; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.Event; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine.State; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; diff --git a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreVO.java b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreVO.java index 2d355df7e2a..48a9f334a19 100644 --- a/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreVO.java +++ b/engine/storage/src/org/apache/cloudstack/storage/volume/db/TemplatePrimaryDataStoreVO.java @@ -32,7 +32,9 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import org.apache.cloudstack.storage.volume.ObjectInDataStoreStateMachine; + +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.fsm.StateObject; diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java index 9c009c95623..72c1843da42 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/DefaultPrimaryDataStore.java @@ -18,45 +18,50 @@ package org.apache.cloudstack.storage.datastore; import java.io.File; import java.util.ArrayList; +import java.util.Date; import java.util.List; import javax.inject.Inject; -import org.apache.cloudstack.engine.datacenter.entity.api.DataCenterResourceEntity.State; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; import org.apache.cloudstack.engine.subsystem.api.storage.Scope; import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProvider; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.ImageDataFactory; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.snapshot.SnapshotDataFactory; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; import org.apache.cloudstack.storage.volume.VolumeObject; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.apache.log4j.Logger; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.component.ComponentContext; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.storage.encoding.EncodingType; public class DefaultPrimaryDataStore implements PrimaryDataStore { private static final Logger s_logger = Logger .getLogger(DefaultPrimaryDataStore.class); protected PrimaryDataStoreDriver driver; - protected PrimaryDataStoreVO pdsv; + protected StoragePoolVO pdsv; @Inject protected PrimaryDataStoreDao dataStoreDao; protected PrimaryDataStoreLifeCycle lifeCycle; @@ -67,15 +72,16 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Inject SnapshotDataFactory snapshotFactory; protected DataStoreProvider provider; - @Inject - private VolumeDao2 volumeDao; + VMTemplatePoolDao templatePoolDao; + + private VolumeDao volumeDao; protected DefaultPrimaryDataStore() { } - public void configure(PrimaryDataStoreVO pdsv, + public void configure(StoragePoolVO pdsv, PrimaryDataStoreDriver driver, DataStoreProvider provider) { this.pdsv = pdsv; this.driver = driver; @@ -83,7 +89,7 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { } public static DefaultPrimaryDataStore createDataStore( - PrimaryDataStoreVO pdsv, PrimaryDataStoreDriver driver, + StoragePoolVO pdsv, PrimaryDataStoreDriver driver, DataStoreProvider provider) { DefaultPrimaryDataStore dataStore = (DefaultPrimaryDataStore)ComponentContext.inject(DefaultPrimaryDataStore.class); dataStore.configure(pdsv, driver, provider); @@ -109,19 +115,16 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Override public DataStoreDriver getDriver() { - // TODO Auto-generated method stub return this.driver; } @Override public DataStoreRole getRole() { - // TODO Auto-generated method stub return DataStoreRole.Primary; } @Override public long getId() { - // TODO Auto-generated method stub return this.pdsv.getId(); } @@ -143,7 +146,7 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Override public Scope getScope() { - PrimaryDataStoreVO vo = dataStoreDao.findById(this.pdsv.getId()); + StoragePoolVO vo = dataStoreDao.findById(this.pdsv.getId()); if (vo.getScope() == ScopeType.CLUSTER) { return new ClusterScope(vo.getClusterId(), vo.getPodId(), vo.getDataCenterId()); @@ -156,7 +159,7 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Override public boolean isHypervisorSupported(HypervisorType hypervisor) { // TODO Auto-generated method stub - return false; + return true; } @Override @@ -171,28 +174,10 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { return false; } - @Override - public long getCapacity() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public long getAvailableCapacity() { - // TODO Auto-generated method stub - return 0; - } @Override public String getUuid() { - // TODO Auto-generated method stub - return null; - } - - @Override - public State getManagedState() { - // TODO Auto-generated method stub - return null; + return this.pdsv.getUuid(); } @Override @@ -201,12 +186,6 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { return null; } - @Override - public String getType() { - // TODO Auto-generated method stub - return null; - } - @Override public PrimaryDataStoreLifeCycle getLifeCycle() { return this.lifeCycle; @@ -214,14 +193,13 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { @Override public boolean exists(DataObject data) { - return (objectInStoreMgr.findObject(data.getId(), data.getType(), - this.getId(), this.getRole()) != null) ? true : false; + return (objectInStoreMgr.findObject(data, data.getDataStore()) != null) ? true : false; } @Override public TemplateInfo getTemplate(long templateId) { - ObjectInDataStoreVO obj = objectInStoreMgr.findObject(templateId, DataObjectType.TEMPLATE, this.getId(), this.getRole()); - if (obj == null) { + VMTemplateStoragePoolVO template = templatePoolDao.findByPoolTemplate(this.getId(), templateId); + if (template == null || template.getState() != ObjectInDataStoreStateMachine.State.Ready) { return null; } return imageDataFactory.getTemplate(templateId, this); @@ -238,4 +216,117 @@ public class DefaultPrimaryDataStore implements PrimaryDataStore { // TODO Auto-generated method stub return null; } + + @Override + public DataObject create(DataObject obj) { + //create template on primary storage + if (obj.getType() == DataObjectType.TEMPLATE) { + VMTemplateStoragePoolVO templateStoragePoolRef = templatePoolDao.findByPoolTemplate(this.getId(), obj.getId()); + if (templateStoragePoolRef == null) { + try { + templateStoragePoolRef = new VMTemplateStoragePoolVO(this.getId(), obj.getId()); + templateStoragePoolRef = templatePoolDao.persist(templateStoragePoolRef); + } catch (Throwable t) { + templateStoragePoolRef = templatePoolDao.findByPoolTemplate(this.getId(), obj.getId()); + if (templateStoragePoolRef == null) { + throw new CloudRuntimeException("Failed to create template storage pool entry"); + } + } + } + + } + + return objectInStoreMgr.get(obj, this); + } + + @Override + public boolean delete(DataObject obj) { + // TODO Auto-generated method stub + return false; + } + + @Override + public long getDataCenterId() { + return this.pdsv.getDataCenterId(); + } + + @Override + public String getPath() { + return this.pdsv.getPath(); + } + + @Override + public StoragePoolType getPoolType() { + return this.pdsv.getPoolType(); + } + + @Override + public Date getCreated() { + return this.pdsv.getCreated(); + } + + @Override + public Date getUpdateTime() { + return this.pdsv.getUpdateTime(); + } + + @Override + public long getCapacityBytes() { + return this.pdsv.getCapacityBytes(); + } + + @Override + public long getAvailableBytes() { + return this.pdsv.getAvailableBytes(); + } + + @Override + public Long getClusterId() { + return this.pdsv.getClusterId(); + } + + @Override + public String getHostAddress() { + return this.pdsv.getHostAddress(); + } + + @Override + public String getUserInfo() { + return this.pdsv.getUserInfo(); + } + + @Override + public boolean isShared() { + return this.pdsv.getScope() == ScopeType.HOST ? false : true; + } + + @Override + public boolean isLocal() { + return !this.isShared(); + } + + @Override + public StoragePoolStatus getStatus() { + return this.pdsv.getStatus(); + } + + @Override + public int getPort() { + return this.pdsv.getPort(); + } + + @Override + public Long getPodId() { + return this.pdsv.getPodId(); + } + + @Override + public Long getStorageProviderId() { + return this.pdsv.getStorageProviderId(); + } + + @Override + public boolean isInMaintenance() { + return this.getStatus() == StoragePoolStatus.Maintenance ? true : false; + } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/AncientPrimaryDataStoreDriverImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/AncientPrimaryDataStoreDriverImpl.java new file mode 100644 index 00000000000..9946fba5f63 --- /dev/null +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/AncientPrimaryDataStoreDriverImpl.java @@ -0,0 +1,289 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.datastore.driver; + +import java.util.Set; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.framework.async.AsyncCompletionCallback; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; +import org.apache.log4j.Logger; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.storage.CreateAnswer; +import com.cloud.agent.api.storage.CreateCommand; +import com.cloud.agent.api.storage.DestroyCommand; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.Storage; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.template.TemplateManager; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.dao.VMInstanceDao; + +public class AncientPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver { + private static final Logger s_logger = Logger + .getLogger(AncientPrimaryDataStoreDriverImpl.class); + @Inject DiskOfferingDao diskOfferingDao; + @Inject VMTemplateDao templateDao; + @Inject VolumeDao volumeDao; + @Inject TemplateManager templateMgr; + @Inject HostDao hostDao; + @Inject StorageManager storageMgr; + @Inject VMInstanceDao vmDao; + @Inject PrimaryDataStoreDao primaryStoreDao; + @Override + public String grantAccess(DataObject data, EndPoint ep) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean revokeAccess(DataObject data, EndPoint ep) { + // TODO Auto-generated method stub + return false; + } + + @Override + public Set listObjects(DataStore store) { + // TODO Auto-generated method stub + return null; + } + + public boolean createVolume( + VolumeInfo volume) throws StorageUnavailableException { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Creating volume: " + volume); + } + + DiskOfferingVO offering = diskOfferingDao.findById(volume.getDiskOfferingId()); + DiskProfile diskProfile = new DiskProfile(volume, offering, + null); + + VMTemplateVO template = null; + if (volume.getTemplateId() != null) { + template = templateDao.findById(volume.getTemplateId()); + } + + StoragePool pool = (StoragePool)volume.getDataStore(); + VolumeVO vol = volumeDao.findById(volume.getId()); + if (pool != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Trying to create in " + pool); + } + vol.setPoolId(pool.getId()); + + CreateCommand cmd = null; + VMTemplateStoragePoolVO tmpltStoredOn = null; + + for (int i = 0; i < 2; i++) { + if (template != null + && template.getFormat() != Storage.ImageFormat.ISO) { + if (pool.getPoolType() == StoragePoolType.CLVM) { + // prepareISOForCreate does what we need, which is to + // tell us where the template is + VMTemplateHostVO tmpltHostOn = templateMgr + .prepareISOForCreate(template, pool); + if (tmpltHostOn == null) { + s_logger.debug("cannot find template " + + template.getId() + " " + + template.getName()); + throw new CloudRuntimeException("cannot find template" + + template.getId() + + template.getName()); + } + HostVO secondaryStorageHost = hostDao + .findById(tmpltHostOn.getHostId()); + String tmpltHostUrl = secondaryStorageHost + .getStorageUrl(); + String fullTmpltUrl = tmpltHostUrl + "/" + + tmpltHostOn.getInstallPath(); + cmd = new CreateCommand(diskProfile, fullTmpltUrl, + new StorageFilerTO(pool)); + } else { + tmpltStoredOn = templateMgr.prepareTemplateForCreate( + template, pool); + if (tmpltStoredOn == null) { + s_logger.debug("Cannot use this pool " + pool + + " because we can't propagate template " + + template); + throw new CloudRuntimeException("Cannot use this pool " + pool + + " because we can't propagate template " + + template); + } + cmd = new CreateCommand(diskProfile, + tmpltStoredOn.getLocalDownloadPath(), + new StorageFilerTO(pool)); + } + } else { + if (template != null + && Storage.ImageFormat.ISO == template.getFormat()) { + VMTemplateHostVO tmpltHostOn = templateMgr + .prepareISOForCreate(template, pool); + if (tmpltHostOn == null) { + throw new CloudRuntimeException( + "Did not find ISO in secondry storage in zone " + + pool.getDataCenterId()); + } + } + cmd = new CreateCommand(diskProfile, new StorageFilerTO( + pool)); + } + + Answer answer = storageMgr.sendToPool(pool, null, cmd); + if (answer.getResult()) { + CreateAnswer createAnswer = (CreateAnswer) answer; + vol.setFolder(pool.getPath()); + vol.setPath(createAnswer.getVolume().getPath()); + vol.setSize(createAnswer.getVolume().getSize()); + vol.setPoolType(pool.getPoolType()); + vol.setPoolId(pool.getId()); + vol.setPodId(pool.getPodId()); + this.volumeDao.update(vol.getId(), vol); + return true; + } else { + if (tmpltStoredOn != null + && (answer instanceof CreateAnswer) + && ((CreateAnswer) answer) + .templateReloadRequested()) { + if (!templateMgr + .resetTemplateDownloadStateOnPool(tmpltStoredOn + .getId())) { + break; // break out of template-redeploy retry loop + } + } else { + break; + } + } + } + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Unable to create volume " + volume.getId()); + } + return false; + } + + @Override + public void createAsync(DataObject data, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + String errMsg = null; + if (data.getType() == DataObjectType.VOLUME) { + try { + createVolume((VolumeInfo)data); + } catch (StorageUnavailableException e) { + s_logger.debug("failed to create volume", e); + errMsg = e.toString(); + } catch (Exception e) { + s_logger.debug("failed to create volume", e); + errMsg = e.toString(); + } + } + CreateCmdResult result = new CreateCmdResult(null, null); + if (errMsg != null) { + result.setResult(errMsg); + } + + callback.complete(result); + + } + + @Override + public void deleteAsync(DataObject data, + AsyncCompletionCallback callback) { + + String vmName = null; + VolumeVO vol = this.volumeDao.findById(data.getId()); + + + StoragePool pool = (StoragePool)data.getDataStore(); + + DestroyCommand cmd = new DestroyCommand(pool, vol, vmName); + + CommandResult result = new CommandResult(); + try { + Answer answer = this.storageMgr.sendToPool(pool, cmd); + if (answer != null && !answer.getResult()) { + result.setResult(answer.getDetails()); + s_logger.info("Will retry delete of " + vol + " from " + pool.getId()); + } + } catch (StorageUnavailableException e) { + s_logger.error("Storage is unavailable currently. Will retry delete of " + + vol + " from " + pool.getId(), e); + result.setResult(e.toString()); + } catch (Exception ex) { + s_logger.debug("Unable to destoy volume" + vol + " from " + pool.getId(), ex); + result.setResult(ex.toString()); + } + callback.complete(result); + } + + @Override + public void copyAsync(DataObject srcdata, DataObject destData, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + + @Override + public boolean canCopy(DataObject srcData, DataObject destData) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void takeSnapshot(SnapshotInfo snapshot, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + + @Override + public void revertSnapshot(SnapshotInfo snapshot, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + + } + +} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java index dfe4518edab..efd04d18294 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/driver/DefaultPrimaryDataStoreDriverImpl.java @@ -27,6 +27,7 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.framework.async.AsyncRpcConext; @@ -35,7 +36,6 @@ import org.apache.cloudstack.storage.command.CreateObjectCommand; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.datastore.DataObjectManager; import org.apache.cloudstack.storage.endpoint.EndPointSelector; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; import org.apache.log4j.Logger; diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/AncientPrimaryDataStoreLifeCyclImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/AncientPrimaryDataStoreLifeCyclImpl.java new file mode 100644 index 00000000000..3ce14ee8b48 --- /dev/null +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/AncientPrimaryDataStoreLifeCyclImpl.java @@ -0,0 +1,952 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.datastore.lifecycle; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreStatus; +import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CreateStoragePoolCommand; +import com.cloud.agent.api.DeleteStoragePoolCommand; +import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.alert.AlertManager; +import com.cloud.capacity.Capacity; +import com.cloud.capacity.CapacityVO; +import com.cloud.capacity.dao.CapacityDao; +import com.cloud.exception.DiscoveryException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.Status; +import com.cloud.resource.ResourceManager; +import com.cloud.server.ManagementServer; +import com.cloud.storage.OCFS2Manager; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolDiscoverer; +import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.StoragePoolWorkVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.StoragePoolWorkDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.user.Account; +import com.cloud.user.User; +import com.cloud.user.UserContext; +import com.cloud.user.dao.UserDao; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.UriUtils; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.exception.ExecutionException; +import com.cloud.vm.ConsoleProxyVO; +import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.SecondaryStorageVmVO; +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.VirtualMachineManager; +import com.cloud.vm.dao.ConsoleProxyDao; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.SecondaryStorageVmDao; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + +public class AncientPrimaryDataStoreLifeCyclImpl implements + PrimaryDataStoreLifeCycle { + private static final Logger s_logger = Logger + .getLogger(AncientPrimaryDataStoreLifeCyclImpl.class); + @Inject + protected ResourceManager _resourceMgr; + protected List _discoverers; + @Inject + PrimaryDataStoreDao primaryDataStoreDao; + @Inject + protected OCFS2Manager _ocfs2Mgr; + @Inject + DataStoreManager dataStoreMgr; + @Inject + AgentManager agentMgr; + @Inject + StorageManager storageMgr; + @Inject + protected CapacityDao _capacityDao; + + @Inject + VolumeDao volumeDao; + @Inject + VMInstanceDao vmDao; + @Inject + ManagementServer server; + @Inject + protected VirtualMachineManager vmMgr; + @Inject + protected SecondaryStorageVmDao _secStrgDao; + @Inject + UserVmDao userVmDao; + @Inject + protected UserDao _userDao; + @Inject + protected DomainRouterDao _domrDao; + @Inject + protected StoragePoolHostDao _storagePoolHostDao; + @Inject + protected AlertManager _alertMgr; + + + + @Inject + protected ConsoleProxyDao _consoleProxyDao; + + @Inject + protected StoragePoolWorkDao _storagePoolWorkDao; + + @Override + public DataStore initialize(Map dsInfos) { + Long clusterId = (Long) dsInfos.get("clusterId"); + Long podId = (Long) dsInfos.get("podId"); + Long zoneId = (Long) dsInfos.get("zoneId"); + String url = (String) dsInfos.get("url"); + Long providerId = (Long)dsInfos.get("providerId"); + if (clusterId != null && podId == null) { + throw new InvalidParameterValueException( + "Cluster id requires pod id"); + } + + URI uri = null; + try { + uri = new URI(UriUtils.encodeURIComponent(url)); + if (uri.getScheme() == null) { + throw new InvalidParameterValueException("scheme is null " + + url + ", add nfs:// as a prefix"); + } else if (uri.getScheme().equalsIgnoreCase("nfs")) { + String uriHost = uri.getHost(); + String uriPath = uri.getPath(); + if (uriHost == null || uriPath == null + || uriHost.trim().isEmpty() || uriPath.trim().isEmpty()) { + throw new InvalidParameterValueException( + "host or path is null, should be nfs://hostname/path"); + } + } else if (uri.getScheme().equalsIgnoreCase("sharedMountPoint")) { + String uriPath = uri.getPath(); + if (uriPath == null) { + throw new InvalidParameterValueException( + "host or path is null, should be sharedmountpoint://localhost/path"); + } + } else if (uri.getScheme().equalsIgnoreCase("rbd")) { + String uriPath = uri.getPath(); + if (uriPath == null) { + throw new InvalidParameterValueException( + "host or path is null, should be rbd://hostname/pool"); + } + } + } catch (URISyntaxException e) { + throw new InvalidParameterValueException(url + + " is not a valid uri"); + } + + String tags = (String) dsInfos.get("tags"); + Map details = (Map) dsInfos + .get("details"); + if (tags != null) { + String[] tokens = tags.split(","); + + for (String tag : tokens) { + tag = tag.trim(); + if (tag.length() == 0) { + continue; + } + details.put(tag, "true"); + } + } + + String scheme = uri.getScheme(); + String storageHost = uri.getHost(); + String hostPath = uri.getPath().replaceFirst("/", ""); + String userInfo = uri.getUserInfo(); + int port = uri.getPort(); + StoragePoolVO pool = null; + if (s_logger.isDebugEnabled()) { + s_logger.debug("createPool Params @ scheme - " + scheme + + " storageHost - " + storageHost + " hostPath - " + + hostPath + " port - " + port); + } + if (scheme.equalsIgnoreCase("nfs")) { + if (port == -1) { + port = 2049; + } + pool = new StoragePoolVO(StoragePoolType.NetworkFilesystem, + storageHost, port, hostPath); + if (clusterId == null) { + throw new IllegalArgumentException( + "NFS need to have clusters specified for XenServers"); + } + } else if (scheme.equalsIgnoreCase("file")) { + if (port == -1) { + port = 0; + } + pool = new StoragePoolVO(StoragePoolType.Filesystem, + "localhost", 0, hostPath); + } else if (scheme.equalsIgnoreCase("sharedMountPoint")) { + pool = new StoragePoolVO(StoragePoolType.SharedMountPoint, + storageHost, 0, hostPath); + } else if (scheme.equalsIgnoreCase("clvm")) { + pool = new StoragePoolVO(StoragePoolType.CLVM, storageHost, 0, + hostPath.replaceFirst("/", "")); + } else if (scheme.equalsIgnoreCase("rbd")) { + if (port == -1) { + port = 6789; + } + pool = new StoragePoolVO(StoragePoolType.RBD, storageHost, + port, hostPath.replaceFirst("/", "")); + pool.setUserInfo(userInfo); + } else if (scheme.equalsIgnoreCase("PreSetup")) { + pool = new StoragePoolVO(StoragePoolType.PreSetup, + storageHost, 0, hostPath); + } else if (scheme.equalsIgnoreCase("iscsi")) { + String[] tokens = hostPath.split("/"); + int lun = NumbersUtil.parseInt(tokens[tokens.length - 1], -1); + if (port == -1) { + port = 3260; + } + if (lun != -1) { + if (clusterId == null) { + throw new IllegalArgumentException( + "IscsiLUN need to have clusters specified"); + } + hostPath.replaceFirst("/", ""); + pool = new StoragePoolVO(StoragePoolType.IscsiLUN, + storageHost, port, hostPath); + } else { + for (StoragePoolDiscoverer discoverer : _discoverers) { + Map> pools; + try { + pools = discoverer.find(zoneId, podId, uri, details); + } catch (DiscoveryException e) { + throw new IllegalArgumentException( + "Not enough information for discovery " + uri, + e); + } + if (pools != null) { + Map.Entry> entry = pools + .entrySet().iterator().next(); + pool = entry.getKey(); + details = entry.getValue(); + break; + } + } + } + } else if (scheme.equalsIgnoreCase("iso")) { + if (port == -1) { + port = 2049; + } + pool = new StoragePoolVO(StoragePoolType.ISO, storageHost, + port, hostPath); + } else if (scheme.equalsIgnoreCase("vmfs")) { + pool = new StoragePoolVO(StoragePoolType.VMFS, + "VMFS datastore: " + hostPath, 0, hostPath); + } else if (scheme.equalsIgnoreCase("ocfs2")) { + port = 7777; + pool = new StoragePoolVO(StoragePoolType.OCFS2, "clustered", + port, hostPath); + } else { + StoragePoolType type = Enum.valueOf(StoragePoolType.class, scheme); + + if (type != null) { + pool = new StoragePoolVO(type, storageHost, + 0, hostPath); + } else { + s_logger.warn("Unable to figure out the scheme for URI: " + uri); + throw new IllegalArgumentException( + "Unable to figure out the scheme for URI: " + uri); + } + } + + if (pool == null) { + s_logger.warn("Unable to figure out the scheme for URI: " + uri); + throw new IllegalArgumentException( + "Unable to figure out the scheme for URI: " + uri); + } + + Object localStorage = dsInfos.get("localStorage"); + if (localStorage == null) { + List pools = primaryDataStoreDao + .listPoolByHostPath(storageHost, hostPath); + if (!pools.isEmpty() && !scheme.equalsIgnoreCase("sharedmountpoint")) { + Long oldPodId = pools.get(0).getPodId(); + throw new CloudRuntimeException("Storage pool " + uri + + " already in use by another pod (id=" + oldPodId + ")"); + } + } + + long poolId = primaryDataStoreDao.getNextInSequence(Long.class, "id"); + Object existingUuid = dsInfos.get("uuid"); + String uuid = null; + + if (existingUuid != null) { + uuid = (String)existingUuid; + } else if (scheme.equalsIgnoreCase("sharedmountpoint") + || scheme.equalsIgnoreCase("clvm")) { + uuid = UUID.randomUUID().toString(); + } else if (scheme.equalsIgnoreCase("PreSetup")) { + uuid = hostPath.replace("/", ""); + } else { + uuid = UUID.nameUUIDFromBytes( + new String(storageHost + hostPath).getBytes()).toString(); + } + + List spHandles = primaryDataStoreDao + .findIfDuplicatePoolsExistByUUID(uuid); + if ((spHandles != null) && (spHandles.size() > 0)) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Another active pool with the same uuid already exists"); + } + throw new CloudRuntimeException( + "Another active pool with the same uuid already exists"); + } + + String poolName = (String) dsInfos.get("name"); + if (s_logger.isDebugEnabled()) { + s_logger.debug("In createPool Setting poolId - " + poolId + + " uuid - " + uuid + " zoneId - " + zoneId + " podId - " + + podId + " poolName - " + poolName); + } + + pool.setId(poolId); + pool.setUuid(uuid); + pool.setDataCenterId(zoneId); + pool.setPodId(podId); + pool.setName(poolName); + pool.setClusterId(clusterId); + pool.setStorageProviderId(providerId); + pool.setStatus(StoragePoolStatus.Initialized); + pool = primaryDataStoreDao.persist(pool, details); + + return dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); + } + + protected boolean createStoragePool(long hostId, StoragePool pool) { + s_logger.debug("creating pool " + pool.getName() + " on host " + + hostId); + if (pool.getPoolType() != StoragePoolType.NetworkFilesystem + && pool.getPoolType() != StoragePoolType.Filesystem + && pool.getPoolType() != StoragePoolType.IscsiLUN + && pool.getPoolType() != StoragePoolType.Iscsi + && pool.getPoolType() != StoragePoolType.VMFS + && pool.getPoolType() != StoragePoolType.SharedMountPoint + && pool.getPoolType() != StoragePoolType.PreSetup + && pool.getPoolType() != StoragePoolType.OCFS2 + && pool.getPoolType() != StoragePoolType.RBD + && pool.getPoolType() != StoragePoolType.CLVM) { + s_logger.warn(" Doesn't support storage pool type " + + pool.getPoolType()); + return false; + } + CreateStoragePoolCommand cmd = new CreateStoragePoolCommand(true, pool); + final Answer answer = agentMgr.easySend(hostId, cmd); + if (answer != null && answer.getResult()) { + return true; + } else { + primaryDataStoreDao.expunge(pool.getId()); + String msg = ""; + if (answer != null) { + msg = "Can not create storage pool through host " + hostId + + " due to " + answer.getDetails(); + s_logger.warn(msg); + } else { + msg = "Can not create storage pool through host " + hostId + + " due to CreateStoragePoolCommand returns null"; + s_logger.warn(msg); + } + throw new CloudRuntimeException(msg); + } + } + + @Override + public boolean attachCluster(DataStore store, ClusterScope scope) { + PrimaryDataStoreInfo primarystore = (PrimaryDataStoreInfo) store; + // Check if there is host up in this cluster + List allHosts = _resourceMgr.listAllUpAndEnabledHosts( + Host.Type.Routing, primarystore.getClusterId(), + primarystore.getPodId(), primarystore.getDataCenterId()); + if (allHosts.isEmpty()) { + throw new CloudRuntimeException( + "No host up to associate a storage pool with in cluster " + + primarystore.getClusterId()); + } + + if (primarystore.getPoolType() == StoragePoolType.OCFS2 + && !_ocfs2Mgr.prepareNodes(allHosts, primarystore)) { + s_logger.warn("Can not create storage pool " + primarystore + + " on cluster " + primarystore.getClusterId()); + primaryDataStoreDao.expunge(primarystore.getId()); + return false; + } + + boolean success = false; + for (HostVO h : allHosts) { + success = createStoragePool(h.getId(), primarystore); + if (success) { + break; + } + } + + s_logger.debug("In createPool Adding the pool to each of the hosts"); + List poolHosts = new ArrayList(); + for (HostVO h : allHosts) { + try { + this.storageMgr.connectHostToSharedPool(h.getId(), + primarystore.getId()); + poolHosts.add(h); + } catch (Exception e) { + s_logger.warn("Unable to establish a connection between " + h + + " and " + primarystore, e); + } + } + + if (poolHosts.isEmpty()) { + s_logger.warn("No host can access storage pool " + primarystore + + " on cluster " + primarystore.getClusterId()); + primaryDataStoreDao.expunge(primarystore.getId()); + return false; + } else { + storageMgr.createCapacityEntry(primarystore.getId()); + } + StoragePoolVO pool = this.primaryDataStoreDao.findById(store.getId()); + pool.setScope(ScopeType.CLUSTER); + pool.setStatus(StoragePoolStatus.Up); + this.primaryDataStoreDao.update(pool.getId(), pool); + return true; + } + + @Override + public boolean attachZone(DataStore dataStore, ZoneScope scope) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean dettach() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean unmanaged() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean maintain(long storeId) { + Long userId = UserContext.current().getCallerUserId(); + User user = _userDao.findById(userId); + Account account = UserContext.current().getCaller(); + StoragePoolVO pool = this.primaryDataStoreDao.findById(storeId); + try { + StoragePool storagePool = (StoragePool) this.dataStoreMgr + .getDataStore(storeId, DataStoreRole.Primary); + List hosts = _resourceMgr.listHostsInClusterByStatus( + pool.getClusterId(), Status.Up); + if (hosts == null || hosts.size() == 0) { + pool.setStatus(StoragePoolStatus.Maintenance); + primaryDataStoreDao.update(pool.getId(), pool); + return true; + } else { + // set the pool state to prepare for maintenance + pool.setStatus(StoragePoolStatus.PrepareForMaintenance); + primaryDataStoreDao.update(pool.getId(), pool); + } + // remove heartbeat + for (HostVO host : hosts) { + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand( + false, storagePool); + final Answer answer = agentMgr.easySend(host.getId(), cmd); + if (answer == null || !answer.getResult()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("ModifyStoragePool false failed due to " + + ((answer == null) ? "answer null" : answer + .getDetails())); + } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("ModifyStoragePool false secceeded"); + } + } + } + // check to see if other ps exist + // if they do, then we can migrate over the system vms to them + // if they dont, then just stop all vms on this one + List upPools = primaryDataStoreDao + .listByStatusInZone(pool.getDataCenterId(), + DataStoreStatus.Up); + boolean restart = true; + if (upPools == null || upPools.size() == 0) { + restart = false; + } + + // 2. Get a list of all the ROOT volumes within this storage pool + List allVolumes = this.volumeDao.findByPoolId(pool + .getId()); + + // 3. Enqueue to the work queue + for (VolumeVO volume : allVolumes) { + VMInstanceVO vmInstance = vmDao + .findById(volume.getInstanceId()); + + if (vmInstance == null) { + continue; + } + + // enqueue sp work + if (vmInstance.getState().equals(State.Running) + || vmInstance.getState().equals(State.Starting) + || vmInstance.getState().equals(State.Stopping)) { + + try { + StoragePoolWorkVO work = new StoragePoolWorkVO( + vmInstance.getId(), pool.getId(), false, false, + server.getId()); + _storagePoolWorkDao.persist(work); + } catch (Exception e) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Work record already exists, re-using by re-setting values"); + } + StoragePoolWorkVO work = _storagePoolWorkDao + .findByPoolIdAndVmId(pool.getId(), + vmInstance.getId()); + work.setStartedAfterMaintenance(false); + work.setStoppedForMaintenance(false); + work.setManagementServerId(server.getId()); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + + // 4. Process the queue + List pendingWork = _storagePoolWorkDao + .listPendingWorkForPrepareForMaintenanceByPoolId(pool + .getId()); + + for (StoragePoolWorkVO work : pendingWork) { + // shut down the running vms + VMInstanceVO vmInstance = vmDao.findById(work.getVmId()); + + if (vmInstance == null) { + continue; + } + + // if the instance is of type consoleproxy, call the console + // proxy + if (vmInstance.getType().equals( + VirtualMachine.Type.ConsoleProxy)) { + // call the consoleproxymanager + ConsoleProxyVO consoleProxy = _consoleProxyDao + .findById(vmInstance.getId()); + if (!vmMgr.advanceStop(consoleProxy, true, user, account)) { + String errorMsg = "There was an error stopping the console proxy id: " + + vmInstance.getId() + + " ,cannot enable storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + // update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + + if (restart) { + + if (this.vmMgr.advanceStart(consoleProxy, null, user, + account) == null) { + String errorMsg = "There was an error starting the console proxy id: " + + vmInstance.getId() + + " on another storage pool, cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + } else { + // update work status + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + + // if the instance is of type uservm, call the user vm manager + if (vmInstance.getType().equals(VirtualMachine.Type.User)) { + UserVmVO userVm = userVmDao.findById(vmInstance.getId()); + if (!vmMgr.advanceStop(userVm, true, user, account)) { + String errorMsg = "There was an error stopping the user vm id: " + + vmInstance.getId() + + " ,cannot enable storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + // update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + + // if the instance is of type secondary storage vm, call the + // secondary storage vm manager + if (vmInstance.getType().equals( + VirtualMachine.Type.SecondaryStorageVm)) { + SecondaryStorageVmVO secStrgVm = _secStrgDao + .findById(vmInstance.getId()); + if (!vmMgr.advanceStop(secStrgVm, true, user, account)) { + String errorMsg = "There was an error stopping the ssvm id: " + + vmInstance.getId() + + " ,cannot enable storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + // update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + + if (restart) { + if (vmMgr.advanceStart(secStrgVm, null, user, account) == null) { + String errorMsg = "There was an error starting the ssvm id: " + + vmInstance.getId() + + " on another storage pool, cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + } else { + // update work status + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + + // if the instance is of type domain router vm, call the network + // manager + if (vmInstance.getType().equals( + VirtualMachine.Type.DomainRouter)) { + DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); + if (!vmMgr.advanceStop(domR, true, user, account)) { + String errorMsg = "There was an error stopping the domain router id: " + + vmInstance.getId() + + " ,cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + throw new CloudRuntimeException(errorMsg); + } else { + // update work status + work.setStoppedForMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + + if (restart) { + if (vmMgr.advanceStart(domR, null, user, account) == null) { + String errorMsg = "There was an error starting the domain router id: " + + vmInstance.getId() + + " on another storage pool, cannot enable primary storage maintenance"; + s_logger.warn(errorMsg); + } else { + // update work status + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } + } + + // 5. Update the status + pool.setStatus(StoragePoolStatus.Maintenance); + this.primaryDataStoreDao.update(pool.getId(), pool); + + return true; + } catch (Exception e) { + s_logger.error( + "Exception in enabling primary storage maintenance:", e); + setPoolStateToError(pool); + throw new CloudRuntimeException(e.getMessage()); + } + } + + private void setPoolStateToError(StoragePoolVO primaryStorage) { + primaryStorage.setStatus(StoragePoolStatus.ErrorInMaintenance); + this.primaryDataStoreDao.update(primaryStorage.getId(), primaryStorage); + } + + @Override + public boolean cancelMaintain(long storageId) { + // Change the storage state back to up + Long userId = UserContext.current().getCallerUserId(); + User user = _userDao.findById(userId); + Account account = UserContext.current().getCaller(); + StoragePoolVO poolVO = this.primaryDataStoreDao + .findById(storageId); + StoragePool pool = (StoragePool) this.dataStoreMgr.getDataStore( + storageId, DataStoreRole.Primary); + poolVO.setStatus(StoragePoolStatus.Up); + primaryDataStoreDao.update(storageId, poolVO); + + List hosts = _resourceMgr.listHostsInClusterByStatus( + pool.getClusterId(), Status.Up); + if (hosts == null || hosts.size() == 0) { + return true; + } + // add heartbeat + for (HostVO host : hosts) { + ModifyStoragePoolCommand msPoolCmd = new ModifyStoragePoolCommand( + true, pool); + final Answer answer = agentMgr.easySend(host.getId(), msPoolCmd); + if (answer == null || !answer.getResult()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("ModifyStoragePool add failed due to " + + ((answer == null) ? "answer null" : answer + .getDetails())); + } + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("ModifyStoragePool add secceeded"); + } + } + } + + // 2. Get a list of pending work for this queue + List pendingWork = _storagePoolWorkDao + .listPendingWorkForCancelMaintenanceByPoolId(poolVO.getId()); + + // 3. work through the queue + for (StoragePoolWorkVO work : pendingWork) { + try { + VMInstanceVO vmInstance = vmDao.findById(work.getVmId()); + + if (vmInstance == null) { + continue; + } + + // if the instance is of type consoleproxy, call the console + // proxy + if (vmInstance.getType().equals( + VirtualMachine.Type.ConsoleProxy)) { + + ConsoleProxyVO consoleProxy = _consoleProxyDao + .findById(vmInstance.getId()); + if (vmMgr.advanceStart(consoleProxy, null, user, account) == null) { + String msg = "There was an error starting the console proxy id: " + + vmInstance.getId() + + " on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + // update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + + // if the instance is of type ssvm, call the ssvm manager + if (vmInstance.getType().equals( + VirtualMachine.Type.SecondaryStorageVm)) { + SecondaryStorageVmVO ssVm = _secStrgDao.findById(vmInstance + .getId()); + if (vmMgr.advanceStart(ssVm, null, user, account) == null) { + String msg = "There was an error starting the ssvm id: " + + vmInstance.getId() + + " on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + // update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + + // if the instance is of type ssvm, call the ssvm manager + if (vmInstance.getType().equals( + VirtualMachine.Type.DomainRouter)) { + DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); + if (vmMgr.advanceStart(domR, null, user, account) == null) { + String msg = "There was an error starting the domR id: " + + vmInstance.getId() + + " on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + // update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + + // if the instance is of type user vm, call the user vm manager + if (vmInstance.getType().equals(VirtualMachine.Type.User)) { + UserVmVO userVm = userVmDao.findById(vmInstance.getId()); + + if (vmMgr.advanceStart(userVm, null, user, account) == null) { + + String msg = "There was an error starting the user vm id: " + + vmInstance.getId() + + " on storage pool, cannot complete primary storage maintenance"; + s_logger.warn(msg); + throw new ExecutionException(msg); + } else { + // update work queue + work.setStartedAfterMaintenance(true); + _storagePoolWorkDao.update(work.getId(), work); + } + } + } catch (Exception e) { + s_logger.debug("Failed start vm", e); + throw new CloudRuntimeException(e.toString()); + } + } + return true; + } + + @DB + @Override + public boolean deleteDataStore(long storeId) { + // for the given pool id, find all records in the storage_pool_host_ref + List hostPoolRecords = this._storagePoolHostDao + .listByPoolId(storeId); + StoragePoolVO poolVO = this.primaryDataStoreDao.findById(storeId); + StoragePool pool = (StoragePool)this.dataStoreMgr.getDataStore(storeId, DataStoreRole.Primary); + boolean deleteFlag = false; + Transaction txn = Transaction.currentTxn(); + try { + // if not records exist, delete the given pool (base case) + if (hostPoolRecords.size() == 0) { + + txn.start(); + poolVO.setUuid(null); + this.primaryDataStoreDao.update(poolVO.getId(), poolVO); + primaryDataStoreDao.remove(poolVO.getId()); + deletePoolStats(poolVO.getId()); + txn.commit(); + + deleteFlag = true; + return true; + } else { + // Remove the SR associated with the Xenserver + for (StoragePoolHostVO host : hostPoolRecords) { + DeleteStoragePoolCommand deleteCmd = new DeleteStoragePoolCommand( + pool); + final Answer answer = agentMgr.easySend(host.getHostId(), + deleteCmd); + + if (answer != null && answer.getResult()) { + deleteFlag = true; + break; + } + } + } + } finally { + if (deleteFlag) { + // now delete the storage_pool_host_ref and storage_pool records + txn.start(); + for (StoragePoolHostVO host : hostPoolRecords) { + _storagePoolHostDao.deleteStoragePoolHostDetails( + host.getHostId(), host.getPoolId()); + } + poolVO.setUuid(null); + this.primaryDataStoreDao.update(poolVO.getId(), poolVO); + primaryDataStoreDao.remove(poolVO.getId()); + deletePoolStats(poolVO.getId()); + // Delete op_host_capacity entries + this._capacityDao.removeBy(Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, + null, null, null, poolVO.getId()); + txn.commit(); + + s_logger.debug("Storage pool id=" + poolVO.getId() + + " is removed successfully"); + return true; + } else { + // alert that the storage cleanup is required + s_logger.warn("Failed to Delete storage pool id: " + poolVO.getId()); + _alertMgr + .sendAlert(AlertManager.ALERT_TYPE_STORAGE_DELETE, + poolVO.getDataCenterId(), poolVO.getPodId(), + "Unable to delete storage pool id= " + poolVO.getId(), + "Delete storage pool command failed. Please check logs."); + } + } + return false; + } + + @DB + private boolean deletePoolStats(Long poolId) { + CapacityVO capacity1 = _capacityDao.findByHostIdType(poolId, + CapacityVO.CAPACITY_TYPE_STORAGE); + CapacityVO capacity2 = _capacityDao.findByHostIdType(poolId, + CapacityVO.CAPACITY_TYPE_STORAGE_ALLOCATED); + Transaction txn = Transaction.currentTxn(); + txn.start(); + if (capacity1 != null) { + _capacityDao.remove(capacity1.getId()); + } + + if (capacity2 != null) { + _capacityDao.remove(capacity2.getId()); + } + + txn.commit(); + return true; + } + + @Override + public boolean attachHost(DataStore store, HostScope scope, StoragePoolInfo existingInfo) { + StoragePoolHostVO poolHost = _storagePoolHostDao.findByPoolHost(store.getId(), scope.getScopeId()); + if (poolHost == null) { + poolHost = new StoragePoolHostVO(store.getId(), scope.getScopeId(), existingInfo.getLocalPath()); + _storagePoolHostDao.persist(poolHost); + } + + StoragePoolVO pool = this.primaryDataStoreDao.findById(store.getId()); + pool.setScope(scope.getScopeType()); + pool.setAvailableBytes(existingInfo.getAvailableBytes()); + pool.setCapacityBytes(existingInfo.getCapacityBytes()); + pool.setStatus(StoragePoolStatus.Up); + this.primaryDataStoreDao.update(pool.getId(), pool); + this.storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getCapacityBytes() - pool.getAvailableBytes()); + + return true; + } + +} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java index ffe7efdcda7..5e8727a316a 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/lifecycle/DefaultPrimaryDataStoreLifeCycleImpl.java @@ -26,22 +26,22 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle; import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd; import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd; -import org.apache.cloudstack.storage.datastore.DataStoreStatus; -import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.endpoint.EndPointSelector; -import org.apache.cloudstack.storage.image.datastore.ImageDataStoreHelper; import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper; +import com.cloud.agent.api.StoragePoolInfo; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.StoragePoolStatus; public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle { @Inject @@ -58,9 +58,9 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif } @Override - public DataStore initialize(Map dsInfos) { + public DataStore initialize(Map dsInfos) { - PrimaryDataStoreVO storeVO = primaryStoreHelper.createPrimaryDataStore(dsInfos); + StoragePoolVO storeVO = primaryStoreHelper.createPrimaryDataStore(dsInfos); return providerMgr.getPrimaryDataStore(storeVO.getId()); } @@ -83,11 +83,11 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif @Override public boolean attachCluster(DataStore dataStore, ClusterScope scope) { - PrimaryDataStoreVO dataStoreVO = dataStoreDao.findById(dataStore.getId()); + StoragePoolVO dataStoreVO = dataStoreDao.findById(dataStore.getId()); dataStoreVO.setDataCenterId(scope.getZoneId()); dataStoreVO.setPodId(scope.getPodId()); dataStoreVO.setClusterId(scope.getScopeId()); - dataStoreVO.setStatus(DataStoreStatus.Attaching); + dataStoreVO.setStatus(StoragePoolStatus.Attaching); dataStoreVO.setScope(scope.getScopeType()); dataStoreDao.update(dataStoreVO.getId(), dataStoreVO); @@ -95,7 +95,7 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif attachCluster(dataStore); dataStoreVO = dataStoreDao.findById(dataStore.getId()); - dataStoreVO.setStatus(DataStoreStatus.Up); + dataStoreVO.setStatus(StoragePoolStatus.Up); dataStoreDao.update(dataStoreVO.getId(), dataStoreVO); return true; @@ -114,19 +114,19 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif } @Override - public boolean maintain() { + public boolean maintain(long storeId) { // TODO Auto-generated method stub return false; } @Override - public boolean cancelMaintain() { + public boolean cancelMaintain(long storeId) { // TODO Auto-generated method stub return false; } @Override - public boolean deleteDataStore() { + public boolean deleteDataStore(long storeId) { // TODO Auto-generated method stub return false; } @@ -139,4 +139,11 @@ public class DefaultPrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLif return false; } + @Override + public boolean attachHost(DataStore store, HostScope scope, + StoragePoolInfo existingInfo) { + // TODO Auto-generated method stub + return false; + } + } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreProviderManagerImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreProviderManagerImpl.java index 1a24d87346e..fdbe4b47c1e 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreProviderManagerImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/DefaultPrimaryDataStoreProviderManagerImpl.java @@ -21,21 +21,21 @@ package org.apache.cloudstack.storage.datastore.manager; import java.util.HashMap; import java.util.Map; +import javax.annotation.PostConstruct; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; import org.apache.cloudstack.storage.datastore.DefaultPrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; import org.apache.cloudstack.storage.datastore.db.DataStoreProviderDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreVO; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProvider; -import org.apache.cloudstack.storage.datastore.provider.DataStoreProviderManager; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; import org.springframework.stereotype.Component; -import com.cloud.utils.component.ComponentContext; - @Component public class DefaultPrimaryDataStoreProviderManagerImpl implements PrimaryDataStoreProviderManager { @Inject @@ -44,16 +44,18 @@ public class DefaultPrimaryDataStoreProviderManagerImpl implements PrimaryDataSt DataStoreProviderManager providerManager; @Inject PrimaryDataStoreDao dataStoreDao; - Map driverMaps = new HashMap(); + Map driverMaps; + @PostConstruct + public void config() { + driverMaps = new HashMap(); + } + @Override public PrimaryDataStore getPrimaryDataStore(long dataStoreId) { - PrimaryDataStoreVO dataStoreVO = dataStoreDao.findById(dataStoreId); + StoragePoolVO dataStoreVO = dataStoreDao.findById(dataStoreId); long providerId = dataStoreVO.getStorageProviderId(); DataStoreProvider provider = providerManager.getDataStoreProviderById(providerId); - /*DefaultPrimaryDataStore dataStore = DefaultPrimaryDataStore.createDataStore(dataStoreVO, - driverMaps.get(provider.getUuid()), - provider);*/ DefaultPrimaryDataStore dataStore = DefaultPrimaryDataStore.createDataStore(dataStoreVO, driverMaps.get(provider.getUuid()), provider); return dataStore; } @@ -66,4 +68,16 @@ public class DefaultPrimaryDataStoreProviderManagerImpl implements PrimaryDataSt driverMaps.put(uuid, driver); return true; } + + @Override + public PrimaryDataStore getPrimaryDataStore(String uuid) { + StoragePoolVO dataStoreVO = dataStoreDao.findByUuid(uuid); + return getPrimaryDataStore(dataStoreVO.getId()); + } + + @Override + public boolean registerHostListener(String uuid, HypervisorHostListener listener) { + // TODO Auto-generated method stub + return false; + } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/data model.ucls b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/data model.ucls index 9386454efb3..f1590397b8f 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/data model.ucls +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/manager/data model.ucls @@ -1,21 +1,3 @@ - - + - + @@ -72,4 +54,4 @@ - + \ No newline at end of file diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/AncientPrimaryDataStoreProviderImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/AncientPrimaryDataStoreProviderImpl.java new file mode 100644 index 00000000000..702ab238ba8 --- /dev/null +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/AncientPrimaryDataStoreProviderImpl.java @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.datastore.provider; + +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; +import org.apache.cloudstack.storage.datastore.driver.AncientPrimaryDataStoreDriverImpl; +import org.apache.cloudstack.storage.datastore.lifecycle.AncientPrimaryDataStoreLifeCyclImpl; +import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; +import org.springframework.stereotype.Component; + +import com.cloud.utils.component.ComponentContext; + +@Component +public class AncientPrimaryDataStoreProviderImpl implements + PrimaryDataStoreProvider { + + private final String providerName = "ancient primary data store provider"; + protected PrimaryDataStoreDriver driver; + @Inject + PrimaryDataStoreProviderManager storeMgr; + protected DataStoreLifeCycle lifecyle; + protected String uuid; + protected long id; + @Override + public String getName() { + return providerName; + } + + @Override + public DataStoreLifeCycle getLifeCycle() { + return this.lifecyle; + } + + @Override + public boolean configure(Map params) { + lifecyle = ComponentContext.inject(AncientPrimaryDataStoreLifeCyclImpl.class); + driver = ComponentContext.inject(AncientPrimaryDataStoreDriverImpl.class); + uuid = (String)params.get("uuid"); + id = (Long)params.get("id"); + storeMgr.registerDriver(uuid, this.driver); + return true; + } + + @Override + public String getUuid() { + return this.uuid; + } + + @Override + public long getId() { + return this.id; + } + +} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java new file mode 100644 index 00000000000..f2cb1c45c82 --- /dev/null +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultHostListener.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.cloudstack.storage.datastore.provider; + +import javax.inject.Inject; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ModifyStoragePoolAnswer; +import com.cloud.agent.api.ModifyStoragePoolCommand; +import com.cloud.alert.AlertManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.utils.exception.CloudRuntimeException; + +public class DefaultHostListener implements HypervisorHostListener { + private static final Logger s_logger = Logger + .getLogger(DefaultHostListener.class); + @Inject AgentManager agentMgr; + @Inject DataStoreManager dataStoreMgr; + @Inject AlertManager alertMgr; + @Inject StoragePoolHostDao storagePoolHostDao; + @Inject PrimaryDataStoreDao primaryStoreDao; + @Override + public boolean hostConnect(long hostId, long poolId) { + StoragePool pool = (StoragePool)this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary); + ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool); + final Answer answer = agentMgr.easySend(hostId, cmd); + + if (answer == null) { + throw new CloudRuntimeException("Unable to get an answer to the modify storage pool command" + pool.getId()); + } + + if (!answer.getResult()) { + String msg = "Add host failed due to ModifyStoragePoolCommand failed" + answer.getDetails(); + alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg); + throw new CloudRuntimeException("Unable establish connection from storage head to storage pool " + pool.getId() + " due to " + answer.getDetails() + pool.getId()); + } + + assert (answer instanceof ModifyStoragePoolAnswer) : "Well, now why won't you actually return the ModifyStoragePoolAnswer when it's ModifyStoragePoolCommand? Pool=" + pool.getId() + "Host=" + hostId; + ModifyStoragePoolAnswer mspAnswer = (ModifyStoragePoolAnswer) answer; + + StoragePoolHostVO poolHost = storagePoolHostDao.findByPoolHost(pool.getId(), hostId); + if (poolHost == null) { + poolHost = new StoragePoolHostVO(pool.getId(), hostId, mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/")); + storagePoolHostDao.persist(poolHost); + } else { + poolHost.setLocalPath(mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/")); + } + + StoragePoolVO poolVO = this.primaryStoreDao.findById(poolId); + poolVO.setAvailableBytes(mspAnswer.getPoolInfo().getAvailableBytes()); + poolVO.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes()); + primaryStoreDao.update(pool.getId(), poolVO); + + s_logger.info("Connection established between " + pool + " host + " + hostId); + return true; + } + + @Override + public boolean hostDisconnected(long hostId, long poolId) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java index 540ea6381fa..85a5d0226d7 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/provider/DefaultPrimaryDatastoreProviderImpl.java @@ -21,6 +21,7 @@ import java.util.Map; import javax.inject.Inject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; import org.apache.cloudstack.storage.datastore.driver.DefaultPrimaryDataStoreDriverImpl; import org.apache.cloudstack.storage.datastore.lifecycle.DefaultPrimaryDataStoreLifeCycleImpl; @@ -35,6 +36,7 @@ public class DefaultPrimaryDatastoreProviderImpl implements PrimaryDataStoreProv protected PrimaryDataStoreDriver driver; @Inject PrimaryDataStoreProviderManager storeMgr; + protected DataStoreLifeCycle lifecyle; protected String uuid; protected long id; @@ -52,9 +54,11 @@ public class DefaultPrimaryDatastoreProviderImpl implements PrimaryDataStoreProv public boolean configure(Map params) { lifecyle = ComponentContext.inject(DefaultPrimaryDataStoreLifeCycleImpl.class); driver = ComponentContext.inject(DefaultPrimaryDataStoreDriverImpl.class); + HypervisorHostListener listener = ComponentContext.inject(DefaultHostListener.class); uuid = (String)params.get("uuid"); id = (Long)params.get("id"); storeMgr.registerDriver(uuid, this.driver); + storeMgr.registerHostListener(uuid, listener); return true; } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategy.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategy.java index 7679bb3e729..99b34cbcf18 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategy.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategy.java @@ -18,9 +18,9 @@ */ package org.apache.cloudstack.storage.volume; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.volume.VolumeServiceImpl.CreateBaseImageResult; public interface TemplateInstallStrategy { diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java index 80e098d769a..5f1735c180a 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/TemplateInstallStrategyImpl.java @@ -20,24 +20,16 @@ package org.apache.cloudstack.storage.volume; import javax.inject.Inject; -import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; -import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; -import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.framework.async.AsyncRpcConext; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.image.ImageDataFactory; -import org.apache.cloudstack.storage.image.TemplateInfo; import org.apache.cloudstack.storage.motion.DataMotionService; import org.apache.cloudstack.storage.volume.VolumeServiceImpl.CreateBaseImageResult; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.fsm.NoTransitionException; - @Component public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { private static final Logger s_logger = Logger @@ -50,7 +42,7 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { ImageDataFactory imageFactory; protected long waitingTime = 1800; // half an hour protected long waitingRetries = 10; - +/* protected TemplateInfo waitingForTemplateDownload(TemplateInfo template, PrimaryDataStore dataStore) { long retries = this.waitingRetries; @@ -106,8 +98,8 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { boolean freshNewTemplate = false; if (obj == null) { try { - /*templateOnPrimaryStoreObj = objectInDataStoreMgr.create( - template, store);*/ + templateOnPrimaryStoreObj = objectInDataStoreMgr.create( + template, store); freshNewTemplate = true; } catch (Throwable e) { obj = objectInDataStoreMgr.findObject(template.getId(), @@ -264,13 +256,10 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { res.setResult(result.getResult()); context.getParentCallback().complete(res); } - ObjectInDataStoreVO obj = objectInDataStoreMgr.findObject( - templateOnPrimaryStoreObj.getId(), templateOnPrimaryStoreObj - .getType(), templateOnPrimaryStoreObj.getDataStore() - .getId(), templateOnPrimaryStoreObj.getDataStore() - .getRole()); + DataObjectInStore obj = objectInDataStoreMgr.findObject( + templateOnPrimaryStoreObj, templateOnPrimaryStoreObj.getDataStore()); + - obj.setInstallPath(result.getPath()); CreateBaseImageResult res = new CreateBaseImageResult( templateOnPrimaryStoreObj); try { @@ -289,6 +278,12 @@ public class TemplateInstallStrategyImpl implements TemplateInstallStrategy { } context.getParentCallback().complete(res); return null; + }*/ + @Override + public Void installAsync(TemplateInfo template, PrimaryDataStore store, + AsyncCompletionCallback callback) { + // TODO Auto-generated method stub + return null; } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeDataFactoryImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeDataFactoryImpl.java index 64af097bb32..e0ecd165d7f 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeDataFactoryImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeDataFactoryImpl.java @@ -20,21 +20,23 @@ package org.apache.cloudstack.storage.volume; import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.storage.datastore.DataStoreManager; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.datastore.VolumeDataFactory; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.springframework.stereotype.Component; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; + @Component public class VolumeDataFactoryImpl implements VolumeDataFactory { @Inject - VolumeDao2 volumeDao; + VolumeDao volumeDao; @Inject ObjectInDataStoreManager objMap; @Inject @@ -42,12 +44,30 @@ public class VolumeDataFactoryImpl implements VolumeDataFactory { @Override public VolumeInfo getVolume(long volumeId, DataStore store) { VolumeVO volumeVO = volumeDao.findById(volumeId); - ObjectInDataStoreVO obj = objMap.findObject(volumeId, DataObjectType.VOLUME, store.getId(), store.getRole()); - if (obj == null) { - VolumeObject vol = VolumeObject.getVolumeObject(null, volumeVO); - return vol; - } + VolumeObject vol = VolumeObject.getVolumeObject(store, volumeVO); + + return vol; + } + + @Override + public VolumeInfo getVolume(long volumeId) { + VolumeVO volumeVO = volumeDao.findById(volumeId); + VolumeObject vol = null; + if (volumeVO.getPoolId() == null) { + DataStore store = objMap.findStore(volumeVO.getUuid(), DataObjectType.VOLUME, DataStoreRole.Image); + vol = VolumeObject.getVolumeObject(store, volumeVO); + } else { + DataStore store = this.storeMgr.getDataStore(volumeVO.getPoolId(), DataStoreRole.Primary); + vol = VolumeObject.getVolumeObject(store, volumeVO); + } + return vol; + } + + @Override + public VolumeInfo getVolume(DataObject volume, DataStore store) { + VolumeInfo vol = (VolumeObject)getVolume(volume.getId(), store); + vol.addPayload(((VolumeInfo)volume).getpayload()); return vol; } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java index 14d741707b5..f8d50437d14 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeEntityImpl.java @@ -22,20 +22,17 @@ import java.lang.reflect.Method; import java.util.Date; import java.util.List; import java.util.Map; -import java.util.concurrent.ExecutionException; import org.apache.cloudstack.engine.cloud.entity.api.SnapshotEntity; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; import org.apache.cloudstack.engine.datacenter.entity.api.StorageEntity; import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import org.apache.cloudstack.engine.subsystem.api.storage.type.VolumeType; -import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreEntityImpl; -import org.apache.cloudstack.storage.volume.VolumeService.VolumeApiResult; - -import com.cloud.utils.exception.CloudRuntimeException; public class VolumeEntityImpl implements VolumeEntity { private VolumeInfo volumeInfo; @@ -167,7 +164,7 @@ public class VolumeEntityImpl implements VolumeEntity { @Override public void destroy() { - AsyncCallFuture future = vs.deleteVolumeAsync(volumeInfo); + /*AsyncCallFuture future = vs.deleteVolumeAsync(volumeInfo); try { result = future.get(); if (!result.isSuccess()) { @@ -177,7 +174,7 @@ public class VolumeEntityImpl implements VolumeEntity { throw new CloudRuntimeException("wait to delete volume info failed", e); } catch (ExecutionException e) { throw new CloudRuntimeException("wait to delete volume failed", e); - } + }*/ } @Override diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java deleted file mode 100644 index bcff312626f..00000000000 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeManagerImpl.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.cloudstack.storage.volume; - -import javax.inject.Inject; - -import org.apache.cloudstack.engine.subsystem.api.storage.VolumeProfile; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; -import org.springframework.stereotype.Component; - -import com.cloud.storage.Volume; -import com.cloud.storage.Volume.Event; -import com.cloud.storage.Volume.State; -import com.cloud.utils.fsm.NoTransitionException; -import com.cloud.utils.fsm.StateMachine2; - -@Component -public class VolumeManagerImpl implements VolumeManager { - @Inject - protected VolumeDao2 _volumeDao; - private final StateMachine2 s_fsm = new StateMachine2(); - public VolumeManagerImpl() { - initStateMachine(); - } - - @Override - public VolumeVO allocateDuplicateVolume(VolumeVO oldVol) { - /* - VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), oldVol.getDiskOfferingId(), oldVol.getSize()); - newVol.setTemplateId(oldVol.getTemplateId()); - newVol.setDeviceId(oldVol.getDeviceId()); - newVol.setInstanceId(oldVol.getInstanceId()); - newVol.setRecreatable(oldVol.isRecreatable()); - newVol.setReservationId(oldVol.getReservationId()); - */ - return null; - // return _volumeDao.persist(newVol); - } - - private void initStateMachine() { - s_fsm.addTransition(Volume.State.Allocated, Event.CreateRequested, Volume.State.Creating); - s_fsm.addTransition(Volume.State.Allocated, Event.DestroyRequested, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Creating, Event.OperationRetry, Volume.State.Creating); - s_fsm.addTransition(Volume.State.Creating, Event.OperationFailed, Volume.State.Allocated); - s_fsm.addTransition(Volume.State.Creating, Event.OperationSucceeded, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Creating, Event.DestroyRequested, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Creating, Event.CreateRequested, Volume.State.Creating); - s_fsm.addTransition(Volume.State.Allocated, Event.UploadRequested, Volume.State.UploadOp); - s_fsm.addTransition(Volume.State.UploadOp, Event.CopyRequested, Volume.State.Creating);// CopyRequested for volume from sec to primary storage - s_fsm.addTransition(Volume.State.Creating, Event.CopySucceeded, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Creating, Event.CopyFailed, Volume.State.UploadOp);// Copying volume from sec to primary failed. - s_fsm.addTransition(Volume.State.UploadOp, Event.DestroyRequested, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Ready, Event.DestroyRequested, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Destroy, Event.ExpungingRequested, Volume.State.Expunging); - s_fsm.addTransition(Volume.State.Ready, Event.SnapshotRequested, Volume.State.Snapshotting); - s_fsm.addTransition(Volume.State.Snapshotting, Event.OperationSucceeded, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Snapshotting, Event.OperationFailed, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Ready, Event.MigrationRequested, Volume.State.Migrating); - s_fsm.addTransition(Volume.State.Migrating, Event.OperationSucceeded, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Migrating, Event.OperationFailed, Volume.State.Ready); - s_fsm.addTransition(Volume.State.Destroy, Event.OperationSucceeded, Volume.State.Destroy); - s_fsm.addTransition(Volume.State.Destroying, Event.OperationSucceeded, Volume.State.Destroy); - s_fsm.addTransition(Volume.State.Destroying, Event.OperationFailed, Volume.State.Destroying); - s_fsm.addTransition(Volume.State.Destroying, Event.DestroyRequested, Volume.State.Destroying); - } - - @Override - public StateMachine2 getStateMachine() { - return s_fsm; - } - - @Override - public VolumeVO processEvent(Volume vol, Volume.Event event) throws NoTransitionException { - // _volStateMachine.transitTo(vol, event, null, _volumeDao); - return _volumeDao.findById(vol.getId()); - } - - @Override - public VolumeProfile getProfile(long volumeId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public VolumeVO getVolume(long volumeId) { - // TODO Auto-generated method stub - return null; - } - - @Override - public VolumeVO updateVolume(VolumeVO volume) { - // TODO Auto-generated method stub - return null; - } -} diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java index 9e04909135e..87951ceeb64 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java @@ -16,19 +16,23 @@ // under the License. package org.apache.cloudstack.storage.volume; +import java.util.Date; + import javax.inject.Inject; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; -import org.apache.cloudstack.storage.db.ObjectInDataStoreVO; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; import org.apache.log4j.Logger; import com.cloud.storage.Volume; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.component.ComponentContext; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; @@ -38,17 +42,16 @@ import com.cloud.utils.storage.encoding.EncodingType; public class VolumeObject implements VolumeInfo { private static final Logger s_logger = Logger.getLogger(VolumeObject.class); protected VolumeVO volumeVO; - private StateMachine2 _volStateMachine; + private StateMachine2 _volStateMachine; protected DataStore dataStore; @Inject - VolumeDao2 volumeDao; - @Inject - VolumeManager volumeMgr; + VolumeDao volumeDao; @Inject ObjectInDataStoreManager ojbectInStoreMgr; + private Object payload; protected VolumeObject() { - + _volStateMachine = Volume.State.getStateMachine(); } protected void configure(DataStore dataStore, VolumeVO volumeVO) { @@ -88,12 +91,11 @@ public class VolumeObject implements VolumeInfo { public long getVolumeId() { return volumeVO.getId(); } - public boolean stateTransit(Volume.Event event) { boolean result = false; - _volStateMachine = volumeMgr.getStateMachine(); try { result = _volStateMachine.transitTo(volumeVO, event, null, volumeDao); + volumeVO = volumeDao.findById(volumeVO.getId()); } catch (NoTransitionException e) { String errorMessage = "Failed to transit volume: " + this.getVolumeId() + ", due to: " + e.toString(); s_logger.debug(errorMessage); @@ -122,7 +124,7 @@ public class VolumeObject implements VolumeInfo { if (this.dataStore == null) { throw new CloudRuntimeException("datastore must be set before using this object"); } - ObjectInDataStoreVO obj = ojbectInStoreMgr.findObject(this.volumeVO.getId(), DataObjectType.VOLUME, this.dataStore.getId(), this.dataStore.getRole()); + DataObjectInStore obj = ojbectInStoreMgr.findObject(this.volumeVO.getUuid(), DataObjectType.VOLUME, this.dataStore.getUuid(), this.dataStore.getRole()); if (obj.getState() != ObjectInDataStoreStateMachine.State.Ready) { return this.dataStore.getUri() + "&" + EncodingType.OBJTYPE + "=" + DataObjectType.VOLUME + @@ -145,4 +147,167 @@ public class VolumeObject implements VolumeInfo { // TODO Auto-generated method stub return null; } + + @Override + public void processEvent( + ObjectInDataStoreStateMachine.Event event) { + if (this.dataStore == null) { + return; + } + try { + Volume.Event volEvent = null; + if (this.dataStore.getRole() == DataStoreRole.Image) { + ojbectInStoreMgr.update(this, event); + if (event == ObjectInDataStoreStateMachine.Event.CreateRequested) { + volEvent = Volume.Event.UploadRequested; + } else if (event == ObjectInDataStoreStateMachine.Event.OperationSuccessed) { + volEvent = Volume.Event.CopySucceeded; + } else if (event == ObjectInDataStoreStateMachine.Event.OperationFailed) { + volEvent = Volume.Event.CopyFailed; + } + } else { + if (event == ObjectInDataStoreStateMachine.Event.CreateRequested || + event == ObjectInDataStoreStateMachine.Event.CreateOnlyRequested) { + volEvent = Volume.Event.CreateRequested; + } else if (event == ObjectInDataStoreStateMachine.Event.CopyingRequested) { + volEvent = Volume.Event.CopyRequested; + } + } + + if (event == ObjectInDataStoreStateMachine.Event.DestroyRequested) { + volEvent = Volume.Event.DestroyRequested; + } else if (event == ObjectInDataStoreStateMachine.Event.ExpungeRequested) { + volEvent = Volume.Event.ExpungingRequested; + } else if (event == ObjectInDataStoreStateMachine.Event.OperationSuccessed) { + volEvent = Volume.Event.OperationSucceeded; + } else if (event == ObjectInDataStoreStateMachine.Event.OperationFailed) { + volEvent = Volume.Event.OperationFailed; + } + this.stateTransit(volEvent); + } catch (Exception e) { + s_logger.debug("Failed to update state", e); + throw new CloudRuntimeException("Failed to update state:" + e.toString()); + } + + } + + @Override + public String getName() { + return this.volumeVO.getName(); + } + + @Override + public Long getInstanceId() { + return this.volumeVO.getInstanceId(); + } + + @Override + public String getFolder() { + return this.volumeVO.getFolder(); + } + + @Override + public String getPath() { + return this.volumeVO.getPath(); + } + + @Override + public Long getPodId() { + return this.volumeVO.getPodId(); + } + + @Override + public long getDataCenterId() { + return this.volumeVO.getDataCenterId(); + } + + @Override + public Type getVolumeType() { + return this.volumeVO.getVolumeType(); + } + + @Override + public Long getPoolId() { + return this.volumeVO.getPoolId(); + } + + @Override + public Date getAttached() { + return this.volumeVO.getAttached(); + } + + @Override + public Long getDeviceId() { + return this.volumeVO.getDeviceId(); + } + + @Override + public Date getCreated() { + return this.volumeVO.getCreated(); + } + + @Override + public long getDiskOfferingId() { + return this.volumeVO.getDiskOfferingId(); + } + + @Override + public String getChainInfo() { + return this.volumeVO.getChainInfo(); + } + + @Override + public boolean isRecreatable() { + return this.volumeVO.isRecreatable(); + } + + @Override + public long getUpdatedCount() { + return this.volumeVO.getUpdatedCount(); + } + + @Override + public void incrUpdatedCount() { + this.volumeVO.incrUpdatedCount(); + } + + @Override + public Date getUpdated() { + return this.volumeVO.getUpdated(); + } + + @Override + public String getReservationId() { + return this.volumeVO.getReservationId(); + } + + @Override + public void setReservationId(String reserv) { + this.volumeVO.setReservationId(reserv); + } + + @Override + public long getAccountId() { + return this.volumeVO.getAccountId(); + } + + @Override + public long getDomainId() { + return this.volumeVO.getDomainId(); + } + + @Override + public Long getTemplateId() { + return this.volumeVO.getTemplateId(); + } + + @Override + public void addPayload(Object data) { + this.payload = data; + } + + @Override + public Object getpayload() { + return this.payload; + } } diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java index 8cfbae455e7..891ad1249df 100644 --- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java +++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeServiceImpl.java @@ -22,12 +22,16 @@ import javax.inject.Inject; import org.apache.cloudstack.engine.cloud.entity.api.VolumeEntity; import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult; import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; -import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; -import org.apache.cloudstack.engine.subsystem.api.storage.type.VolumeType; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; @@ -36,22 +40,29 @@ import org.apache.cloudstack.storage.datastore.DataObjectManager; import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager; import org.apache.cloudstack.storage.datastore.PrimaryDataStore; import org.apache.cloudstack.storage.datastore.PrimaryDataStoreProviderManager; -import org.apache.cloudstack.storage.image.TemplateInfo; -import org.apache.cloudstack.storage.image.motion.ImageMotionService; -import org.apache.cloudstack.storage.volume.db.VolumeDao2; -import org.apache.cloudstack.storage.volume.db.VolumeVO; +import org.apache.cloudstack.storage.motion.DataMotionService; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; +import com.cloud.exception.ConcurrentOperationException; import com.cloud.storage.Volume; +import com.cloud.storage.Volume.Type; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.utils.db.DB; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.dao.VMInstanceDao; //1. change volume state //2. orchestrator of volume, control most of the information of volume, storage pool id, voluem state, scope etc. @Component public class VolumeServiceImpl implements VolumeService { + private static final Logger s_logger = Logger + .getLogger(VolumeServiceImpl.class); @Inject - VolumeDao2 volDao; + VolumeDao volDao; @Inject PrimaryDataStoreProviderManager dataStoreMgr; @Inject @@ -59,27 +70,31 @@ public class VolumeServiceImpl implements VolumeService { @Inject DataObjectManager dataObjectMgr; @Inject - ImageMotionService imageMotion; + DataMotionService motionSrv; @Inject TemplateInstallStrategy templateInstallStrategy; + @Inject + VolumeDataFactory volFactory; + @Inject SnapshotManager snapshotMgr; + @Inject VMInstanceDao vmDao; public VolumeServiceImpl() { } private class CreateVolumeContext extends AsyncRpcConext { - private VolumeObject volume; + private DataObject volume; private AsyncCallFuture future; /** * @param callback */ - public CreateVolumeContext(AsyncCompletionCallback callback, VolumeObject volume, AsyncCallFuture future) { + public CreateVolumeContext(AsyncCompletionCallback callback, DataObject volume, AsyncCallFuture future) { super(callback); this.volume = volume; this.future = future; } - public VolumeObject getVolume() { + public DataObject getVolume() { return this.volume; } @@ -89,49 +104,35 @@ public class VolumeServiceImpl implements VolumeService { } - - @Override - public AsyncCallFuture createVolumeAsync(VolumeInfo volume, long dataStoreId) { - PrimaryDataStore dataStore = dataStoreMgr.getPrimaryDataStore(dataStoreId); + public AsyncCallFuture createVolumeAsync(VolumeInfo volume, DataStore dataStore) { AsyncCallFuture future = new AsyncCallFuture(); - VolumeApiResult result = new VolumeApiResult(volume); - - if (dataStore == null) { - result.setResult("Can't find dataStoreId: " + dataStoreId); - future.complete(result); - return future; - } + DataObject volumeOnStore = dataStore.create(volume); + volumeOnStore.processEvent(Event.CreateOnlyRequested); - if (dataStore.exists(volume)) { - result.setResult("Volume: " + volume.getId() + " already exists on primary data store: " + dataStoreId); - future.complete(result); - return future; - } - - VolumeObject vo = (VolumeObject) volume; - vo.stateTransit(Volume.Event.CreateRequested); - - CreateVolumeContext context = new CreateVolumeContext(null, vo, future); + CreateVolumeContext context = new CreateVolumeContext(null, volumeOnStore, future); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().createVolumeCallback(null, null)) .setContext(context); - dataObjectMgr.createAsync(volume, dataStore, caller, true); + dataStore.getDriver().createAsync(volumeOnStore, caller); return future; } protected Void createVolumeCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { CreateCmdResult result = callback.getResult(); - VolumeObject vo = context.getVolume(); - VolumeApiResult volResult = new VolumeApiResult(vo); + DataObject vo = context.getVolume(); + String errMsg = null; if (result.isSuccess()) { - vo.stateTransit(Volume.Event.OperationSucceeded); + vo.processEvent(Event.OperationSuccessed); } else { - vo.stateTransit(Volume.Event.OperationFailed); - volResult.setResult(result.getResult()); + vo.processEvent(Event.OperationFailed); + errMsg = result.getResult(); + } + VolumeApiResult volResult = new VolumeApiResult((VolumeObject)vo); + if (errMsg != null) { + volResult.setResult(errMsg); } - context.getFuture().complete(volResult); return null; } @@ -159,26 +160,47 @@ public class VolumeServiceImpl implements VolumeService { @DB @Override - public AsyncCallFuture deleteVolumeAsync(VolumeInfo volume) { - VolumeObject vo = (VolumeObject)volume; + public AsyncCallFuture expungeVolumeAsync(VolumeInfo volume) { AsyncCallFuture future = new AsyncCallFuture(); VolumeApiResult result = new VolumeApiResult(volume); - - DataStore dataStore = vo.getDataStore(); - vo.stateTransit(Volume.Event.DestroyRequested); - if (dataStore == null) { - vo.stateTransit(Volume.Event.OperationSucceeded); - volDao.remove(vo.getId()); + if (volume.getDataStore() == null) { + this.volDao.remove(volume.getId()); future.complete(result); return future; } + String vmName = null; + VolumeVO vol = this.volDao.findById(volume.getId()); + if (vol.getVolumeType() == Type.ROOT && vol.getInstanceId() != null) { + VirtualMachine vm = vmDao.findByIdIncludingRemoved(vol + .getInstanceId()); + if (vm != null) { + vmName = vm.getInstanceName(); + } + } + + String volumePath = vol.getPath(); + Long poolId = vol.getPoolId(); + if (poolId == null || volumePath == null || volumePath.trim().isEmpty()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Marking volume that was never created as destroyed: " + + vol); + } + this.volDao.remove(vol.getId()); + future.complete(result); + return future; + } + VolumeObject vo = (VolumeObject)volume; + + volume.processEvent(Event.ExpungeRequested); + + DeleteVolumeContext context = new DeleteVolumeContext(null, vo, future); AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().deleteVolumeCallback(null, null)) .setContext(context); - dataObjectMgr.deleteAsync(volume, caller); + volume.getDataStore().getDriver().deleteAsync(volume, caller); return future; } @@ -187,10 +209,10 @@ public class VolumeServiceImpl implements VolumeService { VolumeObject vo = context.getVolume(); VolumeApiResult apiResult = new VolumeApiResult(vo); if (result.isSuccess()) { - vo.stateTransit(Volume.Event.OperationSucceeded); + vo.processEvent(Event.OperationSuccessed); volDao.remove(vo.getId()); } else { - vo.stateTransit(Volume.Event.OperationFailed); + vo.processEvent(Event.OperationFailed); apiResult.setResult(result.getResult()); } context.getFuture().complete(apiResult); @@ -203,24 +225,6 @@ public class VolumeServiceImpl implements VolumeService { return false; } - @Override - public boolean createVolumeFromSnapshot(long volumeId, long snapshotId) { - // TODO Auto-generated method stub - return false; - } - - @Override - public boolean rokeAccess(long volumeId, long endpointId) { - // TODO Auto-generated method stub - return false; - } - - @Override - public VolumeEntity allocateVolumeInDb(long size, VolumeType type, String volName, Long templateId) { - VolumeVO vo = volDao.allocVolume(size, type, volName, templateId); - return new VolumeEntityImpl(VolumeObject.getVolumeObject(null, vo), this); - } - @Override public VolumeEntity getVolumeEntity(long volumeId) { VolumeVO vo = volDao.findById(volumeId); @@ -236,25 +240,21 @@ public class VolumeServiceImpl implements VolumeService { } } - @Override - public String grantAccess(VolumeInfo volume, EndPoint endpointId) { - // TODO Auto-generated method stub - return null; - } - class CreateBaseImageContext extends AsyncRpcConext { private final VolumeInfo volume; private final PrimaryDataStore dataStore; private final TemplateInfo srcTemplate; private final AsyncCallFuture future; + final DataObject destObj; public CreateBaseImageContext(AsyncCompletionCallback callback, VolumeInfo volume, PrimaryDataStore datastore, TemplateInfo srcTemplate, - AsyncCallFuture future) { + AsyncCallFuture future, DataObject destObj) { super(callback); this.volume = volume; this.dataStore = datastore; this.future = future; this.srcTemplate = srcTemplate; + this.destObj = destObj; } public VolumeInfo getVolume() { @@ -285,33 +285,45 @@ public class VolumeServiceImpl implements VolumeService { @DB protected void createBaseImageAsync(VolumeInfo volume, PrimaryDataStore dataStore, TemplateInfo template, AsyncCallFuture future) { + + DataObject templateOnPrimaryStoreObj = dataStore.create(template); CreateBaseImageContext context = new CreateBaseImageContext(null, volume, dataStore, template, - future); - - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + future, templateOnPrimaryStoreObj); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().copyBaseImageCallback(null, null)) .setContext(context); - DataObject templateOnPrimaryStoreObj = dataObjectMgr.createInternalStateOnly(template, dataStore); + + templateOnPrimaryStoreObj.processEvent(Event.CreateOnlyRequested); - dataObjectMgr.copyAsync(context.srcTemplate, templateOnPrimaryStoreObj, caller); + try { + motionSrv.copyAsync(template, templateOnPrimaryStoreObj, caller); + } catch (Exception e) { + s_logger.debug("failed to create template on storage", e); + templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); + VolumeApiResult result = new VolumeApiResult(volume); + result.setResult(e.toString()); + caller.complete(result); + } return; } @DB - protected Void copyBaseImageCallback(AsyncCallbackDispatcher callback, CreateBaseImageContext context) { - CreateCmdResult result = callback.getResult(); + protected Void copyBaseImageCallback(AsyncCallbackDispatcher callback, CreateBaseImageContext context) { + CopyCommandResult result = callback.getResult(); VolumeApiResult res = new VolumeApiResult(context.getVolume()); AsyncCallFuture future = context.getFuture(); + DataObject templateOnPrimaryStoreObj = context.destObj; if (!result.isSuccess()) { + templateOnPrimaryStoreObj.processEvent(Event.OperationFailed); res.setResult(result.getResult()); future.complete(res); return null; } - DataObject templateOnPrimaryStoreObj = objectInDataStoreMgr.get(context.srcTemplate, context.dataStore); - + + templateOnPrimaryStoreObj.processEvent(Event.OperationSuccessed); createVolumeFromBaseImageAsync(context.volume, templateOnPrimaryStoreObj, context.dataStore, future); return null; } @@ -332,10 +344,7 @@ public class VolumeServiceImpl implements VolumeService { this.templateOnStore = templateOnStore; } - public VolumeObject getVolumeObject() { - return this.vo; - } - + public AsyncCallFuture getFuture() { return this.future; } @@ -343,39 +352,32 @@ public class VolumeServiceImpl implements VolumeService { @DB protected void createVolumeFromBaseImageAsync(VolumeInfo volume, DataObject templateOnPrimaryStore, PrimaryDataStore pd, AsyncCallFuture future) { - VolumeObject vo = (VolumeObject) volume; - try { - vo.stateTransit(Volume.Event.CreateRequested); - } catch (Exception e) { - VolumeApiResult result = new VolumeApiResult(volume); - result.setResult(e.toString()); - future.complete(result); - return; - } - + VolumeObject vo = (VolumeObject)volume; CreateVolumeFromBaseImageContext context = new CreateVolumeFromBaseImageContext(null, vo, pd, templateOnPrimaryStore, future); - AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); caller.setCallback(caller.getTarget().copyBaseImageCallBack(null, null)) .setContext(context); - DataObject volumeOnPrimaryStorage = dataObjectMgr.createInternalStateOnly(volume, pd); - dataObjectMgr.copyAsync(context.templateOnStore, volumeOnPrimaryStorage, caller); + DataObject volumeOnPrimaryStorage = pd.create(volume); + volume.processEvent(Event.CreateOnlyRequested); + + motionSrv.copyAsync(context.templateOnStore, volumeOnPrimaryStorage, caller); return; } @DB - public Void copyBaseImageCallBack(AsyncCallbackDispatcher callback, CreateVolumeFromBaseImageContext context) { - VolumeObject vo = context.getVolumeObject(); - CreateCmdResult result = callback.getResult(); + public Void copyBaseImageCallBack(AsyncCallbackDispatcher callback, CreateVolumeFromBaseImageContext context) { + VolumeObject vo = context.vo; + CopyCommandResult result = callback.getResult(); VolumeApiResult volResult = new VolumeApiResult(vo); if (result.isSuccess()) { if (result.getPath() != null) { vo.setPath(result.getPath()); } - vo.stateTransit(Volume.Event.OperationSucceeded); + vo.processEvent(Event.OperationSuccessed); } else { - vo.stateTransit(Volume.Event.OperationFailed); + vo.processEvent(Event.OperationFailed); volResult.setResult(result.getResult()); } @@ -397,13 +399,65 @@ public class VolumeServiceImpl implements VolumeService { return future; } - createVolumeFromBaseImageAsync(volume, template, pd, future); + createVolumeFromBaseImageAsync(volume, templateOnPrimaryStore, pd, future); return future; } @Override - public TemplateOnPrimaryDataStoreInfo grantAccess(TemplateOnPrimaryDataStoreInfo template, EndPoint endPoint) { + @DB + public boolean destroyVolume(long volumeId) + throws ConcurrentOperationException { + + VolumeInfo vol = this.volFactory.getVolume(volumeId); + vol.processEvent(Event.DestroyRequested); + this.snapshotMgr.deletePoliciesForVolume(volumeId); + + vol.processEvent(Event.OperationSuccessed); + + return true; + } + + @Override + public AsyncCallFuture createVolumeFromSnapshot( + VolumeInfo volume, DataStore store, SnapshotInfo snapshot) { // TODO Auto-generated method stub return null; } + + @Override + public AsyncCallFuture copyVolume(VolumeInfo srcVolume, + DataStore destStore) { + // TODO Auto-generated method stub + return null; + } + + @Override + public AsyncCallFuture registerVolume(VolumeInfo volume, DataStore store) { + + AsyncCallFuture future = new AsyncCallFuture(); + VolumeObject vo = (VolumeObject) volume; + vo.stateTransit(Volume.Event.UploadRequested); + + CreateVolumeContext context = new CreateVolumeContext(null, vo, future); + AsyncCallbackDispatcher caller = AsyncCallbackDispatcher.create(this); + caller.setCallback(caller.getTarget().registerVolumeCallback(null, null)) + .setContext(context); + + dataObjectMgr.createAsync(volume, store, caller, true); + return future; + } + + protected Void registerVolumeCallback(AsyncCallbackDispatcher callback, CreateVolumeContext context) { + CreateCmdResult result = callback.getResult(); + VolumeObject vo = (VolumeObject)context.volume; + /*if (result.isFailed()) { + vo.stateTransit(Volume.Event.OperationFailed); + } else { + vo.stateTransit(Volume.Event.OperationSucceeded); + }*/ + VolumeApiResult res = new VolumeApiResult(vo); + context.future.complete(res); + return null; + } + } diff --git a/framework/api/pom.xml b/framework/api/pom.xml new file mode 100644 index 00000000000..3212d7c2644 --- /dev/null +++ b/framework/api/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + cloud-framework-api + + org.apache.cloudstack + cloudstack-framework + 4.1.0-SNAPSHOT + ../pom.xml + + + + + org.apache.cloudstack + cloud-utils + 4.1.0-SNAPSHOT + + + + + + install + src + ${project.basedir}/test + + + ${project.basedir}/test/resources + + + + diff --git a/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java b/framework/api/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java similarity index 100% rename from framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java rename to framework/api/src/org/apache/cloudstack/framework/async/AsyncCallFuture.java diff --git a/framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java b/framework/api/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java similarity index 100% rename from framework/ipc/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java rename to framework/api/src/org/apache/cloudstack/framework/async/AsyncCompletionCallback.java diff --git a/framework/pom.xml b/framework/pom.xml index 4dfb409f04e..4633dab2b30 100644 --- a/framework/pom.xml +++ b/framework/pom.xml @@ -33,5 +33,6 @@ ipc rest events + api diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java index 84c37473a4a..5d7edce12ef 100755 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/VmwareServerDiscoverer.java @@ -60,9 +60,9 @@ import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.user.Account; import com.cloud.utils.UriUtils; diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java index a0540637e95..c2f4923e7e6 100755 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/discoverer/XcpServerDiscoverer.java @@ -79,9 +79,9 @@ import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceStateAdapter; import com.cloud.resource.ServerResource; import com.cloud.resource.UnableDeleteHostException; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.user.Account; diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java index 70660d2bb69..9c291491114 100644 --- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java +++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java @@ -144,6 +144,7 @@ public class XenServerStorageResource { try { obj = Decoder.decode(uriString); + DecodedDataStore store = obj.getStore(); if (obj.getObjType().equalsIgnoreCase("template") && store.getRole().equalsIgnoreCase("image")) { return getTemplateSize(cmd, obj.getPath()); @@ -224,6 +225,7 @@ public class XenServerStorageResource { } protected SR getNfsSR(Connection conn, DecodedDataStore store) { + Map deviceConfig = new HashMap(); String uuid = store.getUuid(); @@ -410,6 +412,7 @@ public class XenServerStorageResource { try { DecodedDataObject obj = Decoder.decode(storeUrl); DecodedDataStore store = obj.getStore(); + if (store.getScheme().equalsIgnoreCase("nfs")) { SR sr = getNfsSR(conn, store); } else if (store.getScheme().equalsIgnoreCase("iscsi")) { @@ -570,7 +573,9 @@ public class XenServerStorageResource { Connection conn = hypervisorResource.getConnection(); try { DecodedDataObject obj = Decoder.decode(dataStoreUri); + DecodedDataStore store = obj.getStore(); + SR sr = hypervisorResource.getStorageRepository(conn, store.getUuid()); hypervisorResource.setupHeartbeatSr(conn, sr, false); long capacity = sr.getPhysicalSize(conn); diff --git a/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java b/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java index 812867ee69d..af21f50cc6f 100644 --- a/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java +++ b/plugins/storage-allocators/random/src/com/cloud/storage/allocator/RandomStoragePoolAllocator.java @@ -21,6 +21,7 @@ import java.util.List; import javax.ejb.Local; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -28,7 +29,6 @@ import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.server.StatsCollector; import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateVO; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; @@ -77,7 +77,8 @@ public class RandomStoragePoolAllocator extends AbstractStoragePoolAllocator { break; } if (checkPool(avoid, pool, dskCh, template, null, sc, plan)) { - suitablePools.add(pool); + StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); + suitablePools.add(pol); } } diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java index 3244c7aa4ed..88c53740f32 100644 --- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java +++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java @@ -24,8 +24,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult; import org.apache.cloudstack.engine.subsystem.api.storage.DataObject; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; import org.apache.cloudstack.framework.async.AsyncCompletionCallback; -import org.apache.cloudstack.storage.snapshot.SnapshotInfo; import org.apache.cloudstack.storage.volume.PrimaryDataStoreDriver; public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver { diff --git a/server/src/com/cloud/alert/AlertManagerImpl.java b/server/src/com/cloud/alert/AlertManagerImpl.java index 4545f0a5e99..f8a8fd8b1b9 100755 --- a/server/src/com/cloud/alert/AlertManagerImpl.java +++ b/server/src/com/cloud/alert/AlertManagerImpl.java @@ -38,6 +38,8 @@ import javax.mail.URLName; import javax.mail.internet.InternetAddress; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -69,8 +71,6 @@ import com.cloud.network.dao.IPAddressDao; import com.cloud.org.Grouping.AllocationState; import com.cloud.resource.ResourceManager; import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.component.ManagerBase; @@ -102,7 +102,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager { @Inject private VolumeDao _volumeDao; @Inject private IPAddressDao _publicIPAddressDao; @Inject private DataCenterIpAddressDao _privateIPAddressDao; - @Inject private StoragePoolDao _storagePoolDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private ConfigurationDao _configDao; @Inject private ResourceManager _resourceMgr; @Inject private ConfigurationManager _configMgr; diff --git a/server/src/com/cloud/api/ApiDBUtils.java b/server/src/com/cloud/api/ApiDBUtils.java index e6b1bf16a03..0a203528f85 100755 --- a/server/src/com/cloud/api/ApiDBUtils.java +++ b/server/src/com/cloud/api/ApiDBUtils.java @@ -45,7 +45,7 @@ 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.api.response.ZoneResponse; - +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; import com.cloud.api.query.dao.AccountJoinDao; @@ -182,10 +182,13 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.*; import com.cloud.storage.Storage.ImageFormat; + import com.cloud.storage.Volume.Type; import com.cloud.storage.dao.*; import com.cloud.storage.snapshot.SnapshotPolicy; +import com.cloud.template.TemplateManager; import com.cloud.user.*; + import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; @@ -218,9 +221,12 @@ public class ApiDBUtils { static AsyncJobManager _asyncMgr; static SecurityGroupManager _securityGroupMgr; static StorageManager _storageMgr; + static VolumeManager _volumeMgr; static UserVmManager _userVmMgr; static NetworkModel _networkModel; static NetworkManager _networkMgr; + static TemplateManager _templateMgr; + static StatsCollector _statsCollector; static AccountDao _accountDao; @@ -321,6 +327,8 @@ public class ApiDBUtils { @Inject private NetworkModel networkModel; @Inject private NetworkManager networkMgr; @Inject private StatsCollector statsCollector; + @Inject private TemplateManager templateMgr; + @Inject private VolumeManager volumeMgr; @Inject private AccountDao accountDao; @Inject private AccountVlanMapDao accountVlanMapDao; @@ -421,6 +429,7 @@ public class ApiDBUtils { _networkModel = networkModel; _networkMgr = networkMgr; _configMgr = configMgr; + _templateMgr = templateMgr; _accountDao = accountDao; _accountVlanMapDao = accountVlanMapDao; @@ -784,7 +793,7 @@ public class ApiDBUtils { List res = _templateHostDao.listByTemplateId(templateId); return res.size() == 0 ? null : res.get(0); } else { - return _storageMgr.getTemplateHostRef(zoneId, templateId, readyOnly); + return _templateMgr.getTemplateHostRef(zoneId, templateId, readyOnly); } } @@ -886,7 +895,7 @@ public class ApiDBUtils { throw new InvalidParameterValueException("Please specify a valid volume ID."); } - return _storageMgr.volumeOnSharedStoragePool(volume); + return _volumeMgr.volumeOnSharedStoragePool(volume); } public static List getNics(VirtualMachine vm) { diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index a94e93568e2..3da31689d1d 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -94,6 +94,7 @@ import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.api.response.VpnUsersResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.cloudstack.api.response.S3Response; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; import com.cloud.async.AsyncJob; @@ -165,6 +166,7 @@ import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; + import com.cloud.storage.snapshot.SnapshotPolicy; import com.cloud.storage.snapshot.SnapshotSchedule; import com.cloud.template.VirtualMachineTemplate; diff --git a/server/src/com/cloud/api/commands/GetUsageRecordsCmd.java b/server/src/com/cloud/api/commands/GetUsageRecordsCmd.java new file mode 100644 index 00000000000..36d66d9dc96 --- /dev/null +++ b/server/src/com/cloud/api/commands/GetUsageRecordsCmd.java @@ -0,0 +1,372 @@ +// 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.commands; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +import org.apache.cloudstack.api.response.AccountResponse; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.log4j.Logger; + +import org.apache.cloudstack.api.ApiConstants; +import com.cloud.api.ApiDBUtils; +import com.cloud.dc.DataCenter; +import com.cloud.domain.Domain; + +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListResponse; +import com.cloud.projects.Project; +import com.cloud.server.ManagementServerExt; +import com.cloud.storage.VMTemplateVO; + +import org.apache.cloudstack.api.response.UsageRecordResponse; + +import com.cloud.usage.UsageTypes; +import com.cloud.usage.UsageVO; +import com.cloud.user.Account; +import com.cloud.uuididentity.dao.IdentityDao; +import com.cloud.uuididentity.dao.IdentityDaoImpl; +import com.cloud.vm.VMInstanceVO; + +@APICommand(name = "listUsageRecords", description="Lists usage records for accounts", responseObject=UsageRecordResponse.class) +public class GetUsageRecordsCmd extends BaseListCmd { + public static final Logger s_logger = Logger.getLogger(GetUsageRecordsCmd.class.getName()); + + private static final String s_name = "listusagerecordsresponse"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name=ApiConstants.ACCOUNT, type=CommandType.STRING, description="List usage records for the specified user.") + private String accountName; + + @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.UUID, entityType = DomainResponse.class, + description="List usage records for the specified domain.") + private Long domainId; + + @Parameter(name=ApiConstants.END_DATE, type=CommandType.DATE, required=true, description="End date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.") + private Date endDate; + + @Parameter(name=ApiConstants.START_DATE, type=CommandType.DATE, required=true, description="Start date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.") + private Date startDate; + + @Parameter(name=ApiConstants.ACCOUNT_ID, type=CommandType.UUID, entityType = AccountResponse.class, + description="List usage records for the specified account") + private Long accountId; + + @Parameter(name=ApiConstants.PROJECT_ID, type=CommandType.UUID, entityType = ProjectResponse.class, + description="List usage records for specified project") + private Long projectId; + + @Parameter(name=ApiConstants.TYPE, type=CommandType.LONG, description="List usage records for the specified usage type") + private Long usageType; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + public Date getEndDate() { + return endDate; + } + + public Date getStartDate() { + return startDate; + } + + public Long getAccountId() { + return accountId; + } + + public Long getUsageType() { + return usageType; + } + + public Long getProjectId() { + return projectId; + } + + ///////////////////////////////////////////////////// + /////////////// Misc parameters /////////////////// + ///////////////////////////////////////////////////// + + private TimeZone usageTimezone; + + public TimeZone getUsageTimezone() { + return usageTimezone; + } + + public void setUsageTimezone(TimeZone tz) { + this.usageTimezone = tz; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return s_name; + } + + public String getDateStringInternal(Date inputDate) { + if (inputDate == null) return null; + + TimeZone tz = getUsageTimezone(); + Calendar cal = Calendar.getInstance(tz); + cal.setTime(inputDate); + + StringBuffer sb = new StringBuffer(); + sb.append(cal.get(Calendar.YEAR)+"-"); + + int month = cal.get(Calendar.MONTH) + 1; + if (month < 10) { + sb.append("0" + month + "-"); + } else { + sb.append(month+"-"); + } + + int day = cal.get(Calendar.DAY_OF_MONTH); + if (day < 10) { + sb.append("0" + day); + } else { + sb.append(""+day); + } + + sb.append("'T'"); + + int hour = cal.get(Calendar.HOUR_OF_DAY); + if (hour < 10) { + sb.append("0" + hour + ":"); + } else { + sb.append(hour+":"); + } + + int minute = cal.get(Calendar.MINUTE); + if (minute < 10) { + sb.append("0" + minute + ":"); + } else { + sb.append(minute+":"); + } + + int seconds = cal.get(Calendar.SECOND); + if (seconds < 10) { + sb.append("0" + seconds); + } else { + sb.append(""+seconds); + } + + double offset = cal.get(Calendar.ZONE_OFFSET); + if (tz.inDaylightTime(inputDate)) { + offset += (1.0*tz.getDSTSavings()); // add the timezone's DST value (typically 1 hour expressed in milliseconds) + } + + offset = offset / (1000d*60d*60d); + int hourOffset = (int)offset; + double decimalVal = Math.abs(offset) - Math.abs(hourOffset); + int minuteOffset = (int)(decimalVal * 60); + + if (hourOffset < 0) { + if (hourOffset > -10) { + sb.append("-0"+Math.abs(hourOffset)); + } else { + sb.append("-"+Math.abs(hourOffset)); + } + } else { + if (hourOffset < 10) { + sb.append("+0" + hourOffset); + } else { + sb.append("+" + hourOffset); + } + } + + sb.append(":"); + + if (minuteOffset == 0) { + sb.append("00"); + } else if (minuteOffset < 10) { + sb.append("0" + minuteOffset); + } else { + sb.append("" + minuteOffset); + } + + return sb.toString(); + } + + @Override + public void execute(){ + ManagementServerExt _mgrExt = (ManagementServerExt)_mgr; + List usageRecords = _mgrExt.getUsageRecords(this); + IdentityDao identityDao = new IdentityDaoImpl(); + ListResponse response = new ListResponse(); + List usageResponses = new ArrayList(); + for (Object usageRecordGeneric : usageRecords) { + UsageRecordResponse usageRecResponse = new UsageRecordResponse(); + if (usageRecordGeneric instanceof UsageVO) { + UsageVO usageRecord = (UsageVO)usageRecordGeneric; + + Account account = ApiDBUtils.findAccountByIdIncludingRemoved(usageRecord.getAccountId()); + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + //find the project + Project project = ApiDBUtils.findProjectByProjectAccountId(account.getId()); + usageRecResponse.setProjectId(project.getUuid()); + usageRecResponse.setProjectName(project.getName()); + } else { + usageRecResponse.setAccountId(account.getUuid()); + usageRecResponse.setAccountName(account.getAccountName()); + } + + Domain domain = ApiDBUtils.findDomainById(usageRecord.getDomainId()); + if (domain != null) { + usageRecResponse.setDomainId(domain.getUuid()); + } + + if (usageRecord.getZoneId() != null) { + DataCenter zone = ApiDBUtils.findZoneById(usageRecord.getZoneId()); + if (zone != null) { + usageRecResponse.setZoneId(zone.getUuid()); + } + } + usageRecResponse.setDescription(usageRecord.getDescription()); + usageRecResponse.setUsage(usageRecord.getUsageDisplay()); + usageRecResponse.setUsageType(usageRecord.getUsageType()); + if (usageRecord.getVmInstanceId() != null) { + VMInstanceVO vm = ApiDBUtils.findVMInstanceById(usageRecord.getVmInstanceId()); + if (vm != null) { + usageRecResponse.setVirtualMachineId(vm.getUuid()); + } + } + usageRecResponse.setVmName(usageRecord.getVmName()); + if (usageRecord.getTemplateId() != null) { + VMTemplateVO template = ApiDBUtils.findTemplateById(usageRecord.getTemplateId()); + if (template != null) { + usageRecResponse.setTemplateId(template.getUuid()); + } + } + + if(usageRecord.getUsageType() == UsageTypes.RUNNING_VM || usageRecord.getUsageType() == UsageTypes.ALLOCATED_VM){ + //Service Offering Id + usageRecResponse.setOfferingId(identityDao.getIdentityUuid("disk_offering", usageRecord.getOfferingId().toString())); + //VM Instance ID + usageRecResponse.setUsageId(identityDao.getIdentityUuid("vm_instance", usageRecord.getUsageId().toString())); + //Hypervisor Type + usageRecResponse.setType(usageRecord.getType()); + + } else if(usageRecord.getUsageType() == UsageTypes.IP_ADDRESS){ + //isSourceNAT + usageRecResponse.setSourceNat((usageRecord.getType().equals("SourceNat"))?true:false); + //isSystem + usageRecResponse.setSystem((usageRecord.getSize() == 1)?true:false); + //IP Address ID + usageRecResponse.setUsageId(identityDao.getIdentityUuid("user_ip_address", usageRecord.getUsageId().toString())); + + } else if(usageRecord.getUsageType() == UsageTypes.NETWORK_BYTES_SENT || usageRecord.getUsageType() == UsageTypes.NETWORK_BYTES_RECEIVED){ + //Device Type + usageRecResponse.setType(usageRecord.getType()); + if(usageRecord.getType().equals("DomainRouter")){ + //Domain Router Id + usageRecResponse.setUsageId(identityDao.getIdentityUuid("vm_instance", usageRecord.getUsageId().toString())); + } else { + //External Device Host Id + usageRecResponse.setUsageId(identityDao.getIdentityUuid("host", usageRecord.getUsageId().toString())); + } + //Network ID + usageRecResponse.setNetworkId(identityDao.getIdentityUuid("networks", usageRecord.getNetworkId().toString())); + + } else if(usageRecord.getUsageType() == UsageTypes.VOLUME){ + //Volume ID + usageRecResponse.setUsageId(identityDao.getIdentityUuid("volumes", usageRecord.getUsageId().toString())); + //Volume Size + usageRecResponse.setSize(usageRecord.getSize()); + //Disk Offering Id + if(usageRecord.getOfferingId() != null){ + usageRecResponse.setOfferingId(identityDao.getIdentityUuid("disk_offering", usageRecord.getOfferingId().toString())); + } + + } else if(usageRecord.getUsageType() == UsageTypes.TEMPLATE || usageRecord.getUsageType() == UsageTypes.ISO){ + //Template/ISO ID + usageRecResponse.setUsageId(identityDao.getIdentityUuid("vm_template", usageRecord.getUsageId().toString())); + //Template/ISO Size + usageRecResponse.setSize(usageRecord.getSize()); + + } else if(usageRecord.getUsageType() == UsageTypes.SNAPSHOT){ + //Snapshot ID + usageRecResponse.setUsageId(identityDao.getIdentityUuid("snapshots", usageRecord.getUsageId().toString())); + //Snapshot Size + usageRecResponse.setSize(usageRecord.getSize()); + + } else if(usageRecord.getUsageType() == UsageTypes.LOAD_BALANCER_POLICY){ + //Load Balancer Policy ID + usageRecResponse.setUsageId(usageRecord.getUsageId().toString()); + + } else if(usageRecord.getUsageType() == UsageTypes.PORT_FORWARDING_RULE){ + //Port Forwarding Rule ID + usageRecResponse.setUsageId(usageRecord.getUsageId().toString()); + + } else if(usageRecord.getUsageType() == UsageTypes.NETWORK_OFFERING){ + //Network Offering Id + usageRecResponse.setOfferingId(identityDao.getIdentityUuid("network_offerings", usageRecord.getOfferingId().toString())); + //is Default + usageRecResponse.setDefault((usageRecord.getUsageId() == 1)? true:false); + + } else if(usageRecord.getUsageType() == UsageTypes.VPN_USERS){ + //VPN User ID + usageRecResponse.setUsageId(usageRecord.getUsageId().toString()); + + } else if(usageRecord.getUsageType() == UsageTypes.SECURITY_GROUP){ + //Security Group Id + usageRecResponse.setUsageId(identityDao.getIdentityUuid("security_group", usageRecord.getUsageId().toString())); + } + + if (usageRecord.getRawUsage() != null) { + DecimalFormat decimalFormat = new DecimalFormat("###########.######"); + usageRecResponse.setRawUsage(decimalFormat.format(usageRecord.getRawUsage())); + } + + if (usageRecord.getStartDate() != null) { + usageRecResponse.setStartDate(getDateStringInternal(usageRecord.getStartDate())); + } + if (usageRecord.getEndDate() != null) { + usageRecResponse.setEndDate(getDateStringInternal(usageRecord.getEndDate())); + } + } + + usageRecResponse.setObjectName("usagerecord"); + usageResponses.add(usageRecResponse); + } + + response.setResponses(usageResponses); + response.setResponseName(getCommandName()); + this.setResponseObject(response); + } +} diff --git a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java index 4440b7a3a10..0cf19fbdfff 100755 --- a/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java +++ b/server/src/com/cloud/baremetal/BareMetalTemplateAdapter.java @@ -37,10 +37,10 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.resource.ResourceManager; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.TemplateProfile; +import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.template.TemplateAdapter; import com.cloud.template.TemplateAdapterBase; diff --git a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java b/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java index 5de5ccdd059..2817fcc32c2 100755 --- a/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java +++ b/server/src/com/cloud/baremetal/BareMetalVmManagerImpl.java @@ -27,19 +27,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; +import org.apache.cloudstack.api.command.user.vm.StartVMCmd; import org.apache.log4j.Logger; -import com.cloud.agent.api.Answer; import com.cloud.agent.api.StopAnswer; -import com.cloud.agent.api.baremetal.IpmISetBootDevCommand; -import com.cloud.agent.api.baremetal.IpmiBootorResetCommand; import com.cloud.agent.manager.Commands; -import org.apache.cloudstack.api.command.user.vm.StartVMCmd; import com.cloud.baremetal.PxeServerManager.PxeServerType; import com.cloud.configuration.Resource.ResourceType; @@ -62,25 +55,18 @@ import com.cloud.org.Grouping; import com.cloud.resource.ResourceManager; import com.cloud.service.ServiceOfferingVO; import com.cloud.storage.Storage; -import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.TemplateProfile; import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.Volume; +import com.cloud.storage.Storage.TemplateType; import com.cloud.template.TemplateAdapter; -import com.cloud.template.TemplateAdapter.TemplateAdapterType; import com.cloud.user.Account; -import com.cloud.user.AccountVO; import com.cloud.user.SSHKeyPair; -import com.cloud.user.User; import com.cloud.user.UserContext; import com.cloud.user.*; import com.cloud.uservm.UserVm; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; -import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.Manager; import com.cloud.utils.concurrency.NamedThreadFactory; -import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.StateListener; import com.cloud.utils.net.NetUtils; @@ -103,7 +89,7 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet @PostConstruct public void init() { } - + /* @Override public boolean attachISOToVM(long vmId, long isoId, boolean attach) { s_logger.warn("attachISOToVM is not supported by Bare Metal, just fake a true"); @@ -131,6 +117,7 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet @Override public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { /*Baremetal creates record after host rebooting for imaging, in createPrivateTemplate*/ + /* return null; } @@ -164,10 +151,12 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet } HostVO pxe = pxes.get(0); + */ /* * prepare() will check if current account has right for creating * template */ + /* TemplateAdapter adapter = AdapterBase.getAdapterByName(_adapters, TemplateAdapterType.BareMetal.getName()); Long userId = UserContext.current().getCallerUserId(); userId = (userId == null ? User.UID_SYSTEM : userId); @@ -202,6 +191,7 @@ public class BareMetalVmManagerImpl extends UserVmManagerImpl implements BareMet throw new CloudRuntimeException(e.getMessage()); } } + */ @Override public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, diff --git a/server/src/com/cloud/capacity/CapacityManager.java b/server/src/com/cloud/capacity/CapacityManager.java index fffb41f87e6..656e744ecf7 100755 --- a/server/src/com/cloud/capacity/CapacityManager.java +++ b/server/src/com/cloud/capacity/CapacityManager.java @@ -16,8 +16,9 @@ // under the License. package com.cloud.capacity; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.host.HostVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateVO; import com.cloud.utils.component.Manager; import com.cloud.vm.VirtualMachine; diff --git a/server/src/com/cloud/capacity/CapacityManagerImpl.java b/server/src/com/cloud/capacity/CapacityManagerImpl.java index 4787c7bb37f..74152ff9c39 100755 --- a/server/src/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/com/cloud/capacity/CapacityManagerImpl.java @@ -27,6 +27,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -57,10 +58,7 @@ import com.cloud.resource.ServerResource; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStoragePoolVO; -import com.cloud.storage.VMTemplateSwiftVO; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.VMTemplatePoolDao; @@ -499,28 +497,9 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, } // Add the size for the templateForVmCreation if its not already present - if ((templateForVmCreation != null) && !tmpinstalled) { - // If the template that was passed into this allocator is not installed in the storage pool, - // add 3 * (template size on secondary storage) to the running total - VMTemplateHostVO templateHostVO = _storageMgr.findVmTemplateHost(templateForVmCreation.getId(), pool); - - if (templateHostVO == null) { - VMTemplateSwiftVO templateSwiftVO = _swiftMgr.findByTmpltId(templateForVmCreation.getId()); - if (templateSwiftVO != null) { - long templateSize = templateSwiftVO.getPhysicalSize(); - if (templateSize == 0) { - templateSize = templateSwiftVO.getSize(); - } - totalAllocatedSize += (templateSize + _extraBytesPerVolume); - } - } else { - long templateSize = templateHostVO.getPhysicalSize(); - if ( templateSize == 0 ){ - templateSize = templateHostVO.getSize(); - } - totalAllocatedSize += (templateSize + _extraBytesPerVolume); - } - } + /*if ((templateForVmCreation != null) && !tmpinstalled) { + + }*/ return totalAllocatedSize; } diff --git a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java index c33bfafc3af..358261470e3 100755 --- a/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/server/src/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -27,13 +27,13 @@ import java.util.Map; import javax.ejb.Local; import javax.inject.Inject; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; import com.cloud.storage.Storage; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.utils.Pair; import com.cloud.utils.db.Filter; diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 168ac0e43cb..69f70e521d8 100755 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -29,14 +29,10 @@ import java.util.UUID; import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import javax.persistence.Table; import org.apache.cloudstack.api.ServerApiException; -import com.cloud.offering.DiskOffering; -import com.cloud.storage.dao.DiskOfferingDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.agent.api.AgentControlAnswer; @@ -102,6 +98,7 @@ import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.rules.RulesManager; +import com.cloud.offering.DiskOffering; import com.cloud.offering.NetworkOffering; import com.cloud.offering.ServiceOffering; import com.cloud.offerings.dao.NetworkOfferingDao; @@ -114,13 +111,14 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.servlet.ConsoleProxyServlet; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; +import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.template.TemplateManager; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.User; @@ -233,6 +231,8 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy @Inject RulesManager _rulesMgr; @Inject + TemplateManager templateMgr; + @Inject IPAddressDao _ipAddressDao; private ConsoleProxyListener _listener; @@ -1175,7 +1175,7 @@ public class ConsoleProxyManagerImpl extends ManagerBase implements ConsoleProxy ZoneHostInfo zoneHostInfo = zoneHostInfoMap.get(dataCenterId); if (zoneHostInfo != null && isZoneHostReady(zoneHostInfo)) { VMTemplateVO template = _templateDao.findSystemVMTemplate(dataCenterId); - HostVO secondaryStorageHost = _storageMgr.getSecondaryStorageHost(dataCenterId); + HostVO secondaryStorageHost = this.templateMgr.getSecondaryStorageHost(dataCenterId); boolean templateReady = false; if (template != null && secondaryStorageHost != null) { diff --git a/server/src/com/cloud/deploy/FirstFitPlanner.java b/server/src/com/cloud/deploy/FirstFitPlanner.java index 66a24ac0e43..b452da06807 100755 --- a/server/src/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/com/cloud/deploy/FirstFitPlanner.java @@ -27,6 +27,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.log4j.Logger; import com.cloud.agent.manager.allocator.HostAllocator; @@ -59,7 +60,6 @@ import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.allocator.StoragePoolAllocator; @@ -99,6 +99,7 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { @Inject protected CapacityDao _capacityDao; @Inject protected AccountManager _accountMgr; @Inject protected StorageManager _storageMgr; + @Inject DataStoreManager dataStoreMgr; //@com.cloud.utils.component.Inject(adapter=StoragePoolAllocator.class) @Inject protected List _storagePoolAllocators; @@ -736,11 +737,11 @@ public class FirstFitPlanner extends PlannerBase implements DeploymentPlanner { if(plan.getPoolId() != null){ s_logger.debug("Volume has pool already allocated, checking if pool can be reused, poolId: "+toBeCreated.getPoolId()); List suitablePools = new ArrayList(); - StoragePoolVO pool; + StoragePool pool = null; if(toBeCreated.getPoolId() != null){ - pool = _storagePoolDao.findById(toBeCreated.getPoolId()); + pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(toBeCreated.getPoolId()); }else{ - pool = _storagePoolDao.findById(plan.getPoolId()); + pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(plan.getPoolId()); } if(!pool.isInMaintenance()){ diff --git a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java index eb27fda1fe8..bba8be5c649 100755 --- a/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java +++ b/server/src/com/cloud/ha/HighAvailabilityManagerImpl.java @@ -31,7 +31,6 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; import org.apache.log4j.NDC; -import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; import com.cloud.alert.AlertManager; @@ -60,6 +59,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.server.ManagementServer; import com.cloud.storage.StorageManager; +import com.cloud.storage.VolumeManager; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; import com.cloud.user.AccountManager; @@ -140,6 +140,8 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai ManagementServer _msServer; @Inject ConfigurationDao _configDao; + @Inject + VolumeManager volumeMgr; String _instance; ScheduledExecutorService _executor; @@ -499,7 +501,7 @@ public class HighAvailabilityManagerImpl extends ManagerBase implements HighAvai return null; // VM doesn't require HA } - if (!_storageMgr.canVmRestartOnAnotherServer(vm.getId())) { + if (!this.volumeMgr.canVmRestartOnAnotherServer(vm.getId())) { if (s_logger.isDebugEnabled()) { s_logger.debug("VM can not restart on another server."); } diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index 79ccdb30198..98044fb5968 100755 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -44,6 +44,7 @@ import org.apache.cloudstack.api.command.admin.storage.AddS3Cmd; import org.apache.cloudstack.api.command.admin.storage.ListS3sCmd; import org.apache.cloudstack.api.command.admin.swift.AddSwiftCmd; import org.apache.cloudstack.api.command.admin.swift.ListSwiftsCmd; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -116,7 +117,6 @@ import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StorageService; import com.cloud.storage.Swift; import com.cloud.storage.SwiftVO; @@ -2223,20 +2223,22 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager, User caller = _accountMgr.getActiveUser(UserContext.current() .getCallerUserId()); - if (forceDestroyStorage) { - // put local storage into mainenance mode, will set all the VMs on - // this local storage into stopped state - StoragePool storagePool = _storageMgr.findLocalStorageOnHost(host + + if (forceDestroyStorage) { + // put local storage into mainenance mode, will set all the VMs on + // this local storage into stopped state + StoragePoolVO storagePool = _storageMgr.findLocalStorageOnHost(host .getId()); if (storagePool != null) { if (storagePool.getStatus() == StoragePoolStatus.Up || storagePool.getStatus() == StoragePoolStatus.ErrorInMaintenance) { - try { - storagePool = _storageSvr + try { + StoragePool pool = _storageSvr .preparePrimaryStorageForMaintenance(storagePool .getId()); - if (storagePool == null) { - s_logger.debug("Failed to set primary storage into maintenance mode"); + if (pool == null) { + s_logger.debug("Failed to set primary storage into maintenance mode"); + throw new UnableDeleteHostException( "Failed to set primary storage into maintenance mode"); } diff --git a/server/src/com/cloud/server/ManagementServer.java b/server/src/com/cloud/server/ManagementServer.java index 5c34deea53b..6773725f361 100755 --- a/server/src/com/cloud/server/ManagementServer.java +++ b/server/src/com/cloud/server/ManagementServer.java @@ -19,11 +19,12 @@ package com.cloud.server; import java.util.Date; import java.util.List; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.event.EventVO; import com.cloud.host.HostVO; import com.cloud.info.ConsoleProxyInfo; import com.cloud.storage.GuestOSVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.utils.Pair; import com.cloud.utils.component.PluggableService; import com.cloud.vm.VirtualMachine; diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index d3812067118..e80d48c6512 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -47,12 +47,12 @@ import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.naming.ConfigurationException; -import com.cloud.storage.dao.*; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ApiConstants; import com.cloud.event.ActionEventUtils; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoCmd; + import org.apache.cloudstack.api.command.admin.account.*; import org.apache.cloudstack.api.command.admin.autoscale.*; import org.apache.cloudstack.api.command.admin.cluster.*; @@ -108,6 +108,8 @@ import org.apache.cloudstack.api.command.user.vpc.*; import org.apache.cloudstack.api.command.user.vpn.*; import org.apache.cloudstack.api.command.user.zone.*; import org.apache.cloudstack.api.response.ExtractResponse; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; @@ -206,15 +208,22 @@ import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.GuestOSVO; import com.cloud.storage.GuestOsCategory; import com.cloud.storage.Storage; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageManager; -import com.cloud.storage.StoragePoolVO; +import com.cloud.storage.StoragePool; import com.cloud.storage.Upload; import com.cloud.storage.Upload.Mode; import com.cloud.storage.UploadVO; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.GuestOSCategoryDao; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.UploadDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.snapshot.SnapshotManager; @@ -222,6 +231,7 @@ import com.cloud.storage.swift.SwiftManager; import com.cloud.storage.upload.UploadMonitor; import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.template.TemplateManager; import com.cloud.template.VirtualMachineTemplate.TemplateFilter; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -390,6 +400,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject HighAvailabilityManager _haMgr; @Inject + TemplateManager templateMgr; + @Inject + DataStoreManager dataStoreMgr; + @Inject HostTagsDao _hostTagsDao; @Inject @@ -2635,8 +2649,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } long accountId = volume.getAccountId(); - StoragePoolVO srcPool = _poolDao.findById(volume.getPoolId()); - HostVO sserver = _storageMgr.getSecondaryStorageHost(zoneId); + StoragePool srcPool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(volume.getPoolId()); + HostVO sserver = this.templateMgr.getSecondaryStorageHost(zoneId); String secondaryStorageURL = sserver.getStorageUrl(); List extractURLList = _uploadDao.listByTypeUploadStatus(volumeId, Upload.Type.VOLUME, UploadVO.Status.DOWNLOAD_URL_CREATED); @@ -2713,7 +2727,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } } - private String getFormatForPool(StoragePoolVO pool) { + private String getFormatForPool(StoragePool pool) { ClusterVO cluster = ApiDBUtils.findClusterById(pool.getClusterId()); if (cluster.getHypervisorType() == HypervisorType.XenServer) { diff --git a/server/src/com/cloud/server/StatsCollector.java b/server/src/com/cloud/server/StatsCollector.java index be83c188f8b..76bae5b4aca 100755 --- a/server/src/com/cloud/server/StatsCollector.java +++ b/server/src/com/cloud/server/StatsCollector.java @@ -29,8 +29,8 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; -import com.cloud.resource.ResourceManager; - +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -49,14 +49,13 @@ import com.cloud.host.HostStats; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; +import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceState; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolHostVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.StorageStats; import com.cloud.storage.VolumeStats; import com.cloud.storage.VolumeVO; -import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.secondary.SecondaryStorageVmManager; @@ -84,7 +83,7 @@ public class StatsCollector { @Inject private HostDao _hostDao; @Inject private UserVmDao _userVmDao; @Inject private VolumeDao _volsDao; - @Inject private StoragePoolDao _storagePoolDao; + @Inject private PrimaryDataStoreDao _storagePoolDao; @Inject private StorageManager _storageManager; @Inject private StoragePoolHostDao _storagePoolHostDao; @Inject private SecondaryStorageVmManager _ssvmMgr; @@ -301,7 +300,7 @@ public class StatsCollector { GetStorageStatsCommand command = new GetStorageStatsCommand(pool.getUuid(), pool.getPoolType(), pool.getPath()); long poolId = pool.getId(); try { - Answer answer = _storageManager.sendToPool(pool, command); + Answer answer = _storageManager.sendToPool(pool.getId(), command); if (answer != null && answer.getResult()) { storagePoolStats.put(pool.getId(), (StorageStats)answer); diff --git a/server/src/com/cloud/storage/LocalStoragePoolListener.java b/server/src/com/cloud/storage/LocalStoragePoolListener.java index 8d5875e9d76..a04c79cf435 100755 --- a/server/src/com/cloud/storage/LocalStoragePoolListener.java +++ b/server/src/com/cloud/storage/LocalStoragePoolListener.java @@ -16,8 +16,6 @@ // under the License. package com.cloud.storage; -import java.util.List; - import javax.inject.Inject; import org.apache.log4j.Logger; @@ -30,20 +28,14 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupStorageCommand; import com.cloud.agent.api.StoragePoolInfo; -import com.cloud.capacity.Capacity; -import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDao; -import com.cloud.dc.DataCenterVO; import com.cloud.dc.dao.DataCenterDao; import com.cloud.exception.ConnectionException; import com.cloud.host.HostVO; import com.cloud.host.Status; -import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.dao.StoragePoolDao; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.utils.db.DB; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; public class LocalStoragePoolListener implements Listener { private final static Logger s_logger = Logger.getLogger(LocalStoragePoolListener.class); @@ -91,63 +83,7 @@ public class LocalStoragePoolListener implements Listener { return; } - DataCenterVO dc = _dcDao.findById(host.getDataCenterId()); - if (dc == null || !dc.isLocalStorageEnabled()) { - return; - } - - try { - StoragePoolVO pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), pInfo.getHostPath(), pInfo.getUuid()); - if(pool == null && host.getHypervisorType() == HypervisorType.VMware) { - // perform run-time upgrade. In versions prior to 2.2.12, there is a bug that we don't save local datastore info (host path is empty), this will cause us - // not able to distinguish multiple local datastores that may be available on the host, to support smooth migration, we - // need to perform runtime upgrade here - if(pInfo.getHostPath().length() > 0) { - pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), "", pInfo.getUuid()); - } - } - - if (pool == null) { - - long poolId = _storagePoolDao.getNextInSequence(Long.class, "id"); - String name = cmd.getName() == null ? (host.getName() + " Local Storage") : cmd.getName(); - Transaction txn = Transaction.currentTxn(); - txn.start(); - pool = new StoragePoolVO(poolId, name, pInfo.getUuid(), pInfo.getPoolType(), host.getDataCenterId(), - host.getPodId(), pInfo.getAvailableBytes(), pInfo.getCapacityBytes(), pInfo.getHost(), 0, - pInfo.getHostPath()); - pool.setClusterId(host.getClusterId()); - pool.setStatus(StoragePoolStatus.Up); - _storagePoolDao.persist(pool, pInfo.getDetails()); - StoragePoolHostVO poolHost = new StoragePoolHostVO(pool.getId(), host.getId(), pInfo.getLocalPath()); - _storagePoolHostDao.persist(poolHost); - _storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getCapacityBytes() - pool.getAvailableBytes()); - - txn.commit(); - } else { - Transaction txn = Transaction.currentTxn(); - txn.start(); - pool.setPath(pInfo.getHostPath()); - pool.setAvailableBytes(pInfo.getAvailableBytes()); - pool.setCapacityBytes(pInfo.getCapacityBytes()); - _storagePoolDao.update(pool.getId(), pool); - if (pInfo.getDetails() != null) { - _storagePoolDao.updateDetails(pool.getId(), pInfo.getDetails()); - } - StoragePoolHostVO poolHost = _storagePoolHostDao.findByPoolHost(pool.getId(), host.getId()); - if (poolHost == null) { - poolHost = new StoragePoolHostVO(pool.getId(), host.getId(), pInfo.getLocalPath()); - _storagePoolHostDao.persist(poolHost); - } - - _storageMgr.createCapacityEntry(pool, Capacity.CAPACITY_TYPE_LOCAL_STORAGE, pool.getCapacityBytes() - pool.getAvailableBytes()); - - txn.commit(); - } - } catch (Exception e) { - s_logger.warn("Unable to setup the local storage pool for " + host, e); - throw new ConnectionException(true, "Unable to setup the local storage pool for " + host, e); - } + this._storageMgr.createLocalStorage(host, pInfo); } diff --git a/server/src/com/cloud/storage/OCFS2ManagerImpl.java b/server/src/com/cloud/storage/OCFS2ManagerImpl.java index 6bbeec40551..5c526a69e4f 100755 --- a/server/src/com/cloud/storage/OCFS2ManagerImpl.java +++ b/server/src/com/cloud/storage/OCFS2ManagerImpl.java @@ -25,6 +25,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; diff --git a/server/src/com/cloud/storage/RegisterVolumePayload.java b/server/src/com/cloud/storage/RegisterVolumePayload.java new file mode 100644 index 00000000000..142de186e25 --- /dev/null +++ b/server/src/com/cloud/storage/RegisterVolumePayload.java @@ -0,0 +1,43 @@ +/* + * 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.storage; + +public class RegisterVolumePayload { + private final String url; + private final String checksum; + private final String format; + + public RegisterVolumePayload(String url, String checksum, String format) { + this.url = url; + this.checksum = checksum; + this.format = format; + } + + public String getUrl() { + return this.url; + } + + public String getChecksum() { + return this.checksum; + } + + public String getFormat() { + return this.format; + } +} diff --git a/server/src/com/cloud/storage/StorageManager.java b/server/src/com/cloud/storage/StorageManager.java index 97853ac76de..9213b4bf486 100755 --- a/server/src/com/cloud/storage/StorageManager.java +++ b/server/src/com/cloud/storage/StorageManager.java @@ -17,50 +17,29 @@ package com.cloud.storage; import java.util.List; +import java.util.Set; + +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; +import com.cloud.agent.api.StoragePoolInfo; import com.cloud.agent.manager.Commands; import com.cloud.capacity.CapacityVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; -import com.cloud.deploy.DeployDestination; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientStorageCapacityException; +import com.cloud.exception.ConnectionException; import com.cloud.exception.StorageUnavailableException; 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.Storage.ImageFormat; -import com.cloud.storage.Volume.Event; -import com.cloud.storage.Volume.Type; -import com.cloud.user.Account; import com.cloud.utils.Pair; -import com.cloud.utils.component.Manager; -import com.cloud.utils.fsm.NoTransitionException; import com.cloud.vm.DiskProfile; import com.cloud.vm.VMInstanceVO; -import com.cloud.vm.VirtualMachine; -import com.cloud.vm.VirtualMachineProfile; - -public interface StorageManager extends StorageService, Manager { - boolean canVmRestartOnAnotherServer(long vmId); - - /** Returns the absolute path of the specified ISO - * @param templateId - the ID of the template that represents the ISO - * @param datacenterId - * @return absolute ISO path - */ - public Pair getAbsoluteIsoPath(long templateId, long dataCenterId); - - /** - * Returns the URL of the secondary storage host - * @param zoneId - * @return URL - */ - public String getSecondaryStorageURL(long zoneId); +public interface StorageManager extends StorageService { /** * Returns a comma separated list of tags for the specified storage pool * @param poolId @@ -68,67 +47,9 @@ public interface StorageManager extends StorageService, Manager { */ public String getStoragePoolTags(long poolId); - /** - * Returns the secondary storage host - * @param zoneId - * @return secondary storage host - */ - public HostVO getSecondaryStorageHost(long zoneId); + - /** - * Returns the secondary storage host - * @param zoneId - * @return secondary storage host - */ - public VMTemplateHostVO findVmTemplateHost(long templateId, StoragePool pool); - /** - * Moves a volume from its current storage pool to a storage pool with enough capacity in the specified zone, pod, or cluster - * @param volume - * @param destPoolDcId - * @param destPoolPodId - * @param destPoolClusterId - * @return VolumeVO - * @throws ConcurrentOperationException - */ - VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException; - - /** - * Create a volume based on the given criteria - * @param volume - * @param vm - * @param template - * @param dc - * @param pod - * @param clusterId - * @param offering - * @param diskOffering - * @param avoids - * @param size - * @param hyperType - * @return volume VO if success, null otherwise - */ - VolumeVO createVolume(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, - ServiceOfferingVO offering, DiskOfferingVO diskOffering, List avoids, long size, HypervisorType hyperType); - - /** - * Marks the specified volume as destroyed in the management server database. The expunge thread will delete the volume from its storage pool. - * @param volume - * @return - */ - boolean destroyVolume(VolumeVO volume) throws ConcurrentOperationException; - - /** Create capacity entries in the op capacity table - * @param storagePool - */ - public void createCapacityEntry(StoragePoolVO storagePool); - - /** - * Checks that the volume is stored on a shared storage pool - * @param volume - * @return true if the volume is on a shared storage pool, false otherwise - */ - boolean volumeOnSharedStoragePool(VolumeVO volume); Answer sendToPool(long poolId, Command cmd) throws StorageUnavailableException; Answer sendToPool(StoragePool pool, Command cmd) throws StorageUnavailableException; @@ -137,17 +58,6 @@ public interface StorageManager extends StorageService, Manager { Pair sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List hostIdsToAvoid, Commands cmds) throws StorageUnavailableException; Pair sendToPool(StoragePool pool, long[] hostIdsToTryFirst, List hostIdsToAvoid, Command cmd) throws StorageUnavailableException; - /** - * Checks that one of the following is true: - * 1. The volume is not attached to any VM - * 2. The volume is attached to a VM that is running on a host with the KVM hypervisor, and the VM is stopped - * 3. The volume is attached to a VM that is running on a host with the XenServer hypervisor (the VM can be stopped or running) - * @return true if one of the above conditions is true - */ - boolean volumeInactive(VolumeVO volume); - - String getVmNameOnVolume(VolumeVO volume); - /** * Checks if a host has running VMs that are using its local storage pool. * @return true if local storage is active on the host @@ -162,31 +72,10 @@ public interface StorageManager extends StorageService, Manager { String getPrimaryStorageNameLabel(VolumeVO volume); - /** - * Allocates one volume. - * @param - * @param type - * @param offering - * @param name - * @param size - * @param template - * @param vm - * @param account - * @return VolumeVO a persisted volume. - */ - DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, T vm, Account owner); - DiskProfile allocateTemplatedVolume(Type type, String name, DiskOfferingVO offering, VMTemplateVO template, T vm, Account owner); void createCapacityEntry(StoragePoolVO storagePool, short capacityType, long allocated); - void prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException, ConcurrentOperationException; - - void release(VirtualMachineProfile profile); - - void cleanupVolumes(long vmId) throws ConcurrentOperationException; - - void prepareForMigration(VirtualMachineProfile vm, DeployDestination dest); Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException; @@ -194,14 +83,6 @@ public interface StorageManager extends StorageService, Manager { CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, Long podId, Long zoneId); - boolean createStoragePool(long hostId, StoragePoolVO pool); - - boolean delPoolFromHost(long hostId); - - HostVO getSecondaryStorageHost(long zoneId, long tmpltId); - - List getSecondaryStorageHosts(long zoneId); - List ListByDataCenterHypervisor(long datacenterId, HypervisorType type); @@ -209,34 +90,34 @@ public interface StorageManager extends StorageService, Manager { StoragePoolVO findLocalStorageOnHost(long hostId); - VMTemplateHostVO getTemplateHostRef(long zoneId, long tmpltId, boolean readyOnly); - - boolean StorageMigration( - VirtualMachineProfile vm, - StoragePool destPool) throws ConcurrentOperationException; - - boolean stateTransitTo(Volume vol, Event event) - throws NoTransitionException; - - VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId); - Host updateSecondaryStorage(long secStorageId, String newUrl); List getUpHostsInPool(long poolId); void cleanupSecondaryStorage(boolean recurring); - VolumeVO copyVolumeFromSecToPrimary(VolumeVO volume, VMInstanceVO vm, - VMTemplateVO template, DataCenterVO dc, HostPodVO pod, - Long clusterId, ServiceOfferingVO offering, - DiskOfferingVO diskOffering, List avoids, long size, - HypervisorType hyperType) throws NoTransitionException; - - String getSupportedImageFormatForCluster(Long clusterId); HypervisorType getHypervisorTypeFromFormat(ImageFormat format); boolean storagePoolHasEnoughSpace(List volume, StoragePool pool); - boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException; + + boolean registerHostListener(String providerUuid, HypervisorHostListener listener); + + StoragePool findStoragePool(DiskProfile dskCh, DataCenterVO dc, + HostPodVO pod, Long clusterId, Long hostId, VMInstanceVO vm, + Set avoid); + + + void connectHostToSharedPool(long hostId, long poolId) + throws StorageUnavailableException; + + void createCapacityEntry(long poolId); + + + + + + DataStore createLocalStorage(Host host, StoragePoolInfo poolInfo) throws ConnectionException; + } diff --git a/server/src/com/cloud/storage/StorageManagerImpl.java b/server/src/com/cloud/storage/StorageManagerImpl.java index 05e0cfe9869..f2d92e590d2 100755 --- a/server/src/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/com/cloud/storage/StorageManagerImpl.java @@ -17,8 +17,6 @@ package com.cloud.storage; import java.math.BigDecimal; -import java.net.Inet6Address; -import java.net.InetAddress; import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; @@ -27,15 +25,13 @@ import java.sql.ResultSet; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; -import java.util.UUID; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -48,17 +44,41 @@ import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaint import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd; import org.apache.cloudstack.api.command.admin.storage.DeletePoolCmd; import org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd; -import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreStatus; +import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; +import org.apache.cloudstack.engine.subsystem.api.storage.HypervisorHostListener; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.framework.async.AsyncCallFuture; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; -import com.cloud.agent.api.*; -import com.cloud.agent.api.storage.*; -import com.cloud.agent.api.to.StorageFilerTO; -import com.cloud.agent.api.to.VolumeTO; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.BackupSnapshotCommand; +import com.cloud.agent.api.CleanupSnapshotBackupCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.ManageSnapshotCommand; +import com.cloud.agent.api.StoragePoolInfo; +import com.cloud.agent.api.storage.DeleteTemplateCommand; +import com.cloud.agent.api.storage.DeleteVolumeCommand; + import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; import com.cloud.api.ApiDBUtils; @@ -72,46 +92,61 @@ import com.cloud.cluster.ClusterManagerListener; import com.cloud.cluster.ManagementServerHostVO; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; -import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.consoleproxy.ConsoleProxyManager; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; -import com.cloud.dc.Pod; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; -import com.cloud.deploy.DeployDestination; -import com.cloud.domain.Domain; import com.cloud.domain.dao.DomainDao; -import com.cloud.event.ActionEvent; -import com.cloud.event.EventTypes; -import com.cloud.event.UsageEventUtils; + import com.cloud.event.dao.EventDao; -import com.cloud.exception.*; +import com.cloud.event.dao.UsageEventDao; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.ConnectionException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.OperationTimedoutException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceInUseException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.StorageUnavailableException; + import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuruManager; +import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.network.NetworkModel; -import com.cloud.offering.ServiceOffering; import com.cloud.org.Grouping; import com.cloud.org.Grouping.AllocationState; import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceState; import com.cloud.server.ManagementServer; import com.cloud.server.StatsCollector; -import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.storage.Volume.Event; import com.cloud.storage.Volume.Type; import com.cloud.storage.allocator.StoragePoolAllocator; -import com.cloud.storage.dao.*; + +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotPolicyDao; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.StoragePoolWorkDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateS3Dao; +import com.cloud.storage.dao.VMTemplateSwiftDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; + import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.listener.StoragePoolMonitor; import com.cloud.storage.listener.VolumeStateListener; @@ -124,23 +159,24 @@ import com.cloud.template.TemplateManager; import com.cloud.user.*; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserDao; -import com.cloud.uservm.UserVm; -import com.cloud.utils.EnumUtils; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.UriUtils; import com.cloud.utils.component.ComponentContext; -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.*; import com.cloud.utils.db.JoinBuilder.JoinType; import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.exception.CloudRuntimeException; -import com.cloud.utils.exception.ExecutionException; -import com.cloud.utils.fsm.NoTransitionException; -import com.cloud.utils.fsm.StateMachine2; -import com.cloud.vm.*; + +import com.cloud.vm.DiskProfile; +import com.cloud.vm.UserVmManager; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachineManager; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VirtualMachineProfileImpl; + import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.*; @@ -173,6 +209,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Inject protected NetworkModel _networkMgr; @Inject + protected ServiceOfferingDao _serviceOfferingDao; + @Inject protected VolumeDao _volsDao; @Inject protected HostDao _hostDao; @@ -209,7 +247,7 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Inject protected VMInstanceDao _vmInstanceDao; @Inject - protected StoragePoolDao _storagePoolDao = null; + protected PrimaryDataStoreDao _storagePoolDao = null; @Inject protected CapacityDao _capacityDao; @Inject @@ -262,14 +300,30 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C protected ResourceTagDao _resourceTagDao; @Inject protected List _storagePoolAllocators; - @Inject ConfigurationDao _configDao; - @Inject ManagementServer _msServer; + @Inject + ConfigurationDao _configDao; + @Inject + ManagementServer _msServer; + @Inject + DataStoreManager dataStoreMgr; + @Inject + DataStoreProviderManager dataStoreProviderMgr; + @Inject + VolumeService volService; + @Inject + VolumeDataFactory volFactory; + @Inject + ImageDataFactory tmplFactory; + @Inject + SnapshotDataFactory snapshotFactory; + @Inject + protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; - // TODO : we don't have any instantiated pool discover, disable injection temporarily + // TODO : we don't have any instantiated pool discover, disable injection + // temporarily // @Inject protected List _discoverers; - protected SearchBuilder HostTemplateStatesSearch; protected GenericSearchBuilder UpHostsInPoolSearch; protected SearchBuilder StoragePoolSearch; @@ -288,32 +342,39 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C protected BigDecimal _overProvisioningFactor = new BigDecimal(1); private long _maxVolumeSizeInGb; private long _serverId; - private final StateMachine2 _volStateMachine; + private int _customDiskOfferingMinSize = 1; private int _customDiskOfferingMaxSize = 1024; private double _storageUsedThreshold = 1.0d; private double _storageAllocatedThreshold = 1.0d; protected BigDecimal _storageOverprovisioningFactor = new BigDecimal(1); + private Map hostListeners = new HashMap(); private boolean _recreateSystemVmEnabled; - public boolean share(VMInstanceVO vm, List vols, HostVO host, boolean cancelPreviousShare) throws StorageUnavailableException { + public boolean share(VMInstanceVO vm, List vols, HostVO host, + boolean cancelPreviousShare) throws StorageUnavailableException { // if pool is in maintenance and it is the ONLY pool available; reject - List rootVolForGivenVm = _volsDao.findByInstanceAndType(vm.getId(), Type.ROOT); + List rootVolForGivenVm = _volsDao.findByInstanceAndType( + vm.getId(), Type.ROOT); if (rootVolForGivenVm != null && rootVolForGivenVm.size() > 0) { - boolean isPoolAvailable = isPoolAvailable(rootVolForGivenVm.get(0).getPoolId()); + boolean isPoolAvailable = isPoolAvailable(rootVolForGivenVm.get(0) + .getPoolId()); if (!isPoolAvailable) { - throw new StorageUnavailableException("Can not share " + vm, rootVolForGivenVm.get(0).getPoolId()); + throw new StorageUnavailableException("Can not share " + vm, + rootVolForGivenVm.get(0).getPoolId()); } } // this check is done for maintenance mode for primary storage // if any one of the volume is unusable, we return false - // if we return false, the allocator will try to switch to another PS if available + // if we return false, the allocator will try to switch to another PS if + // available for (VolumeVO vol : vols) { if (vol.getRemoved() != null) { - s_logger.warn("Volume id:" + vol.getId() + " is removed, cannot share on this instance"); + s_logger.warn("Volume id:" + vol.getId() + + " is removed, cannot share on this instance"); // not ok to share return false; } @@ -323,26 +384,15 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return true; } - @Override - public VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId) { - VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), oldVol.getDiskOfferingId(), oldVol.getSize()); - if (templateId != null) { - newVol.setTemplateId(templateId); - } else { - newVol.setTemplateId(oldVol.getTemplateId()); - } - newVol.setDeviceId(oldVol.getDeviceId()); - newVol.setInstanceId(oldVol.getInstanceId()); - newVol.setRecreatable(oldVol.isRecreatable()); - return _volsDao.persist(newVol); - } - private boolean isPoolAvailable(Long poolId) { // get list of all pools List pools = _storagePoolDao.listAll(); // if no pools or 1 pool which is in maintenance - if (pools == null || pools.size() == 0 || (pools.size() == 1 && pools.get(0).getStatus().equals(StoragePoolStatus.Maintenance))) { + if (pools == null + || pools.size() == 0 + || (pools.size() == 1 && pools.get(0).getStatus() + .equals(DataStoreStatus.Maintenance))) { return false; } else { return true; @@ -350,8 +400,10 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public List ListByDataCenterHypervisor(long datacenterId, HypervisorType type) { - List pools = _storagePoolDao.listByDataCenterId(datacenterId); + public List ListByDataCenterHypervisor( + long datacenterId, HypervisorType type) { + List pools = _storagePoolDao + .listByDataCenterId(datacenterId); List retPools = new ArrayList(); for (StoragePoolVO pool : pools) { if (pool.getStatus() != StoragePoolStatus.Up) { @@ -368,21 +420,33 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Override public boolean isLocalStorageActiveOnHost(Long hostId) { - List storagePoolHostRefs = _storagePoolHostDao.listByHostId(hostId); + List storagePoolHostRefs = _storagePoolHostDao + .listByHostId(hostId); for (StoragePoolHostVO storagePoolHostRef : storagePoolHostRefs) { - StoragePoolVO storagePool = _storagePoolDao.findById(storagePoolHostRef.getPoolId()); - if (storagePool.getPoolType() == StoragePoolType.LVM || storagePool.getPoolType() == StoragePoolType.EXT) { - SearchBuilder volumeSB = _volsDao.createSearchBuilder(); - volumeSB.and("poolId", volumeSB.entity().getPoolId(), SearchCriteria.Op.EQ); - volumeSB.and("removed", volumeSB.entity().getRemoved(), SearchCriteria.Op.NULL); + StoragePoolVO PrimaryDataStoreVO = _storagePoolDao + .findById(storagePoolHostRef.getPoolId()); + if (PrimaryDataStoreVO.getPoolType() == StoragePoolType.LVM + || PrimaryDataStoreVO.getPoolType() == StoragePoolType.EXT) { + SearchBuilder volumeSB = _volsDao + .createSearchBuilder(); + volumeSB.and("poolId", volumeSB.entity().getPoolId(), + SearchCriteria.Op.EQ); + volumeSB.and("removed", volumeSB.entity().getRemoved(), + SearchCriteria.Op.NULL); - SearchBuilder activeVmSB = _vmInstanceDao.createSearchBuilder(); - activeVmSB.and("state", activeVmSB.entity().getState(), SearchCriteria.Op.IN); - volumeSB.join("activeVmSB", activeVmSB, volumeSB.entity().getInstanceId(), activeVmSB.entity().getId(), JoinBuilder.JoinType.INNER); + SearchBuilder activeVmSB = _vmInstanceDao + .createSearchBuilder(); + activeVmSB.and("state", activeVmSB.entity().getState(), + SearchCriteria.Op.IN); + volumeSB.join("activeVmSB", activeVmSB, volumeSB.entity() + .getInstanceId(), activeVmSB.entity().getId(), + JoinBuilder.JoinType.INNER); SearchCriteria volumeSC = volumeSB.create(); - volumeSC.setParameters("poolId", storagePool.getId()); - volumeSC.setJoinParameters("activeVmSB", "state", State.Starting, State.Running, State.Stopping, State.Migrating); + volumeSC.setParameters("poolId", PrimaryDataStoreVO.getId()); + volumeSC.setJoinParameters("activeVmSB", "state", + State.Starting, State.Running, State.Stopping, + State.Migrating); List volumes = _volsDao.search(volumeSC, null); if (volumes.size() > 0) { @@ -394,26 +458,35 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return false; } - protected StoragePoolVO findStoragePool(DiskProfile dskCh, final DataCenterVO dc, HostPodVO pod, Long clusterId, Long hostId, VMInstanceVO vm, final Set avoid) { + @Override + public StoragePool findStoragePool(DiskProfile dskCh, + final DataCenterVO dc, HostPodVO pod, Long clusterId, Long hostId, + VMInstanceVO vm, final Set avoid) { - VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); + VirtualMachineProfile profile = new VirtualMachineProfileImpl( + vm); for (StoragePoolAllocator allocator : _storagePoolAllocators) { - final List poolList = allocator.allocateToPool(dskCh, profile, dc.getId(), pod.getId(), clusterId, hostId, avoid, 1); + final List poolList = allocator.allocateToPool( + dskCh, profile, dc.getId(), pod.getId(), clusterId, hostId, + avoid, 1); if (poolList != null && !poolList.isEmpty()) { - return (StoragePoolVO) poolList.get(0); + return (StoragePool)this.dataStoreMgr.getDataStore(poolList.get(0).getId(), DataStoreRole.Primary); } } return null; } @Override - public Answer[] sendToPool(StoragePool pool, Commands cmds) throws StorageUnavailableException { + public Answer[] sendToPool(StoragePool pool, Commands cmds) + throws StorageUnavailableException { return sendToPool(pool, null, null, cmds).second(); } @Override - public Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, Command cmd) throws StorageUnavailableException { - Answer[] answers = sendToPool(pool, hostIdsToTryFirst, null, new Commands(cmd)).second(); + public Answer sendToPool(StoragePool pool, long[] hostIdsToTryFirst, + Command cmd) throws StorageUnavailableException { + Answer[] answers = sendToPool(pool, hostIdsToTryFirst, null, + new Commands(cmd)).second(); if (answers == null) { return null; } @@ -421,7 +494,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public Answer sendToPool(StoragePool pool, Command cmd) throws StorageUnavailableException { + public Answer sendToPool(StoragePool pool, Command cmd) + throws StorageUnavailableException { Answer[] answers = sendToPool(pool, new Commands(cmd)); if (answers == null) { return null; @@ -429,439 +503,27 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return answers[0]; } - @Override - public Answer sendToPool(long poolId, Command cmd) throws StorageUnavailableException { - StoragePool pool = _storagePoolDao.findById(poolId); - return sendToPool(pool, cmd); - } - - @Override - public Answer[] sendToPool(long poolId, Commands cmds) throws StorageUnavailableException { - StoragePool pool = _storagePoolDao.findById(poolId); - return sendToPool(pool, cmds); - } - - protected DiskProfile createDiskCharacteristics(VolumeVO volume, VMTemplateVO template, DataCenterVO dc, DiskOfferingVO diskOffering) { - if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { - SearchCriteria sc = HostTemplateStatesSearch.create(); - sc.setParameters("id", template.getId()); - sc.setParameters("state", com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); - sc.setJoinParameters("host", "dcId", dc.getId()); - - List sss = _vmTemplateHostDao.search(sc, null); - if (sss.size() == 0) { - throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + dc.getId()); - } - VMTemplateHostVO ss = sss.get(0); - - return new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), diskOffering.getId(), ss.getSize(), diskOffering.getTagsArray(), diskOffering.getUseLocalStorage(), - diskOffering.isRecreatable(), Storage.ImageFormat.ISO != template.getFormat() ? template.getId() : null); - } else { - return new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), diskOffering.getId(), diskOffering.getDiskSize(), diskOffering.getTagsArray(), - diskOffering.getUseLocalStorage(), diskOffering.isRecreatable(), null); - } - } - - @Override - public boolean canVmRestartOnAnotherServer(long vmId) { - List vols = _volsDao.findCreatedByInstance(vmId); - for (VolumeVO vol : vols) { - if (!vol.isRecreatable() && !vol.getPoolType().isShared()) { - return false; - } - } - return true; - } - - @DB - protected Pair createVolumeFromSnapshot(VolumeVO volume, SnapshotVO snapshot) { - VolumeVO createdVolume = null; - Long volumeId = volume.getId(); - - String volumeFolder = null; - - try { - stateTransitTo(volume, Volume.Event.CreateRequested); - } catch (NoTransitionException e) { - s_logger.debug(e.toString()); - return null; - } - // Create the Volume object and save it so that we can return it to the user - Account account = _accountDao.findById(volume.getAccountId()); - - final HashSet poolsToAvoid = new HashSet(); - StoragePoolVO pool = null; - boolean success = false; - Set podsToAvoid = new HashSet(); - Pair pod = null; - String volumeUUID = null; - String details = null; - - DiskOfferingVO diskOffering = _diskOfferingDao.findByIdIncludingRemoved(volume.getDiskOfferingId()); - DataCenterVO dc = _dcDao.findById(volume.getDataCenterId()); - DiskProfile dskCh = new DiskProfile(volume, diskOffering, snapshot.getHypervisorType()); - - int retry = 0; - // Determine what pod to store the volume in - while ((pod = _resourceMgr.findPod(null, null, dc, account.getId(), podsToAvoid)) != null) { - podsToAvoid.add(pod.first().getId()); - // Determine what storage pool to store the volume in - while ((pool = findStoragePool(dskCh, dc, pod.first(), null, null, null, poolsToAvoid)) != null) { - poolsToAvoid.add(pool); - volumeFolder = pool.getPath(); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Attempting to create volume from snapshotId: " + snapshot.getId() + " on storage pool " + pool.getName()); - } - - // Get the newly created VDI from the snapshot. - // This will return a null volumePath if it could not be created - Pair volumeDetails = createVDIFromSnapshot(UserContext.current().getCallerUserId(), snapshot, pool); - - volumeUUID = volumeDetails.first(); - details = volumeDetails.second(); - - if (volumeUUID != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume with UUID " + volumeUUID + " was created on storage pool " + pool.getName()); - } - success = true; - break; // break out of the "find storage pool" loop - } else { - retry++; - if (retry >= 3) { - _volsDao.expunge(volumeId); - String msg = "Unable to create volume from snapshot " + snapshot.getId() + " after retrying 3 times, due to " + details; - s_logger.debug(msg); - throw new CloudRuntimeException(msg); - - } - } - s_logger.warn("Unable to create volume on pool " + pool.getName() + ", reason: " + details); - } - - if (success) { - break; // break out of the "find pod" loop - } - } - - if (!success) { - _volsDao.expunge(volumeId); - String msg = "Unable to create volume from snapshot " + snapshot.getId() + " due to " + details; - s_logger.debug(msg); - throw new CloudRuntimeException(msg); - - } - - createdVolume = _volsDao.findById(volumeId); - - try { - if (success) { - createdVolume.setPodId(pod.first().getId()); - createdVolume.setPoolId(pool.getId()); - createdVolume.setPoolType(pool.getPoolType()); - createdVolume.setFolder(volumeFolder); - createdVolume.setPath(volumeUUID); - createdVolume.setDomainId(account.getDomainId()); - stateTransitTo(createdVolume, Volume.Event.OperationSucceeded); - } - } catch (NoTransitionException e) { - s_logger.debug("Failed to update volume state: " + e.toString()); - return null; - } - - return new Pair(createdVolume, details); - } - - @Override - public boolean stateTransitTo(Volume vol, Volume.Event event) throws NoTransitionException { - return _volStateMachine.transitTo(vol, event, null, _volsDao); - } - - protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId) { - - // By default, assume failure. - VolumeVO createdVolume = null; - SnapshotVO snapshot = _snapshotDao.findById(snapshotId); // Precondition: snapshot is not null and not removed. - - Pair volumeDetails = createVolumeFromSnapshot(volume, snapshot); - if (volumeDetails != null) { - createdVolume = volumeDetails.first(); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, createdVolume.getAccountId(), - createdVolume.getDataCenterId(), createdVolume.getId(), createdVolume.getName(), createdVolume.getDiskOfferingId(), - null, createdVolume.getSize(), Volume.class.getName(), createdVolume.getUuid()); - } - return createdVolume; - } - - protected Pair createVDIFromSnapshot(long userId, SnapshotVO snapshot, StoragePoolVO pool) { - String vdiUUID = null; - Long snapshotId = snapshot.getId(); - Long volumeId = snapshot.getVolumeId(); - Long dcId = snapshot.getDataCenterId(); - String secondaryStoragePoolUrl = _snapMgr.getSecondaryStorageURL(snapshot); - long accountId = snapshot.getAccountId(); - - String backedUpSnapshotUuid = snapshot.getBackupSnapshotId(); - snapshot = _snapshotDao.findById(snapshotId); - if (snapshot.getVersion().trim().equals("2.1")) { - VolumeVO volume = _volsDao.findByIdIncludingRemoved(volumeId); - if (volume == null) { - throw new CloudRuntimeException("failed to upgrade snapshot " + snapshotId + " due to unable to find orignal volume:" + volumeId + ", try it later "); - } - if (volume.getTemplateId() == null) { - _snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); - } else { - VMTemplateVO template = _templateDao.findByIdIncludingRemoved(volume.getTemplateId()); - if (template == null) { - throw new CloudRuntimeException("failed to upgrade snapshot " + snapshotId + " due to unalbe to find orignal template :" + volume.getTemplateId() + ", try it later "); - } - Long templateId = template.getId(); - Long tmpltAccountId = template.getAccountId(); - if (!_snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { - throw new CloudRuntimeException("failed to upgrade snapshot " + snapshotId + " due to this snapshot is being used, try it later "); - } - UpgradeSnapshotCommand cmd = new UpgradeSnapshotCommand(null, secondaryStoragePoolUrl, dcId, accountId, volumeId, templateId, tmpltAccountId, null, snapshot.getBackupSnapshotId(), - snapshot.getName(), "2.1"); - Answer answer = null; - try { - answer = sendToPool(pool, cmd); - } catch (StorageUnavailableException e) { - } finally { - _snapshotDao.unlockFromLockTable(snapshotId.toString()); - } - if ((answer != null) && answer.getResult()) { - _snapshotDao.updateSnapshotVersion(volumeId, "2.1", "2.2"); - } else { - return new Pair(null, "Unable to upgrade snapshot from 2.1 to 2.2 for " + snapshot.getId()); - } - } - } - String basicErrMsg = "Failed to create volume from " + snapshot.getName() + " on pool " + pool; - try { - if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) { - _snapshotMgr.downloadSnapshotsFromSwift(snapshot); - } else if (snapshot.getS3Id() != null && snapshot.getS3Id() != 0) { - _snapshotMgr.downloadSnapshotsFromS3(snapshot); - } - CreateVolumeFromSnapshotCommand createVolumeFromSnapshotCommand = new CreateVolumeFromSnapshotCommand(pool, secondaryStoragePoolUrl, dcId, accountId, volumeId, - backedUpSnapshotUuid, snapshot.getName(), _createVolumeFromSnapshotWait); - CreateVolumeFromSnapshotAnswer answer; - if (!_snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { - throw new CloudRuntimeException("failed to create volume from " + snapshotId + " due to this snapshot is being used, try it later "); - } - answer = (CreateVolumeFromSnapshotAnswer) sendToPool(pool, createVolumeFromSnapshotCommand); - if (answer != null && answer.getResult()) { - vdiUUID = answer.getVdi(); - } else { - s_logger.error(basicErrMsg + " due to " + ((answer == null) ? "null" : answer.getDetails())); - throw new CloudRuntimeException(basicErrMsg); - } - } catch (StorageUnavailableException e) { - s_logger.error(basicErrMsg); - } finally { - if (snapshot.getSwiftId() != null) { - _snapshotMgr.deleteSnapshotsDirForVolume(secondaryStoragePoolUrl, dcId, accountId, volumeId); - } - _snapshotDao.unlockFromLockTable(snapshotId.toString()); - } - return new Pair(vdiUUID, basicErrMsg); - } - - - @Override - @DB - public VolumeVO copyVolumeFromSecToPrimary(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, ServiceOfferingVO offering, DiskOfferingVO diskOffering, - List avoids, long size, HypervisorType hyperType) throws NoTransitionException { - - final HashSet avoidPools = new HashSet(avoids); - DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); - dskCh.setHyperType(vm.getHypervisorType()); - // Find a suitable storage to create volume on - StoragePoolVO destPool = findStoragePool(dskCh, dc, pod, clusterId, null, vm, avoidPools); - - // Copy the volume from secondary storage to the destination storage pool - stateTransitTo(volume, Event.CopyRequested); - VolumeHostVO volumeHostVO = _volumeHostDao.findByVolumeId(volume.getId()); - HostVO secStorage = _hostDao.findById(volumeHostVO.getHostId()); - String secondaryStorageURL = secStorage.getStorageUrl(); - String[] volumePath = volumeHostVO.getInstallPath().split("/"); - String volumeUUID = volumePath[volumePath.length - 1].split("\\.")[0]; - - CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volumeUUID, destPool, secondaryStorageURL, false, _copyvolumewait); - CopyVolumeAnswer cvAnswer; - try { - cvAnswer = (CopyVolumeAnswer) sendToPool(destPool, cvCmd); - } catch (StorageUnavailableException e1) { - stateTransitTo(volume, Event.CopyFailed); - throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); - } - - if (cvAnswer == null || !cvAnswer.getResult()) { - stateTransitTo(volume, Event.CopyFailed); - throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); - } - Transaction txn = Transaction.currentTxn(); - txn.start(); - volume.setPath(cvAnswer.getVolumePath()); - volume.setFolder(destPool.getPath()); - volume.setPodId(destPool.getPodId()); - volume.setPoolId(destPool.getId()); - volume.setPodId(destPool.getPodId()); - stateTransitTo(volume, Event.CopySucceeded); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), - volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(), - null, volume.getSize(), Volume.class.getName(), volume.getUuid()); - _volumeHostDao.remove(volumeHostVO.getId()); - txn.commit(); - return volume; - - } - - @Override - @DB - public VolumeVO createVolume(VolumeVO volume, VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, ServiceOfferingVO offering, DiskOfferingVO diskOffering, - List avoids, long size, HypervisorType hyperType) { - StoragePoolVO pool = null; - final HashSet avoidPools = new HashSet(avoids); - - try { - stateTransitTo(volume, Volume.Event.CreateRequested); - } catch (NoTransitionException e) { - s_logger.debug("Unable to update volume state: " + e.toString()); - return null; - } - - if (diskOffering != null && diskOffering.isCustomized()) { - diskOffering.setDiskSize(size); - } - DiskProfile dskCh = null; - if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { - dskCh = createDiskCharacteristics(volume, template, dc, offering); - } else { - dskCh = createDiskCharacteristics(volume, template, dc, diskOffering); - } - - dskCh.setHyperType(hyperType); - - VolumeTO created = null; - int retry = _retry; - while (--retry >= 0) { - created = null; - - long podId = pod.getId(); - pod = _podDao.findById(podId); - if (pod == null) { - s_logger.warn("Unable to find pod " + podId + " when create volume " + volume.getName()); - break; - } - - pool = findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(), vm, avoidPools); - if (pool == null) { - s_logger.warn("Unable to find storage poll when create volume " + volume.getName()); - break; - } - - avoidPools.add(pool); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Trying to create " + volume + " on " + pool); - } - - CreateCommand cmd = null; - VMTemplateStoragePoolVO tmpltStoredOn = null; - - for (int i = 0; i < 2; i++) { - if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) { - if (pool.getPoolType() == StoragePoolType.CLVM) { - //prepareISOForCreate does what we need, which is to tell us where the template is - VMTemplateHostVO tmpltHostOn = _tmpltMgr.prepareISOForCreate(template, pool); - if (tmpltHostOn == null) { - continue; - } - HostVO secondaryStorageHost = _hostDao.findById(tmpltHostOn.getHostId()); - String tmpltHostUrl = secondaryStorageHost.getStorageUrl(); - String fullTmpltUrl = tmpltHostUrl + "/" + tmpltHostOn.getInstallPath(); - cmd = new CreateCommand(dskCh, fullTmpltUrl, new StorageFilerTO(pool)); - } else { - tmpltStoredOn = _tmpltMgr.prepareTemplateForCreate(template, pool); - if (tmpltStoredOn == null) { - continue; - } - cmd = new CreateCommand(dskCh, tmpltStoredOn.getLocalDownloadPath(), new StorageFilerTO(pool)); - } - } else { - if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO == template.getFormat()) { - VMTemplateHostVO tmpltHostOn = _tmpltMgr.prepareISOForCreate(template, pool); - if (tmpltHostOn == null) { - throw new CloudRuntimeException("Did not find ISO in secondry storage in zone " + pool.getDataCenterId()); - } - } - cmd = new CreateCommand(dskCh, new StorageFilerTO(pool)); - } - - try { - Answer answer = sendToPool(pool, cmd); - if (answer != null && answer.getResult()) { - created = ((CreateAnswer) answer).getVolume(); - break; - } - - if (tmpltStoredOn != null && answer != null && (answer instanceof CreateAnswer) && ((CreateAnswer) answer).templateReloadRequested()) { - if (!_tmpltMgr.resetTemplateDownloadStateOnPool(tmpltStoredOn.getId())) { - break; // break out of template-redeploy retry loop - } - } else { - break; - } - } catch (StorageUnavailableException e) { - s_logger.debug("Storage unavailable for " + pool.getId()); - break; // break out of template-redeploy retry loop - } - } - - if (created != null) { - break; - } - - s_logger.debug("Retrying the create because it failed on pool " + pool); - } - - if (created == null) { - return null; - } else { - volume.setFolder(pool.getPath()); - volume.setPath(created.getPath()); - volume.setSize(created.getSize()); - volume.setPoolType(pool.getPoolType()); - volume.setPoolId(pool.getId()); - volume.setPodId(pod.getId()); - try { - stateTransitTo(volume, Volume.Event.OperationSucceeded); - } catch (NoTransitionException e) { - s_logger.debug("Unable to update volume state: " + e.toString()); - return null; - } - return volume; - } - } - - public Long chooseHostForStoragePool(StoragePoolVO poolVO, List avoidHosts, boolean sendToVmResidesOn, Long vmId) { + public Long chooseHostForStoragePool(StoragePoolVO poolVO, + List avoidHosts, boolean sendToVmResidesOn, Long vmId) { if (sendToVmResidesOn) { if (vmId != null) { VMInstanceVO vmInstance = _vmInstanceDao.findById(vmId); if (vmInstance != null) { Long hostId = vmInstance.getHostId(); - if (hostId != null && !avoidHosts.contains(vmInstance.getHostId())) { + if (hostId != null + && !avoidHosts.contains(vmInstance.getHostId())) { return hostId; } } } /* - * Can't find the vm where host resides on(vm is destroyed? or volume is detached from vm), randomly choose - * a host - * to send the cmd + * Can't find the vm where host resides on(vm is destroyed? or + * volume is detached from vm), randomly choose a host to send the + * cmd */ } - List poolHosts = _poolHostDao.listByHostStatus(poolVO.getId(), Status.Up); + List poolHosts = _poolHostDao.listByHostStatus( + poolVO.getId(), Status.Up); Collections.shuffle(poolHosts); if (poolHosts != null && poolHosts.size() > 0) { for (StoragePoolHostVO sphvo : poolHosts) { @@ -876,9 +538,12 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Override public boolean configure(String name, Map params) throws ConfigurationException { - Map configs = _configDao.getConfiguration("management-server", params); - String overProvisioningFactorStr = configs.get("storage.overprovisioning.factor"); + Map configs = _configDao.getConfiguration( + "management-server", params); + + String overProvisioningFactorStr = configs + .get("storage.overprovisioning.factor"); if (overProvisioningFactorStr != null) { _overProvisioningFactor = new BigDecimal(overProvisioningFactorStr); } @@ -886,94 +551,128 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C _retry = NumbersUtil.parseInt(configs.get(Config.StartRetry.key()), 10); _pingInterval = NumbersUtil.parseInt(configs.get("ping.interval"), 60); _hostRetry = NumbersUtil.parseInt(configs.get("host.retry"), 2); - _storagePoolAcquisitionWaitSeconds = NumbersUtil.parseInt(configs.get("pool.acquisition.wait.seconds"), 1800); - s_logger.info("pool.acquisition.wait.seconds is configured as " + _storagePoolAcquisitionWaitSeconds + " seconds"); + _storagePoolAcquisitionWaitSeconds = NumbersUtil.parseInt( + configs.get("pool.acquisition.wait.seconds"), 1800); + s_logger.info("pool.acquisition.wait.seconds is configured as " + + _storagePoolAcquisitionWaitSeconds + " seconds"); - _agentMgr.registerForHostEvents(new StoragePoolMonitor(this, _storagePoolDao), true, false, true); + _agentMgr.registerForHostEvents(new StoragePoolMonitor(this, + _storagePoolDao), true, false, true); String storageCleanupEnabled = configs.get("storage.cleanup.enabled"); - _storageCleanupEnabled = (storageCleanupEnabled == null) ? true : Boolean.parseBoolean(storageCleanupEnabled); + _storageCleanupEnabled = (storageCleanupEnabled == null) ? true + : Boolean.parseBoolean(storageCleanupEnabled); - String value = _configDao.getValue(Config.CreateVolumeFromSnapshotWait.toString()); - _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value, Integer.parseInt(Config.CreateVolumeFromSnapshotWait.getDefaultValue())); + String value = _configDao.getValue(Config.CreateVolumeFromSnapshotWait + .toString()); + _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CreateVolumeFromSnapshotWait + .getDefaultValue())); value = _configDao.getValue(Config.CopyVolumeWait.toString()); - _copyvolumewait = NumbersUtil.parseInt(value, Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); + _copyvolumewait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); value = _configDao.getValue(Config.RecreateSystemVmEnabled.key()); _recreateSystemVmEnabled = Boolean.parseBoolean(value); value = _configDao.getValue(Config.StorageTemplateCleanupEnabled.key()); - _templateCleanupEnabled = (value == null ? true : Boolean.parseBoolean(value)); + _templateCleanupEnabled = (value == null ? true : Boolean + .parseBoolean(value)); String time = configs.get("storage.cleanup.interval"); _storageCleanupInterval = NumbersUtil.parseInt(time, 86400); - String storageUsedThreshold = _configDao.getValue(Config.StorageCapacityDisableThreshold.key()); + String storageUsedThreshold = _configDao + .getValue(Config.StorageCapacityDisableThreshold.key()); if (storageUsedThreshold != null) { _storageUsedThreshold = Double.parseDouble(storageUsedThreshold); } - String storageAllocatedThreshold = _configDao.getValue(Config.StorageAllocatedCapacityDisableThreshold.key()); + String storageAllocatedThreshold = _configDao + .getValue(Config.StorageAllocatedCapacityDisableThreshold.key()); if (storageAllocatedThreshold != null) { - _storageAllocatedThreshold = Double.parseDouble(storageAllocatedThreshold); + _storageAllocatedThreshold = Double + .parseDouble(storageAllocatedThreshold); } - String globalStorageOverprovisioningFactor = configs.get("storage.overprovisioning.factor"); - _storageOverprovisioningFactor = new BigDecimal(NumbersUtil.parseFloat(globalStorageOverprovisioningFactor, 2.0f)); + String globalStorageOverprovisioningFactor = configs + .get("storage.overprovisioning.factor"); + _storageOverprovisioningFactor = new BigDecimal(NumbersUtil.parseFloat( + globalStorageOverprovisioningFactor, 2.0f)); - s_logger.info("Storage cleanup enabled: " + _storageCleanupEnabled + ", interval: " + _storageCleanupInterval + ", template cleanup enabled: " + _templateCleanupEnabled); + s_logger.info("Storage cleanup enabled: " + _storageCleanupEnabled + + ", interval: " + _storageCleanupInterval + + ", template cleanup enabled: " + _templateCleanupEnabled); String workers = configs.get("expunge.workers"); int wrks = NumbersUtil.parseInt(workers, 10); - _executor = Executors.newScheduledThreadPool(wrks, new NamedThreadFactory("StorageManager-Scavenger")); + _executor = Executors.newScheduledThreadPool(wrks, + new NamedThreadFactory("StorageManager-Scavenger")); - _agentMgr.registerForHostEvents(ComponentContext.inject(LocalStoragePoolListener.class), true, false, false); + _agentMgr.registerForHostEvents( + ComponentContext.inject(LocalStoragePoolListener.class), true, + false, false); - String maxVolumeSizeInGbString = _configDao.getValue("storage.max.volume.size"); - _maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, 2000); + String maxVolumeSizeInGbString = _configDao + .getValue("storage.max.volume.size"); + _maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, + 2000); - String _customDiskOfferingMinSizeStr = _configDao.getValue(Config.CustomDiskOfferingMinSize.toString()); - _customDiskOfferingMinSize = NumbersUtil.parseInt(_customDiskOfferingMinSizeStr, Integer.parseInt(Config.CustomDiskOfferingMinSize.getDefaultValue())); + String _customDiskOfferingMinSizeStr = _configDao + .getValue(Config.CustomDiskOfferingMinSize.toString()); + _customDiskOfferingMinSize = NumbersUtil.parseInt( + _customDiskOfferingMinSizeStr, Integer + .parseInt(Config.CustomDiskOfferingMinSize + .getDefaultValue())); - String _customDiskOfferingMaxSizeStr = _configDao.getValue(Config.CustomDiskOfferingMaxSize.toString()); - _customDiskOfferingMaxSize = NumbersUtil.parseInt(_customDiskOfferingMaxSizeStr, Integer.parseInt(Config.CustomDiskOfferingMaxSize.getDefaultValue())); + String _customDiskOfferingMaxSizeStr = _configDao + .getValue(Config.CustomDiskOfferingMaxSize.toString()); + _customDiskOfferingMaxSize = NumbersUtil.parseInt( + _customDiskOfferingMaxSizeStr, Integer + .parseInt(Config.CustomDiskOfferingMaxSize + .getDefaultValue())); - HostTemplateStatesSearch = _vmTemplateHostDao.createSearchBuilder(); - HostTemplateStatesSearch.and("id", HostTemplateStatesSearch.entity().getTemplateId(), SearchCriteria.Op.EQ); - HostTemplateStatesSearch.and("state", HostTemplateStatesSearch.entity().getDownloadState(), SearchCriteria.Op.EQ); - - SearchBuilder HostSearch = _hostDao.createSearchBuilder(); - HostSearch.and("dcId", HostSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); - - HostTemplateStatesSearch.join("host", HostSearch, HostSearch.entity().getId(), HostTemplateStatesSearch.entity().getHostId(), JoinBuilder.JoinType.INNER); - HostSearch.done(); - HostTemplateStatesSearch.done(); _serverId = _msServer.getId(); - UpHostsInPoolSearch = _storagePoolHostDao.createSearchBuilder(Long.class); - UpHostsInPoolSearch.selectField(UpHostsInPoolSearch.entity().getHostId()); + UpHostsInPoolSearch = _storagePoolHostDao + .createSearchBuilder(Long.class); + UpHostsInPoolSearch.selectField(UpHostsInPoolSearch.entity() + .getHostId()); SearchBuilder hostSearch = _hostDao.createSearchBuilder(); hostSearch.and("status", hostSearch.entity().getStatus(), Op.EQ); - hostSearch.and("resourceState", hostSearch.entity().getResourceState(), Op.EQ); - UpHostsInPoolSearch.join("hosts", hostSearch, hostSearch.entity().getId(), UpHostsInPoolSearch.entity().getHostId(), JoinType.INNER); - UpHostsInPoolSearch.and("pool", UpHostsInPoolSearch.entity().getPoolId(), Op.EQ); + hostSearch.and("resourceState", hostSearch.entity().getResourceState(), + Op.EQ); + UpHostsInPoolSearch.join("hosts", hostSearch, hostSearch.entity() + .getId(), UpHostsInPoolSearch.entity().getHostId(), + JoinType.INNER); + UpHostsInPoolSearch.and("pool", UpHostsInPoolSearch.entity() + .getPoolId(), Op.EQ); UpHostsInPoolSearch.done(); StoragePoolSearch = _vmInstanceDao.createSearchBuilder(); SearchBuilder volumeSearch = _volumeDao.createSearchBuilder(); - volumeSearch.and("volumeType", volumeSearch.entity().getVolumeType(), SearchCriteria.Op.EQ); - volumeSearch.and("poolId", volumeSearch.entity().getPoolId(), SearchCriteria.Op.EQ); - StoragePoolSearch.join("vmVolume", volumeSearch, volumeSearch.entity().getInstanceId(), StoragePoolSearch.entity().getId(), JoinBuilder.JoinType.INNER); + volumeSearch.and("volumeType", volumeSearch.entity().getVolumeType(), + SearchCriteria.Op.EQ); + volumeSearch.and("poolId", volumeSearch.entity().getPoolId(), + SearchCriteria.Op.EQ); + StoragePoolSearch.join("vmVolume", volumeSearch, volumeSearch.entity() + .getInstanceId(), StoragePoolSearch.entity().getId(), + JoinBuilder.JoinType.INNER); StoragePoolSearch.done(); LocalStorageSearch = _storagePoolDao.createSearchBuilder(); - SearchBuilder storageHostSearch = _storagePoolHostDao.createSearchBuilder(); - storageHostSearch.and("hostId", storageHostSearch.entity().getHostId(), SearchCriteria.Op.EQ); - LocalStorageSearch.join("poolHost", storageHostSearch, storageHostSearch.entity().getPoolId(), LocalStorageSearch.entity().getId(), JoinBuilder.JoinType.INNER); - LocalStorageSearch.and("type", LocalStorageSearch.entity().getPoolType(), SearchCriteria.Op.IN); + SearchBuilder storageHostSearch = _storagePoolHostDao + .createSearchBuilder(); + storageHostSearch.and("hostId", storageHostSearch.entity().getHostId(), + SearchCriteria.Op.EQ); + LocalStorageSearch.join("poolHost", storageHostSearch, + storageHostSearch.entity().getPoolId(), LocalStorageSearch + .entity().getId(), JoinBuilder.JoinType.INNER); + LocalStorageSearch.and("type", LocalStorageSearch.entity() + .getPoolType(), SearchCriteria.Op.IN); LocalStorageSearch.done(); Volume.State.getStateMachine().registerListener( new VolumeStateListener()); @@ -981,159 +680,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return true; } - public String getRandomVolumeName() { - return UUID.randomUUID().toString(); - } - - @Override - public boolean volumeOnSharedStoragePool(VolumeVO volume) { - Long poolId = volume.getPoolId(); - if (poolId == null) { - return false; - } else { - StoragePoolVO pool = _storagePoolDao.findById(poolId); - - if (pool == null) { - return false; - } else { - return pool.isShared(); - } - } - } - - @Override - public boolean volumeInactive(VolumeVO volume) { - Long vmId = volume.getInstanceId(); - if (vmId != null) { - UserVm vm = _userVmDao.findById(vmId); - if (vm == null) { - return true; - } - State state = vm.getState(); - if (state.equals(State.Stopped) || state.equals(State.Destroyed)) { - return true; - } - } - return false; - } - - @Override - public String getVmNameOnVolume(VolumeVO volume) { - Long vmId = volume.getInstanceId(); - if (vmId != null) { - VMInstanceVO vm = _vmInstanceDao.findById(vmId); - - if (vm == null) { - return null; - } - return vm.getInstanceName(); - } - return null; - } - - @Override - public Pair getAbsoluteIsoPath(long templateId, long dataCenterId) { - String isoPath = null; - - List storageHosts = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.SecondaryStorage, dataCenterId); - if (storageHosts != null) { - for (HostVO storageHost : storageHosts) { - List templateHostVOs = _vmTemplateHostDao.listByTemplateHostStatus(templateId, storageHost.getId(), VMTemplateStorageResourceAssoc.Status.DOWNLOADED ); - if (templateHostVOs != null && !templateHostVOs.isEmpty()) { - VMTemplateHostVO tmpHostVO = templateHostVOs.get(0); - isoPath = storageHost.getStorageUrl() + "/" + tmpHostVO.getInstallPath(); - return new Pair(isoPath, storageHost.getStorageUrl()); - } - } - } - s_logger.warn("Unable to find secondary storage in zone id=" + dataCenterId); - return null; - } - - @Override - public String getSecondaryStorageURL(long zoneId) { - // Determine the secondary storage URL - HostVO secondaryStorageHost = getSecondaryStorageHost(zoneId); - - if (secondaryStorageHost == null) { - return null; - } - - return secondaryStorageHost.getStorageUrl(); - } - - @Override - public HostVO getSecondaryStorageHost(long zoneId, long tmpltId) { - List hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); - if (hosts == null || hosts.size() == 0) { - return null; - } - for (HostVO host : hosts) { - VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(host.getId(), tmpltId); - if (tmpltHost != null && !tmpltHost.getDestroyed() && tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { - return host; - } - } - return null; - } - - @Override - public VMTemplateHostVO getTemplateHostRef(long zoneId, long tmpltId, boolean readyOnly) { - List hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); - if (hosts == null || hosts.size() == 0) { - return null; - } - VMTemplateHostVO inProgress = null; - VMTemplateHostVO other = null; - for (HostVO host : hosts) { - VMTemplateHostVO tmpltHost = _vmTemplateHostDao.findByHostTemplate(host.getId(), tmpltId); - if (tmpltHost != null && !tmpltHost.getDestroyed()) { - if (tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { - return tmpltHost; - } else if (tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) { - inProgress = tmpltHost; - } else { - other = tmpltHost; - } - } - } - if (inProgress != null) { - return inProgress; - } - return other; - } - - @Override - public HostVO getSecondaryStorageHost(long zoneId) { - List hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); - if (hosts == null || hosts.size() == 0) { - hosts = _ssvmMgr.listLocalSecondaryStorageHostsInOneZone(zoneId); - if (hosts.isEmpty()) { - return null; - } - } - - int size = hosts.size(); - Random rn = new Random(); - int index = rn.nextInt(size); - return hosts.get(index); - } - - @Override - public List getSecondaryStorageHosts(long zoneId) { - List hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); - if (hosts == null || hosts.size() == 0) { - hosts = _ssvmMgr.listLocalSecondaryStorageHostsInOneZone(zoneId); - if (hosts.isEmpty()) { - return new ArrayList(); - } - } - return hosts; - } - + @Override public String getStoragePoolTags(long poolId) { - return _configMgr.listToCsvTags(_storagePoolDao.searchForStoragePoolDetails(poolId, "true")); + return _configMgr.listToCsvTags(_storagePoolDao + .searchForStoragePoolDetails(poolId, "true")); } @Override @@ -1141,7 +692,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C if (_storageCleanupEnabled) { Random generator = new Random(); int initialDelay = generator.nextInt(_storageCleanupInterval); - _executor.scheduleWithFixedDelay(new StorageGarbageCollector(), initialDelay, _storageCleanupInterval, TimeUnit.SECONDS); + _executor.scheduleWithFixedDelay(new StorageGarbageCollector(), + initialDelay, _storageCleanupInterval, TimeUnit.SECONDS); } else { s_logger.debug("Storage cleanup is not enabled, so the storage cleanup thread is not being scheduled."); } @@ -1157,22 +709,97 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return true; } + + @DB + @Override + public DataStore createLocalStorage(Host host, StoragePoolInfo pInfo) throws ConnectionException { - protected StorageManagerImpl() { - _volStateMachine = Volume.State.getStateMachine(); + DataCenterVO dc = _dcDao.findById(host.getDataCenterId()); + if (dc == null || !dc.isLocalStorageEnabled()) { + return null; + } + DataStore store = null; + try { + StoragePoolVO pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), pInfo.getHostPath(), pInfo.getUuid()); + if(pool == null && host.getHypervisorType() == HypervisorType.VMware) { + // perform run-time upgrade. In versions prior to 2.2.12, there is a bug that we don't save local datastore info (host path is empty), this will cause us + // not able to distinguish multiple local datastores that may be available on the host, to support smooth migration, we + // need to perform runtime upgrade here + if(pInfo.getHostPath().length() > 0) { + pool = _storagePoolDao.findPoolByHostPath(host.getDataCenterId(), host.getPodId(), pInfo.getHost(), "", pInfo.getUuid()); + } + } + DataStoreProvider provider = this.dataStoreProviderMgr.getDefaultPrimaryDataStoreProvider(); + DataStoreLifeCycle lifeCycle = provider.getLifeCycle(); + if (pool == null) { + Map params = new HashMap(); + String name = (host.getName() + " Local Storage"); + params.put("zoneId", host.getDataCenterId()); + params.put("clusterId", host.getClusterId()); + params.put("podId", host.getPodId()); + params.put("url", pInfo.getPoolType().toString() + "://" + pInfo.getHost() + "/" + pInfo.getHostPath()); + params.put("name", name); + params.put("localStorage", true); + params.put("details", pInfo.getDetails()); + params.put("uuid", pInfo.getUuid()); + params.put("providerId", provider.getId()); + + store = lifeCycle.initialize(params); + } else { + store = (DataStore) dataStoreMgr.getDataStore(pool.getId(), + DataStoreRole.Primary); + } + + HostScope scope = new HostScope(host.getId()); + lifeCycle.attachHost(store, scope, pInfo); + } catch (Exception e) { + s_logger.warn("Unable to setup the local storage pool for " + host, e); + throw new ConnectionException(true, "Unable to setup the local storage pool for " + host, e); + } + + return (DataStore) dataStoreMgr.getDataStore(store.getId(), + DataStoreRole.Primary); } @Override @SuppressWarnings("rawtypes") - public StoragePoolVO createPool(CreateStoragePoolCmd cmd) throws ResourceInUseException, IllegalArgumentException, UnknownHostException, ResourceUnavailableException { - Long clusterId = cmd.getClusterId(); - Long podId = cmd.getPodId(); - Map ds = cmd.getDetails(); + public PrimaryDataStoreInfo createPool(CreateStoragePoolCmd cmd) + throws ResourceInUseException, IllegalArgumentException, + UnknownHostException, ResourceUnavailableException { + String providerUuid = cmd.getStorageProviderUuid(); + DataStoreProvider storeProvider = dataStoreProviderMgr + .getDataStoreProviderByUuid(providerUuid); - if (clusterId != null && podId == null) { - throw new InvalidParameterValueException("Cluster id requires pod id"); + if (storeProvider == null) { + storeProvider = dataStoreProviderMgr.getDefaultPrimaryDataStoreProvider(); + throw new InvalidParameterValueException( + "invalid storage provider uuid" + providerUuid); } + Long clusterId = cmd.getClusterId(); + Long podId = cmd.getPodId(); + Long zoneId = cmd.getZoneId(); + + ScopeType scopeType = ScopeType.CLUSTER; + String scope = cmd.getScope(); + if (scope != null) { + try { + scopeType = Enum.valueOf(ScopeType.class, scope); + } catch (Exception e) { + throw new InvalidParameterValueException("invalid scope" + + scope); + } + } + + if (scopeType == ScopeType.CLUSTER && clusterId == null) { + throw new InvalidParameterValueException( + "cluster id can't be null, if scope is cluster"); + } else if (scopeType == ScopeType.ZONE && zoneId == null) { + throw new InvalidParameterValueException( + "zone id can't be null, if scope is zone"); + } + + Map ds = cmd.getDetails(); Map details = new HashMap(); if (ds != null) { Collection detailsCollection = ds.values(); @@ -1182,233 +809,69 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C Iterator it2 = d.entrySet().iterator(); while (it2.hasNext()) { Map.Entry entry = (Map.Entry) it2.next(); - details.put((String) entry.getKey(), (String) entry.getValue()); + details.put((String) entry.getKey(), + (String) entry.getValue()); } } } - // verify input parameters - Long zoneId = cmd.getZoneId(); DataCenterVO zone = _dcDao.findById(cmd.getZoneId()); if (zone == null) { - throw new InvalidParameterValueException("unable to find zone by id " + zoneId); + throw new InvalidParameterValueException( + "unable to find zone by id " + zoneId); } // Check if zone is disabled Account account = UserContext.current().getCaller(); - if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(account.getType())) { - throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId); + if (Grouping.AllocationState.Disabled == zone.getAllocationState() + && !_accountMgr.isRootAdmin(account.getType())) { + throw new PermissionDeniedException( + "Cannot perform this operation, Zone is currently disabled: " + + zoneId); } - // Check if there is host up in this cluster - List allHosts = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.Routing, clusterId, podId, zoneId); - if (allHosts.isEmpty()) { - throw new ResourceUnavailableException("No host up to associate a storage pool with in cluster " + clusterId, Pod.class, podId); - } - URI uri = null; + Map params = new HashMap(); + params.put("zoneId", zone.getId()); + params.put("clusterId", clusterId); + params.put("podId", podId); + params.put("url", cmd.getUrl()); + params.put("tags", cmd.getTags()); + params.put("name", cmd.getStoragePoolName()); + params.put("details", details); + params.put("providerId", storeProvider.getId()); + + DataStoreLifeCycle lifeCycle = storeProvider.getLifeCycle(); + DataStore store = null; try { - uri = new URI(UriUtils.encodeURIComponent(cmd.getUrl())); - if (uri.getScheme() == null) { - throw new InvalidParameterValueException("scheme is null " + cmd.getUrl() + ", add nfs:// as a prefix"); - } else if (uri.getScheme().equalsIgnoreCase("nfs")) { - String uriHost = uri.getHost(); - String uriPath = uri.getPath(); - if (uriHost == null || uriPath == null || uriHost.trim().isEmpty() || uriPath.trim().isEmpty()) { - throw new InvalidParameterValueException("host or path is null, should be nfs://hostname/path"); - } - } else if (uri.getScheme().equalsIgnoreCase("sharedMountPoint")) { - String uriPath = uri.getPath(); - if (uriPath == null) { - throw new InvalidParameterValueException("host or path is null, should be sharedmountpoint://localhost/path"); - } - } else if (uri.getScheme().equalsIgnoreCase("rbd")) { - String uriPath = uri.getPath(); - if (uriPath == null) { - throw new InvalidParameterValueException("host or path is null, should be rbd://hostname/pool"); - } + store = lifeCycle.initialize(params); + + if (scopeType == ScopeType.CLUSTER) { + ClusterScope clusterScope = new ClusterScope(clusterId, podId, + zoneId); + lifeCycle.attachCluster(store, clusterScope); + } else if (scopeType == ScopeType.ZONE) { + ZoneScope zoneScope = new ZoneScope(zoneId); + lifeCycle.attachZone(store, zoneScope); } - } catch (URISyntaxException e) { - throw new InvalidParameterValueException(cmd.getUrl() + " is not a valid uri"); + } catch (Exception e) { + s_logger.debug("Failed to add data store", e); + throw new CloudRuntimeException("Failed to add data store", e); } - String tags = cmd.getTags(); - if (tags != null) { - String[] tokens = tags.split(","); - - for (String tag : tokens) { - tag = tag.trim(); - if (tag.length() == 0) { - continue; - } - details.put(tag, "true"); - } - } - - String scheme = uri.getScheme(); - String storageHost = uri.getHost(); - String hostPath = uri.getPath(); - String userInfo = uri.getUserInfo(); - int port = uri.getPort(); - StoragePoolVO pool = null; - if (s_logger.isDebugEnabled()) { - s_logger.debug("createPool Params @ scheme - " + scheme + " storageHost - " + storageHost + " hostPath - " + hostPath + " port - " + port); - } - if (scheme.equalsIgnoreCase("nfs")) { - if (port == -1) { - port = 2049; - } - pool = new StoragePoolVO(StoragePoolType.NetworkFilesystem, storageHost, port, hostPath); - if (clusterId == null) { - throw new IllegalArgumentException("NFS need to have clusters specified for XenServers"); - } - } else if (scheme.equalsIgnoreCase("file")) { - if (port == -1) { - port = 0; - } - pool = new StoragePoolVO(StoragePoolType.Filesystem, "localhost", 0, hostPath); - } else if (scheme.equalsIgnoreCase("sharedMountPoint")) { - pool = new StoragePoolVO(StoragePoolType.SharedMountPoint, storageHost, 0, hostPath); - } else if (scheme.equalsIgnoreCase("clvm")) { - pool = new StoragePoolVO(StoragePoolType.CLVM, storageHost, 0, hostPath.replaceFirst("/", "")); - } else if (scheme.equalsIgnoreCase("rbd")) { - if (port == -1) { - port = 6789; - } - pool = new StoragePoolVO(StoragePoolType.RBD, storageHost, port, hostPath.replaceFirst("/", ""), userInfo); - } else if (scheme.equalsIgnoreCase("PreSetup")) { - pool = new StoragePoolVO(StoragePoolType.PreSetup, storageHost, 0, hostPath); - } else if (scheme.equalsIgnoreCase("iscsi")) { - String[] tokens = hostPath.split("/"); - int lun = NumbersUtil.parseInt(tokens[tokens.length - 1], -1); - if (port == -1) { - port = 3260; - } - if (lun != -1) { - if (clusterId == null) { - throw new IllegalArgumentException("IscsiLUN need to have clusters specified"); - } - hostPath.replaceFirst("/", ""); - pool = new StoragePoolVO(StoragePoolType.IscsiLUN, storageHost, port, hostPath); - } else { - for (StoragePoolDiscoverer discoverer : _discoverers) { - Map> pools; - try { - pools = discoverer.find(cmd.getZoneId(), podId, uri, details); - } catch (DiscoveryException e) { - throw new IllegalArgumentException("Not enough information for discovery " + uri, e); - } - if (pools != null) { - Map.Entry> entry = pools.entrySet().iterator().next(); - pool = entry.getKey(); - details = entry.getValue(); - break; - } - } - } - } else if (scheme.equalsIgnoreCase("iso")) { - if (port == -1) { - port = 2049; - } - pool = new StoragePoolVO(StoragePoolType.ISO, storageHost, port, hostPath); - } else if (scheme.equalsIgnoreCase("vmfs")) { - pool = new StoragePoolVO(StoragePoolType.VMFS, "VMFS datastore: " + hostPath, 0, hostPath); - } else if (scheme.equalsIgnoreCase("ocfs2")) { - port = 7777; - pool = new StoragePoolVO(StoragePoolType.OCFS2, "clustered", port, hostPath); - } else { - s_logger.warn("Unable to figure out the scheme for URI: " + uri); - throw new IllegalArgumentException("Unable to figure out the scheme for URI: " + uri); - } - - if (pool == null) { - s_logger.warn("Unable to figure out the scheme for URI: " + uri); - throw new IllegalArgumentException("Unable to figure out the scheme for URI: " + uri); - } - - List pools = _storagePoolDao.listPoolByHostPath(storageHost, hostPath); - if (!pools.isEmpty() && !scheme.equalsIgnoreCase("sharedmountpoint")) { - Long oldPodId = pools.get(0).getPodId(); - throw new ResourceInUseException("Storage pool " + uri + " already in use by another pod (id=" + oldPodId + ")", "StoragePool", uri.toASCIIString()); - } - - long poolId = _storagePoolDao.getNextInSequence(Long.class, "id"); - String uuid = null; - if (scheme.equalsIgnoreCase("sharedmountpoint") || scheme.equalsIgnoreCase("clvm")) { - uuid = UUID.randomUUID().toString(); - } else if (scheme.equalsIgnoreCase("PreSetup")) { - uuid = hostPath.replace("/", ""); - } else { - uuid = UUID.nameUUIDFromBytes(new String(storageHost + hostPath).getBytes()).toString(); - } - - List spHandles = _storagePoolDao.findIfDuplicatePoolsExistByUUID(uuid); - if ((spHandles != null) && (spHandles.size() > 0)) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Another active pool with the same uuid already exists"); - } - throw new ResourceInUseException("Another active pool with the same uuid already exists"); - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("In createPool Setting poolId - " + poolId + " uuid - " + uuid + " zoneId - " + zoneId + " podId - " + podId + " poolName - " + cmd.getStoragePoolName()); - } - - pool.setId(poolId); - pool.setUuid(uuid); - pool.setDataCenterId(cmd.getZoneId()); - pool.setPodId(podId); - pool.setName(cmd.getStoragePoolName()); - pool.setClusterId(clusterId); - pool.setStatus(StoragePoolStatus.Up); - pool = _storagePoolDao.persist(pool, details); - - if (pool.getPoolType() == StoragePoolType.OCFS2 && !_ocfs2Mgr.prepareNodes(allHosts, pool)) { - s_logger.warn("Can not create storage pool " + pool + " on cluster " + clusterId); - _storagePoolDao.expunge(pool.getId()); - return null; - } - - boolean success = false; - for (HostVO h : allHosts) { - success = createStoragePool(h.getId(), pool); - if (success) { - break; - } - } - if (!success) { - s_logger.warn("Can not create storage pool " + pool + " on cluster " + clusterId); - _storagePoolDao.expunge(pool.getId()); - return null; - } - s_logger.debug("In createPool Adding the pool to each of the hosts"); - List poolHosts = new ArrayList(); - for (HostVO h : allHosts) { - try { - connectHostToSharedPool(h.getId(), pool); - poolHosts.add(h); - } catch (Exception e) { - s_logger.warn("Unable to establish a connection between " + h + " and " + pool, e); - } - } - - if (poolHosts.isEmpty()) { - s_logger.warn("No host can access storage pool " + pool + " on cluster " + clusterId); - _storagePoolDao.expunge(pool.getId()); - return null; - } else { - createCapacityEntry(pool); - } - return pool; + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore(store.getId(), + DataStoreRole.Primary); } @Override - public StoragePoolVO updateStoragePool(UpdateStoragePoolCmd cmd) throws IllegalArgumentException { + public PrimaryDataStoreInfo updateStoragePool(UpdateStoragePoolCmd cmd) + throws IllegalArgumentException { // Input validation Long id = cmd.getId(); List tags = cmd.getTags(); StoragePoolVO pool = _storagePoolDao.findById(id); if (pool == null) { - throw new IllegalArgumentException("Unable to find storage pool with ID: " + id); + throw new IllegalArgumentException( + "Unable to find storage pool with ID: " + id); } if (tags != null) { @@ -1423,835 +886,112 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C _storagePoolDao.updateDetails(id, details); } - return pool; + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore(pool.getId(), + DataStoreRole.Primary); } @Override @DB public boolean deletePool(DeletePoolCmd cmd) { Long id = cmd.getId(); - boolean deleteFlag = false; boolean forced = cmd.isForced(); - // verify parameters StoragePoolVO sPool = _storagePoolDao.findById(id); if (sPool == null) { s_logger.warn("Unable to find pool:" + id); - throw new InvalidParameterValueException("Unable to find pool by id " + id); + throw new InvalidParameterValueException( + "Unable to find pool by id " + id); } - if(sPool.getStatus() != StoragePoolStatus.Maintenance){ - s_logger.warn("Unable to delete storage id: " + id +" due to it is not in Maintenance state"); - throw new InvalidParameterValueException("Unable to delete storage due to it is not in Maintenance state, id: " + id); + if (sPool.getStatus() != StoragePoolStatus.Maintenance) { + s_logger.warn("Unable to delete storage id: " + id + + " due to it is not in Maintenance state"); + throw new InvalidParameterValueException( + "Unable to delete storage due to it is not in Maintenance state, id: " + + id); } - if (sPool.getPoolType().equals(StoragePoolType.LVM) || sPool.getPoolType().equals(StoragePoolType.EXT)) { + if (sPool.isLocal()) { s_logger.warn("Unable to delete local storage id:" + id); - throw new InvalidParameterValueException("Unable to delete local storage id: " + id); + throw new InvalidParameterValueException( + "Unable to delete local storage id: " + id); } Pair vlms = _volsDao.getCountAndTotalByPool(id); if (forced) { if (vlms.first() > 0) { - Pair nonDstrdVlms = _volsDao.getNonDestroyedCountAndTotalByPool(id); + Pair nonDstrdVlms = _volsDao + .getNonDestroyedCountAndTotalByPool(id); if (nonDstrdVlms.first() > 0) { - throw new CloudRuntimeException("Cannot delete pool " + sPool.getName() + " as there are associated " + - "non-destroyed vols for this pool"); + throw new CloudRuntimeException("Cannot delete pool " + + sPool.getName() + " as there are associated " + + "non-destroyed vols for this pool"); } - //force expunge non-destroyed volumes + // force expunge non-destroyed volumes List vols = _volsDao.listVolumesToBeDestroyed(); for (VolumeVO vol : vols) { - expungeVolume(vol, true); + AsyncCallFuture future = this.volService.expungeVolumeAsync(this.volFactory.getVolume(vol.getId())); + try { + future.get(); + } catch (InterruptedException e) { + s_logger.debug("expunge volume failed" + vol.getId(), e); + } catch (ExecutionException e) { + s_logger.debug("expunge volume failed" + vol.getId(), e); + } } } } else { // Check if the pool has associated volumes in the volumes table // If it does , then you cannot delete the pool if (vlms.first() > 0) { - throw new CloudRuntimeException("Cannot delete pool " + sPool.getName() + " as there are associated vols" + - " for this pool"); + throw new CloudRuntimeException("Cannot delete pool " + + sPool.getName() + " as there are associated vols" + + " for this pool"); } } - // First get the host_id from storage_pool_host_ref for given pool id - StoragePoolVO lock = _storagePoolDao.acquireInLockTable(sPool.getId()); + StoragePoolVO lock = _storagePoolDao.acquireInLockTable(sPool + .getId()); if (lock == null) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Failed to acquire lock when deleting StoragePool with ID: " + sPool.getId()); + s_logger.debug("Failed to acquire lock when deleting PrimaryDataStoreVO with ID: " + + sPool.getId()); } return false; } - // mark storage pool as removed (so it can't be used for new volumes creation), release the lock - boolean isLockReleased = false; - isLockReleased = _storagePoolDao.releaseFromLockTable(lock.getId()); + _storagePoolDao.releaseFromLockTable(lock.getId()); s_logger.trace("Released lock for storage pool " + id); - // for the given pool id, find all records in the storage_pool_host_ref - List hostPoolRecords = _storagePoolHostDao.listByPoolId(id); - Transaction txn = Transaction.currentTxn(); - try { - // if not records exist, delete the given pool (base case) - if (hostPoolRecords.size() == 0) { - - txn.start(); - sPool.setUuid(null); - _storagePoolDao.update(id, sPool); - _storagePoolDao.remove(id); - deletePoolStats(id); - txn.commit(); - - deleteFlag = true; - return true; - } else { - // Remove the SR associated with the Xenserver - for (StoragePoolHostVO host : hostPoolRecords) { - DeleteStoragePoolCommand deleteCmd = new DeleteStoragePoolCommand(sPool); - final Answer answer = _agentMgr.easySend(host.getHostId(), deleteCmd); - - if (answer != null && answer.getResult()) { - deleteFlag = true; - break; - } - } - } - } finally { - if (deleteFlag) { - // now delete the storage_pool_host_ref and storage_pool records - txn.start(); - for (StoragePoolHostVO host : hostPoolRecords) { - _storagePoolHostDao.deleteStoragePoolHostDetails(host.getHostId(), host.getPoolId()); - } - sPool.setUuid(null); - _storagePoolDao.update(id, sPool); - _storagePoolDao.remove(id); - deletePoolStats(id); - // Delete op_host_capacity entries - _capacityDao.removeBy(Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, null, null, null, id); - txn.commit(); - - s_logger.debug("Storage pool id=" + id + " is removed successfully"); - return true; - } else { - // alert that the storage cleanup is required - s_logger.warn("Failed to Delete storage pool id: " + id); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_STORAGE_DELETE, sPool.getDataCenterId(), sPool.getPodId(), "Unable to delete storage pool id= " + id, - "Delete storage pool command failed. Please check logs."); - } - - if (lock != null && !isLockReleased) { - _storagePoolDao.releaseFromLockTable(lock.getId()); - } - } + DataStoreProvider storeProvider = dataStoreProviderMgr + .getDataStoreProviderById(sPool.getStorageProviderId()); + DataStoreLifeCycle lifeCycle = storeProvider.getLifeCycle(); + lifeCycle.deleteDataStore(id); return false; - - } - - @DB - private boolean deletePoolStats(Long poolId) { - CapacityVO capacity1 = _capacityDao.findByHostIdType(poolId, CapacityVO.CAPACITY_TYPE_STORAGE); - CapacityVO capacity2 = _capacityDao.findByHostIdType(poolId, CapacityVO.CAPACITY_TYPE_STORAGE_ALLOCATED); - Transaction txn = Transaction.currentTxn(); - txn.start(); - if (capacity1 != null) { - _capacityDao.remove(capacity1.getId()); - } - - if (capacity2 != null) { - _capacityDao.remove(capacity2.getId()); - } - - txn.commit(); - return true; - } @Override - public boolean createStoragePool(long hostId, StoragePoolVO pool) { - s_logger.debug("creating pool " + pool.getName() + " on host " + hostId); - if (pool.getPoolType() != StoragePoolType.NetworkFilesystem && pool.getPoolType() != StoragePoolType.Filesystem && pool.getPoolType() != StoragePoolType.IscsiLUN - && pool.getPoolType() != StoragePoolType.Iscsi && pool.getPoolType() != StoragePoolType.VMFS && pool.getPoolType() != StoragePoolType.SharedMountPoint - && pool.getPoolType() != StoragePoolType.PreSetup && pool.getPoolType() != StoragePoolType.OCFS2 && pool.getPoolType() != StoragePoolType.RBD && pool.getPoolType() != StoragePoolType.CLVM) { - s_logger.warn(" Doesn't support storage pool type " + pool.getPoolType()); - return false; - } - CreateStoragePoolCommand cmd = new CreateStoragePoolCommand(true, pool); - final Answer answer = _agentMgr.easySend(hostId, cmd); - if (answer != null && answer.getResult()) { - return true; - } else { - _storagePoolDao.expunge(pool.getId()); - String msg = ""; - if (answer != null) { - msg = "Can not create storage pool through host " + hostId + " due to " + answer.getDetails(); - s_logger.warn(msg); - } else { - msg = "Can not create storage pool through host " + hostId + " due to CreateStoragePoolCommand returns null"; - s_logger.warn(msg); - } - throw new CloudRuntimeException(msg); - } - } - - @Override - public boolean delPoolFromHost(long hostId) { - List poolHosts = _poolHostDao.listByHostIdIncludingRemoved(hostId); - for (StoragePoolHostVO poolHost : poolHosts) { - s_logger.debug("Deleting pool " + poolHost.getPoolId() + " from host " + hostId); - _poolHostDao.remove(poolHost.getId()); - } - return true; - } - - public void connectHostToSharedPool(long hostId, StoragePoolVO pool) throws StorageUnavailableException { - assert (pool.getPoolType().isShared()) : "Now, did you actually read the name of this method?"; + public void connectHostToSharedPool(long hostId, long poolId) + throws StorageUnavailableException { + StoragePool pool = (StoragePool)this.dataStoreMgr.getDataStore(poolId, DataStoreRole.Primary); + assert (pool.isShared()) : "Now, did you actually read the name of this method?"; s_logger.debug("Adding pool " + pool.getName() + " to host " + hostId); - ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(true, pool); - final Answer answer = _agentMgr.easySend(hostId, cmd); - - if (answer == null) { - throw new StorageUnavailableException("Unable to get an answer to the modify storage pool command", pool.getId()); - } - - if (!answer.getResult()) { - String msg = "Add host failed due to ModifyStoragePoolCommand failed" + answer.getDetails(); - _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, pool.getDataCenterId(), pool.getPodId(), msg, msg); - throw new StorageUnavailableException("Unable establish connection from storage head to storage pool " + pool.getId() + " due to " + answer.getDetails(), pool.getId()); - } - - assert (answer instanceof ModifyStoragePoolAnswer) : "Well, now why won't you actually return the ModifyStoragePoolAnswer when it's ModifyStoragePoolCommand? Pool=" + pool.getId() + "Host=" + hostId; - ModifyStoragePoolAnswer mspAnswer = (ModifyStoragePoolAnswer) answer; - - StoragePoolHostVO poolHost = _poolHostDao.findByPoolHost(pool.getId(), hostId); - if (poolHost == null) { - poolHost = new StoragePoolHostVO(pool.getId(), hostId, mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/")); - _poolHostDao.persist(poolHost); - } else { - poolHost.setLocalPath(mspAnswer.getPoolInfo().getLocalPath().replaceAll("//", "/")); - } - pool.setAvailableBytes(mspAnswer.getPoolInfo().getAvailableBytes()); - pool.setCapacityBytes(mspAnswer.getPoolInfo().getCapacityBytes()); - _storagePoolDao.update(pool.getId(), pool); - - s_logger.info("Connection established between " + pool + " host + " + hostId); + DataStoreProvider provider = dataStoreProviderMgr + .getDataStoreProviderById(pool.getStorageProviderId()); + HypervisorHostListener listener = hostListeners.get(provider.getUuid()); + listener.hostConnect(hostId, pool.getId()); } + + - @Override - public VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException { + - // Find a destination storage pool with the specified criteria - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId()); - DiskProfile dskCh = new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), diskOffering.getId(), diskOffering.getDiskSize(), diskOffering.getTagsArray(), - diskOffering.getUseLocalStorage(), diskOffering.isRecreatable(), null); - dskCh.setHyperType(dataDiskHyperType); - DataCenterVO destPoolDataCenter = _dcDao.findById(destPoolDcId); - HostPodVO destPoolPod = _podDao.findById(destPoolPodId); - StoragePoolVO destPool = findStoragePool(dskCh, destPoolDataCenter, destPoolPod, destPoolClusterId, null, null, new HashSet()); - String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId()); + + - if (destPool == null) { - throw new CloudRuntimeException("Failed to find a storage pool with enough capacity to move the volume to."); - } - if (secondaryStorageURL == null) { - throw new CloudRuntimeException("Failed to find secondary storage."); - } - - List vols = new ArrayList(); - vols.add(volume); - migrateVolumes(vols, destPool); - return _volsDao.findById(volume.getId()); - } - - - /* - * Upload the volume to secondary storage. - * - */ - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPLOAD, eventDescription = "uploading volume", async = true) - public VolumeVO uploadVolume(UploadVolumeCmd cmd) throws ResourceAllocationException{ - Account caller = UserContext.current().getCaller(); - long ownerId = cmd.getEntityOwnerId(); - Long zoneId = cmd.getZoneId(); - String volumeName = cmd.getVolumeName(); - String url = cmd.getUrl(); - String format = cmd.getFormat(); - - validateVolume(caller, ownerId, zoneId, volumeName, url, format); - VolumeVO volume = persistVolume(caller, ownerId, zoneId, volumeName, url, cmd.getFormat()); - _downloadMonitor.downloadVolumeToStorage(volume, zoneId, url, cmd.getChecksum(), ImageFormat.valueOf(format.toUpperCase())); - return volume; - } - - private boolean validateVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format) throws ResourceAllocationException{ - - // permission check - _accountMgr.checkAccess(caller, null, true, _accountMgr.getActiveAccountById(ownerId)); - - // Check that the resource limit for volumes won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), ResourceType.volume); - - - // Verify that zone exists - DataCenterVO zone = _dcDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Unable to find zone by id " + zoneId); - } - - // Check if zone is disabled - if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { - throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId); - } - - if (url.toLowerCase().contains("file://")) { - throw new InvalidParameterValueException("File:// type urls are currently unsupported"); - } - - ImageFormat imgfmt = ImageFormat.valueOf(format.toUpperCase()); - if (imgfmt == null) { - throw new IllegalArgumentException("Image format is incorrect " + format + ". Supported formats are " + EnumUtils.listValues(ImageFormat.values())); - } - - String userSpecifiedName = volumeName; - if (userSpecifiedName == null) { - userSpecifiedName = getRandomVolumeName(); - } - if((!url.toLowerCase().endsWith("vhd"))&&(!url.toLowerCase().endsWith("vhd.zip")) - &&(!url.toLowerCase().endsWith("vhd.bz2"))&&(!url.toLowerCase().endsWith("vhd.gz")) - &&(!url.toLowerCase().endsWith("qcow2"))&&(!url.toLowerCase().endsWith("qcow2.zip")) - &&(!url.toLowerCase().endsWith("qcow2.bz2"))&&(!url.toLowerCase().endsWith("qcow2.gz")) - &&(!url.toLowerCase().endsWith("ova"))&&(!url.toLowerCase().endsWith("ova.zip")) - &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz")) - &&(!url.toLowerCase().endsWith("img"))&&(!url.toLowerCase().endsWith("raw"))){ - throw new InvalidParameterValueException("Please specify a valid " + format.toLowerCase()); - } - - if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith(".vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith("vhd.gz") )) - || (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith(".qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz") )) - || (format.equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith(".ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase().endsWith("ova.gz"))) - || (format.equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith(".img") && !url.toLowerCase().endsWith("raw")))) { - throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + format.toLowerCase()); - } - validateUrl(url); - - return false; - } - - private String validateUrl(String url){ - try { - URI uri = new URI(url); - if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") - && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file"))) { - throw new IllegalArgumentException("Unsupported scheme for url: " + url); - } - - int port = uri.getPort(); - if (!(port == 80 || port == 443 || port == -1)) { - throw new IllegalArgumentException("Only ports 80 and 443 are allowed"); - } - String host = uri.getHost(); - try { - InetAddress hostAddr = InetAddress.getByName(host); - if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) { - throw new IllegalArgumentException("Illegal host specified in url"); - } - if (hostAddr instanceof Inet6Address) { - throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")"); - } - } catch (UnknownHostException uhe) { - throw new IllegalArgumentException("Unable to resolve " + host); - } - - return uri.toString(); - } catch (URISyntaxException e) { - throw new IllegalArgumentException("Invalid URL " + url); - } - - } - - private VolumeVO persistVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format) { - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK); - volume.setPoolId(null); - volume.setDataCenterId(zoneId); - volume.setPodId(null); - volume.setAccountId(ownerId); - volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId())); - long diskOfferingId = _diskOfferingDao.findByUniqueName("Cloud.com-Custom").getId(); - volume.setDiskOfferingId(diskOfferingId); - //volume.setSize(size); - volume.setInstanceId(null); - volume.setUpdated(new Date()); - volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId()); - - volume = _volsDao.persist(volume); - try { - stateTransitTo(volume, Event.UploadRequested); - } catch (NoTransitionException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - UserContext.current().setEventDetails("Volume Id: " + volume.getId()); - - // Increment resource count during allocation; if actual creation fails, decrement it - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume); - - txn.commit(); - return volume; - } - - - /* - * Just allocate a volume in the database, don't send the createvolume cmd to hypervisor. The volume will be finally - * created - * only when it's attached to a VM. - */ - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true) - public VolumeVO allocVolume(CreateVolumeCmd cmd) throws ResourceAllocationException { - // FIXME: some of the scheduled event stuff might be missing here... - Account caller = UserContext.current().getCaller(); - - long ownerId = cmd.getEntityOwnerId(); - - // permission check - _accountMgr.checkAccess(caller, null, true, _accountMgr.getActiveAccountById(ownerId)); - - // Check that the resource limit for volumes won't be exceeded - _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), ResourceType.volume); - - Long zoneId = cmd.getZoneId(); - Long diskOfferingId = null; - DiskOfferingVO diskOffering = null; - Long size = null; - - // validate input parameters before creating the volume - if ((cmd.getSnapshotId() == null && cmd.getDiskOfferingId() == null) || (cmd.getSnapshotId() != null && cmd.getDiskOfferingId() != null)) { - throw new InvalidParameterValueException("Either disk Offering Id or snapshot Id must be passed whilst creating volume"); - } - - if (cmd.getSnapshotId() == null) {// create a new volume - - diskOfferingId = cmd.getDiskOfferingId(); - size = cmd.getSize(); - Long sizeInGB = size; - if (size != null) { - if (size > 0) { - size = size * 1024 * 1024 * 1024; // user specify size in GB - } else { - throw new InvalidParameterValueException("Disk size must be larger than 0"); - } - } - - // Check that the the disk offering is specified - diskOffering = _diskOfferingDao.findById(diskOfferingId); - if ((diskOffering == null) || diskOffering.getRemoved() != null || !DiskOfferingVO.Type.Disk.equals(diskOffering.getType())) { - throw new InvalidParameterValueException("Please specify a valid disk offering."); - } - - if (diskOffering.isCustomized()) { - if (size == null) { - throw new InvalidParameterValueException("This disk offering requires a custom size specified"); - } - if ((sizeInGB < _customDiskOfferingMinSize) || (sizeInGB > _customDiskOfferingMaxSize)) { - throw new InvalidParameterValueException("Volume size: " + sizeInGB + "GB is out of allowed range. Max: " + _customDiskOfferingMaxSize + " Min:" + _customDiskOfferingMinSize); - } - } - - if (!diskOffering.isCustomized() && size != null) { - throw new InvalidParameterValueException("This disk offering does not allow custom size"); - } - - if (diskOffering.getDomainId() == null) { - // do nothing as offering is public - } else { - _configMgr.checkDiskOfferingAccess(caller, diskOffering); - } - - if (diskOffering.getDiskSize() > 0) { - size = diskOffering.getDiskSize(); - } - - if (!validateVolumeSizeRange(size)) {// convert size from mb to gb for validation - throw new InvalidParameterValueException("Invalid size for custom volume creation: " + size + " ,max volume size is:" + _maxVolumeSizeInGb); - } - } else { // create volume from snapshot - Long snapshotId = cmd.getSnapshotId(); - SnapshotVO snapshotCheck = _snapshotDao.findById(snapshotId); - if (snapshotCheck == null) { - throw new InvalidParameterValueException("unable to find a snapshot with id " + snapshotId); - } - - if (snapshotCheck.getState() != Snapshot.State.BackedUp) { - throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.State.BackedUp + " state yet and can't be used for volume creation"); - } - - diskOfferingId = snapshotCheck.getDiskOfferingId(); - diskOffering = _diskOfferingDao.findById(diskOfferingId); - zoneId = snapshotCheck.getDataCenterId(); - size = snapshotCheck.getSize(); // ; disk offering is used for tags purposes - - // check snapshot permissions - _accountMgr.checkAccess(caller, null, true, snapshotCheck); - - /* - * // bug #11428. Operation not supported if vmware and snapshots parent volume = ROOT - * if(snapshotCheck.getHypervisorType() == HypervisorType.VMware - * && _volumeDao.findByIdIncludingRemoved(snapshotCheck.getVolumeId()).getVolumeType() == Type.ROOT){ - * throw new UnsupportedServiceException("operation not supported, snapshot with id " + snapshotId + - * " is created from ROOT volume"); - * } - * - */ - } - - // Verify that zone exists - DataCenterVO zone = _dcDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Unable to find zone by id " + zoneId); - } - - // Check if zone is disabled - if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) { - throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId); - } - - // If local storage is disabled then creation of volume with local disk offering not allowed - if (!zone.isLocalStorageEnabled() && diskOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException("Zone is not configured to use local storage but volume's disk offering " + diskOffering.getName() + " uses it"); - } - - // Check that there is appropriate primary storage pool in the specified zone - List storagePools = _storagePoolDao.listByDataCenterId(zoneId); - boolean appropriatePoolExists = false; - if (!diskOffering.getUseLocalStorage()) { - for (StoragePoolVO storagePool : storagePools) { - if (storagePool.isShared()) { - appropriatePoolExists = true; - break; - } - } - } else { - for (StoragePoolVO storagePool : storagePools) { - if (storagePool.isLocal()) { - appropriatePoolExists = true; - break; - } - } - } - - // Check that there is at least one host in the specified zone - List hosts = _resourceMgr.listAllUpAndEnabledHostsInOneZoneByType(Host.Type.Routing, zoneId); - if (hosts.isEmpty()) { - throw new InvalidParameterValueException("There is no workable host in data center id " + zoneId + ", please check hosts' agent status and see if they are disabled"); - } - - if (!appropriatePoolExists) { - String storageType = diskOffering.getUseLocalStorage() ? ServiceOffering.StorageType.local.toString() : ServiceOffering.StorageType.shared.toString(); - throw new InvalidParameterValueException("Volume's disk offering uses " + storageType + " storage, please specify a zone that has at least one " + storageType + " primary storage pool."); - } - - String userSpecifiedName = cmd.getVolumeName(); - if (userSpecifiedName == null) { - userSpecifiedName = getRandomVolumeName(); - } - - Transaction txn = Transaction.currentTxn(); - txn.start(); - - 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); - volume.setAccountId(ownerId); - volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId())); - volume.setDiskOfferingId(diskOfferingId); - volume.setSize(size); - volume.setInstanceId(null); - volume.setUpdated(new Date()); - volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId()); - - volume = _volsDao.persist(volume); - if(cmd.getSnapshotId() == null){ - //for volume created from snapshot, create usage event after volume creation - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), - volume.getDataCenterId(), volume.getId(), volume.getName(), diskOfferingId, null, size, - Volume.class.getName(), volume.getUuid()); - } - - UserContext.current().setEventDetails("Volume Id: " + volume.getId()); - - // Increment resource count during allocation; if actual creation fails, decrement it - _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume); - - txn.commit(); - - return volume; - } - - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", async = true) - public VolumeVO createVolume(CreateVolumeCmd cmd) { - VolumeVO volume = _volsDao.findById(cmd.getEntityId()); - boolean created = false; - - try { - if (cmd.getSnapshotId() != null) { - volume = createVolumeFromSnapshot(volume, cmd.getSnapshotId()); - if (volume.getState() == Volume.State.Ready) { - created = true; - } - return volume; - } else { - _volsDao.update(volume.getId(), volume); - created = true; - } - - return _volsDao.findById(volume.getId()); - } finally { - if (!created) { - s_logger.trace("Decrementing volume resource count for account id=" + volume.getAccountId() + " as volume failed to create on the backend"); - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume); - } - } - } - - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true) - public VolumeVO resizeVolume(ResizeVolumeCmd cmd) { - VolumeVO volume = _volsDao.findById(cmd.getEntityId()); - Long newSize = null; - boolean shrinkOk = cmd.getShrinkOk(); - boolean success = false; - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId()); - DiskOfferingVO newDiskOffering = null; - - newDiskOffering = _diskOfferingDao.findById(cmd.getNewDiskOfferingId()); - - /* Volumes with no hypervisor have never been assigned, and can be resized by recreating. - perhaps in the future we can just update the db entry for the volume */ - if(_volsDao.getHypervisorType(volume.getId()) == HypervisorType.None){ - throw new InvalidParameterValueException("Can't resize a volume that has never been attached, not sure which hypervisor type. Recreate volume to resize."); - } - - /* Only works for KVM/Xen/VMware for now */ - if(_volsDao.getHypervisorType(volume.getId()) != HypervisorType.KVM - && _volsDao.getHypervisorType(volume.getId()) != HypervisorType.XenServer - && _volsDao.getHypervisorType(volume.getId()) != HypervisorType.VMware){ - throw new InvalidParameterValueException("Cloudstack currently only supports volumes marked as KVM, XenServer or VMware hypervisor for resize"); - } - - if (volume == null) { - throw new InvalidParameterValueException("No such volume"); - } - - if (volume.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException("Volume should be in ready state before attempting a resize"); - } - - if (!volume.getVolumeType().equals(Volume.Type.DATADISK)) { - throw new InvalidParameterValueException("Can only resize DATA volumes"); - } - - /* figure out whether or not a new disk offering or size parameter is required, get the correct size value */ - if (newDiskOffering == null) { - if (diskOffering.isCustomized()) { - newSize = cmd.getSize(); - - if (newSize == null) { - throw new InvalidParameterValueException("new offering is of custom size, need to specify a size"); - } - - newSize = ( newSize << 30 ); - } else { - throw new InvalidParameterValueException("current offering" + volume.getDiskOfferingId() + " cannot be resized, need to specify a disk offering"); - } - } else { - - if (newDiskOffering.getRemoved() != null || !DiskOfferingVO.Type.Disk.equals(newDiskOffering.getType())) { - throw new InvalidParameterValueException("Disk offering ID is missing or invalid"); - } - - if(diskOffering.getTags() != null) { - if(!newDiskOffering.getTags().equals(diskOffering.getTags())){ - throw new InvalidParameterValueException("Tags on new and old disk offerings must match"); - } - } else if (newDiskOffering.getTags() != null ){ - throw new InvalidParameterValueException("There are no tags on current disk offering, new disk offering needs to have no tags"); - } - - if (newDiskOffering.getDomainId() == null) { - // do nothing as offering is public - } else { - _configMgr.checkDiskOfferingAccess(UserContext.current().getCaller(), newDiskOffering); - } - - if (newDiskOffering.isCustomized()) { - newSize = cmd.getSize(); - - if (newSize == null) { - throw new InvalidParameterValueException("new offering is of custom size, need to specify a size"); - } - - newSize = ( newSize << 30 ); - } else { - newSize = newDiskOffering.getDiskSize(); - } - } - - if (newSize == null) { - throw new InvalidParameterValueException("could not detect a size parameter or fetch one from the diskofferingid parameter"); - } - - if (!validateVolumeSizeRange(newSize)) { - throw new InvalidParameterValueException("Requested size out of range"); - } - - /* does the caller have the authority to act on this volume? */ - _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, volume); - - UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); - - StoragePool pool = _storagePoolDao.findById(volume.getPoolId()); - long currentSize = volume.getSize(); - - /* lets make certain they (think they) know what they're doing if they - want to shrink, by forcing them to provide the shrinkok parameter. This will - be checked again at the hypervisor level where we can see the actual disk size */ - if (currentSize > newSize && !shrinkOk) { - throw new InvalidParameterValueException("Going from existing size of " + currentSize + " to size of " - + newSize + " would shrink the volume, need to sign off by supplying the shrinkok parameter with value of true"); - } - - /* get a list of hosts to send the commands to, try the system the - associated vm is running on first, then the last known place it ran. - If not attached to a userVm, we pass 'none' and resizevolume.sh is - ok with that since it only needs the vm name to live resize */ - long[] hosts = null; - String instanceName = "none"; - if (userVm != null) { - instanceName = userVm.getInstanceName(); - if(userVm.getHostId() != null) { - hosts = new long[] { userVm.getHostId() }; - } else if(userVm.getLastHostId() != null) { - hosts = new long[] { userVm.getLastHostId() }; - } - - /*Xen only works offline, SR does not support VDI.resizeOnline*/ - if(_volsDao.getHypervisorType(volume.getId()) == HypervisorType.XenServer - && ! userVm.getState().equals(State.Stopped)) { - throw new InvalidParameterValueException("VM must be stopped or disk detached in order to resize with the Xen HV"); - } - } - - try { - try { - stateTransitTo(volume, Volume.Event.ResizeRequested); - } catch (NoTransitionException etrans) { - throw new CloudRuntimeException("Unable to change volume state for resize: " + etrans.toString()); - } - - ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand(volume.getPath(), new StorageFilerTO(pool), - currentSize, newSize, shrinkOk, instanceName); - ResizeVolumeAnswer answer = (ResizeVolumeAnswer) sendToPool(pool, hosts, resizeCmd); - - /* need to fetch/store new volume size in database. This value comes from - hypervisor rather than trusting that a success means we have a volume of the - size we requested */ - if (answer != null && answer.getResult()) { - long finalSize = answer.getNewSize(); - s_logger.debug("Resize: volume started at size " + currentSize + " and ended at size " + finalSize); - volume.setSize(finalSize); - if (newDiskOffering != null) { - volume.setDiskOfferingId(cmd.getNewDiskOfferingId()); - } - _volsDao.update(volume.getId(), volume); - - success = true; - return volume; - } else if (answer != null) { - s_logger.debug("Resize: returned '" + answer.getDetails() + "'"); - } - } catch (StorageUnavailableException e) { - s_logger.debug("volume failed to resize: "+e); - return null; - } finally { - if(success) { - try { - stateTransitTo(volume, Volume.Event.OperationSucceeded); - } catch (NoTransitionException etrans) { - throw new CloudRuntimeException("Failed to change volume state: " + etrans.toString()); - } - } else { - try { - stateTransitTo(volume, Volume.Event.OperationFailed); - } catch (NoTransitionException etrans) { - throw new CloudRuntimeException("Failed to change volume state: " + etrans.toString()); - } - } - } - return null; - } - - @Override - @DB - public boolean destroyVolume(VolumeVO volume) throws ConcurrentOperationException { - try { - if (!stateTransitTo(volume, Volume.Event.DestroyRequested)) { - throw new ConcurrentOperationException("Failed to transit to destroyed state"); - } - } catch (NoTransitionException e) { - s_logger.debug("Unable to destoy the volume: " + e.toString()); - return false; - } - - long volumeId = volume.getId(); - - // Delete the recurring snapshot policies for this volume. - _snapshotMgr.deletePoliciesForVolume(volumeId); - - Long instanceId = volume.getInstanceId(); - VMInstanceVO vmInstance = null; - if (instanceId != null) { - vmInstance = _vmInstanceDao.findById(instanceId); - } - - if (instanceId == null || (vmInstance.getType().equals(VirtualMachine.Type.User))) { - // Decrement the resource count for volumes belonging user VM's only - _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume); - // Log usage event for volumes belonging user VM's only - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), - volume.getDataCenterId(), volume.getId(), volume.getName(), - Volume.class.getName(), volume.getUuid()); - } - - try { - if (!stateTransitTo(volume, Volume.Event.OperationSucceeded)) { - throw new ConcurrentOperationException("Failed to transit state"); - - } - } catch (NoTransitionException e) { - s_logger.debug("Unable to change volume state: " + e.toString()); - return false; - } - - return true; - - } - - @Override - public void createCapacityEntry(StoragePoolVO storagePool) { - createCapacityEntry(storagePool, Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, 0); - } + @Override public void createCapacityEntry(StoragePoolVO storagePool, short capacityType, long allocated) { @@ -2384,17 +1124,21 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } + cleanupSecondaryStorage(recurring); List vols = _volsDao.listVolumesToBeDestroyed(); for (VolumeVO vol : vols) { try { - expungeVolume(vol, false); + + this.volService.expungeVolumeAsync(this.volFactory.getVolume(vol.getId())); + } catch (Exception e) { s_logger.warn("Unable to destroy " + vol.getId(), e); } } + // remove snapshots in Error state List snapshots = _snapshotDao.listAllByStatus(Snapshot.State.Error); for (SnapshotVO snapshotVO : snapshots) { @@ -2405,11 +1149,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } - } finally { + }finally { scanLock.unlock(); } - } - } finally { + } + }finally { scanLock.releaseRef(); } } @@ -2430,7 +1174,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } return list; } catch (Exception e) { - s_logger.debug("failed to get all volumes who has snapshots in secondary storage " + hostId + " due to " + e.getMessage()); + s_logger.debug("failed to get all volumes who has snapshots in secondary storage " + + hostId + " due to " + e.getMessage()); return null; } @@ -2451,7 +1196,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } return list; } catch (Exception e) { - s_logger.debug("failed to get all snapshots for a volume " + volumeId + " due to " + e.getMessage()); + s_logger.debug("failed to get all snapshots for a volume " + + volumeId + " due to " + e.getMessage()); return null; } } @@ -2461,42 +1207,66 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C public void cleanupSecondaryStorage(boolean recurring) { try { // Cleanup templates in secondary storage hosts - List secondaryStorageHosts = _ssvmMgr.listSecondaryStorageHostsInAllZones(); + List secondaryStorageHosts = _ssvmMgr + .listSecondaryStorageHostsInAllZones(); for (HostVO secondaryStorageHost : secondaryStorageHosts) { try { long hostId = secondaryStorageHost.getId(); - List destroyedTemplateHostVOs = _vmTemplateHostDao.listDestroyed(hostId); - s_logger.debug("Secondary storage garbage collector found " + destroyedTemplateHostVOs.size() + " templates to cleanup on secondary storage host: " + List destroyedTemplateHostVOs = _vmTemplateHostDao + .listDestroyed(hostId); + s_logger.debug("Secondary storage garbage collector found " + + destroyedTemplateHostVOs.size() + + " templates to cleanup on secondary storage host: " + secondaryStorageHost.getName()); for (VMTemplateHostVO destroyedTemplateHostVO : destroyedTemplateHostVOs) { - if (!_tmpltMgr.templateIsDeleteable(destroyedTemplateHostVO)) { + if (!_tmpltMgr + .templateIsDeleteable(destroyedTemplateHostVO)) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Not deleting template at: " + destroyedTemplateHostVO); + s_logger.debug("Not deleting template at: " + + destroyedTemplateHostVO); } continue; } if (s_logger.isDebugEnabled()) { - s_logger.debug("Deleting template host: " + destroyedTemplateHostVO); + s_logger.debug("Deleting template host: " + + destroyedTemplateHostVO); } - String installPath = destroyedTemplateHostVO.getInstallPath(); + String installPath = destroyedTemplateHostVO + .getInstallPath(); if (installPath != null) { - Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteTemplateCommand(secondaryStorageHost.getStorageUrl(), destroyedTemplateHostVO.getInstallPath())); + Answer answer = _agentMgr.sendToSecStorage( + secondaryStorageHost, + new DeleteTemplateCommand( + secondaryStorageHost + .getStorageUrl(), + destroyedTemplateHostVO + .getInstallPath())); if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + destroyedTemplateHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); + s_logger.debug("Failed to delete " + + destroyedTemplateHostVO + + " due to " + + ((answer == null) ? "answer is null" + : answer.getDetails())); } else { - _vmTemplateHostDao.remove(destroyedTemplateHostVO.getId()); - s_logger.debug("Deleted template at: " + destroyedTemplateHostVO.getInstallPath()); + _vmTemplateHostDao + .remove(destroyedTemplateHostVO.getId()); + s_logger.debug("Deleted template at: " + + destroyedTemplateHostVO + .getInstallPath()); } } else { - _vmTemplateHostDao.remove(destroyedTemplateHostVO.getId()); + _vmTemplateHostDao.remove(destroyedTemplateHostVO + .getId()); } } } catch (Exception e) { - s_logger.warn("problem cleaning up templates in secondary storage " + secondaryStorageHost, e); + s_logger.warn( + "problem cleaning up templates in secondary storage " + + secondaryStorageHost, e); } } @@ -2511,9 +1281,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C for (Long volumeId : vIDs) { boolean lock = false; try { - VolumeVO volume = _volsDao.findByIdIncludingRemoved(volumeId); + VolumeVO volume = _volsDao + .findByIdIncludingRemoved(volumeId); if (volume.getRemoved() == null) { - volume = _volsDao.acquireInLockTable(volumeId, 10); + volume = _volsDao.acquireInLockTable(volumeId, + 10); if (volume == null) { continue; } @@ -2523,16 +1295,25 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C if (snapshots == null) { continue; } - CleanupSnapshotBackupCommand cmd = new CleanupSnapshotBackupCommand(secondaryStorageHost.getStorageUrl(), secondaryStorageHost.getDataCenterId(), volume.getAccountId(), - volumeId, snapshots); + CleanupSnapshotBackupCommand cmd = new CleanupSnapshotBackupCommand( + secondaryStorageHost.getStorageUrl(), + secondaryStorageHost.getDataCenterId(), + volume.getAccountId(), volumeId, snapshots); - Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, cmd); + Answer answer = _agentMgr.sendToSecStorage( + secondaryStorageHost, cmd); if ((answer == null) || !answer.getResult()) { - String details = "Failed to cleanup snapshots for volume " + volumeId + " due to " + (answer == null ? "null" : answer.getDetails()); + String details = "Failed to cleanup snapshots for volume " + + volumeId + + " due to " + + (answer == null ? "null" : answer + .getDetails()); s_logger.warn(details); } } catch (Exception e1) { - s_logger.warn("problem cleaning up snapshots in secondary storage " + secondaryStorageHost, e1); + s_logger.warn( + "problem cleaning up snapshots in secondary storage " + + secondaryStorageHost, e1); } finally { if (lock) { _volsDao.releaseFromLockTable(volumeId); @@ -2540,40 +1321,63 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } } catch (Exception e2) { - s_logger.warn("problem cleaning up snapshots in secondary storage " + secondaryStorageHost, e2); + s_logger.warn( + "problem cleaning up snapshots in secondary storage " + + secondaryStorageHost, e2); } } - //CleanUp volumes on Secondary Storage. + // CleanUp volumes on Secondary Storage. for (HostVO secondaryStorageHost : secondaryStorageHosts) { try { long hostId = secondaryStorageHost.getId(); - List destroyedVolumeHostVOs = _volumeHostDao.listDestroyed(hostId); - s_logger.debug("Secondary storage garbage collector found " + destroyedVolumeHostVOs.size() + " templates to cleanup on secondary storage host: " + List destroyedVolumeHostVOs = _volumeHostDao + .listDestroyed(hostId); + s_logger.debug("Secondary storage garbage collector found " + + destroyedVolumeHostVOs.size() + + " templates to cleanup on secondary storage host: " + secondaryStorageHost.getName()); for (VolumeHostVO destroyedVolumeHostVO : destroyedVolumeHostVOs) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Deleting volume host: " + destroyedVolumeHostVO); + s_logger.debug("Deleting volume host: " + + destroyedVolumeHostVO); } - String installPath = destroyedVolumeHostVO.getInstallPath(); + String installPath = destroyedVolumeHostVO + .getInstallPath(); if (installPath != null) { - Answer answer = _agentMgr.sendToSecStorage(secondaryStorageHost, new DeleteVolumeCommand(secondaryStorageHost.getStorageUrl(), destroyedVolumeHostVO.getInstallPath())); + Answer answer = _agentMgr.sendToSecStorage( + secondaryStorageHost, + new DeleteVolumeCommand( + secondaryStorageHost + .getStorageUrl(), + destroyedVolumeHostVO + .getInstallPath())); if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + destroyedVolumeHostVO + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); + s_logger.debug("Failed to delete " + + destroyedVolumeHostVO + + " due to " + + ((answer == null) ? "answer is null" + : answer.getDetails())); } else { - _volumeHostDao.remove(destroyedVolumeHostVO.getId()); - s_logger.debug("Deleted volume at: " + destroyedVolumeHostVO.getInstallPath()); + _volumeHostDao.remove(destroyedVolumeHostVO + .getId()); + s_logger.debug("Deleted volume at: " + + destroyedVolumeHostVO + .getInstallPath()); } } else { - _volumeHostDao.remove(destroyedVolumeHostVO.getId()); + _volumeHostDao + .remove(destroyedVolumeHostVO.getId()); } } - }catch (Exception e2) { - s_logger.warn("problem cleaning up volumes in secondary storage " + secondaryStorageHost, e2); + } catch (Exception e2) { + s_logger.warn( + "problem cleaning up volumes in secondary storage " + + secondaryStorageHost, e2); } } } catch (Exception e3) { @@ -2585,235 +1389,63 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C public String getPrimaryStorageNameLabel(VolumeVO volume) { Long poolId = volume.getPoolId(); - // poolId is null only if volume is destroyed, which has been checked before. + // poolId is null only if volume is destroyed, which has been checked + // before. assert poolId != null; - StoragePoolVO storagePoolVO = _storagePoolDao.findById(poolId); - assert storagePoolVO != null; - return storagePoolVO.getUuid(); + StoragePoolVO PrimaryDataStoreVO = _storagePoolDao + .findById(poolId); + assert PrimaryDataStoreVO != null; + return PrimaryDataStoreVO.getUuid(); } @Override @DB - public StoragePoolVO preparePrimaryStorageForMaintenance(Long primaryStorageId) throws ResourceUnavailableException, InsufficientCapacityException { + public PrimaryDataStoreInfo preparePrimaryStorageForMaintenance( + Long primaryStorageId) throws ResourceUnavailableException, + InsufficientCapacityException { Long userId = UserContext.current().getCallerUserId(); User user = _userDao.findById(userId); Account account = UserContext.current().getCaller(); + boolean restart = true; StoragePoolVO primaryStorage = null; - try { - // 1. Get the primary storage record and perform validation check - primaryStorage = _storagePoolDao.lockRow(primaryStorageId, true); - if (primaryStorage == null) { - String msg = "Unable to obtain lock on the storage pool record in preparePrimaryStorageForMaintenance()"; - s_logger.error(msg); - throw new ExecutionException(msg); - } - - List spes = _storagePoolDao.listBy(primaryStorage.getDataCenterId(), primaryStorage.getPodId(), primaryStorage.getClusterId()); - for (StoragePoolVO sp : spes) { - if (sp.getStatus() == StoragePoolStatus.PrepareForMaintenance) { - throw new CloudRuntimeException("Only one storage pool in a cluster can be in PrepareForMaintenance mode, " + sp.getId() + " is already in PrepareForMaintenance mode "); - } - } - - if (!primaryStorage.getStatus().equals(StoragePoolStatus.Up) && !primaryStorage.getStatus().equals(StoragePoolStatus.ErrorInMaintenance)) { - throw new InvalidParameterValueException("Primary storage with id " + primaryStorageId + " is not ready for migration, as the status is:" + primaryStorage.getStatus().toString()); - } - - List hosts = _resourceMgr.listHostsInClusterByStatus(primaryStorage.getClusterId(), Status.Up); - if (hosts == null || hosts.size() == 0) { - primaryStorage.setStatus(StoragePoolStatus.Maintenance); - _storagePoolDao.update(primaryStorageId, primaryStorage); - return _storagePoolDao.findById(primaryStorageId); - } else { - // set the pool state to prepare for maintenance - primaryStorage.setStatus(StoragePoolStatus.PrepareForMaintenance); - _storagePoolDao.update(primaryStorageId, primaryStorage); - } - // remove heartbeat - for (HostVO host : hosts) { - ModifyStoragePoolCommand cmd = new ModifyStoragePoolCommand(false, primaryStorage); - final Answer answer = _agentMgr.easySend(host.getId(), cmd); - if (answer == null || !answer.getResult()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("ModifyStoragePool false failed due to " + ((answer == null) ? "answer null" : answer.getDetails())); - } - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("ModifyStoragePool false secceeded"); - } - } - } - // check to see if other ps exist - // if they do, then we can migrate over the system vms to them - // if they dont, then just stop all vms on this one - List upPools = _storagePoolDao.listByStatusInZone(primaryStorage.getDataCenterId(), StoragePoolStatus.Up); - - if (upPools == null || upPools.size() == 0) { - restart = false; - } - - // 2. Get a list of all the ROOT volumes within this storage pool - List allVolumes = _volsDao.findByPoolId(primaryStorageId); - - // 3. Enqueue to the work queue - for (VolumeVO volume : allVolumes) { - VMInstanceVO vmInstance = _vmInstanceDao.findById(volume.getInstanceId()); - - if (vmInstance == null) { - continue; - } - - // enqueue sp work - if (vmInstance.getState().equals(State.Running) || vmInstance.getState().equals(State.Starting) || vmInstance.getState().equals(State.Stopping)) { - - try { - StoragePoolWorkVO work = new StoragePoolWorkVO(vmInstance.getId(), primaryStorageId, false, false, _serverId); - _storagePoolWorkDao.persist(work); - } catch (Exception e) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Work record already exists, re-using by re-setting values"); - } - StoragePoolWorkVO work = _storagePoolWorkDao.findByPoolIdAndVmId(primaryStorageId, vmInstance.getId()); - work.setStartedAfterMaintenance(false); - work.setStoppedForMaintenance(false); - work.setManagementServerId(_serverId); - _storagePoolWorkDao.update(work.getId(), work); - } - } - } - - // 4. Process the queue - List pendingWork = _storagePoolWorkDao.listPendingWorkForPrepareForMaintenanceByPoolId(primaryStorageId); - - for (StoragePoolWorkVO work : pendingWork) { - // shut down the running vms - VMInstanceVO vmInstance = _vmInstanceDao.findById(work.getVmId()); - - if (vmInstance == null) { - continue; - } - - // if the instance is of type consoleproxy, call the console proxy - if (vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) { - // call the consoleproxymanager - ConsoleProxyVO consoleProxy = _consoleProxyDao.findById(vmInstance.getId()); - if (!_vmMgr.advanceStop(consoleProxy, true, user, account)) { - String errorMsg = "There was an error stopping the console proxy id: " + vmInstance.getId() + " ,cannot enable storage maintenance"; - s_logger.warn(errorMsg); - throw new CloudRuntimeException(errorMsg); - } else { - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - - if (restart) { - - if (_vmMgr.advanceStart(consoleProxy, null, user, account) == null) { - String errorMsg = "There was an error starting the console proxy id: " + vmInstance.getId() + " on another storage pool, cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - } else { - // update work status - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - } - - // if the instance is of type uservm, call the user vm manager - if (vmInstance.getType().equals(VirtualMachine.Type.User)) { - UserVmVO userVm = _userVmDao.findById(vmInstance.getId()); - if (!_vmMgr.advanceStop(userVm, true, user, account)) { - String errorMsg = "There was an error stopping the user vm id: " + vmInstance.getId() + " ,cannot enable storage maintenance"; - s_logger.warn(errorMsg); - throw new CloudRuntimeException(errorMsg); - } else { - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - - // if the instance is of type secondary storage vm, call the secondary storage vm manager - if (vmInstance.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) { - SecondaryStorageVmVO secStrgVm = _secStrgDao.findById(vmInstance.getId()); - if (!_vmMgr.advanceStop(secStrgVm, true, user, account)) { - String errorMsg = "There was an error stopping the ssvm id: " + vmInstance.getId() + " ,cannot enable storage maintenance"; - s_logger.warn(errorMsg); - throw new CloudRuntimeException(errorMsg); - } else { - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - - if (restart) { - if (_vmMgr.advanceStart(secStrgVm, null, user, account) == null) { - String errorMsg = "There was an error starting the ssvm id: " + vmInstance.getId() + " on another storage pool, cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - } else { - // update work status - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - } - - // if the instance is of type domain router vm, call the network manager - if (vmInstance.getType().equals(VirtualMachine.Type.DomainRouter)) { - DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); - if (!_vmMgr.advanceStop(domR, true, user, account)) { - String errorMsg = "There was an error stopping the domain router id: " + vmInstance.getId() + " ,cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - throw new CloudRuntimeException(errorMsg); - } else { - // update work status - work.setStoppedForMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - - if (restart) { - if (_vmMgr.advanceStart(domR, null, user, account) == null) { - String errorMsg = "There was an error starting the domain router id: " + vmInstance.getId() + " on another storage pool, cannot enable primary storage maintenance"; - s_logger.warn(errorMsg); - } else { - // update work status - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - } - } - - // 5. Update the status - primaryStorage.setStatus(StoragePoolStatus.Maintenance); - _storagePoolDao.update(primaryStorageId, primaryStorage); - - return _storagePoolDao.findById(primaryStorageId); - } catch (Exception e) { - if (e instanceof ExecutionException || e instanceof ResourceUnavailableException) { - s_logger.error("Exception in enabling primary storage maintenance:", e); - setPoolStateToError(primaryStorage); - throw (ResourceUnavailableException) e; - } - if (e instanceof InvalidParameterValueException) { - s_logger.error("Exception in enabling primary storage maintenance:", e); - setPoolStateToError(primaryStorage); - throw (InvalidParameterValueException) e; - } - if (e instanceof InsufficientCapacityException) { - s_logger.error("Exception in enabling primary storage maintenance:", e); - setPoolStateToError(primaryStorage); - throw (InsufficientCapacityException) e; - } - // for everything else - s_logger.error("Exception in enabling primary storage maintenance:", e); - setPoolStateToError(primaryStorage); - throw new CloudRuntimeException(e.getMessage()); + primaryStorage = _storagePoolDao.findById(primaryStorageId); + if (primaryStorage == null) { + String msg = "Unable to obtain lock on the storage pool record in preparePrimaryStorageForMaintenance()"; + s_logger.error(msg); + throw new InvalidParameterValueException(msg); } + + List spes = _storagePoolDao.listBy( + primaryStorage.getDataCenterId(), primaryStorage.getPodId(), + primaryStorage.getClusterId()); + for (StoragePoolVO sp : spes) { + if (sp.getStatus() == StoragePoolStatus.PrepareForMaintenance) { + throw new CloudRuntimeException( + "Only one storage pool in a cluster can be in PrepareForMaintenance mode, " + + sp.getId() + + " is already in PrepareForMaintenance mode "); + } + } + + if (!primaryStorage.getStatus().equals(DataStoreStatus.Up) + && !primaryStorage.getStatus().equals( + DataStoreStatus.ErrorInMaintenance)) { + throw new InvalidParameterValueException("Primary storage with id " + + primaryStorageId + + " is not ready for migration, as the status is:" + + primaryStorage.getStatus().toString()); + } + + DataStoreProvider provider = dataStoreProviderMgr + .getDataStoreProviderById(primaryStorage.getStorageProviderId()); + DataStoreLifeCycle lifeCycle = provider.getLifeCycle(); + lifeCycle.maintain(primaryStorage.getId()); + + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore( + primaryStorage.getId(), DataStoreRole.Primary); } private void setPoolStateToError(StoragePoolVO primaryStorage) { @@ -2823,156 +1455,46 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Override @DB - public StoragePoolVO cancelPrimaryStorageForMaintenance(CancelPrimaryStorageMaintenanceCmd cmd) throws ResourceUnavailableException { + public PrimaryDataStoreInfo cancelPrimaryStorageForMaintenance( + CancelPrimaryStorageMaintenanceCmd cmd) + throws ResourceUnavailableException { Long primaryStorageId = cmd.getId(); Long userId = UserContext.current().getCallerUserId(); User user = _userDao.findById(userId); Account account = UserContext.current().getCaller(); StoragePoolVO primaryStorage = null; - try { - Transaction txn = Transaction.currentTxn(); - txn.start(); - // 1. Get the primary storage record and perform validation check - primaryStorage = _storagePoolDao.lockRow(primaryStorageId, true); - if (primaryStorage == null) { - String msg = "Unable to obtain lock on the storage pool in cancelPrimaryStorageForMaintenance()"; - s_logger.error(msg); - throw new ExecutionException(msg); - } + primaryStorage = _storagePoolDao.findById(primaryStorageId); - if (primaryStorage.getStatus().equals(StoragePoolStatus.Up) || primaryStorage.getStatus().equals(StoragePoolStatus.PrepareForMaintenance)) { - throw new StorageUnavailableException("Primary storage with id " + primaryStorageId + " is not ready to complete migration, as the status is:" + primaryStorage.getStatus().toString(), - primaryStorageId); - } - - // Change the storage state back to up - primaryStorage.setStatus(StoragePoolStatus.Up); - _storagePoolDao.update(primaryStorageId, primaryStorage); - txn.commit(); - List hosts = _resourceMgr.listHostsInClusterByStatus(primaryStorage.getClusterId(), Status.Up); - if (hosts == null || hosts.size() == 0) { - return _storagePoolDao.findById(primaryStorageId); - } - // add heartbeat - for (HostVO host : hosts) { - ModifyStoragePoolCommand msPoolCmd = new ModifyStoragePoolCommand(true, primaryStorage); - final Answer answer = _agentMgr.easySend(host.getId(), msPoolCmd); - if (answer == null || !answer.getResult()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("ModifyStoragePool add failed due to " + ((answer == null) ? "answer null" : answer.getDetails())); - } - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("ModifyStoragePool add secceeded"); - } - } - } - - // 2. Get a list of pending work for this queue - List pendingWork = _storagePoolWorkDao.listPendingWorkForCancelMaintenanceByPoolId(primaryStorageId); - - // 3. work through the queue - for (StoragePoolWorkVO work : pendingWork) { - - VMInstanceVO vmInstance = _vmInstanceDao.findById(work.getVmId()); - - if (vmInstance == null) { - continue; - } - - // if the instance is of type consoleproxy, call the console proxy - if (vmInstance.getType().equals(VirtualMachine.Type.ConsoleProxy)) { - - ConsoleProxyVO consoleProxy = _consoleProxyDao.findById(vmInstance.getId()); - if (_vmMgr.advanceStart(consoleProxy, null, user, account) == null) { - String msg = "There was an error starting the console proxy id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } else { - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - - // if the instance is of type ssvm, call the ssvm manager - if (vmInstance.getType().equals(VirtualMachine.Type.SecondaryStorageVm)) { - SecondaryStorageVmVO ssVm = _secStrgDao.findById(vmInstance.getId()); - if (_vmMgr.advanceStart(ssVm, null, user, account) == null) { - String msg = "There was an error starting the ssvm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } else { - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - - // if the instance is of type ssvm, call the ssvm manager - if (vmInstance.getType().equals(VirtualMachine.Type.DomainRouter)) { - DomainRouterVO domR = _domrDao.findById(vmInstance.getId()); - if (_vmMgr.advanceStart(domR, null, user, account) == null) { - String msg = "There was an error starting the domR id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } else { - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } - - // if the instance is of type user vm, call the user vm manager - if (vmInstance.getType().equals(VirtualMachine.Type.User)) { - UserVmVO userVm = _userVmDao.findById(vmInstance.getId()); - try { - if (_vmMgr.advanceStart(userVm, null, user, account) == null) { - - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg); - throw new ExecutionException(msg); - } else { - // update work queue - work.setStartedAfterMaintenance(true); - _storagePoolWorkDao.update(work.getId(), work); - } - } catch (StorageUnavailableException e) { - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg, e); - throw new ExecutionException(msg); - } catch (InsufficientCapacityException e) { - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg, e); - throw new ExecutionException(msg); - } catch (ConcurrentOperationException e) { - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg, e); - throw new ExecutionException(msg); - } catch (ExecutionException e) { - String msg = "There was an error starting the user vm id: " + vmInstance.getId() + " on storage pool, cannot complete primary storage maintenance"; - s_logger.warn(msg, e); - throw new ExecutionException(msg); - } - } - } - return primaryStorage; - } catch (Exception e) { - setPoolStateToError(primaryStorage); - if (e instanceof ExecutionException) { - throw (ResourceUnavailableException) e; - } else if (e instanceof InvalidParameterValueException) { - throw (InvalidParameterValueException) e; - } else {// all other exceptions - throw new CloudRuntimeException(e.getMessage()); - } + if (primaryStorage == null) { + String msg = "Unable to obtain lock on the storage pool in cancelPrimaryStorageForMaintenance()"; + s_logger.error(msg); + throw new InvalidParameterValueException(msg); } + + if (primaryStorage.getStatus().equals(DataStoreStatus.Up) + || primaryStorage.getStatus().equals( + DataStoreStatus.PrepareForMaintenance)) { + throw new StorageUnavailableException("Primary storage with id " + + primaryStorageId + + " is not ready to complete migration, as the status is:" + + primaryStorage.getStatus().toString(), primaryStorageId); + } + + DataStoreProvider provider = dataStoreProviderMgr + .getDataStoreProviderById(primaryStorage.getStorageProviderId()); + DataStoreLifeCycle lifeCycle = provider.getLifeCycle(); + lifeCycle.cancelMaintain(primaryStorage.getId()); + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore( + primaryStorage.getId(), DataStoreRole.Primary); } - private boolean sendToVmResidesOn(StoragePoolVO storagePool, Command cmd) { - ClusterVO cluster = _clusterDao.findById(storagePool.getClusterId()); - if ((cluster.getHypervisorType() == HypervisorType.KVM || cluster.getHypervisorType() == HypervisorType.VMware) + private boolean sendToVmResidesOn(StoragePoolVO PrimaryDataStoreVO, + Command cmd) { + ClusterVO cluster = _clusterDao.findById(PrimaryDataStoreVO + .getClusterId()); + if ((cluster.getHypervisorType() == HypervisorType.KVM || cluster + .getHypervisorType() == HypervisorType.VMware) && ((cmd instanceof ManageSnapshotCommand) || (cmd instanceof BackupSnapshotCommand))) { return true; } else { @@ -2980,754 +1502,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume") - public boolean deleteVolume(long volumeId, Account caller) throws ConcurrentOperationException { - - // Check that the volume ID is valid - VolumeVO volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new InvalidParameterValueException("Unable to aquire volume with ID: " + volumeId); - } - - if (!_snapshotMgr.canOperateOnVolume(volume)) { - throw new InvalidParameterValueException("There are snapshot creating on it, Unable to delete the volume"); - } - - // permission check - _accountMgr.checkAccess(caller, null, true, volume); - - // Check that the volume is not currently attached to any VM - if (volume.getInstanceId() != null) { - throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM."); - } - - // Check that volume is completely Uploaded - if (volume.getState() == Volume.State.UploadOp){ - VolumeHostVO volumeHost = _volumeHostDao.findByVolumeId(volume.getId()); - if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS){ - throw new InvalidParameterValueException("Please specify a volume that is not uploading"); - } - } - - // Check that the volume is not already destroyed - if (volume.getState() != Volume.State.Destroy) { - if (!destroyVolume(volume)) { - return false; - } - } - - try { - expungeVolume(volume, false); - } catch (Exception e) { - s_logger.warn("Failed to expunge volume:", e); - return false; - } - - return true; - } - - private boolean validateVolumeSizeRange(long size) { - if (size < 0 || (size > 0 && size < (1024 * 1024 * 1024))) { - throw new InvalidParameterValueException("Please specify a size of at least 1 Gb."); - } else if (size > (_maxVolumeSizeInGb * 1024 * 1024 * 1024)) { - throw new InvalidParameterValueException("volume size " + size + ", but the maximum size allowed is " + _maxVolumeSizeInGb + " Gb."); - } - - return true; - } - - protected DiskProfile toDiskProfile(VolumeVO vol, DiskOfferingVO offering) { - return new DiskProfile(vol.getId(), vol.getVolumeType(), vol.getName(), offering.getId(), vol.getSize(), offering.getTagsArray(), offering.getUseLocalStorage(), offering.isRecreatable(), - vol.getTemplateId()); - } - - @Override - public DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, T vm, Account owner) { - if (size == null) { - size = offering.getDiskSize(); - } else { - size = (size * 1024 * 1024 * 1024); - } - VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size); - if (vm != null) { - vol.setInstanceId(vm.getId()); - } - - if (type.equals(Type.ROOT)) { - vol.setDeviceId(0l); - } else { - vol.setDeviceId(1l); - } - - vol = _volsDao.persist(vol); - - // Save usage event and update resource count for user vm volumes - if (vm instanceof UserVm) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), - vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size, - Volume.class.getName(), vol.getUuid()); - _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume); - } - return toDiskProfile(vol, offering); - } - - @Override - public 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...."; - - SearchCriteria sc = HostTemplateStatesSearch.create(); - sc.setParameters("id", template.getId()); - sc.setParameters("state", com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); - sc.setJoinParameters("host", "dcId", vm.getDataCenterId()); - List tsvs = _vmTemplateSwiftDao.listByTemplateId(template.getId()); - Long size = null; - if (tsvs != null && tsvs.size() > 0) { - size = tsvs.get(0).getSize(); - } - - if (size == null && _s3Mgr.isS3Enabled()) { - VMTemplateS3VO vmTemplateS3VO = _vmTemplateS3Dao.findOneByTemplateId(template.getId()); - if (vmTemplateS3VO != null) { - size = vmTemplateS3VO.getSize(); - } - } - - if (size == null) { - List sss = _vmTemplateHostDao.search(sc, null); - if (sss == null || sss.size() == 0) { - throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + vm.getDataCenterId()); - } - size = sss.get(0).getSize(); - } - - VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), size); - if (vm != null) { - vol.setInstanceId(vm.getId()); - } - vol.setTemplateId(template.getId()); - - if (type.equals(Type.ROOT)) { - vol.setDeviceId(0l); - if (!vm.getType().equals(VirtualMachine.Type.User)) { - vol.setRecreatable(true); - } - } else { - vol.setDeviceId(1l); - } - - vol = _volsDao.persist(vol); - - // Create event and update resource count for volumes if vm is a user vm - if (vm instanceof UserVm) { - - Long offeringId = null; - - if (offering.getType() == DiskOfferingVO.Type.Disk) { - offeringId = offering.getId(); - } - - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), - vol.getDataCenterId(), vol.getId(), vol.getName(), offeringId, template.getId(), - vol.getSize(), Volume.class.getName(), vol.getUuid()); - - _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume); - } - return toDiskProfile(vol, offering); - } - - @Override - public void prepareForMigration(VirtualMachineProfile vm, DeployDestination dest) { - List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Preparing " + vols.size() + " volumes for " + vm); - } - - for (VolumeVO vol : vols) { - StoragePool pool = _storagePoolDao.findById(vol.getPoolId()); - vm.addDisk(new VolumeTO(vol, pool)); - } - - if (vm.getType() == VirtualMachine.Type.User) { - UserVmVO userVM = (UserVmVO) vm.getVirtualMachine(); - if (userVM.getIsoId() != null) { - Pair isoPathPair = getAbsoluteIsoPath(userVM.getIsoId(), userVM.getDataCenterId()); - if (isoPathPair != null) { - String isoPath = isoPathPair.first(); - VolumeTO iso = new VolumeTO(vm.getId(), Volume.Type.ISO, StoragePoolType.ISO, null, null, null, isoPath, 0, null, null); - vm.addDisk(iso); - } - } - } - } - - @DB - @Override - public Volume migrateVolume(Long volumeId, Long storagePoolId) throws ConcurrentOperationException { - VolumeVO vol = _volsDao.findById(volumeId); - if (vol == null) { - throw new InvalidParameterValueException("Failed to find the volume id: " + volumeId); - } - - if (vol.getState() != Volume.State.Ready) { - throw new InvalidParameterValueException("Volume must be in ready state"); - } - - if (vol.getInstanceId() != null) { - throw new InvalidParameterValueException("Volume needs to be dettached from VM"); - } - - StoragePool destPool = _storagePoolDao.findById(storagePoolId); - if (destPool == null) { - throw new InvalidParameterValueException("Failed to find the destination storage pool: " + storagePoolId); - } - - if (!volumeOnSharedStoragePool(vol)) { - throw new InvalidParameterValueException("Migration of volume from local storage pool is not supported"); - } - - List vols = new ArrayList(); - vols.add(vol); - - migrateVolumes(vols, destPool); - return vol; - } - - @DB - public boolean migrateVolumes(List volumes, StoragePool destPool) throws ConcurrentOperationException { - Transaction txn = Transaction.currentTxn(); - txn.start(); - - boolean transitResult = false; - long checkPointTaskId = -1; - try { - List volIds = new ArrayList(); - for (Volume volume : volumes) { - if (!_snapshotMgr.canOperateOnVolume((VolumeVO) volume)) { - throw new CloudRuntimeException("There are snapshots creating on this volume, can not move this volume"); - } - - try { - if (!stateTransitTo(volume, Volume.Event.MigrationRequested)) { - throw new ConcurrentOperationException("Failed to transit volume state"); - } - } catch (NoTransitionException e) { - s_logger.debug("Failed to set state into migrate: " + e.toString()); - throw new CloudRuntimeException("Failed to set state into migrate: " + e.toString()); - } - volIds.add(volume.getId()); - } - - transitResult = true; - } finally { - if (!transitResult) { - txn.rollback(); - } else { - txn.commit(); - } - } - - // At this stage, nobody can modify volumes. Send the copyvolume command - List> destroyCmds = new ArrayList>(); - List answers = new ArrayList(); - try { - for (Volume volume : volumes) { - String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId()); - StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId()); - CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volume.getPath(), srcPool, secondaryStorageURL, true, _copyvolumewait); - CopyVolumeAnswer cvAnswer; - try { - cvAnswer = (CopyVolumeAnswer) sendToPool(srcPool, cvCmd); - } catch (StorageUnavailableException e1) { - throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.", e1); - } - - if (cvAnswer == null || !cvAnswer.getResult()) { - throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage."); - } - - String secondaryStorageVolumePath = cvAnswer.getVolumePath(); - - // Copy the volume from secondary storage to the destination storage - // pool - cvCmd = new CopyVolumeCommand(volume.getId(), secondaryStorageVolumePath, destPool, secondaryStorageURL, false, _copyvolumewait); - try { - cvAnswer = (CopyVolumeAnswer) sendToPool(destPool, cvCmd); - } catch (StorageUnavailableException e1) { - throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); - } - - if (cvAnswer == null || !cvAnswer.getResult()) { - throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool."); - } - - answers.add(cvAnswer); - destroyCmds.add(new Pair(srcPool, new DestroyCommand(srcPool, volume, null))); - } - } finally { - if (answers.size() != volumes.size()) { - // this means one of copying volume failed - for (Volume volume : volumes) { - try { - stateTransitTo(volume, Volume.Event.OperationFailed); - } catch (NoTransitionException e) { - s_logger.debug("Failed to change volume state: " + e.toString()); - } - } - } else { - // Need a transaction, make sure all the volumes get migrated to new storage pool - txn = Transaction.currentTxn(); - txn.start(); - - transitResult = false; - try { - for (int i = 0; i < volumes.size(); i++) { - CopyVolumeAnswer answer = answers.get(i); - VolumeVO volume = (VolumeVO) volumes.get(i); - Long oldPoolId = volume.getPoolId(); - volume.setPath(answer.getVolumePath()); - volume.setFolder(destPool.getPath()); - volume.setPodId(destPool.getPodId()); - volume.setPoolId(destPool.getId()); - volume.setLastPoolId(oldPoolId); - volume.setPodId(destPool.getPodId()); - try { - stateTransitTo(volume, Volume.Event.OperationSucceeded); - } catch (NoTransitionException e) { - s_logger.debug("Failed to change volume state: " + e.toString()); - throw new CloudRuntimeException("Failed to change volume state: " + e.toString()); - } - } - transitResult = true; - } finally { - if (!transitResult) { - txn.rollback(); - } else { - txn.commit(); - } - } - - } - } - - // all the volumes get migrated to new storage pool, need to delete the copy on old storage pool - for (Pair cmd : destroyCmds) { - try { - Answer cvAnswer = sendToPool(cmd.first(), cmd.second()); - } catch (StorageUnavailableException e) { - s_logger.debug("Unable to delete the old copy on storage pool: " + e.toString()); - } - } - return true; - } - - @Override - public boolean StorageMigration(VirtualMachineProfile vm, StoragePool destPool) throws ConcurrentOperationException { - List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); - List volumesNeedToMigrate = new ArrayList(); - - for (VolumeVO volume : vols) { - if (volume.getState() != Volume.State.Ready) { - s_logger.debug("volume: " + volume.getId() + " is in " + volume.getState() + " state"); - throw new CloudRuntimeException("volume: " + volume.getId() + " is in " + volume.getState() + " state"); - } - - if (volume.getPoolId() == destPool.getId()) { - s_logger.debug("volume: " + volume.getId() + " is on the same storage pool: " + destPool.getId()); - continue; - } - - volumesNeedToMigrate.add(volume); - } - - if (volumesNeedToMigrate.isEmpty()) { - s_logger.debug("No volume need to be migrated"); - return true; - } - - return migrateVolumes(volumesNeedToMigrate, destPool); - } - - @Override - public void prepare(VirtualMachineProfile vm, DeployDestination dest) throws StorageUnavailableException, InsufficientStorageCapacityException { - - if (dest == null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("DeployDestination cannot be null, cannot prepare Volumes for the vm: " + vm); - } - throw new CloudRuntimeException("Unable to prepare Volume for vm because DeployDestination is null, vm:" + vm); - } - List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Checking if we need to prepare " + vols.size() + " volumes for " + vm); - } - - boolean recreate = _recreateSystemVmEnabled; - - List recreateVols = new ArrayList(vols.size()); - - for (VolumeVO vol : vols) { - StoragePool assignedPool = null; - if (dest.getStorageForDisks() != null) { - assignedPool = dest.getStorageForDisks().get(vol); - } - if (assignedPool == null && recreate) { - assignedPool = _storagePoolDao.findById(vol.getPoolId()); - - } - if (assignedPool != null || recreate) { - Volume.State state = vol.getState(); - if (state == Volume.State.Allocated || state == Volume.State.Creating) { - recreateVols.add(vol); - } else { - if (vol.isRecreatable()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume " + vol + " will be recreated on storage pool " + assignedPool + " assigned by deploymentPlanner"); - } - recreateVols.add(vol); - } else { - if (assignedPool.getId() != vol.getPoolId()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Mismatch in storage pool " + assignedPool + " assigned by deploymentPlanner and the one associated with volume " + vol); - } - DiskOfferingVO diskOffering = _diskOfferingDao.findById(vol.getDiskOfferingId()); - if (diskOffering.getUseLocalStorage()) - { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Local volume " + vol + " will be recreated on storage pool " + assignedPool + " assigned by deploymentPlanner"); - } - recreateVols.add(vol); - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Shared volume " + vol + " will be migrated on storage pool " + assignedPool + " assigned by deploymentPlanner"); - } - try { - List volumesToMigrate = new ArrayList(); - volumesToMigrate.add(vol); - migrateVolumes(volumesToMigrate, assignedPool); - vm.addDisk(new VolumeTO(vol, assignedPool)); - } catch (ConcurrentOperationException e) { - throw new CloudRuntimeException("Migration of volume " + vol + " to storage pool " + assignedPool + " failed", e); - } - } - } else { - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); - vm.addDisk(new VolumeTO(vol, pool)); - } - - } - } - } else { - if (vol.getPoolId() == null) { - throw new StorageUnavailableException("Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create " + vol, Volume.class, vol.getId()); - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("No need to recreate the volume: " + vol + ", since it already has a pool assigned: " + vol.getPoolId() + ", adding disk to VM"); - } - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); - vm.addDisk(new VolumeTO(vol, pool)); - } - } - - for (VolumeVO vol : recreateVols) { - VolumeVO newVol; - StoragePool existingPool = null; - if (recreate && (dest.getStorageForDisks() == null || dest.getStorageForDisks().get(vol) == null)) { - existingPool = _storagePoolDao.findById(vol.getPoolId()); - s_logger.debug("existing pool: " + existingPool.getId()); - } - - if (vol.getState() == Volume.State.Allocated || vol.getState() == Volume.State.Creating) { - newVol = vol; - } else { - newVol = switchVolume(vol, vm); - // update the volume->storagePool map since volumeId has changed - if (dest.getStorageForDisks() != null && dest.getStorageForDisks().containsKey(vol)) { - StoragePool poolWithOldVol = dest.getStorageForDisks().get(vol); - dest.getStorageForDisks().put(newVol, poolWithOldVol); - dest.getStorageForDisks().remove(vol); - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Created new volume " + newVol + " for old volume " + vol); - } - } - - try { - stateTransitTo(newVol, Volume.Event.CreateRequested); - } catch (NoTransitionException e) { - throw new CloudRuntimeException("Unable to create " + e.toString()); - } - - Pair created = createVolume(newVol, _diskOfferingDao.findById(newVol.getDiskOfferingId()), vm, vols, dest, existingPool); - - if (created == null) { - Long poolId = newVol.getPoolId(); - newVol.setPoolId(null); - try { - stateTransitTo(newVol, Volume.Event.OperationFailed); - } catch (NoTransitionException e) { - throw new CloudRuntimeException("Unable to update the failure on a volume: " + newVol, e); - } - throw new StorageUnavailableException("Unable to create " + newVol, poolId == null ? -1L : poolId); - } - created.first().setDeviceId(newVol.getDeviceId().intValue()); - newVol.setFolder(created.second().getPath()); - newVol.setPath(created.first().getPath()); - newVol.setSize(created.first().getSize()); - newVol.setPoolType(created.second().getPoolType()); - newVol.setPodId(created.second().getPodId()); - try { - stateTransitTo(newVol, Volume.Event.OperationSucceeded); - } catch (NoTransitionException e) { - throw new CloudRuntimeException("Unable to update an CREATE operation succeeded on volume " + newVol, e); - } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume " + newVol + " is created on " + created.second()); - } - - vm.addDisk(created.first()); - } - } - - @DB - protected VolumeVO switchVolume(VolumeVO existingVolume, VirtualMachineProfile vm) throws StorageUnavailableException { - Transaction txn = Transaction.currentTxn(); - - Long templateIdToUse = null; - Long volTemplateId = existingVolume.getTemplateId(); - long vmTemplateId = vm.getTemplateId(); - if (volTemplateId != null && volTemplateId.longValue() != vmTemplateId) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("switchVolume: Old Volume's templateId: " + volTemplateId + " does not match the VM's templateId: " + vmTemplateId + ", updating templateId in the new Volume"); - } - templateIdToUse = vmTemplateId; - } - - txn.start(); - VolumeVO newVolume = allocateDuplicateVolume(existingVolume, templateIdToUse); - // In case of Vmware if vm reference is not removed then during root disk cleanup - // the vm also gets deleted, so remove the reference - if (vm.getHypervisorType() == HypervisorType.VMware) { - _volsDao.detachVolume(existingVolume.getId()); - } - try { - stateTransitTo(existingVolume, Volume.Event.DestroyRequested); - } catch (NoTransitionException e) { - s_logger.debug("Unable to destroy existing volume: " + e.toString()); - } - txn.commit(); - return newVolume; - - } - - public Pair createVolume(VolumeVO toBeCreated, DiskOfferingVO offering, VirtualMachineProfile vm, List alreadyCreated, - DeployDestination dest, StoragePool sPool) throws StorageUnavailableException { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Creating volume: " + toBeCreated); - } - DiskProfile diskProfile = new DiskProfile(toBeCreated, offering, vm.getHypervisorType()); - - VMTemplateVO template = null; - if (toBeCreated.getTemplateId() != null) { - template = _templateDao.findById(toBeCreated.getTemplateId()); - } - - StoragePool pool = null; - if (sPool != null) { - pool = sPool; - } else { - pool = dest.getStorageForDisks().get(toBeCreated); - } - - if (pool != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Trying to create in " + pool); - } - toBeCreated.setPoolId(pool.getId()); - try { - stateTransitTo(toBeCreated, Volume.Event.OperationRetry); - } catch (NoTransitionException e) { - throw new CloudRuntimeException("Unable to retry a create operation on volume " + toBeCreated); - } - - CreateCommand cmd = null; - VMTemplateStoragePoolVO tmpltStoredOn = null; - - for (int i = 0; i < 2; i++) { - if (template != null && template.getFormat() != Storage.ImageFormat.ISO) { - if (pool.getPoolType() == StoragePoolType.CLVM) { - //prepareISOForCreate does what we need, which is to tell us where the template is - VMTemplateHostVO tmpltHostOn = _tmpltMgr.prepareISOForCreate(template, pool); - if (tmpltHostOn == null) { - s_logger.debug("cannot find template " + template.getId() + " " + template.getName()); - return null; - } - HostVO secondaryStorageHost = _hostDao.findById(tmpltHostOn.getHostId()); - String tmpltHostUrl = secondaryStorageHost.getStorageUrl(); - String fullTmpltUrl = tmpltHostUrl + "/" + tmpltHostOn.getInstallPath(); - cmd = new CreateCommand(diskProfile, fullTmpltUrl, new StorageFilerTO(pool)); - } else { - tmpltStoredOn = _tmpltMgr.prepareTemplateForCreate(template, pool); - if (tmpltStoredOn == null) { - s_logger.debug("Cannot use this pool " + pool + " because we can't propagate template " + template); - return null; - } - cmd = new CreateCommand(diskProfile, tmpltStoredOn.getLocalDownloadPath(), new StorageFilerTO(pool)); - } - } else { - if (template != null && Storage.ImageFormat.ISO == template.getFormat()) { - VMTemplateHostVO tmpltHostOn = _tmpltMgr.prepareISOForCreate(template, pool); - if (tmpltHostOn == null) { - throw new CloudRuntimeException("Did not find ISO in secondry storage in zone " + pool.getDataCenterId()); - } - } - cmd = new CreateCommand(diskProfile, new StorageFilerTO(pool)); - } - long[] hostIdsToTryFirst = { dest.getHost().getId() }; - Answer answer = sendToPool(pool, hostIdsToTryFirst, cmd); - if (answer.getResult()) { - CreateAnswer createAnswer = (CreateAnswer) answer; - return new Pair(createAnswer.getVolume(), pool); - } else { - if (tmpltStoredOn != null && (answer instanceof CreateAnswer) && ((CreateAnswer) answer).templateReloadRequested()) { - if (!_tmpltMgr.resetTemplateDownloadStateOnPool(tmpltStoredOn.getId())) { - break; // break out of template-redeploy retry loop - } - } else { - break; - } - } - } - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("Unable to create volume " + toBeCreated); - } - return null; - } - - @Override - public void release(VirtualMachineProfile profile) { - // add code here - } - - public void expungeVolume(VolumeVO vol, boolean force) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Expunging " + vol); - } - - //Find out if the volume is present on secondary storage - VolumeHostVO volumeHost = _volumeHostDao.findByVolumeId(vol.getId()); - if(volumeHost != null){ - if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED){ - HostVO ssHost = _hostDao.findById(volumeHost.getHostId()); - DeleteVolumeCommand dtCommand = new DeleteVolumeCommand(ssHost.getStorageUrl(), volumeHost.getInstallPath()); - Answer answer = _agentMgr.sendToSecStorage(ssHost, dtCommand); - if (answer == null || !answer.getResult()) { - s_logger.debug("Failed to delete " + volumeHost + " due to " + ((answer == null) ? "answer is null" : answer.getDetails())); - return; - } - }else if(volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS){ - s_logger.debug("Volume: " + vol.getName() + " is currently being uploaded; cant' delete it."); - throw new CloudRuntimeException("Please specify a volume that is not currently being uploaded."); - } - _volumeHostDao.remove(volumeHost.getId()); - _volumeDao.remove(vol.getId()); - return; - } - - String vmName = null; - if (vol.getVolumeType() == Type.ROOT && vol.getInstanceId() != null) { - VirtualMachine vm = _vmInstanceDao.findByIdIncludingRemoved(vol.getInstanceId()); - if (vm != null) { - vmName = vm.getInstanceName(); - } - } - - String volumePath = vol.getPath(); - Long poolId = vol.getPoolId(); - if (poolId == null || volumePath == null || volumePath.trim().isEmpty()) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Marking volume that was never created as destroyed: " + vol); - } - _volsDao.remove(vol.getId()); - return; - } - - StoragePoolVO pool = _storagePoolDao.findById(poolId); - if (pool == null) { - s_logger.debug("Removing volume as storage pool is gone: " + poolId); - _volsDao.remove(vol.getId()); - return; - } - - DestroyCommand cmd = new DestroyCommand(pool, vol, vmName); - boolean removeVolume = false; - try { - Answer answer = sendToPool(pool, cmd); - if (answer != null && answer.getResult()) { - removeVolume = true; - } else { - s_logger.info("Will retry delete of " + vol + " from " + poolId); - } - } catch (StorageUnavailableException e) { - if (force) { - s_logger.info("Storage is unavailable currently, but marking volume id=" + vol.getId() + " as expunged anyway due to force=true"); - removeVolume = true; - } else { - s_logger.info("Storage is unavailable currently. Will retry delete of " + vol + " from " + poolId); - } - } catch (RuntimeException ex) { - if (force) { - s_logger.info("Failed to expunge volume, but marking volume id=" + vol.getId() + " as expunged anyway " + - "due to force=true. Volume failed to expunge due to ", ex); - removeVolume = true; - } else { - throw ex; - } - } finally { - if (removeVolume) { - _volsDao.remove(vol.getId()); - if (s_logger.isDebugEnabled()) { - s_logger.debug("Volume successfully expunged from " + poolId); - } - } - } - - } - - @Override - @DB - public void cleanupVolumes(long vmId) throws ConcurrentOperationException { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Cleaning storage for vm: " + vmId); - } - List volumesForVm = _volsDao.findByInstance(vmId); - List toBeExpunged = new ArrayList(); - Transaction txn = Transaction.currentTxn(); - txn.start(); - for (VolumeVO vol : volumesForVm) { - 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); - } - toBeExpunged.add(vol); - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Detaching " + vol); - } - _volsDao.detachVolume(vol.getId()); - } - } - txn.commit(); - - for (VolumeVO expunge : toBeExpunged) { - expungeVolume(expunge, false); - } - } - + + + protected class StorageGarbageCollector implements Runnable { public StorageGarbageCollector() { @@ -3747,25 +1524,35 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public void onManagementNodeJoined(List nodeList, long selfNodeId) { + public void onManagementNodeJoined(List nodeList, + long selfNodeId) { // TODO Auto-generated method stub } @Override - public void onManagementNodeLeft(List nodeList, long selfNodeId) { + public void onManagementNodeLeft(List nodeList, + long selfNodeId) { for (ManagementServerHostVO vo : nodeList) { if (vo.getMsid() == _serverId) { - s_logger.info("Cleaning up storage maintenance jobs associated with Management server" + vo.getMsid()); - List poolIds = _storagePoolWorkDao.searchForPoolIdsForPendingWorkJobs(vo.getMsid()); + s_logger.info("Cleaning up storage maintenance jobs associated with Management server" + + vo.getMsid()); + List poolIds = _storagePoolWorkDao + .searchForPoolIdsForPendingWorkJobs(vo.getMsid()); if (poolIds.size() > 0) { for (Long poolId : poolIds) { - StoragePoolVO pool = _storagePoolDao.findById(poolId); + StoragePoolVO pool = _storagePoolDao + .findById(poolId); // check if pool is in an inconsistent state if (pool != null - && (pool.getStatus().equals(StoragePoolStatus.ErrorInMaintenance) || pool.getStatus().equals(StoragePoolStatus.PrepareForMaintenance) || pool.getStatus().equals( - StoragePoolStatus.CancelMaintenance))) { - _storagePoolWorkDao.removePendingJobsOnMsRestart(vo.getMsid(), poolId); + && (pool.getStatus().equals( + DataStoreStatus.ErrorInMaintenance) + || pool.getStatus() + .equals(DataStoreStatus.PrepareForMaintenance) || pool + .getStatus() + .equals(DataStoreStatus.CancelMaintenance))) { + _storagePoolWorkDao.removePendingJobsOnMsRestart( + vo.getMsid(), poolId); pool.setStatus(StoragePoolStatus.ErrorInMaintenance); _storagePoolDao.update(poolId, pool); } @@ -3794,22 +1581,28 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C hosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(zoneId); } - CapacityVO capacity = new CapacityVO(hostId, zoneId, null, null, 0, 0, CapacityVO.CAPACITY_TYPE_SECONDARY_STORAGE); + CapacityVO capacity = new CapacityVO(hostId, zoneId, null, null, 0, 0, + CapacityVO.CAPACITY_TYPE_SECONDARY_STORAGE); for (HostVO host : hosts) { - StorageStats stats = ApiDBUtils.getSecondaryStorageStatistics(host.getId()); + StorageStats stats = ApiDBUtils.getSecondaryStorageStatistics(host + .getId()); if (stats == null) { continue; } - capacity.setUsedCapacity(stats.getByteUsed() + capacity.getUsedCapacity()); - capacity.setTotalCapacity(stats.getCapacityBytes() + capacity.getTotalCapacity()); + capacity.setUsedCapacity(stats.getByteUsed() + + capacity.getUsedCapacity()); + capacity.setTotalCapacity(stats.getCapacityBytes() + + capacity.getTotalCapacity()); } return capacity; } @Override - public CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, Long podId, Long zoneId) { - SearchCriteria sc = _storagePoolDao.createSearchCriteria(); + public CapacityVO getStoragePoolUsedStats(Long poolId, Long clusterId, + Long podId, Long zoneId) { + SearchCriteria sc = _storagePoolDao + .createSearchCriteria(); List pools = new ArrayList(); if (zoneId != null) { @@ -3833,59 +1626,29 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C pools = _storagePoolDao.search(sc, null); } - CapacityVO capacity = new CapacityVO(poolId, zoneId, podId, clusterId, 0, 0, CapacityVO.CAPACITY_TYPE_STORAGE); - for (StoragePoolVO storagePool : pools) { - StorageStats stats = ApiDBUtils.getStoragePoolStatistics(storagePool.getId()); + CapacityVO capacity = new CapacityVO(poolId, zoneId, podId, clusterId, + 0, 0, CapacityVO.CAPACITY_TYPE_STORAGE); + for (StoragePoolVO PrimaryDataStoreVO : pools) { + StorageStats stats = ApiDBUtils + .getStoragePoolStatistics(PrimaryDataStoreVO.getId()); if (stats == null) { continue; } - capacity.setUsedCapacity(stats.getByteUsed() + capacity.getUsedCapacity()); - capacity.setTotalCapacity(stats.getCapacityBytes() + capacity.getTotalCapacity()); + capacity.setUsedCapacity(stats.getByteUsed() + + capacity.getUsedCapacity()); + capacity.setTotalCapacity(stats.getCapacityBytes() + + capacity.getTotalCapacity()); } return capacity; } @Override - public StoragePool getStoragePool(long id) { - return _storagePoolDao.findById(id); + public PrimaryDataStoreInfo getStoragePool(long id) { + return (PrimaryDataStoreInfo) dataStoreMgr.getDataStore(id, + DataStoreRole.Primary); } - @Override - public VMTemplateHostVO findVmTemplateHost(long templateId, StoragePool pool) { - long dcId = pool.getDataCenterId(); - Long podId = pool.getPodId(); - - List secHosts = _ssvmMgr.listSecondaryStorageHostsInOneZone(dcId); - - // FIXME, for cloudzone, the local secondary storoge - if (pool.isLocal() && pool.getPoolType() == StoragePoolType.Filesystem && secHosts.isEmpty()) { - List sphs = _storagePoolHostDao.listByPoolId(pool.getId()); - if (!sphs.isEmpty()) { - StoragePoolHostVO localStoragePoolHost = sphs.get(0); - return _templateHostDao.findLocalSecondaryStorageByHostTemplate(localStoragePoolHost.getHostId(), templateId); - } else { - return null; - } - } - - if (secHosts.size() == 1) { - VMTemplateHostVO templateHostVO = _templateHostDao.findByHostTemplate(secHosts.get(0).getId(), templateId); - return templateHostVO; - } - if (podId != null) { - List templHosts = _templateHostDao.listByTemplateStatus(templateId, dcId, podId, VMTemplateStorageResourceAssoc.Status.DOWNLOADED); - if (templHosts != null && !templHosts.isEmpty()) { - Collections.shuffle(templHosts); - return templHosts.get(0); - } - } - List templHosts = _templateHostDao.listByTemplateStatus(templateId, dcId, VMTemplateStorageResourceAssoc.Status.DOWNLOADED); - if (templHosts != null && !templHosts.isEmpty()) { - Collections.shuffle(templHosts); - return templHosts.get(0); - } - return null; - } + @Override @DB @@ -3900,9 +1663,11 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @DB public StoragePoolVO findLocalStorageOnHost(long hostId) { SearchCriteria sc = LocalStorageSearch.create(); - sc.setParameters("type", new Object[] { StoragePoolType.Filesystem, StoragePoolType.LVM }); + sc.setParameters("type", new Object[] { StoragePoolType.Filesystem, + StoragePoolType.LVM }); sc.setJoinParameters("poolHost", "hostId", hostId); - List storagePools = _storagePoolDao.search(sc, null); + List storagePools = _storagePoolDao + .search(sc, null); if (!storagePools.isEmpty()) { return storagePools.get(0); } else { @@ -3914,25 +1679,33 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C public Host updateSecondaryStorage(long secStorageId, String newUrl) { HostVO secHost = _hostDao.findById(secStorageId); if (secHost == null) { - throw new InvalidParameterValueException("Can not find out the secondary storage id: " + secStorageId); + throw new InvalidParameterValueException( + "Can not find out the secondary storage id: " + + secStorageId); } if (secHost.getType() != Host.Type.SecondaryStorage) { - throw new InvalidParameterValueException("host: " + secStorageId + " is not a secondary storage"); + throw new InvalidParameterValueException("host: " + secStorageId + + " is not a secondary storage"); } URI uri = null; try { uri = new URI(UriUtils.encodeURIComponent(newUrl)); if (uri.getScheme() == null) { - throw new InvalidParameterValueException("uri.scheme is null " + newUrl + ", add nfs:// as a prefix"); + throw new InvalidParameterValueException("uri.scheme is null " + + newUrl + ", add nfs:// as a prefix"); } else if (uri.getScheme().equalsIgnoreCase("nfs")) { - if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") || uri.getPath() == null || uri.getPath().equalsIgnoreCase("")) { - throw new InvalidParameterValueException("Your host and/or path is wrong. Make sure it's of the format nfs://hostname/path"); + if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") + || uri.getPath() == null + || uri.getPath().equalsIgnoreCase("")) { + throw new InvalidParameterValueException( + "Your host and/or path is wrong. Make sure it's of the format nfs://hostname/path"); } } } catch (URISyntaxException e) { - throw new InvalidParameterValueException(newUrl + " is not a valid uri"); + throw new InvalidParameterValueException(newUrl + + " is not a valid uri"); } String oldUrl = secHost.getStorageUrl(); @@ -3941,7 +1714,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C try { oldUri = new URI(UriUtils.encodeURIComponent(oldUrl)); if (!oldUri.getScheme().equalsIgnoreCase(uri.getScheme())) { - throw new InvalidParameterValueException("can not change old scheme:" + oldUri.getScheme() + " to " + uri.getScheme()); + throw new InvalidParameterValueException( + "can not change old scheme:" + oldUri.getScheme() + + " to " + uri.getScheme()); } } catch (URISyntaxException e) { s_logger.debug("Failed to get uri from " + oldUrl); @@ -3954,29 +1729,12 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C return secHost; } - - - @Override - public String getSupportedImageFormatForCluster(Long clusterId) { - ClusterVO cluster = ApiDBUtils.findClusterById(clusterId); - - if (cluster.getHypervisorType() == HypervisorType.XenServer) { - return "vhd"; - } else if (cluster.getHypervisorType() == HypervisorType.KVM) { - return "qcow2"; - } else if (cluster.getHypervisorType() == HypervisorType.VMware) { - return "ova"; - } else if (cluster.getHypervisorType() == HypervisorType.Ovm) { - return "raw"; - } else { - return null; - } - } + @Override public HypervisorType getHypervisorTypeFromFormat(ImageFormat format) { - if(format == null) { + if (format == null) { return HypervisorType.None; } @@ -3993,22 +1751,32 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } } - private boolean checkUsagedSpace(StoragePool pool){ + private boolean checkUsagedSpace(StoragePool pool) { StatsCollector sc = StatsCollector.getInstance(); if (sc != null) { long totalSize = pool.getCapacityBytes(); StorageStats stats = sc.getStoragePoolStats(pool.getId()); - if(stats == null){ + if (stats == null) { stats = sc.getStorageStats(pool.getId()); } if (stats != null) { - double usedPercentage = ((double)stats.getByteUsed() / (double)totalSize); + double usedPercentage = ((double) stats.getByteUsed() / (double) totalSize); if (s_logger.isDebugEnabled()) { - s_logger.debug("Checking pool " + pool.getId() + " for storage, totalSize: " + pool.getCapacityBytes() + ", usedBytes: " + stats.getByteUsed() + ", usedPct: " + usedPercentage + ", disable threshold: " + _storageUsedThreshold); + s_logger.debug("Checking pool " + pool.getId() + + " for storage, totalSize: " + + pool.getCapacityBytes() + ", usedBytes: " + + stats.getByteUsed() + ", usedPct: " + + usedPercentage + ", disable threshold: " + + _storageUsedThreshold); } if (usedPercentage >= _storageUsedThreshold) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Insufficient space on pool: " + pool.getId() + " since its usage percentage: " +usedPercentage + " has crossed the pool.storage.capacity.disablethreshold: " + _storageUsedThreshold); + s_logger.debug("Insufficient space on pool: " + + pool.getId() + + " since its usage percentage: " + + usedPercentage + + " has crossed the pool.storage.capacity.disablethreshold: " + + _storageUsedThreshold); } return false; } @@ -4019,54 +1787,113 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C } @Override - public boolean storagePoolHasEnoughSpace(List volumes, StoragePool pool) { - if(volumes == null || volumes.isEmpty()) + public boolean storagePoolHasEnoughSpace(List volumes, + StoragePool pool) { + if (volumes == null || volumes.isEmpty()) return false; - if(!checkUsagedSpace(pool)) + if (!checkUsagedSpace(pool)) return false; // allocated space includes template of specified volume StoragePoolVO poolVO = _storagePoolDao.findById(pool.getId()); - long allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, null); + long allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity( + poolVO, null); long totalAskingSize = 0; for (Volume volume : volumes) { - if(volume.getTemplateId()!=null){ - VMTemplateVO tmpl = _templateDao.findById(volume.getTemplateId()); - if (tmpl.getFormat() != ImageFormat.ISO){ - allocatedSizeWithtemplate = _capacityMgr.getAllocatedPoolCapacity(poolVO, tmpl); + if (volume.getTemplateId() != null) { + VMTemplateVO tmpl = _templateDao.findById(volume + .getTemplateId()); + if (tmpl.getFormat() != ImageFormat.ISO) { + allocatedSizeWithtemplate = _capacityMgr + .getAllocatedPoolCapacity(poolVO, tmpl); } } - if(volume.getState() != Volume.State.Ready) + if (volume.getState() != Volume.State.Ready) totalAskingSize = totalAskingSize + volume.getSize(); } long totalOverProvCapacity; if (pool.getPoolType() == StoragePoolType.NetworkFilesystem) { - totalOverProvCapacity = _storageOverprovisioningFactor.multiply(new BigDecimal(pool.getCapacityBytes())).longValue();// All this for the inaccuracy of floats for big number multiplication. - }else { + totalOverProvCapacity = _storageOverprovisioningFactor.multiply( + new BigDecimal(pool.getCapacityBytes())).longValue(); + } else { totalOverProvCapacity = pool.getCapacityBytes(); } if (s_logger.isDebugEnabled()) { - s_logger.debug("Checking pool: " + pool.getId() + " for volume allocation " + volumes.toString() + ", maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize + ", allocated disable threshold: " + _storageAllocatedThreshold); + s_logger.debug("Checking pool: " + pool.getId() + + " for volume allocation " + volumes.toString() + + ", maxSize : " + totalOverProvCapacity + + ", totalAllocatedSize : " + allocatedSizeWithtemplate + + ", askingSize : " + totalAskingSize + + ", allocated disable threshold: " + + _storageAllocatedThreshold); } - double usedPercentage = (allocatedSizeWithtemplate + totalAskingSize) / (double)(totalOverProvCapacity); - if (usedPercentage > _storageAllocatedThreshold){ + double usedPercentage = (allocatedSizeWithtemplate + totalAskingSize) + / (double) (totalOverProvCapacity); + if (usedPercentage > _storageAllocatedThreshold) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + " since its allocated percentage: " +usedPercentage + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + _storageAllocatedThreshold + ", skipping this pool"); + s_logger.debug("Insufficient un-allocated capacity on: " + + pool.getId() + + " for volume allocation: " + + volumes.toString() + + " since its allocated percentage: " + + usedPercentage + + " has crossed the allocated pool.storage.allocated.capacity.disablethreshold: " + + _storageAllocatedThreshold + ", skipping this pool"); } return false; } if (totalOverProvCapacity < (allocatedSizeWithtemplate + totalAskingSize)) { if (s_logger.isDebugEnabled()) { - s_logger.debug("Insufficient un-allocated capacity on: " + pool.getId() + " for volume allocation: " + volumes.toString() + ", not enough storage, maxSize : " + totalOverProvCapacity + ", totalAllocatedSize : " + allocatedSizeWithtemplate + ", askingSize : " + totalAskingSize); + s_logger.debug("Insufficient un-allocated capacity on: " + + pool.getId() + " for volume allocation: " + + volumes.toString() + + ", not enough storage, maxSize : " + + totalOverProvCapacity + ", totalAllocatedSize : " + + allocatedSizeWithtemplate + ", askingSize : " + + totalAskingSize); } return false; } return true; } + @Override + public void createCapacityEntry(long poolId) { + StoragePoolVO storage = _storagePoolDao.findById(poolId); + createCapacityEntry(storage, Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED, 0); + } + + + @Override + public synchronized boolean registerHostListener(String providerUuid, + HypervisorHostListener listener) { + hostListeners.put(providerUuid, listener); + return true; + } + + @Override + public Answer sendToPool(long poolId, Command cmd) + throws StorageUnavailableException { + // TODO Auto-generated method stub + return null; + } + + @Override + public Answer[] sendToPool(long poolId, Commands cmd) + throws StorageUnavailableException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getName() { + // TODO Auto-generated method stub + return null; + } + } diff --git a/server/src/com/cloud/storage/TemplateProfile.java b/server/src/com/cloud/storage/TemplateProfile.java index 1d8b6bfc1a3..41bbaaa1057 100755 --- a/server/src/com/cloud/storage/TemplateProfile.java +++ b/server/src/com/cloud/storage/TemplateProfile.java @@ -18,9 +18,9 @@ package com.cloud.storage; import java.util.Map; + import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.VMTemplateVO; public class TemplateProfile { Long userId; @@ -46,6 +46,7 @@ public class TemplateProfile { Long templateId; VMTemplateVO template; String templateTag; + String imageStoreUuid; Map details; public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, @@ -83,10 +84,12 @@ public class TemplateProfile { public TemplateProfile(Long templateId, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHvm, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, ImageFormat format, Long guestOsId, Long zoneId, - HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details, Boolean sshKeyEnabled) { + HypervisorType hypervisorType, String accountName, Long domainId, Long accountId, String chksum, Boolean bootable, String templateTag, Map details, Boolean sshKeyEnabled, + String imageStoreUuid) { this(templateId, userId, name, displayText, bits, passwordEnabled, requiresHvm, url, isPublic, featured, isExtractable, format, guestOsId, zoneId, hypervisorType, accountName, domainId, accountId, chksum, bootable, details, sshKeyEnabled); this.templateTag = templateTag; + this.imageStoreUuid = imageStoreUuid; } public Long getTemplateId() { @@ -252,4 +255,8 @@ public class TemplateProfile { public Boolean getSshKeyEnabled() { return this.sshKeyEnbaled; } + + public String getImageStoreUuid() { + return this.imageStoreUuid; + } } diff --git a/server/src/com/cloud/storage/VolumeManager.java b/server/src/com/cloud/storage/VolumeManager.java new file mode 100644 index 00000000000..41434f41dcc --- /dev/null +++ b/server/src/com/cloud/storage/VolumeManager.java @@ -0,0 +1,99 @@ +/* + * 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.storage; + +import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; + +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientStorageCapacityException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.storage.Volume.Type; +import com.cloud.user.Account; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; + +public interface VolumeManager extends VolumeApiService { + + VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, + Long destPoolClusterId, HypervisorType dataDiskHyperType) + throws ConcurrentOperationException; + + VolumeVO uploadVolume(UploadVolumeCmd cmd) + throws ResourceAllocationException; + + VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId); + + boolean volumeOnSharedStoragePool(VolumeVO volume); + + boolean volumeInactive(VolumeVO volume); + + String getVmNameOnVolume(VolumeVO volume); + + VolumeVO allocVolume(CreateVolumeCmd cmd) + throws ResourceAllocationException; + + VolumeVO createVolume(CreateVolumeCmd cmd); + + VolumeVO resizeVolume(ResizeVolumeCmd cmd); + + boolean deleteVolume(long volumeId, Account caller) + throws ConcurrentOperationException; + + void destroyVolume(VolumeVO volume); + + DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, VMInstanceVO vm, Account owner); + Volume attachVolumeToVM(AttachVolumeCmd command); + + Volume detachVolumeFromVM(DetachVolumeCmd cmmd); + + void release(VirtualMachineProfile profile); + + void cleanupVolumes(long vmId) throws ConcurrentOperationException; + + Volume migrateVolume(Long volumeId, Long storagePoolId) + throws ConcurrentOperationException; + + boolean StorageMigration( + VirtualMachineProfile vm, + StoragePool destPool) throws ConcurrentOperationException; + + void prepareForMigration( + VirtualMachineProfile vm, + DeployDestination dest); + + void prepare(VirtualMachineProfile vm, + DeployDestination dest) throws StorageUnavailableException, + InsufficientStorageCapacityException, ConcurrentOperationException; + + boolean canVmRestartOnAnotherServer(long vmId); + + DiskProfile allocateTemplatedVolume(Type type, String name, + DiskOfferingVO offering, VMTemplateVO template, VMInstanceVO vm, + Account owner); +} diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java new file mode 100644 index 00000000000..5843dddbec5 --- /dev/null +++ b/server/src/com/cloud/storage/VolumeManagerImpl.java @@ -0,0 +1,2620 @@ +/* + * 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.storage; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ExecutionException; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd; +import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ScopeType; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult; +import org.apache.cloudstack.framework.async.AsyncCallFuture; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.AttachVolumeAnswer; +import com.cloud.agent.api.AttachVolumeCommand; +import com.cloud.agent.api.storage.CopyVolumeAnswer; +import com.cloud.agent.api.storage.CopyVolumeCommand; +import com.cloud.agent.api.storage.DestroyCommand; +import com.cloud.agent.api.storage.ResizeVolumeAnswer; +import com.cloud.agent.api.storage.ResizeVolumeCommand; +import com.cloud.agent.api.to.StorageFilerTO; +import com.cloud.agent.api.to.VolumeTO; +import com.cloud.alert.AlertManager; +import com.cloud.api.ApiDBUtils; +import com.cloud.async.AsyncJobExecutor; +import com.cloud.async.AsyncJobManager; +import com.cloud.async.AsyncJobVO; +import com.cloud.async.BaseAsyncJobExecutor; +import com.cloud.capacity.CapacityManager; +import com.cloud.capacity.dao.CapacityDao; +import com.cloud.configuration.Config; +import com.cloud.configuration.ConfigurationManager; +import com.cloud.configuration.Resource.ResourceType; +import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.consoleproxy.ConsoleProxyManager; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.HostPodVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.HostPodDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.domain.Domain; +import com.cloud.domain.dao.DomainDao; +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.event.UsageEventVO; +import com.cloud.event.dao.EventDao; +import com.cloud.event.dao.UsageEventDao; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientStorageCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; +import com.cloud.hypervisor.HypervisorGuruManager; +import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; +import com.cloud.network.NetworkModel; +import com.cloud.org.Grouping; +import com.cloud.resource.ResourceManager; +import com.cloud.server.ManagementServer; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.Storage.ImageFormat; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.Volume.Event; +import com.cloud.storage.Volume.Type; +import com.cloud.storage.allocator.StoragePoolAllocator; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotPolicyDao; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.StoragePoolWorkDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateS3Dao; +import com.cloud.storage.dao.VMTemplateSwiftDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; +import com.cloud.storage.download.DownloadMonitor; +import com.cloud.storage.s3.S3Manager; +import com.cloud.storage.secondary.SecondaryStorageVmManager; +import com.cloud.storage.snapshot.SnapshotManager; +import com.cloud.storage.snapshot.SnapshotScheduler; +import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.template.TemplateManager; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.UserContext; +import com.cloud.user.dao.AccountDao; +import com.cloud.user.dao.UserDao; +import com.cloud.uservm.UserVm; +import com.cloud.utils.EnumUtils; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; +import com.cloud.utils.component.ManagerBase; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.JoinBuilder; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.fsm.NoTransitionException; +import com.cloud.utils.fsm.StateMachine2; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.UserVmManager; +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.VirtualMachineManager; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.ConsoleProxyDao; +import com.cloud.vm.dao.DomainRouterDao; +import com.cloud.vm.dao.SecondaryStorageVmDao; +import com.cloud.vm.dao.UserVmDao; +import com.cloud.vm.dao.VMInstanceDao; + +@Component +public class VolumeManagerImpl extends ManagerBase implements VolumeManager { + private static final Logger s_logger = Logger + .getLogger(VolumeManagerImpl.class); + @Inject + protected UserVmManager _userVmMgr; + @Inject + protected AgentManager _agentMgr; + @Inject + protected TemplateManager _tmpltMgr; + @Inject + protected AsyncJobManager _asyncMgr; + @Inject + protected SnapshotManager _snapshotMgr; + @Inject + protected SnapshotScheduler _snapshotScheduler; + @Inject + protected AccountManager _accountMgr; + @Inject + protected ConfigurationManager _configMgr; + @Inject + protected ConsoleProxyManager _consoleProxyMgr; + @Inject + protected SecondaryStorageVmManager _secStorageMgr; + @Inject + protected NetworkModel _networkMgr; + @Inject + protected ServiceOfferingDao _serviceOfferingDao; + @Inject + protected VolumeDao _volsDao; + @Inject + protected HostDao _hostDao; + @Inject + protected ConsoleProxyDao _consoleProxyDao; + @Inject + protected SnapshotDao _snapshotDao; + @Inject + protected SnapshotManager _snapMgr; + @Inject + protected SnapshotPolicyDao _snapshotPolicyDao; + @Inject + protected StoragePoolHostDao _storagePoolHostDao; + @Inject + protected AlertManager _alertMgr; + @Inject + protected VMTemplateHostDao _vmTemplateHostDao = null; + @Inject + protected VMTemplatePoolDao _vmTemplatePoolDao = null; + @Inject + protected VMTemplateSwiftDao _vmTemplateSwiftDao = null; + @Inject + protected VMTemplateS3Dao _vmTemplateS3Dao; + @Inject + protected S3Manager _s3Mgr; + @Inject + protected VMTemplateDao _vmTemplateDao = null; + @Inject + protected StoragePoolHostDao _poolHostDao = null; + @Inject + protected UserVmDao _userVmDao; + @Inject + VolumeHostDao _volumeHostDao; + @Inject + protected VMInstanceDao _vmInstanceDao; + @Inject + protected PrimaryDataStoreDao _storagePoolDao = null; + @Inject + protected CapacityDao _capacityDao; + @Inject + protected CapacityManager _capacityMgr; + @Inject + protected DiskOfferingDao _diskOfferingDao; + @Inject + protected AccountDao _accountDao; + @Inject + protected EventDao _eventDao = null; + @Inject + protected DataCenterDao _dcDao = null; + @Inject + protected HostPodDao _podDao = null; + @Inject + protected VMTemplateDao _templateDao; + @Inject + protected VMTemplateHostDao _templateHostDao; + @Inject + protected ServiceOfferingDao _offeringDao; + @Inject + protected DomainDao _domainDao; + @Inject + protected UserDao _userDao; + @Inject + protected ClusterDao _clusterDao; + @Inject + protected UsageEventDao _usageEventDao; + @Inject + protected VirtualMachineManager _vmMgr; + @Inject + protected DomainRouterDao _domrDao; + @Inject + protected SecondaryStorageVmDao _secStrgDao; + @Inject + protected StoragePoolWorkDao _storagePoolWorkDao; + @Inject + protected HypervisorGuruManager _hvGuruMgr; + @Inject + protected VolumeDao _volumeDao; + @Inject + protected OCFS2Manager _ocfs2Mgr; + @Inject + protected ResourceLimitService _resourceLimitMgr; + @Inject + protected SecondaryStorageVmManager _ssvmMgr; + @Inject + protected ResourceManager _resourceMgr; + @Inject + protected DownloadMonitor _downloadMonitor; + @Inject + protected ResourceTagDao _resourceTagDao; + @Inject + protected List _storagePoolAllocators; + @Inject + ConfigurationDao _configDao; + @Inject + ManagementServer _msServer; + @Inject + DataStoreManager dataStoreMgr; + @Inject + DataStoreProviderManager dataStoreProviderMgr; + @Inject + VolumeService volService; + @Inject + VolumeDataFactory volFactory; + @Inject + ImageDataFactory tmplFactory; + @Inject + SnapshotDataFactory snapshotFactory; + private int _copyvolumewait; + @Inject + protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao; + private final StateMachine2 _volStateMachine; + @Inject + StorageManager storageMgr; + private int _customDiskOfferingMinSize = 1; + private int _customDiskOfferingMaxSize = 1024; + private long _maxVolumeSizeInGb; + private boolean _recreateSystemVmEnabled; + protected SearchBuilder HostTemplateStatesSearch; + + public VolumeManagerImpl() { + _volStateMachine = Volume.State.getStateMachine(); + } + + @Override + public VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, + Long destPoolPodId, Long destPoolClusterId, + HypervisorType dataDiskHyperType) + throws ConcurrentOperationException { + + // Find a destination storage pool with the specified criteria + DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume + .getDiskOfferingId()); + DiskProfile dskCh = new DiskProfile(volume.getId(), + volume.getVolumeType(), volume.getName(), diskOffering.getId(), + diskOffering.getDiskSize(), diskOffering.getTagsArray(), + diskOffering.getUseLocalStorage(), + diskOffering.isRecreatable(), null); + dskCh.setHyperType(dataDiskHyperType); + DataCenterVO destPoolDataCenter = _dcDao.findById(destPoolDcId); + HostPodVO destPoolPod = _podDao.findById(destPoolPodId); + + StoragePool destPool = storageMgr.findStoragePool(dskCh, + destPoolDataCenter, destPoolPod, destPoolClusterId, null, null, + new HashSet()); + + if (destPool == null) { + throw new CloudRuntimeException( + "Failed to find a storage pool with enough capacity to move the volume to."); + } + + List vols = new ArrayList(); + vols.add(volume); + migrateVolumes(vols, destPool); + return this.volFactory.getVolume(volume.getId()); + } + + /* + * Upload the volume to secondary storage. + */ + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_UPLOAD, eventDescription = "uploading volume", async = true) + public VolumeVO uploadVolume(UploadVolumeCmd cmd) + throws ResourceAllocationException { + Account caller = UserContext.current().getCaller(); + long ownerId = cmd.getEntityOwnerId(); + Long zoneId = cmd.getZoneId(); + String volumeName = cmd.getVolumeName(); + String url = cmd.getUrl(); + String format = cmd.getFormat(); + String imageStoreUuid = cmd.getImageStoreUuid(); + DataStore store = this._tmpltMgr.getImageStore(imageStoreUuid, zoneId); + + validateVolume(caller, ownerId, zoneId, volumeName, url, format); + + VolumeVO volume = persistVolume(caller, ownerId, zoneId, volumeName, + url, cmd.getFormat()); + + VolumeInfo vol = this.volFactory.getVolume(volume.getId()); + + RegisterVolumePayload payload = new RegisterVolumePayload(cmd.getUrl(), cmd.getChecksum(), + cmd.getFormat()); + vol.addPayload(payload); + + this.volService.registerVolume(vol, store); + return volume; + } + + private boolean validateVolume(Account caller, long ownerId, Long zoneId, + String volumeName, String url, String format) + throws ResourceAllocationException { + + // permission check + _accountMgr.checkAccess(caller, null, true, + _accountMgr.getActiveAccountById(ownerId)); + + // Check that the resource limit for volumes won't be exceeded + _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), + ResourceType.volume); + + // Verify that zone exists + DataCenterVO zone = _dcDao.findById(zoneId); + if (zone == null) { + throw new InvalidParameterValueException( + "Unable to find zone by id " + zoneId); + } + + // Check if zone is disabled + if (Grouping.AllocationState.Disabled == zone.getAllocationState() + && !_accountMgr.isRootAdmin(caller.getType())) { + throw new PermissionDeniedException( + "Cannot perform this operation, Zone is currently disabled: " + + zoneId); + } + + if (url.toLowerCase().contains("file://")) { + throw new InvalidParameterValueException( + "File:// type urls are currently unsupported"); + } + + ImageFormat imgfmt = ImageFormat.valueOf(format.toUpperCase()); + if (imgfmt == null) { + throw new IllegalArgumentException("Image format is incorrect " + + format + ". Supported formats are " + + EnumUtils.listValues(ImageFormat.values())); + } + + String userSpecifiedName = volumeName; + if (userSpecifiedName == null) { + userSpecifiedName = getRandomVolumeName(); + } + if ((!url.toLowerCase().endsWith("vhd")) + && (!url.toLowerCase().endsWith("vhd.zip")) + && (!url.toLowerCase().endsWith("vhd.bz2")) + && (!url.toLowerCase().endsWith("vhd.gz")) + && (!url.toLowerCase().endsWith("qcow2")) + && (!url.toLowerCase().endsWith("qcow2.zip")) + && (!url.toLowerCase().endsWith("qcow2.bz2")) + && (!url.toLowerCase().endsWith("qcow2.gz")) + && (!url.toLowerCase().endsWith("ova")) + && (!url.toLowerCase().endsWith("ova.zip")) + && (!url.toLowerCase().endsWith("ova.bz2")) + && (!url.toLowerCase().endsWith("ova.gz")) + && (!url.toLowerCase().endsWith("img")) + && (!url.toLowerCase().endsWith("raw"))) { + throw new InvalidParameterValueException("Please specify a valid " + + format.toLowerCase()); + } + + if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith( + ".vhd") + && !url.toLowerCase().endsWith("vhd.zip") + && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase() + .endsWith("vhd.gz"))) + || (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase() + .endsWith(".qcow2") + && !url.toLowerCase().endsWith("qcow2.zip") + && !url.toLowerCase().endsWith("qcow2.bz2") && !url + .toLowerCase().endsWith("qcow2.gz"))) + || (format.equalsIgnoreCase("ova") && (!url.toLowerCase() + .endsWith(".ova") + && !url.toLowerCase().endsWith("ova.zip") + && !url.toLowerCase().endsWith("ova.bz2") && !url + .toLowerCase().endsWith("ova.gz"))) + || (format.equalsIgnoreCase("raw") && (!url.toLowerCase() + .endsWith(".img") && !url.toLowerCase().endsWith("raw")))) { + throw new InvalidParameterValueException( + "Please specify a valid URL. URL:" + url + + " is an invalid for the format " + + format.toLowerCase()); + } + validateUrl(url); + + return false; + } + + @Override + public VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId) { + VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), + oldVol.getName(), oldVol.getDataCenterId(), + oldVol.getDomainId(), oldVol.getAccountId(), + oldVol.getDiskOfferingId(), oldVol.getSize()); + if (templateId != null) { + newVol.setTemplateId(templateId); + } else { + newVol.setTemplateId(oldVol.getTemplateId()); + } + newVol.setDeviceId(oldVol.getDeviceId()); + newVol.setInstanceId(oldVol.getInstanceId()); + newVol.setRecreatable(oldVol.isRecreatable()); + return _volsDao.persist(newVol); + } + + @DB + protected VolumeInfo createVolumeFromSnapshot(VolumeVO volume, + SnapshotVO snapshot) { + Account account = _accountDao.findById(volume.getAccountId()); + + final HashSet poolsToAvoid = new HashSet(); + StoragePool pool = null; + + Set podsToAvoid = new HashSet(); + Pair pod = null; + + + DiskOfferingVO diskOffering = _diskOfferingDao + .findByIdIncludingRemoved(volume.getDiskOfferingId()); + DataCenterVO dc = _dcDao.findById(volume.getDataCenterId()); + DiskProfile dskCh = new DiskProfile(volume, diskOffering, + snapshot.getHypervisorType()); + + // Determine what pod to store the volume in + while ((pod = _resourceMgr.findPod(null, null, dc, account.getId(), + podsToAvoid)) != null) { + podsToAvoid.add(pod.first().getId()); + // Determine what storage pool to store the volume in + while ((pool = storageMgr.findStoragePool(dskCh, dc, pod.first(), null, null, + null, poolsToAvoid)) != null) { + break; + + } + } + + VolumeInfo vol = this.volFactory.getVolume(volume.getId()); + DataStore store = this.dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); + SnapshotInfo snapInfo = this.snapshotFactory.getSnapshot(snapshot.getId()); + AsyncCallFuture future = this.volService.createVolumeFromSnapshot(vol, store, snapInfo); + try { + VolumeApiResult result = future.get(); + if (result.isFailed()) { + s_logger.debug("Failed to create volume from snapshot:" + result.getResult()); + throw new CloudRuntimeException("Failed to create volume from snapshot:" + result.getResult()); + } + return result.getVolume(); + } catch (InterruptedException e) { + s_logger.debug("Failed to create volume from snapshot", e); + throw new CloudRuntimeException("Failed to create volume from snapshot", e); + } catch (ExecutionException e) { + s_logger.debug("Failed to create volume from snapshot", e); + throw new CloudRuntimeException("Failed to create volume from snapshot", e); + } + + } + + protected DiskProfile createDiskCharacteristics(VolumeInfo volume, + VMTemplateVO template, DataCenterVO dc, DiskOfferingVO diskOffering) { + if (volume.getVolumeType() == Type.ROOT + && Storage.ImageFormat.ISO != template.getFormat()) { + SearchCriteria sc = HostTemplateStatesSearch + .create(); + sc.setParameters("id", template.getId()); + sc.setParameters( + "state", + com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + sc.setJoinParameters("host", "dcId", dc.getId()); + + List sss = _vmTemplateHostDao.search(sc, null); + if (sss.size() == 0) { + throw new CloudRuntimeException("Template " + + template.getName() + + " has not been completely downloaded to zone " + + dc.getId()); + } + VMTemplateHostVO ss = sss.get(0); + + return new DiskProfile(volume.getId(), volume.getVolumeType(), + volume.getName(), diskOffering.getId(), ss.getSize(), + diskOffering.getTagsArray(), + diskOffering.getUseLocalStorage(), + diskOffering.isRecreatable(), + Storage.ImageFormat.ISO != template.getFormat() ? template + .getId() : null); + } else { + return new DiskProfile(volume.getId(), volume.getVolumeType(), + volume.getName(), diskOffering.getId(), + diskOffering.getDiskSize(), diskOffering.getTagsArray(), + diskOffering.getUseLocalStorage(), + diskOffering.isRecreatable(), null); + } + } + + protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId) { + VolumeInfo createdVolume = null; + SnapshotVO snapshot = _snapshotDao.findById(snapshotId); + createdVolume = createVolumeFromSnapshot(volume, + snapshot); + + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, + createdVolume.getAccountId(), + createdVolume.getDataCenterId(), createdVolume.getId(), + createdVolume.getName(), createdVolume.getDiskOfferingId(), + null, createdVolume.getSize()); + _usageEventDao.persist(usageEvent); + + return this._volsDao.findById(createdVolume.getId()); + } + + @DB + public VolumeInfo copyVolumeFromSecToPrimary(VolumeInfo volume, + VMInstanceVO vm, VMTemplateVO template, DataCenterVO dc, + HostPodVO pod, Long clusterId, ServiceOfferingVO offering, + DiskOfferingVO diskOffering, List avoids, + long size, HypervisorType hyperType) throws NoTransitionException { + + final HashSet avoidPools = new HashSet( + avoids); + DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, + diskOffering); + dskCh.setHyperType(vm.getHypervisorType()); + // Find a suitable storage to create volume on + StoragePool destPool = storageMgr.findStoragePool(dskCh, dc, pod, + clusterId, null, vm, avoidPools); + DataStore destStore = this.dataStoreMgr.getDataStore(destPool.getId(), DataStoreRole.Primary); + AsyncCallFuture future = this.volService.copyVolume(volume, destStore); + + try { + VolumeApiResult result = future.get(); + if (result.isFailed()) { + s_logger.debug("copy volume failed: " + result.getResult()); + throw new CloudRuntimeException("copy volume failed: " + result.getResult()); + } + return result.getVolume(); + } catch (InterruptedException e) { + s_logger.debug("Failed to copy volume: " + volume.getId(), e); + throw new CloudRuntimeException("Failed to copy volume", e); + } catch (ExecutionException e) { + s_logger.debug("Failed to copy volume: " + volume.getId(), e); + throw new CloudRuntimeException("Failed to copy volume", e); + } + } + + @DB + public VolumeInfo createVolume(VolumeInfo volume, VMInstanceVO vm, + VMTemplateVO template, DataCenterVO dc, HostPodVO pod, + Long clusterId, ServiceOfferingVO offering, + DiskOfferingVO diskOffering, List avoids, + long size, HypervisorType hyperType) { + StoragePool pool = null; + + if (diskOffering != null && diskOffering.isCustomized()) { + diskOffering.setDiskSize(size); + } + + DiskProfile dskCh = null; + if (volume.getVolumeType() == Type.ROOT + && Storage.ImageFormat.ISO != template.getFormat()) { + dskCh = createDiskCharacteristics(volume, template, dc, offering); + } else { + dskCh = createDiskCharacteristics(volume, template, dc, + diskOffering); + } + + dskCh.setHyperType(hyperType); + + final HashSet avoidPools = new HashSet( + avoids); + + pool = storageMgr.findStoragePool(dskCh, dc, pod, clusterId, vm.getHostId(), + vm, avoidPools); + if (pool == null) { + s_logger.warn("Unable to find storage poll when create volume " + + volume.getName()); + throw new CloudRuntimeException("Unable to find storage poll when create volume" + volume.getName()); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Trying to create " + volume + " on " + pool); + } + DataStore store = this.dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); + AsyncCallFuture future = null; + boolean isNotCreatedFromTemplate = volume.getTemplateId() == null ? true : false; + if (isNotCreatedFromTemplate) { + future = this.volService.createVolumeAsync(volume, store); + } else { + TemplateInfo templ = this.tmplFactory.getTemplate(template.getId()); + future = this.volService.createVolumeFromTemplateAsync(volume, store.getId(), templ); + } + try { + VolumeApiResult result = future.get(); + if (result.isFailed()) { + s_logger.debug("create volume failed: " + result.getResult()); + throw new CloudRuntimeException("create volume failed:" + result.getResult()); + } + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), + volume.getDiskOfferingId(), null, volume.getSize()); + _usageEventDao.persist(usageEvent); + return result.getVolume(); + } catch (InterruptedException e) { + s_logger.error("create volume failed", e); + throw new CloudRuntimeException("create volume failed", e); + } catch (ExecutionException e) { + s_logger.error("create volume failed", e); + throw new CloudRuntimeException("create volume failed", e); + } + + } + + public String getRandomVolumeName() { + return UUID.randomUUID().toString(); + } + + private VolumeVO persistVolume(Account caller, long ownerId, Long zoneId, + String volumeName, String url, String format) { + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, + new Long(-1), null, null, 0, Volume.Type.DATADISK); + volume.setPoolId(null); + volume.setDataCenterId(zoneId); + volume.setPodId(null); + volume.setAccountId(ownerId); + volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller + .getDomainId())); + long diskOfferingId = _diskOfferingDao.findByUniqueName( + "Cloud.com-Custom").getId(); + volume.setDiskOfferingId(diskOfferingId); + // volume.setSize(size); + volume.setInstanceId(null); + volume.setUpdated(new Date()); + volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller + .getDomainId()); + + volume = _volsDao.persist(volume); + try { + stateTransitTo(volume, Event.UploadRequested); + } catch (NoTransitionException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + UserContext.current().setEventDetails("Volume Id: " + volume.getId()); + + // Increment resource count during allocation; if actual creation fails, + // decrement it + _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), + ResourceType.volume); + + txn.commit(); + return volume; + } + + @Override + public boolean volumeOnSharedStoragePool(VolumeVO volume) { + Long poolId = volume.getPoolId(); + if (poolId == null) { + return false; + } else { + StoragePoolVO pool = _storagePoolDao.findById(poolId); + + if (pool == null) { + return false; + } else { + return (pool.getScope() == ScopeType.HOST) ? false : true; + } + } + } + + @Override + public boolean volumeInactive(VolumeVO volume) { + Long vmId = volume.getInstanceId(); + if (vmId != null) { + UserVm vm = _userVmDao.findById(vmId); + if (vm == null) { + return true; + } + State state = vm.getState(); + if (state.equals(State.Stopped) || state.equals(State.Destroyed)) { + return true; + } + } + return false; + } + + @Override + public String getVmNameOnVolume(VolumeVO volume) { + Long vmId = volume.getInstanceId(); + if (vmId != null) { + VMInstanceVO vm = _vmInstanceDao.findById(vmId); + + if (vm == null) { + return null; + } + return vm.getInstanceName(); + } + return null; + } + + /* + * Just allocate a volume in the database, don't send the createvolume cmd + * to hypervisor. The volume will be finally created only when it's attached + * to a VM. + */ + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", create = true) + public VolumeVO allocVolume(CreateVolumeCmd cmd) + throws ResourceAllocationException { + // FIXME: some of the scheduled event stuff might be missing here... + Account caller = UserContext.current().getCaller(); + + long ownerId = cmd.getEntityOwnerId(); + + // permission check + _accountMgr.checkAccess(caller, null, true, + _accountMgr.getActiveAccountById(ownerId)); + + // Check that the resource limit for volumes won't be exceeded + _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), + ResourceType.volume); + + Long zoneId = cmd.getZoneId(); + Long diskOfferingId = null; + DiskOfferingVO diskOffering = null; + Long size = null; + + // validate input parameters before creating the volume + if ((cmd.getSnapshotId() == null && cmd.getDiskOfferingId() == null) + || (cmd.getSnapshotId() != null && cmd.getDiskOfferingId() != null)) { + throw new InvalidParameterValueException( + "Either disk Offering Id or snapshot Id must be passed whilst creating volume"); + } + + if (cmd.getSnapshotId() == null) {// create a new volume + + diskOfferingId = cmd.getDiskOfferingId(); + size = cmd.getSize(); + Long sizeInGB = size; + if (size != null) { + if (size > 0) { + size = size * 1024 * 1024 * 1024; // user specify size in GB + } else { + throw new InvalidParameterValueException( + "Disk size must be larger than 0"); + } + } + + // Check that the the disk offering is specified + diskOffering = _diskOfferingDao.findById(diskOfferingId); + if ((diskOffering == null) || diskOffering.getRemoved() != null + || !DiskOfferingVO.Type.Disk.equals(diskOffering.getType())) { + throw new InvalidParameterValueException( + "Please specify a valid disk offering."); + } + + if (diskOffering.isCustomized()) { + if (size == null) { + throw new InvalidParameterValueException( + "This disk offering requires a custom size specified"); + } + if ((sizeInGB < _customDiskOfferingMinSize) + || (sizeInGB > _customDiskOfferingMaxSize)) { + throw new InvalidParameterValueException("Volume size: " + + sizeInGB + "GB is out of allowed range. Max: " + + _customDiskOfferingMaxSize + " Min:" + + _customDiskOfferingMinSize); + } + } + + if (!diskOffering.isCustomized() && size != null) { + throw new InvalidParameterValueException( + "This disk offering does not allow custom size"); + } + + if (diskOffering.getDomainId() == null) { + // do nothing as offering is public + } else { + _configMgr.checkDiskOfferingAccess(caller, diskOffering); + } + + if (diskOffering.getDiskSize() > 0) { + size = diskOffering.getDiskSize(); + } + + if (!validateVolumeSizeRange(size)) {// convert size from mb to gb + // for validation + throw new InvalidParameterValueException( + "Invalid size for custom volume creation: " + size + + " ,max volume size is:" + _maxVolumeSizeInGb); + } + } else { // create volume from snapshot + Long snapshotId = cmd.getSnapshotId(); + SnapshotVO snapshotCheck = _snapshotDao.findById(snapshotId); + if (snapshotCheck == null) { + throw new InvalidParameterValueException( + "unable to find a snapshot with id " + snapshotId); + } + + if (snapshotCheck.getStatus() != Snapshot.Status.BackedUp) { + throw new InvalidParameterValueException("Snapshot id=" + + snapshotId + " is not in " + Snapshot.Status.BackedUp + + " state yet and can't be used for volume creation"); + } + + diskOfferingId = snapshotCheck.getDiskOfferingId(); + diskOffering = _diskOfferingDao.findById(diskOfferingId); + zoneId = snapshotCheck.getDataCenterId(); + size = snapshotCheck.getSize(); // ; disk offering is used for tags + // purposes + + // check snapshot permissions + _accountMgr.checkAccess(caller, null, true, snapshotCheck); + } + + // Verify that zone exists + DataCenterVO zone = _dcDao.findById(zoneId); + if (zone == null) { + throw new InvalidParameterValueException( + "Unable to find zone by id " + zoneId); + } + + // Check if zone is disabled + if (Grouping.AllocationState.Disabled == zone.getAllocationState() + && !_accountMgr.isRootAdmin(caller.getType())) { + throw new PermissionDeniedException( + "Cannot perform this operation, Zone is currently disabled: " + + zoneId); + } + + // If local storage is disabled then creation of volume with local disk + // offering not allowed + if (!zone.isLocalStorageEnabled() && diskOffering.getUseLocalStorage()) { + throw new InvalidParameterValueException( + "Zone is not configured to use local storage but volume's disk offering " + + diskOffering.getName() + " uses it"); + } + + String userSpecifiedName = cmd.getVolumeName(); + if (userSpecifiedName == null) { + userSpecifiedName = getRandomVolumeName(); + } + + Transaction txn = Transaction.currentTxn(); + txn.start(); + + 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); + volume.setAccountId(ownerId); + volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller + .getDomainId())); + volume.setDiskOfferingId(diskOfferingId); + volume.setSize(size); + volume.setInstanceId(null); + volume.setUpdated(new Date()); + volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller + .getDomainId()); + + volume = _volsDao.persist(volume); + if (cmd.getSnapshotId() == null) { + // for volume created from snapshot, create usage event after volume + // creation + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName(), + diskOfferingId, null, size); + _usageEventDao.persist(usageEvent); + } + + UserContext.current().setEventDetails("Volume Id: " + volume.getId()); + + // Increment resource count during allocation; if actual creation fails, + // decrement it + _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), + ResourceType.volume); + + txn.commit(); + + return volume; + } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_CREATE, eventDescription = "creating volume", async = true) + public VolumeVO createVolume(CreateVolumeCmd cmd) { + VolumeVO volume = _volsDao.findById(cmd.getEntityId()); + boolean created = true; + + try { + if (cmd.getSnapshotId() != null) { + volume = createVolumeFromSnapshot(volume, cmd.getSnapshotId()); + if (volume.getState() != Volume.State.Ready) { + created = false; + } + } + return volume; + } catch(Exception e) { + created = false; + s_logger.debug("Failed to create volume: " + volume.getId(), e); + return null; + } finally { + if (!created) { + s_logger.trace("Decrementing volume resource count for account id=" + + volume.getAccountId() + + " as volume failed to create on the backend"); + _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), + ResourceType.volume); + } + } + } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_RESIZE, eventDescription = "resizing volume", async = true) + public VolumeVO resizeVolume(ResizeVolumeCmd cmd) { + VolumeVO volume = _volsDao.findById(cmd.getEntityId()); + Long newSize = null; + boolean shrinkOk = cmd.getShrinkOk(); + boolean success = false; + DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume + .getDiskOfferingId()); + DiskOfferingVO newDiskOffering = null; + + newDiskOffering = _diskOfferingDao.findById(cmd.getNewDiskOfferingId()); + + /* + * Volumes with no hypervisor have never been assigned, and can be + * resized by recreating. perhaps in the future we can just update the + * db entry for the volume + */ + if (_volsDao.getHypervisorType(volume.getId()) == HypervisorType.None) { + throw new InvalidParameterValueException( + "Can't resize a volume that has never been attached, not sure which hypervisor type. Recreate volume to resize."); + } + + /* Only works for KVM/Xen for now */ + if (_volsDao.getHypervisorType(volume.getId()) != HypervisorType.KVM + && _volsDao.getHypervisorType(volume.getId()) != HypervisorType.XenServer) { + throw new InvalidParameterValueException( + "Cloudstack currently only supports volumes marked as KVM or XenServer hypervisor for resize"); + } + + if (volume == null) { + throw new InvalidParameterValueException("No such volume"); + } + + if (volume.getState() != Volume.State.Ready) { + throw new InvalidParameterValueException( + "Volume should be in ready state before attempting a resize"); + } + + if (!volume.getVolumeType().equals(Volume.Type.DATADISK)) { + throw new InvalidParameterValueException( + "Can only resize DATA volumes"); + } + + /* + * figure out whether or not a new disk offering or size parameter is + * required, get the correct size value + */ + if (newDiskOffering == null) { + if (diskOffering.isCustomized()) { + newSize = cmd.getSize(); + + if (newSize == null) { + throw new InvalidParameterValueException( + "new offering is of custom size, need to specify a size"); + } + + newSize = (newSize << 30); + } else { + throw new InvalidParameterValueException("current offering" + + volume.getDiskOfferingId() + + " cannot be resized, need to specify a disk offering"); + } + } else { + + if (newDiskOffering.getRemoved() != null + || !DiskOfferingVO.Type.Disk.equals(newDiskOffering + .getType())) { + throw new InvalidParameterValueException( + "Disk offering ID is missing or invalid"); + } + + if (diskOffering.getTags() != null) { + if (!newDiskOffering.getTags().equals(diskOffering.getTags())) { + throw new InvalidParameterValueException( + "Tags on new and old disk offerings must match"); + } + } else if (newDiskOffering.getTags() != null) { + throw new InvalidParameterValueException( + "There are no tags on current disk offering, new disk offering needs to have no tags"); + } + + if (newDiskOffering.getDomainId() == null) { + // do nothing as offering is public + } else { + _configMgr.checkDiskOfferingAccess(UserContext.current() + .getCaller(), newDiskOffering); + } + + if (newDiskOffering.isCustomized()) { + newSize = cmd.getSize(); + + if (newSize == null) { + throw new InvalidParameterValueException( + "new offering is of custom size, need to specify a size"); + } + + newSize = (newSize << 30); + } else { + newSize = newDiskOffering.getDiskSize(); + } + } + + if (newSize == null) { + throw new InvalidParameterValueException( + "could not detect a size parameter or fetch one from the diskofferingid parameter"); + } + + if (!validateVolumeSizeRange(newSize)) { + throw new InvalidParameterValueException( + "Requested size out of range"); + } + + /* does the caller have the authority to act on this volume? */ + _accountMgr.checkAccess(UserContext.current().getCaller(), null, true, + volume); + + UserVmVO userVm = _userVmDao.findById(volume.getInstanceId()); + + PrimaryDataStoreInfo pool = (PrimaryDataStoreInfo)this.dataStoreMgr.getDataStore(volume.getPoolId(), DataStoreRole.Primary); + long currentSize = volume.getSize(); + + /* + * lets make certain they (think they) know what they're doing if they + * want to shrink, by forcing them to provide the shrinkok parameter. + * This will be checked again at the hypervisor level where we can see + * the actual disk size + */ + if (currentSize > newSize && !shrinkOk) { + throw new InvalidParameterValueException( + "Going from existing size of " + + currentSize + + " to size of " + + newSize + + " would shrink the volume, need to sign off by supplying the shrinkok parameter with value of true"); + } + + /* + * get a list of hosts to send the commands to, try the system the + * associated vm is running on first, then the last known place it ran. + * If not attached to a userVm, we pass 'none' and resizevolume.sh is ok + * with that since it only needs the vm name to live resize + */ + long[] hosts = null; + String instanceName = "none"; + if (userVm != null) { + instanceName = userVm.getInstanceName(); + if (userVm.getHostId() != null) { + hosts = new long[] { userVm.getHostId() }; + } else if (userVm.getLastHostId() != null) { + hosts = new long[] { userVm.getLastHostId() }; + } + + /* Xen only works offline, SR does not support VDI.resizeOnline */ + if (_volsDao.getHypervisorType(volume.getId()) == HypervisorType.XenServer + && !userVm.getState().equals(State.Stopped)) { + throw new InvalidParameterValueException( + "VM must be stopped or disk detached in order to resize with the Xen HV"); + } + } + + try { + try { + stateTransitTo(volume, Volume.Event.ResizeRequested); + } catch (NoTransitionException etrans) { + throw new CloudRuntimeException( + "Unable to change volume state for resize: " + + etrans.toString()); + } + + ResizeVolumeCommand resizeCmd = new ResizeVolumeCommand( + volume.getPath(), new StorageFilerTO(pool), currentSize, + newSize, shrinkOk, instanceName); + ResizeVolumeAnswer answer = (ResizeVolumeAnswer) this.storageMgr.sendToPool(pool, + hosts, resizeCmd); + + /* + * need to fetch/store new volume size in database. This value comes + * from hypervisor rather than trusting that a success means we have + * a volume of the size we requested + */ + if (answer != null && answer.getResult()) { + long finalSize = answer.getNewSize(); + s_logger.debug("Resize: volume started at size " + currentSize + + " and ended at size " + finalSize); + volume.setSize(finalSize); + if (newDiskOffering != null) { + volume.setDiskOfferingId(cmd.getNewDiskOfferingId()); + } + _volsDao.update(volume.getId(), volume); + + success = true; + return volume; + } else if (answer != null) { + s_logger.debug("Resize: returned '" + answer.getDetails() + "'"); + } + } catch (StorageUnavailableException e) { + s_logger.debug("volume failed to resize: " + e); + return null; + } finally { + if (success) { + try { + stateTransitTo(volume, Volume.Event.OperationSucceeded); + } catch (NoTransitionException etrans) { + throw new CloudRuntimeException( + "Failed to change volume state: " + + etrans.toString()); + } + } else { + try { + stateTransitTo(volume, Volume.Event.OperationFailed); + } catch (NoTransitionException etrans) { + throw new CloudRuntimeException( + "Failed to change volume state: " + + etrans.toString()); + } + } + } + return null; + } + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume") + public boolean deleteVolume(long volumeId, Account caller) + throws ConcurrentOperationException { + + VolumeVO volume = _volsDao.findById(volumeId); + if (volume == null) { + throw new InvalidParameterValueException( + "Unable to aquire volume with ID: " + volumeId); + } + + if (!_snapshotMgr.canOperateOnVolume(volume)) { + throw new InvalidParameterValueException( + "There are snapshot creating on it, Unable to delete the volume"); + } + + _accountMgr.checkAccess(caller, null, true, volume); + + if (volume.getInstanceId() != null) { + throw new InvalidParameterValueException( + "Please specify a volume that is not attached to any VM."); + } + + if (volume.getState() == Volume.State.UploadOp) { + VolumeHostVO volumeHost = _volumeHostDao.findByVolumeId(volume + .getId()); + if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) { + throw new InvalidParameterValueException( + "Please specify a volume that is not uploading"); + } + } + + try { + if (volume.getState() != Volume.State.Destroy && volume.getState() != Volume.State.Expunging && volume.getState() != Volume.State.Expunging) { + Long instanceId = volume.getInstanceId(); + if (!this.volService.destroyVolume(volume.getId())) { + return false; + } + + VMInstanceVO vmInstance = this._vmInstanceDao.findById(instanceId); + if (instanceId == null + || (vmInstance.getType().equals(VirtualMachine.Type.User))) { + // Decrement the resource count for volumes belonging user VM's only + _resourceLimitMgr.decrementResourceCount(volume.getAccountId(), + ResourceType.volume); + // Log usage event for volumes belonging user VM's only + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), + volume.getDataCenterId(), volume.getId(), volume.getName()); + _usageEventDao.persist(usageEvent); + } + } + AsyncCallFuture future = this.volService.expungeVolumeAsync(this.volFactory.getVolume(volume.getId())); + future.get(); + + } catch (Exception e) { + s_logger.warn("Failed to expunge volume:", e); + return false; + } + + return true; + } + + private boolean validateVolumeSizeRange(long size) { + if (size < 0 || (size > 0 && size < (1024 * 1024 * 1024))) { + throw new InvalidParameterValueException( + "Please specify a size of at least 1 Gb."); + } else if (size > (_maxVolumeSizeInGb * 1024 * 1024 * 1024)) { + throw new InvalidParameterValueException("volume size " + size + + ", but the maximum size allowed is " + _maxVolumeSizeInGb + + " Gb."); + } + + return true; + } + + protected DiskProfile toDiskProfile(VolumeVO vol, DiskOfferingVO offering) { + return new DiskProfile(vol.getId(), vol.getVolumeType(), vol.getName(), + offering.getId(), vol.getSize(), offering.getTagsArray(), + offering.getUseLocalStorage(), offering.isRecreatable(), + vol.getTemplateId()); + } + + @Override + public DiskProfile allocateRawVolume(Type type, + String name, DiskOfferingVO offering, Long size, VMInstanceVO vm, Account owner) { + if (size == null) { + size = offering.getDiskSize(); + } else { + size = (size * 1024 * 1024 * 1024); + } + VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), + owner.getDomainId(), owner.getId(), offering.getId(), size); + if (vm != null) { + vol.setInstanceId(vm.getId()); + } + + if (type.equals(Type.ROOT)) { + vol.setDeviceId(0l); + } else { + vol.setDeviceId(1l); + } + + vol = _volsDao.persist(vol); + + // Save usage event and update resource count for user vm volumes + if (vm instanceof UserVm) { + + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), + vol.getDataCenterId(), vol.getId(), vol.getName(), + offering.getId(), null, size); + _usageEventDao.persist(usageEvent); + + _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), + ResourceType.volume); + } + return toDiskProfile(vol, offering); + } + + @Override + public DiskProfile allocateTemplatedVolume( + Type type, String name, DiskOfferingVO offering, + VMTemplateVO template, VMInstanceVO vm, Account owner) { + assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really...."; + + Long size = this._tmpltMgr.getTemplateSize(template.getId(), vm.getDataCenterId()); + + VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), + owner.getDomainId(), owner.getId(), offering.getId(), size); + if (vm != null) { + vol.setInstanceId(vm.getId()); + } + vol.setTemplateId(template.getId()); + + if (type.equals(Type.ROOT)) { + vol.setDeviceId(0l); + if (!vm.getType().equals(VirtualMachine.Type.User)) { + vol.setRecreatable(true); + } + } else { + vol.setDeviceId(1l); + } + + vol = _volsDao.persist(vol); + + // Create event and update resource count for volumes if vm is a user vm + if (vm instanceof UserVm) { + + Long offeringId = null; + + if (offering.getType() == DiskOfferingVO.Type.Disk) { + offeringId = offering.getId(); + } + + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), + vol.getDataCenterId(), vol.getId(), vol.getName(), + offeringId, template.getId(), vol.getSize()); + _usageEventDao.persist(usageEvent); + + _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), + ResourceType.volume); + } + return toDiskProfile(vol, offering); + } + + private String getSupportedImageFormatForCluster(Long clusterId) { + ClusterVO cluster = ApiDBUtils.findClusterById(clusterId); + + if (cluster.getHypervisorType() == HypervisorType.XenServer) { + return "vhd"; + } else if (cluster.getHypervisorType() == HypervisorType.KVM) { + return "qcow2"; + } else if (cluster.getHypervisorType() == HypervisorType.VMware) { + return "ova"; + } else if (cluster.getHypervisorType() == HypervisorType.Ovm) { + return "raw"; + } else { + return null; + } + } + + private VolumeInfo copyVolume(StoragePoolVO rootDiskPool + , VolumeInfo volume, VMInstanceVO vm, VMTemplateVO rootDiskTmplt, DataCenterVO dcVO, + HostPodVO pod, DiskOfferingVO diskVO, ServiceOfferingVO svo, HypervisorType rootDiskHyperType) throws NoTransitionException { + VolumeHostVO volHostVO = _volumeHostDao.findByHostVolume(volume.getDataStore().getId(), volume.getId()); + if (!volHostVO + .getFormat() + .getFileExtension() + .equals( + getSupportedImageFormatForCluster(rootDiskPool + .getClusterId()))) { + throw new InvalidParameterValueException( + "Failed to attach volume to VM since volumes format " + + volHostVO.getFormat() + .getFileExtension() + + " is not compatible with the vm hypervisor type"); + } + + VolumeInfo volumeOnPrimary = copyVolumeFromSecToPrimary(volume, + vm, rootDiskTmplt, dcVO, pod, + rootDiskPool.getClusterId(), svo, diskVO, + new ArrayList(), + volume.getSize(), rootDiskHyperType); + + return volumeOnPrimary; + } + + private VolumeInfo createVolumeOnPrimaryStorage(VMInstanceVO vm, VolumeVO rootVolumeOfVm, VolumeInfo volume, HypervisorType rootDiskHyperType) throws NoTransitionException { + VMTemplateVO rootDiskTmplt = _templateDao.findById(vm + .getTemplateId()); + DataCenterVO dcVO = _dcDao.findById(vm + .getDataCenterId()); + HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn()); + StoragePoolVO rootDiskPool = _storagePoolDao + .findById(rootVolumeOfVm.getPoolId()); + ServiceOfferingVO svo = _serviceOfferingDao.findById(vm + .getServiceOfferingId()); + DiskOfferingVO diskVO = _diskOfferingDao.findById(volume + .getDiskOfferingId()); + Long clusterId = (rootDiskPool == null ? null : rootDiskPool + .getClusterId()); + + VolumeInfo vol = null; + if (volume.getState() == Volume.State.Allocated) { + vol = createVolume(volume, vm, + rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO, + new ArrayList(), volume.getSize(), + rootDiskHyperType); + } else if (volume.getState() == Volume.State.Uploaded) { + vol = copyVolume(rootDiskPool + , volume, vm, rootDiskTmplt, dcVO, + pod, diskVO, svo, rootDiskHyperType); + } + return vol; + } + + private boolean needMoveVolume(VolumeVO rootVolumeOfVm, VolumeInfo volume) { + StoragePoolVO vmRootVolumePool = _storagePoolDao + .findById(rootVolumeOfVm.getPoolId()); + DiskOfferingVO volumeDiskOffering = _diskOfferingDao + .findById(volume.getDiskOfferingId()); + String[] volumeTags = volumeDiskOffering.getTagsArray(); + + boolean isVolumeOnSharedPool = !volumeDiskOffering + .getUseLocalStorage(); + StoragePoolVO sourcePool = _storagePoolDao.findById(volume + .getPoolId()); + List matchingVMPools = _storagePoolDao + .findPoolsByTags(vmRootVolumePool.getDataCenterId(), + vmRootVolumePool.getPodId(), + vmRootVolumePool.getClusterId(), volumeTags, + isVolumeOnSharedPool); + + boolean moveVolumeNeeded = true; + if (matchingVMPools.size() == 0) { + String poolType; + if (vmRootVolumePool.getClusterId() != null) { + poolType = "cluster"; + } else if (vmRootVolumePool.getPodId() != null) { + poolType = "pod"; + } else { + poolType = "zone"; + } + throw new CloudRuntimeException( + "There are no storage pools in the VM's " + poolType + + " with all of the volume's tags (" + + volumeDiskOffering.getTags() + ")."); + } else { + long sourcePoolId = sourcePool.getId(); + Long sourcePoolDcId = sourcePool.getDataCenterId(); + Long sourcePoolPodId = sourcePool.getPodId(); + Long sourcePoolClusterId = sourcePool.getClusterId(); + for (StoragePoolVO vmPool : matchingVMPools) { + long vmPoolId = vmPool.getId(); + Long vmPoolDcId = vmPool.getDataCenterId(); + Long vmPoolPodId = vmPool.getPodId(); + Long vmPoolClusterId = vmPool.getClusterId(); + + // Moving a volume is not required if storage pools belongs + // to same cluster in case of shared volume or + // identical storage pool in case of local + if (sourcePoolDcId == vmPoolDcId + && sourcePoolPodId == vmPoolPodId + && sourcePoolClusterId == vmPoolClusterId + && (isVolumeOnSharedPool || sourcePoolId == vmPoolId)) { + moveVolumeNeeded = false; + break; + } + } + } + + return moveVolumeNeeded; + } + + + private VolumeVO sendAttachVolumeCommand(UserVmVO vm, VolumeVO volume, Long deviceId) { + String errorMsg = "Failed to attach volume: " + volume.getName() + + " to VM: " + vm.getHostName(); + boolean sendCommand = (vm.getState() == State.Running); + AttachVolumeAnswer answer = null; + Long hostId = vm.getHostId(); + if (hostId == null) { + hostId = vm.getLastHostId(); + HostVO host = _hostDao.findById(hostId); + if (host != null + && host.getHypervisorType() == HypervisorType.VMware) { + sendCommand = true; + } + } + + if (sendCommand) { + StoragePoolVO volumePool = _storagePoolDao.findById(volume + .getPoolId()); + AttachVolumeCommand cmd = new AttachVolumeCommand(true, + vm.getInstanceName(), volume.getPoolType(), + volume.getFolder(), volume.getPath(), volume.getName(), + deviceId, volume.getChainInfo()); + cmd.setPoolUuid(volumePool.getUuid()); + + try { + answer = (AttachVolumeAnswer) _agentMgr.send(hostId, cmd); + } catch (Exception e) { + throw new CloudRuntimeException(errorMsg + " due to: " + + e.getMessage()); + } + } + + if (!sendCommand || (answer != null && answer.getResult())) { + // Mark the volume as attached + if (sendCommand) { + _volsDao.attachVolume(volume.getId(), vm.getId(), + answer.getDeviceId()); + } else { + _volsDao.attachVolume(volume.getId(), vm.getId(), deviceId); + } + return _volsDao.findById(volume.getId()); + } else { + if (answer != null) { + String details = answer.getDetails(); + if (details != null && !details.isEmpty()) { + errorMsg += "; " + details; + } + } + throw new CloudRuntimeException(errorMsg); + } + } + + private int getMaxDataVolumesSupported(UserVmVO vm) { + Long hostId = vm.getHostId(); + if (hostId == null) { + hostId = vm.getLastHostId(); + } + HostVO host = _hostDao.findById(hostId); + Integer maxDataVolumesSupported = null; + if (host != null) { + _hostDao.loadDetails(host); + maxDataVolumesSupported = _hypervisorCapabilitiesDao + .getMaxDataVolumesLimit(host.getHypervisorType(), + host.getDetail("product_version")); + } + if (maxDataVolumesSupported == null) { + maxDataVolumesSupported = 6; // 6 data disks by default if nothing + // is specified in + // 'hypervisor_capabilities' table + } + + return maxDataVolumesSupported.intValue(); + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription = "attaching volume", async = true) + public Volume attachVolumeToVM(AttachVolumeCmd command) { + Long vmId = command.getVirtualMachineId(); + Long volumeId = command.getId(); + Long deviceId = command.getDeviceId(); + Account caller = UserContext.current().getCaller(); + + // Check that the volume ID is valid + VolumeInfo volume = volFactory.getVolume(volumeId); + // Check that the volume is a data volume + if (volume == null || volume.getVolumeType() != Volume.Type.DATADISK) { + throw new InvalidParameterValueException( + "Please specify a valid data volume."); + } + + // Check that the volume is not currently attached to any VM + if (volume.getInstanceId() != null) { + throw new InvalidParameterValueException( + "Please specify a volume that is not attached to any VM."); + } + + // Check that the volume is not destroyed + if (volume.getState() == Volume.State.Destroy) { + throw new InvalidParameterValueException( + "Please specify a volume that is not destroyed."); + } + + // Check that the virtual machine ID is valid and it's a user vm + UserVmVO vm = _userVmDao.findById(vmId); + if (vm == null || vm.getType() != VirtualMachine.Type.User) { + throw new InvalidParameterValueException( + "Please specify a valid User VM."); + } + + // Check that the VM is in the correct state + if (vm.getState() != State.Running && vm.getState() != State.Stopped) { + throw new InvalidParameterValueException( + "Please specify a VM that is either running or stopped."); + } + + // Check that the device ID is valid + if (deviceId != null) { + if (deviceId.longValue() == 0) { + throw new InvalidParameterValueException( + "deviceId can't be 0, which is used by Root device"); + } + } + + // Check that the number of data volumes attached to VM is less than + // that supported by hypervisor + List existingDataVolumes = _volsDao.findByInstanceAndType( + vmId, Volume.Type.DATADISK); + int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); + if (existingDataVolumes.size() >= maxDataVolumesSupported) { + throw new InvalidParameterValueException( + "The specified VM already has the maximum number of data disks (" + + maxDataVolumesSupported + + "). Please specify another VM."); + } + + // Check that the VM and the volume are in the same zone + if (vm.getDataCenterId() != volume.getDataCenterId()) { + throw new InvalidParameterValueException( + "Please specify a VM that is in the same zone as the volume."); + } + + // If local storage is disabled then attaching a volume with local disk + // offering not allowed + DataCenterVO dataCenter = _dcDao.findById(volume.getDataCenterId()); + if (!dataCenter.isLocalStorageEnabled()) { + DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume + .getDiskOfferingId()); + if (diskOffering.getUseLocalStorage()) { + throw new InvalidParameterValueException( + "Zone is not configured to use local storage but volume's disk offering " + + diskOffering.getName() + " uses it"); + } + } + + // permission check + _accountMgr.checkAccess(caller, null, true, volume, vm); + + if (!(Volume.State.Allocated.equals(volume.getState()) + || Volume.State.Ready.equals(volume.getState()) || Volume.State.Uploaded + .equals(volume.getState()))) { + throw new InvalidParameterValueException( + "Volume state must be in Allocated, Ready or in Uploaded state"); + } + + VolumeVO rootVolumeOfVm = null; + List rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, + Volume.Type.ROOT); + if (rootVolumesOfVm.size() != 1) { + throw new CloudRuntimeException( + "The VM " + + vm.getHostName() + + " has more than one ROOT volume and is in an invalid state."); + } else { + rootVolumeOfVm = rootVolumesOfVm.get(0); + } + + HypervisorType rootDiskHyperType = vm.getHypervisorType(); + + HypervisorType dataDiskHyperType = _volsDao.getHypervisorType(volume + .getId()); + if (dataDiskHyperType != HypervisorType.None + && rootDiskHyperType != dataDiskHyperType) { + throw new InvalidParameterValueException( + "Can't attach a volume created by: " + dataDiskHyperType + + " to a " + rootDiskHyperType + " vm"); + } + + + deviceId = getDeviceId(vmId, deviceId); + VolumeInfo volumeOnPrimaryStorage = volume; + if (volume.getState().equals(Volume.State.Allocated) + || volume.getState() == Volume.State.Uploaded) { + try { + volumeOnPrimaryStorage = createVolumeOnPrimaryStorage(vm, rootVolumeOfVm, volume, rootDiskHyperType); + } catch (NoTransitionException e) { + s_logger.debug("Failed to create volume on primary storage", e); + throw new CloudRuntimeException("Failed to create volume on primary storage", e); + } + } + + boolean moveVolumeNeeded = needMoveVolume(rootVolumeOfVm, volumeOnPrimaryStorage); + + if (moveVolumeNeeded) { + PrimaryDataStoreInfo primaryStore = (PrimaryDataStoreInfo)volumeOnPrimaryStorage.getDataStore(); + if (primaryStore.isLocal()) { + throw new CloudRuntimeException( + "Failed to attach local data volume " + + volume.getName() + + " to VM " + + vm.getDisplayName() + + " as migration of local data volume is not allowed"); + } + StoragePoolVO vmRootVolumePool = _storagePoolDao + .findById(rootVolumeOfVm.getPoolId()); + + try { + volumeOnPrimaryStorage = moveVolume(volumeOnPrimaryStorage, + vmRootVolumePool.getDataCenterId(), + vmRootVolumePool.getPodId(), + vmRootVolumePool.getClusterId(), + dataDiskHyperType); + } catch (ConcurrentOperationException e) { + s_logger.debug("move volume failed", e); + throw new CloudRuntimeException("move volume failed", e); + } + } + + + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor + .getCurrentExecutor(); + if (asyncExecutor != null) { + AsyncJobVO job = asyncExecutor.getJob(); + + if (s_logger.isInfoEnabled()) { + s_logger.info("Trying to attaching volume " + volumeId + + " to vm instance:" + vm.getId() + + ", update async job-" + job.getId() + + " progress status"); + } + + _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); + _asyncMgr.updateAsyncJobStatus(job.getId(), + BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId); + } + + VolumeVO newVol = _volumeDao.findById(volumeOnPrimaryStorage.getId()); + newVol = sendAttachVolumeCommand(vm, newVol, deviceId); + return newVol; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "detaching volume", async = true) + public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) { + Account caller = UserContext.current().getCaller(); + if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd + .getVirtualMachineId() == null) + || (cmmd.getId() != null && (cmmd.getDeviceId() != null || cmmd + .getVirtualMachineId() != null)) + || (cmmd.getId() == null && (cmmd.getDeviceId() == null || cmmd + .getVirtualMachineId() == null))) { + throw new InvalidParameterValueException( + "Please provide either a volume id, or a tuple(device id, instance id)"); + } + + Long volumeId = cmmd.getId(); + VolumeVO volume = null; + + if (volumeId != null) { + volume = _volsDao.findById(volumeId); + } else { + volume = _volsDao.findByInstanceAndDeviceId( + cmmd.getVirtualMachineId(), cmmd.getDeviceId()).get(0); + } + + Long vmId = null; + + if (cmmd.getVirtualMachineId() == null) { + vmId = volume.getInstanceId(); + } else { + vmId = cmmd.getVirtualMachineId(); + } + + // Check that the volume ID is valid + if (volume == null) { + throw new InvalidParameterValueException( + "Unable to find volume with ID: " + volumeId); + } + + // Permissions check + _accountMgr.checkAccess(caller, null, true, volume); + + // Check that the volume is a data volume + if (volume.getVolumeType() != Volume.Type.DATADISK) { + throw new InvalidParameterValueException( + "Please specify a data volume."); + } + + // Check that the volume is currently attached to a VM + if (vmId == null) { + throw new InvalidParameterValueException( + "The specified volume is not attached to a VM."); + } + + // Check that the VM is in the correct state + UserVmVO vm = this._userVmDao.findById(vmId); + if (vm.getState() != State.Running && vm.getState() != State.Stopped + && vm.getState() != State.Destroyed) { + throw new InvalidParameterValueException( + "Please specify a VM that is either running or stopped."); + } + + AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor + .getCurrentExecutor(); + if (asyncExecutor != null) { + AsyncJobVO job = asyncExecutor.getJob(); + + if (s_logger.isInfoEnabled()) { + s_logger.info("Trying to attaching volume " + volumeId + + "to vm instance:" + vm.getId() + + ", update async job-" + job.getId() + + " progress status"); + } + + _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); + _asyncMgr.updateAsyncJobStatus(job.getId(), + BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId); + } + + String errorMsg = "Failed to detach volume: " + volume.getName() + + " from VM: " + vm.getHostName(); + boolean sendCommand = (vm.getState() == State.Running); + Answer answer = null; + + if (sendCommand) { + AttachVolumeCommand cmd = new AttachVolumeCommand(false, + vm.getInstanceName(), volume.getPoolType(), + volume.getFolder(), volume.getPath(), volume.getName(), + cmmd.getDeviceId() != null ? cmmd.getDeviceId() : volume + .getDeviceId(), volume.getChainInfo()); + + StoragePoolVO volumePool = _storagePoolDao.findById(volume + .getPoolId()); + cmd.setPoolUuid(volumePool.getUuid()); + + try { + answer = _agentMgr.send(vm.getHostId(), cmd); + } catch (Exception e) { + throw new CloudRuntimeException(errorMsg + " due to: " + + e.getMessage()); + } + } + + if (!sendCommand || (answer != null && answer.getResult())) { + // Mark the volume as detached + _volsDao.detachVolume(volume.getId()); + if (answer != null && answer instanceof AttachVolumeAnswer) { + volume.setChainInfo(((AttachVolumeAnswer) answer) + .getChainInfo()); + _volsDao.update(volume.getId(), volume); + } + + return _volsDao.findById(volumeId); + } else { + + if (answer != null) { + String details = answer.getDetails(); + if (details != null && !details.isEmpty()) { + errorMsg += "; " + details; + } + } + + throw new CloudRuntimeException(errorMsg); + } + } + + + + + + + @DB + protected VolumeVO switchVolume(VolumeVO existingVolume, + VirtualMachineProfile vm) + throws StorageUnavailableException { + Transaction txn = Transaction.currentTxn(); + + Long templateIdToUse = null; + Long volTemplateId = existingVolume.getTemplateId(); + long vmTemplateId = vm.getTemplateId(); + if (volTemplateId != null && volTemplateId.longValue() != vmTemplateId) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("switchVolume: Old Volume's templateId: " + + volTemplateId + + " does not match the VM's templateId: " + + vmTemplateId + + ", updating templateId in the new Volume"); + } + templateIdToUse = vmTemplateId; + } + + txn.start(); + VolumeVO newVolume = allocateDuplicateVolume(existingVolume, + templateIdToUse); + // In case of Vmware if vm reference is not removed then during root + // disk cleanup + // the vm also gets deleted, so remove the reference + if (vm.getHypervisorType() == HypervisorType.VMware) { + _volsDao.detachVolume(existingVolume.getId()); + } + try { + stateTransitTo(existingVolume, Volume.Event.DestroyRequested); + } catch (NoTransitionException e) { + s_logger.debug("Unable to destroy existing volume: " + e.toString()); + } + txn.commit(); + return newVolume; + + } + + + @Override + public void release(VirtualMachineProfile profile) { + // add code here + } + + + @Override + @DB + public void cleanupVolumes(long vmId) throws ConcurrentOperationException { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Cleaning storage for vm: " + vmId); + } + List volumesForVm = _volsDao.findByInstance(vmId); + List toBeExpunged = new ArrayList(); + Transaction txn = Transaction.currentTxn(); + txn.start(); + for (VolumeVO vol : volumesForVm) { + 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)) { + this.volService.destroyVolume(vol.getId()); + } + toBeExpunged.add(vol); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Detaching " + vol); + } + _volsDao.detachVolume(vol.getId()); + } + } + txn.commit(); + AsyncCallFuture future = null; + for (VolumeVO expunge : toBeExpunged) { + future = this.volService.expungeVolumeAsync(this.volFactory.getVolume(expunge.getId())); + try { + future.get(); + } catch (InterruptedException e) { + s_logger.debug("failed expunge volume" + expunge.getId(), e); + } catch (ExecutionException e) { + s_logger.debug("failed expunge volume" + expunge.getId(), e); + } + } + } + + @DB + @Override + public Volume migrateVolume(Long volumeId, Long storagePoolId) + throws ConcurrentOperationException { + VolumeVO vol = _volsDao.findById(volumeId); + if (vol == null) { + throw new InvalidParameterValueException( + "Failed to find the volume id: " + volumeId); + } + + if (vol.getState() != Volume.State.Ready) { + throw new InvalidParameterValueException( + "Volume must be in ready state"); + } + + if (vol.getInstanceId() != null) { + throw new InvalidParameterValueException( + "Volume needs to be dettached from VM"); + } + + StoragePool destPool = (StoragePool)this.dataStoreMgr.getDataStore(storagePoolId, DataStoreRole.Primary); + if (destPool == null) { + throw new InvalidParameterValueException( + "Failed to find the destination storage pool: " + + storagePoolId); + } + + if (!volumeOnSharedStoragePool(vol)) { + throw new InvalidParameterValueException( + "Migration of volume from local storage pool is not supported"); + } + + List vols = new ArrayList(); + vols.add(vol); + + migrateVolumes(vols, destPool); + return vol; + } + + @DB + public boolean migrateVolumes(List volumes, StoragePool destPool) + throws ConcurrentOperationException { + Transaction txn = Transaction.currentTxn(); + txn.start(); + + boolean transitResult = false; + long checkPointTaskId = -1; + try { + List volIds = new ArrayList(); + for (Volume volume : volumes) { + if (!_snapshotMgr.canOperateOnVolume((VolumeVO) volume)) { + throw new CloudRuntimeException( + "There are snapshots creating on this volume, can not move this volume"); + } + + try { + if (!stateTransitTo(volume, Volume.Event.MigrationRequested)) { + throw new ConcurrentOperationException( + "Failed to transit volume state"); + } + } catch (NoTransitionException e) { + s_logger.debug("Failed to set state into migrate: " + + e.toString()); + throw new CloudRuntimeException( + "Failed to set state into migrate: " + e.toString()); + } + volIds.add(volume.getId()); + } + + transitResult = true; + } finally { + if (!transitResult) { + txn.rollback(); + } else { + txn.commit(); + } + } + + // At this stage, nobody can modify volumes. Send the copyvolume command + List> destroyCmds = new ArrayList>(); + List answers = new ArrayList(); + try { + for (Volume volume : volumes) { + String secondaryStorageURL = this._tmpltMgr.getSecondaryStorageURL(volume + .getDataCenterId()); + StoragePool srcPool = (StoragePool)this.dataStoreMgr.getDataStore(volume + .getPoolId(), DataStoreRole.Primary); + CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), + volume.getPath(), srcPool, secondaryStorageURL, true, + _copyvolumewait); + CopyVolumeAnswer cvAnswer; + try { + cvAnswer = (CopyVolumeAnswer) this.storageMgr.sendToPool(srcPool, cvCmd); + } catch (StorageUnavailableException e1) { + throw new CloudRuntimeException( + "Failed to copy the volume from the source primary storage pool to secondary storage.", + e1); + } + + if (cvAnswer == null || !cvAnswer.getResult()) { + throw new CloudRuntimeException( + "Failed to copy the volume from the source primary storage pool to secondary storage."); + } + + String secondaryStorageVolumePath = cvAnswer.getVolumePath(); + + // Copy the volume from secondary storage to the destination + // storage + // pool + cvCmd = new CopyVolumeCommand(volume.getId(), + secondaryStorageVolumePath, destPool, + secondaryStorageURL, false, _copyvolumewait); + try { + cvAnswer = (CopyVolumeAnswer) this.storageMgr.sendToPool(destPool, cvCmd); + } catch (StorageUnavailableException e1) { + throw new CloudRuntimeException( + "Failed to copy the volume from secondary storage to the destination primary storage pool."); + } + + if (cvAnswer == null || !cvAnswer.getResult()) { + throw new CloudRuntimeException( + "Failed to copy the volume from secondary storage to the destination primary storage pool."); + } + + answers.add(cvAnswer); + destroyCmds.add(new Pair( + srcPool, new DestroyCommand(srcPool, volume, null))); + } + } finally { + if (answers.size() != volumes.size()) { + // this means one of copying volume failed + for (Volume volume : volumes) { + try { + stateTransitTo(volume, Volume.Event.OperationFailed); + } catch (NoTransitionException e) { + s_logger.debug("Failed to change volume state: " + + e.toString()); + } + } + } else { + // Need a transaction, make sure all the volumes get migrated to + // new storage pool + txn = Transaction.currentTxn(); + txn.start(); + + transitResult = false; + try { + for (int i = 0; i < volumes.size(); i++) { + CopyVolumeAnswer answer = answers.get(i); + VolumeVO volume = (VolumeVO) volumes.get(i); + Long oldPoolId = volume.getPoolId(); + volume.setPath(answer.getVolumePath()); + volume.setFolder(destPool.getPath()); + volume.setPodId(destPool.getPodId()); + volume.setPoolId(destPool.getId()); + volume.setLastPoolId(oldPoolId); + volume.setPodId(destPool.getPodId()); + try { + stateTransitTo(volume, + Volume.Event.OperationSucceeded); + } catch (NoTransitionException e) { + s_logger.debug("Failed to change volume state: " + + e.toString()); + throw new CloudRuntimeException( + "Failed to change volume state: " + + e.toString()); + } + } + transitResult = true; + } finally { + if (!transitResult) { + txn.rollback(); + } else { + txn.commit(); + } + } + + } + } + + // all the volumes get migrated to new storage pool, need to delete the + // copy on old storage pool + for (Pair cmd : destroyCmds) { + try { + Answer cvAnswer = this.storageMgr.sendToPool(cmd.first(), cmd.second()); + } catch (StorageUnavailableException e) { + s_logger.debug("Unable to delete the old copy on storage pool: " + + e.toString()); + } + } + return true; + } + + @Override + public boolean StorageMigration( + VirtualMachineProfile vm, + StoragePool destPool) throws ConcurrentOperationException { + List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); + List volumesNeedToMigrate = new ArrayList(); + + for (VolumeVO volume : vols) { + if (volume.getState() != Volume.State.Ready) { + s_logger.debug("volume: " + volume.getId() + " is in " + + volume.getState() + " state"); + throw new CloudRuntimeException("volume: " + volume.getId() + + " is in " + volume.getState() + " state"); + } + + if (volume.getPoolId() == destPool.getId()) { + s_logger.debug("volume: " + volume.getId() + + " is on the same storage pool: " + destPool.getId()); + continue; + } + + volumesNeedToMigrate.add(volume); + } + + if (volumesNeedToMigrate.isEmpty()) { + s_logger.debug("No volume need to be migrated"); + return true; + } + + return migrateVolumes(volumesNeedToMigrate, destPool); + } + + @Override + public void prepareForMigration( + VirtualMachineProfile vm, + DeployDestination dest) { + List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Preparing " + vols.size() + " volumes for " + vm); + } + + for (VolumeVO vol : vols) { + PrimaryDataStoreInfo pool = (PrimaryDataStoreInfo)this.dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary); + vm.addDisk(new VolumeTO(vol, pool)); + } + + if (vm.getType() == VirtualMachine.Type.User) { + UserVmVO userVM = (UserVmVO) vm.getVirtualMachine(); + if (userVM.getIsoId() != null) { + Pair isoPathPair = this._tmpltMgr.getAbsoluteIsoPath( + userVM.getIsoId(), userVM.getDataCenterId()); + if (isoPathPair != null) { + String isoPath = isoPathPair.first(); + VolumeTO iso = new VolumeTO(vm.getId(), Volume.Type.ISO, + StoragePoolType.ISO, null, null, null, isoPath, 0, + null, null); + vm.addDisk(iso); + } + } + } + } + + + + private static enum VolumeTaskType { + RECREATE, + NOP, + MIGRATE + } + private static class VolumeTask { + final VolumeTaskType type; + final StoragePoolVO pool; + final VolumeVO volume; + VolumeTask(VolumeTaskType type, VolumeVO volume, StoragePoolVO pool) { + this.type = type; + this.pool = pool; + this.volume = volume; + } + } + + private List getTasks(List vols, Map destVols) throws StorageUnavailableException { + boolean recreate = _recreateSystemVmEnabled; + List tasks = new ArrayList(); + for (VolumeVO vol : vols) { + StoragePoolVO assignedPool = null; + if (destVols != null) { + StoragePool pool = destVols.get(vol); + if (pool != null) { + assignedPool = _storagePoolDao.findById(pool.getId()); + } + } + if (assignedPool == null && recreate) { + assignedPool = _storagePoolDao.findById(vol.getPoolId()); + } + if (assignedPool != null || recreate) { + Volume.State state = vol.getState(); + if (state == Volume.State.Allocated + || state == Volume.State.Creating) { + VolumeTask task = new VolumeTask(VolumeTaskType.RECREATE, vol, null); + tasks.add(task); + } else { + if (vol.isRecreatable()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Volume " + vol + + " will be recreated on storage pool " + + assignedPool + + " assigned by deploymentPlanner"); + } + VolumeTask task = new VolumeTask(VolumeTaskType.RECREATE, vol, null); + tasks.add(task); + } else { + if (assignedPool.getId() != vol.getPoolId()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Mismatch in storage pool " + + assignedPool + + " assigned by deploymentPlanner and the one associated with volume " + + vol); + } + DiskOfferingVO diskOffering = _diskOfferingDao + .findById(vol.getDiskOfferingId()); + if (diskOffering.getUseLocalStorage()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Local volume " + + vol + + " will be recreated on storage pool " + + assignedPool + + " assigned by deploymentPlanner"); + } + VolumeTask task = new VolumeTask(VolumeTaskType.RECREATE, vol, null); + tasks.add(task); + } else { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Shared volume " + + vol + + " will be migrated on storage pool " + + assignedPool + + " assigned by deploymentPlanner"); + } + VolumeTask task = new VolumeTask(VolumeTaskType.MIGRATE, vol, null); + tasks.add(task); + } + } else { + StoragePoolVO pool = _storagePoolDao + .findById(vol.getPoolId()); + VolumeTask task = new VolumeTask(VolumeTaskType.NOP, vol, pool); + tasks.add(task); + } + + } + } + } else { + if (vol.getPoolId() == null) { + throw new StorageUnavailableException( + "Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create " + + vol, Volume.class, vol.getId()); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("No need to recreate the volume: " + vol + + ", since it already has a pool assigned: " + + vol.getPoolId() + ", adding disk to VM"); + } + StoragePoolVO pool = _storagePoolDao.findById(vol + .getPoolId()); + VolumeTask task = new VolumeTask(VolumeTaskType.NOP, vol, pool); + tasks.add(task); + } + } + + return tasks; + } + + private Pair recreateVolume(VolumeVO vol, VirtualMachineProfile vm, + DeployDestination dest) throws StorageUnavailableException { + VolumeVO newVol; + boolean recreate = _recreateSystemVmEnabled; + DataStore destPool = null; + if (recreate + && (dest.getStorageForDisks() == null || dest + .getStorageForDisks().get(vol) == null)) { + destPool = dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary); + s_logger.debug("existing pool: " + destPool.getId()); + } else { + StoragePool pool = dest.getStorageForDisks().get(vol); + destPool = dataStoreMgr.getDataStore(pool.getId(), DataStoreRole.Primary); + } + + if (vol.getState() == Volume.State.Allocated + || vol.getState() == Volume.State.Creating) { + newVol = vol; + } else { + newVol = switchVolume(vol, vm); + // update the volume->PrimaryDataStoreVO map since volumeId has + // changed + if (dest.getStorageForDisks() != null + && dest.getStorageForDisks().containsKey(vol)) { + StoragePool poolWithOldVol = dest + .getStorageForDisks().get(vol); + dest.getStorageForDisks().put(newVol, poolWithOldVol); + dest.getStorageForDisks().remove(vol); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Created new volume " + newVol + + " for old volume " + vol); + } + } + VolumeInfo volume = volFactory.getVolume(newVol.getId(), destPool); + Long templateId = newVol.getTemplateId(); + AsyncCallFuture future = null; + if (templateId == null) { + future = this.volService.createVolumeAsync(volume, destPool); + } else { + TemplateInfo templ = this.tmplFactory.getTemplate(templateId); + future = this.volService.createVolumeFromTemplateAsync(volume, destPool.getId(), templ); + } + VolumeApiResult result = null; + try { + result = future.get(); + if (result.isFailed()) { + s_logger.debug("Unable to create " + + newVol + ":" + result.getResult()); + throw new StorageUnavailableException("Unable to create " + + newVol + ":" + result.getResult(), destPool.getId()); + } + newVol = this._volsDao.findById(newVol.getId()); + } catch (InterruptedException e) { + s_logger.error("Unable to create " + newVol, e); + throw new StorageUnavailableException("Unable to create " + + newVol + ":" + e.toString(), destPool.getId()); + } catch (ExecutionException e) { + s_logger.error("Unable to create " + newVol, e); + throw new StorageUnavailableException("Unable to create " + + newVol + ":" + e.toString(), destPool.getId()); + } + + return new Pair(newVol, destPool); + } + + @Override + public void prepare(VirtualMachineProfile vm, + DeployDestination dest) throws StorageUnavailableException, + InsufficientStorageCapacityException, ConcurrentOperationException { + + if (dest == null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("DeployDestination cannot be null, cannot prepare Volumes for the vm: " + + vm); + } + throw new CloudRuntimeException( + "Unable to prepare Volume for vm because DeployDestination is null, vm:" + + vm); + } + List vols = _volsDao.findUsableVolumesForInstance(vm.getId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Checking if we need to prepare " + vols.size() + + " volumes for " + vm); + } + + List tasks = getTasks(vols, dest.getStorageForDisks()); + Volume vol = null; + StoragePool pool = null; + for (VolumeTask task : tasks) { + if (task.type == VolumeTaskType.NOP) { + pool = (StoragePool)dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary); + vol = task.volume; + } else if (task.type == VolumeTaskType.MIGRATE) { + pool = (StoragePool)dataStoreMgr.getDataStore(task.pool.getId(), DataStoreRole.Primary); + List volumes = new ArrayList(); + volumes.add(task.volume); + migrateVolumes(volumes, pool); + vol = task.volume; + } else if (task.type == VolumeTaskType.RECREATE) { + Pair result = recreateVolume(task.volume, vm, dest); + pool = (StoragePool)dataStoreMgr.getDataStore(result.second().getId(), DataStoreRole.Primary); + vol = result.first(); + } + vm.addDisk(new VolumeTO(vol, pool)); + } + } + + private Long getDeviceId(long vmId, Long deviceId) { + // allocate deviceId + List vols = _volsDao.findByInstance(vmId); + if (deviceId != null) { + if (deviceId.longValue() > 15 || deviceId.longValue() == 0 + || deviceId.longValue() == 3) { + throw new RuntimeException("deviceId should be 1,2,4-15"); + } + for (VolumeVO vol : vols) { + if (vol.getDeviceId().equals(deviceId)) { + throw new RuntimeException("deviceId " + deviceId + + " is used by vm" + vmId); + } + } + } else { + // allocate deviceId here + List devIds = new ArrayList(); + for (int i = 1; i < 15; i++) { + devIds.add(String.valueOf(i)); + } + devIds.remove("3"); + for (VolumeVO vol : vols) { + devIds.remove(vol.getDeviceId().toString().trim()); + } + deviceId = Long.parseLong(devIds.iterator().next()); + } + + return deviceId; + } + + private boolean stateTransitTo(Volume vol, Volume.Event event) + throws NoTransitionException { + return _volStateMachine.transitTo(vol, event, null, _volsDao); + } + + + private String validateUrl(String url) { + try { + URI uri = new URI(url); + if ((uri.getScheme() == null) + || (!uri.getScheme().equalsIgnoreCase("http") + && !uri.getScheme().equalsIgnoreCase("https") && !uri + .getScheme().equalsIgnoreCase("file"))) { + throw new IllegalArgumentException( + "Unsupported scheme for url: " + url); + } + + int port = uri.getPort(); + if (!(port == 80 || port == 443 || port == -1)) { + throw new IllegalArgumentException( + "Only ports 80 and 443 are allowed"); + } + String host = uri.getHost(); + try { + InetAddress hostAddr = InetAddress.getByName(host); + if (hostAddr.isAnyLocalAddress() + || hostAddr.isLinkLocalAddress() + || hostAddr.isLoopbackAddress() + || hostAddr.isMulticastAddress()) { + throw new IllegalArgumentException( + "Illegal host specified in url"); + } + if (hostAddr instanceof Inet6Address) { + throw new IllegalArgumentException( + "IPV6 addresses not supported (" + + hostAddr.getHostAddress() + ")"); + } + } catch (UnknownHostException uhe) { + throw new IllegalArgumentException("Unable to resolve " + host); + } + + return uri.toString(); + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Invalid URL " + url); + } + + } + + @Override + public boolean canVmRestartOnAnotherServer(long vmId) { + List vols = _volsDao.findCreatedByInstance(vmId); + for (VolumeVO vol : vols) { + if (!vol.isRecreatable() && !vol.getPoolType().isShared()) { + return false; + } + } + return true; + } + + @Override + public boolean configure(String name, Map params) + throws ConfigurationException { + String _customDiskOfferingMinSizeStr = _configDao + .getValue(Config.CustomDiskOfferingMinSize.toString()); + _customDiskOfferingMinSize = NumbersUtil.parseInt( + _customDiskOfferingMinSizeStr, Integer + .parseInt(Config.CustomDiskOfferingMinSize + .getDefaultValue())); + + String maxVolumeSizeInGbString = _configDao + .getValue("storage.max.volume.size"); + _maxVolumeSizeInGb = NumbersUtil.parseLong(maxVolumeSizeInGbString, + 2000); + + String value = _configDao.getValue(Config.RecreateSystemVmEnabled.key()); + _recreateSystemVmEnabled = Boolean.parseBoolean(value); + _copyvolumewait = NumbersUtil.parseInt(value, + Integer.parseInt(Config.CopyVolumeWait.getDefaultValue())); + + HostTemplateStatesSearch = _vmTemplateHostDao.createSearchBuilder(); + HostTemplateStatesSearch.and("id", HostTemplateStatesSearch.entity() + .getTemplateId(), SearchCriteria.Op.EQ); + HostTemplateStatesSearch.and("state", HostTemplateStatesSearch.entity() + .getDownloadState(), SearchCriteria.Op.EQ); + + SearchBuilder HostSearch = _hostDao.createSearchBuilder(); + HostSearch.and("dcId", HostSearch.entity().getDataCenterId(), + SearchCriteria.Op.EQ); + + HostTemplateStatesSearch.join("host", HostSearch, HostSearch.entity() + .getId(), HostTemplateStatesSearch.entity().getHostId(), + JoinBuilder.JoinType.INNER); + HostSearch.done(); + HostTemplateStatesSearch.done(); + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return "Volume Manager"; + } + + @Override + public void destroyVolume(VolumeVO volume) { + try { + this.volService.destroyVolume(volume.getId()); + } catch (ConcurrentOperationException e) { + s_logger.debug("Failed to destroy volume" + volume.getId(), e); + throw new CloudRuntimeException("Failed to destroy volume" + volume.getId(), e); + } + } + +} diff --git a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java index 61b5e1f7752..d747d25c7b5 100755 --- a/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/AbstractStoragePoolAllocator.java @@ -26,6 +26,8 @@ import java.util.Set; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import com.cloud.capacity.CapacityManager; @@ -41,7 +43,6 @@ import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; @@ -76,6 +77,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement @Inject ClusterDao _clusterDao; @Inject SwiftManager _swiftMgr; @Inject CapacityManager _capacityMgr; + @Inject DataStoreManager dataStoreMgr; protected BigDecimal _storageOverprovisioningFactor = new BigDecimal(1); long _extraBytesPerVolume = 0; Random _rand; @@ -121,7 +123,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement boolean localStorageAllocationNeeded = localStorageAllocationNeeded(dskCh); if (s_logger.isDebugEnabled()) { s_logger.debug("Is localStorageAllocationNeeded? "+ localStorageAllocationNeeded); - s_logger.debug("Is storage pool shared? "+ pool.getPoolType().isShared()); + s_logger.debug("Is storage pool shared? "+ pool.isShared()); } return ((!localStorageAllocationNeeded && pool.getPoolType().isShared()) || (localStorageAllocationNeeded && !pool.getPoolType().isShared())); @@ -133,8 +135,8 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement if (s_logger.isDebugEnabled()) { s_logger.debug("Checking if storage pool is suitable, name: " + pool.getName()+ " ,poolId: "+ pool.getId()); } - - if (avoid.shouldAvoid(pool)) { + StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); + if (avoid.shouldAvoid(pol)) { if (s_logger.isDebugEnabled()) { s_logger.debug("StoragePool is in avoid set, skipping this pool"); } @@ -157,7 +159,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement } // Check that the pool type is correct - if (!poolIsCorrectType(dskCh, pool)) { + if (!poolIsCorrectType(dskCh, pol)) { if (s_logger.isDebugEnabled()) { s_logger.debug("StoragePool is not of correct type, skipping this pool"); } @@ -181,7 +183,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement Volume volume = _volumeDao.findById(dskCh.getVolumeId()); List requestVolumes = new ArrayList(); requestVolumes.add(volume); - return _storageMgr.storagePoolHasEnoughSpace(requestVolumes, pool); + return _storageMgr.storagePoolHasEnoughSpace(requestVolumes, pol); } diff --git a/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java index 13a010729e0..f0df3a6f001 100644 --- a/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/FirstFitStoragePoolAllocator.java @@ -27,6 +27,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import com.cloud.deploy.DeploymentPlan; @@ -34,11 +35,10 @@ import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.offering.ServiceOffering; import com.cloud.server.StatsCollector; import com.cloud.storage.DiskOfferingVO; -import com.cloud.storage.dao.DiskOfferingDao; -import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.StoragePool; +import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.user.Account; import com.cloud.vm.DiskProfile; import com.cloud.vm.VirtualMachine; @@ -117,7 +117,8 @@ public class FirstFitStoragePoolAllocator extends AbstractStoragePoolAllocator { } if (checkPool(avoid, pool, dskCh, template, null, sc, plan)) { - suitablePools.add(pool); + StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); + suitablePools.add(pol); } } diff --git a/server/src/com/cloud/storage/allocator/LocalStoragePoolAllocator.java b/server/src/com/cloud/storage/allocator/LocalStoragePoolAllocator.java index b6b8e8e98ff..24b4dabe281 100644 --- a/server/src/com/cloud/storage/allocator/LocalStoragePoolAllocator.java +++ b/server/src/com/cloud/storage/allocator/LocalStoragePoolAllocator.java @@ -25,6 +25,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import com.cloud.capacity.CapacityVO; @@ -36,7 +37,6 @@ import com.cloud.offering.ServiceOffering; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.StoragePoolHostDao; @@ -110,7 +110,8 @@ public class LocalStoragePoolAllocator extends FirstFitStoragePoolAllocator { StoragePoolVO pool = _storagePoolDao.findById(hostPool.getPoolId()); if (pool != null && pool.isLocal()) { s_logger.debug("Found suitable local storage pool " + pool.getId() + ", adding to list"); - suitablePools.add(pool); + StoragePool pol = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(pool.getId()); + suitablePools.add(pol); } if (suitablePools.size() == returnUpTo) { diff --git a/server/src/com/cloud/storage/dao/LaunchPermissionDao.java b/server/src/com/cloud/storage/dao/LaunchPermissionDao.java index 86e5a9bf827..0ad60b50ee8 100644 --- a/server/src/com/cloud/storage/dao/LaunchPermissionDao.java +++ b/server/src/com/cloud/storage/dao/LaunchPermissionDao.java @@ -18,6 +18,7 @@ package com.cloud.storage.dao; import java.util.List; + import com.cloud.storage.LaunchPermissionVO; import com.cloud.storage.VMTemplateVO; import com.cloud.utils.db.GenericDao; diff --git a/server/src/com/cloud/storage/dao/StoragePoolDao.java b/server/src/com/cloud/storage/dao/StoragePoolDao.java index ff8292e9705..64bbd5fb5ed 100644 --- a/server/src/com/cloud/storage/dao/StoragePoolDao.java +++ b/server/src/com/cloud/storage/dao/StoragePoolDao.java @@ -20,8 +20,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.utils.db.GenericDao; /** * Data Access Object for storage_pool table diff --git a/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java b/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java index 4019dffd4ae..ebf2943ec9c 100644 --- a/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java +++ b/server/src/com/cloud/storage/dao/StoragePoolDaoImpl.java @@ -28,13 +28,13 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.springframework.stereotype.Component; import com.cloud.host.Status; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StoragePoolDetailVO; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; diff --git a/server/src/com/cloud/storage/dao/VMTemplateDao.java b/server/src/com/cloud/storage/dao/VMTemplateDao.java index a043a2c6079..c39626f54dd 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDao.java @@ -20,6 +20,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; + import com.cloud.domain.DomainVO; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.projects.Project.ListProjectResourcesCriteria; @@ -28,11 +31,12 @@ import com.cloud.template.VirtualMachineTemplate.TemplateFilter; import com.cloud.user.Account; import com.cloud.utils.Pair; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; /* * Data Access Object for vm_templates table */ -public interface VMTemplateDao extends GenericDao { +public interface VMTemplateDao extends GenericDao, StateDao { public List listByPublic(); diff --git a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java index 42f10d34c1b..c4928be8fee 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateDaoImpl.java @@ -16,8 +16,8 @@ // under the License. package com.cloud.storage.dao; -import static com.cloud.utils.StringUtils.*; -import static com.cloud.utils.db.DbUtil.*; +import static com.cloud.utils.StringUtils.join; +import static com.cloud.utils.db.DbUtil.closeResources; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -34,10 +34,12 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateState; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.api.BaseCmd; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.DomainVO; @@ -55,11 +57,10 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.tags.ResourceTagVO; -import com.cloud.tags.dao.ResourceTagsDaoImpl; +import com.cloud.tags.dao.ResourceTagDao; import com.cloud.template.VirtualMachineTemplate.TemplateFilter; import com.cloud.user.Account; import com.cloud.utils.Pair; - import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; import com.cloud.utils.db.GenericDaoBase; @@ -68,7 +69,9 @@ import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; +import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.UpdateBuilder; import com.cloud.utils.exception.CloudRuntimeException; @Component @@ -122,14 +125,15 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem private SearchBuilder PublicIsoSearch; private SearchBuilder UserIsoSearch; private GenericSearchBuilder CountTemplatesByAccount; + private SearchBuilder updateStateSearch; - @Inject ResourceTagsDaoImpl _tagsDao; + @Inject ResourceTagDao _tagsDao; private String routerTmpltName; private String consoleProxyTmpltName; - protected VMTemplateDaoImpl() { + public VMTemplateDaoImpl() { } @Override @@ -378,6 +382,12 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem CountTemplatesByAccount.and("account", CountTemplatesByAccount.entity().getAccountId(), SearchCriteria.Op.EQ); CountTemplatesByAccount.and("removed", CountTemplatesByAccount.entity().getRemoved(), SearchCriteria.Op.NULL); CountTemplatesByAccount.done(); + + updateStateSearch = this.createSearchBuilder(); + updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); + updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); + updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); + updateStateSearch.done(); return result; } @@ -1073,4 +1083,39 @@ public class VMTemplateDaoImpl extends GenericDaoBase implem return templateZonePairList; } + @Override + public boolean updateState(TemplateState currentState, TemplateEvent event, + TemplateState nextState, VMTemplateVO vo, Object data) { + Long oldUpdated = vo.getUpdatedCount(); + Date oldUpdatedTime = vo.getUpdated(); + + + SearchCriteria sc = updateStateSearch.create(); + sc.setParameters("id", vo.getId()); + sc.setParameters("state", currentState); + sc.setParameters("updatedCount", vo.getUpdatedCount()); + + vo.incrUpdatedCount(); + + UpdateBuilder builder = getUpdateBuilder(vo); + builder.set(vo, "state", nextState); + builder.set(vo, "updated", new Date()); + + int rows = update((VMTemplateVO) vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + VMTemplateVO dbVol = findByIdIncludingRemoved(vo.getId()); + if (dbVol != null) { + StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); + str.append(": DB Data={id=").append(dbVol.getId()).append("; state=").append(dbVol.getState()).append("; updatecount=").append(dbVol.getUpdatedCount()).append(";updatedTime=") + .append(dbVol.getUpdated()); + str.append(": New Data={id=").append(vo.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(vo.getUpdatedCount()) + .append("; updatedTime=").append(vo.getUpdated()); + str.append(": stale Data={id=").append(vo.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated) + .append("; updatedTime=").append(oldUpdatedTime); + } else { + s_logger.debug("Unable to update objectIndatastore: id=" + vo.getId() + ", as there is no such object exists in the database anymore"); + } + } + return rows > 0; + } } diff --git a/server/src/com/cloud/storage/dao/VMTemplateHostDao.java b/server/src/com/cloud/storage/dao/VMTemplateHostDao.java index 5625e568ef0..23241cd17da 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateHostDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplateHostDao.java @@ -18,11 +18,15 @@ package com.cloud.storage.dao; import java.util.List; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; -public interface VMTemplateHostDao extends GenericDao { +public interface VMTemplateHostDao extends GenericDao, StateDao { List listByHostId(long id); List listByTemplateId(long templateId); @@ -30,6 +34,8 @@ public interface VMTemplateHostDao extends GenericDao { List listByOnlyTemplateId(long templateId); VMTemplateHostVO findByHostTemplate(long hostId, long templateId); + + VMTemplateHostVO findByTemplateId(long templateId); VMTemplateHostVO findByHostTemplate(long hostId, long templateId, boolean lock); diff --git a/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java b/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java index 4d1ac0208ac..4d19bfc0074 100755 --- a/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VMTemplateHostDaoImpl.java @@ -29,6 +29,9 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -42,7 +45,9 @@ import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.UpdateBuilder; @Component @Local(value={VMTemplateHostDao.class}) @@ -57,6 +62,7 @@ public class VMTemplateHostDaoImpl extends GenericDaoBase HostDestroyedSearch; protected final SearchBuilder TemplateStatusSearch; protected final SearchBuilder TemplateStatesSearch; + protected final SearchBuilder updateStateSearch; protected SearchBuilder ZONE_TEMPLATE_SEARCH; protected SearchBuilder LOCAL_SECONDARY_STORAGE_SEARCH; @@ -120,6 +126,12 @@ public class VMTemplateHostDaoImpl extends GenericDaoBase sc = HostTemplateSearch.create(); + sc.setParameters("template_id", templateId); + sc.setParameters("destroyed", false); + return findOneIncludingRemovedBy(sc); + } @Override public List listByTemplateStatus(long templateId, VMTemplateHostVO.Status downloadState) { @@ -367,5 +387,42 @@ public class VMTemplateHostDaoImpl extends GenericDaoBase sc = updateStateSearch.create(); + sc.setParameters("id", templateHost.getId()); + sc.setParameters("state", currentState); + sc.setParameters("updatedCount", templateHost.getUpdatedCount()); + + templateHost.incrUpdatedCount(); + + UpdateBuilder builder = getUpdateBuilder(vo); + builder.set(vo, "state", nextState); + builder.set(vo, "updated", new Date()); + + int rows = update((VMTemplateHostVO) vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + VMTemplateHostVO dbVol = findByIdIncludingRemoved(templateHost.getId()); + if (dbVol != null) { + StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); + str.append(": DB Data={id=").append(dbVol.getId()).append("; state=").append(dbVol.getState()).append("; updatecount=").append(dbVol.getUpdatedCount()).append(";updatedTime=") + .append(dbVol.getUpdated()); + str.append(": New Data={id=").append(templateHost.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(templateHost.getUpdatedCount()) + .append("; updatedTime=").append(templateHost.getUpdated()); + str.append(": stale Data={id=").append(templateHost.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated) + .append("; updatedTime=").append(oldUpdatedTime); + } else { + s_logger.debug("Unable to update objectIndatastore: id=" + templateHost.getId() + ", as there is no such object exists in the database anymore"); + } + } + return rows > 0; + } } diff --git a/server/src/com/cloud/storage/dao/VMTemplatePoolDao.java b/server/src/com/cloud/storage/dao/VMTemplatePoolDao.java index f485be7f05c..501c3ca5cc8 100644 --- a/server/src/com/cloud/storage/dao/VMTemplatePoolDao.java +++ b/server/src/com/cloud/storage/dao/VMTemplatePoolDao.java @@ -18,10 +18,14 @@ package com.cloud.storage.dao; import java.util.List; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; -public interface VMTemplatePoolDao extends GenericDao { +public interface VMTemplatePoolDao extends GenericDao, StateDao { public List listByPoolId(long id); public List listByTemplateId(long templateId); @@ -42,5 +46,4 @@ public interface VMTemplatePoolDao extends GenericDao TemplateStatusSearch; protected final SearchBuilder TemplatePoolStatusSearch; protected final SearchBuilder TemplateStatesSearch; + protected final SearchBuilder updateStateSearch; protected static final String UPDATE_TEMPLATE_HOST_REF = "UPDATE template_spool_ref SET download_state = ?, download_pct= ?, last_updated = ? " @@ -94,6 +101,12 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase sc = updateStateSearch.create(); + sc.setParameters("id", templatePool.getId()); + sc.setParameters("state", currentState); + sc.setParameters("updatedCount", templatePool.getUpdatedCount()); + + templatePool.incrUpdatedCount(); + + UpdateBuilder builder = getUpdateBuilder(vo); + builder.set(vo, "state", nextState); + builder.set(vo, "updated", new Date()); + + int rows = update((VMTemplateStoragePoolVO) vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + VMTemplateStoragePoolVO dbVol = findByIdIncludingRemoved(templatePool.getId()); + if (dbVol != null) { + StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); + str.append(": DB Data={id=").append(dbVol.getId()).append("; state=").append(dbVol.getState()).append("; updatecount=").append(dbVol.getUpdatedCount()).append(";updatedTime=") + .append(dbVol.getUpdated()); + str.append(": New Data={id=").append(templatePool.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(templatePool.getUpdatedCount()) + .append("; updatedTime=").append(templatePool.getUpdated()); + str.append(": stale Data={id=").append(templatePool.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated) + .append("; updatedTime=").append(oldUpdatedTime); + } else { + s_logger.debug("Unable to update objectIndatastore: id=" + templatePool.getId() + ", as there is no such object exists in the database anymore"); + } + } + return rows > 0; + } + } diff --git a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java index a189d00fead..ca3b82a06c1 100755 --- a/server/src/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeDaoImpl.java @@ -39,7 +39,6 @@ import com.cloud.storage.Volume.Type; import com.cloud.storage.VolumeVO; import com.cloud.tags.dao.ResourceTagsDaoImpl; import com.cloud.utils.Pair; - import com.cloud.utils.db.DB; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.GenericSearchBuilder; @@ -250,7 +249,7 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol } } - protected VolumeDaoImpl() { + public VolumeDaoImpl() { AllFieldsSearch = createSearchBuilder(); AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ); AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ); diff --git a/server/src/com/cloud/storage/dao/VolumeHostDao.java b/server/src/com/cloud/storage/dao/VolumeHostDao.java index 6ba82370608..39dda12345b 100755 --- a/server/src/com/cloud/storage/dao/VolumeHostDao.java +++ b/server/src/com/cloud/storage/dao/VolumeHostDao.java @@ -18,10 +18,14 @@ package com.cloud.storage.dao; import java.util.List; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; + import com.cloud.storage.VolumeHostVO; import com.cloud.utils.db.GenericDao; +import com.cloud.utils.fsm.StateDao; -public interface VolumeHostDao extends GenericDao { +public interface VolumeHostDao extends GenericDao, StateDao{ VolumeHostVO findByHostVolume(long hostId, long volumeId); diff --git a/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java b/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java index 57f2153f10b..2fd39e6eeca 100755 --- a/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java +++ b/server/src/com/cloud/storage/dao/VolumeHostDaoImpl.java @@ -16,28 +16,35 @@ // under the License. package com.cloud.storage.dao; +import java.util.Date; import java.util.List; import javax.ejb.Local; +import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State; +import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.storage.VolumeHostVO; import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.UpdateBuilder; @Component @Local(value={VolumeHostDao.class}) public class VolumeHostDaoImpl extends GenericDaoBase implements VolumeHostDao { - + private static final Logger s_logger = Logger.getLogger(VolumeHostDaoImpl.class); protected final SearchBuilder HostVolumeSearch; protected final SearchBuilder ZoneVolumeSearch; protected final SearchBuilder VolumeSearch; protected final SearchBuilder HostSearch; protected final SearchBuilder HostDestroyedSearch; - - VolumeHostDaoImpl(){ + protected final SearchBuilder updateStateSearch; + public VolumeHostDaoImpl(){ HostVolumeSearch = createSearchBuilder(); HostVolumeSearch.and("host_id", HostVolumeSearch.entity().getHostId(), SearchCriteria.Op.EQ); HostVolumeSearch.and("volume_id", HostVolumeSearch.entity().getVolumeId(), SearchCriteria.Op.EQ); @@ -64,6 +71,12 @@ public class VolumeHostDaoImpl extends GenericDaoBase implem HostDestroyedSearch.and("host_id", HostDestroyedSearch.entity().getHostId(), SearchCriteria.Op.EQ); HostDestroyedSearch.and("destroyed", HostDestroyedSearch.entity().getDestroyed(), SearchCriteria.Op.EQ); HostDestroyedSearch.done(); + + updateStateSearch = this.createSearchBuilder(); + updateStateSearch.and("id", updateStateSearch.entity().getId(), Op.EQ); + updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ); + updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ); + updateStateSearch.done(); } @@ -112,4 +125,41 @@ public class VolumeHostDaoImpl extends GenericDaoBase implem return listIncludingRemovedBy(sc); } + @Override + public boolean updateState(State currentState, Event event, + State nextState, DataObjectInStore vo, Object data) { + VolumeHostVO volHost = (VolumeHostVO) vo; + Long oldUpdated = volHost.getUpdatedCount(); + Date oldUpdatedTime = volHost.getUpdated(); + + + SearchCriteria sc = updateStateSearch.create(); + sc.setParameters("id", volHost.getId()); + sc.setParameters("state", currentState); + sc.setParameters("updatedCount", volHost.getUpdatedCount()); + + volHost.incrUpdatedCount(); + + UpdateBuilder builder = getUpdateBuilder(vo); + builder.set(vo, "state", nextState); + builder.set(vo, "updated", new Date()); + + int rows = update((VolumeHostVO) vo, sc); + if (rows == 0 && s_logger.isDebugEnabled()) { + VolumeHostVO dbVol = findByIdIncludingRemoved(volHost.getId()); + if (dbVol != null) { + StringBuilder str = new StringBuilder("Unable to update ").append(vo.toString()); + str.append(": DB Data={id=").append(dbVol.getId()).append("; state=").append(dbVol.getState()).append("; updatecount=").append(dbVol.getUpdatedCount()).append(";updatedTime=") + .append(dbVol.getUpdated()); + str.append(": New Data={id=").append(volHost.getId()).append("; state=").append(nextState).append("; event=").append(event).append("; updatecount=").append(volHost.getUpdatedCount()) + .append("; updatedTime=").append(volHost.getUpdated()); + str.append(": stale Data={id=").append(volHost.getId()).append("; state=").append(currentState).append("; event=").append(event).append("; updatecount=").append(oldUpdated) + .append("; updatedTime=").append(oldUpdatedTime); + } else { + s_logger.debug("Unable to update objectIndatastore: id=" + volHost.getId() + ", as there is no such object exists in the database anymore"); + } + } + return rows > 0; + } + } diff --git a/server/src/com/cloud/storage/download/DownloadListener.java b/server/src/com/cloud/storage/download/DownloadListener.java index 036d40ad015..d0b186831c8 100755 --- a/server/src/com/cloud/storage/download/DownloadListener.java +++ b/server/src/com/cloud/storage/download/DownloadListener.java @@ -46,11 +46,11 @@ import com.cloud.host.HostVO; import com.cloud.storage.Storage; import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VolumeHostVO; import com.cloud.storage.VolumeVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.Volume.Event; -import com.cloud.storage.VMTemplateVO; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VolumeDao; diff --git a/server/src/com/cloud/storage/download/DownloadMonitor.java b/server/src/com/cloud/storage/download/DownloadMonitor.java index 30ec3b1623b..897befa250b 100644 --- a/server/src/com/cloud/storage/download/DownloadMonitor.java +++ b/server/src/com/cloud/storage/download/DownloadMonitor.java @@ -18,6 +18,7 @@ package com.cloud.storage.download; import java.util.Map; + import com.cloud.exception.StorageUnavailableException; import com.cloud.host.HostVO; import com.cloud.storage.VMTemplateVO; diff --git a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java index 6d3cf2a101b..e12bc320282 100755 --- a/server/src/com/cloud/storage/download/DownloadMonitorImpl.java +++ b/server/src/com/cloud/storage/download/DownloadMonitorImpl.java @@ -37,10 +37,21 @@ import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; import com.cloud.agent.api.Answer; import com.cloud.agent.api.Command; -import com.cloud.agent.api.storage.*; + +import com.cloud.agent.api.storage.DeleteTemplateCommand; +import com.cloud.agent.api.storage.DeleteVolumeCommand; +import com.cloud.agent.api.storage.DownloadCommand; + import com.cloud.agent.api.storage.DownloadCommand.Proxy; import com.cloud.agent.api.storage.DownloadCommand.ResourceType; import com.cloud.agent.api.storage.DownloadProgressCommand.RequestType; + +import com.cloud.agent.api.storage.DownloadProgressCommand; +import com.cloud.agent.api.storage.ListTemplateAnswer; +import com.cloud.agent.api.storage.ListTemplateCommand; +import com.cloud.agent.api.storage.ListVolumeAnswer; +import com.cloud.agent.api.storage.ListVolumeCommand; + import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; import com.cloud.configuration.Config; @@ -50,6 +61,7 @@ import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; +import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.StorageUnavailableException; @@ -59,13 +71,31 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.resource.ResourceManager; import com.cloud.storage.Storage.ImageFormat; -import com.cloud.storage.*; + +import com.cloud.storage.StorageManager; +import com.cloud.storage.SwiftVO; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.dao.*; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.SwiftDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateSwiftDao; +import com.cloud.storage.dao.VMTemplateZoneDao; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeHostDao; + import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.storage.template.TemplateConstants; import com.cloud.storage.template.TemplateInfo; +import com.cloud.template.TemplateManager; import com.cloud.user.Account; import com.cloud.user.ResourceLimitService; import com.cloud.utils.component.ManagerBase; @@ -80,6 +110,7 @@ import com.cloud.vm.SecondaryStorageVmVO; import com.cloud.vm.UserVmManager; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.SecondaryStorageVmDao; + import edu.emory.mathcs.backport.java.util.Collections; @@ -124,6 +155,14 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor ConfigurationDao _configDao; @Inject UserVmManager _vmMgr; + + @Inject TemplateManager templateMgr; + + + @Inject + private UsageEventDao _usageEventDao; + + @Inject private ClusterDao _clusterDao; @Inject @@ -233,7 +272,7 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor if(destTmpltHost != null) { start(); - String sourceChecksum = _vmMgr.getChecksum(srcTmpltHost.getHostId(), srcTmpltHost.getInstallPath()); + String sourceChecksum = this.templateMgr.getChecksum(srcTmpltHost.getHostId(), srcTmpltHost.getInstallPath()); DownloadCommand dcmd = new DownloadCommand(destServer.getStorageUrl(), url, template, TemplateConstants.DEFAULT_HTTP_AUTH_USER, _copyAuthPasswd, maxTemplateSizeInBytes); dcmd.setProxy(getHttpProxy()); @@ -473,6 +512,8 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor long size = -1; if(vmTemplateHost!=null){ size = vmTemplateHost.getPhysicalSize(); + template.setSize(size); + this._templateDao.update(template.getId(), template); } else{ s_logger.warn("Failed to get size for template" + template.getName()); @@ -510,6 +551,8 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor long size = -1; if(volumeHost!=null){ size = volumeHost.getPhysicalSize(); + volume.setSize(size); + this._volumeDao.update(volume.getId(), volume); } else{ s_logger.warn("Failed to get size for volume" + volume.getName()); @@ -925,7 +968,7 @@ public class DownloadMonitorImpl extends ManagerBase implements DownloadMonitor s_logger.debug("Found " +templateHostRefList.size()+ " templates with no checksum. Will ask for computation"); for(VMTemplateHostVO templateHostRef : templateHostRefList){ s_logger.debug("Getting checksum for template - " + templateHostRef.getTemplateId()); - String checksum = _vmMgr.getChecksum(hostId, templateHostRef.getInstallPath()); + String checksum = this.templateMgr.getChecksum(hostId, templateHostRef.getInstallPath()); VMTemplateVO template = _templateDao.findById(templateHostRef.getTemplateId()); s_logger.debug("Setting checksum " +checksum+ " for template - " + template.getName()); template.setChecksum(checksum); diff --git a/server/src/com/cloud/storage/listener/StoragePoolMonitor.java b/server/src/com/cloud/storage/listener/StoragePoolMonitor.java index e848a8727a0..df2df7b5267 100755 --- a/server/src/com/cloud/storage/listener/StoragePoolMonitor.java +++ b/server/src/com/cloud/storage/listener/StoragePoolMonitor.java @@ -20,6 +20,8 @@ import java.util.List; import javax.inject.Inject; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import com.cloud.agent.Listener; @@ -37,17 +39,15 @@ import com.cloud.storage.OCFS2Manager; import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.StorageManagerImpl; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.dao.StoragePoolDao; public class StoragePoolMonitor implements Listener { private static final Logger s_logger = Logger.getLogger(StoragePoolMonitor.class); private final StorageManagerImpl _storageManager; - private final StoragePoolDao _poolDao; + private final PrimaryDataStoreDao _poolDao; @Inject OCFS2Manager _ocfs2Mgr; - public StoragePoolMonitor(StorageManagerImpl mgr, StoragePoolDao poolDao) { + public StoragePoolMonitor(StorageManagerImpl mgr, PrimaryDataStoreDao poolDao) { this._storageManager = mgr; this._poolDao = poolDao; @@ -80,7 +80,7 @@ public class StoragePoolMonitor implements Listener { if (pool.getStatus() != StoragePoolStatus.Up) { continue; } - if (!pool.getPoolType().isShared()) { + if (!pool.isShared()) { continue; } @@ -91,8 +91,8 @@ public class StoragePoolMonitor implements Listener { Long hostId = host.getId(); s_logger.debug("Host " + hostId + " connected, sending down storage pool information ..."); try { - _storageManager.connectHostToSharedPool(hostId, pool); - _storageManager.createCapacityEntry(pool); + _storageManager.connectHostToSharedPool(hostId, pool.getId()); + _storageManager.createCapacityEntry(pool.getId()); } catch (Exception e) { s_logger.warn("Unable to connect host " + hostId + " to pool " + pool + " due to " + e.toString(), e); } diff --git a/server/src/com/cloud/storage/resource/DummySecondaryStorageResource.java b/server/src/com/cloud/storage/resource/DummySecondaryStorageResource.java index 877b97c185d..8f25514180c 100644 --- a/server/src/com/cloud/storage/resource/DummySecondaryStorageResource.java +++ b/server/src/com/cloud/storage/resource/DummySecondaryStorageResource.java @@ -46,8 +46,8 @@ import com.cloud.host.Host.Type; import com.cloud.resource.ServerResource; import com.cloud.resource.ServerResourceBase; import com.cloud.storage.Storage; -import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Storage.StoragePoolType; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.template.TemplateConstants; import com.cloud.storage.template.TemplateInfo; diff --git a/server/src/com/cloud/storage/s3/S3Manager.java b/server/src/com/cloud/storage/s3/S3Manager.java index 0e47d7273d6..0f74e431376 100644 --- a/server/src/com/cloud/storage/s3/S3Manager.java +++ b/server/src/com/cloud/storage/s3/S3Manager.java @@ -23,6 +23,7 @@ import java.util.List; import com.cloud.agent.api.to.S3TO; import org.apache.cloudstack.api.command.admin.storage.AddS3Cmd; import org.apache.cloudstack.api.command.admin.storage.ListS3sCmd; + import com.cloud.dc.DataCenterVO; import com.cloud.exception.DiscoveryException; import com.cloud.storage.S3; diff --git a/server/src/com/cloud/storage/s3/S3ManagerImpl.java b/server/src/com/cloud/storage/s3/S3ManagerImpl.java index 13fe2b76ed1..61e5573394d 100644 --- a/server/src/com/cloud/storage/s3/S3ManagerImpl.java +++ b/server/src/com/cloud/storage/s3/S3ManagerImpl.java @@ -68,8 +68,8 @@ import com.cloud.storage.S3; import com.cloud.storage.S3VO; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateS3VO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.dao.S3Dao; import com.cloud.storage.dao.VMTemplateDao; diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index fca89dcb1cb..46ac7af59f8 100755 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -98,8 +98,8 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage; import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.VMTemplateDao; diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java index e06da75580c..6b48b8237ec 100755 --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java @@ -28,12 +28,25 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd; +import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd; +import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd; import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.cloud.agent.AgentManager; -import com.cloud.agent.api.*; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.BackupSnapshotAnswer; +import com.cloud.agent.api.BackupSnapshotCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.DeleteSnapshotBackupCommand; +import com.cloud.agent.api.DeleteSnapshotsDirCommand; +import com.cloud.agent.api.DownloadSnapshotFromS3Command; +import com.cloud.agent.api.ManageSnapshotAnswer; +import com.cloud.agent.api.ManageSnapshotCommand; +import com.cloud.agent.api.downloadSnapshotFromSwiftCommand; import com.cloud.agent.api.to.S3TO; import com.cloud.agent.api.to.SwiftTO; import com.cloud.alert.AlertManager; @@ -46,7 +59,11 @@ import com.cloud.dc.DataCenter; import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.domain.dao.DomainDao; -import com.cloud.event.*; +import com.cloud.event.ActionEvent; +import com.cloud.event.ActionEventUtils; +import com.cloud.event.EventTypes; +import com.cloud.event.EventVO; +import com.cloud.event.UsageEventUtils; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; @@ -60,25 +77,46 @@ import com.cloud.org.Grouping; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.resource.ResourceManager; import com.cloud.server.ResourceTag.TaggedResourceType; -import com.cloud.storage.*; +import com.cloud.storage.Snapshot; import com.cloud.storage.Snapshot.Type; +import com.cloud.storage.SnapshotPolicyVO; +import com.cloud.storage.SnapshotScheduleVO; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; import com.cloud.storage.Storage.StoragePoolType; -import com.cloud.storage.dao.*; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.DiskOfferingDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.SnapshotPolicyDao; +import com.cloud.storage.dao.SnapshotScheduleDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.listener.SnapshotStateListener; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.tags.ResourceTagVO; import com.cloud.tags.dao.ResourceTagDao; -import com.cloud.user.*; +import com.cloud.template.TemplateManager; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountVO; +import com.cloud.user.DomainManager; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.User; +import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.utils.DateUtil; import com.cloud.utils.DateUtil.IntervalType; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; - -import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.db.DB; import com.cloud.utils.db.Filter; @@ -86,7 +124,6 @@ import com.cloud.utils.db.JoinBuilder; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.*; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.NoTransitionException; import com.cloud.utils.fsm.StateMachine2; @@ -95,6 +132,7 @@ import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.dao.UserVmDao; + import org.apache.cloudstack.api.command.user.snapshot.CreateSnapshotPolicyCmd; import org.apache.cloudstack.api.command.user.snapshot.DeleteSnapshotPoliciesCmd; import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotPoliciesCmd; @@ -105,9 +143,9 @@ import javax.ejb.Local; import javax.naming.ConfigurationException; import java.util.*; import com.cloud.vm.snapshot.VMSnapshot; -import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; + @Component @Local(value = { SnapshotManager.class, SnapshotService.class }) public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, SnapshotService { @@ -170,9 +208,16 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, private ResourceTagDao _resourceTagDao; @Inject private ConfigurationDao _configDao; + @Inject private VMSnapshotDao _vmSnapshotDao; String _name; + + @Inject TemplateManager templateMgr; + @Inject VolumeManager volumeMgr; + @Inject DataStoreManager dataStoreMgr; + + private int _totalRetries; private int _pauseInterval; private int _deltaSnapshotMax; @@ -186,8 +231,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, protected Answer sendToPool(Volume vol, Command cmd) { - StoragePool pool = _storagePoolDao.findById(vol.getPoolId()); - + StoragePool pool = (StoragePool)dataStoreMgr.getPrimaryDataStore(vol.getPoolId()); long[] hostIdsToTryFirst = null; Long vmHostId = getHostIdForSnapshotOperation(vol); @@ -252,7 +296,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, } // Send a ManageSnapshotCommand to the agent - String vmName = _storageMgr.getVmNameOnVolume(volume); + String vmName = this.volumeMgr.getVmNameOnVolume(volume); long volumeId = volume.getId(); long preId = _snapshotDao.getLastSnapshot(volumeId, snapshotId); @@ -264,8 +308,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, preSnapshotPath = preSnapshotVO.getPath(); } } - StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId()); - + StoragePool srcPool = (StoragePool)dataStoreMgr.getPrimaryDataStore(volume.getPoolId()); // RBD volumes do not support snapshotting in the way CloudStack does it. // For now we leave the snapshot feature disabled for RBD volumes if (srcPool.getPoolType() == StoragePoolType.RBD) { @@ -414,12 +457,12 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, if(activeSnapshots.size() > 1) throw new CloudRuntimeException("There is other active snapshot tasks on the instance to which the volume is attached, please try again later"); } - List activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(), + /*List activeVMSnapshots = _vmSnapshotDao.listByInstanceId(userVm.getId(), VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging); if (activeVMSnapshots.size() > 0) { throw new CloudRuntimeException( "There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later"); - } + } */ } } @@ -530,7 +573,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, VolumeVO volume = _volsDao.findById(volumeId); Long dcId = volume.getDataCenterId(); Long accountId = volume.getAccountId(); - HostVO secHost = _storageMgr.getSecondaryStorageHost(dcId); + HostVO secHost = this.templateMgr.getSecondaryStorageHost(dcId); String secondaryStoragePoolUrl = secHost.getStorageUrl(); Long swiftId = ss.getSwiftId(); @@ -581,7 +624,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, final VolumeVO volume = _volsDao.findById(snapshot.getVolumeId()); final Long zoneId = volume.getDataCenterId(); - final HostVO secHost = _storageMgr.getSecondaryStorageHost(zoneId); + final HostVO secHost = this.templateMgr.getSecondaryStorageHost(zoneId); final S3TO s3 = _s3Mgr.getS3TO(snapshot.getS3Id()); final List backupUuids = determineBackupUuids(snapshot); @@ -662,9 +705,9 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, prevSnapshotUuid = prevSnapshot.getPath(); } } - boolean isVolumeInactive = _storageMgr.volumeInactive(volume); - String vmName = _storageMgr.getVmNameOnVolume(volume); - StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId()); + boolean isVolumeInactive = this.volumeMgr.volumeInactive(volume); + String vmName = this.volumeMgr.getVmNameOnVolume(volume); + StoragePool srcPool = (StoragePool)dataStoreMgr.getPrimaryDataStore(volume.getPoolId()); BackupSnapshotCommand backupSnapshotCommand = new BackupSnapshotCommand(secondaryStoragePoolUrl, dcId, accountId, volumeId, snapshot.getId(), volume.getPath(), srcPool, snapshotUuid, snapshot.getName(), prevSnapshotUuid, prevBackupUuid, isVolumeInactive, vmName, _backupsnapshotwait); @@ -735,7 +778,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, if ( id != null) { return _hostDao.findById(id); } - return _storageMgr.getSecondaryStorageHost(dcId); + return this.templateMgr.getSecondaryStorageHost(dcId); } private Long getSnapshotUserId() { @@ -884,7 +927,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager, secHost = _hostDao.findById(snapshot.getSecHostId()); } else { Long dcId = snapshot.getDataCenterId(); - secHost = _storageMgr.getSecondaryStorageHost(dcId); + secHost = this.templateMgr.getSecondaryStorageHost(dcId); } return secHost; } diff --git a/server/src/com/cloud/storage/upload/UploadMonitor.java b/server/src/com/cloud/storage/upload/UploadMonitor.java index aada1f43c41..1c3590e91e2 100755 --- a/server/src/com/cloud/storage/upload/UploadMonitor.java +++ b/server/src/com/cloud/storage/upload/UploadMonitor.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.storage.upload; + import com.cloud.async.AsyncJobManager; import com.cloud.host.HostVO; import com.cloud.storage.Upload.Mode; diff --git a/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java b/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java index 97639564967..a8e1393d6da 100644 --- a/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java +++ b/server/src/com/cloud/tags/dao/ResourceTagsDaoImpl.java @@ -17,6 +17,7 @@ package com.cloud.tags.dao; import java.util.List; + import javax.ejb.Local; import org.springframework.stereotype.Component; diff --git a/server/src/com/cloud/template/HyervisorTemplateAdapter.java b/server/src/com/cloud/template/HyervisorTemplateAdapter.java index fe6bc2a86f0..fa72e75612f 100755 --- a/server/src/com/cloud/template/HyervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HyervisorTemplateAdapter.java @@ -22,12 +22,21 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.util.List; +import java.util.concurrent.ExecutionException; import javax.ejb.Local; import javax.inject.Inject; import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; +import org.apache.cloudstack.framework.async.AsyncCallFuture; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; @@ -43,10 +52,10 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.host.HostVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.TemplateProfile; +import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.secondary.SecondaryStorageVmManager; @@ -70,11 +79,18 @@ public class HyervisorTemplateAdapter extends TemplateAdapterBase implements Tem @Inject DownloadMonitor _downloadMonitor; @Inject SecondaryStorageVmManager _ssvmMgr; @Inject AgentManager _agentMgr; + @Inject DataStoreManager storeMgr; + @Inject ImageService imageService; + @Inject ImageDataFactory imageFactory; + @Inject TemplateManager templateMgr; + @Override public String getName() { return TemplateAdapterType.Hypervisor.getName(); } + + private String validateUrl(String url) { try { @@ -155,7 +171,18 @@ public class HyervisorTemplateAdapter extends TemplateAdapterBase implements Tem throw new CloudRuntimeException("Unable to persist the template " + profile.getTemplate()); } - _downloadMonitor.downloadTemplateToStorage(template, profile.getZoneId()); + DataStore imageStore = this.templateMgr.getImageStore(profile.getImageStoreUuid(), profile.getZoneId()); + + AsyncCallFuture future = this.imageService.createTemplateAsync(this.imageFactory.getTemplate(template.getId()), imageStore); + try { + future.get(); + } catch (InterruptedException e) { + s_logger.debug("create template Failed", e); + throw new CloudRuntimeException("create template Failed", e); + } catch (ExecutionException e) { + s_logger.debug("create template Failed", e); + throw new CloudRuntimeException("create template Failed", e); + } _resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template); return template; diff --git a/server/src/com/cloud/template/TemplateAdapter.java b/server/src/com/cloud/template/TemplateAdapter.java index 19cfef039de..1f8f491cb25 100755 --- a/server/src/com/cloud/template/TemplateAdapter.java +++ b/server/src/com/cloud/template/TemplateAdapter.java @@ -22,6 +22,7 @@ import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; + import com.cloud.exception.ResourceAllocationException; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.storage.TemplateProfile; @@ -65,5 +66,5 @@ public interface TemplateAdapter extends Adapter { public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, - String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled) throws ResourceAllocationException; + String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid) throws ResourceAllocationException; } diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index fa677acdc5c..c5074ad0a8a 100755 --- a/server/src/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/com/cloud/template/TemplateAdapterBase.java @@ -22,14 +22,17 @@ import java.util.Map; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; import org.apache.log4j.Logger; -import org.apache.cloudstack.api.ApiConstants; import com.cloud.api.ApiDBUtils; -import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.dao.ConfigurationDao; import com.cloud.dc.DataCenterVO; @@ -43,10 +46,10 @@ import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.org.Grouping; import com.cloud.storage.GuestOS; -import com.cloud.storage.TemplateProfile; +import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; -import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.TemplateProfile; import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateHostDao; import com.cloud.storage.dao.VMTemplateZoneDao; @@ -76,6 +79,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat protected @Inject UsageEventDao _usageEventDao; protected @Inject HostDao _hostDao; protected @Inject ResourceLimitService _resourceLimitMgr; + protected @Inject DataStoreManager storeMgr; @Override public boolean stop() { @@ -94,16 +98,26 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, String accountName, Long domainId, String chksum, Boolean bootable, Map details) throws ResourceAllocationException { return prepare(isIso, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, featured, isExtractable, format, guestOSId, zoneId, hypervisorType, - chksum, bootable, null, null, details, false); + chksum, bootable, null, null, details, false, null); } public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url, Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, Long zoneId, HypervisorType hypervisorType, - String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled) throws ResourceAllocationException { + String chksum, Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshkeyEnabled, + String imageStoreUuid) throws ResourceAllocationException { //Long accountId = null; // parameters verification + String storeUuid = imageStoreUuid; + if (storeUuid != null) { + DataStore store = this.storeMgr.getDataStore(storeUuid, DataStoreRole.Image); + if (store == null) { + throw new InvalidParameterValueException("invalide image store uuid" + storeUuid); + } + + } + if (isPublic == null) { isPublic = Boolean.FALSE; } @@ -200,7 +214,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat Long id = _tmpltDao.getNextInSequence(Long.class, "id"); UserContext.current().setEventDetails("Id: " +id+ " name: " + name); return new TemplateProfile(id, userId, name, displayText, bits, passwordEnabled, requiresHVM, url, isPublic, - featured, isExtractable, imgfmt, guestOSId, zoneId, hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details, sshkeyEnabled); + featured, isExtractable, imgfmt, guestOSId, zoneId, hypervisorType, templateOwner.getAccountName(), templateOwner.getDomainId(), templateOwner.getAccountId(), chksum, bootable, templateTag, details, sshkeyEnabled, imageStoreUuid); } @Override @@ -210,10 +224,12 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId()); _accountMgr.checkAccess(caller, null, true, owner); + + return prepare(false, UserContext.current().getCallerUserId(), cmd.getTemplateName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(), cmd.getRequiresHvm(), cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), cmd.getZoneId(), HypervisorType.getType(cmd.getHypervisor()), - cmd.getChecksum(), true, cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled()); + cmd.getChecksum(), true, cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), cmd.getImageStoreUuid()); } public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException { @@ -224,7 +240,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat return prepare(true, UserContext.current().getCallerUserId(), cmd.getIsoName(), cmd.getDisplayText(), 64, false, true, cmd.getUrl(), cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), ImageFormat.ISO.toString(), cmd.getOsTypeId(), - cmd.getZoneId(), HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null, owner, null, false); + cmd.getZoneId(), HypervisorType.None, cmd.getChecksum(), cmd.isBootable(), null, owner, null, false, cmd.getImageStoreUuid()); } protected VMTemplateVO persistTemplate(TemplateProfile profile) { @@ -234,6 +250,7 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat profile.getBits(), profile.getAccountId(), profile.getCheckSum(), profile.getDisplayText(), profile.getPasswordEnabled(), profile.getGuestOsId(), profile.getBootable(), profile.getHypervisorType(), profile.getTemplateTag(), profile.getDetails(), profile.getSshKeyEnabled()); + if (zoneId == null || zoneId.longValue() == -1) { List dcs = _dcDao.listAll(); diff --git a/server/src/com/cloud/template/TemplateManager.java b/server/src/com/cloud/template/TemplateManager.java index ad145a911bf..1b054614b20 100755 --- a/server/src/com/cloud/template/TemplateManager.java +++ b/server/src/com/cloud/template/TemplateManager.java @@ -18,16 +18,19 @@ package com.cloud.template; import java.util.List; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; + import com.cloud.dc.DataCenterVO; import com.cloud.exception.InternalErrorException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; import com.cloud.host.HostVO; import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateHostVO; import com.cloud.storage.VMTemplateStoragePoolVO; import com.cloud.storage.VMTemplateVO; +import com.cloud.utils.Pair; /** * TemplateManager manages the templates stored on secondary storage. It is responsible for creating private/public templates. @@ -91,4 +94,27 @@ public interface TemplateManager extends TemplateService{ VMTemplateHostVO prepareISOForCreate(VMTemplateVO template, StoragePool pool); + + VMTemplateHostVO findVmTemplateHost(long templateId, + StoragePool pool); + + Pair getAbsoluteIsoPath(long templateId, long dataCenterId); + + String getSecondaryStorageURL(long zoneId); + + HostVO getSecondaryStorageHost(long zoneId, long tmpltId); + + VMTemplateHostVO getTemplateHostRef(long zoneId, long tmpltId, + boolean readyOnly); + + HostVO getSecondaryStorageHost(long zoneId); + + List getSecondaryStorageHosts(long zoneId); + + Long getTemplateSize(long templateId, long zoneId); + + DataStore getImageStore(String storeUuid, long zoneId); + + String getChecksum(Long hostId, String templatePath); + } diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java index f9cf277842d..736f712b9c9 100755 --- a/server/src/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/com/cloud/template/TemplateManagerImpl.java @@ -26,6 +26,9 @@ import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.UUID; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -35,22 +38,50 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd; -import org.apache.cloudstack.api.command.user.iso.*; -import org.apache.cloudstack.api.command.user.template.*; +import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; +import org.apache.cloudstack.api.command.user.iso.ExtractIsoCmd; +import org.apache.cloudstack.api.command.user.iso.ListIsoPermissionsCmd; +import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd; +import org.apache.cloudstack.api.command.user.iso.UpdateIsoPermissionsCmd; +import org.apache.cloudstack.api.command.user.template.CopyTemplateCmd; +import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; +import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd; +import org.apache.cloudstack.api.command.user.template.ListTemplatePermissionsCmd; +import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; +import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd; +import org.apache.cloudstack.engine.subsystem.api.storage.CommandResult; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreRole; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.ImageService; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory; +import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo; +import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope; +import org.apache.cloudstack.framework.async.AsyncCallFuture; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import org.apache.cloudstack.acl.SecurityChecker.AccessType; import com.cloud.agent.AgentManager; import com.cloud.agent.api.Answer; +import com.cloud.agent.api.AttachIsoCommand; +import com.cloud.agent.api.ComputeChecksumCommand; import com.cloud.agent.api.downloadTemplateFromSwiftToSecondaryStorageCommand; +import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand; import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.to.SwiftTO; -import com.cloud.agent.api.uploadTemplateToSwiftFromSecondaryStorageCommand; + +import com.cloud.api.ApiDBUtils; import com.cloud.async.AsyncJobManager; import com.cloud.async.AsyncJobVO; import com.cloud.configuration.Config; @@ -64,12 +95,14 @@ import com.cloud.domain.dao.DomainDao; import com.cloud.event.ActionEvent; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; +import com.cloud.event.UsageEventVO; import com.cloud.event.dao.EventDao; import com.cloud.event.dao.UsageEventDao; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.StorageUnavailableException; +import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor; @@ -77,34 +110,72 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.HypervisorGuruManager; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; -import com.cloud.storage.*; + +import com.cloud.resource.ResourceManager; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.LaunchPermissionVO; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; + import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.TemplateProfile; import com.cloud.storage.Upload; import com.cloud.storage.Upload.Type; + +import com.cloud.storage.UploadVO; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateS3VO; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.dao.*; +import com.cloud.storage.VMTemplateSwiftVO; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeManager; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.GuestOSDao; +import com.cloud.storage.dao.LaunchPermissionDao; +import com.cloud.storage.dao.SnapshotDao; +import com.cloud.storage.dao.StoragePoolDao; +import com.cloud.storage.dao.StoragePoolHostDao; +import com.cloud.storage.dao.UploadDao; +import com.cloud.storage.dao.VMTemplateDao; +import com.cloud.storage.dao.VMTemplateDetailsDao; +import com.cloud.storage.dao.VMTemplateHostDao; +import com.cloud.storage.dao.VMTemplatePoolDao; +import com.cloud.storage.dao.VMTemplateS3Dao; +import com.cloud.storage.dao.VMTemplateSwiftDao; +import com.cloud.storage.dao.VMTemplateZoneDao; +import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.download.DownloadMonitor; import com.cloud.storage.s3.S3Manager; import com.cloud.storage.secondary.SecondaryStorageVmManager; import com.cloud.storage.swift.SwiftManager; import com.cloud.storage.upload.UploadMonitor; import com.cloud.template.TemplateAdapter.TemplateAdapterType; -import com.cloud.user.*; + +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.user.AccountService; +import com.cloud.user.AccountVO; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.User; +import com.cloud.user.UserContext; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.UserAccountDao; import com.cloud.user.dao.UserDao; import com.cloud.uservm.UserVm; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Pair; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.ManagerBase; - import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.db.*; import com.cloud.utils.exception.CloudRuntimeException; @@ -123,6 +194,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Inject VMTemplateHostDao _tmpltHostDao; @Inject VMTemplatePoolDao _tmpltPoolDao; @Inject VMTemplateZoneDao _tmpltZoneDao; + @Inject + protected VMTemplateDetailsDao _templateDetailsDao; @Inject VMInstanceDao _vmInstanceDao; @Inject StoragePoolDao _poolDao; @Inject StoragePoolHostDao _poolHostDao; @@ -153,6 +226,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, ClusterDao _clusterDao; @Inject DomainDao _domainDao; @Inject UploadDao _uploadDao; + @Inject + protected GuestOSDao _guestOSDao; long _routerTemplateId = -1; @Inject StorageManager _storageMgr; @Inject AsyncJobManager _asyncMgr; @@ -164,6 +239,20 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Inject SecondaryStorageVmManager _ssvmMgr; @Inject LaunchPermissionDao _launchPermissionDao; @Inject ProjectManager _projectMgr; + @Inject + VolumeDataFactory volFactory; + @Inject + ImageDataFactory tmplFactory; + @Inject + SnapshotDataFactory snapshotFactory; + @Inject + ImageService imageSvr; + @Inject + DataStoreManager dataStoreMgr; + @Inject + protected ResourceManager _resourceMgr; + @Inject VolumeManager volumeMgr; + @Inject VMTemplateHostDao templateHostDao; int _primaryStorageDownloadWait; @@ -217,7 +306,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, if(!_accountService.isRootAdmin(account.getType())){ throw new PermissionDeniedException("Parameter templatetag can only be specified by a Root Admin, permission denied"); } - } + } + TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor())); TemplateProfile profile = adapter.prepare(cmd); VMTemplateVO template = adapter.create(profile); @@ -228,6 +318,22 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new CloudRuntimeException("Failed to create a template"); } } + + @Override + public DataStore getImageStore(String storeUuid, long zoneId) { + DataStore imageStore = null; + if (storeUuid != null) { + imageStore = this.dataStoreMgr.getDataStore(storeUuid, DataStoreRole.Image); + } else { + List stores = this.dataStoreMgr.getImageStores(new ZoneScope(zoneId)); + if (stores.size() > 1) { + throw new CloudRuntimeException("multiple image stores, don't know which one to use"); + } + imageStore = stores.get(0); + } + + return imageStore; + } @Override @ActionEvent(eventType = EventTypes.EVENT_ISO_EXTRACT, eventDescription = "extracting ISO", async = true) @@ -330,7 +436,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, _accountMgr.checkAccess(caller, AccessType.ModifyEntry, true, template); - List sservers = _storageMgr.getSecondaryStorageHosts(zoneId); + List sservers = getSecondaryStorageHosts(zoneId); VMTemplateHostVO tmpltHostRef = null; if (sservers != null) { @@ -425,7 +531,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, private void reallyRun() { s_logger.info("Start to preload template " + template.getId() + " into primary storage " + pool.getId()); - prepareTemplateForCreate(template, pool); + StoragePool pol = (StoragePool)dataStoreMgr.getPrimaryDataStore(pool.getId()); + prepareTemplateForCreate(template, pol); s_logger.info("End of preloading template " + template.getId() + " into primary storage " + pool.getId()); } }); @@ -539,8 +646,8 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } @Override @DB - public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO template, StoragePool pool) { - template = _tmpltDao.findById(template.getId(), true); + public VMTemplateStoragePoolVO prepareTemplateForCreate(VMTemplateVO templ, StoragePool pool) { + VMTemplateVO template = _tmpltDao.findById(templ.getId(), true); long poolId = pool.getId(); long templateId = template.getId(); @@ -564,7 +671,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, } } - templateHostRef = _storageMgr.findVmTemplateHost(templateId, pool); + templateHostRef = findVmTemplateHost(templateId, pool); if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) { String result = downloadTemplateFromSwiftToSecondaryStorage(dcId, templateId); @@ -578,7 +685,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, s_logger.error("Unable to find a secondary storage host who has completely downloaded the template."); return null; } - templateHostRef = _storageMgr.findVmTemplateHost(templateId, pool); + templateHostRef = findVmTemplateHost(templateId, pool); if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) { s_logger.error("Unable to find a secondary storage host who has completely downloaded the template."); return null; @@ -671,6 +778,61 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, return null; } + + + + @Override + public VMTemplateHostVO findVmTemplateHost(long templateId, + StoragePool pool) { + long dcId = pool.getDataCenterId(); + Long podId = pool.getPodId(); + + List secHosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(dcId); + + + if (secHosts.size() == 1) { + VMTemplateHostVO templateHostVO = this._tmpltHostDao + .findByHostTemplate(secHosts.get(0).getId(), templateId); + return templateHostVO; + } + if (podId != null) { + List templHosts = this._tmpltHostDao + .listByTemplateStatus(templateId, dcId, podId, + VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + if (templHosts != null && !templHosts.isEmpty()) { + Collections.shuffle(templHosts); + return templHosts.get(0); + } + } + List templHosts = this._tmpltHostDao + .listByTemplateStatus(templateId, dcId, + VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + if (templHosts != null && !templHosts.isEmpty()) { + Collections.shuffle(templHosts); + return templHosts.get(0); + } + return null; + } + + @Override + public String getChecksum(Long hostId, String templatePath) { + HostVO ssHost = _hostDao.findById(hostId); + Host.Type type = ssHost.getType(); + if (type != Host.Type.SecondaryStorage + && type != Host.Type.LocalSecondaryStorage) { + return null; + } + String secUrl = ssHost.getStorageUrl(); + Answer answer; + answer = _agentMgr.sendToSecStorage(ssHost, new ComputeChecksumCommand( + secUrl, templatePath)); + if (answer != null && answer.getResult()) { + return answer.getDetails(); + } + return null; + } + @Override @DB public VMTemplateHostVO prepareISOForCreate(VMTemplateVO template, StoragePool pool) { @@ -684,7 +846,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, long templateStoragePoolRefId; String origUrl = null; - templateHostRef = _storageMgr.findVmTemplateHost(templateId, pool); + templateHostRef = findVmTemplateHost(templateId, pool); if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) { String result = downloadTemplateFromSwiftToSecondaryStorage(dcId, templateId); @@ -698,7 +860,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, s_logger.error("Unable to find a secondary storage host who has completely downloaded the template."); return null; } - templateHostRef = _storageMgr.findVmTemplateHost(templateId, pool); + templateHostRef = findVmTemplateHost(templateId, pool); if (templateHostRef == null || templateHostRef.getDownloadState() != Status.DOWNLOADED) { s_logger.error("Unable to find a secondary storage host who has completely downloaded the template."); return null; @@ -839,13 +1001,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new InvalidParameterValueException("Unable to find template with id"); } - HostVO dstSecHost = _storageMgr.getSecondaryStorageHost(destZoneId, templateId); + HostVO dstSecHost = getSecondaryStorageHost(destZoneId, templateId); if ( dstSecHost != null ) { s_logger.debug("There is template " + templateId + " in secondary storage " + dstSecHost.getId() + " in zone " + destZoneId + " , don't need to copy"); return template; } - HostVO srcSecHost = _storageMgr.getSecondaryStorageHost(sourceZoneId, templateId); + HostVO srcSecHost = getSecondaryStorageHost(sourceZoneId, templateId); if ( srcSecHost == null ) { throw new InvalidParameterValueException("There is no template " + templateId + " in zone " + sourceZoneId ); } @@ -900,7 +1062,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, @Override public void evictTemplateFromStoragePool(VMTemplateStoragePoolVO templatePoolVO) { - StoragePoolVO pool = _poolDao.findById(templatePoolVO.getPoolId()); + StoragePool pool = (StoragePool)this.dataStoreMgr.getPrimaryDataStore(templatePoolVO.getPoolId()); VMTemplateVO template = _tmpltDao.findByIdIncludingRemoved(templatePoolVO.getTemplateId()); @@ -1176,12 +1338,57 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, throw new CloudRuntimeException("Failed to attach iso"); } } + + private boolean attachISOToVM(long vmId, long isoId, boolean attach) { + UserVmVO vm = this._userVmDao.findById(vmId); + + if (vm == null) { + return false; + } else if (vm.getState() != State.Running) { + return true; + } + String isoPath; + VMTemplateVO tmplt = this._tmpltDao.findById(isoId); + if (tmplt == null) { + s_logger.warn("ISO: " + isoId + " does not exist"); + return false; + } + // Get the path of the ISO + Pair isoPathPair = null; + if (tmplt.getTemplateType() == TemplateType.PERHOST) { + isoPath = tmplt.getName(); + } else { + isoPathPair = getAbsoluteIsoPath(isoId, + vm.getDataCenterId()); + if (isoPathPair == null) { + s_logger.warn("Couldn't get absolute iso path"); + return false; + } else { + isoPath = isoPathPair.first(); + } + } + + String vmName = vm.getInstanceName(); + + HostVO host = _hostDao.findById(vm.getHostId()); + if (host == null) { + s_logger.warn("Host: " + vm.getHostId() + " does not exist"); + return false; + } + AttachIsoCommand cmd = new AttachIsoCommand(vmName, isoPath, attach); + if (isoPathPair != null) { + cmd.setStoreUrl(isoPathPair.second()); + } + Answer a = _agentMgr.easySend(vm.getHostId(), cmd); + + return (a != null && a.getResult()); + } private boolean attachISOToVM(long vmId, long userId, long isoId, boolean attach) { UserVmVO vm = _userVmDao.findById(vmId); VMTemplateVO iso = _tmpltDao.findById(isoId); - boolean success = _vmMgr.attachISOToVM(vmId, isoId, attach); + boolean success = attachISOToVM(vmId, isoId, attach); if ( success && attach) { vm.setIsoId(iso.getId()); _userVmDao.update(vmId, vm); @@ -1475,4 +1682,456 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager, return true; } + + private String getRandomPrivateTemplateName() { + return UUID.randomUUID().toString(); + } + + + + + + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", async = true) + public VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) + throws CloudRuntimeException { + Long userId = UserContext.current().getCallerUserId(); + if (userId == null) { + userId = User.UID_SYSTEM; + } + long templateId = command.getEntityId(); + Long volumeId = command.getVolumeId(); + Long snapshotId = command.getSnapshotId(); + VMTemplateVO privateTemplate = null; + Long accountId = null; + SnapshotVO snapshot = null; + + try { + TemplateInfo tmplInfo = this.tmplFactory.getTemplate(templateId); + snapshot = _snapshotDao.findById(snapshotId); + ZoneScope scope = new ZoneScope(snapshot.getDataCenterId()); + List store = this.dataStoreMgr.getImageStores(scope); + if (store.size() > 1) { + throw new CloudRuntimeException("muliple image data store, don't know which one to use"); + } + AsyncCallFuture future = null; + if (snapshotId != null) { + SnapshotInfo snapInfo = this.snapshotFactory.getSnapshot(snapshotId); + future = this.imageSvr.createTemplateFromSnapshotAsync(snapInfo, tmplInfo, store.get(0)); + } else if (volumeId != null) { + VolumeInfo volInfo = this.volFactory.getVolume(volumeId); + future = this.imageSvr.createTemplateFromVolumeAsync(volInfo, tmplInfo, store.get(0)); + } else { + throw new CloudRuntimeException( + "Creating private Template need to specify snapshotId or volumeId"); + } + + CommandResult result = null; + try { + result = future.get(); + if (result.isFailed()) { + privateTemplate = null; + s_logger.debug("Failed to create template" + result.getResult()); + throw new CloudRuntimeException("Failed to create template" + result.getResult()); + } + + privateTemplate = this._tmpltDao.findById(templateId); + UsageEventVO usageEvent = new UsageEventVO( + EventTypes.EVENT_TEMPLATE_CREATE, + privateTemplate.getAccountId(), + snapshot.getDataCenterId(), + privateTemplate.getId(), privateTemplate.getName(), + null, privateTemplate.getSourceTemplateId(), + privateTemplate.getSize()); + _usageEventDao.persist(usageEvent); + } catch (InterruptedException e) { + s_logger.debug("Failed to create template", e); + throw new CloudRuntimeException("Failed to create template", e); + } catch (ExecutionException e) { + s_logger.debug("Failed to create template", e); + throw new CloudRuntimeException("Failed to create template", e); + } + + } finally { + /*if (snapshot != null && snapshot.getSwiftId() != null + && secondaryStorageURL != null && zoneId != null + && accountId != null && volumeId != null) { + _snapshotMgr.deleteSnapshotsForVolume(secondaryStorageURL, + zoneId, accountId, volumeId); + }*/ + if (privateTemplate == null) { + Transaction txn = Transaction.currentTxn(); + txn.start(); + // Remove the template record + this._tmpltDao.expunge(templateId); + + // decrement resource count + if (accountId != null) { + _resourceLimitMgr.decrementResourceCount(accountId, + ResourceType.template); + } + txn.commit(); + } + } + + if (privateTemplate != null) { + return privateTemplate; + } else { + throw new CloudRuntimeException("Failed to create a template"); + } + } + + private static boolean isAdmin(short accountType) { + return ((accountType == Account.ACCOUNT_TYPE_ADMIN) + || (accountType == Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN) + || (accountType == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) || (accountType == Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)); + } + @Override + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) + public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, + Account templateOwner) throws ResourceAllocationException { + Long userId = UserContext.current().getCallerUserId(); + + Account caller = UserContext.current().getCaller(); + boolean isAdmin = (isAdmin(caller.getType())); + + _accountMgr.checkAccess(caller, null, true, templateOwner); + + String name = cmd.getTemplateName(); + if ((name == null) || (name.length() > 32)) { + throw new InvalidParameterValueException( + "Template name cannot be null and should be less than 32 characters"); + } + + if (cmd.getTemplateTag() != null) { + if (!_accountService.isRootAdmin(caller.getType())) { + throw new PermissionDeniedException( + "Parameter templatetag can only be specified by a Root Admin, permission denied"); + } + } + + // do some parameter defaulting + Integer bits = cmd.getBits(); + Boolean requiresHvm = cmd.getRequiresHvm(); + Boolean passwordEnabled = cmd.isPasswordEnabled(); + Boolean isPublic = cmd.isPublic(); + Boolean featured = cmd.isFeatured(); + int bitsValue = ((bits == null) ? 64 : bits.intValue()); + boolean requiresHvmValue = ((requiresHvm == null) ? true : requiresHvm + .booleanValue()); + boolean passwordEnabledValue = ((passwordEnabled == null) ? false + : passwordEnabled.booleanValue()); + if (isPublic == null) { + isPublic = Boolean.FALSE; + } + boolean allowPublicUserTemplates = Boolean.parseBoolean(_configDao + .getValue("allow.public.user.templates")); + if (!isAdmin && !allowPublicUserTemplates && isPublic) { + throw new PermissionDeniedException("Failed to create template " + + name + ", only private templates can be created."); + } + + Long volumeId = cmd.getVolumeId(); + Long snapshotId = cmd.getSnapshotId(); + if ((volumeId == null) && (snapshotId == null)) { + throw new InvalidParameterValueException( + "Failed to create private template record, neither volume ID nor snapshot ID were specified."); + } + if ((volumeId != null) && (snapshotId != null)) { + throw new InvalidParameterValueException( + "Failed to create private template record, please specify only one of volume ID (" + + volumeId + + ") and snapshot ID (" + + snapshotId + + ")"); + } + + HypervisorType hyperType; + VolumeVO volume = null; + VMTemplateVO privateTemplate = null; + if (volumeId != null) { // create template from volume + volume = this._volumeDao.findById(volumeId); + if (volume == null) { + throw new InvalidParameterValueException( + "Failed to create private template record, unable to find volume " + + volumeId); + } + // check permissions + _accountMgr.checkAccess(caller, null, true, volume); + + // If private template is created from Volume, check that the volume + // will not be active when the private template is + // created + if (!this.volumeMgr.volumeInactive(volume)) { + String msg = "Unable to create private template for volume: " + + volume.getName() + + "; volume is attached to a non-stopped VM, please stop the VM first"; + if (s_logger.isInfoEnabled()) { + s_logger.info(msg); + } + throw new CloudRuntimeException(msg); + } + hyperType = this._volumeDao.getHypervisorType(volumeId); + } else { // create template from snapshot + SnapshotVO snapshot = _snapshotDao.findById(snapshotId); + if (snapshot == null) { + throw new InvalidParameterValueException( + "Failed to create private template record, unable to find snapshot " + + snapshotId); + } + + volume = this._volumeDao.findById(snapshot.getVolumeId()); + VolumeVO snapshotVolume = this._volumeDao + .findByIdIncludingRemoved(snapshot.getVolumeId()); + + // check permissions + _accountMgr.checkAccess(caller, null, true, snapshot); + + if (snapshot.getState() != Snapshot.State.BackedUp) { + throw new InvalidParameterValueException("Snapshot id=" + + snapshotId + " is not in " + Snapshot.State.BackedUp + + " state yet and can't be used for template creation"); + } + + /* + * // bug #11428. Operation not supported if vmware and snapshots + * parent volume = ROOT if(snapshot.getHypervisorType() == + * HypervisorType.VMware && snapshotVolume.getVolumeType() == + * Type.DATADISK){ throw new UnsupportedServiceException( + * "operation not supported, snapshot with id " + snapshotId + + * " is created from Data Disk"); } + */ + + hyperType = snapshot.getHypervisorType(); + } + + _resourceLimitMgr.checkResourceLimit(templateOwner, + ResourceType.template); + + if (!isAdmin || featured == null) { + featured = Boolean.FALSE; + } + Long guestOSId = cmd.getOsTypeId(); + GuestOSVO guestOS = this._guestOSDao.findById(guestOSId); + if (guestOS == null) { + throw new InvalidParameterValueException("GuestOS with ID: " + + guestOSId + " does not exist."); + } + + String uniqueName = Long.valueOf((userId == null) ? 1 : userId) + .toString() + + UUID.nameUUIDFromBytes(name.getBytes()).toString(); + Long nextTemplateId = this._tmpltDao.getNextInSequence(Long.class, "id"); + String description = cmd.getDisplayText(); + boolean isExtractable = false; + Long sourceTemplateId = null; + if (volume != null) { + VMTemplateVO template = ApiDBUtils.findTemplateById(volume + .getTemplateId()); + isExtractable = template != null + && template.isExtractable() + && template.getTemplateType() != Storage.TemplateType.SYSTEM; + if (template != null) { + sourceTemplateId = template.getId(); + } else if (volume.getVolumeType() == Volume.Type.ROOT) { // vm created out + // of blank + // template + UserVm userVm = ApiDBUtils.findUserVmById(volume + .getInstanceId()); + sourceTemplateId = userVm.getIsoId(); + } + } + String templateTag = cmd.getTemplateTag(); + if (templateTag != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Adding template tag: " + templateTag); + } + } + privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, name, + ImageFormat.RAW, isPublic, featured, isExtractable, + TemplateType.USER, null, null, requiresHvmValue, bitsValue, + templateOwner.getId(), null, description, passwordEnabledValue, + guestOS.getId(), true, hyperType, templateTag, cmd.getDetails()); + if (sourceTemplateId != null) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("This template is getting created from other template, setting source template Id to: " + + sourceTemplateId); + } + } + privateTemplate.setSourceTemplateId(sourceTemplateId); + + VMTemplateVO template = this._tmpltDao.persist(privateTemplate); + // Increment the number of templates + if (template != null) { + if (cmd.getDetails() != null) { + this._templateDetailsDao.persist(template.getId(), cmd.getDetails()); + } + + _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), + ResourceType.template); + } + + if (template != null) { + return template; + } else { + throw new CloudRuntimeException("Failed to create a template"); + } + + } + + @Override + public Pair getAbsoluteIsoPath(long templateId, + long dataCenterId) { + String isoPath = null; + + List storageHosts = _resourceMgr.listAllHostsInOneZoneByType( + Host.Type.SecondaryStorage, dataCenterId); + if (storageHosts != null) { + for (HostVO storageHost : storageHosts) { + List templateHostVOs = this._tmpltHostDao + .listByTemplateHostStatus( + templateId, + storageHost.getId(), + VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + if (templateHostVOs != null && !templateHostVOs.isEmpty()) { + VMTemplateHostVO tmpHostVO = templateHostVOs.get(0); + isoPath = storageHost.getStorageUrl() + "/" + + tmpHostVO.getInstallPath(); + return new Pair(isoPath, + storageHost.getStorageUrl()); + } + } + } + s_logger.warn("Unable to find secondary storage in zone id=" + + dataCenterId); + return null; + } + + @Override + public String getSecondaryStorageURL(long zoneId) { + // Determine the secondary storage URL + HostVO secondaryStorageHost = getSecondaryStorageHost(zoneId); + + if (secondaryStorageHost == null) { + return null; + } + + return secondaryStorageHost.getStorageUrl(); + } + + @Override + public HostVO getSecondaryStorageHost(long zoneId, long tmpltId) { + List hosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(zoneId); + if (hosts == null || hosts.size() == 0) { + return null; + } + for (HostVO host : hosts) { + VMTemplateHostVO tmpltHost = this._tmpltHostDao.findByHostTemplate( + host.getId(), tmpltId); + if (tmpltHost != null + && !tmpltHost.getDestroyed() + && tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { + return host; + } + } + return null; + } + + @Override + public VMTemplateHostVO getTemplateHostRef(long zoneId, long tmpltId, + boolean readyOnly) { + List hosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(zoneId); + if (hosts == null || hosts.size() == 0) { + return null; + } + VMTemplateHostVO inProgress = null; + VMTemplateHostVO other = null; + for (HostVO host : hosts) { + VMTemplateHostVO tmpltHost = this._tmpltHostDao.findByHostTemplate( + host.getId(), tmpltId); + if (tmpltHost != null && !tmpltHost.getDestroyed()) { + if (tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) { + return tmpltHost; + } else if (tmpltHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) { + inProgress = tmpltHost; + } else { + other = tmpltHost; + } + } + } + if (inProgress != null) { + return inProgress; + } + return other; + } + + @Override + public HostVO getSecondaryStorageHost(long zoneId) { + List hosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(zoneId); + if (hosts == null || hosts.size() == 0) { + hosts = _ssvmMgr.listLocalSecondaryStorageHostsInOneZone(zoneId); + if (hosts.isEmpty()) { + return null; + } + } + + int size = hosts.size(); + Random rn = new Random(); + int index = rn.nextInt(size); + return hosts.get(index); + } + + @Override + public List getSecondaryStorageHosts(long zoneId) { + List hosts = _ssvmMgr + .listSecondaryStorageHostsInOneZone(zoneId); + if (hosts == null || hosts.size() == 0) { + hosts = _ssvmMgr.listLocalSecondaryStorageHostsInOneZone(zoneId); + if (hosts.isEmpty()) { + return new ArrayList(); + } + } + return hosts; + } + + @Override + public Long getTemplateSize(long templateId, long zoneId) { + SearchCriteria sc = HostTemplateStatesSearch.create(); + sc.setParameters("id", templateId); + sc.setParameters( + "state", + com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED); + sc.setJoinParameters("host", "dcId", zoneId); + List tsvs = _tmpltSwiftDao + .listByTemplateId(templateId); + Long size = null; + if (tsvs != null && tsvs.size() > 0) { + size = tsvs.get(0).getSize(); + } + + if (size == null && _s3Mgr.isS3Enabled()) { + VMTemplateS3VO vmTemplateS3VO = _vmS3TemplateDao + .findOneByTemplateId(templateId); + if (vmTemplateS3VO != null) { + size = vmTemplateS3VO.getSize(); + } + } + + if (size == null) { + List sss = this.templateHostDao.search(sc, null); + if (sss == null || sss.size() == 0) { + throw new CloudRuntimeException("Template " + + templateId + + " has not been completely downloaded to zone " + + zoneId); + } + size = sss.get(0).getSize(); + } + return size; + } + } diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index a3f9505c3df..f9a61e89df7 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -104,6 +104,7 @@ import com.cloud.server.auth.UserAuthenticator; import com.cloud.storage.StorageManager; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; +import com.cloud.storage.VolumeManager; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.VMTemplateDao; @@ -118,7 +119,6 @@ import com.cloud.user.dao.UserDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; - import com.cloud.utils.component.Manager; import com.cloud.utils.component.ManagerBase; import com.cloud.utils.concurrency.NamedThreadFactory; @@ -226,6 +226,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M Site2SiteVpnManager _vpnMgr; @Inject private AutoScaleManager _autoscaleMgr; + @Inject VolumeManager volumeMgr; @Inject private List _userAuthenticators; @@ -576,7 +577,7 @@ public class AccountManagerImpl extends ManagerBase implements AccountManager, M for (VolumeVO volume : volumes) { if (!volume.getState().equals(Volume.State.Destroy)) { try { - _storageMgr.deleteVolume(volume.getId(), caller); + this.volumeMgr.deleteVolume(volume.getId(), caller); } catch (Exception ex) { s_logger.warn("Failed to cleanup volumes as a part of account id=" + accountId + " cleanup due to Exception: ", ex); accountCleanupNeeded = true; diff --git a/server/src/com/cloud/vm/UserVmManager.java b/server/src/com/cloud/vm/UserVmManager.java index 3e4a2dbf27f..cc1fffd780b 100755 --- a/server/src/com/cloud/vm/UserVmManager.java +++ b/server/src/com/cloud/vm/UserVmManager.java @@ -49,16 +49,7 @@ public interface UserVmManager extends VirtualMachineGuru, UserVmServi * @return VirtualMachine */ UserVmVO getVirtualMachine(long vmId); - - /** - * Attaches an ISO to the virtual CDROM device of the specified VM. Will eject any existing virtual CDROM if isoPath is null. - * @param vmId - * @param isoId - * @param attach whether to attach or detach the given iso - * @return - */ - boolean attachISOToVM(long vmId, long isoId, boolean attach); - + /** * Stops the virtual machine * @param userId the id of the user performing the action @@ -101,8 +92,6 @@ public interface UserVmManager extends VirtualMachineGuru, UserVmServi */ Pair, Integer> searchForUserVMs(Criteria c, Account caller, Long domainId, boolean isRecursive, List permittedAccounts, boolean listAll, ListProjectResourcesCriteria listProjectResourcesCriteria, Map tags); - String getChecksum(Long hostId, String templatePath); - Pair> startVirtualMachine(long vmId, Long hostId, Map additionalParams) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; } diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index ed8cd3630a8..6022b38f6b2 100644 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -34,10 +34,8 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.BaseCmd; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; @@ -52,32 +50,19 @@ import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; - import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity; import org.apache.cloudstack.engine.service.api.OrchestrationService; import org.apache.commons.codec.binary.Base64; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; +import com.cloud.agent.AgentManager.OnError; import com.cloud.agent.api.Answer; -import com.cloud.agent.api.AttachIsoCommand; -import com.cloud.agent.api.AttachVolumeAnswer; -import com.cloud.agent.api.AttachVolumeCommand; -import com.cloud.agent.api.ComputeChecksumCommand; -import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand; -import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand; import com.cloud.agent.api.GetVmStatsAnswer; import com.cloud.agent.api.GetVmStatsCommand; -import com.cloud.agent.api.SnapshotCommand; import com.cloud.agent.api.StartAnswer; import com.cloud.agent.api.StopAnswer; -import com.cloud.agent.api.UpgradeSnapshotCommand; import com.cloud.agent.api.VmStatsEntry; -import com.cloud.agent.AgentManager.OnError; -import com.cloud.agent.api.*; -import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer; import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.agent.api.to.VolumeTO; @@ -87,13 +72,9 @@ import com.cloud.agent.api.UnPlugNicAnswer; import com.cloud.agent.api.UnPlugNicCommand; import com.cloud.agent.manager.Commands; import com.cloud.alert.AlertManager; -import com.cloud.api.ApiDBUtils; import com.cloud.api.query.dao.UserVmJoinDao; import com.cloud.api.query.vo.UserVmJoinVO; -import com.cloud.async.AsyncJobExecutor; import com.cloud.async.AsyncJobManager; -import com.cloud.async.AsyncJobVO; -import com.cloud.async.BaseAsyncJobExecutor; import com.cloud.capacity.CapacityManager; import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManager; @@ -133,15 +114,11 @@ import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; -import com.cloud.network.Network; import com.cloud.network.*; import com.cloud.network.Network.IpAddresses; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -import com.cloud.network.NetworkManager; -import com.cloud.network.NetworkModel; import com.cloud.network.Networks.TrafficType; -import com.cloud.network.PhysicalNetwork; import com.cloud.network.dao.FirewallRulesDao; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; @@ -182,7 +159,6 @@ import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.GuestOSCategoryVO; import com.cloud.storage.GuestOSVO; -import com.cloud.storage.Snapshot; import com.cloud.storage.SnapshotVO; import com.cloud.storage.Storage; import com.cloud.storage.Storage.ImageFormat; @@ -191,14 +167,10 @@ import com.cloud.storage.Storage.TemplateType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePoolStatus; -import com.cloud.storage.StoragePoolVO; -import com.cloud.storage.VMTemplateHostVO; -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.Type; -import com.cloud.storage.VolumeHostVO; +import com.cloud.storage.VolumeManager; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; @@ -213,6 +185,7 @@ import com.cloud.storage.dao.VolumeDao; import com.cloud.storage.dao.VolumeHostDao; import com.cloud.storage.snapshot.SnapshotManager; import com.cloud.tags.dao.ResourceTagDao; +import com.cloud.template.TemplateManager; import com.cloud.template.VirtualMachineTemplate; import com.cloud.template.VirtualMachineTemplate.BootloaderType; import com.cloud.user.Account; @@ -278,7 +251,7 @@ import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; import com.cloud.vm.snapshot.VMSnapshot; import com.cloud.vm.snapshot.VMSnapshotManager; -import com.cloud.vm.snapshot.VMSnapshotVO; +//import com.cloud.vm.snapshot.VMSnapshotVO; import com.cloud.vm.snapshot.dao.VMSnapshotDao; @Local(value = { UserVmManager.class, UserVmService.class }) @@ -414,6 +387,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Inject VpcManager _vpcMgr; @Inject + TemplateManager templateMgr; + @Inject protected GuestOSCategoryDao _guestOSCategoryDao; @Inject UsageEventDao _usageEventDao; @@ -436,6 +411,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Inject protected OrchestrationService _orchSrvc; + + @Inject VolumeManager volumeMgr; @Override public UserVmVO getVirtualMachine(long vmId) { @@ -737,592 +714,21 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - private int getMaxDataVolumesSupported(UserVmVO vm) { - Long hostId = vm.getHostId(); - if (hostId == null) { - hostId = vm.getLastHostId(); - } - HostVO host = _hostDao.findById(hostId); - Integer maxDataVolumesSupported = null; - if (host != null) { - _hostDao.loadDetails(host); - maxDataVolumesSupported = _hypervisorCapabilitiesDao - .getMaxDataVolumesLimit(host.getHypervisorType(), - host.getDetail("product_version")); - } - if (maxDataVolumesSupported == null) { - maxDataVolumesSupported = 6; // 6 data disks by default if nothing - // is specified in - // 'hypervisor_capabilities' table - } - return maxDataVolumesSupported.intValue(); - } - - @Override - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription = "attaching volume", async = true) - public Volume attachVolumeToVM(AttachVolumeCmd command) { - Long vmId = command.getVirtualMachineId(); - Long volumeId = command.getId(); - Long deviceId = command.getDeviceId(); - Account caller = UserContext.current().getCaller(); - - // 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() != Volume.Type.DATADISK) { - throw new InvalidParameterValueException( - "Please specify a valid data volume."); - } - - // Check that the volume is not currently attached to any VM - if (volume.getInstanceId() != null) { - throw new InvalidParameterValueException( - "Please specify a volume that is not attached to any VM."); - } - - // Check that the volume is not destroyed - if (volume.getState() == Volume.State.Destroy) { - throw new InvalidParameterValueException( - "Please specify a volume that is not destroyed."); - } - - // Check that the virtual machine ID is valid and it's a user vm - UserVmVO vm = _vmDao.findById(vmId); - if (vm == null || vm.getType() != VirtualMachine.Type.User) { - throw new InvalidParameterValueException( - "Please specify a valid User VM."); - } - - // Check that the VM is in the correct state - if (vm.getState() != State.Running && vm.getState() != State.Stopped) { - throw new InvalidParameterValueException( - "Please specify a VM that is either running or stopped."); - } - - // Check that the device ID is valid - if (deviceId != null) { - if (deviceId.longValue() == 0) { - throw new InvalidParameterValueException( - "deviceId can't be 0, which is used by Root device"); - } - } - - // Check that the number of data volumes attached to VM is less than - // that supported by hypervisor - List existingDataVolumes = _volsDao.findByInstanceAndType( - vmId, Volume.Type.DATADISK); - int maxDataVolumesSupported = getMaxDataVolumesSupported(vm); - if (existingDataVolumes.size() >= maxDataVolumesSupported) { - throw new InvalidParameterValueException( - "The specified VM already has the maximum number of data disks (" - + maxDataVolumesSupported - + "). Please specify another VM."); - } - - // Check that the VM and the volume are in the same zone - if (vm.getDataCenterId() != volume.getDataCenterId()) { - throw new InvalidParameterValueException( - "Please specify a VM that is in the same zone as the volume."); - } - - // If local storage is disabled then attaching a volume with local disk - // offering not allowed - DataCenterVO dataCenter = _dcDao.findById(volume.getDataCenterId()); - if (!dataCenter.isLocalStorageEnabled()) { - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume - .getDiskOfferingId()); - if (diskOffering.getUseLocalStorage()) { - throw new InvalidParameterValueException( - "Zone is not configured to use local storage but volume's disk offering " - + diskOffering.getName() + " uses it"); - } - } - - // permission check - _accountMgr.checkAccess(caller, null, true, volume, vm); - - //check if vm has snapshot, if true: can't attache volume - boolean attach = true; - checkVMSnapshots(vm, volumeId, attach); - - // Check if volume is stored on secondary Storage. - //Check if volume is stored on secondary Storage. - boolean isVolumeOnSec = false; - VolumeHostVO volHostVO = _volumeHostDao.findByVolumeId(volume.getId()); - if (volHostVO != null) { - isVolumeOnSec = true; - if (!(volHostVO.getDownloadState() == Status.DOWNLOADED)) { - throw new InvalidParameterValueException( - "Volume is not uploaded yet. Please try this operation once the volume is uploaded"); - } - } - - if (!(Volume.State.Allocated.equals(volume.getState()) - || Volume.State.Ready.equals(volume.getState()) || Volume.State.UploadOp - .equals(volume.getState()))) { - throw new InvalidParameterValueException( - "Volume state must be in Allocated, Ready or in Uploaded state"); - } - - VolumeVO rootVolumeOfVm = null; - List rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, - Volume.Type.ROOT); - if (rootVolumesOfVm.size() != 1) { - throw new CloudRuntimeException( - "The VM " - + vm.getHostName() - + " has more than one ROOT volume and is in an invalid state."); - } else { - rootVolumeOfVm = rootVolumesOfVm.get(0); - } - - HypervisorType rootDiskHyperType = vm.getHypervisorType(); - - HypervisorType dataDiskHyperType = _volsDao.getHypervisorType(volume - .getId()); - if (dataDiskHyperType != HypervisorType.None - && rootDiskHyperType != dataDiskHyperType) { - throw new InvalidParameterValueException( - "Can't attach a volume created by: " + dataDiskHyperType - + " to a " + rootDiskHyperType + " vm"); - } - - // allocate deviceId - List vols = _volsDao.findByInstance(vmId); - if (deviceId != null) { - if (deviceId.longValue() > 15 || deviceId.longValue() == 0 - || deviceId.longValue() == 3) { - throw new RuntimeException("deviceId should be 1,2,4-15"); - } - for (VolumeVO vol : vols) { - if (vol.getDeviceId().equals(deviceId)) { - throw new RuntimeException("deviceId " + deviceId - + " is used by VM " + vm.getHostName()); - } - } - } else { - // allocate deviceId here - List devIds = new ArrayList(); - for (int i = 1; i < 15; i++) { - devIds.add(String.valueOf(i)); - } - devIds.remove("3"); - for (VolumeVO vol : vols) { - devIds.remove(vol.getDeviceId().toString().trim()); - } - deviceId = Long.parseLong(devIds.iterator().next()); - } - - boolean createVolumeOnBackend = true; - if (rootVolumeOfVm.getState() == Volume.State.Allocated) { - createVolumeOnBackend = false; - if (isVolumeOnSec) { - throw new CloudRuntimeException( - "Cant attach uploaded volume to the vm which is not created. Please start it and then retry"); - } - } - - // create volume on the backend only when vm's root volume is allocated - if (createVolumeOnBackend) { - if (volume.getState().equals(Volume.State.Allocated) - || isVolumeOnSec) { - /* Need to create the volume */ - VMTemplateVO rootDiskTmplt = _templateDao.findById(vm - .getTemplateId()); - DataCenterVO dcVO = _dcDao.findById(vm - .getDataCenterId()); - HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn()); - StoragePoolVO rootDiskPool = _storagePoolDao - .findById(rootVolumeOfVm.getPoolId()); - ServiceOfferingVO svo = _serviceOfferingDao.findById(vm - .getServiceOfferingId()); - DiskOfferingVO diskVO = _diskOfferingDao.findById(volume - .getDiskOfferingId()); - Long clusterId = (rootDiskPool == null ? null : rootDiskPool - .getClusterId()); - - if (!isVolumeOnSec) { - volume = _storageMgr.createVolume(volume, vm, - rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO, - new ArrayList(), volume.getSize(), - rootDiskHyperType); - } else { - try { - // Format of data disk should be the same as root disk - if (!volHostVO - .getFormat() - .getFileExtension() - .equals(_storageMgr - .getSupportedImageFormatForCluster(rootDiskPool - .getClusterId()))) { - throw new InvalidParameterValueException( - "Failed to attach volume to VM since volumes format " - + volHostVO.getFormat() - .getFileExtension() - + " is not compatible with the vm hypervisor type"); - } - - // Check that there is some shared storage. - StoragePoolVO vmRootVolumePool = _storagePoolDao - .findById(rootVolumeOfVm.getPoolId()); - List sharedVMPools = _storagePoolDao - .findPoolsByTags( - vmRootVolumePool.getDataCenterId(), - vmRootVolumePool.getPodId(), - vmRootVolumePool.getClusterId(), null, - true); - if (sharedVMPools.size() == 0) { - throw new CloudRuntimeException( - "Cannot attach volume since there are no shared storage pools in the VM's cluster to copy the uploaded volume to."); - } - - volume = _storageMgr.copyVolumeFromSecToPrimary(volume, - vm, rootDiskTmplt, dcVO, pod, - rootDiskPool.getClusterId(), svo, diskVO, - new ArrayList(), - volume.getSize(), rootDiskHyperType); - } catch (NoTransitionException e) { - throw new CloudRuntimeException( - "Unable to transition the volume ", e); - } - } - - if (volume == null) { - throw new CloudRuntimeException( - "Failed to create volume when attaching it to VM: " - + vm.getHostName()); - } - } - - StoragePoolVO vmRootVolumePool = _storagePoolDao - .findById(rootVolumeOfVm.getPoolId()); - DiskOfferingVO volumeDiskOffering = _diskOfferingDao - .findById(volume.getDiskOfferingId()); - String[] volumeTags = volumeDiskOffering.getTagsArray(); - - boolean isVolumeOnSharedPool = !volumeDiskOffering - .getUseLocalStorage(); - StoragePoolVO sourcePool = _storagePoolDao.findById(volume - .getPoolId()); - List matchingVMPools = _storagePoolDao - .findPoolsByTags(vmRootVolumePool.getDataCenterId(), - vmRootVolumePool.getPodId(), - vmRootVolumePool.getClusterId(), volumeTags, - isVolumeOnSharedPool); - boolean moveVolumeNeeded = true; - if (matchingVMPools.size() == 0) { - String poolType; - if (vmRootVolumePool.getClusterId() != null) { - poolType = "cluster"; - } else if (vmRootVolumePool.getPodId() != null) { - poolType = "pod"; - } else { - poolType = "zone"; - } - throw new CloudRuntimeException( - "There are no storage pools in the VM's " + poolType - + " with all of the volume's tags (" - + volumeDiskOffering.getTags() + ")."); - } else { - long sourcePoolId = sourcePool.getId(); - Long sourcePoolDcId = sourcePool.getDataCenterId(); - Long sourcePoolPodId = sourcePool.getPodId(); - Long sourcePoolClusterId = sourcePool.getClusterId(); - for (StoragePoolVO vmPool : matchingVMPools) { - long vmPoolId = vmPool.getId(); - Long vmPoolDcId = vmPool.getDataCenterId(); - Long vmPoolPodId = vmPool.getPodId(); - Long vmPoolClusterId = vmPool.getClusterId(); - - // Moving a volume is not required if storage pools belongs - // to same cluster in case of shared volume or - // identical storage pool in case of local - if (sourcePoolDcId == vmPoolDcId - && sourcePoolPodId == vmPoolPodId - && sourcePoolClusterId == vmPoolClusterId - && (isVolumeOnSharedPool || sourcePoolId == vmPoolId)) { - moveVolumeNeeded = false; - break; - } - } - } - - if (moveVolumeNeeded) { - if (isVolumeOnSharedPool) { - // Move the volume to a storage pool in the VM's zone, pod, - // or cluster - try { - volume = _storageMgr.moveVolume(volume, - vmRootVolumePool.getDataCenterId(), - vmRootVolumePool.getPodId(), - vmRootVolumePool.getClusterId(), - dataDiskHyperType); - } catch (ConcurrentOperationException e) { - throw new CloudRuntimeException(e.toString()); - } - } else { - throw new CloudRuntimeException( - "Failed to attach local data volume " - + volume.getName() - + " to VM " - + vm.getDisplayName() - + " as migration of local data volume is not allowed"); - } - } - } - - AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor - .getCurrentExecutor(); - if (asyncExecutor != null) { - AsyncJobVO job = asyncExecutor.getJob(); - - if (s_logger.isInfoEnabled()) { - s_logger.info("Trying to attaching volume " + volumeId - + " to vm instance:" + vm.getId() - + ", update async job-" + job.getId() - + " progress status"); - } - - _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); - _asyncMgr.updateAsyncJobStatus(job.getId(), - BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId); - } - - String errorMsg = "Failed to attach volume: " + volume.getName() - + " to VM: " + vm.getHostName(); - boolean sendCommand = (vm.getState() == State.Running); - AttachVolumeAnswer answer = null; - Long hostId = vm.getHostId(); - if (hostId == null) { - hostId = vm.getLastHostId(); - HostVO host = _hostDao.findById(hostId); - if (host != null - && host.getHypervisorType() == HypervisorType.VMware) { - sendCommand = true; - } - } - - if (sendCommand) { - StoragePoolVO volumePool = _storagePoolDao.findById(volume - .getPoolId()); - AttachVolumeCommand cmd = new AttachVolumeCommand(true, - vm.getInstanceName(), volume.getPoolType(), - volume.getFolder(), volume.getPath(), volume.getName(), - deviceId, volume.getChainInfo()); - cmd.setPoolUuid(volumePool.getUuid()); - - try { - answer = (AttachVolumeAnswer) _agentMgr.send(hostId, cmd); - } catch (Exception e) { - throw new CloudRuntimeException(errorMsg + " due to: " - + e.getMessage()); - } - } - - if (!sendCommand || (answer != null && answer.getResult())) { - // Mark the volume as attached - if (sendCommand) { - _volsDao.attachVolume(volume.getId(), vmId, - answer.getDeviceId()); - } else { - _volsDao.attachVolume(volume.getId(), vmId, deviceId); - } - return _volsDao.findById(volumeId); - } else { - if (answer != null) { - String details = answer.getDetails(); - if (details != null && !details.isEmpty()) { - errorMsg += "; " + details; - } - } - throw new CloudRuntimeException(errorMsg); - } - } + private void checkVMSnapshots(UserVmVO vm, Long volumeId, boolean attach) { // Check that if vm has any VM snapshot - Long vmId = vm.getId(); + /*Long vmId = vm.getId(); List listSnapshot = _vmSnapshotDao.listByInstanceId(vmId, VMSnapshot.State.Ready, VMSnapshot.State.Creating, VMSnapshot.State.Reverting, VMSnapshot.State.Expunging); if (listSnapshot != null && listSnapshot.size() != 0) { throw new InvalidParameterValueException( "The VM has VM snapshots, do not allowed to attach volume. Please delete the VM snapshots first."); - } + }*/ } - @Override - @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription = "event_detaching_volume1", async = true) - public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) { - Account caller = UserContext.current().getCaller(); - if ((cmmd.getId() == null && cmmd.getDeviceId() == null && cmmd - .getVirtualMachineId() == null) - || (cmmd.getId() != null && (cmmd.getDeviceId() != null || cmmd - .getVirtualMachineId() != null)) - || (cmmd.getId() == null && (cmmd.getDeviceId() == null || cmmd - .getVirtualMachineId() == null))) { - throw new InvalidParameterValueException( - "Please provide either a volume id, or a tuple(device id, instance id)"); - } - - Long volumeId = cmmd.getId(); - VolumeVO volume = null; - - if (volumeId != null) { - volume = _volsDao.findById(volumeId); - } else { - volume = _volsDao.findByInstanceAndDeviceId( - cmmd.getVirtualMachineId(), cmmd.getDeviceId()).get(0); - } - - Long vmId = null; - - if (cmmd.getVirtualMachineId() == null) { - vmId = volume.getInstanceId(); - } else { - vmId = cmmd.getVirtualMachineId(); - } - - // Check that the volume ID is valid - if (volume == null) { - throw new InvalidParameterValueException( - "Unable to find volume with ID: " + volumeId); - } - - // Permissions check - _accountMgr.checkAccess(caller, null, true, volume); - - // Check that the volume is a data volume - if (volume.getVolumeType() != Volume.Type.DATADISK) { - throw new InvalidParameterValueException( - "Please specify a data volume."); - } - - // Check that the volume is currently attached to a VM - if (vmId == null) { - throw new InvalidParameterValueException( - "The specified volume is not attached to a VM."); - } - - // Check that the VM is in the correct state - UserVmVO vm = _vmDao.findById(vmId); - if (vm.getState() != State.Running && vm.getState() != State.Stopped - && vm.getState() != State.Destroyed) { - throw new InvalidParameterValueException( - "Please specify a VM that is either running or stopped."); - } - - // Check that if the volume has snapshot - boolean attach = false; - checkVMSnapshots(vm, volumeId, attach); - AsyncJobExecutor asyncExecutor = BaseAsyncJobExecutor.getCurrentExecutor(); - if (asyncExecutor != null) { - AsyncJobVO job = asyncExecutor.getJob(); - - if (s_logger.isInfoEnabled()) { - s_logger.info("Trying to attaching volume " + volumeId - + "to vm instance:" + vm.getId() - + ", update async job-" + job.getId() - + " progress status"); - } - - _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", volumeId); - _asyncMgr.updateAsyncJobStatus(job.getId(), - BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId); - } - - String errorMsg = "Failed to detach volume: " + volume.getName() - + " from VM: " + vm.getHostName(); - boolean sendCommand = (vm.getState() == State.Running); - Answer answer = null; - - if (sendCommand) { - AttachVolumeCommand cmd = new AttachVolumeCommand(false, - vm.getInstanceName(), volume.getPoolType(), - volume.getFolder(), volume.getPath(), volume.getName(), - cmmd.getDeviceId() != null ? cmmd.getDeviceId() : volume - .getDeviceId(), volume.getChainInfo()); - - StoragePoolVO volumePool = _storagePoolDao.findById(volume - .getPoolId()); - cmd.setPoolUuid(volumePool.getUuid()); - - try { - answer = _agentMgr.send(vm.getHostId(), cmd); - } catch (Exception e) { - throw new CloudRuntimeException(errorMsg + " due to: " - + e.getMessage()); - } - } - - if (!sendCommand || (answer != null && answer.getResult())) { - // Mark the volume as detached - _volsDao.detachVolume(volume.getId()); - if (answer != null && answer instanceof AttachVolumeAnswer) { - volume.setChainInfo(((AttachVolumeAnswer) answer) - .getChainInfo()); - _volsDao.update(volume.getId(), volume); - } - - return _volsDao.findById(volumeId); - } else { - - if (answer != null) { - String details = answer.getDetails(); - if (details != null && !details.isEmpty()) { - errorMsg += "; " + details; - } - } - - throw new CloudRuntimeException(errorMsg); - } - } - - @Override - public boolean attachISOToVM(long vmId, long isoId, boolean attach) { - UserVmVO vm = _vmDao.findById(vmId); - - if (vm == null) { - return false; - } else if (vm.getState() != State.Running) { - return true; - } - String isoPath; - VMTemplateVO tmplt = _templateDao.findById(isoId); - if (tmplt == null) { - s_logger.warn("ISO: " + isoId + " does not exist"); - return false; - } - // Get the path of the ISO - Pair isoPathPair = null; - if (tmplt.getTemplateType() == TemplateType.PERHOST) { - isoPath = tmplt.getName(); - } else { - isoPathPair = _storageMgr.getAbsoluteIsoPath(isoId, - vm.getDataCenterId()); - if (isoPathPair == null) { - s_logger.warn("Couldn't get absolute iso path"); - return false; - } else { - isoPath = isoPathPair.first(); - } - } - - String vmName = vm.getInstanceName(); - - HostVO host = _hostDao.findById(vm.getHostId()); - if (host == null) { - s_logger.warn("Host: " + vm.getHostId() + " does not exist"); - return false; - } - AttachIsoCommand cmd = new AttachIsoCommand(vmName, isoPath, attach); - if (isoPathPair != null) { - cmd.setStoreUrl(isoPathPair.second()); - } - Answer a = _agentMgr.easySend(vm.getHostId(), cmd); - - return (a != null && a.getResult()); - } + private UserVm rebootVirtualMachine(long userId, long vmId) throws InsufficientCapacityException, ResourceUnavailableException { @@ -1368,7 +774,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use _itMgr.checkIfCanUpgrade(vmInstance, svcOffId); // remove diskAndMemory VM snapshots - List vmSnapshots = _vmSnapshotDao.findByVm(vmId); + /* List vmSnapshots = _vmSnapshotDao.findByVm(vmId); for (VMSnapshotVO vmSnapshotVO : vmSnapshots) { if(vmSnapshotVO.getType() == VMSnapshot.Type.DiskAndMemory){ if(!_vmSnapshotMgr.deleteAllVMSnapshots(vmId, VMSnapshot.Type.DiskAndMemory)){ @@ -1378,7 +784,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - } + }*/ _itMgr.upgradeVmDb(vmId, svcOffId); @@ -1962,474 +1368,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use } } - @Override - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) - public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, - Account templateOwner) throws ResourceAllocationException { - Long userId = UserContext.current().getCallerUserId(); - - Account caller = UserContext.current().getCaller(); - boolean isAdmin = (isAdmin(caller.getType())); - - _accountMgr.checkAccess(caller, null, true, templateOwner); - - String name = cmd.getTemplateName(); - if ((name == null) || (name.length() > 32)) { - throw new InvalidParameterValueException( - "Template name cannot be null and should be less than 32 characters"); - } - - if (cmd.getTemplateTag() != null) { - if (!_accountService.isRootAdmin(caller.getType())) { - throw new PermissionDeniedException( - "Parameter templatetag can only be specified by a Root Admin, permission denied"); - } - } - - // do some parameter defaulting - Integer bits = cmd.getBits(); - Boolean requiresHvm = cmd.getRequiresHvm(); - Boolean passwordEnabled = cmd.isPasswordEnabled(); - Boolean isPublic = cmd.isPublic(); - Boolean featured = cmd.isFeatured(); - int bitsValue = ((bits == null) ? 64 : bits.intValue()); - boolean requiresHvmValue = ((requiresHvm == null) ? true : requiresHvm - .booleanValue()); - boolean passwordEnabledValue = ((passwordEnabled == null) ? false - : passwordEnabled.booleanValue()); - if (isPublic == null) { - isPublic = Boolean.FALSE; - } - boolean allowPublicUserTemplates = Boolean.parseBoolean(_configDao - .getValue("allow.public.user.templates")); - if (!isAdmin && !allowPublicUserTemplates && isPublic) { - throw new PermissionDeniedException("Failed to create template " - + name + ", only private templates can be created."); - } - - Long volumeId = cmd.getVolumeId(); - Long snapshotId = cmd.getSnapshotId(); - if ((volumeId == null) && (snapshotId == null)) { - throw new InvalidParameterValueException( - "Failed to create private template record, neither volume ID nor snapshot ID were specified."); - } - if ((volumeId != null) && (snapshotId != null)) { - throw new InvalidParameterValueException( - "Failed to create private template record, please specify only one of volume ID (" - + volumeId - + ") and snapshot ID (" - + snapshotId - + ")"); - } - - HypervisorType hyperType; - VolumeVO volume = null; - VMTemplateVO privateTemplate = null; - if (volumeId != null) { // create template from volume - volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new InvalidParameterValueException( - "Failed to create private template record, unable to find volume " - + volumeId); - } - // check permissions - _accountMgr.checkAccess(caller, null, true, volume); - - // If private template is created from Volume, check that the volume - // will not be active when the private template is - // created - if (!_storageMgr.volumeInactive(volume)) { - String msg = "Unable to create private template for volume: " - + volume.getName() - + "; volume is attached to a non-stopped VM, please stop the VM first"; - if (s_logger.isInfoEnabled()) { - s_logger.info(msg); - } - throw new CloudRuntimeException(msg); - } - hyperType = _volsDao.getHypervisorType(volumeId); - } else { // create template from snapshot - SnapshotVO snapshot = _snapshotDao.findById(snapshotId); - if (snapshot == null) { - throw new InvalidParameterValueException( - "Failed to create private template record, unable to find snapshot " - + snapshotId); - } - - volume = _volsDao.findById(snapshot.getVolumeId()); - - // check permissions - _accountMgr.checkAccess(caller, null, true, snapshot); - - if (snapshot.getState() != Snapshot.State.BackedUp) { - throw new InvalidParameterValueException("Snapshot id=" + snapshotId + " is not in " + Snapshot.State.BackedUp + " state yet and can't be used for template creation"); - } - - /* - * // bug #11428. Operation not supported if vmware and snapshots - * parent volume = ROOT if(snapshot.getHypervisorType() == - * HypervisorType.VMware && snapshotVolume.getVolumeType() == - * Type.DATADISK){ throw new UnsupportedServiceException( - * "operation not supported, snapshot with id " + snapshotId + - * " is created from Data Disk"); } - */ - - hyperType = snapshot.getHypervisorType(); - } - - _resourceLimitMgr.checkResourceLimit(templateOwner, - ResourceType.template); - - if (!isAdmin || featured == null) { - featured = Boolean.FALSE; - } - Long guestOSId = cmd.getOsTypeId(); - GuestOSVO guestOS = _guestOSDao.findById(guestOSId); - if (guestOS == null) { - throw new InvalidParameterValueException("GuestOS with ID: " - + guestOSId + " does not exist."); - } - - String uniqueName = Long.valueOf((userId == null) ? 1 : userId) - .toString() - + UUID.nameUUIDFromBytes(name.getBytes()).toString(); - Long nextTemplateId = _templateDao.getNextInSequence(Long.class, "id"); - String description = cmd.getDisplayText(); - boolean isExtractable = false; - Long sourceTemplateId = null; - if (volume != null) { - VMTemplateVO template = ApiDBUtils.findTemplateById(volume - .getTemplateId()); - isExtractable = template != null - && template.isExtractable() - && template.getTemplateType() != Storage.TemplateType.SYSTEM; - if (template != null) { - sourceTemplateId = template.getId(); - } else if (volume.getVolumeType() == Type.ROOT) { // vm created out - // of blank - // template - UserVm userVm = ApiDBUtils.findUserVmById(volume - .getInstanceId()); - sourceTemplateId = userVm.getIsoId(); - } - } - String templateTag = cmd.getTemplateTag(); - if (templateTag != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Adding template tag: " + templateTag); - } - } - privateTemplate = new VMTemplateVO(nextTemplateId, uniqueName, name, - ImageFormat.RAW, isPublic, featured, isExtractable, - TemplateType.USER, null, null, requiresHvmValue, bitsValue, - templateOwner.getId(), null, description, passwordEnabledValue, - guestOS.getId(), true, hyperType, templateTag, cmd.getDetails()); - if (sourceTemplateId != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("This template is getting created from other template, setting source template Id to: " - + sourceTemplateId); - } - } - privateTemplate.setSourceTemplateId(sourceTemplateId); - - VMTemplateVO template = _templateDao.persist(privateTemplate); - // Increment the number of templates - if (template != null) { - if (cmd.getDetails() != null) { - _templateDetailsDao.persist(template.getId(), cmd.getDetails()); - } - - _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), - ResourceType.template); - } - - if (template != null) { - return template; - } else { - throw new CloudRuntimeException("Failed to create a template"); - } - - } - - @Override - @DB - @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", async = true) - public VMTemplateVO createPrivateTemplate(CreateTemplateCmd command) - throws CloudRuntimeException { - Long userId = UserContext.current().getCallerUserId(); - if (userId == null) { - userId = User.UID_SYSTEM; - } - long templateId = command.getEntityId(); - Long volumeId = command.getVolumeId(); - Long snapshotId = command.getSnapshotId(); - SnapshotCommand cmd = null; - VMTemplateVO privateTemplate = null; - - String uniqueName = getRandomPrivateTemplateName(); - - StoragePoolVO pool = null; - HostVO secondaryStorageHost = null; - Long zoneId = null; - Long accountId = null; - SnapshotVO snapshot = null; - String secondaryStorageURL = null; - try { - if (snapshotId != null) { // create template from snapshot - snapshot = _snapshotDao.findById(snapshotId); - if (snapshot == null) { - throw new CloudRuntimeException( - "Unable to find Snapshot for Id " + snapshotId); - } - zoneId = snapshot.getDataCenterId(); - secondaryStorageHost = _snapshotMgr - .getSecondaryStorageHost(snapshot); - secondaryStorageURL = _snapshotMgr - .getSecondaryStorageURL(snapshot); - String name = command.getTemplateName(); - String backupSnapshotUUID = snapshot.getBackupSnapshotId(); - if (backupSnapshotUUID == null) { - throw new CloudRuntimeException( - "Unable to create private template from snapshot " - + snapshotId - + " due to there is no backupSnapshotUUID for this snapshot"); - } - - Long dcId = snapshot.getDataCenterId(); - accountId = snapshot.getAccountId(); - volumeId = snapshot.getVolumeId(); - - String origTemplateInstallPath = null; - List pools = _storageMgr - .ListByDataCenterHypervisor(zoneId, - snapshot.getHypervisorType()); - if (pools == null || pools.size() == 0) { - throw new CloudRuntimeException( - "Unable to find storage pools in zone " + zoneId); - } - pool = pools.get(0); - if (snapshot.getVersion() != null - && snapshot.getVersion().equalsIgnoreCase("2.1")) { - VolumeVO volume = _volsDao - .findByIdIncludingRemoved(volumeId); - if (volume == null) { - throw new CloudRuntimeException( - "failed to upgrade snapshot " - + snapshotId - + " due to unable to find orignal volume:" - + volumeId + ", try it later "); - } - if (volume.getTemplateId() == null) { - _snapshotDao.updateSnapshotVersion(volumeId, "2.1", - "2.2"); - } else { - VMTemplateVO template = _templateDao - .findByIdIncludingRemoved(volume - .getTemplateId()); - if (template == null) { - throw new CloudRuntimeException( - "failed to upgrade snapshot " - + snapshotId - + " due to unalbe to find orignal template :" - + volume.getTemplateId() - + ", try it later "); - } - Long origTemplateId = template.getId(); - Long origTmpltAccountId = template.getAccountId(); - if (!_volsDao.lockInLockTable(volumeId.toString(), 10)) { - throw new CloudRuntimeException( - "failed to upgrade snapshot " + snapshotId - + " due to volume:" + volumeId - + " is being used, try it later "); - } - cmd = new UpgradeSnapshotCommand(null, - secondaryStorageURL, dcId, accountId, volumeId, - origTemplateId, origTmpltAccountId, null, - snapshot.getBackupSnapshotId(), - snapshot.getName(), "2.1"); - if (!_volsDao.lockInLockTable(volumeId.toString(), 10)) { - throw new CloudRuntimeException( - "Creating template failed due to volume:" - + volumeId - + " is being used, try it later "); - } - Answer answer = null; - try { - answer = _storageMgr.sendToPool(pool, cmd); - cmd = null; - } catch (StorageUnavailableException e) { - } finally { - _volsDao.unlockFromLockTable(volumeId.toString()); - } - if ((answer != null) && answer.getResult()) { - _snapshotDao.updateSnapshotVersion(volumeId, "2.1", - "2.2"); - } else { - throw new CloudRuntimeException( - "Unable to upgrade snapshot"); - } - } - } - if (snapshot.getSwiftId() != null && snapshot.getSwiftId() != 0) { - _snapshotMgr.downloadSnapshotsFromSwift(snapshot); - } - cmd = new CreatePrivateTemplateFromSnapshotCommand(pool, secondaryStorageURL, dcId, accountId, snapshot.getVolumeId(), backupSnapshotUUID, snapshot.getName(), - origTemplateInstallPath, templateId, name, _createprivatetemplatefromsnapshotwait); - } else if (volumeId != null) { - VolumeVO volume = _volsDao.findById(volumeId); - if (volume == null) { - throw new CloudRuntimeException( - "Unable to find volume for Id " + volumeId); - } - accountId = volume.getAccountId(); - - if (volume.getPoolId() == null) { - _templateDao.remove(templateId); - throw new CloudRuntimeException("Volume " + volumeId - + " is empty, can't create template on it"); - } - String vmName = _storageMgr.getVmNameOnVolume(volume); - zoneId = volume.getDataCenterId(); - secondaryStorageHost = _storageMgr - .getSecondaryStorageHost(zoneId); - if (secondaryStorageHost == null) { - throw new CloudRuntimeException( - "Can not find the secondary storage for zoneId " - + zoneId); - } - secondaryStorageURL = secondaryStorageHost.getStorageUrl(); - - pool = _storagePoolDao.findById(volume.getPoolId()); - cmd = new CreatePrivateTemplateFromVolumeCommand(pool, secondaryStorageURL, templateId, accountId, command.getTemplateName(), uniqueName, volume.getPath(), vmName, _createprivatetemplatefromvolumewait); - - } else { - throw new CloudRuntimeException( - "Creating private Template need to specify snapshotId or volumeId"); - } - // FIXME: before sending the command, check if there's enough - // capacity - // on the storage server to create the template - - // This can be sent to a KVM host too. - CreatePrivateTemplateAnswer answer = null; - if (snapshotId != null) { - if (!_snapshotDao.lockInLockTable(snapshotId.toString(), 10)) { - throw new CloudRuntimeException( - "Creating template from snapshot failed due to snapshot:" - + snapshotId - + " is being used, try it later "); - } - } else { - if (!_volsDao.lockInLockTable(volumeId.toString(), 10)) { - throw new CloudRuntimeException( - "Creating template from volume failed due to volume:" - + volumeId - + " is being used, try it later "); - } - } - try { - answer = (CreatePrivateTemplateAnswer) _storageMgr.sendToPool( - pool, cmd); - } catch (StorageUnavailableException e) { - } finally { - if (snapshotId != null) { - _snapshotDao.unlockFromLockTable(snapshotId.toString()); - } else { - _volsDao.unlockFromLockTable(volumeId.toString()); - } - } - if ((answer != null) && answer.getResult()) { - privateTemplate = _templateDao.findById(templateId); - String answerUniqueName = answer.getUniqueName(); - if (answerUniqueName != null) { - privateTemplate.setUniqueName(answerUniqueName); - } else { - privateTemplate.setUniqueName(uniqueName); - } - ImageFormat format = answer.getImageFormat(); - if (format != null) { - privateTemplate.setFormat(format); - } else { - // This never occurs. - // Specify RAW format makes it unusable for snapshots. - privateTemplate.setFormat(ImageFormat.RAW); - } - - String checkSum = getChecksum(secondaryStorageHost.getId(), - answer.getPath()); - - Transaction txn = Transaction.currentTxn(); - - txn.start(); - - privateTemplate.setChecksum(checkSum); - _templateDao.update(templateId, privateTemplate); - - // add template zone ref for this template - _templateDao.addTemplateToZone(privateTemplate, zoneId); - VMTemplateHostVO templateHostVO = new VMTemplateHostVO( - secondaryStorageHost.getId(), templateId); - templateHostVO.setDownloadPercent(100); - templateHostVO.setDownloadState(Status.DOWNLOADED); - templateHostVO.setInstallPath(answer.getPath()); - templateHostVO.setLastUpdated(new Date()); - templateHostVO.setSize(answer.getVirtualSize()); - templateHostVO.setPhysicalSize(answer.getphysicalSize()); - _templateHostDao.persist(templateHostVO); - - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_TEMPLATE_CREATE, privateTemplate.getAccountId(), - secondaryStorageHost.getDataCenterId(), privateTemplate.getId(), - privateTemplate.getName(), null, privateTemplate.getSourceTemplateId(), - templateHostVO.getSize(), VirtualMachineTemplate.class.getName(), privateTemplate.getUuid()); - txn.commit(); - } - } finally { - if (snapshot != null && snapshot.getSwiftId() != null - && secondaryStorageURL != null && zoneId != null - && accountId != null && volumeId != null) { - _snapshotMgr.deleteSnapshotsForVolume(secondaryStorageURL, - zoneId, accountId, volumeId); - } - if (privateTemplate == null) { - Transaction txn = Transaction.currentTxn(); - txn.start(); - // Remove the template record - _templateDao.expunge(templateId); - - // decrement resource count - if (accountId != null) { - _resourceLimitMgr.decrementResourceCount(accountId, - ResourceType.template); - } - txn.commit(); - } - } - - if (privateTemplate != null) { - return privateTemplate; - } else { - throw new CloudRuntimeException("Failed to create a template"); - } - } - - @Override - public String getChecksum(Long hostId, String templatePath) { - HostVO ssHost = _hostDao.findById(hostId); - Host.Type type = ssHost.getType(); - if (type != Host.Type.SecondaryStorage - && type != Host.Type.LocalSecondaryStorage) { - return null; - } - String secUrl = ssHost.getStorageUrl(); - Answer answer; - answer = _agentMgr.sendToSecStorage(ssHost, new ComputeChecksumCommand( - secUrl, templatePath)); - if (answer != null && answer.getResult()) { - return answer.getDetails(); - } - return null; - } - // used for vm transitioning to error state private void updateVmStateForFailedVmCreation(Long vmId, Long hostId) { @@ -2449,14 +1387,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use List volumesForThisVm = _volsDao .findUsableVolumesForInstance(vm.getId()); for (VolumeVO volume : volumesForThisVm) { - try { - if (volume.getState() != Volume.State.Destroy) { - _storageMgr.destroyVolume(volume); - } - } catch (ConcurrentOperationException e) { - s_logger.warn("Unable to delete volume:" - + volume.getId() + " for vm:" + vmId - + " whilst transitioning to error state"); + if (volume.getState() != Volume.State.Destroy) { + this.volumeMgr.destroyVolume(volume); } } String msg = "Failed to deploy Vm with Id: " + vmId + ", on Host with Id: " + hostId; @@ -3577,7 +2509,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use + vm.getIsoId()); } - Pair isoPathPair = _storageMgr.getAbsoluteIsoPath( + Pair isoPathPair = this.templateMgr.getAbsoluteIsoPath( template.getId(), vm.getDataCenterId()); if (template.getTemplateType() == TemplateType.PERHOST) { @@ -4893,22 +3825,20 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use /* If new template is provided allocate a new volume from new template otherwise allocate new volume from original template */ VolumeVO newVol = null; if (newTemplateId != null){ - newVol = _storageMgr.allocateDuplicateVolume(root, newTemplateId); + newVol = volumeMgr.allocateDuplicateVolume(root, newTemplateId); vm.setGuestOSId(template.getGuestOSId()); vm.setTemplateId(newTemplateId); _vmDao.update(vmId, vm); - } else newVol = _storageMgr.allocateDuplicateVolume(root, null); + } else { + newVol = volumeMgr.allocateDuplicateVolume(root, null); + } _volsDao.attachVolume(newVol.getId(), vmId, newVol.getDeviceId()); /* Detach and destory the old root volume */ - try { - _volsDao.detachVolume(root.getId()); - _storageMgr.destroyVolume(root); - } catch (ConcurrentOperationException e) { - s_logger.debug("Unable to delete old root volume " + root.getId() - + ", user may manually delete it", e); - } + + _volsDao.detachVolume(root.getId()); + this.volumeMgr.destroyVolume(root); if (needRestart) { try { diff --git a/server/src/com/cloud/vm/VirtualMachineManager.java b/server/src/com/cloud/vm/VirtualMachineManager.java index 6a959fcefb6..7b34f7f0616 100644 --- a/server/src/com/cloud/vm/VirtualMachineManager.java +++ b/server/src/com/cloud/vm/VirtualMachineManager.java @@ -20,6 +20,7 @@ import java.net.URI; import java.util.List; import java.util.Map; + import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; import com.cloud.deploy.DeployDestination; diff --git a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java index d0a2305ecab..5d48f146769 100755 --- a/server/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -36,6 +36,7 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager; import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; @@ -118,10 +119,10 @@ import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; -import com.cloud.storage.StoragePoolVO; import com.cloud.storage.VMTemplateVO; import com.cloud.storage.Volume; import com.cloud.storage.Volume.Type; +import com.cloud.storage.VolumeManager; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; @@ -164,6 +165,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected StorageManager _storageMgr; @Inject + DataStoreManager dataStoreMgr; + @Inject protected NetworkManager _networkMgr; @Inject protected NetworkModel _networkModel; @@ -232,6 +235,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac @Inject protected ConfigurationDao _configDao; + @Inject + VolumeManager volumeMgr; Map> _vmGurus = new HashMap>(); protected StateMachine2 _stateMachine; @@ -298,15 +303,15 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } if (template.getFormat() == ImageFormat.ISO) { - _storageMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner); + this.volumeMgr.allocateRawVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner); } else if (template.getFormat() == ImageFormat.BAREMETAL) { // Do nothing } else { - _storageMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner); + this.volumeMgr.allocateTemplatedVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner); } for (Pair offering : dataDiskOfferings) { - _storageMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner); + this.volumeMgr.allocateRawVolume(Type.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner); } txn.commit(); @@ -394,7 +399,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.debug("Cleaning up NICS"); _networkMgr.cleanupNics(profile); // Clean up volumes based on the vm's instance id - _storageMgr.cleanupVolumes(vm.getId()); + this.volumeMgr.cleanupVolumes(vm.getId()); VirtualMachineGuru guru = getVmGuru(vm); guru.finalizeExpunge(vm); @@ -661,7 +666,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac continue; } - StoragePoolVO pool = _storagePoolDao.findById(vol.getPoolId()); + StoragePool pool = (StoragePool)dataStoreMgr.getPrimaryDataStore(vol.getPoolId()); if (!pool.isInMaintenance()) { if (s_logger.isDebugEnabled()) { s_logger.debug("Root volume is ready, need to place VM in volume's cluster"); @@ -738,7 +743,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } _networkMgr.prepare(vmProfile, dest, ctx); if (vm.getHypervisorType() != HypervisorType.BareMetal) { - _storageMgr.prepare(vmProfile, dest); + this.volumeMgr.prepare(vmProfile, dest); } //since StorageMgr succeeded in volume creation, reuse Volume for further tries until current cluster has capacity if(!reuseVolume){ @@ -953,7 +958,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac s_logger.warn("Unable to release some network resources.", e); } - _storageMgr.release(profile); + this.volumeMgr.release(profile); s_logger.debug("Successfully cleanued up resources for the vm " + vm + " in " + state + " state"); return true; } @@ -1102,7 +1107,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac try { if (vm.getHypervisorType() != HypervisorType.BareMetal) { - _storageMgr.release(profile); + this.volumeMgr.release(profile); s_logger.debug("Successfully released storage resources for the vm " + vm); } } catch (Exception e) { @@ -1221,7 +1226,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); boolean migrationResult = false; try { - migrationResult = _storageMgr.StorageMigration(profile, destPool); + migrationResult = this.volumeMgr.StorageMigration(profile, destPool); if (migrationResult) { //if the vm is migrated to different pod in basic mode, need to reallocate ip @@ -1306,7 +1311,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); _networkMgr.prepareNicForMigration(profile, dest); - _storageMgr.prepareForMigration(profile, dest); + this.volumeMgr.prepareForMigration(profile, dest); VirtualMachineTO to = toVmTO(profile); PrepareForMigrationCommand pfmc = new PrepareForMigrationCommand(to); diff --git a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java index e83d6a0d926..eb9e5ad29c2 100644 --- a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java +++ b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + import com.cloud.agent.api.to.VolumeTO; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.offering.ServiceOffering; diff --git a/server/test/com/cloud/vm/MockUserVmManagerImpl.java b/server/test/com/cloud/vm/MockUserVmManagerImpl.java index 1ee627fb738..09825a8eeb6 100644 --- a/server/test/com/cloud/vm/MockUserVmManagerImpl.java +++ b/server/test/com/cloud/vm/MockUserVmManagerImpl.java @@ -25,7 +25,6 @@ import javax.naming.ConfigurationException; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.template.CreateTemplateCmd; import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; @@ -40,8 +39,6 @@ import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; -import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; -import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; import org.springframework.stereotype.Component; import com.cloud.agent.api.StopAnswer; @@ -69,7 +66,6 @@ import com.cloud.offering.ServiceOffering; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.server.Criteria; import com.cloud.storage.StoragePool; -import com.cloud.storage.Volume; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -155,11 +151,6 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override - public boolean attachISOToVM(long vmId, long isoId, boolean attach) { - // TODO Auto-generated method stub - return false; - } @Override public boolean stopVirtualMachine(long userId, long vmId) { @@ -209,12 +200,6 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override - public String getChecksum(Long hostId, String templatePath) { - // TODO Auto-generated method stub - return null; - } - @Override public boolean configure(String name, Map params) throws ConfigurationException { return true; @@ -255,24 +240,6 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override - public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException { - // TODO Auto-generated method stub - return null; - } - - @Override - public Volume attachVolumeToVM(AttachVolumeCmd cmd) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) { - // TODO Auto-generated method stub - return null; - } - @Override public UserVm startVirtualMachine(StartVMCmd cmd) throws StorageUnavailableException, ExecutionException, ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException, ResourceAllocationException { @@ -316,18 +283,6 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return null; } - @Override - public VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { - // TODO Auto-generated method stub - return null; - } - - @Override - public VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd cmd) { - // TODO Auto-generated method stub - return null; - } - @Override public UserVm startVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException { // TODO Auto-generated method stub @@ -469,4 +424,9 @@ public class MockUserVmManagerImpl extends ManagerBase implements UserVmManager, return false; } + @Override + public UserVm resetVMSSHKey(ResetVMSSHKeyCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException { + // TODO Auto-generated method stub + return null; + } } diff --git a/setup/db/templates.sql b/setup/db/templates.sql index 9980b159630..7abc92da63b 100755 --- a/setup/db/templates.sql +++ b/setup/db/templates.sql @@ -15,28 +15,28 @@ -- specific language governing permissions and limitations -- under the License. -INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type) - VALUES (1, UUID(), 'routing-1', 'SystemVM Template (XenServer)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.vhd.bz2', 'f613f38c96bf039f2e5cbf92fa8ad4f8', 0, 'SystemVM Template (XenServer)', 'VHD', 133, 0, 1, 'XenServer'); -INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, removed, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable) - VALUES (2, UUID(), 'centos53-x86_64', 'CentOS 5.3(64-bit) no GUI (XenServer)', 1, now(), now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/templates/builtin/f59f18fb-ae94-4f97-afd2-f84755767aca.vhd.bz2', 'b63d854a9560c013142567bbae8d98cf', 0, 'CentOS 5.3(64-bit) no GUI (XenServer)', 'VHD', 12, 1, 1, 'XenServer', 1); +INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, image_data_store_id) + VALUES (1, UUID(), 'routing-1', 'SystemVM Template (XenServer)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.vhd.bz2', 'f613f38c96bf039f2e5cbf92fa8ad4f8', 0, 'SystemVM Template (XenServer)', 'VHD', 133, 0, 1, 'XenServer', 1); +INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, removed, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable, image_data_store_id) + VALUES (2, UUID(), 'centos53-x86_64', 'CentOS 5.3(64-bit) no GUI (XenServer)', 1, now(), now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/templates/builtin/f59f18fb-ae94-4f97-afd2-f84755767aca.vhd.bz2', 'b63d854a9560c013142567bbae8d98cf', 0, 'CentOS 5.3(64-bit) no GUI (XenServer)', 'VHD', 12, 1, 1, 'XenServer', 1, 1); -INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type) - VALUES (3, UUID(), 'routing-3', 'SystemVM Template (KVM)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.qcow2.bz2', '2755de1f9ef2ce4d6f2bee2efbb4da92', 0, 'SystemVM Template (KVM)', 'QCOW2', 15, 0, 1, 'KVM'); +INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, image_data_store_id) + VALUES (3, UUID(), 'routing-3', 'SystemVM Template (KVM)', 0, now(), 'SYSTEM', 0, 64, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.qcow2.bz2', '2755de1f9ef2ce4d6f2bee2efbb4da92', 0, 'SystemVM Template (KVM)', 'QCOW2', 15, 0, 1, 'KVM', 1); -INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, display_text, enable_password, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable) - VALUES (4, UUID(), 'centos55-x86_64', 'CentOS 5.5(64-bit) no GUI (KVM)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/releases/2.2.0/eec2209b-9875-3c8d-92be-c001bd8a0faf.qcow2.bz2', 'ed0e788280ff2912ea40f7f91ca7a249', 'CentOS 5.5(64-bit) no GUI (KVM)', 0, 'QCOW2', 112, 1, 1, 'KVM', 1); +INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, display_text, enable_password, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable, image_data_store_id) + VALUES (4, UUID(), 'centos55-x86_64', 'CentOS 5.5(64-bit) no GUI (KVM)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/releases/2.2.0/eec2209b-9875-3c8d-92be-c001bd8a0faf.qcow2.bz2', 'ed0e788280ff2912ea40f7f91ca7a249', 'CentOS 5.5(64-bit) no GUI (KVM)', 0, 'QCOW2', 112, 1, 1, 'KVM', 1, 1); -INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable) - VALUES (5, UUID(), 'centos56-x86_64-xen', 'CentOS 5.6(64-bit) no GUI (XenServer)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/templates/builtin/centos56-x86_64.vhd.bz2', '905cec879afd9c9d22ecc8036131a180', 0, 'CentOS 5.6(64-bit) no GUI (XenServer)', 'VHD', 12, 1, 1, 'XenServer', 1); +INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable, image_data_store_id) + VALUES (5, UUID(), 'centos56-x86_64-xen', 'CentOS 5.6(64-bit) no GUI (XenServer)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/templates/builtin/centos56-x86_64.vhd.bz2', '905cec879afd9c9d22ecc8036131a180', 0, 'CentOS 5.6(64-bit) no GUI (XenServer)', 'VHD', 12, 1, 1, 'XenServer', 1, 1); -INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable) - VALUES (7, UUID(), 'centos53-x64', 'CentOS 5.3(64-bit) no GUI (vSphere)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/releases/2.2.0/CentOS5.3-x86_64.ova', 'f6f881b7f2292948d8494db837fe0f47', 0, 'CentOS 5.3(64-bit) no GUI (vSphere)', 'OVA', 12, 1, 1, 'VMware', 1); +INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, extractable, image_data_store_id) + VALUES (7, UUID(), 'centos53-x64', 'CentOS 5.3(64-bit) no GUI (vSphere)', 1, now(), 'BUILTIN', 0, 64, 1, 'http://download.cloud.com/releases/2.2.0/CentOS5.3-x86_64.ova', 'f6f881b7f2292948d8494db837fe0f47', 0, 'CentOS 5.3(64-bit) no GUI (vSphere)', 'OVA', 12, 1, 1, 'VMware', 1, 1); -INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type) - VALUES (8, UUID(), 'routing-8', 'SystemVM Template (vSphere)', 0, now(), 'SYSTEM', 0, 32, 1, 'http://download.cloud.com/templates/burbank/burbank-systemvm-08012012.ova', '7137e453f950079ea2ba6feaafd939e8', 0, 'SystemVM Template (vSphere)', 'OVA', 15, 0, 1, 'VMware'); +INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, image_data_store_id) + VALUES (8, UUID(), 'routing-8', 'SystemVM Template (vSphere)', 0, now(), 'SYSTEM', 0, 32, 1, 'http://download.cloud.com/templates/burbank/burbank-systemvm-08012012.ova', '7137e453f950079ea2ba6feaafd939e8', 0, 'SystemVM Template (vSphere)', 'OVA', 15, 0, 1, 'VMware', 1); -INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type) - VALUES (9, UUID(), 'routing-9', 'SystemVM Template (HyperV)', 0, now(), 'SYSTEM', 0, 32, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.vhd.bz2', 'f613f38c96bf039f2e5cbf92fa8ad4f8', 0, 'SystemVM Template (HyperV)', 'VHD', 15, 0, 1, 'Hyperv'); +INSERT INTO `cloud`.`vm_template` (id, uuid, unique_name, name, public, created, type, hvm, bits, account_id, url, checksum, enable_password, display_text, format, guest_os_id, featured, cross_zones, hypervisor_type, image_data_store_id) + VALUES (9, UUID(), 'routing-9', 'SystemVM Template (HyperV)', 0, now(), 'SYSTEM', 0, 32, 1, 'http://download.cloud.com/templates/acton/acton-systemvm-02062012.vhd.bz2', 'f613f38c96bf039f2e5cbf92fa8ad4f8', 0, 'SystemVM Template (HyperV)', 'VHD', 15, 0, 1, 'Hyperv', 1); INSERT INTO `cloud`.`guest_os_category` (id, uuid, name) VALUES (1, UUID(), 'CentOS'); INSERT INTO `cloud`.`guest_os_category` (id, uuid, name) VALUES (2, UUID(), 'Debian');