From d3b8e748a6ccc0d1be13c4d696d08060022e15c5 Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 7 Jun 2021 02:58:34 -0400 Subject: [PATCH 01/58] API command initialization --- .../api/command/user/vm/CloneVMCmd.java | 39 +++++++++++++++++++ .../cloud/server/ManagementServerImpl.java | 22 +---------- 2 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java new file mode 100644 index 000000000000..b02e6f9f3749 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -0,0 +1,39 @@ +package org.apache.cloudstack.api.command.user.vm; + +import com.cloud.exception.*; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.ResponseObject; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.user.UserCmd; +import org.apache.cloudstack.api.response.UserVmResponse; + +@APICommand(name = "cloneVirtualMachine", responseObject = UserVmResponse.class, description = "clone a virtual VM in full clone mode", + responseView = ResponseObject.ResponseView.Restricted, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true) +public class CloneVMCmd extends BaseAsyncCmd implements UserCmd { + + @Override + public String getEventType() { + return null; + } + + @Override + public String getEventDescription() { + return null; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + + } + + @Override + public String getCommandName() { + return null; + } + + @Override + public long getEntityOwnerId() { + return 0; + } +} diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 18afeb42a929..f4f67c89f3db 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -465,26 +465,7 @@ import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd; -import org.apache.cloudstack.api.command.user.vm.AddIpToVmNicCmd; -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; -import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd; -import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; -import org.apache.cloudstack.api.command.user.vm.ListVMsCmd; -import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; -import org.apache.cloudstack.api.command.user.vm.RemoveIpFromVmNicCmd; -import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; -import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; -import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; -import org.apache.cloudstack.api.command.user.vm.StartVMCmd; -import org.apache.cloudstack.api.command.user.vm.StopVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd; -import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; +import org.apache.cloudstack.api.command.user.vm.*; 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.vmgroup.ListVMGroupsCmd; @@ -2797,6 +2778,7 @@ public long getMemoryOrCpuCapacityByHost(final Long hostId, final short capacity @Override public List> getCommands() { final List> cmdList = new ArrayList>(); + cmdList.add(CloneVMCmd.class); cmdList.add(CreateAccountCmd.class); cmdList.add(DeleteAccountCmd.class); cmdList.add(DisableAccountCmd.class); From e2f72280eb8d56ea01dd4c7e7c14a117897147aa Mon Sep 17 00:00:00 2001 From: junxuan Date: Thu, 10 Jun 2021 19:32:25 -0400 Subject: [PATCH 02/58] first step to create the clone api execution --- .../main/java/com/cloud/event/EventTypes.java | 1 + .../api/command/user/vm/CloneVMCmd.java | 52 ++++++++++++++++--- .../cloud/server/ManagementServerImpl.java | 24 ++++++++- 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index ebe7590fd5f6..3eb0b8dda86c 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -105,6 +105,7 @@ public class EventTypes { public static final String EVENT_VM_IMPORT = "VM.IMPORT"; public static final String EVENT_VM_UNMANAGE = "VM.UNMANAGE"; public static final String EVENT_VM_RECOVER = "VM.RECOVER"; + public static final String EVENT_VM_CLONE = "VM.CLONE"; // Domain Router public static final String EVENT_ROUTER_CREATE = "ROUTER.CREATE"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index b02e6f9f3749..de241b2c8cae 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -1,39 +1,77 @@ package org.apache.cloudstack.api.command.user.vm; -import com.cloud.exception.*; +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import com.cloud.uservm.UserVm; +import com.cloud.vm.VirtualMachine; +import org.apache.cloudstack.acl.SecurityChecker.AccessType; +import org.apache.cloudstack.api.ACL; import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandJobType; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ResponseObject; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.command.user.UserCmd; import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.log4j.Logger; @APICommand(name = "cloneVirtualMachine", responseObject = UserVmResponse.class, description = "clone a virtual VM in full clone mode", - responseView = ResponseObject.ResponseView.Restricted, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true) + responseView = ResponseObject.ResponseView.Restricted, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true, entityType = {VirtualMachine.class}) public class CloneVMCmd extends BaseAsyncCmd implements UserCmd { + public static final Logger s_logger = Logger.getLogger(CloneVMCmd.class.getName()); + private static final String s_name = "clonevirtualmachineresponse"; + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @ACL(accessType = AccessType.OperateEntry) + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType=UserVmResponse.class, + required = true, description = "The ID of the virtual machine") + private Long id; + + public Long getId() { + return this.id; + } @Override public String getEventType() { - return null; + return EventTypes.EVENT_VM_CLONE; + } + + @Override + public ApiCommandJobType getInstanceType() { + return ApiCommandJobType.VirtualMachine; } @Override public String getEventDescription() { - return null; + return "Cloning user VM: " + this._uuidMgr.getUuid(VirtualMachine.class, getId()); } @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { - + UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", null).get(0); + response.setResponseName("test_clone"); + setResponseObject(response); } @Override public String getCommandName() { - return null; + return s_name; } @Override public long getEntityOwnerId() { - return 0; + UserVm vm = this._responseGenerator.findUserVmById(getId()); + if (vm != null) { + return vm.getAccountId(); + } + return Account.ACCOUNT_ID_SYSTEM; } } diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index f4f67c89f3db..dde9906073d4 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -465,7 +465,27 @@ import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd; -import org.apache.cloudstack.api.command.user.vm.*; +import org.apache.cloudstack.api.command.user.vm.AddIpToVmNicCmd; +import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; +import org.apache.cloudstack.api.command.user.vm.CloneVMCmd; +import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; +import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; +import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ListNicsCmd; +import org.apache.cloudstack.api.command.user.vm.ListVMsCmd; +import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveIpFromVmNicCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; +import org.apache.cloudstack.api.command.user.vm.StartVMCmd; +import org.apache.cloudstack.api.command.user.vm.StopVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd; +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.vmgroup.ListVMGroupsCmd; @@ -2778,7 +2798,6 @@ public long getMemoryOrCpuCapacityByHost(final Long hostId, final short capacity @Override public List> getCommands() { final List> cmdList = new ArrayList>(); - cmdList.add(CloneVMCmd.class); cmdList.add(CreateAccountCmd.class); cmdList.add(DeleteAccountCmd.class); cmdList.add(DisableAccountCmd.class); @@ -3064,6 +3083,7 @@ public List> getCommands() { cmdList.add(ExpungeVMCmd.class); cmdList.add(GetVMPasswordCmd.class); cmdList.add(ListVMsCmd.class); + cmdList.add(CloneVMCmd.class); cmdList.add(ScaleVMCmd.class); cmdList.add(RebootVMCmd.class); cmdList.add(RemoveNicFromVMCmd.class); From 6b2604d1ba86f9dcecbdd5d7ca89a6dbb877ad23 Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 18 Jun 2021 03:40:07 -0400 Subject: [PATCH 03/58] add findISO and findVO steps --- .../main/java/com/cloud/vm/UserVmService.java | 25 ++++++------- .../api/command/user/vm/CloneVMCmd.java | 35 ++++++++++++------- .../java/com/cloud/vm/UserVmManagerImpl.java | 35 +++++-------------- 3 files changed, 43 insertions(+), 52 deletions(-) diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index 0b48a4867c00..c3d0a59f0b7f 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -18,24 +18,12 @@ import java.util.List; import java.util.Map; +import java.util.Optional; import org.apache.cloudstack.api.BaseCmd.HTTPMethod; 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.vm.AddNicToVMCmd; -import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; -import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; -import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; -import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; -import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; -import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; -import org.apache.cloudstack.api.command.user.vm.StartVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd; -import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; +import org.apache.cloudstack.api.command.user.vm.*; import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd; import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd; @@ -85,6 +73,15 @@ public interface UserVmService { */ UserVm destroyVm(long vmId, boolean expunge) throws ResourceUnavailableException, ConcurrentOperationException; + /** + * Clone a specific VM (full clone) + * + * @param cmd + * - the command specifying vmId to be cloned + * @return the VM if cloneVM operation is successful + * */ + Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException; + /** * Resets the password of a virtual machine. * diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index de241b2c8cae..6efb3502aa0e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -10,18 +10,14 @@ import com.cloud.uservm.UserVm; import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.ACL; -import org.apache.cloudstack.api.APICommand; -import org.apache.cloudstack.api.ApiCommandJobType; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseAsyncCmd; -import org.apache.cloudstack.api.Parameter; -import org.apache.cloudstack.api.ResponseObject; -import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.*; import org.apache.cloudstack.api.command.user.UserCmd; import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; +import java.util.Optional; + @APICommand(name = "cloneVirtualMachine", responseObject = UserVmResponse.class, description = "clone a virtual VM in full clone mode", responseView = ResponseObject.ResponseView.Restricted, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true, entityType = {VirtualMachine.class}) public class CloneVMCmd extends BaseAsyncCmd implements UserCmd { @@ -55,10 +51,25 @@ public String getEventDescription() { } @Override - public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { - UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", null).get(0); - response.setResponseName("test_clone"); - setResponseObject(response); + public void execute() { + Optional result; + try { + CallContext.current().setEventDetails("Vm Id for full clone: " + getId()); + result = _userVmService.cloneVirtualMachine(this); + } catch (ResourceUnavailableException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); + } catch (ConcurrentOperationException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); + } + result.ifPresentOrElse((userVm)-> { + UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", userVm).get(0); + response.setResponseName("test_clone"); + setResponseObject(response); + }, ()-> { + throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, "failed to clone VM: " + getId()); + }); } @Override diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 14cdae66d28e..11f1a2776406 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -22,18 +22,8 @@ import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -63,21 +53,7 @@ import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.DeployVMCmdByAdmin; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -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; -import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; -import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; -import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; -import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; -import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; -import org.apache.cloudstack.api.command.user.vm.SecurityGroupAction; -import org.apache.cloudstack.api.command.user.vm.StartVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; -import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd; -import org.apache.cloudstack.api.command.user.vm.UpgradeVMCmd; +import org.apache.cloudstack.api.command.user.vm.*; 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.ResizeVolumeCmd; @@ -4499,6 +4475,13 @@ protected String validateUserData(String userData, HTTPMethod httpmethod) { return null; } + @Override + @ActionEvent(eventType = EventTypes.EVENT_VM_CLONE, eventDescription = "clone vm", async = true) + public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException { + VolumeVO volumeInformation = _volsDao.findByUuid(""); + return Optional.ofNullable(null); + } + @Override @ActionEvent(eventType = EventTypes.EVENT_VM_CREATE, eventDescription = "starting Vm", async = true) public UserVm startVirtualMachine(DeployVMCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException { From 8c815aba944108470221e82081b4a70edd9f97dd Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 21 Jun 2021 04:03:04 -0400 Subject: [PATCH 04/58] add creation of root-disk -> template -> vm step --- .../cloud/template/TemplateApiService.java | 9 ++++ .../main/java/com/cloud/vm/UserVmService.java | 18 ++++++- .../api/command/user/vm/CloneVMCmd.java | 35 ++++++++++++-- .../cloud/template/TemplateManagerImpl.java | 11 +++++ .../java/com/cloud/vm/UserVmManagerImpl.java | 48 +++++++++++++++++-- 5 files changed, 112 insertions(+), 9 deletions(-) diff --git a/api/src/main/java/com/cloud/template/TemplateApiService.java b/api/src/main/java/com/cloud/template/TemplateApiService.java index ea818a55a0cc..bcda2bc2f2dc 100644 --- a/api/src/main/java/com/cloud/template/TemplateApiService.java +++ b/api/src/main/java/com/cloud/template/TemplateApiService.java @@ -20,6 +20,7 @@ import java.net.URISyntaxException; import java.util.List; +import com.cloud.exception.ResourceUnavailableException; import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; @@ -40,6 +41,7 @@ import com.cloud.exception.StorageUnavailableException; import com.cloud.user.Account; import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.command.user.vm.CloneVMCmd; import org.apache.cloudstack.api.response.GetUploadParamsResponse; public interface TemplateApiService { @@ -99,6 +101,13 @@ public interface TemplateApiService { boolean updateTemplateOrIsoPermissions(BaseUpdateTemplateOrIsoPermissionsCmd cmd); + /** + * create a template record for later usage of creating a real template by createPrivateTemplate + * */ + VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException; + + VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd) throws CloudRuntimeException; + VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException; VirtualMachineTemplate createPrivateTemplate(CreateTemplateCmd command) throws CloudRuntimeException; diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index c3d0a59f0b7f..02b67c8e7695 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -23,7 +23,21 @@ import org.apache.cloudstack.api.BaseCmd.HTTPMethod; 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.vm.*; +import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; +import org.apache.cloudstack.api.command.user.vm.CloneVMCmd; +import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; +import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; +import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; +import org.apache.cloudstack.api.command.user.vm.StartVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd; +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; @@ -82,6 +96,8 @@ public interface UserVmService { * */ Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException; + void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException; + /** * Resets the password of a virtual machine. * diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 6efb3502aa0e..a740c6031baf 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -2,12 +2,12 @@ import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.NetworkRuleConflictException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.*; @@ -20,7 +20,7 @@ @APICommand(name = "cloneVirtualMachine", responseObject = UserVmResponse.class, description = "clone a virtual VM in full clone mode", responseView = ResponseObject.ResponseView.Restricted, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true, entityType = {VirtualMachine.class}) -public class CloneVMCmd extends BaseAsyncCmd implements UserCmd { +public class CloneVMCmd extends BaseAsyncCreateCustomIdCmd implements UserCmd { public static final Logger s_logger = Logger.getLogger(CloneVMCmd.class.getName()); private static final String s_name = "clonevirtualmachineresponse"; @@ -28,7 +28,7 @@ public class CloneVMCmd extends BaseAsyncCmd implements UserCmd { //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// @ACL(accessType = AccessType.OperateEntry) - @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType=UserVmResponse.class, + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType=UserVmResponse.class, required = true, description = "The ID of the virtual machine") private Long id; @@ -50,6 +50,29 @@ public String getEventDescription() { return "Cloning user VM: " + this._uuidMgr.getUuid(VirtualMachine.class, getId()); } + @Override + public void create() throws ResourceAllocationException { + VirtualMachineTemplate template = null; + try { + _userVmService.checkCloneCondition(this); + } catch (ResourceUnavailableException e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, e.getMessage()); + } + template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); + if (template == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to generate a template during clone!"); + } + } + + public String getVMName() { + return getTargetVM().getInstanceName(); + } + + public String getTemplateName() { + return getVMName() + "-QA"; + } + @Override public void execute() { Optional result; @@ -85,4 +108,8 @@ public long getEntityOwnerId() { } return Account.ACCOUNT_ID_SYSTEM; } + + public UserVm getTargetVM() { + return this._userVmService.getUserVm(getId()); + } } diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 3ca0807e6228..698e23119d2a 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -54,6 +54,7 @@ import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplateCmd; import org.apache.cloudstack.api.command.user.template.UpdateTemplatePermissionsCmd; +import org.apache.cloudstack.api.command.user.vm.CloneVMCmd; import org.apache.cloudstack.api.response.GetUploadParamsResponse; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService; @@ -1781,6 +1782,16 @@ public void doInTransactionWithoutResult(TransactionStatus status) { } } + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template from clone", create = true) + public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException { + Account caller = CallContext.current().getCallingAccount(); + boolean isAdmin = (_accountMgr.isAdmin(caller.getId())); + _accountMgr.checkAccess(caller, null, true, templateOwner); + String name = cmd.getTemplateName(); + return null; + } @Override @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 11f1a2776406..4fb7b83f93ad 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -22,8 +22,19 @@ import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -53,7 +64,22 @@ import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.DeployVMCmdByAdmin; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; -import org.apache.cloudstack.api.command.user.vm.*; +import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd; +import org.apache.cloudstack.api.command.user.vm.CloneVMCmd; +import org.apache.cloudstack.api.command.user.vm.DeployVMCmd; +import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd; +import org.apache.cloudstack.api.command.user.vm.RebootVMCmd; +import org.apache.cloudstack.api.command.user.vm.RemoveNicFromVMCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMPasswordCmd; +import org.apache.cloudstack.api.command.user.vm.ResetVMSSHKeyCmd; +import org.apache.cloudstack.api.command.user.vm.RestoreVMCmd; +import org.apache.cloudstack.api.command.user.vm.ScaleVMCmd; +import org.apache.cloudstack.api.command.user.vm.SecurityGroupAction; +import org.apache.cloudstack.api.command.user.vm.StartVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateDefaultNicForVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd; +import org.apache.cloudstack.api.command.user.vm.UpdateVmNicIpCmd; +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.ResizeVolumeCmd; @@ -4475,10 +4501,24 @@ protected String validateUserData(String userData, HTTPMethod httpmethod) { return null; } + @Override + public void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, CloudRuntimeException, ConcurrentOperationException { + UserVm curVm = cmd.getTargetVM(); + if (curVm == null) { + throw new CloudRuntimeException("the VM doesn't exist or not registered in management server!"); + } + UserVmVO vmStatus = _vmDao.findById(cmd.getId()); + if (vmStatus.state != State.Shutdown) { + throw new CloudRuntimeException("You should clone an instance that's shutdown!"); + } + List volumeInformation = _volsDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); + if (CollectionUtils.isEmpty(volumeInformation)) { + throw new CloudRuntimeException("The VM to copy does not have a Volume attached!"); + } + } @Override @ActionEvent(eventType = EventTypes.EVENT_VM_CLONE, eventDescription = "clone vm", async = true) - public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException { - VolumeVO volumeInformation = _volsDao.findByUuid(""); + public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, CloudRuntimeException { return Optional.ofNullable(null); } From fb6cb0acb6c96d6ce2da46c742e0af4bdb03e59f Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 23 Jun 2021 02:21:01 -0400 Subject: [PATCH 05/58] prepare the template impl --- .../api/command/user/vm/CloneVMCmd.java | 42 ++++++- .../cloud/template/TemplateManagerImpl.java | 114 ++++++++++++++++++ .../java/com/cloud/vm/UserVmManagerImpl.java | 1 + 3 files changed, 151 insertions(+), 6 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index a740c6031baf..0bc6163e5756 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -7,10 +7,17 @@ import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; -import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.VirtualMachine; import org.apache.cloudstack.acl.SecurityChecker.AccessType; -import org.apache.cloudstack.api.*; +import org.apache.cloudstack.api.ACL; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiCommandJobType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCustomIdCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ResponseObject; +import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.command.user.UserCmd; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.context.CallContext; @@ -32,6 +39,26 @@ public class CloneVMCmd extends BaseAsyncCreateCustomIdCmd implements UserCmd { required = true, description = "The ID of the virtual machine") private Long id; + public Long getVolumeId() { + return volumeId; + } + + public void setVolumeId(Long volumeId) { + this.volumeId = volumeId; + } + + private Long volumeId; + + private VirtualMachineTemplate createdTemplate; + + public void setCreatedTemplate(VirtualMachineTemplate template) { + this.createdTemplate = template; + } + + public VirtualMachineTemplate getCreatedTemplate() { + return this.createdTemplate; + } + public Long getId() { return this.id; } @@ -55,14 +82,17 @@ public void create() throws ResourceAllocationException { VirtualMachineTemplate template = null; try { _userVmService.checkCloneCondition(this); + template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); + setCreatedTemplate(template); +// _userVmService.createBasicSecurityGroupVirtualMachine(); // disabled since it crashes } catch (ResourceUnavailableException e) { s_logger.warn("Exception: ", e); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, e.getMessage()); } - template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); - if (template == null) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to generate a template during clone!"); - } + } + + public boolean isPublic() { + return false; } public String getVMName() { diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 698e23119d2a..e972748ff5b8 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1790,8 +1790,122 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template boolean isAdmin = (_accountMgr.isAdmin(caller.getId())); _accountMgr.checkAccess(caller, null, true, templateOwner); String name = cmd.getTemplateName(); + if (name.length() > 32) { + name = name.substring(5) + "-QA"; + } + + int bits = 64; // where to specify + boolean requireHVM = true, sshKeyEnabled = true, featured = false; + boolean isPublic = cmd.isPublic(); + Long volumeId = cmd.getVolumeId(); + HypervisorType hyperType = null; + VolumeVO volume = _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 (!_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 = _volumeDao.getHypervisorType(volumeId); + if (HypervisorType.LXC.equals(hyperType)) { + throw new InvalidParameterValueException("Template creation is not supported for LXC volume: " + volumeId); + } + + _resourceLimitMgr.checkResourceLimit(templateOwner, ResourceType.template); + _resourceLimitMgr.checkResourceLimit(templateOwner, ResourceType.secondary_storage, volume.getSize()); + + Long guestOSId = cmd.getTargetVM().getGuestOSId(); + GuestOSVO guestOS = _guestOSDao.findById(guestOSId); + if (guestOS == null) { + throw new InvalidParameterValueException("GuestOS with ID: " + guestOSId + " does not exist."); + } + + Long nextTemplateId = _tmpltDao.getNextInSequence(Long.class, "id"); + String description = ""; // TODO: add this to clone parameter in the future + 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 (volume.getIsoId() != null && volume.getIsoId() != 0) { + sourceTemplateId = volume.getIsoId(); + } else if (volume.getTemplateId() != null) { + sourceTemplateId = volume.getTemplateId(); + } + } + + VMTemplateVO privateTemplate = null; + privateTemplate = new VMTemplateVO(nextTemplateId, name, ImageFormat.RAW, isPublic, featured, isExtractable, + TemplateType.USER, null, true, 64, templateOwner.getId(), null, description, + true, guestOS.getId(), true, hyperType, null, new HashMap<>(){{put("template to be cleared", "yes");}}, false, false, false, false); + List stores = _imgStoreDao.findRegionImageStores(); + if (!CollectionUtils.isEmpty(stores)) { + privateTemplate.setCrossZones(true); + } + + privateTemplate.setSourceTemplateId(sourceTemplateId); + + VMTemplateVO template = _tmpltDao.persist(privateTemplate); + // Increment the number of templates + if (template != null) { + Map details = new HashMap(); + + if (sourceTemplateId != null) { + VMTemplateVO sourceTemplate = _tmpltDao.findById(sourceTemplateId); + if (sourceTemplate != null && sourceTemplate.getDetails() != null) { + details.putAll(sourceTemplate.getDetails()); + } + } + + if (volume != null) { + Long vmId = volume.getInstanceId(); + if (vmId != null) { + UserVmVO userVm = _userVmDao.findById(vmId); + if (userVm != null) { + _userVmDao.loadDetails(userVm); + Map vmDetails = userVm.getDetails(); + vmDetails = vmDetails.entrySet() + .stream() + .filter(map -> map.getValue() != null) + .collect(Collectors.toMap(map -> map.getKey(), map -> map.getValue())); + details.putAll(vmDetails); + } + } + } + + if (!details.isEmpty()) { + privateTemplate.setDetails(details); + _tmpltDao.saveDetails(privateTemplate); + } + + _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.template); + _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.secondary_storage, + volume.getSize()); + } + + if (template != null) { + return template; + } else { + throw new CloudRuntimeException("Failed to create a template"); + } + } + + @Override + public VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd) throws CloudRuntimeException { return null; } + @Override @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 4fb7b83f93ad..60607b99a845 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4515,6 +4515,7 @@ public void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableExcept if (CollectionUtils.isEmpty(volumeInformation)) { throw new CloudRuntimeException("The VM to copy does not have a Volume attached!"); } + cmd.setVolumeId(volumeInformation.get(0).getId()); } @Override @ActionEvent(eventType = EventTypes.EVENT_VM_CLONE, eventDescription = "clone vm", async = true) From 77c39c21bf5bcaa0888f411eba8e4002088e338c Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 23 Jun 2021 02:23:28 -0400 Subject: [PATCH 06/58] clear the dot record for later test --- api/src/main/java/com/cloud/template/TemplateApiService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/main/java/com/cloud/template/TemplateApiService.java b/api/src/main/java/com/cloud/template/TemplateApiService.java index bcda2bc2f2dc..f0e6f0b264a4 100644 --- a/api/src/main/java/com/cloud/template/TemplateApiService.java +++ b/api/src/main/java/com/cloud/template/TemplateApiService.java @@ -20,7 +20,6 @@ import java.net.URISyntaxException; import java.util.List; -import com.cloud.exception.ResourceUnavailableException; import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; From 1971a39f4bdb9ac2d09cfd3334dbaf28a7c6a51b Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 25 Jun 2021 11:49:00 -0400 Subject: [PATCH 07/58] checks for VM are implemented --- .../main/java/com/cloud/vm/UserVmService.java | 5 +- .../api/command/user/vm/CloneVMCmd.java | 49 ++++++----- .../cloud/template/TemplateManagerImpl.java | 2 +- .../java/com/cloud/vm/UserVmManagerImpl.java | 83 +++++++++++++++---- 4 files changed, 101 insertions(+), 38 deletions(-) diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index 02b67c8e7695..a7fe2824763c 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -96,7 +96,7 @@ public interface UserVmService { * */ Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException; - void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException; + void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ResourceAllocationException; /** * Resets the password of a virtual machine. @@ -442,6 +442,9 @@ UserVm createAdvancedVirtualMachine(DataCenter zone, ServiceOffering serviceOffe UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, StorageUnavailableException, ResourceAllocationException; + UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws InsufficientCapacityException, ResourceUnavailableException, ConcurrentOperationException, + StorageUnavailableException, ResourceAllocationException; + UserVm getUserVm(long vmId); /** diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 0bc6163e5756..b834c95dc55f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -1,9 +1,7 @@ package org.apache.cloudstack.api.command.user.vm; import com.cloud.event.EventTypes; -import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; +import com.cloud.exception.*; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -19,6 +17,7 @@ import org.apache.cloudstack.api.ResponseObject; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.command.user.UserCmd; +import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; @@ -39,24 +38,19 @@ public class CloneVMCmd extends BaseAsyncCreateCustomIdCmd implements UserCmd { required = true, description = "The ID of the virtual machine") private Long id; - public Long getVolumeId() { - return volumeId; - } - - public void setVolumeId(Long volumeId) { - this.volumeId = volumeId; - } + //Owner information + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the virtual machine. Must be used with domainId.") + private String accountName; - private Long volumeId; + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") + private Long domainId; - private VirtualMachineTemplate createdTemplate; - - public void setCreatedTemplate(VirtualMachineTemplate template) { - this.createdTemplate = template; + public String getAccountName() { + return accountName; } - public VirtualMachineTemplate getCreatedTemplate() { - return this.createdTemplate; + public Long getDomainId() { + return domainId; } public Long getId() { @@ -79,15 +73,21 @@ public String getEventDescription() { @Override public void create() throws ResourceAllocationException { - VirtualMachineTemplate template = null; try { _userVmService.checkCloneCondition(this); - template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); - setCreatedTemplate(template); + UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); + if (vmRecord == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "unable to record a new VM to db!"); + } + setEntityId(vmRecord.getId()); + setEntityUuid(vmRecord.getUuid()); // _userVmService.createBasicSecurityGroupVirtualMachine(); // disabled since it crashes - } catch (ResourceUnavailableException e) { + } catch (ResourceUnavailableException | InsufficientCapacityException e) { s_logger.warn("Exception: ", e); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, e.getMessage()); + } catch (InvalidParameterValueException e) { + s_logger.warn("Exception: ", e); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); } } @@ -107,7 +107,8 @@ public String getTemplateName() { public void execute() { Optional result; try { - CallContext.current().setEventDetails("Vm Id for full clone: " + getId()); +// CallContext.current().setEventDetails("Vm Id for full clone: " + getId()); +// VirtualMachineTemplate template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); result = _userVmService.cloneVirtualMachine(this); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); @@ -116,6 +117,10 @@ public void execute() { s_logger.warn("Exception: ", ex); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); } +// catch (ResourceAllocationException ex) { +// s_logger.warn("Exception: ", ex); +// throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage()); +// } result.ifPresentOrElse((userVm)-> { UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", userVm).get(0); response.setResponseName("test_clone"); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index e972748ff5b8..fc91584b2d44 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1797,7 +1797,7 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template int bits = 64; // where to specify boolean requireHVM = true, sshKeyEnabled = true, featured = false; boolean isPublic = cmd.isPublic(); - Long volumeId = cmd.getVolumeId(); + Long volumeId = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT).get(0).getId(); HypervisorType hyperType = null; VolumeVO volume = _volumeDao.findById(volumeId); if (volume == null) { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 60607b99a845..f6973b940dfa 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -51,6 +51,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import com.cloud.user.*; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -292,16 +293,6 @@ import com.cloud.template.TemplateApiService; import com.cloud.template.TemplateManager; import com.cloud.template.VirtualMachineTemplate; -import com.cloud.user.Account; -import com.cloud.user.AccountManager; -import com.cloud.user.AccountService; -import com.cloud.user.ResourceLimitService; -import com.cloud.user.SSHKeyPair; -import com.cloud.user.SSHKeyPairVO; -import com.cloud.user.User; -import com.cloud.user.UserStatisticsVO; -import com.cloud.user.UserVO; -import com.cloud.user.VmDiskStatisticsVO; import com.cloud.user.dao.AccountDao; import com.cloud.user.dao.SSHKeyPairDao; import com.cloud.user.dao.UserDao; @@ -4502,7 +4493,17 @@ protected String validateUserData(String userData, HTTPMethod httpmethod) { } @Override - public void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, CloudRuntimeException, ConcurrentOperationException { + public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueException, ResourceUnavailableException, CloudRuntimeException, ResourceAllocationException { + final DomainVO domain = _domainDao.findById(cmd.getDomainId()); + final Account account = _accountService.getActiveAccountByName(cmd.getAccountName(), cmd.getDomainId()); + if (domain != null && account != null) { + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + throw new InvalidParameterValueException("Invalid user type: project to clone the VM"); + } + if (account.getState() != Account.State.enabled) { + throw new InvalidParameterValueException("User is not enabled to clone this VM"); + } + } UserVm curVm = cmd.getTargetVM(); if (curVm == null) { throw new CloudRuntimeException("the VM doesn't exist or not registered in management server!"); @@ -4511,11 +4512,59 @@ public void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableExcept if (vmStatus.state != State.Shutdown) { throw new CloudRuntimeException("You should clone an instance that's shutdown!"); } - List volumeInformation = _volsDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); - if (CollectionUtils.isEmpty(volumeInformation)) { + List volumes = _volsDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); + if (CollectionUtils.isEmpty(volumes)) { throw new CloudRuntimeException("The VM to copy does not have a Volume attached!"); } - cmd.setVolumeId(volumeInformation.get(0).getId()); + // verify that the VM doesn't expire + Map details = curVm.getDetails(); + verifyDetails(details); +// Account activeOwner = _accountDao.findById(cmd.getEntityOwnerId()); + long zoneId = curVm.getDataCenterId(); + DataCenter zone = _entityMgr.findById(DataCenter.class, zoneId); + if (zone == null) { + throw new InvalidParameterValueException("Unable to find a zone in the current VM by zone id=" + zoneId); + } + // service offering check + long serviceOfferingId = curVm.getServiceOfferingId(); + ServiceOffering serviceOffering = _entityMgr.findById(ServiceOffering.class, serviceOfferingId); + if (serviceOffering == null) { + throw new InvalidParameterValueException("Service offering Id for this VM: " + serviceOfferingId + " doesn't exist now"); + } + if (!serviceOffering.isDynamic()) { + for(String detail: details.keySet()) { + if(detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) { + throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering"); + } + } + } + // disk offering check + VolumeVO rootDisk = volumes.get(0); + Long diskOfferingID = rootDisk.getDiskOfferingId(); + DiskOfferingVO diskOffering =null; + if (diskOfferingID != null) { + diskOffering = _diskOfferingDao.findById(diskOfferingID); + if (diskOffering == null) { + throw new CloudRuntimeException("Unable to find disk offering " + diskOfferingID); + } + } + if (!zone.isLocalStorageEnabled()) { + if (serviceOffering.isUseLocalStorage()) { + throw new CloudRuntimeException("Zone is not configured to use local storage now but this service offering " + serviceOffering.getName() + " uses it"); + } + if (diskOffering != null && diskOffering.isUseLocalStorage()) { + throw new CloudRuntimeException("Zone is not configured to use local storage but disk offering " + diskOffering.getName() + " uses it"); + } + } + // resource limit checks & account check + AccountVO activeOwner = _accountDao.findById(cmd.getEntityOwnerId()); + List totalVolumes = _volsDao.findByInstance(cmd.getId()); + _resourceLimitMgr.checkResourceLimit(activeOwner, ResourceType.volume, totalVolumes.size()); + Long totalSize = 0L; + for (VolumeVO volumeToCheck : totalVolumes) { + totalSize += volumeToCheck.getSize(); + } + _resourceLimitMgr.checkResourceLimit(activeOwner, ResourceType.primary_storage, totalSize); } @Override @ActionEvent(eventType = EventTypes.EVENT_VM_CLONE, eventDescription = "clone vm", async = true) @@ -5508,6 +5557,12 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE return vm; } + @Override + public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperationException { + //network configurations and check, then create the template + return null; + } + /** * Persist extra configuration data in the user_vm_details table as key/value pair * @param decodedUrl String consisting of the extra config data to appended onto the vmx file for VMware instances From 368711043ee79256466d61a17ee1066fca985764 Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 25 Jun 2021 11:52:02 -0400 Subject: [PATCH 08/58] fix checkstyle --- .../cloudstack/api/command/user/vm/CloneVMCmd.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index b834c95dc55f..83a95b46ba3e 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -1,8 +1,11 @@ package org.apache.cloudstack.api.command.user.vm; import com.cloud.event.EventTypes; -import com.cloud.exception.*; -import com.cloud.template.VirtualMachineTemplate; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.Account; import com.cloud.uservm.UserVm; import com.cloud.vm.VirtualMachine; @@ -19,7 +22,7 @@ import org.apache.cloudstack.api.command.user.UserCmd; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.UserVmResponse; -import org.apache.cloudstack.context.CallContext; +//import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; import java.util.Optional; From fbb886cfb0af4fd87f58040635f8ae7c5dba636c Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 25 Jun 2021 11:53:58 -0400 Subject: [PATCH 09/58] compilation fixed --- .../main/java/com/cloud/vm/UserVmManagerImpl.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index f6973b940dfa..a5dbc3cc8a9e 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -51,7 +51,17 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -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.SSHKeyPair; +import com.cloud.user.SSHKeyPairVO; +import com.cloud.user.User; +import com.cloud.user.UserStatisticsVO; +import com.cloud.user.UserVO; +import com.cloud.user.VmDiskStatisticsVO; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; From 16d75daafe4f4a56af95328158314905efc6bf0d Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 25 Jun 2021 17:26:26 -0400 Subject: [PATCH 10/58] checkClone debug --- .../main/java/com/cloud/vm/UserVmManagerImpl.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index a5dbc3cc8a9e..e9281f9a416d 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4504,8 +4504,11 @@ protected String validateUserData(String userData, HTTPMethod httpmethod) { @Override public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueException, ResourceUnavailableException, CloudRuntimeException, ResourceAllocationException { - final DomainVO domain = _domainDao.findById(cmd.getDomainId()); - final Account account = _accountService.getActiveAccountByName(cmd.getAccountName(), cmd.getDomainId()); + if (cmd.getAccountName() != null && cmd.getDomainId() == null) { + throw new InvalidParameterValueException("You must input the domainId together with the account name"); + } + final DomainVO domain = cmd.getDomainId() == null ? null : _domainDao.findById(cmd.getDomainId()); + final Account account = cmd.getAccountName() == null ? null : _accountService.getActiveAccountByName(cmd.getAccountName(), cmd.getDomainId()); if (domain != null && account != null) { if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { throw new InvalidParameterValueException("Invalid user type: project to clone the VM"); @@ -5570,6 +5573,12 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE @Override public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperationException { //network configurations and check, then create the template + UserVm curVm = cmd.getTargetVM(); + // check if host is available + Long hostId = curVm.getHostId(); + getDestinationHost(hostId, true); + + return null; } From 779681cf2ab17880efa5340a8cf5c2e9224a6358 Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 25 Jun 2021 19:14:00 -0400 Subject: [PATCH 11/58] server state update --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index e9281f9a416d..3722e75faf5a 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4522,7 +4522,7 @@ public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueExce throw new CloudRuntimeException("the VM doesn't exist or not registered in management server!"); } UserVmVO vmStatus = _vmDao.findById(cmd.getId()); - if (vmStatus.state != State.Shutdown) { + if (vmStatus.state != State.Shutdown || vmStatus.state != State.Stopped) { throw new CloudRuntimeException("You should clone an instance that's shutdown!"); } List volumes = _volsDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); From 5a81d2b7e81e88acb0b783313b5e48ccec2a2744 Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 25 Jun 2021 19:20:26 -0400 Subject: [PATCH 12/58] add and statement --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 3722e75faf5a..354f849cab1e 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4522,7 +4522,7 @@ public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueExce throw new CloudRuntimeException("the VM doesn't exist or not registered in management server!"); } UserVmVO vmStatus = _vmDao.findById(cmd.getId()); - if (vmStatus.state != State.Shutdown || vmStatus.state != State.Stopped) { + if (vmStatus.state != State.Shutdown && vmStatus.state != State.Stopped) { throw new CloudRuntimeException("You should clone an instance that's shutdown!"); } List volumes = _volsDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); From 6f4fca9a9a5793a211be41190b1e87107d4b84d5 Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 25 Jun 2021 19:35:44 -0400 Subject: [PATCH 13/58] fix null error --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 354f849cab1e..6b0e739dfed1 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4544,7 +4544,7 @@ public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueExce if (serviceOffering == null) { throw new InvalidParameterValueException("Service offering Id for this VM: " + serviceOfferingId + " doesn't exist now"); } - if (!serviceOffering.isDynamic()) { + if (!serviceOffering.isDynamic() && details != null) { for(String detail: details.keySet()) { if(detail.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || detail.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || detail.equalsIgnoreCase(VmDetailConstants.MEMORY)) { throw new InvalidParameterValueException("cpuNumber or cpuSpeed or memory should not be specified for static service offering"); From 896b0331d7750a88aa4c4aa656f99b0a69a597b4 Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 28 Jun 2021 09:17:36 -0400 Subject: [PATCH 14/58] test hit the current vm information --- .../api/command/user/vm/CloneVMCmd.java | 10 ++++ .../cloud/template/TemplateManagerImpl.java | 1 - .../java/com/cloud/vm/UserVmManagerImpl.java | 46 ++++++++++++++++--- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 83a95b46ba3e..0479a7d3fb36 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -48,6 +48,8 @@ public class CloneVMCmd extends BaseAsyncCreateCustomIdCmd implements UserCmd { @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "an optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") private Long domainId; + private Long temporaryTemlateId; + public String getAccountName() { return accountName; } @@ -74,6 +76,14 @@ public String getEventDescription() { return "Cloning user VM: " + this._uuidMgr.getUuid(VirtualMachine.class, getId()); } + public Long getTemporaryTemlateId() { + return this.temporaryTemlateId; + } + + public void setTemporaryTemlateId(Long tempId) { + this.temporaryTemlateId = tempId; + } + @Override public void create() throws ResourceAllocationException { try { diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index fc91584b2d44..b96ab18841f0 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1783,7 +1783,6 @@ public void doInTransactionWithoutResult(TransactionStatus status) { } @Override - @DB @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template from clone", create = true) public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 6b0e739dfed1..bc260b2a506a 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -51,6 +51,8 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import com.cloud.network.*; +import com.cloud.network.security.SecurityGroupVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountService; @@ -226,14 +228,10 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao; import com.cloud.hypervisor.kvm.dpdk.DpdkHelper; -import com.cloud.network.IpAddressManager; -import com.cloud.network.Network; import com.cloud.network.Network.IpAddresses; import com.cloud.network.Network.Provider; import com.cloud.network.Network.Service; -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; @@ -4525,6 +4523,14 @@ public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueExce if (vmStatus.state != State.Shutdown && vmStatus.state != State.Stopped) { throw new CloudRuntimeException("You should clone an instance that's shutdown!"); } + if (vmStatus.getHypervisorType() != HypervisorType.KVM && vmStatus.getHypervisorType() != HypervisorType.Simulator) { + throw new CloudRuntimeException("The clone operation is only supported on KVM and Simulator!"); + } + Long accountId = curVm.getAccountId(); + Account vmOwner = _accountDao.findById(accountId); + if (vmOwner == null) { + throw new CloudRuntimeException("This VM doesn't have an owner account, please assign one to it"); + } List volumes = _volsDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); if (CollectionUtils.isEmpty(volumes)) { throw new CloudRuntimeException("The VM to copy does not have a Volume attached!"); @@ -5571,14 +5577,40 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE } @Override - public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperationException { + public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException { //network configurations and check, then create the template UserVm curVm = cmd.getTargetVM(); // check if host is available Long hostId = curVm.getHostId(); getDestinationHost(hostId, true); - - + Long zoneId = curVm.getDataCenterId(); + DataCenter dataCenter = _entityMgr.findById(DataCenter.class, zoneId); + Map vmProperties = curVm.getDetails(); + String keyboard = vmProperties.get(VmDetailConstants.KEYBOARD); + HypervisorType hypervisorType = curVm.getHypervisorType(); + Account curAccount = _accountDao.findById(curVm.getAccountId()); + long callingUserId = CallContext.current().getCallingUserId(); + Account callerAccount = CallContext.current().getCallingAccount(); +// IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, curAccount.getId() == Account.ACCOUNT_ID_SYSTEM, callerAccount, callingUserId, dataCenter, null, null); + long serviceOfferingId = curVm.getServiceOfferingId(); + ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); + List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); + List securityGroupIdList = securityGroupList.stream().map(SecurityGroupVO::getId).collect(Collectors.toList()); + String uuidName = _uuidMgr.generateUuid(UserVm.class, null); + String hostName = generateHostName(uuidName); + String displayName = hostName + "-Clone"; + Long diskOfferingId = curVm.getDiskOfferingId(); + Long size = null; // mutual exclusive with disk offering id + HTTPMethod httpMethod = cmd.getHttpMethod(); + String userData = curVm.getUserData(); + String sshKeyPair = null; + Map ipToNetoworkMap = null; // Since we've specified Ip + boolean isDisplayVM = curVm.isDisplayVm(); + boolean dynamicScalingEnabled = curVm.isDynamicallyScalable(); + +// if (dataCenter.getNetworkType() == NetworkType.Basic) { +// +// } return null; } From cfd131c3c83b9421660fa03aae76e0b4e364fa31 Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 28 Jun 2021 09:34:31 -0400 Subject: [PATCH 15/58] fix typo of star import --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index bc260b2a506a..c22ea5c83907 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -51,7 +51,11 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import com.cloud.network.*; +import com.cloud.network.IpAddress; +import com.cloud.network.IpAddressManager; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.PhysicalNetwork; import com.cloud.network.security.SecurityGroupVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; From 9677858d48b56ba4903bac5dcc63f413966d95fc Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 28 Jun 2021 09:41:19 -0400 Subject: [PATCH 16/58] fix the null pt except --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index c22ea5c83907..2dac8084911d 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5589,7 +5589,7 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio getDestinationHost(hostId, true); Long zoneId = curVm.getDataCenterId(); DataCenter dataCenter = _entityMgr.findById(DataCenter.class, zoneId); - Map vmProperties = curVm.getDetails(); + Map vmProperties = curVm.getDetails() != null ? curVm.getDetails() : new HashMap<>(); String keyboard = vmProperties.get(VmDetailConstants.KEYBOARD); HypervisorType hypervisorType = curVm.getHypervisorType(); Account curAccount = _accountDao.findById(curVm.getAccountId()); From 85129eea652cb6c483946a26e0f2795e53a47c00 Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 28 Jun 2021 10:21:29 -0400 Subject: [PATCH 17/58] add vm record creation code --- .../apache/cloudstack/api/command/user/vm/CloneVMCmd.java | 5 +++++ .../main/java/com/cloud/template/TemplateManagerImpl.java | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 0479a7d3fb36..ac8f3eebbca6 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -6,6 +6,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; import com.cloud.vm.VirtualMachine; @@ -88,6 +89,10 @@ public void setTemporaryTemlateId(Long tempId) { public void create() throws ResourceAllocationException { try { _userVmService.checkCloneCondition(this); + VirtualMachineTemplate template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); + if (template == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "failed to create a template to db"); + } UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); if (vmRecord == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "unable to record a new VM to db!"); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index b96ab18841f0..6d7fc7b2ca23 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1786,7 +1786,6 @@ public void doInTransactionWithoutResult(TransactionStatus status) { @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template from clone", create = true) public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); - boolean isAdmin = (_accountMgr.isAdmin(caller.getId())); _accountMgr.checkAccess(caller, null, true, templateOwner); String name = cmd.getTemplateName(); if (name.length() > 32) { @@ -1794,7 +1793,7 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template } int bits = 64; // where to specify - boolean requireHVM = true, sshKeyEnabled = true, featured = false; + boolean featured = false; boolean isPublic = cmd.isPublic(); Long volumeId = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT).get(0).getId(); HypervisorType hyperType = null; From b6607f4f270411f9d0a6bbeff27fd781f6d3b734 Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 28 Jun 2021 12:00:25 -0400 Subject: [PATCH 18/58] add the user vm db creation code --- .../api/command/user/vm/CloneVMCmd.java | 1 + .../java/com/cloud/vm/UserVmManagerImpl.java | 32 ++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index ac8f3eebbca6..1879cd27b3eb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -93,6 +93,7 @@ public void create() throws ResourceAllocationException { if (template == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "failed to create a template to db"); } + setTemporaryTemlateId(template.getId()); UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); if (vmRecord == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "unable to record a new VM to db!"); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 2dac8084911d..8cc906273ebf 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -68,6 +68,8 @@ import com.cloud.user.UserStatisticsVO; import com.cloud.user.UserVO; import com.cloud.user.VmDiskStatisticsVO; +import com.cloud.utils.net.MacAddress; +import com.googlecode.ipv6.IPv6Address; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -5581,7 +5583,7 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE } @Override - public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperationException, ResourceAllocationException, InsufficientAddressCapacityException { + public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperationException, ResourceAllocationException, InsufficientCapacityException, ResourceUnavailableException { //network configurations and check, then create the template UserVm curVm = cmd.getTargetVM(); // check if host is available @@ -5595,7 +5597,10 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio Account curAccount = _accountDao.findById(curVm.getAccountId()); long callingUserId = CallContext.current().getCallingUserId(); Account callerAccount = CallContext.current().getCallingAccount(); -// IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, curAccount.getId() == Account.ACCOUNT_ID_SYSTEM, callerAccount, callingUserId, dataCenter, null, null); + IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, curAccount.getId() == Account.ACCOUNT_ID_SYSTEM, callerAccount, callingUserId, dataCenter, null, null); + String ipv6Address = null; + String macAddress = null; + IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), null, macAddress); long serviceOfferingId = curVm.getServiceOfferingId(); ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); @@ -5608,14 +5613,25 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio HTTPMethod httpMethod = cmd.getHttpMethod(); String userData = curVm.getUserData(); String sshKeyPair = null; - Map ipToNetoworkMap = null; // Since we've specified Ip + Map ipToNetoworkMap = null; // Since we've specified Ip boolean isDisplayVM = curVm.isDisplayVm(); boolean dynamicScalingEnabled = curVm.isDynamicallyScalable(); - -// if (dataCenter.getNetworkType() == NetworkType.Basic) { -// -// } - return null; + Long templateId = cmd.getTemporaryTemlateId(); + VirtualMachineTemplate template = _entityMgr.findById(VirtualMachineTemplate.class, templateId); + if (template == null) { + throw new CloudRuntimeException("the temporary template is not created, server error, contact your sys admin"); + } + List networkIds = null; + String group = null; + InstanceGroupVO groupVo = getGroupForVm(cmd.getId()); + if (groupVo != null) { + group = groupVo.getName(); + } + UserVm vmResult = createBasicSecurityGroupVirtualMachine(dataCenter, serviceOffering, template, securityGroupIdList, curAccount, hostName, displayName, diskOfferingId, + size , group , hypervisorType, cmd.getHttpMethod(), userData , sshKeyPair , ipToNetoworkMap, addr, isDisplayVM , keyboard , null, + curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), + null, new HashMap<>(), dynamicScalingEnabled); + return vmResult; } /** From afae56078259caabf3d271cf3f9f51c89c997cd6 Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 28 Jun 2021 12:03:01 -0400 Subject: [PATCH 19/58] add vm creation typo fix --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 8cc906273ebf..16d540034dc7 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -68,8 +68,6 @@ import com.cloud.user.UserStatisticsVO; import com.cloud.user.UserVO; import com.cloud.user.VmDiskStatisticsVO; -import com.cloud.utils.net.MacAddress; -import com.googlecode.ipv6.IPv6Address; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; From 0a1405d0790e3e29fb805b020b3ec1d5ef322bcf Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 28 Jun 2021 12:19:19 -0400 Subject: [PATCH 20/58] change ip to available --- .../apache/cloudstack/api/command/user/vm/CloneVMCmd.java | 4 ++++ server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 1879cd27b3eb..a7de9630736d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -107,6 +107,10 @@ public void create() throws ResourceAllocationException { } catch (InvalidParameterValueException e) { s_logger.warn("Exception: ", e); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } finally { + if (getTemporaryTemlateId() != null) { + // TODO: delete template in the service + } } } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 16d540034dc7..2bfa26ee5b28 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5595,10 +5595,11 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio Account curAccount = _accountDao.findById(curVm.getAccountId()); long callingUserId = CallContext.current().getCallingUserId(); Account callerAccount = CallContext.current().getCallingAccount(); - IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, curAccount.getId() == Account.ACCOUNT_ID_SYSTEM, callerAccount, callingUserId, dataCenter, null, null); +// IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, curAccount.getId() == Account.ACCOUNT_ID_SYSTEM, callerAccount, callingUserId, dataCenter, null, null); String ipv6Address = null; String macAddress = null; - IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), null, macAddress); +// IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), null, macAddress); + IpAddresses addr = new IpAddresses("127.20.0.183", ipv6Address, macAddress); long serviceOfferingId = curVm.getServiceOfferingId(); ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); From 64c0fd51ec6eef65bc62b9c09051da729181a5ef Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 28 Jun 2021 12:21:41 -0400 Subject: [PATCH 21/58] fix ip issue --- .../org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java | 1 + server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index a7de9630736d..074e47b1671a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -110,6 +110,7 @@ public void create() throws ResourceAllocationException { } finally { if (getTemporaryTemlateId() != null) { // TODO: delete template in the service + s_logger.warn("clearing the temporary template: " + getTemporaryTemlateId()); } } } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 2bfa26ee5b28..9f24fd8b3620 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -51,7 +51,7 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; -import com.cloud.network.IpAddress; +//import com.cloud.network.IpAddress; import com.cloud.network.IpAddressManager; import com.cloud.network.Network; import com.cloud.network.NetworkModel; From e04dc22896699b24ac3a64e8e5efcf6d6087862c Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 28 Jun 2021 12:31:36 -0400 Subject: [PATCH 22/58] fix the vm creation detail --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 9f24fd8b3620..224f9f6ed38e 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5628,7 +5628,7 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio } UserVm vmResult = createBasicSecurityGroupVirtualMachine(dataCenter, serviceOffering, template, securityGroupIdList, curAccount, hostName, displayName, diskOfferingId, size , group , hypervisorType, cmd.getHttpMethod(), userData , sshKeyPair , ipToNetoworkMap, addr, isDisplayVM , keyboard , null, - curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), + curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), null, new HashMap<>(), dynamicScalingEnabled); return vmResult; } From 7bef87f11dac1585b5d208801305e5494009416d Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 2 Jul 2021 02:22:53 -0400 Subject: [PATCH 23/58] template zone addition code --- .../java/com/cloud/template/TemplateManagerImpl.java | 9 ++++++--- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 6d7fc7b2ca23..639f8468aaaa 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1789,12 +1789,13 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template _accountMgr.checkAccess(caller, null, true, templateOwner); String name = cmd.getTemplateName(); if (name.length() > 32) { - name = name.substring(5) + "-QA"; + name = name.substring(5) + "-QA-Clone"; } - int bits = 64; // where to specify boolean featured = false; boolean isPublic = cmd.isPublic(); + UserVm curVm = cmd.getTargetVM(); + long zoneId = curVm.getDataCenterId(); Long volumeId = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT).get(0).getId(); HypervisorType hyperType = null; VolumeVO volume = _volumeDao.findById(volumeId); @@ -1853,8 +1854,10 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template } privateTemplate.setSourceTemplateId(sourceTemplateId); - VMTemplateVO template = _tmpltDao.persist(privateTemplate); + // persist this to the template zone area and remember to remove the resource count in the execute phase once in failure or clean up phase + VMTemplateZoneVO templateZone = new VMTemplateZoneVO(zoneId, template.getId(), new Date()); + _tmpltZoneDao.persist(templateZone); // Increment the number of templates if (template != null) { Map details = new HashMap(); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 224f9f6ed38e..037b8461f5a7 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5626,6 +5626,7 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio if (groupVo != null) { group = groupVo.getName(); } + UserVm vmResult = createBasicSecurityGroupVirtualMachine(dataCenter, serviceOffering, template, securityGroupIdList, curAccount, hostName, displayName, diskOfferingId, size , group , hypervisorType, cmd.getHttpMethod(), userData , sshKeyPair , ipToNetoworkMap, addr, isDisplayVM , keyboard , null, curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), From d15f6207fa64d120a39b50b6c2d4e1b1c6d7eeb1 Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 2 Jul 2021 02:25:54 -0400 Subject: [PATCH 24/58] trail-issue-1 --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 037b8461f5a7..224f9f6ed38e 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5626,7 +5626,6 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio if (groupVo != null) { group = groupVo.getName(); } - UserVm vmResult = createBasicSecurityGroupVirtualMachine(dataCenter, serviceOffering, template, securityGroupIdList, curAccount, hostName, displayName, diskOfferingId, size , group , hypervisorType, cmd.getHttpMethod(), userData , sshKeyPair , ipToNetoworkMap, addr, isDisplayVM , keyboard , null, curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), From fee4a95a016a1b3fe410f103afdc41405375e4fb Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 2 Jul 2021 03:08:22 -0400 Subject: [PATCH 25/58] change test ip address --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 224f9f6ed38e..06399bd130bd 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5599,7 +5599,7 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio String ipv6Address = null; String macAddress = null; // IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), null, macAddress); - IpAddresses addr = new IpAddresses("127.20.0.183", ipv6Address, macAddress); + IpAddresses addr = new IpAddresses("60.147.41.98", ipv6Address, macAddress); long serviceOfferingId = curVm.getServiceOfferingId(); ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); From eecacc08c6883ef7591a8701c1ee2d16f7c9aea2 Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 2 Jul 2021 10:18:20 -0400 Subject: [PATCH 26/58] add template download record --- .../src/main/java/com/cloud/template/TemplateManagerImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 639f8468aaaa..8ad16a024b19 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1858,6 +1858,8 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template // persist this to the template zone area and remember to remove the resource count in the execute phase once in failure or clean up phase VMTemplateZoneVO templateZone = new VMTemplateZoneVO(zoneId, template.getId(), new Date()); _tmpltZoneDao.persist(templateZone); + TemplateDataStoreVO voRecord = _tmplStoreDao.createTemplateDirectDownloadEntry(template.getId(), template.getSize()); + _tmplStoreDao.persist(voRecord); // Increment the number of templates if (template != null) { Map details = new HashMap(); From 31824f2b6a8abb43423a93ecaef2c5191bb472bb Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 15:46:18 -0400 Subject: [PATCH 27/58] get the template created and prepare for the vm start --- .../java/com/cloud/network/NetworkModel.java | 4 + .../cloud/template/TemplateApiService.java | 2 +- .../api/command/user/vm/CloneVMCmd.java | 5 +- .../com/cloud/network/NetworkModelImpl.java | 10 +++ .../cloud/template/TemplateManagerImpl.java | 84 +++++++++++++++++-- .../java/com/cloud/vm/UserVmManagerImpl.java | 32 +++++-- 6 files changed, 123 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/com/cloud/network/NetworkModel.java b/api/src/main/java/com/cloud/network/NetworkModel.java index e933a1cc7bd3..0f05b1afa13f 100644 --- a/api/src/main/java/com/cloud/network/NetworkModel.java +++ b/api/src/main/java/com/cloud/network/NetworkModel.java @@ -107,6 +107,10 @@ public interface NetworkModel { List listNetworksUsedByVm(long vmId, boolean isSystem); + default List listNetworksUsedByVm(long vmId) { + throw new UnsupportedOperationException(); + } + Nic getNicInNetwork(long vmId, long networkId); List getNicsForTraffic(long vmId, TrafficType type); diff --git a/api/src/main/java/com/cloud/template/TemplateApiService.java b/api/src/main/java/com/cloud/template/TemplateApiService.java index f0e6f0b264a4..0e647d67f986 100644 --- a/api/src/main/java/com/cloud/template/TemplateApiService.java +++ b/api/src/main/java/com/cloud/template/TemplateApiService.java @@ -105,7 +105,7 @@ public interface TemplateApiService { * */ VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException; - VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd) throws CloudRuntimeException; + VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws CloudRuntimeException; VirtualMachineTemplate createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 074e47b1671a..e92cf27bc10f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -24,6 +24,7 @@ import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.UserVmResponse; //import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.context.CallContext; import org.apache.log4j.Logger; import java.util.Optional; @@ -131,8 +132,8 @@ public String getTemplateName() { public void execute() { Optional result; try { -// CallContext.current().setEventDetails("Vm Id for full clone: " + getId()); -// VirtualMachineTemplate template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); + CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); +// _templateService.createPrivateTemplate(this); result = _userVmService.cloneVirtualMachine(this); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java index 4322478d93e1..32643ca2a48f 100644 --- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeSet; +import java.util.stream.Collectors; import javax.inject.Inject; import javax.naming.ConfigurationException; @@ -831,6 +832,15 @@ public List listNetworksUsedByVm(long vmId, boolean isSystem) { return networks; } + @Override + public List listNetworksUsedByVm(long vmId) { + return listNetworksUsedByVm(vmId, false). + stream(). + mapToLong(NetworkVO::getId). + boxed(). + collect(Collectors.toList()); + } + @Override public Nic getNicInNetwork(long vmId, long networkId) { return _nicDao.findByNtwkIdAndInstanceId(networkId, vmId); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 8ad16a024b19..19e6b25ba3f0 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1782,6 +1782,85 @@ public void doInTransactionWithoutResult(TransactionStatus status) { } } + @Override + @DB + @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating actual private template", create = true) + public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws CloudRuntimeException { + UserVm curVm = cmd.getTargetVM(); + long templateId = cmd.getTemporaryTemlateId(); + final Long accountId = curVm.getAccountId(); + Account caller = CallContext.current().getCallingAccount(); + List volumes = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); + VolumeVO targetVolume = volumes.get(0); + long volumeId = targetVolume.getId(); + VMTemplateVO finalTmpProduct = null; + try { + TemplateInfo cloneTempalateInfp = _tmplFactory.getTemplate(templateId, DataStoreRole.Image); + long zoneId = curVm.getDataCenterId(); + AsyncCallFuture future = null; + VolumeInfo vInfo = _volFactory.getVolume(volumeId); + DataStore store = _dataStoreMgr.getImageStoreWithFreeCapacity(zoneId); + future = _tmpltSvr.createTemplateFromVolumeAsync(vInfo, cloneTempalateInfp, store); + CommandResult result = null; + try { + result = future.get(); + + if (result.isFailed()) { + finalTmpProduct = null; + s_logger.debug("Failed to create template: " + result.getResult()); + throw new CloudRuntimeException("Failed to create template: " + result.getResult()); + } + if (_dataStoreMgr.isRegionStore(store)) { + _tmpltSvr.associateTemplateToZone(templateId, null); + } else { + // Already done in the record to db step + } + finalTmpProduct = _tmpltDao.findById(templateId); + TemplateDataStoreVO srcTmpltStore = _tmplStoreDao.findByStoreTemplate(store.getId(), templateId); + UsageEventVO usageEvent = + new UsageEventVO(EventTypes.EVENT_TEMPLATE_CREATE, finalTmpProduct.getAccountId(), zoneId, finalTmpProduct.getId(), privateTemplate.getName(), null, + finalTmpProduct.getSourceTemplateId(), srcTmpltStore.getPhysicalSize(), finalTmpProduct.getSize()); + _usageEventDao.persist(usageEvent); + } catch (InterruptedException e) { + s_logger.debug("Failed to create template for id: " + templateId, e); + throw new CloudRuntimeException("Failed to create template" , e); + } catch (ExecutionException e) { + s_logger.debug("Failed to create template for id: " + templateId, e); + throw new CloudRuntimeException("Failed to create template ", e); + } + + } finally { + if (finalTmpProduct == null) { + final VolumeVO volumeFinal = targetVolume; + final SnapshotVO snapshotFinal = null; + Transaction.execute(new TransactionCallbackNoReturn() { + @Override + public void doInTransactionWithoutResult(TransactionStatus status) { + // template_store_ref entries should have been removed using our + // DataObject.processEvent command in case of failure, but clean + // it up here to avoid + // some leftovers which will cause removing template from + // vm_template table fail. + _tmplStoreDao.deletePrimaryRecordsForTemplate(templateId); + // Remove the template_zone_ref record + _tmpltZoneDao.deletePrimaryRecordsForTemplate(templateId); + // Remove the template record + _tmpltDao.expunge(templateId); + + // decrement resource count + if (accountId != null) { + _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.template); + _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.secondary_storage, new Long(volumeFinal != null ? volumeFinal.getSize() + : snapshotFinal.getSize())); + } + } + }); + + } + } + return null; + } + @Override @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template from clone", create = true) public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException { @@ -1904,11 +1983,6 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template } } - @Override - public VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd) throws CloudRuntimeException { - return null; - } - @Override @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template", create = true) public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account templateOwner) throws ResourceAllocationException { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 06399bd130bd..78d229988799 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5599,7 +5599,7 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio String ipv6Address = null; String macAddress = null; // IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), null, macAddress); - IpAddresses addr = new IpAddresses("60.147.41.98", ipv6Address, macAddress); + IpAddresses addr = new IpAddresses("60.147.41.99", ipv6Address, macAddress); long serviceOfferingId = curVm.getServiceOfferingId(); ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); @@ -5620,16 +5620,36 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio if (template == null) { throw new CloudRuntimeException("the temporary template is not created, server error, contact your sys admin"); } - List networkIds = null; + List networkIds = _networkModel.listNetworksUsedByVm(curVm.getId()); String group = null; InstanceGroupVO groupVo = getGroupForVm(cmd.getId()); if (groupVo != null) { group = groupVo.getName(); } - UserVm vmResult = createBasicSecurityGroupVirtualMachine(dataCenter, serviceOffering, template, securityGroupIdList, curAccount, hostName, displayName, diskOfferingId, - size , group , hypervisorType, cmd.getHttpMethod(), userData , sshKeyPair , ipToNetoworkMap, addr, isDisplayVM , keyboard , null, - curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), - null, new HashMap<>(), dynamicScalingEnabled); + UserVm vmResult = null; + List affinityGroupIdList = _affinityGroupDao.findByAccountAndNames(curAccount.getId(), curAccount.getAccountName()) + .stream(). + mapToLong(AffinityGroupVO::getId). + boxed(). + collect(Collectors.toList()); + if (dataCenter.getNetworkType() == NetworkType.Basic) { + vmResult = createBasicSecurityGroupVirtualMachine(dataCenter, serviceOffering, template, securityGroupIdList, curAccount, hostName, displayName, diskOfferingId, + size, group, hypervisorType, cmd.getHttpMethod(), userData, sshKeyPair, ipToNetoworkMap, addr, isDisplayVM, keyboard, affinityGroupIdList, + curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), + null, new HashMap<>(), dynamicScalingEnabled); + } else { + if (dataCenter.isSecurityGroupEnabled()) { + vmResult = createAdvancedSecurityGroupVirtualMachine(dataCenter, serviceOffering, template, networkIds, securityGroupIdList, curAccount, hostName, + displayName, diskOfferingId, size, group, hypervisorType, cmd.getHttpMethod(), userData, sshKeyPair, ipToNetoworkMap, addr, isDisplayVM, keyboard, + affinityGroupIdList, curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), cmd.getCustomId(), new HashMap<>(), + null, new HashMap<>(), dynamicScalingEnabled); + } else { + vmResult = createAdvancedVirtualMachine(dataCenter, serviceOffering, template, networkIds, curAccount, hostName, displayName, diskOfferingId, size, group, + hypervisorType, cmd.getHttpMethod(), userData, sshKeyPair, ipToNetoworkMap, addr, isDisplayVM, keyboard, affinityGroupIdList, curVm.getDetails() == null ? new HashMap<>() : curVm.getDetails(), + cmd.getCustomId(), new HashMap<>(), null, new HashMap<>(), dynamicScalingEnabled); + } + } + return vmResult; } From e3bf89459584e511ca05c806d0f59300d4102089 Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 16:51:46 -0400 Subject: [PATCH 28/58] fix unknown symbol --- .../src/main/java/com/cloud/template/TemplateManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 19e6b25ba3f0..a1ac73bb4998 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1818,7 +1818,7 @@ public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws Cloud finalTmpProduct = _tmpltDao.findById(templateId); TemplateDataStoreVO srcTmpltStore = _tmplStoreDao.findByStoreTemplate(store.getId(), templateId); UsageEventVO usageEvent = - new UsageEventVO(EventTypes.EVENT_TEMPLATE_CREATE, finalTmpProduct.getAccountId(), zoneId, finalTmpProduct.getId(), privateTemplate.getName(), null, + new UsageEventVO(EventTypes.EVENT_TEMPLATE_CREATE, finalTmpProduct.getAccountId(), zoneId, finalTmpProduct.getId(), finalTmpProduct.getName(), null, finalTmpProduct.getSourceTemplateId(), srcTmpltStore.getPhysicalSize(), finalTmpProduct.getSize()); _usageEventDao.persist(usageEvent); } catch (InterruptedException e) { From 99e50434144102c27f2387a23dde0ee46e3035e3 Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 17:27:32 -0400 Subject: [PATCH 29/58] finish the final private creation --- .../org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index e92cf27bc10f..9cf9007a6943 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -133,7 +133,7 @@ public void execute() { Optional result; try { CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); -// _templateService.createPrivateTemplate(this); + _templateService.createPrivateTemplate(this); result = _userVmService.cloneVirtualMachine(this); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); From 40abfac2c349e19ea9f58c0c156003cd49474f64 Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 17:49:26 -0400 Subject: [PATCH 30/58] add logger information --- .../org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 9cf9007a6943..f71c8a18d2ae 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -101,7 +101,6 @@ public void create() throws ResourceAllocationException { } setEntityId(vmRecord.getId()); setEntityUuid(vmRecord.getUuid()); -// _userVmService.createBasicSecurityGroupVirtualMachine(); // disabled since it crashes } catch (ResourceUnavailableException | InsufficientCapacityException e) { s_logger.warn("Exception: ", e); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, e.getMessage()); @@ -133,6 +132,8 @@ public void execute() { Optional result; try { CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); + s_logger.info("creating actual template id: " + getTemporaryTemlateId()); + s_logger.info("starting actual VM id: " + getEntityId()); _templateService.createPrivateTemplate(this); result = _userVmService.cloneVirtualMachine(this); } catch (ResourceUnavailableException ex) { From d235477b349d7682c3e5e9d563bcdb81fb4aae31 Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 18:04:40 -0400 Subject: [PATCH 31/58] add autobox statement --- .../org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index f71c8a18d2ae..270699c6ae08 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -82,7 +82,7 @@ public Long getTemporaryTemlateId() { return this.temporaryTemlateId; } - public void setTemporaryTemlateId(Long tempId) { + public void setTemporaryTemlateId(long tempId) { this.temporaryTemlateId = tempId; } @@ -94,6 +94,7 @@ public void create() throws ResourceAllocationException { if (template == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "failed to create a template to db"); } + s_logger.info("The template id recorded is: " + template.getId()); setTemporaryTemlateId(template.getId()); UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); if (vmRecord == null) { From a48d7fa367fe8ae16091bf6a348cda59d300f9fa Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 21:46:45 -0400 Subject: [PATCH 32/58] add template Id setting --- .../org/apache/cloudstack/api/BaseAsyncCreateCmd.java | 9 +++++++++ .../cloudstack/api/command/user/vm/CloneVMCmd.java | 3 ++- .../java/com/cloud/template/TemplateManagerImpl.java | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java index 60c2a183ad33..869431b8b03a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java @@ -23,6 +23,8 @@ public abstract class BaseAsyncCreateCmd extends BaseAsyncCmd { private String uuid; + private Long templateId; + public abstract void create() throws ResourceAllocationException; public Long getEntityId() { @@ -49,4 +51,11 @@ public String getCreateEventDescription() { return null; } + public Long getTemplateId() { + return templateId; + } + + public void setTemplateId(Long id) { + this.templateId = id; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 270699c6ae08..0cadbbba1dc8 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -95,6 +95,7 @@ public void create() throws ResourceAllocationException { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "failed to create a template to db"); } s_logger.info("The template id recorded is: " + template.getId()); + setTemplateId(template.getId()); setTemporaryTemlateId(template.getId()); UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); if (vmRecord == null) { @@ -133,7 +134,7 @@ public void execute() { Optional result; try { CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); - s_logger.info("creating actual template id: " + getTemporaryTemlateId()); + s_logger.info("creating actual template id: " + getTemplateId()); s_logger.info("starting actual VM id: " + getEntityId()); _templateService.createPrivateTemplate(this); result = _userVmService.cloneVirtualMachine(this); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index a1ac73bb4998..5546a6a07e23 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1787,7 +1787,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating actual private template", create = true) public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws CloudRuntimeException { UserVm curVm = cmd.getTargetVM(); - long templateId = cmd.getTemporaryTemlateId(); + long templateId = cmd.getTemplateId(); final Long accountId = curVm.getAccountId(); Account caller = CallContext.current().getCallingAccount(); List volumes = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); From 7fb099482d1415bd6758920c2cda86319ca5319c Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 22:19:39 -0400 Subject: [PATCH 33/58] use uuid as replacement of template --- .../org/apache/cloudstack/api/BaseAsyncCreateCmd.java | 10 ---------- .../cloudstack/api/command/user/vm/CloneVMCmd.java | 7 +++---- .../java/com/cloud/template/TemplateManagerImpl.java | 2 +- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java b/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java index 869431b8b03a..10fee857dfcf 100644 --- a/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/BaseAsyncCreateCmd.java @@ -23,8 +23,6 @@ public abstract class BaseAsyncCreateCmd extends BaseAsyncCmd { private String uuid; - private Long templateId; - public abstract void create() throws ResourceAllocationException; public Long getEntityId() { @@ -50,12 +48,4 @@ public String getCreateEventType() { public String getCreateEventDescription() { return null; } - - public Long getTemplateId() { - return templateId; - } - - public void setTemplateId(Long id) { - this.templateId = id; - } } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 0cadbbba1dc8..83ae60a6c3ef 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -95,14 +95,13 @@ public void create() throws ResourceAllocationException { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "failed to create a template to db"); } s_logger.info("The template id recorded is: " + template.getId()); - setTemplateId(template.getId()); - setTemporaryTemlateId(template.getId()); UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); if (vmRecord == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "unable to record a new VM to db!"); } + setTemporaryTemlateId(template.getId()); setEntityId(vmRecord.getId()); - setEntityUuid(vmRecord.getUuid()); + setEntityUuid(String.valueOf(template.getId())); } catch (ResourceUnavailableException | InsufficientCapacityException e) { s_logger.warn("Exception: ", e); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, e.getMessage()); @@ -134,7 +133,7 @@ public void execute() { Optional result; try { CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); - s_logger.info("creating actual template id: " + getTemplateId()); + s_logger.info("creating actual template id: " + getEntityUuid()); s_logger.info("starting actual VM id: " + getEntityId()); _templateService.createPrivateTemplate(this); result = _userVmService.cloneVirtualMachine(this); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 5546a6a07e23..f5494b7c8444 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1787,7 +1787,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating actual private template", create = true) public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws CloudRuntimeException { UserVm curVm = cmd.getTargetVM(); - long templateId = cmd.getTemplateId(); + long templateId = Long.parseLong(cmd.getEntityUuid()); final Long accountId = curVm.getAccountId(); Account caller = CallContext.current().getCallingAccount(); List volumes = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); From ed9ac4e2fc02ff171497ca3b750452cc518badb9 Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 22:27:23 -0400 Subject: [PATCH 34/58] fix the template recording bug --- .../org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 83ae60a6c3ef..179d5efd32f1 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -95,11 +95,11 @@ public void create() throws ResourceAllocationException { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "failed to create a template to db"); } s_logger.info("The template id recorded is: " + template.getId()); + setTemporaryTemlateId(template.getId()); UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); if (vmRecord == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "unable to record a new VM to db!"); } - setTemporaryTemlateId(template.getId()); setEntityId(vmRecord.getId()); setEntityUuid(String.valueOf(template.getId())); } catch (ResourceUnavailableException | InsufficientCapacityException e) { From 23a53cb22ecbdeaf3e67c6295fbb8c696b1442e0 Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 22:53:31 -0400 Subject: [PATCH 35/58] fix instance creation null --- .../org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java | 2 +- .../src/main/java/com/cloud/template/TemplateManagerImpl.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 179d5efd32f1..b724dc21f000 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -133,7 +133,7 @@ public void execute() { Optional result; try { CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); - s_logger.info("creating actual template id: " + getEntityUuid()); + s_logger.info("creating actual template id: " + Long.parseLong(getEntityUuid())); s_logger.info("starting actual VM id: " + getEntityId()); _templateService.createPrivateTemplate(this); result = _userVmService.cloneVirtualMachine(this); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index f5494b7c8444..0b0309f9187e 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1807,7 +1807,7 @@ public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws Cloud if (result.isFailed()) { finalTmpProduct = null; - s_logger.debug("Failed to create template: " + result.getResult()); + s_logger.warn("Failed to create template: " + result.getResult()); throw new CloudRuntimeException("Failed to create template: " + result.getResult()); } if (_dataStoreMgr.isRegionStore(store)) { @@ -1815,6 +1815,7 @@ public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws Cloud } else { // Already done in the record to db step } + s_logger.info("successfully created the template with Id: " + templateId); finalTmpProduct = _tmpltDao.findById(templateId); TemplateDataStoreVO srcTmpltStore = _tmplStoreDao.findByStoreTemplate(store.getId(), templateId); UsageEventVO usageEvent = @@ -1830,6 +1831,7 @@ public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws Cloud } } finally { + finalTmpProduct = _tmpltDao.findById(templateId); if (finalTmpProduct == null) { final VolumeVO volumeFinal = targetVolume; final SnapshotVO snapshotFinal = null; From 53785ed1c657e74eb0ebd312a97f9469a92e46e0 Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 4 Jul 2021 23:52:35 -0400 Subject: [PATCH 36/58] fix the template creation sequence --- .../cloudstack/api/command/user/vm/CloneVMCmd.java | 5 ++--- .../com/cloud/template/TemplateManagerImpl.java | 13 ++++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index b724dc21f000..91144ab72651 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -96,12 +96,13 @@ public void create() throws ResourceAllocationException { } s_logger.info("The template id recorded is: " + template.getId()); setTemporaryTemlateId(template.getId()); + _templateService.createPrivateTemplate(this); UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); if (vmRecord == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "unable to record a new VM to db!"); } setEntityId(vmRecord.getId()); - setEntityUuid(String.valueOf(template.getId())); + setEntityUuid(vmRecord.getUuid()); } catch (ResourceUnavailableException | InsufficientCapacityException e) { s_logger.warn("Exception: ", e); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, e.getMessage()); @@ -133,9 +134,7 @@ public void execute() { Optional result; try { CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); - s_logger.info("creating actual template id: " + Long.parseLong(getEntityUuid())); s_logger.info("starting actual VM id: " + getEntityId()); - _templateService.createPrivateTemplate(this); result = _userVmService.cloneVirtualMachine(this); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 0b0309f9187e..1955aa96f625 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1787,7 +1787,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating actual private template", create = true) public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws CloudRuntimeException { UserVm curVm = cmd.getTargetVM(); - long templateId = Long.parseLong(cmd.getEntityUuid()); + long templateId = cmd.getTemporaryTemlateId(); final Long accountId = curVm.getAccountId(); Account caller = CallContext.current().getCallingAccount(); List volumes = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); @@ -1814,6 +1814,8 @@ public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws Cloud _tmpltSvr.associateTemplateToZone(templateId, null); } else { // Already done in the record to db step + VMTemplateZoneVO templateZone = new VMTemplateZoneVO(zoneId, templateId, new Date()); + _tmpltZoneDao.persist(templateZone); } s_logger.info("successfully created the template with Id: " + templateId); finalTmpProduct = _tmpltDao.findById(templateId); @@ -1937,10 +1939,11 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template privateTemplate.setSourceTemplateId(sourceTemplateId); VMTemplateVO template = _tmpltDao.persist(privateTemplate); // persist this to the template zone area and remember to remove the resource count in the execute phase once in failure or clean up phase - VMTemplateZoneVO templateZone = new VMTemplateZoneVO(zoneId, template.getId(), new Date()); - _tmpltZoneDao.persist(templateZone); - TemplateDataStoreVO voRecord = _tmplStoreDao.createTemplateDirectDownloadEntry(template.getId(), template.getSize()); - _tmplStoreDao.persist(voRecord); +// VMTemplateZoneVO templateZone = new VMTemplateZoneVO(zoneId, template.getId(), new Date()); +// _tmpltZoneDao.persist(templateZone); +// TemplateDataStoreVO voRecord = _tmplStoreDao.createTemplateDirectDownloadEntry(template.getId(), template.getSize()); +// voRecord.setDataStoreId(2); +// _tmplStoreDao.persist(voRecord); // Increment the number of templates if (template != null) { Map details = new HashMap(); From 306a7f42d3aac05ac17ae0ac5d422ca0420c1cbf Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 5 Jul 2021 02:22:23 -0400 Subject: [PATCH 37/58] finish the start vm coding --- .../main/java/com/cloud/vm/UserVmService.java | 2 +- .../api/command/user/vm/CloneVMCmd.java | 10 +++++----- .../java/com/cloud/vm/UserVmManagerImpl.java | 19 +++++++++++++++++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index a7fe2824763c..90f41d860ffa 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -94,7 +94,7 @@ public interface UserVmService { * - the command specifying vmId to be cloned * @return the VM if cloneVM operation is successful * */ - Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException; + Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ResourceAllocationException; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 91144ab72651..438f31854e79 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -143,12 +143,12 @@ public void execute() { s_logger.warn("Exception: ", ex); throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); } -// catch (ResourceAllocationException ex) { -// s_logger.warn("Exception: ", ex); -// throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage()); -// } + catch (ResourceAllocationException | InsufficientCapacityException ex) { + s_logger.warn("Exception: ", ex); + throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage()); + } result.ifPresentOrElse((userVm)-> { - UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", userVm).get(0); + UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", result.get()).get(0); response.setResponseName("test_clone"); setResponseObject(response); }, ()-> { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 78d229988799..6c423beba7b9 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4589,10 +4589,25 @@ public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueExce } _resourceLimitMgr.checkResourceLimit(activeOwner, ResourceType.primary_storage, totalSize); } + @Override @ActionEvent(eventType = EventTypes.EVENT_VM_CLONE, eventDescription = "clone vm", async = true) - public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, CloudRuntimeException { - return Optional.ofNullable(null); + public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, CloudRuntimeException, InsufficientCapacityException, ResourceAllocationException { + long vmId = cmd.getEntityId(); + UserVmVO curVm = _vmDao.findById(vmId); + Long podId = curVm.getPodIdToDeployIn(); + Long clusterId = null; + Long hostId = curVm.getHostId(); + Map additonalParams = new HashMap<>(); + Map diskOfferingMap = null; + if (MapUtils.isNotEmpty(curVm.getDetails()) && curVm.getDetails().containsKey(ApiConstants.BootType.UEFI.toString())) { + Map map = curVm.getDetails(); + additonalParams.put(VirtualMachineProfile.Param.UefiFlag, "Yes"); + additonalParams.put(VirtualMachineProfile.Param.BootType, ApiConstants.BootType.UEFI.toString()); + additonalParams.put(VirtualMachineProfile.Param.BootMode, map.get(ApiConstants.BootType.UEFI.toString())); + } + + return Optional.of(startVirtualMachine(vmId, podId, clusterId, hostId, diskOfferingMap, additonalParams, null)); } @Override From 8ecb6a587b933b08e514ad67cad8e7bc9c0165b6 Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 5 Jul 2021 02:36:48 -0400 Subject: [PATCH 38/58] fix start virtual machine null pointer bug --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 6c423beba7b9..e94225b3e4c1 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4599,7 +4599,7 @@ public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnava Long clusterId = null; Long hostId = curVm.getHostId(); Map additonalParams = new HashMap<>(); - Map diskOfferingMap = null; + Map diskOfferingMap = new HashMap<>(); if (MapUtils.isNotEmpty(curVm.getDetails()) && curVm.getDetails().containsKey(ApiConstants.BootType.UEFI.toString())) { Map map = curVm.getDetails(); additonalParams.put(VirtualMachineProfile.Param.UefiFlag, "Yes"); From a1bf574b8e8b28a1cfbc7ed842174bb801b97f30 Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 5 Jul 2021 02:49:21 -0400 Subject: [PATCH 39/58] add public ip address for kvm host test --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index e94225b3e4c1..483f58991bba 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5614,7 +5614,7 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio String ipv6Address = null; String macAddress = null; // IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), null, macAddress); - IpAddresses addr = new IpAddresses("60.147.41.99", ipv6Address, macAddress); + IpAddresses addr = new IpAddresses("172.20.0.97", ipv6Address, macAddress); long serviceOfferingId = curVm.getServiceOfferingId(); ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); From 96393890f03fd6c27f9319774947b22f7fcad3fd Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 5 Jul 2021 12:20:28 -0400 Subject: [PATCH 40/58] new clone ip added --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 483f58991bba..c269e2fd71c9 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5614,7 +5614,7 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio String ipv6Address = null; String macAddress = null; // IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), null, macAddress); - IpAddresses addr = new IpAddresses("172.20.0.97", ipv6Address, macAddress); + IpAddresses addr = new IpAddresses("172.20.0.100", ipv6Address, macAddress); long serviceOfferingId = curVm.getServiceOfferingId(); ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); From 0871f74a4e0c6c0eb5c5693affb1f446cb9d070a Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 5 Jul 2021 12:55:53 -0400 Subject: [PATCH 41/58] change test ip to 98 --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index c269e2fd71c9..1ffb479c22ff 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5614,7 +5614,7 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio String ipv6Address = null; String macAddress = null; // IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), null, macAddress); - IpAddresses addr = new IpAddresses("172.20.0.100", ipv6Address, macAddress); + IpAddresses addr = new IpAddresses("172.20.0.98", ipv6Address, macAddress); long serviceOfferingId = curVm.getServiceOfferingId(); ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); From f5b896e5a8291a73bffdf6e715cac2b1fba3a74a Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 02:22:04 -0400 Subject: [PATCH 42/58] fixing the first password issue --- .../cloud/template/TemplateApiService.java | 3 +- .../api/command/user/vm/CloneVMCmd.java | 14 ++- .../cloud/template/TemplateManagerImpl.java | 93 ++++++++++++------- .../java/com/cloud/vm/UserVmManagerImpl.java | 6 +- 4 files changed, 79 insertions(+), 37 deletions(-) diff --git a/api/src/main/java/com/cloud/template/TemplateApiService.java b/api/src/main/java/com/cloud/template/TemplateApiService.java index 0e647d67f986..fd45499ef6b4 100644 --- a/api/src/main/java/com/cloud/template/TemplateApiService.java +++ b/api/src/main/java/com/cloud/template/TemplateApiService.java @@ -20,6 +20,7 @@ import java.net.URISyntaxException; import java.util.List; +import com.cloud.storage.VolumeApiService; import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd; import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd; @@ -103,7 +104,7 @@ public interface TemplateApiService { /** * create a template record for later usage of creating a real template by createPrivateTemplate * */ - VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException; + VirtualMachineTemplate createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner, VolumeApiService serviceObj) throws ResourceAllocationException; VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws CloudRuntimeException; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 438f31854e79..41837c93ac72 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -6,6 +6,7 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.storage.Snapshot; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; @@ -52,6 +53,8 @@ public class CloneVMCmd extends BaseAsyncCreateCustomIdCmd implements UserCmd { private Long temporaryTemlateId; + private Long temporarySnapShotId; + public String getAccountName() { return accountName; } @@ -82,6 +85,15 @@ public Long getTemporaryTemlateId() { return this.temporaryTemlateId; } + public void setTemporarySnapShotId(Long snapshotId) { + this.temporarySnapShotId = snapshotId; + } + + public Long getTemporarySnapShotId() { + return temporarySnapShotId; + } + + public void setTemporaryTemlateId(long tempId) { this.temporaryTemlateId = tempId; } @@ -90,7 +102,7 @@ public void setTemporaryTemlateId(long tempId) { public void create() throws ResourceAllocationException { try { _userVmService.checkCloneCondition(this); - VirtualMachineTemplate template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId())); + VirtualMachineTemplate template = _templateService.createPrivateTemplateRecord(this, _accountService.getAccount(getEntityOwnerId()), _volumeService); if (template == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "failed to create a template to db"); } diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 1955aa96f625..3e68ef0f9605 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -33,6 +33,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.storage.*; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd; @@ -143,29 +144,9 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; -import com.cloud.storage.DataStoreRole; -import com.cloud.storage.GuestOSVO; -import com.cloud.storage.ImageStoreUploadMonitorImpl; -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.TemplateProfile; -import com.cloud.storage.Upload; -import com.cloud.storage.VMTemplateHostVO; -import com.cloud.storage.VMTemplateStoragePoolVO; -import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.VMTemplateStorageResourceAssoc.Status; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VMTemplateZoneVO; -import com.cloud.storage.Volume; -import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.GuestOSDao; import com.cloud.storage.dao.LaunchPermissionDao; import com.cloud.storage.dao.SnapshotDao; @@ -1788,19 +1769,50 @@ public void doInTransactionWithoutResult(TransactionStatus status) { public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws CloudRuntimeException { UserVm curVm = cmd.getTargetVM(); long templateId = cmd.getTemporaryTemlateId(); + long snapshotId = cmd.getTemporarySnapShotId(); final Long accountId = curVm.getAccountId(); Account caller = CallContext.current().getCallingAccount(); List volumes = _volumeDao.findByInstanceAndType(cmd.getId(), Volume.Type.ROOT); VolumeVO targetVolume = volumes.get(0); long volumeId = targetVolume.getId(); VMTemplateVO finalTmpProduct = null; + SnapshotVO snapshot = null; try { TemplateInfo cloneTempalateInfp = _tmplFactory.getTemplate(templateId, DataStoreRole.Image); long zoneId = curVm.getDataCenterId(); AsyncCallFuture future = null; VolumeInfo vInfo = _volFactory.getVolume(volumeId); DataStore store = _dataStoreMgr.getImageStoreWithFreeCapacity(zoneId); - future = _tmpltSvr.createTemplateFromVolumeAsync(vInfo, cloneTempalateInfp, store); + snapshot = _snapshotDao.findById(snapshotId); +// future = _tmpltSvr.createTemplateFromVolumeAsync(vInfo, cloneTempalateInfp, store); + // create template from snapshot + DataStoreRole dataStoreRole = ApiResponseHelper.getDataStoreRole(snapshot, _snapshotStoreDao, _dataStoreMgr); + SnapshotInfo snapInfo = _snapshotFactory.getSnapshot(snapshotId, dataStoreRole); + if (dataStoreRole == DataStoreRole.Image) { + if (snapInfo == null) { + snapInfo = _snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Primary); + if(snapInfo == null) { + throw new CloudRuntimeException("Cannot find snapshot "+snapshotId); + } + // We need to copy the snapshot onto secondary. + SnapshotStrategy snapshotStrategy = _storageStrategyFactory.getSnapshotStrategy(snapshot, SnapshotOperation.BACKUP); + snapshotStrategy.backupSnapshot(snapInfo); + + // Attempt to grab it again. + snapInfo = _snapshotFactory.getSnapshot(snapshotId, dataStoreRole); + if(snapInfo == null) { + throw new CloudRuntimeException("Cannot find snapshot " + snapshotId + " on secondary and could not create backup"); + } + } + _accountMgr.checkAccess(caller, null, true, snapInfo); + DataStore snapStore = snapInfo.getDataStore(); + + if (snapStore != null) { + store = snapStore; // pick snapshot image store to create template + } + } + future = _tmpltSvr.createTemplateFromSnapshotAsync(snapInfo, cloneTempalateInfp, store); + // wait for the result to converge CommandResult result = null; try { result = future.get(); @@ -1836,7 +1848,7 @@ public VirtualMachineTemplate createPrivateTemplate(CloneVMCmd cmd) throws Cloud finalTmpProduct = _tmpltDao.findById(templateId); if (finalTmpProduct == null) { final VolumeVO volumeFinal = targetVolume; - final SnapshotVO snapshotFinal = null; + final SnapshotVO snapshotFinal = snapshot; Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { @@ -1867,7 +1879,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { @Override @ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating template from clone", create = true) - public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner) throws ResourceAllocationException { + public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account templateOwner, VolumeApiService volumeService) throws ResourceAllocationException { Account caller = CallContext.current().getCallingAccount(); _accountMgr.checkAccess(caller, null, true, templateOwner); String name = cmd.getTemplateName(); @@ -1883,21 +1895,22 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template HypervisorType hyperType = null; VolumeVO volume = _volumeDao.findById(volumeId); if (volume == null) { - throw new InvalidParameterValueException("Failed to create private template record, unable to find volume " + volumeId); + throw new InvalidParameterValueException("Failed to create private template record, unable to find root 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 (!_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); - } +// if (!_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 = _volumeDao.getHypervisorType(volumeId); if (HypervisorType.LXC.equals(hyperType)) { @@ -1913,7 +1926,23 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template throw new InvalidParameterValueException("GuestOS with ID: " + guestOSId + " does not exist."); } + // get snapshot from this step + + Long nextTemplateId = _tmpltDao.getNextInSequence(Long.class, "id"); + s_logger.info("Creating snapshot for the tempalte creation"); + SnapshotVO snapshot = (SnapshotVO) volumeService.allocSnapshot(volumeId, null, curVm.getDisplayName() + "-Clone-" + nextTemplateId, Snapshot.LocationType.PRIMARY); + if (snapshot == null) { + throw new CloudRuntimeException("Unable to create a snapshot during the template creation recording"); + } + Snapshot snapshotEntity = volumeService.takeSnapshot(volumeId, null, snapshot.getId(), caller, false, Snapshot.LocationType.PRIMARY, false, new HashMap<>()); + if (snapshotEntity == null) { + throw new CloudRuntimeException("Error when creating the snapshot entity"); + } + if (snapshotEntity.getState() != Snapshot.State.BackedUp) { + throw new CloudRuntimeException("Async backup of snapshot happens during the clone for snapshot id: " + snapshot.getId()); + } + cmd.setTemporarySnapShotId(snapshot.getId()); String description = ""; // TODO: add this to clone parameter in the future boolean isExtractable = false; Long sourceTemplateId = null; @@ -1978,7 +2007,7 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.template); _resourceLimitMgr.incrementResourceCount(templateOwner.getId(), ResourceType.secondary_storage, - volume.getSize()); + snapshot.getSize()); } if (template != null) { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 1ffb479c22ff..a2955491d742 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4524,9 +4524,9 @@ public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueExce throw new CloudRuntimeException("the VM doesn't exist or not registered in management server!"); } UserVmVO vmStatus = _vmDao.findById(cmd.getId()); - if (vmStatus.state != State.Shutdown && vmStatus.state != State.Stopped) { - throw new CloudRuntimeException("You should clone an instance that's shutdown!"); - } +// if (vmStatus.state != State.Shutdown && vmStatus.state != State.Stopped) { +// throw new CloudRuntimeException("You should clone an instance that's shutdown!"); +// } if (vmStatus.getHypervisorType() != HypervisorType.KVM && vmStatus.getHypervisorType() != HypervisorType.Simulator) { throw new CloudRuntimeException("The clone operation is only supported on KVM and Simulator!"); } From 8bebd3b6dd781dfa3d1aa50eeccd4fa61bdbdc86 Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 02:23:40 -0400 Subject: [PATCH 43/58] fix the style code --- .../org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java | 1 - 1 file changed, 1 deletion(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 41837c93ac72..cdd5cb342c4d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -6,7 +6,6 @@ import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; -import com.cloud.storage.Snapshot; import com.cloud.template.VirtualMachineTemplate; import com.cloud.user.Account; import com.cloud.uservm.UserVm; From 21ac7a77aa1ccaa92af6eb98ca62dd5afd7355e5 Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 02:26:07 -0400 Subject: [PATCH 44/58] audit the star --- .../cloud/template/TemplateManagerImpl.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 3e68ef0f9605..e00c5b8650ab 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -33,7 +33,27 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.storage.*; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.ImageStoreUploadMonitorImpl; +import com.cloud.storage.LaunchPermissionVO; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolHostVO; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.TemplateProfile; +import com.cloud.storage.Upload; +import com.cloud.storage.VMTemplateHostVO; +import com.cloud.storage.VMTemplateStoragePoolVO; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeApiService; +import com.cloud.storage.VolumeVO; import org.apache.cloudstack.acl.SecurityChecker.AccessType; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd; From 385df67c0d69535c119b525c2b402bec7dfcc9dc Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 02:57:36 -0400 Subject: [PATCH 45/58] location type changed --- .../src/main/java/com/cloud/template/TemplateManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index e00c5b8650ab..15f982f5e430 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1951,11 +1951,11 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template Long nextTemplateId = _tmpltDao.getNextInSequence(Long.class, "id"); s_logger.info("Creating snapshot for the tempalte creation"); - SnapshotVO snapshot = (SnapshotVO) volumeService.allocSnapshot(volumeId, null, curVm.getDisplayName() + "-Clone-" + nextTemplateId, Snapshot.LocationType.PRIMARY); + SnapshotVO snapshot = (SnapshotVO) volumeService.allocSnapshot(volumeId, null, curVm.getDisplayName() + "-Clone-" + nextTemplateId, null); if (snapshot == null) { throw new CloudRuntimeException("Unable to create a snapshot during the template creation recording"); } - Snapshot snapshotEntity = volumeService.takeSnapshot(volumeId, null, snapshot.getId(), caller, false, Snapshot.LocationType.PRIMARY, false, new HashMap<>()); + Snapshot snapshotEntity = volumeService.takeSnapshot(volumeId, null, snapshot.getId(), caller, false, null, false, new HashMap<>()); if (snapshotEntity == null) { throw new CloudRuntimeException("Error when creating the snapshot entity"); } From cec1ee9cfd6d7b027e5f52021e451804fce96fd5 Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 03:09:30 -0400 Subject: [PATCH 46/58] fix the snapshot policy --- .../src/main/java/com/cloud/template/TemplateManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 15f982f5e430..48f5407f6398 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1951,11 +1951,11 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template Long nextTemplateId = _tmpltDao.getNextInSequence(Long.class, "id"); s_logger.info("Creating snapshot for the tempalte creation"); - SnapshotVO snapshot = (SnapshotVO) volumeService.allocSnapshot(volumeId, null, curVm.getDisplayName() + "-Clone-" + nextTemplateId, null); + SnapshotVO snapshot = (SnapshotVO) volumeService.allocSnapshot(volumeId, Snapshot.MANUAL_POLICY_ID, curVm.getDisplayName() + "-Clone-" + nextTemplateId, null); if (snapshot == null) { throw new CloudRuntimeException("Unable to create a snapshot during the template creation recording"); } - Snapshot snapshotEntity = volumeService.takeSnapshot(volumeId, null, snapshot.getId(), caller, false, null, false, new HashMap<>()); + Snapshot snapshotEntity = volumeService.takeSnapshot(volumeId, Snapshot.MANUAL_POLICY_ID, snapshot.getId(), caller, false, null, false, new HashMap<>()); if (snapshotEntity == null) { throw new CloudRuntimeException("Error when creating the snapshot entity"); } From d4d7570ad46b24669f7c542c3dc2f2872d8a6552 Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 20:54:26 -0400 Subject: [PATCH 47/58] add automatic ip assignment- --- .../main/java/com/cloud/vm/UserVmManagerImpl.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index a2955491d742..1e07f2fbf8d3 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -52,10 +52,7 @@ import javax.xml.parsers.ParserConfigurationException; //import com.cloud.network.IpAddress; -import com.cloud.network.IpAddressManager; -import com.cloud.network.Network; -import com.cloud.network.NetworkModel; -import com.cloud.network.PhysicalNetwork; +import com.cloud.network.*; import com.cloud.network.security.SecurityGroupVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -5610,11 +5607,12 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio Account curAccount = _accountDao.findById(curVm.getAccountId()); long callingUserId = CallContext.current().getCallingUserId(); Account callerAccount = CallContext.current().getCallingAccount(); -// IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, curAccount.getId() == Account.ACCOUNT_ID_SYSTEM, callerAccount, callingUserId, dataCenter, null, null); +// IpAddress ipAddress = _ipAddrMgr.assignPublicIpAddress(zoneId, curVm.getPodIdToDeployIn(), callerAccount, VlanType.DirectAttached, ) + IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, false, callerAccount, callingUserId, dataCenter, null, null); String ipv6Address = null; String macAddress = null; -// IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), null, macAddress); - IpAddresses addr = new IpAddresses("172.20.0.98", ipv6Address, macAddress); + IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), ipv6Address, macAddress); +// IpAddresses addr = new IpAddresses("172.20.0.98", ipv6Address, macAddress); long serviceOfferingId = curVm.getServiceOfferingId(); ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); List securityGroupList = _securityGroupMgr.getSecurityGroupsForVm(curVm.getId()); From 52f281035c13a311dc91692dda66c9a6055b0148 Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 21:01:17 -0400 Subject: [PATCH 48/58] add ip allocation --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 1e07f2fbf8d3..9ff1814ef36e 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5608,7 +5608,7 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio long callingUserId = CallContext.current().getCallingUserId(); Account callerAccount = CallContext.current().getCallingAccount(); // IpAddress ipAddress = _ipAddrMgr.assignPublicIpAddress(zoneId, curVm.getPodIdToDeployIn(), callerAccount, VlanType.DirectAttached, ) - IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, false, callerAccount, callingUserId, dataCenter, null, null); + IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, false, callerAccount, callingUserId, dataCenter, true, null); String ipv6Address = null; String macAddress = null; IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), ipv6Address, macAddress); From 1a475b3916d8549352f48be954957ace63feb113 Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 21:02:49 -0400 Subject: [PATCH 49/58] fix the check-style typo --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 9ff1814ef36e..8ecd7c1ca91e 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -52,7 +52,11 @@ import javax.xml.parsers.ParserConfigurationException; //import com.cloud.network.IpAddress; -import com.cloud.network.*; +import com.cloud.network.IpAddress; +import com.cloud.network.IpAddressManager; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.PhysicalNetwork; import com.cloud.network.security.SecurityGroupVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; From b64c48bf3a8e7ab0e9c7ada9a72024a6ff8fb1ce Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 23:28:31 -0400 Subject: [PATCH 50/58] try null address for vm creation --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 8ecd7c1ca91e..636c9ddbf905 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5612,10 +5612,10 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio long callingUserId = CallContext.current().getCallingUserId(); Account callerAccount = CallContext.current().getCallingAccount(); // IpAddress ipAddress = _ipAddrMgr.assignPublicIpAddress(zoneId, curVm.getPodIdToDeployIn(), callerAccount, VlanType.DirectAttached, ) - IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, false, callerAccount, callingUserId, dataCenter, true, null); +// IpAddress ipAddress = _ipAddrMgr.allocateIp(curAccount, false, callerAccount, callingUserId, dataCenter, true, null); String ipv6Address = null; String macAddress = null; - IpAddresses addr = new IpAddresses(ipAddress.getVmIp(), ipv6Address, macAddress); + IpAddresses addr = new IpAddresses(null, ipv6Address, macAddress); // IpAddresses addr = new IpAddresses("172.20.0.98", ipv6Address, macAddress); long serviceOfferingId = curVm.getServiceOfferingId(); ServiceOffering serviceOffering = _serviceOfferingDao.findById(curVm.getId(), serviceOfferingId); From 6b145d17494d6467c71d7caab7db56195fbec832 Mon Sep 17 00:00:00 2001 From: junxuan Date: Wed, 7 Jul 2021 23:31:19 -0400 Subject: [PATCH 51/58] ignore unused ip --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 636c9ddbf905..4d23854009f6 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -50,9 +50,8 @@ import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; - //import com.cloud.network.IpAddress; -import com.cloud.network.IpAddress; +//import com.cloud.network.IpAddress; import com.cloud.network.IpAddressManager; import com.cloud.network.Network; import com.cloud.network.NetworkModel; From fbf37531d0312af3ed9d94f76330f0514625d351 Mon Sep 17 00:00:00 2001 From: junxuan Date: Thu, 8 Jul 2021 00:37:27 -0400 Subject: [PATCH 52/58] finish the network allocation --- .../src/main/java/com/cloud/template/TemplateManagerImpl.java | 2 +- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index 48f5407f6398..79a7646b813e 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -1979,7 +1979,7 @@ public VMTemplateVO createPrivateTemplateRecord(CloneVMCmd cmd, Account template VMTemplateVO privateTemplate = null; privateTemplate = new VMTemplateVO(nextTemplateId, name, ImageFormat.RAW, isPublic, featured, isExtractable, TemplateType.USER, null, true, 64, templateOwner.getId(), null, description, - true, guestOS.getId(), true, hyperType, null, new HashMap<>(){{put("template to be cleared", "yes");}}, false, false, false, false); + false, guestOS.getId(), true, hyperType, null, new HashMap<>(){{put("template to be cleared", "yes");}}, false, false, false, false); List stores = _imgStoreDao.findRegionImageStores(); if (!CollectionUtils.isEmpty(stores)) { privateTemplate.setCrossZones(true); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 4d23854009f6..46863728851c 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5665,7 +5665,6 @@ public UserVm recordVirtualMachineToDB(CloneVMCmd cmd) throws ConcurrentOperatio cmd.getCustomId(), new HashMap<>(), null, new HashMap<>(), dynamicScalingEnabled); } } - return vmResult; } From 63c7c5e9b61a0ce39013439e23117d2949018ae7 Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 9 Jul 2021 00:50:27 -0400 Subject: [PATCH 53/58] datadisk code added --- .../com/cloud/storage/VolumeApiService.java | 4 + .../main/java/com/cloud/vm/UserVmService.java | 3 +- .../api/command/user/vm/CloneVMCmd.java | 2 +- .../cloud/storage/VolumeApiServiceImpl.java | 7 + .../java/com/cloud/vm/UserVmManagerImpl.java | 140 ++++++++++++------ 5 files changed, 110 insertions(+), 46 deletions(-) diff --git a/api/src/main/java/com/cloud/storage/VolumeApiService.java b/api/src/main/java/com/cloud/storage/VolumeApiService.java index 5c4130158cd8..5ea49650ae37 100644 --- a/api/src/main/java/com/cloud/storage/VolumeApiService.java +++ b/api/src/main/java/com/cloud/storage/VolumeApiService.java @@ -21,6 +21,8 @@ import java.net.MalformedURLException; import java.util.Map; +import com.cloud.exception.StorageUnavailableException; +import org.apache.cloudstack.api.command.user.vm.CloneVMCmd; 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; @@ -92,6 +94,8 @@ public interface VolumeApiService { Volume detachVolumeViaDestroyVM(long vmId, long volumeId); + Volume cloneDataVolume(CloneVMCmd cmd, long snapshotId, Volume volume) throws StorageUnavailableException; + Volume detachVolumeFromVM(DetachVolumeCmd cmd); Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account account, boolean quiescevm, Snapshot.LocationType locationType, boolean asyncBackup, Map tags) diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index 90f41d860ffa..74c090eb5f32 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.Optional; +import com.cloud.storage.VolumeApiService; import org.apache.cloudstack.api.BaseCmd.HTTPMethod; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; @@ -94,7 +95,7 @@ public interface UserVmService { * - the command specifying vmId to be cloned * @return the VM if cloneVM operation is successful * */ - Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; + Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService volumeService) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ResourceAllocationException; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index cdd5cb342c4d..66414dc28969 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -146,7 +146,7 @@ public void execute() { try { CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); s_logger.info("starting actual VM id: " + getEntityId()); - result = _userVmService.cloneVirtualMachine(this); + result = _userVmService.cloneVirtualMachine(this, _volumeService); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index a2b2a4978c0d..732ece2345db 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -31,6 +31,7 @@ import javax.inject.Inject; +import org.apache.cloudstack.api.command.user.vm.CloneVMCmd; 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; @@ -900,6 +901,12 @@ public VolumeVO createVolume(CreateVolumeCmd cmd) { } } + @Override + public Volume cloneDataVolume(CloneVMCmd cmd, long snapshotId, Volume volume) throws StorageUnavailableException { + long vmId = cmd.getEntityId(); + return createVolumeFromSnapshot((VolumeVO) volume, snapshotId, vmId); + } + protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId, Long vmId) throws StorageUnavailableException { VolumeInfo createdVolume = null; SnapshotVO snapshot = _snapshotDao.findById(snapshotId); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 46863728851c..4be22defc2f6 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -22,19 +22,8 @@ import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -57,6 +46,7 @@ import com.cloud.network.NetworkModel; import com.cloud.network.PhysicalNetwork; import com.cloud.network.security.SecurityGroupVO; +import com.cloud.storage.*; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountService; @@ -68,6 +58,7 @@ import com.cloud.user.UserStatisticsVO; import com.cloud.user.UserVO; import com.cloud.user.VmDiskStatisticsVO; +import com.cloud.utils.db.*; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -125,15 +116,13 @@ import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DettachCommand; -import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; -import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; -import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; +import org.apache.cloudstack.storage.datastore.db.*; import org.apache.commons.codec.binary.Base64; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; +import org.owasp.esapi.util.CollectionsUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -273,26 +262,9 @@ import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.service.dao.ServiceOfferingDetailsDao; -import com.cloud.storage.DataStoreRole; -import com.cloud.storage.DiskOfferingVO; -import com.cloud.storage.GuestOSCategoryVO; -import com.cloud.storage.GuestOSVO; -import com.cloud.storage.ScopeType; -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.StoragePoolType; 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.VMTemplateStorageResourceAssoc; -import com.cloud.storage.VMTemplateVO; -import com.cloud.storage.VMTemplateZoneVO; -import com.cloud.storage.Volume; -import com.cloud.storage.VolumeApiService; -import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.DiskOfferingDao; import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSDao; @@ -319,16 +291,6 @@ import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.crypt.RSAHelper; -import com.cloud.utils.db.DB; -import com.cloud.utils.db.EntityManager; -import com.cloud.utils.db.GlobalLock; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.db.Transaction; -import com.cloud.utils.db.TransactionCallbackNoReturn; -import com.cloud.utils.db.TransactionCallbackWithException; -import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; -import com.cloud.utils.db.TransactionStatus; -import com.cloud.utils.db.UUIDManager; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExecutionException; import com.cloud.utils.fsm.NoTransitionException; @@ -4590,11 +4552,101 @@ public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueExce _resourceLimitMgr.checkResourceLimit(activeOwner, ResourceType.primary_storage, totalSize); } + private VolumeVO saveDataDiskVolumeFromSnapShot(final Account owner, final Boolean displayVolume, final Long zoneId, final Long diskOfferingId, + final Storage.ProvisioningType provisioningType, final Long size, final Long minIops, final Long maxIops, final VolumeVO parentVolume, final String volumeName, final String uuid, final Map details) { + return Transaction.execute((TransactionCallback) status -> { + VolumeVO volume = new VolumeVO(volumeName, -1, -1, -1, -1, new Long(-1), null, null, provisioningType, 0, Volume.Type.DATADISK); + volume.setPoolId(null); + volume.setUuid(uuid); + volume.setDataCenterId(zoneId); + volume.setPodId(null); + volume.setAccountId(owner.getId()); + volume.setDomainId(owner.getDomainId()); + volume.setDiskOfferingId(diskOfferingId); + volume.setSize(size); + volume.setMinIops(minIops); + volume.setMaxIops(maxIops); + volume.setInstanceId(null); + volume.setUpdated(new Date()); + volume.setDisplayVolume(displayVolume); + if (parentVolume != null) { + volume.setTemplateId(parentVolume.getTemplateId()); + volume.setFormat(parentVolume.getFormat()); + } else { + volume.setTemplateId(null); + } + + volume = _volsDao.persist(volume); + CallContext.current().setEventDetails("Volume Id: " + volume.getUuid()); + + // Increment resource count during allocation; if actual creation fails, + // decrement it + _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume, displayVolume); + _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.primary_storage, displayVolume, new Long(volume.getSize())); + return volume; + }); + } + @Override @ActionEvent(eventType = EventTypes.EVENT_VM_CLONE, eventDescription = "clone vm", async = true) - public Optional cloneVirtualMachine(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, CloudRuntimeException, InsufficientCapacityException, ResourceAllocationException { + public Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService volumeService) throws ResourceUnavailableException, ConcurrentOperationException, CloudRuntimeException, InsufficientCapacityException, ResourceAllocationException { long vmId = cmd.getEntityId(); UserVmVO curVm = _vmDao.findById(vmId); + // create and attach data disk + long targetClonedVmId = cmd.getId(); + Account caller = CallContext.current().getCallingAccount(); + List dataDisks = _volsDao.findByInstanceAndType(targetClonedVmId, Volume.Type.DATADISK); + List createdSnapshots = new ArrayList<>(); + List createdVolumes = new ArrayList<>(); + long zoneId = cmd.getTargetVM().getDataCenterId(); + s_logger.info("Trying to attach data disk before starting the VM..."); + if (dataDisks.size() > 0) { + VolumeVO newDatadisk = null; + try { + for (VolumeVO dataDisk : dataDisks) { + long diskId = dataDisk.getId(); + SnapshotVO dataSnapShot = (SnapshotVO) volumeService.allocSnapshot(diskId, Snapshot.MANUAL_POLICY_ID, "DataDisk-Clone" + dataDisk.getName(), null); + if (dataSnapShot == null) { + throw new CloudRuntimeException("Unable to allocate snapshot of data disk: " + dataDisk.getId() + " name: " + dataDisk.getName()); + } + createdSnapshots.add(dataSnapShot); + SnapshotVO snapshotEntity = (SnapshotVO) volumeService.takeSnapshot(diskId, Snapshot.MANUAL_POLICY_ID, dataSnapShot.getId(), caller, false, null, false, new HashMap<>()); + if (snapshotEntity == null) { + throw new CloudRuntimeException("Error when creating the snapshot entity"); + } + if (snapshotEntity.getState() != Snapshot.State.BackedUp) { + throw new CloudRuntimeException("Async backup of snapshot happens during the clone for snapshot id: " + dataSnapShot.getId()); + } + long diskOfferingId = snapshotEntity.getDiskOfferingId(); + DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId); + Long minIops = snapshotEntity.getMinIops(); + Long maxIops = snapshotEntity.getMaxIops(); + Long size = snapshotEntity.getSize(); + Storage.ProvisioningType provisioningType = diskOffering.getProvisioningType(); + DataCenterVO dataCenter = _dcDao.findById(zoneId); + String volumeName = snapshotEntity.getName() + "-DataDisk-Volume"; + VolumeVO parentVolume = _volsDao.findByIdIncludingRemoved(snapshotEntity.getVolumeId()); + newDatadisk = saveDataDiskVolumeFromSnapShot(caller, false, zoneId, + diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, volumeName, _uuidMgr.generateUuid(Volume.class, null), new HashMap<>()); + VolumeVO volumeEntity = (VolumeVO) volumeService.cloneDataVolume(cmd, snapshotEntity.getId(), newDatadisk); + createdVolumes.add(volumeEntity); + } + for (VolumeVO createdVol : createdVolumes) { + ((VolumeApiServiceImpl) volumeService).attachVolumeToVM(vmId, createdVol.getId(), createdVol.getDeviceId()); + } + } catch (CloudRuntimeException e){ + // clear the created disks + s_logger.warn("data disk process failed during clone, clearing the temporary resources..."); + if (newDatadisk != null) { + _resourceLimitMgr.decrementResourceCount(caller.getId(), ResourceType.volume, false); + _resourceLimitMgr.decrementResourceCount(caller.getId(), ResourceType.primary_storage, false, new Long(newDatadisk.getSize())); + } + throw new CloudRuntimeException(e.getMessage()); + } finally { + // clear the temporary data snapshots + } + } + // start the VM if successfull Long podId = curVm.getPodIdToDeployIn(); Long clusterId = null; Long hostId = curVm.getHostId(); From fcb81528deba61fee9abb9e9a0db7e2f8149c0d9 Mon Sep 17 00:00:00 2001 From: junxuan Date: Fri, 9 Jul 2021 14:51:23 -0400 Subject: [PATCH 54/58] fix the import typos --- .../java/com/cloud/vm/UserVmManagerImpl.java | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 4be22defc2f6..f06f8cdad073 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -22,8 +22,19 @@ import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -46,7 +57,24 @@ import com.cloud.network.NetworkModel; import com.cloud.network.PhysicalNetwork; import com.cloud.network.security.SecurityGroupVO; -import com.cloud.storage.*; +import com.cloud.storage.DataStoreRole; +import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.GuestOSCategoryVO; +import com.cloud.storage.GuestOSVO; +import com.cloud.storage.ScopeType; +import com.cloud.storage.Snapshot; +import com.cloud.storage.SnapshotVO; +import com.cloud.storage.Storage; +import com.cloud.storage.StorageManager; +import com.cloud.storage.StoragePool; +import com.cloud.storage.StoragePoolStatus; +import com.cloud.storage.VMTemplateStorageResourceAssoc; +import com.cloud.storage.VMTemplateVO; +import com.cloud.storage.VMTemplateZoneVO; +import com.cloud.storage.Volume; +import com.cloud.storage.VolumeApiService; +import com.cloud.storage.VolumeApiServiceImpl; +import com.cloud.storage.VolumeVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountService; @@ -58,7 +86,17 @@ import com.cloud.user.UserStatisticsVO; import com.cloud.user.UserVO; import com.cloud.user.VmDiskStatisticsVO; -import com.cloud.utils.db.*; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.db.GlobalLock; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.db.TransactionCallbackNoReturn; +import com.cloud.utils.db.TransactionCallbackWithException; +import com.cloud.utils.db.TransactionCallbackWithExceptionNoReturn; +import com.cloud.utils.db.TransactionStatus; +import com.cloud.utils.db.UUIDManager; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -116,13 +154,15 @@ import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.storage.command.DeleteCommand; import org.apache.cloudstack.storage.command.DettachCommand; -import org.apache.cloudstack.storage.datastore.db.*; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreVO; import org.apache.commons.codec.binary.Base64; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; -import org.owasp.esapi.util.CollectionsUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -4468,9 +4508,11 @@ protected String validateUserData(String userData, HTTPMethod httpmethod) { @Override public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueException, ResourceUnavailableException, CloudRuntimeException, ResourceAllocationException { + if (cmd.getAccountName() != null && cmd.getDomainId() == null) { throw new InvalidParameterValueException("You must input the domainId together with the account name"); } + final DomainVO domain = cmd.getDomainId() == null ? null : _domainDao.findById(cmd.getDomainId()); final Account account = cmd.getAccountName() == null ? null : _accountService.getActiveAccountByName(cmd.getAccountName(), cmd.getDomainId()); if (domain != null && account != null) { @@ -4492,6 +4534,10 @@ public void checkCloneCondition(CloneVMCmd cmd) throws InvalidParameterValueExce if (vmStatus.getHypervisorType() != HypervisorType.KVM && vmStatus.getHypervisorType() != HypervisorType.Simulator) { throw new CloudRuntimeException("The clone operation is only supported on KVM and Simulator!"); } + String kvmEnabled = _configDao.getValue("kvm.snapshot.enabled"); + if (kvmEnabled == null || !kvmEnabled.equalsIgnoreCase("true")) { + throw new CloudRuntimeException("Clone VM is not supported, as snapshots are disabled"); + } Long accountId = curVm.getAccountId(); Account vmOwner = _accountDao.findById(accountId); if (vmOwner == null) { From 78d5295b926d0d6607d7e64310b123dd9906af2e Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 11 Jul 2021 03:29:34 -0400 Subject: [PATCH 55/58] fix the service api impl --- api/src/main/java/com/cloud/storage/VolumeApiService.java | 2 ++ .../main/java/com/cloud/storage/VolumeApiServiceImpl.java | 5 +++++ server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/com/cloud/storage/VolumeApiService.java b/api/src/main/java/com/cloud/storage/VolumeApiService.java index 5ea49650ae37..c9a5139043f6 100644 --- a/api/src/main/java/com/cloud/storage/VolumeApiService.java +++ b/api/src/main/java/com/cloud/storage/VolumeApiService.java @@ -105,6 +105,8 @@ Snapshot takeSnapshot(Long volumeId, Long policyId, Long snapshotId, Account acc Volume updateVolume(long volumeId, String path, String state, Long storageId, Boolean displayVolume, String customId, long owner, String chainInfo); + Volume attachVolumeToVm(CloneVMCmd cmd, Long volumeId, Long deviceId); + /** * Extracts the volume to a particular location. * diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index 732ece2345db..95072721109a 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -1670,6 +1670,11 @@ private Volume orchestrateAttachVolumeToVM(Long vmId, Long volumeId, Long device return newVol; } + @Override + public Volume attachVolumeToVm(CloneVMCmd cmd, Long volumeId, Long deviceId) { + return attachVolumeToVM(cmd.getEntityId(), volumeId, deviceId); + } + public Volume attachVolumeToVM(Long vmId, Long volumeId, Long deviceId) { Account caller = CallContext.current().getCallingAccount(); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index f06f8cdad073..471b88c5815d 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4678,7 +4678,8 @@ public Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService vol createdVolumes.add(volumeEntity); } for (VolumeVO createdVol : createdVolumes) { - ((VolumeApiServiceImpl) volumeService).attachVolumeToVM(vmId, createdVol.getId(), createdVol.getDeviceId()); +// ((VolumeApiServiceImpl) volumeService).attachVolumeToVM(vmId, createdVol.getId(), createdVol.getDeviceId()); + volumeService.attachVolumeToVm(cmd, createdVol.getId(), createdVol.getDeviceId()); } } catch (CloudRuntimeException e){ // clear the created disks From 1414e3a2621bfd5d9e15b1125835262b7014d4c0 Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 11 Jul 2021 14:21:03 -0400 Subject: [PATCH 56/58] clear unused import --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 471b88c5815d..9a940d402d4d 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -73,7 +73,6 @@ import com.cloud.storage.VMTemplateZoneVO; import com.cloud.storage.Volume; import com.cloud.storage.VolumeApiService; -import com.cloud.storage.VolumeApiServiceImpl; import com.cloud.storage.VolumeVO; import com.cloud.user.Account; import com.cloud.user.AccountManager; From 877172893d2f555b50b5b8a70ca7ae0a383a0839 Mon Sep 17 00:00:00 2001 From: junxuan Date: Sun, 11 Jul 2021 15:48:16 -0400 Subject: [PATCH 57/58] ake the data disk shown --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 9a940d402d4d..7b0a2ff7d8ac 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -4671,7 +4671,7 @@ public Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService vol DataCenterVO dataCenter = _dcDao.findById(zoneId); String volumeName = snapshotEntity.getName() + "-DataDisk-Volume"; VolumeVO parentVolume = _volsDao.findByIdIncludingRemoved(snapshotEntity.getVolumeId()); - newDatadisk = saveDataDiskVolumeFromSnapShot(caller, false, zoneId, + newDatadisk = saveDataDiskVolumeFromSnapShot(caller, true, zoneId, diskOfferingId, provisioningType, size, minIops, maxIops, parentVolume, volumeName, _uuidMgr.generateUuid(Volume.class, null), new HashMap<>()); VolumeVO volumeEntity = (VolumeVO) volumeService.cloneDataVolume(cmd, snapshotEntity.getId(), newDatadisk); createdVolumes.add(volumeEntity); From c6279ce1c70a5a74c877441addb4fa3a6d1bc0a1 Mon Sep 17 00:00:00 2001 From: junxuan Date: Mon, 12 Jul 2021 18:08:53 -0400 Subject: [PATCH 58/58] data disk snapshot clearance and exception handler --- .../main/java/com/cloud/vm/UserVmService.java | 3 +- .../api/command/user/vm/CloneVMCmd.java | 5 ++-- .../java/com/cloud/vm/UserVmManagerImpl.java | 29 ++++++++++++++----- 3 files changed, 26 insertions(+), 11 deletions(-) diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index 74c090eb5f32..da8c2373ca79 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -21,6 +21,7 @@ import java.util.Optional; import com.cloud.storage.VolumeApiService; +import com.cloud.storage.snapshot.SnapshotApiService; import org.apache.cloudstack.api.BaseCmd.HTTPMethod; import org.apache.cloudstack.api.command.admin.vm.AssignVMCmd; import org.apache.cloudstack.api.command.admin.vm.RecoverVMCmd; @@ -95,7 +96,7 @@ public interface UserVmService { * - the command specifying vmId to be cloned * @return the VM if cloneVM operation is successful * */ - Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService volumeService) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; + Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService volumeService, SnapshotApiService snapshotService) throws ResourceUnavailableException, ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException; void checkCloneCondition(CloneVMCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException, ResourceAllocationException; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java index 66414dc28969..136f5b9ce087 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vm/CloneVMCmd.java @@ -108,6 +108,7 @@ public void create() throws ResourceAllocationException { s_logger.info("The template id recorded is: " + template.getId()); setTemporaryTemlateId(template.getId()); _templateService.createPrivateTemplate(this); + _snapshotService.deleteSnapshot(getTemporarySnapShotId()); UserVm vmRecord = _userVmService.recordVirtualMachineToDB(this); if (vmRecord == null) { throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "unable to record a new VM to db!"); @@ -146,7 +147,7 @@ public void execute() { try { CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); s_logger.info("starting actual VM id: " + getEntityId()); - result = _userVmService.cloneVirtualMachine(this, _volumeService); + result = _userVmService.cloneVirtualMachine(this, _volumeService, _snapshotService); } catch (ResourceUnavailableException ex) { s_logger.warn("Exception: ", ex); throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); @@ -160,7 +161,7 @@ public void execute() { } result.ifPresentOrElse((userVm)-> { UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", result.get()).get(0); - response.setResponseName("test_clone"); + response.setResponseName("full_clone"); setResponseObject(response); }, ()-> { throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, "failed to clone VM: " + getId()); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 7b0a2ff7d8ac..d5691007469b 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -74,6 +74,7 @@ import com.cloud.storage.Volume; import com.cloud.storage.VolumeApiService; import com.cloud.storage.VolumeVO; +import com.cloud.storage.snapshot.SnapshotApiService; import com.cloud.user.Account; import com.cloud.user.AccountManager; import com.cloud.user.AccountService; @@ -4634,7 +4635,7 @@ private VolumeVO saveDataDiskVolumeFromSnapShot(final Account owner, final Boole @Override @ActionEvent(eventType = EventTypes.EVENT_VM_CLONE, eventDescription = "clone vm", async = true) - public Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService volumeService) throws ResourceUnavailableException, ConcurrentOperationException, CloudRuntimeException, InsufficientCapacityException, ResourceAllocationException { + public Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService volumeService, SnapshotApiService snapshotService) throws ResourceUnavailableException, ConcurrentOperationException, CloudRuntimeException, InsufficientCapacityException, ResourceAllocationException { long vmId = cmd.getEntityId(); UserVmVO curVm = _vmDao.findById(vmId); // create and attach data disk @@ -4676,22 +4677,34 @@ public Optional cloneVirtualMachine(CloneVMCmd cmd, VolumeApiService vol VolumeVO volumeEntity = (VolumeVO) volumeService.cloneDataVolume(cmd, snapshotEntity.getId(), newDatadisk); createdVolumes.add(volumeEntity); } - for (VolumeVO createdVol : createdVolumes) { -// ((VolumeApiServiceImpl) volumeService).attachVolumeToVM(vmId, createdVol.getId(), createdVol.getDeviceId()); - volumeService.attachVolumeToVm(cmd, createdVol.getId(), createdVol.getDeviceId()); - } } catch (CloudRuntimeException e){ - // clear the created disks s_logger.warn("data disk process failed during clone, clearing the temporary resources..."); + for (VolumeVO dataDiskToClear : createdVolumes) { + volumeService.destroyVolume(dataDiskToClear.getId(), caller, true, false); + } + // clear the created disks if (newDatadisk != null) { - _resourceLimitMgr.decrementResourceCount(caller.getId(), ResourceType.volume, false); - _resourceLimitMgr.decrementResourceCount(caller.getId(), ResourceType.primary_storage, false, new Long(newDatadisk.getSize())); + volumeService.destroyVolume(newDatadisk.getId(), caller, true, false); } throw new CloudRuntimeException(e.getMessage()); } finally { // clear the temporary data snapshots + for (Snapshot snapshotLeftOver : createdSnapshots) { + snapshotService.deleteSnapshot(snapshotLeftOver.getId()); + } } } + + for (VolumeVO createdVol : createdVolumes) { + try { + volumeService.attachVolumeToVm(cmd, createdVol.getId(), createdVol.getDeviceId()); + } catch (CloudRuntimeException e) { + s_logger.warn("data disk: " + createdVol.getId() + " attachment to VM " + vmId + " failed due to" + e.getMessage()); + s_logger.info("Clearing the data disk: " + createdVol.getId()); + volumeService.destroyVolume(createdVol.getId(), caller, true, true); + } + } + // start the VM if successfull Long podId = curVm.getPodIdToDeployIn(); Long clusterId = null;