mirror of
https://github.com/portainer/portainer.git
synced 2025-07-21 06:19:41 +02:00
fix(apps): update associated resources on deletion [r8s-124] (#75)
This commit is contained in:
parent
d418784346
commit
c1316532eb
15 changed files with 281 additions and 90 deletions
|
@ -6,6 +6,7 @@ import (
|
|||
models "github.com/portainer/portainer/api/http/models/kubernetes"
|
||||
"github.com/rs/zerolog/log"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
autoscalingv2 "k8s.io/api/autoscaling/v2"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
labels "k8s.io/apimachinery/pkg/labels"
|
||||
|
@ -31,20 +32,20 @@ func (kcl *KubeClient) fetchApplications(namespace, nodeName string, withDepende
|
|||
}
|
||||
if !withDependencies {
|
||||
// TODO: make sure not to fetch services in fetchAllApplicationsListResources from this call
|
||||
pods, replicaSets, deployments, statefulSets, daemonSets, _, err := kcl.fetchAllApplicationsListResources(namespace, podListOptions)
|
||||
pods, replicaSets, deployments, statefulSets, daemonSets, _, _, err := kcl.fetchAllApplicationsListResources(namespace, podListOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return kcl.convertPodsToApplications(pods, replicaSets, deployments, statefulSets, daemonSets, nil)
|
||||
return kcl.convertPodsToApplications(pods, replicaSets, deployments, statefulSets, daemonSets, nil, nil)
|
||||
}
|
||||
|
||||
pods, replicaSets, deployments, statefulSets, daemonSets, services, err := kcl.fetchAllApplicationsListResources(namespace, podListOptions)
|
||||
pods, replicaSets, deployments, statefulSets, daemonSets, services, hpas, err := kcl.fetchAllApplicationsListResources(namespace, podListOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return kcl.convertPodsToApplications(pods, replicaSets, deployments, statefulSets, daemonSets, services)
|
||||
return kcl.convertPodsToApplications(pods, replicaSets, deployments, statefulSets, daemonSets, services, hpas)
|
||||
}
|
||||
|
||||
// fetchApplicationsForNonAdmin fetches the applications in the namespaces the user has access to.
|
||||
|
@ -62,20 +63,20 @@ func (kcl *KubeClient) fetchApplicationsForNonAdmin(namespace, nodeName string,
|
|||
}
|
||||
|
||||
if !withDependencies {
|
||||
pods, replicaSets, _, _, _, _, err := kcl.fetchAllPodsAndReplicaSets(namespace, podListOptions)
|
||||
pods, replicaSets, _, _, _, _, _, err := kcl.fetchAllPodsAndReplicaSets(namespace, podListOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return kcl.convertPodsToApplications(pods, replicaSets, nil, nil, nil, nil)
|
||||
return kcl.convertPodsToApplications(pods, replicaSets, nil, nil, nil, nil, nil)
|
||||
}
|
||||
|
||||
pods, replicaSets, deployments, statefulSets, daemonSets, services, err := kcl.fetchAllApplicationsListResources(namespace, podListOptions)
|
||||
pods, replicaSets, deployments, statefulSets, daemonSets, services, hpas, err := kcl.fetchAllApplicationsListResources(namespace, podListOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
applications, err := kcl.convertPodsToApplications(pods, replicaSets, deployments, statefulSets, daemonSets, services)
|
||||
applications, err := kcl.convertPodsToApplications(pods, replicaSets, deployments, statefulSets, daemonSets, services, hpas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -92,7 +93,7 @@ func (kcl *KubeClient) fetchApplicationsForNonAdmin(namespace, nodeName string,
|
|||
}
|
||||
|
||||
// convertPodsToApplications processes pods and converts them to applications, ensuring uniqueness by owner reference.
|
||||
func (kcl *KubeClient) convertPodsToApplications(pods []corev1.Pod, replicaSets []appsv1.ReplicaSet, deployments []appsv1.Deployment, statefulSets []appsv1.StatefulSet, daemonSets []appsv1.DaemonSet, services []corev1.Service) ([]models.K8sApplication, error) {
|
||||
func (kcl *KubeClient) convertPodsToApplications(pods []corev1.Pod, replicaSets []appsv1.ReplicaSet, deployments []appsv1.Deployment, statefulSets []appsv1.StatefulSet, daemonSets []appsv1.DaemonSet, services []corev1.Service, hpas []autoscalingv2.HorizontalPodAutoscaler) ([]models.K8sApplication, error) {
|
||||
applications := []models.K8sApplication{}
|
||||
processedOwners := make(map[string]struct{})
|
||||
|
||||
|
@ -105,7 +106,7 @@ func (kcl *KubeClient) convertPodsToApplications(pods []corev1.Pod, replicaSets
|
|||
processedOwners[ownerUID] = struct{}{}
|
||||
}
|
||||
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, deployments, statefulSets, daemonSets, services, true)
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, deployments, statefulSets, daemonSets, services, hpas, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -150,7 +151,7 @@ func (kcl *KubeClient) GetApplicationNamesFromConfigMap(configMap models.K8sConf
|
|||
for _, pod := range pods {
|
||||
if pod.Namespace == configMap.Namespace {
|
||||
if isPodUsingConfigMap(&pod, configMap.Name) {
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, nil, nil, nil, nil, false)
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, nil, nil, nil, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -167,7 +168,7 @@ func (kcl *KubeClient) GetApplicationNamesFromSecret(secret models.K8sSecret, po
|
|||
for _, pod := range pods {
|
||||
if pod.Namespace == secret.Namespace {
|
||||
if isPodUsingSecret(&pod, secret.Name) {
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, nil, nil, nil, nil, false)
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, nil, nil, nil, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -180,12 +181,12 @@ func (kcl *KubeClient) GetApplicationNamesFromSecret(secret models.K8sSecret, po
|
|||
}
|
||||
|
||||
// ConvertPodToApplication converts a pod to an application, updating owner references if necessary
|
||||
func (kcl *KubeClient) ConvertPodToApplication(pod corev1.Pod, replicaSets []appsv1.ReplicaSet, deployments []appsv1.Deployment, statefulSets []appsv1.StatefulSet, daemonSets []appsv1.DaemonSet, services []corev1.Service, withResource bool) (*models.K8sApplication, error) {
|
||||
func (kcl *KubeClient) ConvertPodToApplication(pod corev1.Pod, replicaSets []appsv1.ReplicaSet, deployments []appsv1.Deployment, statefulSets []appsv1.StatefulSet, daemonSets []appsv1.DaemonSet, services []corev1.Service, hpas []autoscalingv2.HorizontalPodAutoscaler, withResource bool) (*models.K8sApplication, error) {
|
||||
if isReplicaSetOwner(pod) {
|
||||
updateOwnerReferenceToDeployment(&pod, replicaSets)
|
||||
}
|
||||
|
||||
application := createApplication(&pod, deployments, statefulSets, daemonSets, services)
|
||||
application := createApplication(&pod, deployments, statefulSets, daemonSets, services, hpas)
|
||||
if application.ID == "" && application.Name == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
@ -204,7 +205,7 @@ func (kcl *KubeClient) ConvertPodToApplication(pod corev1.Pod, replicaSets []app
|
|||
|
||||
// createApplication creates a K8sApplication object from a pod
|
||||
// it sets the application name, namespace, kind, image, stack id, stack name, and labels
|
||||
func createApplication(pod *corev1.Pod, deployments []appsv1.Deployment, statefulSets []appsv1.StatefulSet, daemonSets []appsv1.DaemonSet, services []corev1.Service) models.K8sApplication {
|
||||
func createApplication(pod *corev1.Pod, deployments []appsv1.Deployment, statefulSets []appsv1.StatefulSet, daemonSets []appsv1.DaemonSet, services []corev1.Service, hpas []autoscalingv2.HorizontalPodAutoscaler) models.K8sApplication {
|
||||
kind := "Pod"
|
||||
name := pod.Name
|
||||
|
||||
|
@ -324,7 +325,11 @@ func createApplication(pod *corev1.Pod, deployments []appsv1.Deployment, statefu
|
|||
}
|
||||
|
||||
if application.ID != "" && application.Name != "" && len(services) > 0 {
|
||||
return updateApplicationWithService(application, services)
|
||||
updateApplicationWithService(&application, services)
|
||||
}
|
||||
|
||||
if application.ID != "" && application.Name != "" && len(hpas) > 0 {
|
||||
updateApplicationWithHorizontalPodAutoscaler(&application, hpas)
|
||||
}
|
||||
|
||||
return application
|
||||
|
@ -332,7 +337,7 @@ func createApplication(pod *corev1.Pod, deployments []appsv1.Deployment, statefu
|
|||
|
||||
// updateApplicationWithService updates the application with the services that match the application's selector match labels
|
||||
// and are in the same namespace as the application
|
||||
func updateApplicationWithService(application models.K8sApplication, services []corev1.Service) models.K8sApplication {
|
||||
func updateApplicationWithService(application *models.K8sApplication, services []corev1.Service) {
|
||||
for _, service := range services {
|
||||
serviceSelector := labels.SelectorFromSet(service.Spec.Selector)
|
||||
|
||||
|
@ -341,8 +346,23 @@ func updateApplicationWithService(application models.K8sApplication, services []
|
|||
application.Services = append(application.Services, service)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return application
|
||||
func updateApplicationWithHorizontalPodAutoscaler(application *models.K8sApplication, hpas []autoscalingv2.HorizontalPodAutoscaler) {
|
||||
for _, hpa := range hpas {
|
||||
// Check if HPA is in the same namespace as the application
|
||||
if hpa.Namespace != application.ResourcePool {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if the scale target ref matches the application
|
||||
scaleTargetRef := hpa.Spec.ScaleTargetRef
|
||||
if scaleTargetRef.Name == application.Name && scaleTargetRef.Kind == application.Kind {
|
||||
hpaCopy := hpa // Create a local copy
|
||||
application.HorizontalPodAutoscaler = &hpaCopy
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// calculatePodResourceUsage calculates the resource usage for a pod in CPU cores and Bytes
|
||||
|
@ -390,7 +410,7 @@ func (kcl *KubeClient) GetApplicationConfigurationOwnersFromConfigMap(configMap
|
|||
for _, pod := range pods {
|
||||
if pod.Namespace == configMap.Namespace {
|
||||
if isPodUsingConfigMap(&pod, configMap.Name) {
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, nil, nil, nil, nil, false)
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, nil, nil, nil, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -416,7 +436,7 @@ func (kcl *KubeClient) GetApplicationConfigurationOwnersFromSecret(secret models
|
|||
for _, pod := range pods {
|
||||
if pod.Namespace == secret.Namespace {
|
||||
if isPodUsingSecret(&pod, secret.Name) {
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, nil, nil, nil, nil, false)
|
||||
application, err := kcl.ConvertPodToApplication(pod, replicaSets, nil, nil, nil, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue