-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Clone a Virtual Machine #5216
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clone a Virtual Machine #5216
Changes from all commits
d3b8e74
e2f7228
6a2237c
6b2604d
8c815ab
fb6cb0a
77c39c2
1971a39
3687110
fbb886c
16d75da
779681c
5a81d2b
6f4fca9
896b033
cfd131c
9677858
85129ee
b6607f4
afae560
0a1405d
64c0fd5
e04dc22
7bef87f
d15f620
fee4a95
eecacc0
31824f2
e3bf894
99e5043
40abfac
d235477
a48d7fa
7fb0994
ed9ac4e
23a53cb
53785ed
306a7f4
8ecb6a5
a1bf574
9639389
0871f74
f5b896e
8bebd3b
21ac7a7
385df67
cec1ee9
d4d7570
52f2810
1a475b3
b64c48b
6b145d1
fbf3753
63c7c5e
fcb8152
78d5295
1414e3a
8771728
c6279ce
8fd5eb5
579fe8a
a005f1c
d339b54
0415cbc
4542f6b
03e380f
4d6d6cf
678d9d8
8ea6949
794ca8f
d9eac6e
14fa30c
0d893f0
c72654c
b0ab18b
a423887
4a3fc6d
83a25c8
d925bed
cdbbd60
6af4d28
a743d20
1194b63
0521448
de15e9d
76f9869
dee4406
b1ad52c
9401571
0cafec9
43d00b3
fa552ce
13bb0a5
8b55262
56f4d1c
4efd6b6
d65ab7b
aa02972
a669bf0
9f58ebd
53cbda0
feb0325
5fa517e
ab56212
8abf141
50d250e
1f6ae9b
ee6ce66
9ffd335
862f901
28e417c
4e7f40f
a44bba9
826ea4d
2ab2472
c3e836a
59bc42a
2fd4ca0
a470cea
6ff0ce4
a0314bf
520e951
cec42c3
5072889
a1e22b7
ae25c4a
866a21d
6b6cffb
b89f788
379309e
1f41407
7b048c4
40788cf
8da90f7
04a6f05
fb99861
63d3da1
feb548b
733b903
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,5 +48,4 @@ public String getCreateEventType() { | |
| public String getCreateEventDescription() { | ||
| return null; | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,185 @@ | ||||||||||
| // Licensed to the Apache Software Foundation (ASF) under one | ||||||||||
| // or more contributor license agreements. See the NOTICE file | ||||||||||
| // distributed with this work for additional information | ||||||||||
| // regarding copyright ownership. The ASF licenses this file | ||||||||||
| // to you under the Apache License, Version 2.0 (the | ||||||||||
| // "License"); you may not use this file except in compliance | ||||||||||
| // with the License. You may obtain a copy of the License at | ||||||||||
| // | ||||||||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||||||||
| // | ||||||||||
| // Unless required by applicable law or agreed to in writing, | ||||||||||
| // software distributed under the License is distributed on an | ||||||||||
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||||||
| // KIND, either express or implied. See the License for the | ||||||||||
| // specific language governing permissions and limitations | ||||||||||
| // under the License. | ||||||||||
| package org.apache.cloudstack.api.command.user.vm; | ||||||||||
|
|
||||||||||
| import com.cloud.event.EventTypes; | ||||||||||
| 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.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.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.BaseAsyncCreateCmd; | ||||||||||
| 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.DomainResponse; | ||||||||||
| 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", | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
or
Suggested change
|
||||||||||
| responseView = ResponseObject.ResponseView.Restricted, requestHasSensitiveInfo = false, responseHasSensitiveInfo = true, entityType = {VirtualMachine.class}, since="4.16.0") | ||||||||||
| public class CloneVMCmd extends BaseAsyncCreateCmd implements UserCmd { | ||||||||||
| public static final Logger s_logger = Logger.getLogger(CloneVMCmd.class.getName()); | ||||||||||
| private static final String s_name = "clonevirtualmachineresponse"; | ||||||||||
| private static final String CLONE_IDENTIFIER = "Clone"; | ||||||||||
|
|
||||||||||
| ///////////////////////////////////////////////////// | ||||||||||
| //////////////// API parameters ///////////////////// | ||||||||||
| ///////////////////////////////////////////////////// | ||||||||||
| @ACL(accessType = AccessType.OperateEntry) | ||||||||||
| @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType=UserVmResponse.class, | ||||||||||
| required = true, description = "The ID of the virtual machine") | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @atrocitytheme can you add a reason why you didn't apply this suggestion? |
||||||||||
| private Long virtualmachineid; | ||||||||||
|
|
||||||||||
| @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "name of the cloned virtual machine") | ||||||||||
| private String name; | ||||||||||
|
|
||||||||||
| //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; | ||||||||||
|
|
||||||||||
| @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; | ||||||||||
|
|
||||||||||
| public String getAccountName() { | ||||||||||
| return accountName; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public Long getDomainId() { | ||||||||||
| return domainId; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public String getName() { | ||||||||||
| return this.name; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public void setName(String name) { | ||||||||||
| this.name = name; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public Long getId() { | ||||||||||
| return this.virtualmachineid; | ||||||||||
| } | ||||||||||
| @Override | ||||||||||
| public String getEventType() { | ||||||||||
| return EventTypes.EVENT_VM_CLONE; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| @Override | ||||||||||
| public ApiCommandJobType getInstanceType() { | ||||||||||
| return ApiCommandJobType.VirtualMachine; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| @Override | ||||||||||
| public String getEventDescription() { | ||||||||||
| return "Cloning user VM: " + this._uuidMgr.getUuid(VirtualMachine.class, getId()); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| @Override | ||||||||||
| public void create() throws ResourceAllocationException { | ||||||||||
| try { | ||||||||||
| _userVmService.validateCloneCondition(this); | ||||||||||
| _userVmService.prepareCloneVirtualMachine(this); | ||||||||||
| } | ||||||||||
| 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()); | ||||||||||
| } catch (ServerApiException e) { | ||||||||||
| throw new ServerApiException(e.getErrorCode(), e.getDescription()); | ||||||||||
| } catch (CloudRuntimeException e) { | ||||||||||
| throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); | ||||||||||
|
Comment on lines
+113
to
+122
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could improve these logs with some context data and unify the catches. |
||||||||||
| } | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public boolean isPublic() { | ||||||||||
| return false; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public String getVMName() { | ||||||||||
| if (getName() == null) { | ||||||||||
| return getTargetVM().getInstanceName() + "-" + CLONE_IDENTIFIER; | ||||||||||
| } | ||||||||||
| return getName(); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public String getTemplateName() { | ||||||||||
| return (getVMName() + "-" + _uuidMgr.generateUuid(VirtualMachineTemplate.class, null)).substring(0, 32); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| @Override | ||||||||||
| public void execute() { | ||||||||||
| Optional<UserVm> result; | ||||||||||
| try { | ||||||||||
| CallContext.current().setEventDetails("Vm Id for full clone: " + getEntityId()); | ||||||||||
| s_logger.info("starting actual VM id: " + getEntityId()); | ||||||||||
| result = _userVmService.cloneVirtualMachine(this, _volumeService, _snapshotService); | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check if volume and snapshot service objects are required to be passed here, or these can be accessed from the service layer?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @atrocitytheme , I unresolved this comment as it is still valid.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see you did apply this in |
||||||||||
| } 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()); | ||||||||||
| } | ||||||||||
| catch (ResourceAllocationException | InsufficientCapacityException ex) { | ||||||||||
| s_logger.warn("Exception: ", ex); | ||||||||||
| throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage()); | ||||||||||
| } | ||||||||||
|
Comment on lines
+148
to
+158
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could improve these logs with some context data and unify the catches. |
||||||||||
| result.ifPresentOrElse((userVm)-> { | ||||||||||
| UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", result.get()).get(0); | ||||||||||
| response.setResponseName("full_clone"); | ||||||||||
| setResponseObject(response); | ||||||||||
| }, ()-> { | ||||||||||
| throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, "failed to clone VM: " + getId()); | ||||||||||
| }); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| @Override | ||||||||||
| public String getCommandName() { | ||||||||||
| return s_name; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| @Override | ||||||||||
| public long getEntityOwnerId() { | ||||||||||
| UserVm vm = this._responseGenerator.findUserVmById(getId()); | ||||||||||
| if (vm != null) { | ||||||||||
| return vm.getAccountId(); | ||||||||||
| } | ||||||||||
| return Account.ACCOUNT_ID_SYSTEM; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public UserVm getTargetVM() { | ||||||||||
| return this._userVmService.getUserVm(getId()); | ||||||||||
| } | ||||||||||
| } | ||||||||||
Uh oh!
There was an error while loading. Please reload this page.