server: add local ISO upload via UI (#3251)

Problem: Users can register ISOs from URL but cannot upload local ISOs.

Root cause: CloudStack provides browser-based upload support for volumes and templates, but ISOs are not supported.

Solution:
The existing browser-based upload from local functionality for templates and volumes (https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=39620237) is extended to support uploading local ISOs.

Extend the UI: A new button is created under the ISOs view: 'Upload from Local'. A new dialog form is displayed in which the user must select the ISO to upload from its local file system.
Extend the API: New 'GetUploadParamsForIso' API command is created to handle the ISO upload.
This commit is contained in:
Nicolas Vazquez 2019-06-05 14:40:51 -03:00 committed by Rohit Yadav
parent bbc0ae873d
commit 7247c5e97e
16 changed files with 807 additions and 36 deletions

View File

@ -24,6 +24,7 @@ import org.apache.cloudstack.api.BaseListTemplateOrIsoPermissionsCmd;
import org.apache.cloudstack.api.BaseUpdateTemplateOrIsoPermissionsCmd;
import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
import org.apache.cloudstack.api.command.user.iso.ExtractIsoCmd;
import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd;
import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
import org.apache.cloudstack.api.command.user.iso.UpdateIsoCmd;
import org.apache.cloudstack.api.command.user.template.CopyTemplateCmd;
@ -45,10 +46,12 @@ public interface TemplateApiService {
VirtualMachineTemplate registerTemplate(RegisterTemplateCmd cmd) throws URISyntaxException, ResourceAllocationException;
public GetUploadParamsResponse registerTemplateForPostUpload(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException, MalformedURLException;
GetUploadParamsResponse registerTemplateForPostUpload(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException, MalformedURLException;
VirtualMachineTemplate registerIso(RegisterIsoCmd cmd) throws IllegalArgumentException, ResourceAllocationException;
GetUploadParamsResponse registerIsoForPostUpload(GetUploadParamsForIsoCmd cmd) throws ResourceAllocationException, MalformedURLException;
VirtualMachineTemplate copyTemplate(CopyTemplateCmd cmd) throws StorageUnavailableException, ResourceAllocationException;
VirtualMachineTemplate prepareTemplate(long templateId, long zoneId, Long storageId);

View File

@ -0,0 +1,158 @@
// 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.iso;
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 org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.AbstractGetUploadParamsCmd;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
import org.apache.cloudstack.api.response.GuestOSResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.context.CallContext;
import java.net.MalformedURLException;
@APICommand(name = GetUploadParamsForIsoCmd.APINAME,
description = "upload an existing ISO into the CloudStack cloud.",
responseObject = GetUploadParamsResponse.class, since = "4.13",
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class GetUploadParamsForIsoCmd extends AbstractGetUploadParamsCmd {
public static final String APINAME = "getUploadParamsForIso";
private static final String s_name = "postuploadisoresponse";
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.BOOTABLE, type = BaseCmd.CommandType.BOOLEAN, description = "true if this ISO is bootable. If not passed explicitly its assumed to be true")
private Boolean bootable;
@Parameter(name = ApiConstants.DISPLAY_TEXT,
type = BaseCmd.CommandType.STRING,
required = true,
description = "the display text of the ISO. This is usually used for display purposes.",
length = 4096)
private String displayText;
@Parameter(name = ApiConstants.IS_FEATURED, type = BaseCmd.CommandType.BOOLEAN, description = "true if you want this ISO to be featured")
private Boolean featured;
@Parameter(name = ApiConstants.IS_PUBLIC,
type = BaseCmd.CommandType.BOOLEAN,
description = "true if you want to register the ISO to be publicly available to all users, false otherwise.")
private Boolean publicIso;
@Parameter(name = ApiConstants.IS_EXTRACTABLE, type = BaseCmd.CommandType.BOOLEAN, description = "true if the ISO or its derivatives are extractable; default is false")
private Boolean extractable;
@Parameter(name = ApiConstants.NAME, type = BaseCmd.CommandType.STRING, required = true, description = "the name of the ISO")
private String isoName;
@Parameter(name = ApiConstants.OS_TYPE_ID,
type = BaseCmd.CommandType.UUID,
entityType = GuestOSResponse.class,
description = "the ID of the OS type that best represents the OS of this ISO. If the ISO is bootable this parameter needs to be passed")
private Long osTypeId;
@Parameter(name=ApiConstants.ZONE_ID, type= BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
required=true, description="the ID of the zone you wish to register the ISO to.")
protected Long zoneId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Boolean isBootable() {
return bootable;
}
public String getDisplayText() {
return displayText;
}
public Boolean isFeatured() {
return featured;
}
public Boolean isPublic() {
return publicIso;
}
public Boolean isExtractable() {
return extractable;
}
public String getIsoName() {
return isoName;
}
public Long getOsTypeId() {
return osTypeId;
}
public Long getZoneId() {
return zoneId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
validateRequest();
try {
GetUploadParamsResponse response = _templateService.registerIsoForPostUpload(this);
response.setResponseName(getCommandName());
setResponseObject(response);
} catch (ResourceAllocationException | MalformedURLException e) {
s_logger.error("Exception while registering template", e);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Exception while registering ISO: " + e.getMessage());
}
}
private void validateRequest() {
if (getZoneId() <= 0) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid zoneid");
}
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public long getEntityOwnerId() {
Long accountId = _accountService.finalyzeAccountId(getAccountName(), getDomainId(), getProjectId(), true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
return accountId;
}
}

View File

@ -40,6 +40,7 @@ import com.cloud.user.Account;
import com.cloud.utils.db.DB;
import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd;
import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
@ -72,6 +73,11 @@ public class BareMetalTemplateAdapter extends TemplateAdapterBase implements Tem
throw new CloudRuntimeException("Baremetal doesn't support ISO template");
}
@Override
public TemplateProfile prepare(GetUploadParamsForIsoCmd cmd) throws ResourceAllocationException {
throw new CloudRuntimeException("Baremetal doesn't support ISO template");
}
private void templateCreateUsage(VMTemplateVO template, long dcId) {
if (template.getAccountId() != Account.ACCOUNT_ID_SYSTEM) {
UsageEventVO usageEvent =

View File

@ -337,6 +337,7 @@ import org.apache.cloudstack.api.command.user.iso.CopyIsoCmd;
import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
import org.apache.cloudstack.api.command.user.iso.DetachIsoCmd;
import org.apache.cloudstack.api.command.user.iso.ExtractIsoCmd;
import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd;
import org.apache.cloudstack.api.command.user.iso.ListIsoPermissionsCmd;
import org.apache.cloudstack.api.command.user.iso.ListIsosCmd;
import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
@ -3076,6 +3077,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
cmdList.add(DeleteManagementNetworkIpRangeCmd.class);
cmdList.add(UploadTemplateDirectDownloadCertificateCmd.class);
cmdList.add(ListMgmtsCmd.class);
cmdList.add(GetUploadParamsForIsoCmd.class);
// Out-of-band management APIs for admins
cmdList.add(EnableOutOfBandManagementForHostCmd.class);

View File

@ -0,0 +1,33 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.storage.upload.params;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.Storage;
public class IsoUploadParams extends UploadParamsBase {
public IsoUploadParams(long userId, String name, String displayText, Boolean isPublic, Boolean isFeatured,
Boolean isExtractable, Long osTypeId, Long zoneId, Boolean bootable, long ownerId) {
super(userId, name, displayText, isPublic, isFeatured, isExtractable, osTypeId, zoneId, bootable, ownerId);
setIso(true);
setBits(64);
setFormat(Storage.ImageFormat.ISO.toString());
setHypervisorType(Hypervisor.HypervisorType.None);
setRequiresHVM(true);
}
}

View File

@ -0,0 +1,38 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.storage.upload.params;
import com.cloud.hypervisor.Hypervisor;
import java.util.Map;
public class TemplateUploadParams extends UploadParamsBase {
public TemplateUploadParams(long userId, String name, String displayText,
Integer bits, Boolean passwordEnabled, Boolean requiresHVM,
Boolean isPublic, Boolean featured,
Boolean isExtractable, String format, Long guestOSId,
Long zoneId, Hypervisor.HypervisorType hypervisorType, String chksum,
String templateTag, long templateOwnerId,
Map details, Boolean sshkeyEnabled,
Boolean isDynamicallyScalable, Boolean isRoutingType) {
super(userId, name, displayText, bits, passwordEnabled, requiresHVM, isPublic, featured, isExtractable,
format, guestOSId, zoneId, hypervisorType, chksum, templateTag, templateOwnerId, details,
sshkeyEnabled, isDynamicallyScalable, isRoutingType);
setBootable(true);
}
}

View File

@ -0,0 +1,49 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.storage.upload.params;
import com.cloud.hypervisor.Hypervisor;
import java.util.Map;
public interface UploadParams {
boolean isIso();
long getUserId();
String getName();
String getDisplayText();
Integer getBits();
boolean isPasswordEnabled();
boolean requiresHVM();
String getUrl();
boolean isPublic();
boolean isFeatured();
boolean isExtractable();
String getFormat();
Long getGuestOSId();
Long getZoneId();
Hypervisor.HypervisorType getHypervisorType();
String getChecksum();
boolean isBootable();
String getTemplateTag();
long getTemplateOwnerId();
Map getDetails();
boolean isSshKeyEnabled();
String getImageStoreUuid();
boolean isDynamicallyScalable();
boolean isRoutingType();
boolean isDirectDownload();
}

View File

@ -0,0 +1,240 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.storage.upload.params;
import com.cloud.hypervisor.Hypervisor;
import java.util.Map;
public abstract class UploadParamsBase implements UploadParams {
private boolean isIso;
private long userId;
private String name;
private String displayText;
private Integer bits;
private boolean passwordEnabled;
private boolean requiresHVM;
private boolean isPublic;
private boolean featured;
private boolean isExtractable;
private String format;
private Long guestOSId;
private Long zoneId;
private Hypervisor.HypervisorType hypervisorType;
private String checksum;
private boolean bootable;
private String templateTag;
private long templateOwnerId;
private Map details;
private boolean sshkeyEnabled;
private boolean isDynamicallyScalable;
private boolean isRoutingType;
UploadParamsBase(long userId, String name, String displayText,
Integer bits, boolean passwordEnabled, boolean requiresHVM,
boolean isPublic, boolean featured,
boolean isExtractable, String format, Long guestOSId,
Long zoneId, Hypervisor.HypervisorType hypervisorType, String checksum,
String templateTag, long templateOwnerId,
Map details, boolean sshkeyEnabled,
boolean isDynamicallyScalable, boolean isRoutingType) {
this.userId = userId;
this.name = name;
this.displayText = displayText;
this.bits = bits;
this.passwordEnabled = passwordEnabled;
this.requiresHVM = requiresHVM;
this.isPublic = isPublic;
this.featured = featured;
this.isExtractable = isExtractable;
this.format = format;
this.guestOSId = guestOSId;
this.zoneId = zoneId;
this.hypervisorType = hypervisorType;
this.checksum = checksum;
this.templateTag = templateTag;
this.templateOwnerId = templateOwnerId;
this.details = details;
this.sshkeyEnabled = sshkeyEnabled;
this.isDynamicallyScalable = isDynamicallyScalable;
this.isRoutingType = isRoutingType;
}
UploadParamsBase(long userId, String name, String displayText, boolean isPublic, boolean isFeatured,
boolean isExtractable, Long osTypeId, Long zoneId, boolean bootable, long ownerId) {
this.userId = userId;
this.name = name;
this.displayText = displayText;
this.isPublic = isPublic;
this.featured = isFeatured;
this.isExtractable = isExtractable;
this.guestOSId = osTypeId;
this.zoneId = zoneId;
this.bootable = bootable;
this.templateOwnerId = ownerId;
}
@Override
public boolean isIso() {
return isIso;
}
@Override
public long getUserId() {
return userId;
}
@Override
public String getName() {
return name;
}
@Override
public String getDisplayText() {
return displayText;
}
@Override
public Integer getBits() {
return bits;
}
@Override
public boolean isPasswordEnabled() {
return passwordEnabled;
}
@Override
public boolean requiresHVM() {
return requiresHVM;
}
@Override
public String getUrl() {
return null;
}
@Override
public boolean isPublic() {
return isPublic;
}
@Override
public boolean isFeatured() {
return featured;
}
@Override
public boolean isExtractable() {
return isExtractable;
}
@Override
public String getFormat() {
return format;
}
@Override
public Long getGuestOSId() {
return guestOSId;
}
@Override
public Long getZoneId() {
return zoneId;
}
@Override
public Hypervisor.HypervisorType getHypervisorType() {
return hypervisorType;
}
@Override
public String getChecksum() {
return checksum;
}
@Override
public boolean isBootable() {
return bootable;
}
@Override
public String getTemplateTag() {
return templateTag;
}
@Override
public long getTemplateOwnerId() {
return templateOwnerId;
}
@Override
public Map getDetails() {
return details;
}
@Override
public boolean isSshKeyEnabled() {
return sshkeyEnabled;
}
@Override
public String getImageStoreUuid() {
return null;
}
@Override
public boolean isDynamicallyScalable() {
return isDynamicallyScalable;
}
@Override
public boolean isRoutingType() {
return isRoutingType;
}
@Override
public boolean isDirectDownload() {
return false;
}
void setIso(boolean iso) {
isIso = iso;
}
void setBootable(boolean bootable) {
this.bootable = bootable;
}
void setBits(Integer bits) {
this.bits = bits;
}
void setFormat(String format) {
this.format = format;
}
void setRequiresHVM(boolean requiresHVM) {
this.requiresHVM = requiresHVM;
}
void setHypervisorType(Hypervisor.HypervisorType hypervisorType) {
this.hypervisorType = hypervisorType;
}
}

View File

@ -35,6 +35,7 @@ import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionStatus;
import org.apache.cloudstack.agent.directdownload.CheckUrlAnswer;
import org.apache.cloudstack.agent.directdownload.CheckUrlCommand;
import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd;
import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
@ -166,6 +167,15 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase {
return profile;
}
@Override
public TemplateProfile prepare(GetUploadParamsForIsoCmd cmd) throws ResourceAllocationException {
TemplateProfile profile = super.prepare(cmd);
// Check that the resource limit for secondary storage won't be exceeded
_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()), ResourceType.secondary_storage);
return profile;
}
@Override
public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException {
TemplateProfile profile = super.prepare(cmd);

View File

@ -20,6 +20,7 @@ import java.util.List;
import java.util.Map;
import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd;
import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
import org.apache.cloudstack.api.command.user.template.DeleteTemplateCmd;
import org.apache.cloudstack.api.command.user.template.ExtractTemplateCmd;
@ -51,29 +52,31 @@ public interface TemplateAdapter extends Adapter {
}
}
public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException;
TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException;
public TemplateProfile prepare(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException;
TemplateProfile prepare(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException;
public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException;
TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException;
public VMTemplateVO create(TemplateProfile profile);
TemplateProfile prepare(GetUploadParamsForIsoCmd cmd) throws ResourceAllocationException;
public List<TemplateOrVolumePostUploadCommand> createTemplateForPostUpload(TemplateProfile profile);
VMTemplateVO create(TemplateProfile profile);
public TemplateProfile prepareDelete(DeleteTemplateCmd cmd);
List<TemplateOrVolumePostUploadCommand> createTemplateForPostUpload(TemplateProfile profile);
public TemplateProfile prepareDelete(DeleteIsoCmd cmd);
TemplateProfile prepareDelete(DeleteTemplateCmd cmd);
public TemplateProfile prepareExtractTemplate(ExtractTemplateCmd cmd);
TemplateProfile prepareDelete(DeleteIsoCmd cmd);
public boolean delete(TemplateProfile profile);
TemplateProfile prepareExtractTemplate(ExtractTemplateCmd cmd);
public TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
boolean delete(TemplateProfile profile);
TemplateProfile prepare(boolean isIso, Long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String accountName,
Long domainId, String chksum, Boolean bootable, Map details, boolean directDownload) throws ResourceAllocationException;
public TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
TemplateProfile prepare(boolean isIso, long userId, String name, String displayText, Integer bits, Boolean passwordEnabled, Boolean requiresHVM, String url,
Boolean isPublic, Boolean featured, Boolean isExtractable, String format, Long guestOSId, List<Long> zoneId, HypervisorType hypervisorType, String chksum,
Boolean bootable, String templateTag, Account templateOwner, Map details, Boolean sshKeyEnabled, String imageStoreUuid, Boolean isDynamicallyScalable,
TemplateType templateType, boolean directDownload) throws ResourceAllocationException;

View File

@ -23,8 +23,13 @@ import java.util.Map;
import javax.inject.Inject;
import com.cloud.storage.upload.params.IsoUploadParams;
import com.cloud.storage.upload.params.TemplateUploadParams;
import com.cloud.storage.upload.params.UploadParams;
import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd;
import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.log4j.Logger;
import org.apache.cloudstack.api.ApiConstants;
@ -284,35 +289,55 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat
}
@Override
public TemplateProfile prepare(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException {
/**
* Prepare upload parameters internal method for templates and ISOs local upload
*/
private TemplateProfile prepareUploadParamsInternal(UploadParams params) throws ResourceAllocationException {
//check if the caller can operate with the template owner
Account caller = CallContext.current().getCallingAccount();
Account owner = _accountMgr.getAccount(cmd.getEntityOwnerId());
Account owner = _accountMgr.getAccount(params.getTemplateOwnerId());
_accountMgr.checkAccess(caller, null, true, owner);
boolean isRouting = (cmd.isRoutingType() == null) ? false : cmd.isRoutingType();
List<Long> zoneList = null;
Long zoneId = cmd.getZoneId();
// ignore passed zoneId if we are using region wide image store
List<ImageStoreVO> stores = _imgStoreDao.findRegionImageStores();
if (!(stores != null && stores.size() > 0)) {
zoneList = new ArrayList<>();
zoneList.add(zoneId);
zoneList.add(params.getZoneId());
}
HypervisorType hypervisorType = HypervisorType.getType(cmd.getHypervisor());
if(hypervisorType == HypervisorType.None) {
throw new InvalidParameterValueException("Hypervisor Type: " + cmd.getHypervisor() + " is invalid. Supported Hypervisor types are "
+ EnumUtils.listValues(HypervisorType.values()).replace("None, ", ""));
if(!params.isIso() && params.getHypervisorType() == HypervisorType.None) {
throw new InvalidParameterValueException("Hypervisor Type: " + params.getHypervisorType() + " is invalid. Supported Hypervisor types are "
+ EnumUtils.listValues(HypervisorType.values()).replace("None, ", ""));
}
return prepare(false, CallContext.current().getCallingUserId(), cmd.getName(), cmd.getDisplayText(), cmd.getBits(), cmd.isPasswordEnabled(),
cmd.getRequiresHvm(), null, cmd.isPublic(), cmd.isFeatured(), cmd.isExtractable(), cmd.getFormat(), cmd.getOsTypeId(), zoneList,
hypervisorType, cmd.getChecksum(), true, cmd.getTemplateTag(), owner, cmd.getDetails(), cmd.isSshKeyEnabled(), null,
cmd.isDynamicallyScalable(), isRouting ? TemplateType.ROUTING : TemplateType.USER, false);
return prepare(params.isIso(), params.getUserId(), params.getName(), params.getDisplayText(), params.getBits(),
params.isPasswordEnabled(), params.requiresHVM(), params.getUrl(), params.isPublic(), params.isFeatured(),
params.isExtractable(), params.getFormat(), params.getGuestOSId(), zoneList,
params.getHypervisorType(), params.getChecksum(), params.isBootable(), params.getTemplateTag(), owner,
params.getDetails(), params.isSshKeyEnabled(), params.getImageStoreUuid(),
params.isDynamicallyScalable(), params.isRoutingType() ? TemplateType.ROUTING : TemplateType.USER, params.isDirectDownload());
}
@Override
public TemplateProfile prepare(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException {
UploadParams params = new TemplateUploadParams(CallContext.current().getCallingUserId(), cmd.getName(),
cmd.getDisplayText(), cmd.getBits(), BooleanUtils.toBoolean(cmd.isPasswordEnabled()),
BooleanUtils.toBoolean(cmd.getRequiresHvm()), BooleanUtils.toBoolean(cmd.isPublic()),
BooleanUtils.toBoolean(cmd.isFeatured()), BooleanUtils.toBoolean(cmd.isExtractable()), cmd.getFormat(), cmd.getOsTypeId(),
cmd.getZoneId(), HypervisorType.getType(cmd.getHypervisor()), cmd.getChecksum(),
cmd.getTemplateTag(), cmd.getEntityOwnerId(), cmd.getDetails(), BooleanUtils.toBoolean(cmd.isSshKeyEnabled()),
BooleanUtils.toBoolean(cmd.isDynamicallyScalable()), BooleanUtils.toBoolean(cmd.isRoutingType()));
return prepareUploadParamsInternal(params);
}
@Override
public TemplateProfile prepare(GetUploadParamsForIsoCmd cmd) throws ResourceAllocationException {
UploadParams params = new IsoUploadParams(CallContext.current().getCallingUserId(), cmd.getName(),
cmd.getDisplayText(), BooleanUtils.toBoolean(cmd.isPublic()), BooleanUtils.toBoolean(cmd.isFeatured()),
BooleanUtils.toBoolean(cmd.isExtractable()), cmd.getOsTypeId(),
cmd.getZoneId(), BooleanUtils.toBoolean(cmd.isBootable()), cmd.getEntityOwnerId());
return prepareUploadParamsInternal(params);
}
@Override

View File

@ -43,6 +43,7 @@ import com.google.common.base.Joiner;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.cloudstack.api.command.user.iso.GetUploadParamsForIsoCmd;
import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
import org.apache.cloudstack.framework.async.AsyncCallFuture;
import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
@ -349,11 +350,14 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating post upload template")
public GetUploadParamsResponse registerTemplateForPostUpload(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException, MalformedURLException {
TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor()));
TemplateProfile profile = adapter.prepare(cmd);
/**
* Internal register template or ISO method - post local upload
* @param adapter
* @param profile
*/
private GetUploadParamsResponse registerPostUploadInternal(TemplateAdapter adapter,
TemplateProfile profile) throws MalformedURLException {
List<TemplateOrVolumePostUploadCommand> payload = adapter.createTemplateForPostUpload(profile);
if(CollectionUtils.isNotEmpty(payload)) {
@ -403,6 +407,21 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
}
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_ISO_CREATE, eventDescription = "creating post upload iso")
public GetUploadParamsResponse registerIsoForPostUpload(GetUploadParamsForIsoCmd cmd) throws ResourceAllocationException, MalformedURLException {
TemplateAdapter adapter = getAdapter(HypervisorType.None);
TemplateProfile profile = adapter.prepare(cmd);
return registerPostUploadInternal(adapter, profile);
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_TEMPLATE_CREATE, eventDescription = "creating post upload template")
public GetUploadParamsResponse registerTemplateForPostUpload(GetUploadParamsForTemplateCmd cmd) throws ResourceAllocationException, MalformedURLException {
TemplateAdapter adapter = getAdapter(HypervisorType.getType(cmd.getHypervisor()));
TemplateProfile profile = adapter.prepare(cmd);
return registerPostUploadInternal(adapter, profile);
}
@Override
public DataStore getImageStore(String storeUuid, Long zoneId) {

View File

@ -1726,6 +1726,7 @@ var dictionary = {
"label.upgrade.router.newer.template":"Upgrade Router to Use Newer Template",
"label.upload":"Upload",
"label.upload.from.local":"Upload from Local",
"label.upload.iso.from.local":"Upload ISO from Local",
"label.upload.template.from.local":"Upload Template from Local",
"label.upload.volume":"Upload volume",
"label.upload.volume.from.local":"Upload Volume from Local",

View File

@ -1666,6 +1666,7 @@ var dictionary = {
"label.upgrade.router.newer.template": "Actualizar Router para usar una Plantilla más Nueva",
"label.upload": "Subir",
"label.upload.from.local": "Subir desde Local",
"label.upload.iso.from.local":"Subir ISO desde Local",
"label.upload.template.from.local": "Subir Plantilla desde Local",
"label.upload.volume": "Subir volumen",
"label.upload.volume.from.local": "Subir un Volumen desde Local",

View File

@ -2539,6 +2539,180 @@
});
},
notification: {
poll: function(args) {
args.complete();
}
}
},
uploadISOFromLocal: {
isHeader: true,
label: 'label.upload.from.local',
messages: {
notification: function(args) {
return 'label.upload.iso.from.local';
}
},
createForm: {
title: 'label.upload.iso.from.local',
preFilter: cloudStack.preFilter.createTemplate,
fileUpload: {
getURL: function(args) {
args.data = args.formData;
var data = {
name: args.data.name,
displayText: args.data.description,
zoneid: args.data.zone,
format: "ISO",
isextractable: (args.data.isExtractable == "on"),
bootable: (args.data.isBootable == "on"),
ispublic: (args.data.isPublic == "on"),
isfeatured: (args.data.isFeatured == "on")
};
if (args.$form.find('.form-item[rel=osTypeId]').is(':visible')) {
$.extend(data, {
osTypeId: args.data.osTypeId,
});
}
$.ajax({
url: createURL('getUploadParamsForIso'),
data: data,
async: false,
success: function(json) {
var uploadparams = json.postuploadisoresponse.getuploadparams;
var templateId = uploadparams.id;
args.response.success({
url: uploadparams.postURL,
ajaxPost: true,
data: {
'X-signature': uploadparams.signature,
'X-expires': uploadparams.expires,
'X-metadata': uploadparams.metadata
}
});
}
});
},
postUpload: function(args) {
if(args.error) {
args.response.error(args.errorMsg);
} else {
cloudStack.dialog.notice({
message: "This ISO file has been uploaded. Please check its status at Templates menu > " + args.data.name + " > Zones tab > click a zone > Status field and Ready field."
});
args.response.success();
}
}
},
fields: {
templateFileUpload: {
label: 'label.local.file',
isFileUpload: true,
validation: {
required: true
}
},
name: {
label: 'label.name',
docID: 'helpRegisterISOName',
validation: {
required: true
}
},
description: {
label: 'label.description',
docID: 'helpRegisterISODescription',
validation: {
required: true
}
},
zone: {
label: 'label.zone',
docID: 'helpRegisterISOZone',
select: function(args) {
$.ajax({
url: createURL("listZones&available=true"),
dataType: "json",
async: true,
success: function(json) {
var zoneObjs = json.listzonesresponse.zone;
args.response.success({
descriptionField: 'name',
data: zoneObjs
});
}
});
}
},
isBootable: {
label: "label.bootable",
docID: 'helpRegisterISOBootable',
isBoolean: true,
isChecked: true
},
osTypeId: {
label: 'label.os.type',
docID: 'helpRegisterISOOSType',
dependsOn: 'isBootable',
isHidden: false,
validation: {
required: true
},
select: function(args) {
$.ajax({
url: createURL("listOsTypes"),
dataType: "json",
async: true,
success: function(json) {
var ostypeObjs = json.listostypesresponse.ostype;
var items = [];
$(ostypeObjs).each(function() {
items.push({
id: this.id,
description: this.description
});
});
args.response.success({
data: items
});
}
});
}
},
isExtractable: {
label: "label.extractable",
docID: 'helpRegisterISOExtractable',
isBoolean: true
},
isPublic: {
label: "label.public",
docID: 'helpRegisterISOPublic',
isBoolean: true,
isHidden: true
},
isFeatured: {
label: "label.featured",
docID: 'helpRegisterISOFeatured',
isBoolean: true,
isHidden: true
}
}
},
action: function(args) {
return;
},
notification: {
poll: function(args) {
args.complete();

View File

@ -131,7 +131,7 @@
}
}]
});
return cloudStack.applyDefaultZindexAndOverlayOnJqueryDialogAndRemoveCloseButton($dialog);
};
@ -818,7 +818,16 @@
$form.find('.loading-overlay').remove();
$('div.loading-overlay').remove();
cloudStack.dialog.error({ message: msg });
if (!msg) {
msg = "Failed to upload file due to system misconfiguration. Please contact admin.";
}
cloudStack.dialog.notice({ message: msg });
$('.tooltip-box').remove();
$formContainer.remove();
$(this).dialog('destroy');
$('.hovered-elem').hide();
}
}
};
@ -1080,7 +1089,7 @@
}
}]
});
return cloudStack.applyDefaultZindexAndOverlayOnJqueryDialogAndRemoveCloseButton($dialog);
},
@ -1108,7 +1117,7 @@
}
}]
});
return cloudStack.applyDefaultZindexAndOverlayOnJqueryDialogAndRemoveCloseButton($dialog, 5001);
}
return false;