package kustomization import ( "fmt" "github.com/thoas/go-funk" "sigs.k8s.io/controller-runtime/pkg/client" clusterApi "edge-infra.dev/pkg/edge/apis/cluster/v1alpha1" "edge-infra.dev/pkg/edge/constants" "edge-infra.dev/pkg/edge/constants/api/cluster" "edge-infra.dev/pkg/edge/constants/api/fleet" "edge-infra.dev/pkg/edge/flux/bootstrap" ) const ( // ForemanBucketName default foreman bucket name. ForemanBucketName = "bucket" // BannerInfraBucketName default banner-infra bucket name. BannerInfraBucketName = "banner-infra-sync" ) var ( warehouseKustomizations = []*Kustomizations{ { Name: "shipments", Namespace: constants.FluxEdgeNamespace, Path: constants.ShipmentKustomizationDir, Prune: false, Force: false, SupportedFleet: fleet.Types, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, { Name: "chariot", Namespace: constants.FluxEdgeNamespace, Path: "chariot", Prune: true, Force: true, SupportedFleet: fleet.Types, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, } defaultKustomizations = []*Kustomizations{ { Name: "chariot", Namespace: constants.FluxEdgeNamespace, Path: "chariot", Prune: true, Force: true, SupportedFleet: fleet.Types, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, { Name: "cluster", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/cluster", Prune: false, Force: true, SupportedFleet: fleet.Types, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, { Name: "namespaces", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/namespaces", Prune: false, Force: true, SupportedFleet: fleet.Types, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, { Name: "cert-manager", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/cert-manager", Prune: false, Force: true, SupportedFleet: fleet.Types, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, { Name: "external-secrets", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/external-secrets", Prune: false, Force: true, SupportedFleet: fleet.Types, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, { Name: "gatekeeper-constraints", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/gatekeeper-policies/constraints", Prune: false, Force: true, SupportedFleet: []fleet.Type{fleet.Store, fleet.BasicStore, fleet.CouchDB, fleet.Cluster}, SupportedCluster: []cluster.Type{cluster.GKE}, OverrideSyncSuffix: false, }, { Name: "gatekeeper-constraint-templates", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/gatekeeper-policies/constraint-templates", Prune: false, Force: true, SupportedFleet: []fleet.Type{fleet.Store, fleet.BasicStore, fleet.CouchDB, fleet.Cluster}, SupportedCluster: []cluster.Type{cluster.GKE}, OverrideSyncSuffix: false, }, { Name: "gatekeeper-system", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/gatekeeper-system", Prune: false, Force: true, SupportedFleet: []fleet.Type{fleet.Store, fleet.BasicStore, fleet.CouchDB, fleet.Cluster}, SupportedCluster: []cluster.Type{cluster.GKE}, OverrideSyncSuffix: false, }, { Name: "flux-system", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/flux-system", Prune: false, Force: true, SupportedFleet: fleet.Types, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, { Name: "redpanda", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/redpanda", Prune: false, Force: true, SupportedFleet: []fleet.Type{fleet.Store}, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, { Name: "k8s-config-connector", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/k8s-config-connector", Prune: false, Force: true, SupportedFleet: []fleet.Type{fleet.Cluster, fleet.Banner}, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, }, { Name: "banner-infra", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/fluxcfg", Prune: false, Force: true, SupportedFleet: []fleet.Type{fleet.Banner}, SupportedCluster: cluster.Types, OverrideSyncSuffix: false, OverridePath: true, }, { Name: "sds", Namespace: constants.FluxEdgeNamespace, Path: "hydrated/sds", Prune: true, Force: true, SupportedFleet: []fleet.Type{fleet.Store}, SupportedCluster: []cluster.Type{cluster.DSDS}, OverrideSyncSuffix: false, }, } ) // EdgeKustomizations represents a group of kustomizations for a cluster from which kustomization manifests can be built. type EdgeKustomizations struct { // Cluster the cluster for which the kustomizations are being generated for. Cluster *clusterApi.Cluster // BucketName the name of the bucket to which the kustomization will point to. BucketName string BucketNamespace string // Rules list of kustomization rules used to generate each kustomization. Rules []*Kustomizations Annotations map[string]string StoreVersion string } // Kustomizations represents a singular kustomization from which a kustomization manifest can be built. type Kustomizations struct { Name string Namespace string Path string Prune bool Force bool SupportedFleet []fleet.Type SupportedCluster []cluster.Type OverrideSyncSuffix bool OverridePath bool } // New returns new Edge Kustomizations. func New() *EdgeKustomizations { return &EdgeKustomizations{ Annotations: make(map[string]string), } } // SetCluster sets the cluster for the edge kustomizations. func (k *EdgeKustomizations) SetCluster(cluster *clusterApi.Cluster) *EdgeKustomizations { k.Cluster = cluster return k } // SetBucketName sets the bucket name for the edge kustomization. func (k *EdgeKustomizations) SetBucketName(name string) *EdgeKustomizations { k.BucketName = name return k } func (k *EdgeKustomizations) SetBucketNamespace(ns string) *EdgeKustomizations { k.BucketNamespace = ns return k } func (k *EdgeKustomizations) SetStoreVersion(version string) *EdgeKustomizations { k.StoreVersion = version return k } func (k *EdgeKustomizations) SetAnnotations(annotations map[string]string) *EdgeKustomizations { k.Annotations = annotations return k } // UseDefaultRules returns all the default kustomization rules. func (k *EdgeKustomizations) UseDefaultRules() *EdgeKustomizations { k.Rules = defaultKustomizations return k } // UseDefaultRules returns all the default kustomization rules. func (k *EdgeKustomizations) UseWarehouseRules() *EdgeKustomizations { k.Rules = warehouseKustomizations return k } // UseDefaultForemanRules filters the default kustomizations and returns kustomization rules for foreman clusters. func (k *EdgeKustomizations) UseDefaultForemanRules() *EdgeKustomizations { foremanRules := funk.Filter(defaultKustomizations, isForemanRule) k.Rules = foremanRules.([]*Kustomizations) return k } // UseDefaultStoreRules filters the default kustomizations and returns kustomization rules for store clusters. func (k *EdgeKustomizations) UseDefaultStoreRules() *EdgeKustomizations { storeRules := funk.Filter(defaultKustomizations, isStoreRule) k.Rules = storeRules.([]*Kustomizations) return k } // UseDefaultBannerInfraRules filters the default kustomizations and returns kustomization rules for banner-infra clusters. func (k *EdgeKustomizations) UseDefaultBannerInfraRules() *EdgeKustomizations { storeRules := funk.Filter(defaultKustomizations, isBannerInfraRule) k.Rules = storeRules.([]*Kustomizations) return k } // RegisterNewRule registers a new kustomization rule that is different from the provided defaults. func (k *EdgeKustomizations) RegisterNewRule(name, namespace, path string, prune, force bool, supportedFleets []fleet.Type, supportedClusters []cluster.Type, overrideSuffix bool) *EdgeKustomizations { k.Rules = append(k.Rules, &Kustomizations{ Name: name, Namespace: namespace, Path: path, Prune: prune, Force: force, SupportedFleet: supportedFleets, SupportedCluster: supportedClusters, OverrideSyncSuffix: overrideSuffix, }) return k } // CreateBannerKustomization creates the customization for the banner func (k *EdgeKustomizations) CreateBannerKustomization() client.Object { return bootstrap.KustomizeFluxConfig(). Name("banner-sync"). Namespace(k.BucketNamespace). BucketName(k.BucketName). Path("./chariot"). Force(true). Prune(true). ForStoreVersion(k.StoreVersion). Annotations(k.Annotations). BucketNamespace(k.BucketNamespace). Build() } // CreateClusterKustomizations creates the kustomization manifests for the cluster. func (k *EdgeKustomizations) CreateClusterKustomizations() []client.Object { kustomizations := make([]client.Object, 0) clusterEdgeID := k.Cluster.Name if k.BucketName == "" { k.BucketName = fmt.Sprintf("%s-cluster-sync", clusterEdgeID) } for _, kusto := range k.Rules { name := fmt.Sprintf("%s-sync", kusto.Name) path := fmt.Sprintf("./%s/%s", clusterEdgeID, kusto.Path) if kusto.OverrideSyncSuffix { name = kusto.Name } if kusto.OverridePath { path = fmt.Sprintf("./%s/%s/%s", clusterEdgeID, kusto.Path, clusterEdgeID) } if funk.Contains(kusto.SupportedFleet, k.Cluster.Spec.Fleet) && funk.Contains(kusto.SupportedCluster, k.Cluster.Spec.Type) { k := bootstrap.KustomizeFluxConfig(). Name(name). Namespace(kusto.Namespace). BucketName(k.BucketName). Path(path). Force(kusto.Force). Prune(kusto.Prune). Annotations(k.Annotations). ForStoreVersion(k.StoreVersion). BucketNamespace(k.BucketNamespace). Build() kustomizations = append(kustomizations, k) } } return kustomizations } // isForemanRule returns true if the cluster is a foreman cluster. func isForemanRule(k *Kustomizations) bool { for _, fleetType := range k.SupportedFleet { if fleetType == fleet.TopLevel { return true } } return false } // isBannerInfraRule returns true if the cluster is a banner-infra cluster. func isBannerInfraRule(k *Kustomizations) bool { for _, fleetType := range k.SupportedFleet { if fleetType == fleet.Banner { return true } } return false } // isStoreRule returns true if the cluster is a basic-store or store cluster. func isStoreRule(k *Kustomizations) bool { for _, fleetType := range k.SupportedFleet { if fleetType == fleet.BasicStore || fleetType == fleet.Store { return true } } return false }