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

Support Configuration of Container Runtimes #790

Merged
merged 5 commits into from
May 6, 2021
Merged
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
194 changes: 194 additions & 0 deletions frontend/src/components/ShootWorkers/ContainerRuntime.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@

<!--
SPDX-FileCopyrightText: 2021 SAP SE or an SAP affiliate company and Gardener contributors

SPDX-License-Identifier: Apache-2.0
-->

<template>
<div class="d-flex flex-row">
<v-select
color="primary"
item-color="primary"
:items="containerRuntimeItems"
:error-messages="getErrorMessages('containerRuntime')"
@input="onInputContainerRuntime"
@blur="$v.containerRuntime.$touch()"
v-model="containerRuntime"
label="Container Runtime"
:disabled="immutableCri"
:hint="criHint"
persistent-hint
>
<template v-slot:item="{ item }">
<span>{{criItemText(item)}}</span>
</template>
<template v-slot:selection="{ item }">
<span>{{criItemText(item)}}</span>
</template>
</v-select>
<v-select
v-if="ociRuntimeItems.length"
class="ml-1"
color="primary"
item-color="primary"
:items="ociRuntimeItems"
:error-messages="getErrorMessages('ociRuntime')"
@input="onInputOciRuntime"
@blur="$v.ociRuntime.$touch()"
v-model="ociRuntime"
label="OCI Runtimes"
multiple
:disabled="immutableCri"
:hint="ociHint"
persistent-hint
>
<template v-slot:item="{ item }">
<span>{{ociItemText(item)}}</span>
</template>
<template v-slot:selection="{ item }">
<span>{{ociItemText(item)}}</span>
</template>
</v-select>
</div>
</template>

<script>
import { required, requiredIf } from 'vuelidate/lib/validators'
import { getValidationErrors } from '@/utils'
import uniq from 'lodash/uniq'
import find from 'lodash/find'
import map from 'lodash/map'
import isEqual from 'lodash/isEqual'
import get from 'lodash/get'
import set from 'lodash/set'
import unset from 'lodash/unset'

// The following runtimes are defaults that are always offered.
// Selecting a default Container / OCI Runtime will not create a CRI config in the shoot worker
// Currently, this is hard-coded in Gardener. Once this can be configured or default is removed, we need to adapt
const DEFAULT_CONTAINER_RUNTIME = 'docker'
const DEFAULT_OCI_RUNTIME = 'runc'

const validationErrors = {
containerRuntime: {
required: 'Container Runtime is required'
},
ociRuntime: {
required: 'OCI Runtime is required'
}
}

const validations = {
containerRuntime: {
required
},
ociRuntime: {
required: requiredIf(function () {
return this.ociRuntimeItems.length
})
}
}

export default {
props: {
worker: {
type: Object,
required: true
},
machineImageCri: {
type: Array,
default: () => []
},
immutableCri: {
type: Boolean,
default: false
}
},
data () {
return {
validationErrors,
valid: undefined,
containerRuntime: undefined,
ociRuntime: undefined,
defaultCri: DEFAULT_CONTAINER_RUNTIME,
defaultOci: DEFAULT_OCI_RUNTIME
}
},
validations,
computed: {
containerRuntimeItems () {
const containerRuntimes = map(this.machineImageCri, 'name')
return uniq([...containerRuntimes, DEFAULT_CONTAINER_RUNTIME])
},
ociRuntimeItems () {
if (this.containerRuntime === DEFAULT_CONTAINER_RUNTIME) {
return [DEFAULT_OCI_RUNTIME]
}
const containerRuntime = find(this.machineImageCri, ['name', this.containerRuntime])
const ociRuntimes = get(containerRuntime, 'containerRuntimes', [])
return map(ociRuntimes, 'type')
},
criHint () {
if (this.immutableCri) {
return 'Container runtime cannot be changed after worker has been created'
}
return undefined
},
ociHint () {
if (this.immutableCri) {
return 'OCI runtimes cannot be changed after worker has been created'
}
return undefined
}
},
methods: {
grolu marked this conversation as resolved.
Show resolved Hide resolved
ociItemText (item) {
return !this.immutableCri && item === this.defaultOci ? `default (${item})` : item
},
criItemText (item) {
return !this.immutableCri && item === this.defaultCri ? `default (${item})` : item
},
getErrorMessages (field) {
return getValidationErrors(this, field)
},
onInputContainerRuntime (value) {
if (value && value !== DEFAULT_CONTAINER_RUNTIME) {
set(this.worker, 'cri.name', value)
} else {
unset(this.worker, 'cri')
}
this.ociRuntime = undefined
this.$v.containerRuntime.$touch()
this.validateInput()
},
onInputOciRuntime (value) {
if (value.length && !isEqual(value, [DEFAULT_OCI_RUNTIME])) {
const containerRuntimes = map(value, ociRuntime => ({ type: ociRuntime }))
set(this.worker, 'cri.containerRuntimes', containerRuntimes)
} else {
unset(this.worker, 'cri.containerRuntimes')
}
this.$v.ociRuntime.$touch()
this.validateInput()
},
validateInput () {
if (this.valid !== !this.$v.$invalid) {
this.valid = !this.$v.$invalid
this.$emit('valid', { id: this.worker.id, valid: this.valid })
}
}
},
mounted () {
this.containerRuntime = get(this.worker, 'cri.name', DEFAULT_CONTAINER_RUNTIME)
const ociRuntime = get(this.worker, 'cri.containerRuntimes')
if (ociRuntime) {
this.ociRuntime = map(ociRuntime, 'type')
} else {
this.ociRuntime = [DEFAULT_OCI_RUNTIME]
}
this.$v.$touch()
this.validateInput()
}
}
</script>
33 changes: 29 additions & 4 deletions frontend/src/components/ShootWorkers/WorkerInputGeneric.vue
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ SPDX-License-Identifier: Apache-2.0
@valid="onMachineImageValid">
</machine-image>
</div>
<div class="regularInput">
<container-runtime
:machine-image-cri="machineImageCri"
:worker="worker"
:immutable-cri="immutableCri"
@valid="onContainerRuntimeValid">
</container-runtime>
</div>
<div v-if="volumeInCloudProfile" class="regularInput">
<volume-type
:volume-types="volumeTypes"
Expand Down Expand Up @@ -121,15 +129,16 @@ import SizeInput from '@/components/ShootWorkers/VolumeSizeInput'
import MachineType from '@/components/ShootWorkers/MachineType'
import VolumeType from '@/components/ShootWorkers/VolumeType'
import MachineImage from '@/components/ShootWorkers/MachineImage'
import ContainerRuntime from '@/components/ShootWorkers/ContainerRuntime'
import isEmpty from 'lodash/isEmpty'
import filter from 'lodash/filter'
import map from 'lodash/map'
import includes from 'lodash/includes'
import sortBy from 'lodash/sortBy'
import find from 'lodash/find'
import concat from 'lodash/concat'
import last from 'lodash/last'
import difference from 'lodash/difference'
import find from 'lodash/find'
import get from 'lodash/get'
import set from 'lodash/set'
import { required, maxLength, minValue, requiredIf } from 'vuelidate/lib/validators'
Expand Down Expand Up @@ -168,7 +177,8 @@ export default {
SizeInput,
MachineType,
VolumeType,
MachineImage
MachineImage,
ContainerRuntime
},
props: {
worker: {
Expand Down Expand Up @@ -211,8 +221,10 @@ export default {
machineTypeValid: undefined,
volumeTypeValid: true, // selection not shown in all cases, default to true
machineImageValid: undefined,
containerRuntimeValid: undefined,
immutableZones: undefined,
volumeSizeInternal: undefined
volumeSizeInternal: undefined,
immutableCri: undefined
}
},
validations () {
Expand Down Expand Up @@ -377,6 +389,12 @@ export default {
return `Your network configuration allows to add ${this.maxAdditionalZones} more zones that are not already used by this cluster`
}
return undefined
},
selectedMachineImage () {
return find(this.machineImages, this.worker.machine.image)
},
machineImageCri () {
return this.selectedMachineImage.cri
}
},
methods: {
Expand Down Expand Up @@ -447,8 +465,14 @@ export default {
this.validateInput()
}
},
onContainerRuntimeValid ({ valid }) {
if (this.containerRuntimeValid !== valid) {
this.containerRuntimeValid = valid
this.validateInput()
}
},
validateInput () {
const valid = !this.$v.$invalid && this.machineTypeValid && this.volumeTypeValid && this.machineImageValid
const valid = !this.$v.$invalid && this.machineTypeValid && this.volumeTypeValid && this.machineImageValid && this.containerRuntimeValid
if (this.valid !== valid) {
this.valid = valid
this.$emit('valid', { id: this.worker.id, valid: this.valid })
Expand Down Expand Up @@ -479,6 +503,7 @@ export default {
this.setVolumeDependingOnMachineType()
this.onInputVolumeSize()
this.immutableZones = this.isNew ? [] : this.worker.zones
this.immutableCri = !this.isNew
}
}
</script>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/store/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -428,14 +428,15 @@ const getters = {
return semver.rcompare(a.version, b.version)
})

return map(versions, ({ version, expirationDate, classification }) => {
return map(versions, ({ version, expirationDate, cri, classification }) => {
const vendorName = vendorNameFromImageName(machineImage.name)
const name = machineImage.name

return {
key: name + '/' + version,
name,
version,
cri,
classification,
isPreview: classification === 'preview',
isSupported: classification === 'supported',
Expand Down