|
| 1 | +// Licensed to the Apache Software Foundation (ASF) under one |
| 2 | +// or more contributor license agreements. See the NOTICE file |
| 3 | +// distributed with this work for additional information |
| 4 | +// regarding copyright ownership. The ASF licenses this file |
| 5 | +// to you under the Apache License, Version 2.0 (the |
| 6 | +// "License"); you may not use this file except in compliance |
| 7 | +// with the License. You may obtain a copy of the License at |
| 8 | +// |
| 9 | +// http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | +// |
| 11 | +// Unless required by applicable law or agreed to in writing, |
| 12 | +// software distributed under the License is distributed on an |
| 13 | +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 14 | +// KIND, either express or implied. See the License for the |
| 15 | +// specific language governing permissions and limitations |
| 16 | +// under the License. |
| 17 | +package org.apache.cloudstack.api.command.user.vm; |
| 18 | + |
| 19 | +import org.apache.cloudstack.acl.RoleType; |
| 20 | +import org.apache.cloudstack.api.ACL; |
| 21 | +import org.apache.cloudstack.api.APICommand; |
| 22 | +import org.apache.cloudstack.api.ApiArgValidator; |
| 23 | +import org.apache.cloudstack.api.ApiConstants; |
| 24 | +import org.apache.cloudstack.api.ApiErrorCode; |
| 25 | +import org.apache.cloudstack.api.BaseCmd; |
| 26 | +import org.apache.cloudstack.api.Parameter; |
| 27 | +import org.apache.cloudstack.api.ResponseObject; |
| 28 | +import org.apache.cloudstack.api.ServerApiException; |
| 29 | +import org.apache.cloudstack.api.response.BackupResponse; |
| 30 | +import org.apache.cloudstack.api.response.DomainResponse; |
| 31 | +import org.apache.cloudstack.api.response.ProjectResponse; |
| 32 | +import org.apache.cloudstack.api.response.ServiceOfferingResponse; |
| 33 | +import org.apache.cloudstack.api.response.SuccessResponse; |
| 34 | +import org.apache.cloudstack.api.response.TemplateResponse; |
| 35 | +import org.apache.cloudstack.context.CallContext; |
| 36 | + |
| 37 | +import com.cloud.exception.ConcurrentOperationException; |
| 38 | +import com.cloud.exception.InsufficientCapacityException; |
| 39 | +import com.cloud.exception.InsufficientServerCapacityException; |
| 40 | +import com.cloud.exception.ResourceAllocationException; |
| 41 | +import com.cloud.exception.ResourceUnavailableException; |
| 42 | +import com.cloud.utils.Pair; |
| 43 | +import com.cloud.vm.VirtualMachine; |
| 44 | + |
| 45 | +@APICommand(name = "createVMFromBxBackup", |
| 46 | + description = "Creates and automatically starts a VM from a backup.", |
| 47 | + responseObject = SuccessResponse.class, |
| 48 | + responseView = ResponseObject.ResponseView.Restricted, |
| 49 | + entityType = {VirtualMachine.class}, |
| 50 | + requestHasSensitiveInfo = false, responseHasSensitiveInfo = true, |
| 51 | + since = "4.21.0", |
| 52 | + authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User}) |
| 53 | +public class CreateVMFromBxBackupCmd extends BaseCmd { |
| 54 | + |
| 55 | + ///////////////////////////////////////////////////// |
| 56 | + //////////////// API parameters ///////////////////// |
| 57 | + ///////////////////////////////////////////////////// |
| 58 | + |
| 59 | + @Parameter(name = ApiConstants.BACKUP_ID, |
| 60 | + type = CommandType.UUID, |
| 61 | + entityType = BackupResponse.class, |
| 62 | + required = true, |
| 63 | + description = "backup ID to create the VM from") |
| 64 | + private Long backupId; |
| 65 | + |
| 66 | + @ACL |
| 67 | + @Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, entityType = ServiceOfferingResponse.class, description = "the ID of the service offering for the virtual machine") |
| 68 | + private Long serviceOfferingId; |
| 69 | + |
| 70 | + @ACL |
| 71 | + @Parameter(name = ApiConstants.TEMPLATE_ID, type = CommandType.UUID, entityType = TemplateResponse.class, description = "the ID of the template for the virtual machine") |
| 72 | + private Long templateId; |
| 73 | + |
| 74 | + @Parameter(name = ApiConstants.PRESERVE_IP, type = CommandType.BOOLEAN, description = "Use the same IP/MAC addresses as stored in the backup metadata. Works only if the original Instance is deleted and the IP/MAC address is available.") |
| 75 | + private Boolean preserveIp; |
| 76 | + |
| 77 | + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "host name for the virtual machine", validations = {ApiArgValidator.RFCComplianceDomainName}) |
| 78 | + private String name; |
| 79 | + |
| 80 | + ///////////////////////////////////////////////////// |
| 81 | + /////////////////// Accessors /////////////////////// |
| 82 | + ///////////////////////////////////////////////////// |
| 83 | + |
| 84 | + public Long getBackupId() { |
| 85 | + return backupId; |
| 86 | + } |
| 87 | + |
| 88 | + public Long getServiceOfferingId() { |
| 89 | + return serviceOfferingId; |
| 90 | + } |
| 91 | + |
| 92 | + public Long getTemplateId() { |
| 93 | + return templateId; |
| 94 | + } |
| 95 | + |
| 96 | + public boolean getPreserveIp() { |
| 97 | + return (preserveIp != null) ? preserveIp : false; |
| 98 | + } |
| 99 | + |
| 100 | + public String getName() { |
| 101 | + return name; |
| 102 | + } |
| 103 | + |
| 104 | + //Owner information |
| 105 | + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "an optional account for the virtual machine. Must be used with domainId.") |
| 106 | + private String accountName; |
| 107 | + |
| 108 | + @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. If account is NOT provided then virtual machine will be assigned to the caller account and domain.") |
| 109 | + private Long domainId; |
| 110 | + |
| 111 | + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Deploy vm for the project") |
| 112 | + private Long projectId; |
| 113 | + |
| 114 | + public void execute () { |
| 115 | + Pair<Boolean, String> result = null; |
| 116 | + try { |
| 117 | + result = _userVmService.restoreVMFromBxBackup(this); |
| 118 | + } catch (ResourceUnavailableException ex) { |
| 119 | + logger.warn("Exception: ", ex); |
| 120 | + throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage()); |
| 121 | + } catch (ResourceAllocationException ex) { |
| 122 | + logger.warn("Exception: ", ex); |
| 123 | + throw new ServerApiException(ApiErrorCode.RESOURCE_ALLOCATION_ERROR, ex.getMessage()); |
| 124 | + } catch (ConcurrentOperationException ex) { |
| 125 | + logger.warn("Exception: ", ex); |
| 126 | + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); |
| 127 | + } catch (InsufficientCapacityException ex) { |
| 128 | + StringBuilder message = new StringBuilder(ex.getMessage()); |
| 129 | + if (ex instanceof InsufficientServerCapacityException) { |
| 130 | + if (((InsufficientServerCapacityException)ex).isAffinityApplied()) { |
| 131 | + message.append(", Please check the affinity groups provided, there may not be sufficient capacity to follow them"); |
| 132 | + } |
| 133 | + } |
| 134 | + logger.info("{}: {}", message.toString(), ex.getLocalizedMessage()); |
| 135 | + logger.debug(message.toString(), ex); |
| 136 | + throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, message.toString()); |
| 137 | + } |
| 138 | + |
| 139 | + if (result != null && Boolean.TRUE.equals(result.first())) { |
| 140 | + SuccessResponse response = new SuccessResponse(getCommandName()); |
| 141 | + response.setResponseName(getCommandName()); |
| 142 | + setResponseObject(response); |
| 143 | + // UserVmResponse response = _responseGenerator.createUserVmResponse(getResponseView(), "virtualmachine", vm).get(0); |
| 144 | + // response.setResponseName(getCommandName()); |
| 145 | + // setResponseObject(response); |
| 146 | + } else { |
| 147 | + String message = result != null ? result.second() : null; |
| 148 | + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, |
| 149 | + message != null ? message : "Failed to create VM from BX backup"); |
| 150 | + } |
| 151 | + } |
| 152 | + |
| 153 | + @Override |
| 154 | + public long getEntityOwnerId() { |
| 155 | + Long accountId = _accountService.finalizeAccountId(accountName, domainId, projectId, true); |
| 156 | + if (accountId == null) { |
| 157 | + return CallContext.current().getCallingAccount().getId(); |
| 158 | + } |
| 159 | + |
| 160 | + return accountId; |
| 161 | + } |
| 162 | +} |
0 commit comments