From 25753e5a2c7486d608b3bd41b42e629ee1933b26 Mon Sep 17 00:00:00 2001 From: Lukas Gross Date: Tue, 5 Sep 2023 16:47:41 +0200 Subject: [PATCH 01/21] Migrated WIP from enh/configure_cloudprovider to vue3 branch --- backend/lib/routes/config.js | 10 +- .../runtime/dashboard/configmap.spec.js | 105 +++++++++ .../dashboard/configmap-vendor-assets.yaml | 20 ++ .../templates/dashboard/configmap.yaml | 12 + .../templates/dashboard/deployment.yaml | 10 + charts/gardener-dashboard/values.yaml | 37 +++ frontend/src/components/GVendorIcon.vue | 17 +- .../Secrets/GSecretDialogGeneric.vue | 221 +++++++++++++----- .../ShootWorkers/GManageWorkers.vue | 15 +- .../ShootWorkers/GWorkerConfiguration.vue | 12 +- frontend/src/store/cloudProfile/index.js | 2 +- frontend/src/store/config.js | 15 ++ frontend/src/utils/createShoot.js | 28 ++- frontend/src/utils/index.js | 6 +- frontend/src/views/GNewShoot.vue | 9 +- 15 files changed, 441 insertions(+), 78 deletions(-) create mode 100644 charts/gardener-dashboard/charts/runtime/templates/dashboard/configmap-vendor-assets.yaml diff --git a/backend/lib/routes/config.js b/backend/lib/routes/config.js index c9c6734318..e77cf53c0d 100644 --- a/backend/lib/routes/config.js +++ b/backend/lib/routes/config.js @@ -57,7 +57,8 @@ function sanitizeFrontendConfig (frontendConfig) { } = {}, vendorHints = [], resourceQuotaHelp = '', - controlPlaneHighAvailabilityHelp = '' + controlPlaneHighAvailabilityHelp = '', + customCloudProviders = {} } = sanitizedFrontendConfig convertAndSanitize(alert, 'message') @@ -89,5 +90,12 @@ function sanitizeFrontendConfig (frontendConfig) { convertAndSanitize(vendorHint, 'message') } + for (const key of Object.keys(customCloudProviders)) { + const secret = customCloudProviders[key]?.secret + if (secret) { + convertAndSanitize(secret, 'help') + } + } + return sanitizedFrontendConfig } diff --git a/charts/__tests__/gardener-dashboard/runtime/dashboard/configmap.spec.js b/charts/__tests__/gardener-dashboard/runtime/dashboard/configmap.spec.js index 2992a883ce..c6e4dabe94 100644 --- a/charts/__tests__/gardener-dashboard/runtime/dashboard/configmap.spec.js +++ b/charts/__tests__/gardener-dashboard/runtime/dashboard/configmap.spec.js @@ -696,6 +696,111 @@ describe('gardener-dashboard', function () { }) }) + describe('cloudProviderList', function () { + it('should render the template with cloudProviderList', async function () { + const values = { + global: { + dashboard: { + frontendConfig: { + cloudProviderList: [ + 'foo', + 'bar' + ] + } + } + } + } + const documents = await renderTemplates(templates, values) + expect(documents).toHaveLength(1) + const [configMap] = documents + const config = yaml.load(configMap.data['config.yaml']) + expect(pick(config, ['frontend.cloudProviderList'])).toMatchSnapshot() + }) + }) + + describe('customCloudProviders', function () { + it('should render the template with customCloudProviders', async function () { + const values = { + global: { + dashboard: { + frontendConfig: { + customCloudProviders: { + foo: { + zoned: true, + shoot: { + provider: { + type: 'foo' + } + }, + secret: { + fields: [ + { + key: 'user', + type: 'text' + }, + { + key: 'password', + type: 'password' + } + ] + } + }, + bar: { + zoned: false, + shoot: { + provider: { + type: 'bar' + } + }, + secret: { + fields: [ + { + key: 'user', + type: 'text' + }, + { + key: 'password', + type: 'password' + } + ] + } + } + } + } + } + } + } + const documents = await renderTemplates(templates, values) + expect(documents).toHaveLength(1) + const [configMap] = documents + const config = yaml.load(configMap.data['config.yaml']) + expect(pick(config, ['frontend.customCloudProviders'])).toMatchSnapshot() + }) + }) + + describe('vendors', function () { + it('should render the template with vendors', async function () { + const values = { + global: { + dashboard: { + frontendConfig: { + vendors: { + foo: { + icon: 'foo_icon.svg' + } + } + } + } + } + } + const documents = await renderTemplates(templates, values) + expect(documents).toHaveLength(1) + const [configMap] = documents + const config = yaml.load(configMap.data['config.yaml']) + expect(pick(config, ['frontend.vendors'])).toMatchSnapshot() + }) + }) + describe('knownConditions', function () { it('should render the template with knownConditions markdown', async function () { const values = { diff --git a/charts/gardener-dashboard/charts/runtime/templates/dashboard/configmap-vendor-assets.yaml b/charts/gardener-dashboard/charts/runtime/templates/dashboard/configmap-vendor-assets.yaml new file mode 100644 index 0000000000..c8b426157d --- /dev/null +++ b/charts/gardener-dashboard/charts/runtime/templates/dashboard/configmap-vendor-assets.yaml @@ -0,0 +1,20 @@ +{{- if .Values.global.dashboard.enabled }} +{{- if .Values.global.dashboard.frontendConfig.vendorAssets }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: dashboard-vendor-assets + namespace: {{ .Release.Namespace }} + labels: + app.kubernetes.io/name: gardener-dashboard + app.kubernetes.io/component: dashboard + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + app.kubernetes.io/instance: "{{ .Release.Name }}" + app.kubernetes.io/managed-by: "{{ .Release.Service }}" +binaryData: +{{- range $file, $content := .Values.global.dashboard.frontendConfig.vendorAssets }} + {{ $file }}: | + {{ $content }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/gardener-dashboard/charts/runtime/templates/dashboard/configmap.yaml b/charts/gardener-dashboard/charts/runtime/templates/dashboard/configmap.yaml index 93f2417e11..a4aca90536 100644 --- a/charts/gardener-dashboard/charts/runtime/templates/dashboard/configmap.yaml +++ b/charts/gardener-dashboard/charts/runtime/templates/dashboard/configmap.yaml @@ -341,6 +341,18 @@ data: {{- if .Values.global.dashboard.frontendConfig.serviceAccountDefaultTokenExpiration }} serviceAccountDefaultTokenExpiration: {{ .Values.global.dashboard.frontendConfig.serviceAccountDefaultTokenExpiration }} {{- end }} + {{- if .Values.global.dashboard.frontendConfig.cloudProviderList }} + cloudProviderList: + {{- range .Values.global.dashboard.frontendConfig.cloudProviderList }} + - {{ . }} + {{- end }} + {{- end }} + {{- if .Values.global.dashboard.frontendConfig.customCloudProviders }} + customCloudProviders: {{ toYaml .Values.global.dashboard.frontendConfig.customCloudProviders | nindent 8 }} + {{- end }} + {{- if .Values.global.dashboard.frontendConfig.vendors }} + vendors: {{ toYaml .Values.global.dashboard.frontendConfig.vendors | nindent 8 }} + {{- end }} {{- if .Values.global.dashboard.frontendConfig.knownConditions }} knownConditions: {{ toYaml .Values.global.dashboard.frontendConfig.knownConditions | nindent 8 }} {{- end }} diff --git a/charts/gardener-dashboard/charts/runtime/templates/dashboard/deployment.yaml b/charts/gardener-dashboard/charts/runtime/templates/dashboard/deployment.yaml index bfc9cfbcbe..a90eb6438b 100644 --- a/charts/gardener-dashboard/charts/runtime/templates/dashboard/deployment.yaml +++ b/charts/gardener-dashboard/charts/runtime/templates/dashboard/deployment.yaml @@ -75,6 +75,12 @@ spec: name: dashboard-assets defaultMode: 0444 {{- end }} + {{- if .Values.global.dashboard.frontendConfig.vendorAssets }} + - name: vendor-assets + configMap: + name: dashboard-vendor-assets + defaultMode: 0444 + {{- end }} {{- if .Values.global.dashboard.serviceAccountTokenVolumeProjection.enabled }} - name: service-account-token projected: @@ -230,6 +236,10 @@ spec: - name: assets mountPath: /app/public/static/assets {{- end }} + {{- if .Values.global.dashboard.frontendConfig.vendorAssets }} + - name: vendor-assets + mountPath: /app/public/static/vendor-assets + {{- end }} {{- if .Values.global.dashboard.serviceAccountTokenVolumeProjection.enabled }} - name: service-account-token mountPath: /var/run/secrets/projected/serviceaccount diff --git a/charts/gardener-dashboard/values.yaml b/charts/gardener-dashboard/values.yaml index 715a71c1b7..7255252b1c 100644 --- a/charts/gardener-dashboard/values.yaml +++ b/charts/gardener-dashboard/values.yaml @@ -310,6 +310,43 @@ global: # resourceQuotaHelp: # text: Help text + # # cloudProviderList - configure available cloud providers. This allows to change order and to add additional (not built-in providers), see also customCloudProviders + # cloudProviderList: + # - aws + # - custom-provider + + # # customCloudProviders - configure additional cloud providers + # customCloudProviders: + # custom-provider: + # zoned: true + # shoot: # shoot template for this provider + # specTemplate: + # provider: + # type: custom-provider + # networking: + # nodes: ${workerCIDR} + # secret: # secret dialog + # fields: + # - key: user + # hint: Enter a valid user + # label: User + # type: text + # validators: + # required: + # type: required + # validationErrors: + # required: User is required + # help: | # help text for secret dialog + # #Foo Cloud Provider + + # # vendors - configure additional or overwrite built-in vendor icons + # vendors: + # custom-provider: + # icon: custom-provider.svg + # + # vendorAssets: + # custom-provider.svg: | + # # controlPlaneHighAvailabilityHelp - configure help text for control plane high availability, control plane pricing etc. # controlPlaneHighAvailabilityHelp: # text: Help text diff --git a/frontend/src/components/GVendorIcon.vue b/frontend/src/components/GVendorIcon.vue index 0a052103bf..83c86fbde4 100644 --- a/frontend/src/components/GVendorIcon.vue +++ b/frontend/src/components/GVendorIcon.vue @@ -28,12 +28,19 @@ SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/src/components/ShootWorkers/GManageWorkers.vue b/frontend/src/components/ShootWorkers/GManageWorkers.vue index 3838736126..088a880009 100644 --- a/frontend/src/components/ShootWorkers/GManageWorkers.vue +++ b/frontend/src/components/ShootWorkers/GManageWorkers.vue @@ -63,9 +63,13 @@ SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/src/components/GVendorIcon.vue b/frontend/src/components/GVendorIcon.vue index 83c86fbde4..571609c301 100644 --- a/frontend/src/components/GVendorIcon.vue +++ b/frontend/src/components/GVendorIcon.vue @@ -63,9 +63,9 @@ const configStore = useConfigStore() const { vendors } = storeToRefs(configStore) const iconSrc = computed(() => { - const customCloudProviderIcon = get(vendors, [props.icon, 'icon']) + const customCloudProviderIcon = get(vendors, ['value', props.icon, 'icon']) if (customCloudProviderIcon) { - return new URL(`/static/vendor-assets/${customCloudProviderIcon}`, import.meta.url) + return `/static/vendor-assets/${customCloudProviderIcon}` } switch (props.icon) { diff --git a/frontend/src/components/NewShoot/GNewShootSelectInfrastructure.vue b/frontend/src/components/NewShoot/GNewShootSelectInfrastructure.vue index a4f8b24f7f..33ca34737a 100644 --- a/frontend/src/components/NewShoot/GNewShootSelectInfrastructure.vue +++ b/frontend/src/components/NewShoot/GNewShootSelectInfrastructure.vue @@ -26,7 +26,7 @@ SPDX-License-Identifier: Apache-2.0 />
- {{ infrastructureKind }} + {{ vendorName(infrastructureKind) }}
@@ -40,9 +40,11 @@ import { } from 'pinia' import { useCloudProfileStore } from '@/store/cloudProfile' +import { useConfigStore } from '@/store/config' import GVendorIcon from '@/components/GVendorIcon' +import { get } from '@/lodash' export default { components: { GVendorIcon, @@ -62,6 +64,9 @@ export default { ...mapState(useCloudProfileStore, [ 'sortedInfrastructureKindList', ]), + ...mapState(useConfigStore, [ + 'vendors', + ]), }, methods: { ...mapActions(useCloudProfileStore, ['cloudProfilesByCloudProviderKind']), @@ -72,6 +77,9 @@ export default { setSelectedInfrastructure (infrastructure) { this.selectedInfrastructure = infrastructure }, + vendorName (infrastructureKind) { + return get(this.vendors, [infrastructureKind, 'name'], infrastructureKind) + }, }, } diff --git a/frontend/src/components/Secrets/GSecretDialogGeneric.vue b/frontend/src/components/Secrets/GSecretDialogGeneric.vue index 8b675926c0..22c50d6ea6 100644 --- a/frontend/src/components/Secrets/GSecretDialogGeneric.vue +++ b/frontend/src/components/Secrets/GSecretDialogGeneric.vue @@ -208,7 +208,7 @@ export default { return transformHtml(this.customCloudProvider?.secret?.help) }, valid () { - return !this.$v.$invalid + return !this.v$.$invalid }, isCreateMode () { return !this.secret @@ -228,7 +228,7 @@ export default { set(this.customCloudProviderParsedData, key, {}) try { if (type === 'yaml') { - this.customCloudProviderParsedData[key] = await this.$yaml.load(this.customCloudProviderData[key]) + this.customCloudProviderParsedData[key] = await this.yaml.load(this.customCloudProviderData[key]) } else if (type === 'json') { this.customCloudProviderParsedData[key] = JSON.parse(this.customCloudProviderData[key]) } @@ -239,7 +239,7 @@ export default { this.customCloudProviderParsedData[key] = {} } } - this.$v.customCloudProviderData[key].$touch() + this.v$.customCloudProviderData[key].$touch() }, reset () { this.v$.$reset() diff --git a/frontend/src/components/ShootWorkers/GMachineImage.vue b/frontend/src/components/ShootWorkers/GMachineImage.vue index 05c3fcd4e2..27b6ef0e72 100644 --- a/frontend/src/components/ShootWorkers/GMachineImage.vue +++ b/frontend/src/components/ShootWorkers/GMachineImage.vue @@ -28,7 +28,7 @@ SPDX-License-Identifier: Apache-2.0 - Name: {{ item.raw.name }} | Version: {{ item.raw.version }} + Name: {{ item.raw.displayName }} | Version: {{ item.raw.version }} {{ itemDescription(item.raw) }} @@ -37,7 +37,7 @@ SPDX-License-Identifier: Apache-2.0 diff --git a/frontend/src/components/GVendorIcon.vue b/frontend/src/components/GVendorIcon.vue index 16c5263748..103da941a6 100644 --- a/frontend/src/components/GVendorIcon.vue +++ b/frontend/src/components/GVendorIcon.vue @@ -65,6 +65,9 @@ const { vendors } = storeToRefs(configStore) const iconSrc = computed(() => { const customCloudProviderIcon = get(vendors, ['value', props.icon, 'icon']) if (customCloudProviderIcon) { + if (startsWith(customCloudProviderIcon, 'data:image/')) { + return customCloudProviderIcon + } return `/static/vendor-assets/${customCloudProviderIcon}` } diff --git a/frontend/src/components/NewShoot/GNewShootSelectInfrastructure.vue b/frontend/src/components/NewShoot/GNewShootSelectInfrastructure.vue index 33ca34737a..4342f0c507 100644 --- a/frontend/src/components/NewShoot/GNewShootSelectInfrastructure.vue +++ b/frontend/src/components/NewShoot/GNewShootSelectInfrastructure.vue @@ -64,12 +64,10 @@ export default { ...mapState(useCloudProfileStore, [ 'sortedInfrastructureKindList', ]), - ...mapState(useConfigStore, [ - 'vendors', - ]), }, methods: { ...mapActions(useCloudProfileStore, ['cloudProfilesByCloudProviderKind']), + ...mapActions(useConfigStore, ['vendorNameForKind']), selectInfrastructure (infrastructure) { this.setSelectedInfrastructure(infrastructure) this.userInterActionBus.emit('updateInfrastructure', infrastructure) @@ -78,7 +76,7 @@ export default { this.selectedInfrastructure = infrastructure }, vendorName (infrastructureKind) { - return get(this.vendors, [infrastructureKind, 'name'], infrastructureKind) + return this.vendorNameForKind(infrastructureKind) }, }, } diff --git a/frontend/src/components/Secrets/GSecretDialog.vue b/frontend/src/components/Secrets/GSecretDialog.vue index 42095c7d3d..e5f02619a2 100644 --- a/frontend/src/components/Secrets/GSecretDialog.vue +++ b/frontend/src/components/Secrets/GSecretDialog.vue @@ -131,6 +131,7 @@ import { useAuthzStore } from '@/store/authz' import { useCloudProfileStore } from '@/store/cloudProfile' import { useGardenerExtensionStore } from '@/store/gardenerExtension' import { useShootStore } from '@/store/shoot' +import { useConfigStore } from '@/store/config' import GToolbar from '@/components/GToolbar.vue' import GMessage from '@/components/GMessage' @@ -193,14 +194,6 @@ export default { type: String, required: true, }, - createTitle: { - type: String, - required: true, - }, - replaceTitle: { - type: String, - required: true, - }, secret: { type: Object, }, @@ -288,7 +281,9 @@ export default { return this.isCreateMode ? 'Add Secret' : 'Replace Secret' }, title () { - return this.isCreateMode ? this.createTitle : this.replaceTitle + return this.isCreateMode + ? `Add new ${this.vendorNameForKind(this.vendor)} Secret` + : `Replace ${this.vendorNameForKind(this.vendor)} Secret` }, relatedShootCount () { return this.shootsByInfrastructureSecret.length @@ -325,6 +320,7 @@ export default { ...mapActions(useCloudProfileStore, [ 'cloudProfilesByCloudProviderKind', ]), + ...mapActions(useConfigStore, ['vendorNameForKind']), hide () { this.visible = false }, diff --git a/frontend/src/components/Secrets/GSecretDialogAlicloud.vue b/frontend/src/components/Secrets/GSecretDialogAlicloud.vue index 36e87d0827..67e61d3c61 100644 --- a/frontend/src/components/Secrets/GSecretDialogAlicloud.vue +++ b/frontend/src/components/Secrets/GSecretDialogAlicloud.vue @@ -11,8 +11,6 @@ SPDX-License-Identifier: Apache-2.0 :data-valid="valid" :secret="secret" :vendor="vendor" - :create-title="`Add new ${name} Secret`" - :replace-title="`Replace ${name} Secret`" >