diff --git a/cmd/atc-installer/installer/run.go b/cmd/atc-installer/installer/run.go index 5fac074a..bf072dd4 100644 --- a/cmd/atc-installer/installer/run.go +++ b/cmd/atc-installer/installer/run.go @@ -23,17 +23,20 @@ import ( ) type Config struct { - Labels map[string]string `json:"labels,omitempty"` - Annotations map[string]string `json:"annotations,omitempty"` - Image string `json:"image,omitzero" Description:"set the image you want to deploy"` - Version string `json:"version,omitzero" Description:"version of the deployed image"` - Port int `json:"port,omitzero"` - ServiceAccountName string `json:"serviceAccountName,omitzero"` - ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitzero"` - GenerateTLS bool `json:"generateTLS,omitzero" Description:"generate new tls certificates even if they already exist"` - DockerConfigSecretName string `json:"dockerConfigSecretName,omitzero" Description:"name of dockerconfig secret to allow atc to pull images from private registries"` - LogFormat string `json:"logFormat,omitzero" Enum:"json,text"` - Verbose bool `json:"verbose,omitzero" Description:"verbose logging"` + Labels map[string]string `json:"labels,omitempty"` + Annotations map[string]string `json:"annotations,omitempty"` + Image string `json:"image,omitzero" Description:"set the image you want to deploy"` + Version string `json:"version,omitzero" Description:"version of the deployed image"` + Port int `json:"port,omitzero"` + ServiceAccountName string `json:"serviceAccountName,omitzero"` + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitzero"` + GenerateTLS bool `json:"generateTLS,omitzero" Description:"generate new tls certificates even if they already exist"` + DockerConfigSecretName string `json:"dockerConfigSecretName,omitzero" Description:"name of dockerconfig secret to allow atc to pull images from private registries"` + LogFormat string `json:"logFormat,omitzero" Enum:"json,text"` + Verbose bool `json:"verbose,omitzero" Description:"verbose logging"` + AirwayValidationWebhookTimeout int `json:"airwayValidationWebhookTimeout,omitzero" Description:"timeout in seconds for airway instance validation webhooks (default: 10)"` + ResourceValidationWebhookTimeout int `json:"resourceValidationWebhookTimeout,omitzero" Description:"timeout in seconds for resource/event dispatching validation webhooks (default: 5)"` + ExternalResourceValidationWebhookTimeout int `json:"externalResourceValidationWebhookTimeout,omitzero" Description:"timeout in seconds for external resource validation webhooks (default: 30)"` } func Run(cfg Config) (flight.Resources, error) { @@ -209,18 +212,39 @@ func Run(cfg Config) (flight.Resources, error) { Name: "yokecd-atc", Image: cmp.Or(cfg.Image, "ghcr.io/yokecd/atc") + ":" + cfg.Version, ImagePullPolicy: cmp.Or(cfg.ImagePullPolicy, corev1.PullIfNotPresent), - Env: []corev1.EnvVar{ - {Name: "PORT", Value: strconv.Itoa(cfg.Port)}, - {Name: "TLS_CA_CERT", Value: "/conf/tls/ca.crt"}, - {Name: "TLS_SERVER_CERT", Value: "/conf/tls/server.crt"}, - {Name: "TLS_SERVER_KEY", Value: "/conf/tls/server.key"}, - {Name: "SVC_NAME", Value: svc.Name}, - {Name: "SVC_NAMESPACE", Value: svc.Namespace}, - {Name: "SVC_PORT", Value: strconv.Itoa(int(svc.Spec.Ports[0].Port))}, - {Name: "DOCKER_CONFIG_SECRET_NAME", Value: cfg.DockerConfigSecretName}, - {Name: "LOG_FORMAT", Value: cfg.LogFormat}, - {Name: "VERBOSE", Value: strconv.FormatBool(cfg.Verbose)}, - }, + Env: func() []corev1.EnvVar { + env := []corev1.EnvVar{ + {Name: "PORT", Value: strconv.Itoa(cfg.Port)}, + {Name: "TLS_CA_CERT", Value: "/conf/tls/ca.crt"}, + {Name: "TLS_SERVER_CERT", Value: "/conf/tls/server.crt"}, + {Name: "TLS_SERVER_KEY", Value: "/conf/tls/server.key"}, + {Name: "SVC_NAME", Value: svc.Name}, + {Name: "SVC_NAMESPACE", Value: svc.Namespace}, + {Name: "SVC_PORT", Value: strconv.Itoa(int(svc.Spec.Ports[0].Port))}, + {Name: "DOCKER_CONFIG_SECRET_NAME", Value: cfg.DockerConfigSecretName}, + {Name: "LOG_FORMAT", Value: cfg.LogFormat}, + {Name: "VERBOSE", Value: strconv.FormatBool(cfg.Verbose)}, + } + if cfg.AirwayValidationWebhookTimeout > 0 { + env = append(env, corev1.EnvVar{ + Name: "AIRWAY_VALIDATION_WEBHOOK_TIMEOUT", + Value: strconv.Itoa(cfg.AirwayValidationWebhookTimeout), + }) + } + if cfg.ResourceValidationWebhookTimeout > 0 { + env = append(env, corev1.EnvVar{ + Name: "RESOURCE_VALIDATION_WEBHOOK_TIMEOUT", + Value: strconv.Itoa(cfg.ResourceValidationWebhookTimeout), + }) + } + if cfg.ExternalResourceValidationWebhookTimeout > 0 { + env = append(env, corev1.EnvVar{ + Name: "EXTERNAL_RESOURCE_VALIDATION_WEBHOOK_TIMEOUT", + Value: strconv.Itoa(cfg.ExternalResourceValidationWebhookTimeout), + }) + } + return env + }(), VolumeMounts: []corev1.VolumeMount{ { Name: "tls-secrets", diff --git a/cmd/atc/config.go b/cmd/atc/config.go index 1fe2a120..e4bf10a5 100644 --- a/cmd/atc/config.go +++ b/cmd/atc/config.go @@ -20,6 +20,10 @@ type Config struct { Verbose bool + AirwayValidationWebhookTimeout int32 + ResourceValidationWebhookTimeout int32 + ExternalResourceValidationWebhookTimeout int32 + TLS TLSConfig } @@ -55,6 +59,10 @@ func LoadConfig() (*Config, error) { conf.Var(parser, &cfg.Verbose, "VERBOSE") + conf.Var(parser, &cfg.AirwayValidationWebhookTimeout, "AIRWAY_VALIDATION_WEBHOOK_TIMEOUT") + conf.Var(parser, &cfg.ResourceValidationWebhookTimeout, "RESOURCE_VALIDATION_WEBHOOK_TIMEOUT") + conf.Var(parser, &cfg.ExternalResourceValidationWebhookTimeout, "EXTERNAL_RESOURCE_VALIDATION_WEBHOOK_TIMEOUT") + if err := parser.Parse(); err != nil { return nil, err } diff --git a/cmd/atc/main.go b/cmd/atc/main.go index aa762e42..8fa55ffc 100644 --- a/cmd/atc/main.go +++ b/cmd/atc/main.go @@ -117,7 +117,7 @@ func run() (err error) { airwayGK := schema.GroupKind{Group: "yoke.cd", Kind: "Airway"} - reconciler, teardown := atc.GetReconciler(cfg.Service, moduleCache, controllers, eventDispatcher, cfg.Concurrency) + reconciler, teardown := atc.GetReconciler(cfg.Service, moduleCache, controllers, eventDispatcher, cfg.Concurrency, cfg.AirwayValidationWebhookTimeout) defer teardown() controller, err := ctrl.NewController(ctx, ctrl.Params{ diff --git a/cmd/atc/resources.go b/cmd/atc/resources.go index 960ecfea..161d80ec 100644 --- a/cmd/atc/resources.go +++ b/cmd/atc/resources.go @@ -92,6 +92,30 @@ func ApplyResources(ctx context.Context, client *k8s.Client, cfg *Config) error return fmt.Errorf("failed to apply airway crd: %w", err) } + // Get timeout value for airway validation webhook, defaulting to 10 seconds if not configured + airwayTimeoutSeconds := func() *int32 { + if cfg.AirwayValidationWebhookTimeout > 0 { + return ptr.To(cfg.AirwayValidationWebhookTimeout) + } + return ptr.To[int32](10) + }() + + // Get timeout value for resource validation webhook (event dispatching), defaulting to 5 seconds if not configured + resourceTimeoutSeconds := func() *int32 { + if cfg.ResourceValidationWebhookTimeout > 0 { + return ptr.To(cfg.ResourceValidationWebhookTimeout) + } + return ptr.To[int32](5) + }() + + // Get timeout value for external resource validation webhook, defaulting to 30 seconds if not configured + externalResourceTimeoutSeconds := func() *int32 { + if cfg.ExternalResourceValidationWebhookTimeout > 0 { + return ptr.To(cfg.ExternalResourceValidationWebhookTimeout) + } + return ptr.To[int32](30) + }() + airwayValidation := &admissionregistrationv1.ValidatingWebhookConfiguration{ TypeMeta: metav1.TypeMeta{ APIVersion: admissionregistrationv1.SchemeGroupVersion.Identifier(), @@ -114,6 +138,7 @@ func ApplyResources(ctx context.Context, client *k8s.Client, cfg *Config) error }, SideEffects: ptr.To(admissionregistrationv1.SideEffectClassNone), AdmissionReviewVersions: []string{"v1"}, + TimeoutSeconds: airwayTimeoutSeconds, Rules: []admissionregistrationv1.RuleWithOperations{ { Operations: []admissionregistrationv1.OperationType{ @@ -156,6 +181,7 @@ func ApplyResources(ctx context.Context, client *k8s.Client, cfg *Config) error AdmissionReviewVersions: []string{"v1"}, FailurePolicy: ptr.To(admissionregistrationv1.Ignore), MatchPolicy: ptr.To(admissionregistrationv1.Exact), + TimeoutSeconds: resourceTimeoutSeconds, MatchConditions: []admissionregistrationv1.MatchCondition{ { Name: "managed-by-atc", @@ -212,7 +238,7 @@ func ApplyResources(ctx context.Context, client *k8s.Client, cfg *Config) error AdmissionReviewVersions: []string{"v1"}, FailurePolicy: ptr.To(admissionregistrationv1.Ignore), MatchPolicy: ptr.To(admissionregistrationv1.Exact), - TimeoutSeconds: ptr.To[int32](1), + TimeoutSeconds: externalResourceTimeoutSeconds, MatchConditions: []admissionregistrationv1.MatchCondition{ { Name: "all", diff --git a/internal/atc/atc.go b/internal/atc/atc.go index 35dfc7f5..9817dcb1 100644 --- a/internal/atc/atc.go +++ b/internal/atc/atc.go @@ -68,14 +68,15 @@ func (controller Controller) FlightState(name, ns string) (FlightState, bool) { type ControllerCache = xsync.Map[string, Controller] -func GetReconciler(service ServiceDef, cache *wasm.ModuleCache, controllers *ControllerCache, dispatcher *EventDispatcher, concurrency int) (ctrl.HandleFunc, func()) { +func GetReconciler(service ServiceDef, cache *wasm.ModuleCache, controllers *ControllerCache, dispatcher *EventDispatcher, concurrency int, airwayValidationWebhookTimeout int32) (ctrl.HandleFunc, func()) { atc := atc{ - concurrency: concurrency, - service: service, - cleanups: map[string]func(){}, - moduleCache: cache, - controllers: controllers, - dispatcher: dispatcher, + concurrency: concurrency, + service: service, + cleanups: map[string]func(){}, + moduleCache: cache, + controllers: controllers, + dispatcher: dispatcher, + validationWebhookTimeout: airwayValidationWebhookTimeout, } return atc.Reconcile, atc.Teardown } @@ -88,6 +89,8 @@ type atc struct { service ServiceDef cleanups map[string]func() moduleCache *wasm.ModuleCache + + validationWebhookTimeout int32 } func (atc atc) Reconcile(ctx context.Context, event ctrl.Event) (result ctrl.Result, err error) { @@ -376,6 +379,14 @@ func (atc atc) Reconcile(ctx context.Context, event ctrl.Event) (result ctrl.Res ctrl.Client(ctx).Mapper.Reset() + // Get timeout value, defaulting to 10 seconds if not configured + timeoutSeconds := func() *int32 { + if atc.validationWebhookTimeout > 0 { + return ptr.To(atc.validationWebhookTimeout) + } + return ptr.To[int32](10) + }() + validationWebhook := admissionregistrationv1.ValidatingWebhookConfiguration{ TypeMeta: metav1.TypeMeta{ APIVersion: admissionregistrationv1.SchemeGroupVersion.Identifier(), @@ -406,6 +417,7 @@ func (atc atc) Reconcile(ctx context.Context, event ctrl.Event) (result ctrl.Res }, SideEffects: ptr.To(admissionregistrationv1.SideEffectClassNone), AdmissionReviewVersions: []string{"v1"}, + TimeoutSeconds: timeoutSeconds, Rules: []admissionregistrationv1.RuleWithOperations{ { Operations: []admissionregistrationv1.OperationType{