From c792b6f87dd9eccb3228af89eb7e199813212beb Mon Sep 17 00:00:00 2001 From: "Gross, Lukas" Date: Tue, 10 Dec 2024 16:53:14 +0100 Subject: [PATCH] - Create and Update Secret resources using `stringData` - Improved SecretDat composable - Added tests for credential store --- .../lib/services/cloudProviderCredentials.js | 29 +- frontend/__fixtures__/credentials.js | 83 ++++- .../composables/useShootContext.spec.js | 2 +- .../__tests__/composables/useShootDns.spec.js | 2 +- frontend/__tests__/stores/credential.spec.js | 348 ++++++++++++++++++ frontend/src/components/GShootSecretName.vue | 4 +- .../src/components/Secrets/GSecretDialog.vue | 16 +- .../Secrets/GSecretDialogAlicloud.vue | 28 +- .../components/Secrets/GSecretDialogAws.vue | 34 +- .../components/Secrets/GSecretDialogAzure.vue | 46 +-- .../Secrets/GSecretDialogCloudflare.vue | 18 +- .../components/Secrets/GSecretDialogDDns.vue | 45 ++- .../components/Secrets/GSecretDialogGcp.vue | 24 +- .../Secrets/GSecretDialogGeneric.vue | 16 +- .../Secrets/GSecretDialogHCloud.vue | 18 +- .../Secrets/GSecretDialogInfoblox.vue | 30 +- .../components/Secrets/GSecretDialogMetal.vue | 30 +- .../Secrets/GSecretDialogNetlify.vue | 17 +- .../Secrets/GSecretDialogOpenstack.vue | 52 +-- .../Secrets/GSecretDialogVSphere.vue | 30 +- .../src/components/ShootDns/GDnsProvider.vue | 4 +- ...seSecretDialogData.js => useSecretData.js} | 29 +- frontend/src/store/credential.js | 148 +++++--- frontend/src/views/GSecrets.vue | 2 +- 24 files changed, 720 insertions(+), 335 deletions(-) create mode 100644 frontend/__tests__/stores/credential.spec.js rename frontend/src/composables/{useSecretDialogData.js => useSecretData.js} (57%) diff --git a/backend/lib/services/cloudProviderCredentials.js b/backend/lib/services/cloudProviderCredentials.js index c6f6e9c55f..476cf33836 100644 --- a/backend/lib/services/cloudProviderCredentials.js +++ b/backend/lib/services/cloudProviderCredentials.js @@ -28,6 +28,7 @@ exports.list = async function ({ user, params }) { 'kind', 'metadata.name', 'metadata.namespace', + 'metadata.uid', 'spec.scope', 'spec.clusterLifetimeDays', ]) @@ -35,6 +36,7 @@ exports.list = async function ({ user, params }) { const quotas = _ .chain(secretBindings) .flatMap(resolveQuotas) + .uniqBy('metadata.uid') .filter('spec.clusterLifetimeDays') .map(pickQuotaProperties) .value() @@ -54,10 +56,10 @@ exports.create = async function ({ user, params }) { secretBindingNamespace: secretNamespace, secretBindingName: secretName, poviderType, - secretData, + secretStringData, } = params - const secretResource = toSecretResource({ namespace: secretNamespace, name: secretName, data: secretData }) + const secretResource = toSecretResource({ namespace: secretNamespace, name: secretName, stringData: secretStringData }) const secret = await client.core.secrets.create(secretNamespace, secretResource) let secretBinding @@ -84,7 +86,7 @@ exports.patch = async function ({ user, params }) { const { secretBindingNamespace, secretBindingName, - secretData, + secretStringData, } = params const secretBinding = await client['core.gardener.cloud'].secretbindings.get(secretBindingNamespace, secretBindingName) @@ -95,17 +97,10 @@ exports.patch = async function ({ user, params }) { throw createError(422, 'Patch allowed only for secrets in own namespace') } - let data - try { - data = _.mapValues(secretData, encodeBase64) - } catch (err) { - throw createError(422, 'Failed to encode "base64" secret data') - } - const patchOperations = [{ op: 'replace', - path: '/data', - value: data, + path: '/stringData', + value: secretStringData, }] const secretRef = secretBinding.secretRef @@ -151,7 +146,7 @@ function resolveQuotas (secretBinding) { } } -function toSecretResource ({ namespace, name, data }) { +function toSecretResource ({ namespace, name, stringData }) { const resource = Resources.Secret const apiVersion = resource.apiVersion const kind = resource.kind @@ -160,12 +155,8 @@ function toSecretResource ({ namespace, name, data }) { namespace, name, } - try { - data = _.mapValues(data, encodeBase64) - } catch (err) { - throw createError(422, 'Failed to encode "base64" secret data') - } - return { apiVersion, kind, metadata, type, data } + + return { apiVersion, kind, metadata, type, stringData } } function toSecretBindingResource ({ namespace, name, poviderType, secretRef }) { diff --git a/frontend/__fixtures__/credentials.js b/frontend/__fixtures__/credentials.js index 40069f3098..16e444cba2 100644 --- a/frontend/__fixtures__/credentials.js +++ b/frontend/__fixtures__/credentials.js @@ -6,38 +6,79 @@ function createProviderCredentials (type, options = {}) { const { + name = type, projectName = 'test', + secretNamepace = `garden-${projectName}`, + quotas = [], } = options - const secretBindingName = `${type}-secretbinding` - const secretName = `${type}-secret` - const namespace = `garden-${projectName}` - return { - secretBinding: { + const secretBindingName = `${name}-secretbinding` + const secretBindingNamespace = `garden-${projectName}` + const secretName = `${name}-secret` + const quotaName = `${name}-quota` + const secretBinding = { + metadata: { + namespace: secretBindingNamespace, + name: secretBindingName, + }, + provider: { + type, + }, + secretRef: { + name: secretName, + namespace: secretNamepace, + }, + } + + let secret + if (secretNamepace === secretBindingNamespace) { + // no secret if referenced in other namespace + secret = { metadata: { - namespace, - name: secretBindingName, - }, - provider: { - type, - }, - secretRef: { + namespace: secretNamepace, name: secretName, - namespace, }, - }, - secret: { + data: { + secret: 'c3VwZXJzZWNyZXQ=', + }, + } + } + + if (secretNamepace !== secretBindingNamespace) { + // always add default quota if secret is in different namespace (trial quota) + quotas.push({ metadata: { - namespace, - name: secretName, + name: quotaName, + namespace: secretNamepace, }, - }, + spec: { + scope: { + kind: 'Project', + apiVersion: 'core.gardener.cloud/v1beta1', + }, + clusterLifetimeDays: 7, + }, + }) + } + + if (quotas.length > 0) { + secretBinding.quotas = quotas.map(({ metadata }) => metadata) + } + + return { + secretBinding, + secret, + quotas, } } const credentials = [ createProviderCredentials('alicloud'), createProviderCredentials('aws'), - createProviderCredentials('azure'), + createProviderCredentials('aws', { name: 'aws-trial', secretNamepace: 'garden-trial' }), + createProviderCredentials('azure', { quotas: [ + { metadata: { name: 'azure-foo-quota', namespace: 'garden-trial' } }, + { metadata: { name: 'azure-bar-quota', namespace: 'garden-test' } }, + ] }), createProviderCredentials('openstack'), createProviderCredentials('gcp'), createProviderCredentials('ironcore'), @@ -46,9 +87,11 @@ const credentials = [ ] const secretBindings = credentials.map(item => item.secretBinding) -const secrets = credentials.map(item => item.secret) +const secrets = credentials.map(item => item.secret).filter(Boolean) +const quotas = credentials.flatMap(item => item.quotas).filter(Boolean) export default { secretBindings, secrets, + quotas, } diff --git a/frontend/__tests__/composables/useShootContext.spec.js b/frontend/__tests__/composables/useShootContext.spec.js index 0371428a3e..423b551dfd 100644 --- a/frontend/__tests__/composables/useShootContext.spec.js +++ b/frontend/__tests__/composables/useShootContext.spec.js @@ -45,7 +45,7 @@ describe('composables', () => { const configStore = useConfigStore() configStore.setConfiguration(global.fixtures.config) const credentialStore = useCredentialStore() - credentialStore.cloudProviderCredentials = global.fixtures.credentials + credentialStore.setCredentials(global.fixtures.credentials) const cloudProfileStore = useCloudProfileStore() cloudProfileStore.setCloudProfiles(cloneDeep(global.fixtures.cloudprofiles)) const gardenerExtensionStore = useGardenerExtensionStore() diff --git a/frontend/__tests__/composables/useShootDns.spec.js b/frontend/__tests__/composables/useShootDns.spec.js index 3a69d1df31..9318302676 100644 --- a/frontend/__tests__/composables/useShootDns.spec.js +++ b/frontend/__tests__/composables/useShootDns.spec.js @@ -26,7 +26,7 @@ describe('composables', () => { setActivePinia(createPinia()) manifest.spec = {} const credentialStore = useCredentialStore() - credentialStore.cloudProviderCredentials = global.fixtures.credentials + credentialStore.setCredentials(global.fixtures.credentials) const gardenerExtensionStore = useGardenerExtensionStore() gardenerExtensionStore.list = global.fixtures.gardenerExtensions diff --git a/frontend/__tests__/stores/credential.spec.js b/frontend/__tests__/stores/credential.spec.js new file mode 100644 index 0000000000..ed8d6862b4 --- /dev/null +++ b/frontend/__tests__/stores/credential.spec.js @@ -0,0 +1,348 @@ +// +// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Gardener contributors +// +// SPDX-License-Identifier: Apache-2.0 +// + +import { + setActivePinia, + createPinia, +} from 'pinia' + +import { useAppStore } from '@/store/app' +import { useAuthzStore } from '@/store/authz' +import { useCloudProfileStore } from '@/store/cloudProfile' +import { useCredentialStore } from '@/store/credential' +import { useGardenerExtensionStore } from '@/store/gardenerExtension' + +import { useApi } from '@/composables/useApi' + +import find from 'lodash/find' +import map from 'lodash/map' + +const testNamespace = 'garden-test' +const awsSecretBindingName = 'aws-secretbinding' +const awsSecretName = 'aws-secret' +const awsTrialSecretBindingName = 'aws-trial-secretbinding' +const azureSecretBindingName = 'azure-secretbinding' + +const toSecretData = secretStringData => { + return Object.entries(secretStringData).reduce((accumulator, [key, value]) => { + accumulator[key] = Buffer.from(value).toString('base64') + return accumulator + }, {}) +} + +describe('stores', () => { + describe('credential', () => { + let api + let appStore + let authzStore + let cloudProfileStore + let gardenerExtensionStore + let credentialStore + + beforeEach(async () => { + setActivePinia(createPinia()) + api = useApi() + vi.spyOn(api, 'getCloudProviderCredentials').mockImplementation(({ namespace }) => { + if (namespace !== testNamespace) { + throw new Error('Unauthorized') + } + return { + data: fixtures.credentials, + } + }) + vi.spyOn(api, 'updateCloudProviderCredential').mockImplementation(({ name, namespace, params }) => { + if (namespace !== testNamespace) { + throw new Error('Unauthorized') + } + const secretBinding = find(credentialStore.secretBindingList, { metadata: { namespace, name } }) + const secretData = toSecretData(params.secretStringData) + + return { + data: { + secretBinding, + secret: { + metadata: { + ...secretBinding.secretRef, + }, + data: { + ...secretData, + }, + }, + }, + } + }) + vi.spyOn(api, 'createCloudProviderCredential').mockImplementation(({ name, namespace, params }) => { + if (namespace !== testNamespace) { + throw new Error('Unauthorized') + } + const secretData = toSecretData(params.secretStringData) + + return { + data: { + secretBinding: { + metadata: { + namespace, + name, + }, + provider: { + type: params.providerType, + }, + secretRef: { + name, + namespace, + }, + }, + secret: { + metadata: { + name, + namespace, + }, + data: { + ...secretData, + }, + }, + }, + } + }) + vi.spyOn(api, 'deleteCloudProviderCredential').mockReturnValue() + appStore = useAppStore() + vi.spyOn(appStore, 'setSuccess') + authzStore = useAuthzStore() + authzStore.setNamespace(testNamespace) + cloudProfileStore = useCloudProfileStore() + cloudProfileStore.list = fixtures.cloudprofiles + gardenerExtensionStore = useGardenerExtensionStore() + gardenerExtensionStore.list = fixtures.gardenerExtensions + credentialStore = useCredentialStore() + credentialStore.setCredentials(fixtures.credentials) + }) + + afterEach(() => { + appStore.setSuccess.mockClear() + api.getCloudProviderCredentials.mockClear() + api.createCloudProviderCredential.mockClear() + api.updateCloudProviderCredential.mockClear() + api.deleteCloudProviderCredential.mockClear() + }) + + it('should create a new credential store', () => { + expect(credentialStore.isInitial).toBe(false) + expect(cloudProfileStore.sortedProviderTypeList).toEqual( + expect.arrayContaining(['aws', 'azure']), + ) + expect(gardenerExtensionStore.dnsProviderTypes).toEqual( + expect.arrayContaining(['aws-route53', 'azure-dns']), + ) + }) + + it('should return secretBindingList with resolved secret', () => { + expect(credentialStore.secretBindingList.length).toBeGreaterThan(0) + const awsSecretBinding = find(credentialStore.secretBindingList, { metadata: { name: awsSecretBindingName } }) + expect(awsSecretBinding.secretRef.name).toBe(awsSecretBinding._secret.metadata.name) + expect(awsSecretBinding.secretRef.namespace).toBe(awsSecretBinding._secret.metadata.namespace) + }) + + it('should return secretBindingList with trial quota and secret from other namespace', () => { + const awsTrialSecretBinding = find(credentialStore.secretBindingList, { metadata: { name: awsTrialSecretBindingName } }) + expect(awsTrialSecretBinding._secret).toBeUndefined() + expect(awsTrialSecretBinding.secretRef.namespace).toBe(awsTrialSecretBinding._quotas[0].metadata.namespace) + }) + + it('should return secretBindingList with multiple quotas', () => { + const azureSecretBinding = find(credentialStore.secretBindingList, { metadata: { name: azureSecretBindingName } }) + expect(azureSecretBinding._secret).toBeDefined() + expect(azureSecretBinding._quotas.length).toBe(2) + const azureQuota = find(credentialStore.quotaList, { metadata: azureSecretBinding.quotas[1] }) + expect(azureQuota).toBeDefined() + }) + + it('should return infrastructureSecretBindingsList', () => { + expect(credentialStore.infrastructureSecretBindingsList.length).toBeGreaterThan(0) + expect(credentialStore.secretBindingList.length).toBeGreaterThan(credentialStore.infrastructureSecretBindingsList.length) + expect(cloudProfileStore.sortedProviderTypeList).toEqual( + expect.arrayContaining(map(credentialStore.infrastructureSecretBindingsList, 'provider.type')), + ) + }) + + it('should return dnsSecretBindingsList', () => { + expect(credentialStore.dnsSecretBindingsList.length).toBeGreaterThan(0) + expect(credentialStore.secretBindingList.length).toBeGreaterThan(credentialStore.dnsSecretBindingsList.length) + expect(gardenerExtensionStore.dnsProviderTypes).toEqual( + expect.arrayContaining(map(credentialStore.dnsSecretBindingsList, 'provider.type')), + ) + }) + + it('should return getSecret', () => { + expect(credentialStore.getSecret({ namespace: testNamespace, name: awsSecretName })).toBeDefined() + }) + + it('should return getSecretBinding', () => { + expect(credentialStore.getSecretBinding({ namespace: testNamespace, name: awsSecretBindingName })).toBeDefined() + }) + + it('should fetchCredentials', async () => { + credentialStore.$reset() + expect(credentialStore.secretBindingList.length).toBe(0) + await credentialStore.fetchCredentials() + expect(api.getCloudProviderCredentials).toBeCalledTimes(1) + expect(api.getCloudProviderCredentials).toBeCalledWith({ namespace: testNamespace }) + expect(credentialStore.secretBindingList.length).toBeGreaterThan(0) + }) + + it('should updateCredential', async () => { + const name = awsSecretBindingName + const secretStringData = { newSecret: 'supersecret2' } + await credentialStore.updateCredential({ name, secretStringData }) + + expect(api.updateCloudProviderCredential).toBeCalledTimes(1) + expect(api.updateCloudProviderCredential).toBeCalledWith({ name, namespace: testNamespace, params: { secretStringData } }) + const awsSecretBinding = find(credentialStore.secretBindingList, { metadata: { name } }) + expect(awsSecretBinding._secret.data).toEqual({ newSecret: 'c3VwZXJzZWNyZXQy' }) + }) + + it('should createCredential', async () => { + const secretStringData = { newSecret: 'supersecret3' } + const name = 'my-new-secret' + const namespace = testNamespace + const providerType = 'aws' + await credentialStore.createCredential({ name, providerType, secretStringData }) + + expect(api.createCloudProviderCredential).toBeCalledTimes(1) + expect(api.createCloudProviderCredential).toBeCalledWith({ name, namespace, params: { providerType, secretStringData } }) + const newSecretBinding = find(credentialStore.secretBindingList, { metadata: { name } }) + expect(newSecretBinding.metadata.namespace).toEqual(namespace) + expect(newSecretBinding.provider.type).toEqual(providerType) + expect(newSecretBinding._secret.data).toEqual({ newSecret: 'c3VwZXJzZWNyZXQz' }) + }) + + it('should deleteCredential secretbinding and referenced secret / quota', async () => { + const name = azureSecretBindingName + const namespace = testNamespace + + let azureSecretBinding = find(credentialStore.secretBindingList, { metadata: { namespace, name } }) + expect(azureSecretBinding).toBeDefined() + + const azureSecretRef = azureSecretBinding.secretRef + let azureSecret = find(credentialStore.secretList, { metadata: azureSecretRef }) + expect(azureSecret).toBeDefined() + + const azureQuotaRef1 = azureSecretBinding.quotas[0] + let azureQuota1 = find(credentialStore.quotaList, { metadata: azureQuotaRef1 }) + expect(azureQuota1).toBeDefined() + + const azureQuotaRef2 = azureSecretBinding.quotas[1] + let azureQuota2 = find(credentialStore.quotaList, { metadata: azureQuotaRef2 }) + expect(azureQuota2).toBeDefined() + + await credentialStore.deleteCredential(name) + + expect(api.deleteCloudProviderCredential).toBeCalledTimes(1) + expect(api.deleteCloudProviderCredential).toBeCalledWith({ name, namespace }) + + azureSecretBinding = find(credentialStore.secretBindingList, { metadata: { namespace, name } }) + expect(azureSecretBinding).toBeUndefined() + + azureSecret = find(credentialStore.secretList, { metadata: azureSecretRef }) + expect(azureSecret).toBeUndefined() + + azureQuota1 = find(credentialStore.quotaList, { metadata: azureQuotaRef1 }) + expect(azureQuota1).toBeUndefined() + + azureQuota2 = find(credentialStore.quotaList, { metadata: azureQuotaRef2 }) + expect(azureQuota2).toBeUndefined() + }) + + it('should not delete secret or quota if referenced by other SecretBinding', async () => { + const name = azureSecretBindingName + const namespace = testNamespace + + let azureSecretBinding = find(credentialStore.secretBindingList, { metadata: { namespace, name } }) + expect(azureSecretBinding).toBeDefined() + + const azureSecretRef = azureSecretBinding.secretRef + const azureQuotaRef1 = azureSecretBinding.quotas[0] + const azureQuotaRef2 = azureSecretBinding.quotas[1] + + // Add another SecretBinding that references the same secret and quota + const otherSecretBinding = { + metadata: { + namespace, + name: 'other-secretbinding', + }, + provider: { + type: 'azure', + }, + secretRef: azureSecretRef, + quotas: [azureQuotaRef1], + } + const { secretBindings, secrets, quotas } = fixtures.credentials + secretBindings.push(otherSecretBinding) + credentialStore.setCredentials({ secretBindings, secrets, quotas }) + + let azureSecret = find(credentialStore.secretList, { metadata: azureSecretRef }) + expect(azureSecret).toBeDefined() + + let azureQuota1 = find(credentialStore.quotaList, { metadata: azureQuotaRef1 }) + expect(azureQuota1).toBeDefined() + + let azureQuota2 = find(credentialStore.quotaList, { metadata: azureQuotaRef2 }) + expect(azureQuota2).toBeDefined() + + await credentialStore.deleteCredential(name) + + expect(api.deleteCloudProviderCredential).toBeCalledTimes(1) + expect(api.deleteCloudProviderCredential).toBeCalledWith({ name, namespace }) + + azureSecretBinding = find(credentialStore.secretBindingList, { metadata: { namespace, name } }) + expect(azureSecretBinding).toBeUndefined() + + azureSecret = find(credentialStore.secretList, { metadata: azureSecretRef }) + expect(azureSecret).toBeDefined() // still referenced by otherSecretBinding + + azureQuota1 = find(credentialStore.quotaList, { metadata: azureQuotaRef1 }) + expect(azureQuota1).toBeDefined() // still referenced by otherSecretBinding + + azureQuota2 = find(credentialStore.quotaList, { metadata: azureQuotaRef2 }) + expect(azureQuota2).toBeUndefined() // not referenced anymore + }) + + it('store should be resetted in case of a fetch error', async () => { + const namespace = 'invalid' + authzStore.setNamespace(namespace) + + expect(credentialStore.secretBindingList.length).toBeGreaterThan(0) + await expect(credentialStore.fetchCredentials()).rejects.toThrow(Error) + expect(credentialStore.secretBindingList.length).toBe(0) + }) + + it('store should be resetted in case of a create error', async () => { + const namespace = 'invalid' + authzStore.setNamespace(namespace) + + expect(credentialStore.secretBindingList.length).toBeGreaterThan(0) + await expect(credentialStore.createCredential({ name: 'foo' })).rejects.toThrow(Error) + expect(credentialStore.secretBindingList.length).toBe(0) + }) + + it('store should be resetted in case of an update error', async () => { + const namespace = 'invalid' + authzStore.setNamespace(namespace) + + expect(credentialStore.secretBindingList.length).toBeGreaterThan(0) + await expect(credentialStore.updateCredential({ name: 'foo' })).rejects.toThrow(Error) + expect(credentialStore.secretBindingList.length).toBe(0) + }) + + it('store should be resetted in case of a delete error', async () => { + const namespace = 'invalid' + authzStore.setNamespace(namespace) + + expect(credentialStore.secretBindingList.length).toBeGreaterThan(0) + await expect(credentialStore.deleteCredential(awsTrialSecretBindingName)).rejects.toThrow(Error) + expect(credentialStore.secretBindingList.length).toBe(0) + }) + }) +}) diff --git a/frontend/src/components/GShootSecretName.vue b/frontend/src/components/GShootSecretName.vue index 4feed2be9f..cf12281cab 100644 --- a/frontend/src/components/GShootSecretName.vue +++ b/frontend/src/components/GShootSecretName.vue @@ -65,11 +65,11 @@ export default { return this.canGetSecrets && this.secretBindingName && this.namespace }, secretBinding () { - return this.getSecretBindingByName({ namespace: this.namespace, name: this.secretBindingName }) + return this.getSecretBinding({ namespace: this.namespace, name: this.secretBindingName }) }, }, methods: { - ...mapActions(useCredentialStore, ['getSecretBindingByName']), + ...mapActions(useCredentialStore, ['getSecretBinding']), }, } diff --git a/frontend/src/components/Secrets/GSecretDialog.vue b/frontend/src/components/Secrets/GSecretDialog.vue index 4fc019e878..b6ff371665 100644 --- a/frontend/src/components/Secrets/GSecretDialog.vue +++ b/frontend/src/components/Secrets/GSecretDialog.vue @@ -124,7 +124,7 @@ import { useShootStore } from '@/store/shoot' import GToolbar from '@/components/GToolbar.vue' import GMessage from '@/components/GMessage' -import { useSecretDialogData } from '@/composables/useSecretDialogData' +import { useSecretData } from '@/composables/useSecretData' import { messageFromErrors, @@ -185,11 +185,11 @@ export default { 'cloud-profile-name', ], setup () { - const { secretData, updateWithSecret } = useSecretDialogData() + const { secretStringData, setSecretData } = useSecretData() return { - secretData, - updateWithSecret, + secretStringData, + setSecretData, v$: useVuelidate(), } }, @@ -316,11 +316,11 @@ export default { }, save () { const poviderType = this.providerType - const secretData = this.secretData + const secretStringData = this.secretStringData if (this.isCreateMode) { - return this.createCredential({ name: this.name, poviderType, secretData }) + return this.createCredential({ name: this.name, poviderType, secretStringData }) } else { - return this.updateCredential({ name: this.name, poviderType, secretData }) + return this.updateCredential({ name: this.name, secretStringData }) } }, reset () { @@ -331,7 +331,7 @@ export default { setDelayedInputFocus(this, 'name') } else { this.name = get(this.secretBinding, ['metadata', 'name']) - this.updateWithSecret(this.secretBinding._secret) + this.setSecretData(this.secretBinding._secret.data) } this.errorMessage = undefined diff --git a/frontend/src/components/Secrets/GSecretDialogAlicloud.vue b/frontend/src/components/Secrets/GSecretDialogAlicloud.vue index 95f2b6e052..b9add52184 100644 --- a/frontend/src/components/Secrets/GSecretDialogAlicloud.vue +++ b/frontend/src/components/Secrets/GSecretDialogAlicloud.vue @@ -98,13 +98,13 @@ import { minLength, maxLength, } from '@vuelidate/validators' -import { ref } from 'vue' +import { toRefs } from 'vue' import GSecretDialog from '@/components/Secrets/GSecretDialog' import GCodeBlock from '@/components/GCodeBlock' import GExternalLink from '@/components/GExternalLink' -import { useProvideSecretDialogData } from '@/composables/useSecretDialogData' +import { useProvideSecretData } from '@/composables/useSecretData' import { getErrorMessages } from '@/utils' import { withFieldName } from '@/utils/validators' @@ -131,22 +131,20 @@ export default { 'update:modelValue', ], setup () { - const accessKeyId = ref(undefined) - const accessKeySecret = ref(undefined) - - useProvideSecretDialogData({ - data: { - accessKeyId, - accessKeySecret, - }, - keyMapping: { - accessKeyId: 'accessKeyID', + const { state } = useProvideSecretData( + [ + 'accessKeyId', + 'accessKeySecret', + ], + { + keyMapping: { + accessKeyId: 'accessKeyID', + }, }, - }) + ) return { - accessKeyId, - accessKeySecret, + ...toRefs(state), v$: useVuelidate(), } }, diff --git a/frontend/src/components/Secrets/GSecretDialogAws.vue b/frontend/src/components/Secrets/GSecretDialogAws.vue index 0e260bd78a..46f3171286 100644 --- a/frontend/src/components/Secrets/GSecretDialogAws.vue +++ b/frontend/src/components/Secrets/GSecretDialogAws.vue @@ -100,13 +100,13 @@ import { minLength, maxLength, } from '@vuelidate/validators' -import { ref } from 'vue' +import { toRefs } from 'vue' import GSecretDialog from '@/components/Secrets/GSecretDialog' import GCodeBlock from '@/components/GCodeBlock' import GExternalLink from '@/components/GExternalLink' -import { useProvideSecretDialogData } from '@/composables/useSecretDialogData' +import { useProvideSecretData } from '@/composables/useSecretData' import { withFieldName, @@ -137,26 +137,22 @@ export default { 'update:modelValue', ], setup () { - const accessKeyId = ref(undefined) - const secretAccessKey = ref(undefined) - const awsRegion = ref(undefined) - - useProvideSecretDialogData({ - data: { - accessKeyId, - secretAccessKey, - awsRegion, - }, - keyMapping: { - accessKeyId: 'accessKeyID', - awsRegion: 'AWS_REGION', + const { state } = useProvideSecretData( + [ + 'accessKeyId', + 'secretAccessKey', + 'awsRegion', + ], + { + keyMapping: { + accessKeyId: 'accessKeyID', + awsRegion: 'AWS_REGION', + }, }, - }) + ) return { - accessKeyId, - secretAccessKey, - awsRegion, + ...toRefs(state), v$: useVuelidate(), } }, diff --git a/frontend/src/components/Secrets/GSecretDialogAzure.vue b/frontend/src/components/Secrets/GSecretDialogAzure.vue index 4677c52a40..37546cfadd 100644 --- a/frontend/src/components/Secrets/GSecretDialogAzure.vue +++ b/frontend/src/components/Secrets/GSecretDialogAzure.vue @@ -110,14 +110,14 @@ SPDX-License-Identifier: Apache-2.0 import { useVuelidate } from '@vuelidate/core' import { required } from '@vuelidate/validators' import { - ref, + toRefs, computed, } from 'vue' import GSecretDialog from '@/components/Secrets/GSecretDialog' import GExternalLink from '@/components/GExternalLink' -import { useProvideSecretDialogData } from '@/composables/useSecretDialogData' +import { useProvideSecretData } from '@/composables/useSecretData' import { withFieldName, @@ -150,34 +150,26 @@ export default { return props.providerType === 'azure-dns' || props.providerType === 'azure-private-dns' }) - const clientId = ref(undefined) - const clientSecret = ref(undefined) - const tenantId = ref(undefined) - const subscriptionId = ref(undefined) - const azureCloud = ref(isDNSSecret.value ? 'AzurePublic' : undefined) - - useProvideSecretDialogData({ - data: { - clientId, - clientSecret, - tenantId, - subscriptionId, - azureCloud, - }, - keyMapping: { - clientId: 'clientID', - subscriptionId: 'subscriptionID', - tenantId: 'tenantID', - azureCloud: 'AZURE_CLOUD', + const { state } = useProvideSecretData( + [ + 'clientId', + 'clientSecret', + 'tenantId', + 'subscriptionId', + 'azureCloud', + ], + { + keyMapping: { + clientId: 'clientID', + subscriptionId: 'subscriptionID', + tenantId: 'tenantID', + azureCloud: 'AZURE_CLOUD', + }, }, - }) + ) return { - clientId, - clientSecret, - tenantId, - subscriptionId, - azureCloud, + ...toRefs(state), isDNSSecret, v$: useVuelidate(), } diff --git a/frontend/src/components/Secrets/GSecretDialogCloudflare.vue b/frontend/src/components/Secrets/GSecretDialogCloudflare.vue index aa5af4b130..147fc0ddf8 100644 --- a/frontend/src/components/Secrets/GSecretDialogCloudflare.vue +++ b/frontend/src/components/Secrets/GSecretDialogCloudflare.vue @@ -59,12 +59,12 @@ SPDX-License-Identifier: Apache-2.0