diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 82de9f4..5472d61 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -215,3 +215,41 @@ var MigrationStatsFields = []string{ "fully_migrated_positions", "status", } + +// getKindPriority returns the installation priority for a resource kind +// Lower number = applied first (follows Helm 2.10 install order) +func GetKindPriority(kind string) int { + priorities := map[string]int{ + "Namespace": 0, + "ResourceQuota": 1, + "LimitRange": 2, + "PodSecurityPolicy": 3, + "Secret": 4, + "ConfigMap": 5, + "StorageClass": 6, + "PersistentVolume": 7, + "PersistentVolumeClaim": 8, + "ServiceAccount": 9, + "CustomResourceDefinition": 10, + "ClusterRole": 11, + "ClusterRoleBinding": 12, + "Role": 13, + "RoleBinding": 14, + "Service": 15, + "DaemonSet": 16, + "Pod": 17, + "ReplicationController": 18, + "ReplicaSet": 19, + "Deployment": 20, + "StatefulSet": 21, + "Job": 22, + "CronJob": 23, + "Ingress": 24, + "APIService": 25, + } + + if priority, exists := priorities[kind]; exists { + return priority + } + return 100 +} diff --git a/internal/k8s/actions/apply.go b/internal/k8s/actions/apply.go index e277529..30c3d40 100644 --- a/internal/k8s/actions/apply.go +++ b/internal/k8s/actions/apply.go @@ -5,7 +5,9 @@ import ( "fmt" "os" "path/filepath" + "sort" + "github.com/OpenSlides/openslides-cli/internal/constants" "github.com/OpenSlides/openslides-cli/internal/k8s/client" "github.com/OpenSlides/openslides-cli/internal/logger" "github.com/OpenSlides/openslides-cli/internal/utils" @@ -108,6 +110,7 @@ func applyDirectory(ctx context.Context, k8sClient *client.Client, dirPath strin return fmt.Errorf("reading directory: %w", err) } + var yamlFiles []os.DirEntry for _, file := range files { if file.IsDir() { continue @@ -117,7 +120,16 @@ func applyDirectory(ctx context.Context, k8sClient *client.Client, dirPath strin logger.Debug("Skipping non-YAML file: %s", file.Name()) continue } + yamlFiles = append(yamlFiles, file) + } + + sort.Slice(yamlFiles, func(i, j int) bool { + kindI := getKindFromFile(filepath.Join(dirPath, yamlFiles[i].Name())) + kindJ := getKindFromFile(filepath.Join(dirPath, yamlFiles[j].Name())) + return constants.GetKindPriority(kindI) < constants.GetKindPriority(kindJ) + }) + for _, file := range yamlFiles { manifestPath := filepath.Join(dirPath, file.Name()) if _, err := applyManifest(ctx, k8sClient, manifestPath); err != nil { logger.Warn("Failed to apply %s: %v", file.Name(), err) @@ -127,3 +139,18 @@ func applyDirectory(ctx context.Context, k8sClient *client.Client, dirPath strin return nil } + +// getKindFromFile reads the Kind field from a YAML file +func getKindFromFile(path string) string { + data, err := os.ReadFile(path) + if err != nil { + return "" + } + + var obj unstructured.Unstructured + if err := yaml.Unmarshal(data, &obj); err != nil { + return "" + } + + return obj.GetKind() +}