fix(volumes): update the external, unused badges and used by col [r8s-105] (#12302)

pull/12309/head
Ali 2024-10-08 11:41:47 +13:00 committed by GitHub
parent 44d6c0885e
commit 469a4e94c2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 62 additions and 28 deletions

View File

@ -214,6 +214,7 @@ func (kcl *KubeClient) CombineVolumesWithApplications(volumes *[]models.K8sVolum
hasReplicaSetOwnerReference := containsReplicaSetOwnerReference(pods) hasReplicaSetOwnerReference := containsReplicaSetOwnerReference(pods)
replicaSetItems := make([]appsv1.ReplicaSet, 0) replicaSetItems := make([]appsv1.ReplicaSet, 0)
deploymentItems := make([]appsv1.Deployment, 0)
if hasReplicaSetOwnerReference { if hasReplicaSetOwnerReference {
replicaSets, err := kcl.cli.AppsV1().ReplicaSets("").List(context.Background(), metav1.ListOptions{}) replicaSets, err := kcl.cli.AppsV1().ReplicaSets("").List(context.Background(), metav1.ListOptions{})
if err != nil { if err != nil {
@ -221,19 +222,48 @@ func (kcl *KubeClient) CombineVolumesWithApplications(volumes *[]models.K8sVolum
return nil, fmt.Errorf("an error occurred during the CombineVolumesWithApplications operation, unable to list replica sets across the cluster. Error: %w", err) return nil, fmt.Errorf("an error occurred during the CombineVolumesWithApplications operation, unable to list replica sets across the cluster. Error: %w", err)
} }
replicaSetItems = replicaSets.Items replicaSetItems = replicaSets.Items
deployments, err := kcl.cli.AppsV1().Deployments("").List(context.Background(), metav1.ListOptions{})
if err != nil {
log.Error().Err(err).Msg("Failed to list deployments across the cluster")
return nil, fmt.Errorf("an error occurred during the CombineVolumesWithApplications operation, unable to list deployments across the cluster. Error: %w", err)
}
deploymentItems = deployments.Items
} }
return kcl.updateVolumesWithOwningApplications(volumes, pods, replicaSetItems) hasStatefulSetOwnerReference := containsStatefulSetOwnerReference(pods)
statefulSetItems := make([]appsv1.StatefulSet, 0)
if hasStatefulSetOwnerReference {
statefulSets, err := kcl.cli.AppsV1().StatefulSets("").List(context.Background(), metav1.ListOptions{})
if err != nil {
log.Error().Err(err).Msg("Failed to list stateful sets across the cluster")
return nil, fmt.Errorf("an error occurred during the CombineVolumesWithApplications operation, unable to list stateful sets across the cluster. Error: %w", err)
}
statefulSetItems = statefulSets.Items
}
hasDaemonSetOwnerReference := containsDaemonSetOwnerReference(pods)
daemonSetItems := make([]appsv1.DaemonSet, 0)
if hasDaemonSetOwnerReference {
daemonSets, err := kcl.cli.AppsV1().DaemonSets("").List(context.Background(), metav1.ListOptions{})
if err != nil {
log.Error().Err(err).Msg("Failed to list daemon sets across the cluster")
return nil, fmt.Errorf("an error occurred during the CombineVolumesWithApplications operation, unable to list daemon sets across the cluster. Error: %w", err)
}
daemonSetItems = daemonSets.Items
}
return kcl.updateVolumesWithOwningApplications(volumes, pods, deploymentItems, replicaSetItems, statefulSetItems, daemonSetItems)
} }
// updateVolumesWithOwningApplications updates the volumes with the applications that use them. // updateVolumesWithOwningApplications updates the volumes with the applications that use them.
func (kcl *KubeClient) updateVolumesWithOwningApplications(volumes *[]models.K8sVolumeInfo, pods *corev1.PodList, replicaSetItems []appsv1.ReplicaSet) (*[]models.K8sVolumeInfo, error) { func (kcl *KubeClient) updateVolumesWithOwningApplications(volumes *[]models.K8sVolumeInfo, pods *corev1.PodList, deploymentItems []appsv1.Deployment, replicaSetItems []appsv1.ReplicaSet, statefulSetItems []appsv1.StatefulSet, daemonSetItems []appsv1.DaemonSet) (*[]models.K8sVolumeInfo, error) {
for i, volume := range *volumes { for i, volume := range *volumes {
for _, pod := range pods.Items { for _, pod := range pods.Items {
if pod.Spec.Volumes != nil { if pod.Spec.Volumes != nil {
for _, podVolume := range pod.Spec.Volumes { for _, podVolume := range pod.Spec.Volumes {
if podVolume.PersistentVolumeClaim != nil && podVolume.PersistentVolumeClaim.ClaimName == volume.PersistentVolumeClaim.Name && pod.Namespace == volume.PersistentVolumeClaim.Namespace { if podVolume.VolumeSource.PersistentVolumeClaim != nil && podVolume.VolumeSource.PersistentVolumeClaim.ClaimName == volume.PersistentVolumeClaim.Name && pod.Namespace == volume.PersistentVolumeClaim.Namespace {
application, err := kcl.ConvertPodToApplication(pod, replicaSetItems, []appsv1.Deployment{}, []appsv1.StatefulSet{}, []appsv1.DaemonSet{}, []corev1.Service{}, false) application, err := kcl.ConvertPodToApplication(pod, replicaSetItems, deploymentItems, statefulSetItems, daemonSetItems, []corev1.Service{}, false)
if err != nil { if err != nil {
log.Error().Err(err).Msg("Failed to convert pod to application") log.Error().Err(err).Msg("Failed to convert pod to application")
return nil, fmt.Errorf("an error occurred during the CombineServicesWithApplications operation, unable to convert pod to application. Error: %w", err) return nil, fmt.Errorf("an error occurred during the CombineServicesWithApplications operation, unable to convert pod to application. Error: %w", err)

View File

@ -21,7 +21,7 @@ import {
KubernetesApplicationVolumePersistentPayload, KubernetesApplicationVolumePersistentPayload,
KubernetesApplicationVolumeSecretPayload, KubernetesApplicationVolumeSecretPayload,
} from 'Kubernetes/models/application/payloads'; } from 'Kubernetes/models/application/payloads';
import KubernetesVolumeHelper from 'Kubernetes/helpers/volumeHelper'; import { generatedApplicationConfigVolumeName } from '@/react/kubernetes/volumes/utils';
import { HelmApplication } from 'Kubernetes/models/application/models'; import { HelmApplication } from 'Kubernetes/models/application/models';
import { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants'; import { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
import { KubernetesPodAffinity, KubernetesPodNodeAffinityNodeSelectorRequirementOperators } from 'Kubernetes/pod/models'; import { KubernetesPodAffinity, KubernetesPodNodeAffinityNodeSelectorRequirementOperators } from 'Kubernetes/pod/models';
@ -239,7 +239,7 @@ class KubernetesApplicationHelper {
const volKeys = _.filter(config.overridenKeys, (item) => item.type === 'FILESYSTEM'); const volKeys = _.filter(config.overridenKeys, (item) => item.type === 'FILESYSTEM');
const groupedVolKeys = _.groupBy(volKeys, 'path'); const groupedVolKeys = _.groupBy(volKeys, 'path');
_.forEach(groupedVolKeys, (items, path) => { _.forEach(groupedVolKeys, (items, path) => {
const volumeName = KubernetesVolumeHelper.generatedApplicationConfigVolumeName(app.Name); const volumeName = generatedApplicationConfigVolumeName(app.Name);
const configurationName = config.selectedConfiguration.metadata.name; const configurationName = config.selectedConfiguration.metadata.name;
const itemsMap = _.map(items, (item) => { const itemsMap = _.map(items, (item) => {
const entry = new KubernetesApplicationVolumeEntryPayload(); const entry = new KubernetesApplicationVolumeEntryPayload();

View File

@ -1,5 +1,4 @@
import _ from 'lodash-es'; import _ from 'lodash-es';
import uuidv4 from 'uuid/v4';
import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants'; import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
class KubernetesVolumeHelper { class KubernetesVolumeHelper {
@ -20,18 +19,6 @@ class KubernetesVolumeHelper {
); );
}); });
} }
static isUsed(item) {
return item.Applications.length !== 0;
}
static generatedApplicationConfigVolumeName(name) {
return 'config-' + name + '-' + uuidv4();
}
static isExternalVolume(volume) {
return !volume.PersistentVolumeClaim.ApplicationOwner;
}
} }
export default KubernetesVolumeHelper; export default KubernetesVolumeHelper;

View File

@ -29,6 +29,7 @@ import { confirm, confirmUpdate, confirmWebEditorDiscard } from '@@/modals/confi
import { buildConfirmButton } from '@@/modals/utils'; import { buildConfirmButton } from '@@/modals/utils';
import { ModalType } from '@@/modals'; import { ModalType } from '@@/modals';
import { KUBE_STACK_NAME_VALIDATION_REGEX } from '@/react/kubernetes/DeployView/StackName/constants'; import { KUBE_STACK_NAME_VALIDATION_REGEX } from '@/react/kubernetes/DeployView/StackName/constants';
import { isVolumeUsed } from '@/react/kubernetes/volumes/utils';
class KubernetesCreateApplicationController { class KubernetesCreateApplicationController {
/* #region CONSTRUCTOR */ /* #region CONSTRUCTOR */
@ -785,7 +786,7 @@ class KubernetesCreateApplicationController {
}); });
this.volumes = volumes; this.volumes = volumes;
const filteredVolumes = _.filter(this.volumes, (volume) => { const filteredVolumes = _.filter(this.volumes, (volume) => {
const isUnused = !KubernetesVolumeHelper.isUsed(volume); const isUnused = !isVolumeUsed(volume);
const isRWX = volume.PersistentVolumeClaim.storageClass && _.includes(volume.PersistentVolumeClaim.storageClass.AccessModes, 'RWX'); const isRWX = volume.PersistentVolumeClaim.storageClass && _.includes(volume.PersistentVolumeClaim.storageClass.AccessModes, 'RWX');
return isUnused || isRWX; return isUnused || isRWX;
}); });

View File

@ -6,6 +6,7 @@ import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper';
import { KubernetesStorageClassAccessPolicies } from 'Kubernetes/models/storage-class/models'; import { KubernetesStorageClassAccessPolicies } from 'Kubernetes/models/storage-class/models';
import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper'; import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
import { confirmRedeploy } from '@/react/kubernetes/volumes/ItemView/ConfirmRedeployModal'; import { confirmRedeploy } from '@/react/kubernetes/volumes/ItemView/ConfirmRedeployModal';
import { isVolumeUsed, isVolumeExternal } from '@/react/kubernetes/volumes/utils';
class KubernetesVolumeController { class KubernetesVolumeController {
/* @ngInject */ /* @ngInject */
@ -49,7 +50,7 @@ class KubernetesVolumeController {
} }
isExternalVolume() { isExternalVolume() {
return KubernetesVolumeHelper.isExternalVolume(this.volume); return isVolumeExternal(this.volume);
} }
isSystemNamespace() { isSystemNamespace() {
@ -57,7 +58,7 @@ class KubernetesVolumeController {
} }
isUsed() { isUsed() {
return KubernetesVolumeHelper.isUsed(this.volume); return isVolumeUsed(this.volume);
} }
onChangeSize() { onChangeSize() {
@ -102,7 +103,7 @@ class KubernetesVolumeController {
} }
updateVolume() { updateVolume() {
if (KubernetesVolumeHelper.isUsed(this.volume)) { if (isVolumeUsed(this.volume)) {
confirmRedeploy().then((redeploy) => { confirmRedeploy().then((redeploy) => {
return this.$async(this.updateVolumeAsync, redeploy); return this.$async(this.updateVolumeAsync, redeploy);
}); });

View File

@ -1,7 +1,6 @@
import { Database } from 'lucide-react'; import { Database } from 'lucide-react';
import { Authorized, useAuthorizations } from '@/react/hooks/useUser'; import { Authorized, useAuthorizations } from '@/react/hooks/useUser';
import KubernetesVolumeHelper from '@/kubernetes/helpers/volumeHelper';
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
import { refreshableSettings } from '@@/datatables/types'; import { refreshableSettings } from '@@/datatables/types';
@ -20,6 +19,7 @@ import { useNamespacesQuery } from '../../namespaces/queries/useNamespacesQuery'
import { useAllVolumesQuery } from '../queries/useVolumesQuery'; import { useAllVolumesQuery } from '../queries/useVolumesQuery';
import { isSystemNamespace } from '../../namespaces/queries/useIsSystemNamespace'; import { isSystemNamespace } from '../../namespaces/queries/useIsSystemNamespace';
import { useDeleteVolumes } from '../queries/useDeleteVolumes'; import { useDeleteVolumes } from '../queries/useDeleteVolumes';
import { isVolumeUsed } from '../utils';
import { columns } from './columns'; import { columns } from './columns';
@ -68,7 +68,7 @@ export function VolumesDatatable() {
disableSelect={!hasWriteAuth} disableSelect={!hasWriteAuth}
isRowSelectable={({ original: volume }) => isRowSelectable={({ original: volume }) =>
!isSystemNamespace(volume.ResourcePool.Namespace.Name, namespaces) && !isSystemNamespace(volume.ResourcePool.Namespace.Name, namespaces) &&
!KubernetesVolumeHelper.isUsed(volume) !isVolumeUsed(volume)
} }
renderTableActions={(selectedItems) => ( renderTableActions={(selectedItems) => (
<Authorized authorizations="K8sVolumesW"> <Authorized authorizations="K8sVolumesW">

View File

@ -1,6 +1,5 @@
import { CellContext } from '@tanstack/react-table'; import { CellContext } from '@tanstack/react-table';
import KubernetesVolumeHelper from '@/kubernetes/helpers/volumeHelper';
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId'; import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
import { Link } from '@@/Link'; import { Link } from '@@/Link';
@ -9,6 +8,7 @@ import { ExternalBadge } from '@@/Badge/ExternalBadge';
import { UnusedBadge } from '@@/Badge/UnusedBadge'; import { UnusedBadge } from '@@/Badge/UnusedBadge';
import { useNamespacesQuery } from '../../namespaces/queries/useNamespacesQuery'; import { useNamespacesQuery } from '../../namespaces/queries/useNamespacesQuery';
import { isVolumeExternal, isVolumeUsed } from '../utils';
import { VolumeViewModel } from './types'; import { VolumeViewModel } from './types';
import { helper } from './columns.helper'; import { helper } from './columns.helper';
@ -44,8 +44,8 @@ export function NameCell({
<SystemBadge /> <SystemBadge />
) : ( ) : (
<> <>
{KubernetesVolumeHelper.isExternalVolume(item) && <ExternalBadge />} {isVolumeExternal(item) && <ExternalBadge />}
{!KubernetesVolumeHelper.isUsed(item) && <UnusedBadge />} {!isVolumeUsed(item) && <UnusedBadge />}
</> </>
)} )}
</div> </div>

View File

@ -0,0 +1,15 @@
import uuidv4 from 'uuid/v4';
import { VolumeViewModel } from './ListView/types';
export function isVolumeUsed(volume: VolumeViewModel) {
return volume.Applications.length !== 0;
}
export function isVolumeExternal(volume: VolumeViewModel) {
return !volume.PersistentVolumeClaim.ApplicationOwner;
}
export function generatedApplicationConfigVolumeName(applicationName: string) {
return `config-${applicationName}-${uuidv4()}`;
}