mirror of https://github.com/portainer/portainer
fix(volumes): update the external, unused badges and used by col [r8s-105] (#12302)
parent
44d6c0885e
commit
469a4e94c2
|
@ -214,6 +214,7 @@ func (kcl *KubeClient) CombineVolumesWithApplications(volumes *[]models.K8sVolum
|
|||
|
||||
hasReplicaSetOwnerReference := containsReplicaSetOwnerReference(pods)
|
||||
replicaSetItems := make([]appsv1.ReplicaSet, 0)
|
||||
deploymentItems := make([]appsv1.Deployment, 0)
|
||||
if hasReplicaSetOwnerReference {
|
||||
replicaSets, err := kcl.cli.AppsV1().ReplicaSets("").List(context.Background(), metav1.ListOptions{})
|
||||
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)
|
||||
}
|
||||
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.
|
||||
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 _, pod := range pods.Items {
|
||||
if pod.Spec.Volumes != nil {
|
||||
for _, podVolume := range pod.Spec.Volumes {
|
||||
if podVolume.PersistentVolumeClaim != nil && podVolume.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)
|
||||
if podVolume.VolumeSource.PersistentVolumeClaim != nil && podVolume.VolumeSource.PersistentVolumeClaim.ClaimName == volume.PersistentVolumeClaim.Name && pod.Namespace == volume.PersistentVolumeClaim.Namespace {
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSetItems, deploymentItems, statefulSetItems, daemonSetItems, []corev1.Service{}, false)
|
||||
if err != nil {
|
||||
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)
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
KubernetesApplicationVolumePersistentPayload,
|
||||
KubernetesApplicationVolumeSecretPayload,
|
||||
} 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 { KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
import { KubernetesPodAffinity, KubernetesPodNodeAffinityNodeSelectorRequirementOperators } from 'Kubernetes/pod/models';
|
||||
|
@ -239,7 +239,7 @@ class KubernetesApplicationHelper {
|
|||
const volKeys = _.filter(config.overridenKeys, (item) => item.type === 'FILESYSTEM');
|
||||
const groupedVolKeys = _.groupBy(volKeys, 'path');
|
||||
_.forEach(groupedVolKeys, (items, path) => {
|
||||
const volumeName = KubernetesVolumeHelper.generatedApplicationConfigVolumeName(app.Name);
|
||||
const volumeName = generatedApplicationConfigVolumeName(app.Name);
|
||||
const configurationName = config.selectedConfiguration.metadata.name;
|
||||
const itemsMap = _.map(items, (item) => {
|
||||
const entry = new KubernetesApplicationVolumeEntryPayload();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import _ from 'lodash-es';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
import { KubernetesApplicationTypes } from 'Kubernetes/models/application/models/appConstants';
|
||||
|
||||
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;
|
||||
|
|
|
@ -29,6 +29,7 @@ import { confirm, confirmUpdate, confirmWebEditorDiscard } from '@@/modals/confi
|
|||
import { buildConfirmButton } from '@@/modals/utils';
|
||||
import { ModalType } from '@@/modals';
|
||||
import { KUBE_STACK_NAME_VALIDATION_REGEX } from '@/react/kubernetes/DeployView/StackName/constants';
|
||||
import { isVolumeUsed } from '@/react/kubernetes/volumes/utils';
|
||||
|
||||
class KubernetesCreateApplicationController {
|
||||
/* #region CONSTRUCTOR */
|
||||
|
@ -785,7 +786,7 @@ class KubernetesCreateApplicationController {
|
|||
});
|
||||
this.volumes = volumes;
|
||||
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');
|
||||
return isUnused || isRWX;
|
||||
});
|
||||
|
|
|
@ -6,6 +6,7 @@ import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper';
|
|||
import { KubernetesStorageClassAccessPolicies } from 'Kubernetes/models/storage-class/models';
|
||||
import KubernetesNamespaceHelper from 'Kubernetes/helpers/namespaceHelper';
|
||||
import { confirmRedeploy } from '@/react/kubernetes/volumes/ItemView/ConfirmRedeployModal';
|
||||
import { isVolumeUsed, isVolumeExternal } from '@/react/kubernetes/volumes/utils';
|
||||
|
||||
class KubernetesVolumeController {
|
||||
/* @ngInject */
|
||||
|
@ -49,7 +50,7 @@ class KubernetesVolumeController {
|
|||
}
|
||||
|
||||
isExternalVolume() {
|
||||
return KubernetesVolumeHelper.isExternalVolume(this.volume);
|
||||
return isVolumeExternal(this.volume);
|
||||
}
|
||||
|
||||
isSystemNamespace() {
|
||||
|
@ -57,7 +58,7 @@ class KubernetesVolumeController {
|
|||
}
|
||||
|
||||
isUsed() {
|
||||
return KubernetesVolumeHelper.isUsed(this.volume);
|
||||
return isVolumeUsed(this.volume);
|
||||
}
|
||||
|
||||
onChangeSize() {
|
||||
|
@ -102,7 +103,7 @@ class KubernetesVolumeController {
|
|||
}
|
||||
|
||||
updateVolume() {
|
||||
if (KubernetesVolumeHelper.isUsed(this.volume)) {
|
||||
if (isVolumeUsed(this.volume)) {
|
||||
confirmRedeploy().then((redeploy) => {
|
||||
return this.$async(this.updateVolumeAsync, redeploy);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Database } from 'lucide-react';
|
||||
|
||||
import { Authorized, useAuthorizations } from '@/react/hooks/useUser';
|
||||
import KubernetesVolumeHelper from '@/kubernetes/helpers/volumeHelper';
|
||||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
|
||||
import { refreshableSettings } from '@@/datatables/types';
|
||||
|
@ -20,6 +19,7 @@ import { useNamespacesQuery } from '../../namespaces/queries/useNamespacesQuery'
|
|||
import { useAllVolumesQuery } from '../queries/useVolumesQuery';
|
||||
import { isSystemNamespace } from '../../namespaces/queries/useIsSystemNamespace';
|
||||
import { useDeleteVolumes } from '../queries/useDeleteVolumes';
|
||||
import { isVolumeUsed } from '../utils';
|
||||
|
||||
import { columns } from './columns';
|
||||
|
||||
|
@ -68,7 +68,7 @@ export function VolumesDatatable() {
|
|||
disableSelect={!hasWriteAuth}
|
||||
isRowSelectable={({ original: volume }) =>
|
||||
!isSystemNamespace(volume.ResourcePool.Namespace.Name, namespaces) &&
|
||||
!KubernetesVolumeHelper.isUsed(volume)
|
||||
!isVolumeUsed(volume)
|
||||
}
|
||||
renderTableActions={(selectedItems) => (
|
||||
<Authorized authorizations="K8sVolumesW">
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { CellContext } from '@tanstack/react-table';
|
||||
|
||||
import KubernetesVolumeHelper from '@/kubernetes/helpers/volumeHelper';
|
||||
import { useEnvironmentId } from '@/react/hooks/useEnvironmentId';
|
||||
|
||||
import { Link } from '@@/Link';
|
||||
|
@ -9,6 +8,7 @@ import { ExternalBadge } from '@@/Badge/ExternalBadge';
|
|||
import { UnusedBadge } from '@@/Badge/UnusedBadge';
|
||||
|
||||
import { useNamespacesQuery } from '../../namespaces/queries/useNamespacesQuery';
|
||||
import { isVolumeExternal, isVolumeUsed } from '../utils';
|
||||
|
||||
import { VolumeViewModel } from './types';
|
||||
import { helper } from './columns.helper';
|
||||
|
@ -44,8 +44,8 @@ export function NameCell({
|
|||
<SystemBadge />
|
||||
) : (
|
||||
<>
|
||||
{KubernetesVolumeHelper.isExternalVolume(item) && <ExternalBadge />}
|
||||
{!KubernetesVolumeHelper.isUsed(item) && <UnusedBadge />}
|
||||
{isVolumeExternal(item) && <ExternalBadge />}
|
||||
{!isVolumeUsed(item) && <UnusedBadge />}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -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()}`;
|
||||
}
|
Loading…
Reference in New Issue