diff --git a/frontend/__tests__/components/GStatusTag.spec.js b/frontend/__tests__/components/GStatusTag.spec.js index b2440311eb..8e9f1f9485 100644 --- a/frontend/__tests__/components/GStatusTag.spec.js +++ b/frontend/__tests__/components/GStatusTag.spec.js @@ -47,7 +47,7 @@ describe('components', () => { const wrapper = mountStatusTag({ shortName: 'foo', name: 'foo-bar', - status: 'True', + status: 'Healthy', }) authnStore.user.isAdmin = true const vm = wrapper.vm @@ -55,7 +55,7 @@ describe('components', () => { expect(vm.chipStatus).toBe('Healthy') expect(vm.chipTooltip.title).toBe('foo-bar') expect(vm.chipIcon).toBe('') - expect(vm.isError || vm.isUnknown || vm.isProgressing).toBe(false) + expect(vm.isError || vm.isUnknown || vm.isProgressing || vm.isDegraded).toBe(false) expect(vm.color).toBe('primary') expect(vm.visible).toBe(true) }) @@ -64,14 +64,14 @@ describe('components', () => { const wrapper = mountStatusTag({ shortName: 'foo', name: 'foo-bar', - status: 'True', + status: 'Healthy', codes: [ 'ERR_CONFIGURATION_PROBLEM', ], }) const vm = wrapper.vm expect(vm.chipText).toBe('foo') - expect(vm.chipStatus).toBe('Error') + expect(vm.chipStatus).toBe('Healthy') expect(vm.isError).toBe(true) expect(vm.isUserError).toBe(true) expect(vm.chipIcon).toBe('mdi-account-alert-outline') @@ -79,7 +79,7 @@ describe('components', () => { expect(vm.visible).toBe(true) }) - it('should render condition for a user without admin role', () => { + it('should render progressing condition', () => { const wrapper = mountStatusTag({ shortName: 'foo', name: 'foo-bar', @@ -91,6 +91,21 @@ describe('components', () => { expect(vm.isProgressing).toBe(true) expect(vm.color).toBe('primary') expect(vm.chipStatus).toBe('Progressing') + expect(vm.chipIcon).toBe('mdi-progress-clock') + }) + + it('should render condition for a user without admin role', () => { + const wrapper = mountStatusTag({ + shortName: 'foo', + name: 'foo-bar', + status: 'Degraded', + showAdminOnly: true, + }) + const vm = wrapper.vm + expect(vm.visible).toBe(false) + expect(vm.isDegraded).toBe(true) + expect(vm.color).toBe('primary') + expect(vm.chipStatus).toBe('Degraded') expect(vm.chipIcon).toBe('') }) @@ -98,15 +113,15 @@ describe('components', () => { const wrapper = mountStatusTag({ shortName: 'foo', name: 'foo-bar', - status: 'Progressing', + status: 'Degraded', showAdminOnly: true, }) authnStore.user.isAdmin = true const vm = wrapper.vm expect(vm.visible).toBe(true) - expect(vm.isProgressing).toBe(true) + expect(vm.isDegraded).toBe(true) expect(vm.color).toBe('info') - expect(vm.chipStatus).toBe('Progressing') + expect(vm.chipStatus).toBe('Degraded') expect(vm.chipIcon).toBe('mdi-progress-alert') }) }) diff --git a/frontend/__tests__/components/GStatusTags.spec.js b/frontend/__tests__/components/GStatusTags.spec.js index 7f6f5fba05..d7f1cf8430 100644 --- a/frontend/__tests__/components/GStatusTags.spec.js +++ b/frontend/__tests__/components/GStatusTags.spec.js @@ -30,6 +30,7 @@ describe('components', () => { return { type, lastTransitionTime, + status: 'True', } }), }, @@ -85,6 +86,7 @@ describe('components', () => { shortName: 'SC', name: 'Sample Condition', sortOrder: '000000SC', + status: 'True', }) }) @@ -98,6 +100,7 @@ describe('components', () => { shortName: 'ELSTC', name: 'Extra Long Sample TEST Condition', sortOrder: '000ELSTC', + status: 'True', }) }) @@ -111,6 +114,7 @@ describe('components', () => { shortName: 'S', name: 'Singlecondition', sortOrder: '0000000S', + status: 'True', }) }) @@ -124,6 +128,9 @@ describe('components', () => { shortName: 'API', name: 'API Server', sortOrder: '00000000', + statusMappings: expect.any(Object), + statusTextMappings: expect.any(Object), + status: 'True', description: expect.stringContaining('kube-apiserver'), }) }) @@ -138,6 +145,7 @@ describe('components', () => { shortName: 'CC', name: 'Config Condition', sortOrder: '00000000', + status: 'True', description: 'Config Condition Description', }) }) @@ -152,6 +160,7 @@ describe('components', () => { shortName: 'CPO', name: 'Control Plane Overwritten', sortOrder: '00000011', + status: 'True', description: 'Overwritten Description', }) }) diff --git a/frontend/src/components/GStatusTag.vue b/frontend/src/components/GStatusTag.vue index 7a4c2e8ff1..0edf99064f 100644 --- a/frontend/src/components/GStatusTag.vue +++ b/frontend/src/components/GStatusTag.vue @@ -64,7 +64,7 @@ SPDX-License-Identifier: Apache-2.0 { - const conditions = shootReadiness.value - .filter(condition => !!condition.lastTransitionTime) - .map(condition => { - const conditionDefaults = configStore.conditionForType(condition.type) - return { - ...conditionDefaults, - ...condition, - sortOrder: padStart(conditionDefaults.sortOrder, 8, '0'), - } - }) - return sortBy(conditions, 'sortOrder') + const merged = [] + + // helper to avoid repeating the same checks + const pushIfValid = (item, mustNotBeTrue) => { + item = mergeItem(item) + if (!item.lastTransitionTime) { + return + } + if (mustNotBeTrue && item.status === 'True') { + return + } + merged.push(item) + } + + for (const c of shootConditions.value) { + pushIfValid(c, false) + } + for (const c of shootConstraints.value) { + pushIfValid(c, true) + } + + return sortBy(merged, 'sortOrder') }) const errorCodeObjects = computed(() => { diff --git a/frontend/src/composables/useShootItem.js b/frontend/src/composables/useShootItem.js index 0d09cf95e7..d99bfd5a0f 100644 --- a/frontend/src/composables/useShootItem.js +++ b/frontend/src/composables/useShootItem.js @@ -125,7 +125,6 @@ export function createShootItemComposable (shootItem, options = {}) { shootConditions, shootConstraints, shootCredentialsRotation, - shootReadiness, shootObservedGeneration, shootTechnicalId, lastMaintenance, @@ -241,7 +240,6 @@ export function createShootItemComposable (shootItem, options = {}) { shootConditions, shootConstraints, shootCredentialsRotation, - shootReadiness, shootObservedGeneration, shootTechnicalId, lastMaintenance, diff --git a/frontend/src/composables/useShootStatus.js b/frontend/src/composables/useShootStatus.js index 027eddcd0e..df6e34248b 100644 --- a/frontend/src/composables/useShootStatus.js +++ b/frontend/src/composables/useShootStatus.js @@ -13,7 +13,6 @@ import { import get from 'lodash/get' import find from 'lodash/find' -import filter from 'lodash/filter' export const useShootStatus = shootItem => { const shootStatus = computed(() => { @@ -62,16 +61,6 @@ export const useShootStatus = shootItem => { return get(shootItem.value, ['status', 'credentials', 'rotation'], {}) }) - const shootReadiness = computed(() => { - const shootConstraintsNotInCondition = filter(shootConstraints.value, condition => { - return condition.status !== 'True' - }) - return [ - ...shootConditions.value, - ...shootConstraintsNotInCondition, - ] - }) - const shootObservedGeneration = computed(() => { return get(shootItem.value, ['status', 'observedGeneration']) }) @@ -140,7 +129,6 @@ export const useShootStatus = shootItem => { shootConditions, shootConstraints, shootCredentialsRotation, - shootReadiness, shootObservedGeneration, shootTechnicalId, lastMaintenance, diff --git a/frontend/src/store/config.js b/frontend/src/store/config.js index 95fbc758f0..e8d0146991 100644 --- a/frontend/src/store/config.js +++ b/frontend/src/store/config.js @@ -23,11 +23,22 @@ import get from 'lodash/get' import isEmpty from 'lodash/isEmpty' import camelCase from 'lodash/camelCase' +const defaultConditionStatusTextMappings = { + True: 'Healthy', + False: 'Error', +} + +const defaultConditionStatusMappings = { + Progressing: 'Degraded', +} + const wellKnownConditions = { APIServerAvailable: { name: 'API Server', shortName: 'API', description: 'Indicates whether the shoot\'s kube-apiserver is healthy and available. If this is in error state then no interaction with the cluster is possible. The workload running on the cluster is most likely not affected.', + statusTextMappings: defaultConditionStatusTextMappings, + statusMappings: defaultConditionStatusMappings, sortOrder: '0', }, ControlPlaneHealthy: { @@ -35,60 +46,76 @@ const wellKnownConditions = { shortName: 'CP', description: 'Indicates whether all control plane components are up and running.', showAdminOnly: true, + statusTextMappings: defaultConditionStatusTextMappings, + statusMappings: defaultConditionStatusMappings, sortOrder: '1', }, SystemComponentsHealthy: { name: 'System Components', shortName: 'SC', description: 'Indicates whether all system components in the kube-system namespace are up and running. Gardener manages these system components and should automatically take care that the components become healthy again.', + statusTextMappings: defaultConditionStatusTextMappings, + statusMappings: defaultConditionStatusMappings, sortOrder: '2', }, EveryNodeReady: { name: 'Nodes', shortName: 'N', description: 'Indicates whether all nodes registered to the cluster are healthy and up-to-date. If this is in error state there then there is probably an issue with the cluster nodes. In worst case there is currently not enough capacity to schedule all the workloads/pods running in the cluster and that might cause a service disruption of your applications.', + statusTextMappings: defaultConditionStatusTextMappings, + statusMappings: defaultConditionStatusMappings, sortOrder: '3', }, ObservabilityComponentsHealthy: { name: 'Observability Components', shortName: 'OC', description: 'Indicates whether all observability components like Prometheus, Vali, Plutono, etc. are up and running. Gardener manages these system components and should automatically take care that the components become healthy again.', + statusTextMappings: defaultConditionStatusTextMappings, + statusMappings: defaultConditionStatusMappings, sortOrder: '4', }, - MaintenancePreconditionsSatisfied: { - name: 'Maintenance Preconditions Satisfied', - shortName: 'M', - description: 'Indicates whether Gardener is able to perform required actions during maintenance. If you do not resolve this issue your cluster will eventually turn into an error state.', - sortOrder: '5', - }, - HibernationPossible: { - name: 'Hibernation Preconditions Satisfied', - shortName: 'H', - description: 'Indicates whether Gardener is able to hibernate this cluster. If you do not resolve this issue your hibernation schedule may not have any effect.', - sortOrder: '6', - }, BackupBucketsReady: { name: 'Seed Backup Buckets', shortName: 'BB', description: 'Indicates that associated BackupBuckets are ready.', - sortOrder: '7', + statusTextMappings: defaultConditionStatusTextMappings, + statusMappings: defaultConditionStatusMappings, + sortOrder: '5', }, ExtensionsReady: { name: 'Seed Extensions', shortName: 'E', description: 'Indicates that the extensions are ready.', - sortOrder: '8', + statusTextMappings: defaultConditionStatusTextMappings, + statusMappings: defaultConditionStatusMappings, + sortOrder: '6', }, GardenletReady: { name: 'Seed Gardenlet', shortName: 'G', description: 'Indicates that the Gardenlet is ready.', - sortOrder: '9', + statusTextMappings: defaultConditionStatusTextMappings, + statusMappings: defaultConditionStatusMappings, + sortOrder: '7', }, SeedSystemComponentsHealthy: { name: 'Seed System Components', shortName: 'SSC', description: 'Indicates the system components health', + statusTextMappings: defaultConditionStatusTextMappings, + statusMappings: defaultConditionStatusMappings, + sortOrder: '8', + }, + MaintenancePreconditionsSatisfied: { + name: 'Maintenance Preconditions Satisfied', + shortName: 'M', + description: 'Indicates whether Gardener is able to perform required actions during maintenance. If you do not resolve this issue your cluster will eventually turn into an error state.', + sortOrder: '9', + }, + HibernationPossible: { + name: 'Hibernation Possible', + shortName: 'H', + description: 'Indicates whether Gardener is able to hibernate this cluster. If you do not resolve this issue your hibernation schedule may not have any effect.', sortOrder: '10', }, CRDsWithProblematicConversionWebhooks: { @@ -106,7 +133,11 @@ const wellKnownConditions = { DualStackNodesMigrationReady: { name: 'Dual Stack Nodes Migration Ready', shortName: 'DSNM', - description: 'Indicates that the nodes of a shoot are ready for dual-stack migration of the cluster. If this is in error state, the nodes need to be rolled before the migration can continue. This error is expected at the beginning of the migration process and does not require immediate user action.', + description: 'Indicates that the nodes of a shoot are ready for dual-stack migration of the cluster.', + statusMappings: { + True: 'Progressing', + False: 'Done', + }, sortOrder: '13', }, }