Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PoC] Add cloud providers via configuration #1436

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion backend/lib/routes/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ function sanitizeFrontendConfig (frontendConfig) {
} = {},
vendorHints = [],
resourceQuotaHelp = '',
controlPlaneHighAvailabilityHelp = ''
controlPlaneHighAvailabilityHelp = '',
customCloudProviders = {}
} = sanitizedFrontendConfig

convertAndSanitize(alert, 'message')
Expand Down Expand Up @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,17 @@ Object {
}
`;

exports[`gardener-dashboard configmap cloudProviderList should render the template with cloudProviderList 1`] = `
Object {
"frontend": Object {
"cloudProviderList": Array [
"foo",
"bar",
],
},
}
`;

exports[`gardener-dashboard configmap controlPlaneHighAvailabilityHelp should render the template with controlPlaneHighAvailabilityHelp markdown 1`] = `
Object {
"frontend": Object {
Expand All @@ -103,6 +114,55 @@ Object {
}
`;

exports[`gardener-dashboard configmap customCloudProviders should render the template with customCloudProviders 1`] = `
Object {
"frontend": Object {
"customCloudProviders": Object {
"bar": Object {
"secret": Object {
"fields": Array [
Object {
"key": "user",
"type": "text",
},
Object {
"key": "password",
"type": "password",
},
],
},
"shoot": Object {
"provider": Object {
"type": "bar",
},
},
"zoned": false,
},
"foo": Object {
"secret": Object {
"fields": Array [
Object {
"key": "user",
"type": "text",
},
Object {
"key": "password",
"type": "password",
},
],
},
"shoot": Object {
"provider": Object {
"type": "foo",
},
},
"zoned": true,
},
},
},
}
`;

exports[`gardener-dashboard configmap knownConditions should render the template with knownConditions markdown 1`] = `
Object {
"frontend": Object {
Expand Down Expand Up @@ -546,3 +606,15 @@ Object {
},
}
`;

exports[`gardener-dashboard configmap vendors should render the template with vendors 1`] = `
Object {
"frontend": Object {
"vendors": Object {
"foo": Object {
"icon": "foo_icon.svg",
},
},
},
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,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 = {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 }}
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,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 }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,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:
Expand Down Expand Up @@ -191,6 +197,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
Expand Down
37 changes: 37 additions & 0 deletions charts/gardener-dashboard/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,43 @@ global:
# controlPlaneHighAvailabilityHelp:
# 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: |

# # knownConditions - overwrite or add shoot condition descriptions
# knownConditions:
# ExampleConditionReady:
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/CloudProfile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { getValidationErrors } from '@/utils'

const validationErrors = {
value: {
required: 'You can\'t leave this empty.'
required: 'You can\'t leave this empty'
}
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/Purpose.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import map from 'lodash/map'

const validationErrors = {
internalPurpose: {
required: 'Purpose is required.'
required: 'Purpose is required'
}
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/SelectSecret.vue
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default {
const isSecretInProject = this.projectName === projectName

return isSecretInProject
? `${this.costObjectTitle} is required. Go to the ADMINISTRATION page to edit the project and set the ${this.costObjectTitle}.`
? `${this.costObjectTitle} is required. Go to the ADMINISTRATION page to edit the project and set the ${this.costObjectTitle}`
: `${this.costObjectTitle} is required and has to be set on the Project ${toUpper(projectName)}`
}
}
Expand Down
11 changes: 9 additions & 2 deletions frontend/src/components/ShootWorkers/ManageWorkers.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ SPDX-License-Identifier: Apache-2.0

<script>
import WorkerInputGeneric from '@/components/ShootWorkers/WorkerInputGeneric'
import { mapGetters } from 'vuex'
import { mapGetters, mapState } from 'vuex'
import { isZonedCluster } from '@/utils'
import { findFreeNetworks, getZonesNetworkConfiguration } from '@/utils/createShoot'
import forEach from 'lodash/forEach'
Expand Down Expand Up @@ -125,6 +125,9 @@ export default {
'generateWorker',
'expiringWorkerGroupsForShoot'
]),
...mapState([
'cfg'
]),
allMachineTypes () {
return this.machineTypesByCloudProfileName({ cloudProfileName: this.cloudProfileName })
},
Expand Down Expand Up @@ -318,7 +321,11 @@ export default {
* do not pass shootspec as we do not have it available in this component and it is (currently) not required to determine isZoned for new clusters. This event handler is only called for new clusters, as the
* userInterActionBus is only set for the create cluster use case
*/
this.zonedCluster = isZonedCluster({ cloudProviderKind: this.cloudProviderKind, isNewCluster: this.isNewCluster })
this.zonedCluster = isZonedCluster({
cloudProviderKind: this.cloudProviderKind,
isNewCluster: this.isNewCluster,
customCloudProviders: this.cfg.customCloudProviders
})
this.setDefaultWorker()
})
this.userInterActionBus.on('updateRegion', region => {
Expand Down
Loading