Skip to content

Commit

Permalink
Merge branch 'master' into enh/virtual_table
Browse files Browse the repository at this point in the history
# Conflicts:
#	frontend/__tests__/components/Vuetify.spec.js
  • Loading branch information
grolu committed Jan 23, 2025
2 parents 767bfb8 + 8402b90 commit c08e11a
Show file tree
Hide file tree
Showing 66 changed files with 2,563 additions and 1,640 deletions.
48 changes: 48 additions & 0 deletions backend/lib/routes/cloudProviderCredentials.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Gardener contributors
//
// SPDX-License-Identifier: Apache-2.0
//

'use strict'

const express = require('express')
const { cloudProviderCredentials } = require('../services')
const { metricsRoute } = require('../middleware')
const { UnprocessableEntity } = require('http-errors')

const router = module.exports = express.Router({
mergeParams: true,
})

const metricsMiddleware = metricsRoute('cloudProviderCredentials')

router.route('/')
.all(metricsMiddleware)
.post(async (req, res, next) => {
try {
const user = req.user
const { method, params } = req.body

let credentialOperation
switch (method) {
case 'list':
credentialOperation = cloudProviderCredentials.list
break
case 'create':
credentialOperation = cloudProviderCredentials.create
break
case 'patch':
credentialOperation = cloudProviderCredentials.patch
break
case 'remove':
credentialOperation = cloudProviderCredentials.remove
break
default:
throw new UnprocessableEntity(`${method} not allowed for cloud provider credentials`)
}
res.send(await credentialOperation.call(cloudProviderCredentials, { user, params }))
} catch (err) {
next(err)
}
})
60 changes: 0 additions & 60 deletions backend/lib/routes/cloudProviderSecrets.js

This file was deleted.

2 changes: 1 addition & 1 deletion backend/lib/routes/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = {
'/projects': require('./projects'),
'/namespaces/:namespace/shoots': require('./shoots'),
'/namespaces/:namespace/tickets': require('./tickets'),
'/namespaces/:namespace/cloudprovidersecrets': require('./cloudProviderSecrets'),
'/cloudprovidercredentials': require('./cloudProviderCredentials'),
'/namespaces/:namespace/members': require('./members'),
'/namespaces/:namespace/resourcequotas': require('./resourceQuotas'),
}
Expand Down
138 changes: 138 additions & 0 deletions backend/lib/services/cloudProviderCredentials.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//
// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and Gardener contributors
//
// SPDX-License-Identifier: Apache-2.0
//

const _ = require('lodash')
const { getQuotas } = require('../cache')
const createError = require('http-errors')
const logger = require('../logger')

exports.list = async function ({ user, params }) {
const client = user.client
const { bindingNamespace } = params

const [
{ items: secretBindings },
{ items: secrets },
] = await Promise.all([
client['core.gardener.cloud'].secretbindings.list(bindingNamespace),
client.core.secrets.list(bindingNamespace, { labelSelector: 'reference.gardener.cloud/secretbinding=true' }),
])

const pickQuotaProperties = _.partialRight(_.pick, [
'apiVersion',
'kind',
'metadata.name',
'metadata.namespace',
'metadata.uid',
'spec.scope',
'spec.clusterLifetimeDays',
])

const quotas = _
.chain(secretBindings)
.flatMap(resolveQuotas)
.uniqBy('metadata.uid')
.filter('spec.clusterLifetimeDays')
.map(pickQuotaProperties)
.value()

return {
secretBindings,
secrets,
quotas,
}
}

exports.create = async function ({ user, params }) {
const client = user.client

let { secret, secretBinding } = params
const secretNamespace = secret.metadata.namespace
const bindingNamespace = secretBinding.metadata.namespace
const secretRefNamespace = secretBinding.secretRef.namespace

if (bindingNamespace !== secretRefNamespace ||
secretRefNamespace !== secretNamespace) {
throw createError(422, 'Create allowed if secret and secretBinding are in the same namespace')
}

secret = await client.core.secrets.create(secretNamespace, secret)

try {
secretBinding = await client['core.gardener.cloud'].secretbindings.create(bindingNamespace, secretBinding)
} catch (err) {
logger.error('failed to create SecretBinding, cleaning up secret %s/%s', secret.metadata.namespace, secret.metadata.name)
await client.core.secrets.delete(secret.metadata.namespace, secret.metadata.name)

throw err
}

return {
secretBinding,
secret,
quotas: resolveQuotas(secretBinding),
}
}

exports.patch = async function ({ user, params }) {
const client = user.client

let { secret, secretBinding } = params
const secretNamespace = secret.metadata.namespace
const secretName = secret.metadata.name
const bindingNamespace = secretBinding.metadata.namespace
const secretBindingName = secretBinding.metadata.name
const secretRefNamespace = secretBinding.secretRef.namespace

secretBinding = await client['core.gardener.cloud'].secretbindings.get(bindingNamespace, secretBindingName)
if (!secretBinding) {
throw createError(404)
}
if (bindingNamespace !== secretRefNamespace ||
secretRefNamespace !== secretNamespace) {
throw createError(422, 'Patch allowed only if secret and secretBinding are in the same namespace')
}
secret = await client.core.secrets.update(bindingNamespace, secretName, secret)

return {
secretBinding,
secret,
quotas: resolveQuotas(secretBinding),
}
}

exports.remove = async function ({ user, params }) {
const client = user.client
const { bindingNamespace, secretBindingName } = params

const secretBinding = await client['core.gardener.cloud'].secretbindings.get(bindingNamespace, secretBindingName)
if (!secretBinding) {
throw createError(404)
}
if (secretBinding.metadata.namespace !== secretBinding.secretRef.namespace) {
throw createError(422, 'Remove allowed only if secret and secretBinding are in the same namespace')
}

const secretRef = secretBinding.secretRef
await Promise.all([
await client['core.gardener.cloud'].secretbindings.delete(bindingNamespace, secretBindingName),
await client.core.secrets.delete(secretRef.namespace, secretRef.name),
])
}

function resolveQuotas (secretBinding) {
const quotas = getQuotas()
const findQuota = ({ namespace, name } = {}) => _.find(quotas, ({ metadata }) => metadata.namespace === namespace && metadata.name === name)
try {
return _
.chain(secretBinding.quotas)
.map(findQuota)
.compact()
.value()
} catch (err) {
return []
}
}
Loading

0 comments on commit c08e11a

Please sign in to comment.