From 85ae62fa596c5222467f84d863b6a8232fe9757d Mon Sep 17 00:00:00 2001 From: Vishesh Date: Thu, 22 Aug 2024 16:17:01 +0530 Subject: [PATCH 1/3] Allow uploading of ISO for creating kubernetes supported versions --- .../api/AbstractGetUploadParamsCmd.java | 28 +++ .../user/iso/GetUploadParamsForIsoCmd.java | 23 +++ .../api/response/GetUploadParamsResponse.java | 4 + .../version/KubernetesVersionManagerImpl.java | 96 +++++++++-- .../version/KubernetesVersionService.java | 3 + ...aramsForKubernetesSupportedVersionCmd.java | 127 ++++++++++++++ ui/src/config/section/image.js | 8 + ui/src/views/AutogenView.vue | 3 + .../image/AddKubernetesSupportedVersion.vue | 160 ++++++++++++++---- 9 files changed, 404 insertions(+), 48 deletions(-) create mode 100644 plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/admin/kubernetes/version/GetUploadParamsForKubernetesSupportedVersionCmd.java diff --git a/api/src/main/java/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java b/api/src/main/java/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java index 083a1be00f56..028aab247572 100644 --- a/api/src/main/java/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/AbstractGetUploadParamsCmd.java @@ -81,6 +81,34 @@ public Long getProjectId() { return projectId; } + public void setName(String name) { + this.name = name; + } + + public void setFormat(String format) { + this.format = format; + } + + public void setZoneId(Long zoneId) { + this.zoneId = zoneId; + } + + public void setChecksum(String checksum) { + this.checksum = checksum; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public void setDomainId(Long domainId) { + this.domainId = domainId; + } + + public void setProjectId(Long projectId) { + this.projectId = projectId; + } + public GetUploadParamsResponse createGetUploadParamsResponse(UUID id, URL postURL, String metadata, String timeout, String signature) { return new GetUploadParamsResponse(id, postURL, metadata, timeout, signature); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java index 01a47f22b726..d52e53d3bb45 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/iso/GetUploadParamsForIsoCmd.java @@ -104,6 +104,29 @@ public Long getOsTypeId() { return osTypeId; } + public void setBootable(Boolean bootable) { + this.bootable = bootable; + } + + public void setDisplayText(String displayText) { + this.displayText = displayText; + } + + public void setFeatured(Boolean featured) { + this.featured = featured; + } + + public void setPublicIso(Boolean publicIso) { + this.publicIso = publicIso; + } + + public void setExtractable(Boolean extractable) { + this.extractable = extractable; + } + + public void setOsTypeId(Long osTypeId) { + this.osTypeId = osTypeId; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/response/GetUploadParamsResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/GetUploadParamsResponse.java index b9be06ecc8f8..00f7e7740c28 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/GetUploadParamsResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/GetUploadParamsResponse.java @@ -62,6 +62,10 @@ public GetUploadParamsResponse() { setObjectName("getuploadparams"); } + public UUID getId() { + return id; + } + public void setId(UUID id) { this.id = id; } diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java index 86247b53d32e..1ac8311504c2 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java @@ -17,6 +17,7 @@ package com.cloud.kubernetes.version; +import java.net.MalformedURLException; import java.util.ArrayList; import java.util.List; @@ -27,10 +28,13 @@ import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.kubernetes.version.AddKubernetesSupportedVersionCmd; import org.apache.cloudstack.api.command.admin.kubernetes.version.DeleteKubernetesSupportedVersionCmd; +import org.apache.cloudstack.api.command.admin.kubernetes.version.GetUploadParamsForKubernetesSupportedVersionCmd; import org.apache.cloudstack.api.command.admin.kubernetes.version.UpdateKubernetesSupportedVersionCmd; 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.kubernetes.version.ListKubernetesSupportedVersionsCmd; +import org.apache.cloudstack.api.response.GetUploadParamsResponse; import org.apache.cloudstack.api.response.KubernetesSupportedVersionResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.context.CallContext; @@ -160,6 +164,33 @@ private List filterKubernetesSupportedVersions(Li return versions; } + private GetUploadParamsResponse registerKubernetesVersionIsoForUpload(final Long zoneId, final String versionName, final String isoChecksum) { + CallContext.register(CallContext.current(), ApiCommandResourceType.Iso); + String isoName = String.format("%s-Kubernetes-Binaries-ISO", versionName); + GetUploadParamsForIsoCmd uploadIso = new GetUploadParamsForIsoCmd(); + uploadIso = ComponentContext.inject(uploadIso); + uploadIso.setName(isoName); + uploadIso.setPublicIso(true); + if (zoneId != null) { + uploadIso.setZoneId(zoneId); + } + uploadIso.setDisplayText(isoName); + uploadIso.setBootable(false); + if (StringUtils.isNotEmpty(isoChecksum)) { + uploadIso.setChecksum(isoChecksum); + } + uploadIso.setAccountName(accountManager.getSystemAccount().getAccountName()); + uploadIso.setDomainId(accountManager.getSystemAccount().getDomainId()); + try { + return templateService.registerIsoForPostUpload(uploadIso); + } catch (MalformedURLException | ResourceAllocationException e) { + logger.error(String.format("Unable to register binaries ISO for supported kubernetes version, %s", versionName), e); + throw new CloudRuntimeException(String.format("Unable to register binaries ISO for supported kubernetes version, %s", versionName), e); + } finally { + CallContext.unregister(); + } + } + private VirtualMachineTemplate registerKubernetesVersionIso(final Long zoneId, final String versionName, final String isoUrl, final String isoChecksum, final boolean directDownload, CPU.CPUArch arch) throws IllegalAccessException, NoSuchFieldException, IllegalArgumentException, ResourceAllocationException { CallContext.register(CallContext.current(), ApiCommandResourceType.Iso); @@ -303,23 +334,8 @@ public ListResponse listKubernetesSupportedV return createKubernetesSupportedVersionListResponse(versions, versionsAndCount.second()); } - @Override - @ActionEvent(eventType = KubernetesVersionEventTypes.EVENT_KUBERNETES_VERSION_ADD, - eventDescription = "Adding Kubernetes supported version") - public KubernetesSupportedVersionResponse addKubernetesSupportedVersion(final AddKubernetesSupportedVersionCmd cmd) { - if (!KubernetesClusterService.KubernetesServiceEnabled.value()) { - throw new CloudRuntimeException("Kubernetes Service plugin is disabled"); - } - String name = cmd.getName(); - final String semanticVersion = cmd.getSemanticVersion(); - final Long zoneId = cmd.getZoneId(); - final String isoUrl = cmd.getUrl(); - final String isoChecksum = cmd.getChecksum(); - final Integer minimumCpu = cmd.getMinimumCpu(); - final Integer minimumRamSize = cmd.getMinimumRamSize(); - final boolean isDirectDownload = cmd.isDirectDownload(); - CPU.CPUArch arch = cmd.getArch(); - + private void validateKubernetesSupportedVersion(Long zoneId, String semanticVersion, Integer minimumCpu, + Integer minimumRamSize, boolean isDirectDownload) { if (minimumCpu == null || minimumCpu < KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_CPU) { throw new InvalidParameterValueException(String.format("Invalid value for %s parameter. Minimum %d vCPUs required.", ApiConstants.MIN_CPU_NUMBER, KubernetesClusterService.MIN_KUBERNETES_CLUSTER_NODE_CPU)); } @@ -338,6 +354,27 @@ public KubernetesSupportedVersionResponse addKubernetesSupportedVersion(final Ad throw new InvalidParameterValueException(String.format("Zone: %s supports only direct download Kubernetes versions", zone.getName())); } } + } + + @Override + @ActionEvent(eventType = KubernetesVersionEventTypes.EVENT_KUBERNETES_VERSION_ADD, + eventDescription = "Adding Kubernetes supported version") + public KubernetesSupportedVersionResponse addKubernetesSupportedVersion(final AddKubernetesSupportedVersionCmd cmd) { + if (!KubernetesClusterService.KubernetesServiceEnabled.value()) { + throw new CloudRuntimeException("Kubernetes Service plugin is disabled"); + } + String name = cmd.getName(); + final String semanticVersion = cmd.getSemanticVersion(); + final Long zoneId = cmd.getZoneId(); + final String isoUrl = cmd.getUrl(); + final String isoChecksum = cmd.getChecksum(); + final Integer minimumCpu = cmd.getMinimumCpu(); + final Integer minimumRamSize = cmd.getMinimumRamSize(); + final boolean isDirectDownload = cmd.isDirectDownload(); + CPU.CPUArch arch = cmd.getArch(); + + validateKubernetesSupportedVersion(zoneId, semanticVersion, minimumCpu, minimumRamSize, isDirectDownload); + if (StringUtils.isEmpty(isoUrl)) { throw new InvalidParameterValueException(String.format("Invalid URL for ISO specified, %s", isoUrl)); } @@ -364,6 +401,30 @@ public KubernetesSupportedVersionResponse addKubernetesSupportedVersion(final Ad return createKubernetesSupportedVersionResponse(supportedVersionVO); } + @Override + public GetUploadParamsResponse registerKubernetesSupportedVersionForPostUpload(GetUploadParamsForKubernetesSupportedVersionCmd cmd) { + if (!KubernetesClusterService.KubernetesServiceEnabled.value()) { + throw new CloudRuntimeException("Kubernetes Service plugin is disabled"); + } + String name = cmd.getName(); + final String semanticVersion = cmd.getSemanticVersion(); + final Long zoneId = cmd.getZoneId(); + final String isoChecksum = cmd.getChecksum(); + final Integer minimumCpu = cmd.getMinimumCpu(); + final Integer minimumRamSize = cmd.getMinimumRamSize(); + + validateKubernetesSupportedVersion(zoneId, semanticVersion, minimumCpu, minimumRamSize, false); + + GetUploadParamsResponse response = registerKubernetesVersionIsoForUpload(zoneId, name, isoChecksum); + + VMTemplateVO template = templateDao.findByUuid(response.getId().toString()); + KubernetesSupportedVersionVO supportedVersionVO = new KubernetesSupportedVersionVO(name, semanticVersion, template.getId(), zoneId, minimumCpu, minimumRamSize); + supportedVersionVO = kubernetesSupportedVersionDao.persist(supportedVersionVO); + CallContext.current().putContextParameter(KubernetesSupportedVersion.class, supportedVersionVO.getUuid()); + + return response; + } + @Override @ActionEvent(eventType = KubernetesVersionEventTypes.EVENT_KUBERNETES_VERSION_DELETE, eventDescription = "deleting Kubernetes supported version", async = true) @@ -432,6 +493,7 @@ public List> getCommands() { return cmdList; } cmdList.add(AddKubernetesSupportedVersionCmd.class); + cmdList.add(GetUploadParamsForKubernetesSupportedVersionCmd.class); cmdList.add(ListKubernetesSupportedVersionsCmd.class); cmdList.add(DeleteKubernetesSupportedVersionCmd.class); cmdList.add(UpdateKubernetesSupportedVersionCmd.class); diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionService.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionService.java index 8e4cd0325563..cbe33e94d1ef 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionService.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionService.java @@ -19,8 +19,10 @@ import org.apache.cloudstack.api.command.admin.kubernetes.version.AddKubernetesSupportedVersionCmd; import org.apache.cloudstack.api.command.admin.kubernetes.version.DeleteKubernetesSupportedVersionCmd; +import org.apache.cloudstack.api.command.admin.kubernetes.version.GetUploadParamsForKubernetesSupportedVersionCmd; import org.apache.cloudstack.api.command.admin.kubernetes.version.UpdateKubernetesSupportedVersionCmd; import org.apache.cloudstack.api.command.user.kubernetes.version.ListKubernetesSupportedVersionsCmd; +import org.apache.cloudstack.api.response.GetUploadParamsResponse; import org.apache.cloudstack.api.response.KubernetesSupportedVersionResponse; import org.apache.cloudstack.api.response.ListResponse; @@ -31,6 +33,7 @@ public interface KubernetesVersionService extends PluggableService { static final String MIN_KUBERNETES_VERSION = "1.11.0"; ListResponse listKubernetesSupportedVersions(ListKubernetesSupportedVersionsCmd cmd); KubernetesSupportedVersionResponse addKubernetesSupportedVersion(AddKubernetesSupportedVersionCmd cmd) throws CloudRuntimeException; + GetUploadParamsResponse registerKubernetesSupportedVersionForPostUpload(GetUploadParamsForKubernetesSupportedVersionCmd cmd); boolean deleteKubernetesSupportedVersion(DeleteKubernetesSupportedVersionCmd cmd) throws CloudRuntimeException; KubernetesSupportedVersionResponse updateKubernetesSupportedVersion(UpdateKubernetesSupportedVersionCmd cmd) throws CloudRuntimeException; } diff --git a/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/admin/kubernetes/version/GetUploadParamsForKubernetesSupportedVersionCmd.java b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/admin/kubernetes/version/GetUploadParamsForKubernetesSupportedVersionCmd.java new file mode 100644 index 000000000000..3ca47166bea2 --- /dev/null +++ b/plugins/integrations/kubernetes-service/src/main/java/org/apache/cloudstack/api/command/admin/kubernetes/version/GetUploadParamsForKubernetesSupportedVersionCmd.java @@ -0,0 +1,127 @@ +// 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.admin.kubernetes.version; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.kubernetes.version.KubernetesSupportedVersion; +import com.cloud.kubernetes.version.KubernetesVersionService; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.AbstractGetUploadParamsCmd; +import org.apache.cloudstack.api.ApiCommandResourceType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ResponseObject; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.admin.AdminCmd; +import org.apache.cloudstack.api.response.GetUploadParamsResponse; +import org.apache.cloudstack.api.response.KubernetesSupportedVersionResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.commons.lang3.StringUtils; + +import javax.inject.Inject; + +@APICommand(name = "getUploadParamsForKubernetesSupportedVersion", + description = "Add a supported Kubernetes version", + responseObject = KubernetesSupportedVersionResponse.class, + responseView = ResponseObject.ResponseView.Full, + entityType = {KubernetesSupportedVersion.class}, + authorized = {RoleType.Admin}) +public class GetUploadParamsForKubernetesSupportedVersionCmd extends AbstractGetUploadParamsCmd implements AdminCmd { + + @Inject + private KubernetesVersionService kubernetesVersionService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name = ApiConstants.SEMANTIC_VERSION, type = CommandType.STRING, required = true, + description = "the semantic version of the Kubernetes version. It needs to be specified in MAJOR.MINOR.PATCH format") + private String semanticVersion; + + @Parameter(name = ApiConstants.CHECKSUM, type = CommandType.STRING, + description = "the checksum value of the binaries ISO. " + ApiConstants.CHECKSUM_PARAMETER_PREFIX_DESCRIPTION) + private String checksum; + + @Parameter(name = ApiConstants.MIN_CPU_NUMBER, type = CommandType.INTEGER, required = true, + description = "the minimum number of CPUs to be set with the Kubernetes version") + private Integer minimumCpu; + + @Parameter(name = ApiConstants.MIN_MEMORY, type = CommandType.INTEGER, required = true, + description = "the minimum RAM size in MB to be set with the Kubernetes version") + private Integer minimumRamSize; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public String getSemanticVersion() { + if(StringUtils.isEmpty(semanticVersion)) { + throw new InvalidParameterValueException("Version can not be null"); + } + if(!semanticVersion.matches("[0-9]+(\\.[0-9]+)*")) { + throw new IllegalArgumentException("Invalid version format. Semantic version needed"); + } + return semanticVersion; + } + + public String getChecksum() { + return checksum; + } + + public Integer getMinimumCpu() { + return minimumCpu; + } + + public Integer getMinimumRamSize() { + return minimumRamSize; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public ApiCommandResourceType getApiResourceType() { + return ApiCommandResourceType.KubernetesSupportedVersion; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + @Override + public void execute() throws ServerApiException, ConcurrentOperationException { + if (getZoneId() <= 0) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid zoneid"); + } + try { + GetUploadParamsResponse response = kubernetesVersionService.registerKubernetesSupportedVersionForPostUpload(this); + if (response == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Kubernetes supported version"); + } + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (CloudRuntimeException ex) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage()); + } + } +} diff --git a/ui/src/config/section/image.js b/ui/src/config/section/image.js index 6001480513bb..b60dbf09857f 100644 --- a/ui/src/config/section/image.js +++ b/ui/src/config/section/image.js @@ -395,6 +395,14 @@ export default { show: isZoneCreated, component: shallowRef(defineAsyncComponent(() => import('@/views/image/AddKubernetesSupportedVersion.vue'))) }, + { + api: 'addKubernetesSupportedVersion', + icon: 'cloud-upload-outlined', + label: 'label.kubernetes.version.add.from.local', + listView: true, + popup: true, + component: shallowRef(defineAsyncComponent(() => import('@/views/image/AddKubernetesSupportedVersion.vue'))) + }, { api: 'updateKubernetesSupportedVersion', icon: 'edit-outlined', diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index 27445ddeb297..2373dc136da1 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -1292,6 +1292,9 @@ export default { if (possibleApi === 'listTemplates') { params.templatefilter = 'executable' } else if (possibleApi === 'listIsos') { + if (this.$route.path.startsWith('/kubernetesiso')) { + params.bootable = false + } params.isofilter = 'executable' } else if (possibleApi === 'listHosts') { params.type = 'routing' diff --git a/ui/src/views/image/AddKubernetesSupportedVersion.vue b/ui/src/views/image/AddKubernetesSupportedVersion.vue index e0cd18c8eaa5..2bca0dbe113d 100644 --- a/ui/src/views/image/AddKubernetesSupportedVersion.vue +++ b/ui/src/views/image/AddKubernetesSupportedVersion.vue @@ -56,7 +56,7 @@ :loading="zoneLoading" :placeholder="apiParams.zoneid.description" @change="handleZoneChange"> - + @@ -65,7 +65,7 @@ - + @@ -73,6 +73,21 @@ v-model:value="form.url" :placeholder="apiParams.url.description" /> + + +

+ +

+

+ {{ $t('label.volume.volumefileupload.description') }} +

+
+