package lumperctl import ( "context" "flag" "fmt" "time" "github.com/peterbourgon/ff/v3" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" "edge-infra.dev/pkg/f8n/warehouse/cluster" "edge-infra.dev/pkg/f8n/warehouse/k8s/controllers/lumperctl/internal" "edge-infra.dev/pkg/f8n/warehouse/oci/cache" eclient "edge-infra.dev/pkg/k8s/runtime/client" ) // config is the controllers application config type Config struct { // cluster and provider options // // clusterUUID is the uuid of the cluster the controller is running on clusterUUID string // provider is the cluster provider the controller is deployed on Provider cluster.Provider // the provider information can also be provided via a reference to a ConfigMap // and an optional key to pull the value from. if the key isn't provided, the // default "cluster_provider" is used providerConfigMapRef string providerConfigMapKey string // svcAct is the name of the service account used to deploy the controller SvcAct string // namespace is the namespace this controller is deployed to Namespace string memoryCacheLimit int UpCfg UnpackedPalletCfg ShipCfg ShipmentCfg Cache cache.Cache // computed by afterParse if not set directly } // shipmentCfg is config that only applie to the Shipment reconciler type ShipmentCfg struct { // concurrent reconciles Concurrent int } // unpackedPalletCfg is config that only applies to the UnpackedPallet reconciler type UnpackedPalletCfg struct { // concurrent reconciles Concurrent int // how frequently we re-reconcile when unpackedpallet dep isn't ready DepRequeueInterval time.Duration } // newConfig creates the controller config, reading initial values via flags and // environment variables via ff func newConfig(args []string) (*Config, error) { fs := flag.NewFlagSet("lumperctl", flag.ExitOnError) cfg := &Config{} cfg.bindFlags(fs) if err := ff.Parse(fs, args, ff.WithEnvVarNoPrefix()); err != nil { return nil, fmt.Errorf("failed to parse configuration: %w", err) } if err := cfg.validate(); err != nil { return nil, fmt.Errorf("invalid configuration: %w", err) } return cfg, nil } // afterParse computes additional values after flags have been parsed func (c *Config) afterParse(ctx context.Context, k client.Client) error { // read provider from configmap if not provided if c.Provider == "" { key, err := eclient.ObjectKeyFromRefStr(c.providerConfigMapRef) if err != nil { return err } cmap := &corev1.ConfigMap{} if err := k.Get(ctx, key, cmap); err != nil { return err } switch { case len(cmap.Data) == 0: return fmt.Errorf("%s is invalid: no data keys", c.providerConfigMapRef) case len(cmap.Data) == 1: for _, v := range cmap.Data { c.Provider = cluster.Provider(v) } case cmap.Data[c.providerConfigMapKey] != "": c.Provider = cluster.Provider(cmap.Data[c.providerConfigMapKey]) default: return fmt.Errorf("%s is invalid: key %s not found", c.providerConfigMapRef, c.providerConfigMapKey) } } if c.Cache == nil { var err error c.Cache, err = cache.New( cache.WithRecorder(internal.CacheRecorder{}), cache.WithMemoryCacheSize(c.memoryCacheLimit), ) if err != nil { return err } } return nil } func (c *Config) validate() error { if c.Provider == "" && c.providerConfigMapRef == "" { return fmt.Errorf("--cluster-provider or --cluster-provider-configmap-ref are required") } return nil } // bindFlags binds the controller's configuration to command line flags. func (c *Config) bindFlags(fs *flag.FlagSet) { // cluster flags fs.Var(&c.Provider, "cluster-provider", "K8s cluster provider. Takes precedence over other provider flags.") fs.StringVar(&c.providerConfigMapRef, "cluster-provider-configmap-ref", "", "Reference to ConfigMap containing cluster provider information, in the "+ "namespace/name format") fs.StringVar(&c.providerConfigMapKey, "cluster-provider-configmap-key", "cluster_provider", "Key to read cluster provider information from. If only a single key exists, "+ "it will be used. If more than one key exists, the value of this flag will "+ "be used.") fs.StringVar(&c.clusterUUID, "cluster-uuid", "", "uuid of the cluster that the controller is running on") // k8s deployment flags fs.StringVar(&c.Namespace, "namespace", "", "K8s Namespace the controller is deployed to") fs.StringVar(&c.SvcAct, "service-account", "", "K8s ServiceAccount scheduling the controller") // caching flags fs.IntVar(&c.memoryCacheLimit, "memory-cache-limit", 200, "entries limit for the in-memory artifact cache") // UnpackedPalletReconciler flags fs.IntVar(&c.UpCfg.Concurrent, "unpacked-pallet-concurrency", 24, "how many UnpackedPallets can reconcile at the same time") fs.DurationVar(&c.UpCfg.DepRequeueInterval, "dependency-requeue-interval", 30*time.Second, "how frequently not-Ready dependencies are checked") // ShipmentReconciler flags fs.IntVar(&c.ShipCfg.Concurrent, "shipment-concurrency", 6, "how many Shipments can reconcile at the same time") }