diff --git a/.earthly/configuration/templates/settings.yaml b/.earthly/configuration/templates/settings.yaml index 97eedaae4..9a7330bda 100644 --- a/.earthly/configuration/templates/settings.yaml +++ b/.earthly/configuration/templates/settings.yaml @@ -57,7 +57,11 @@ spec: stacks: - '*' key: opentelemetry.metrics.dsn + {{- if .Values.v2 }} + value: grpc://opentelemetry-collector.monitoring.svc.cluster.local:4317?insecure=true + {{- else }} value: grpc://otel-collector-opentelemetry-collector.formance.svc.cluster.local:4317?insecure=true + {{- end }} --- apiVersion: formance.com/v1beta1 kind: Settings @@ -67,7 +71,11 @@ spec: stacks: - '*' key: opentelemetry.traces.dsn + {{- if .Values.v2 }} + value: grpc://opentelemetry-collector.monitoring.svc.cluster.local:4317?insecure=true + {{- else }} value: grpc://otel-collector-opentelemetry-collector.formance.svc.cluster.local:4317?insecure=true + {{- end }} --- apiVersion: formance.com/v1beta1 kind: Settings @@ -97,4 +105,36 @@ spec: stacks: - '*' key: "modules.*.grace-period" - value: "5s" \ No newline at end of file + value: "5s" +{{- if .Values.v2 }} +--- +apiVersion: formance.com/v1beta1 +kind: Settings +metadata: + name: rewrite-ghcr-registry +spec: + key: 'registries."ghcr.io".endpoint' + stacks: + - '*' + value: {{ .Values.ghcrRegistry }}?pullSecret=zot +--- +apiVersion: formance.com/v1beta1 +kind: Settings +metadata: + name: gateway-ingress-annotations +spec: + key: 'gateway.ingress.annotations' + stacks: + - '*' + value: 'cert-manager.io/cluster-issuer=zerossl' +--- +apiVersion: formance.com/v1beta1 +kind: Settings +metadata: + name: gateway-ingress-tls +spec: + key: 'gateway.ingress.tls.enabled' + stacks: + - '*' + value: 'true' +{{- end }} \ No newline at end of file diff --git a/Earthfile b/Earthfile index ad5ac1594..10d2222da 100644 --- a/Earthfile +++ b/Earthfile @@ -1,6 +1,7 @@ VERSION 0.8 -IMPORT github.com/formancehq/earthly:tags/v0.19.1 AS core +ARG core=github.com/formancehq/earthly:tags/v0.19.1 +IMPORT $core AS core FROM core+base-image @@ -61,21 +62,37 @@ deploy: # --wait \ # --create-namespace ./base RUN helm dependency update ./operator - RUN --no-cache helm upgrade --install --namespace formance-system --install formance-operator \ + + ARG FORMANCE_DEV_CLUSTER_V2=no + LET ADDITIONAL_ARGS="" + IF [ "$FORMANCE_DEV_CLUSTER_V2" == "yes" ] + SET ADDITIONAL_ARGS="$ADDITIONAL_ARGS --set imagePullSecrets[0].name=zot" + SET ADDITIONAL_ARGS="$ADDITIONAL_ARGS --set image.repository=$REPOSITORY/formancehq/operator" + END + + ARG --required REPOSITORY= + RUN --no-cache helm upgrade --install --namespace formance --install formance-operator \ --wait \ + --debug \ --create-namespace \ --set image.tag=$tag \ --set operator.licence.token=$LICENCE_TOKEN \ --set operator.licence.issuer=$LICENCE_ISSUER ./operator \ - --set operator.dev=true + --set operator.dev=true $ADDITIONAL_ARGS WORKDIR / COPY .earthly .earthly WORKDIR .earthly RUN kubectl get versions default || kubectl apply -f k8s-versions.yaml ARG user + + SET ADDITIONAL_ARGS="" + IF [ "$FORMANCE_DEV_CLUSTER_V2" == "yes" ] + SET ADDITIONAL_ARGS="$ADDITIONAL_ARGS --set v2=true" + SET ADDITIONAL_ARGS="$ADDITIONAL_ARGS --set ghcrRegistry=$REPOSITORY" + END RUN --secret tld helm upgrade --install operator-configuration ./configuration \ - --namespace formance-system \ - --set gateway.fallback=https://console.$user.$tld + --namespace formance \ + --set gateway.fallback=https://console.$user.$tld $ADDITIONAL_ARGS deploy-staging: FROM --pass-args core+base-argocd diff --git a/api/formance.com/v1beta1/benthos_types.go b/api/formance.com/v1beta1/benthos_types.go index 2a7f53ce0..084907242 100644 --- a/api/formance.com/v1beta1/benthos_types.go +++ b/api/formance.com/v1beta1/benthos_types.go @@ -37,7 +37,8 @@ type BenthosSpec struct { //+optional Batching *Batching `json:"batching,omitempty"` //+optional - InitContainers []corev1.Container `json:"initContainers"` + InitContainers []corev1.Container `json:"initContainers"` + ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` } type BenthosStatus struct { diff --git a/api/formance.com/v1beta1/stargate_types.go b/api/formance.com/v1beta1/stargate_types.go index 8d537347e..600b81c59 100644 --- a/api/formance.com/v1beta1/stargate_types.go +++ b/api/formance.com/v1beta1/stargate_types.go @@ -35,11 +35,13 @@ type StargateTLSConfig struct { type StargateSpec struct { ModuleProperties `json:",inline"` StackDependency `json:",inline"` - ServerURL string `json:"serverURL"` - OrganizationID string `json:"organizationID"` - StackID string `json:"stackID"` - Auth StargateAuthSpec `json:"auth"` - TLS StargateTLSConfig `json:"tls"` + ServerURL string `json:"serverURL"` + OrganizationID string `json:"organizationID"` + StackID string `json:"stackID"` + Auth StargateAuthSpec `json:"auth"` + + //+optional + TLS StargateTLSConfig `json:"tls"` } // StargateStatus defines the observed state of Stargate diff --git a/api/formance.com/v1beta1/zz_generated.deepcopy.go b/api/formance.com/v1beta1/zz_generated.deepcopy.go index 779aa0592..df8b1d60f 100644 --- a/api/formance.com/v1beta1/zz_generated.deepcopy.go +++ b/api/formance.com/v1beta1/zz_generated.deepcopy.go @@ -447,6 +447,11 @@ func (in *BenthosSpec) DeepCopyInto(out *BenthosSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]v1.LocalObjectReference, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BenthosSpec. diff --git a/config/crd/bases/formance.com_benthos.yaml b/config/crd/bases/formance.com_benthos.yaml index a0fbc8d6f..207c3c4d0 100644 --- a/config/crd/bases/formance.com_benthos.yaml +++ b/config/crd/bases/formance.com_benthos.yaml @@ -76,6 +76,21 @@ spec: Allow to enable dev mode on the module Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) type: boolean + imagePullSecrets: + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + type: array initContainers: items: description: A single application container that you want to run diff --git a/config/crd/bases/formance.com_stargates.yaml b/config/crd/bases/formance.com_stargates.yaml index 1e2a1c04a..ba3968b9e 100644 --- a/config/crd/bases/formance.com_stargates.yaml +++ b/config/crd/bases/formance.com_stargates.yaml @@ -105,7 +105,6 @@ spec: - organizationID - serverURL - stackID - - tls type: object status: description: StargateStatus defines the observed state of Stargate diff --git a/docs/09-Configuration reference/01-Settings.md b/docs/09-Configuration reference/01-Settings.md index 0d3d1dffc..4db5ce3e9 100644 --- a/docs/09-Configuration reference/01-Settings.md +++ b/docs/09-Configuration reference/01-Settings.md @@ -9,7 +9,7 @@ While we have some basic types (string, number, bool ...), we also have some com ## Available settings | Key | Type | Example | Description | -|------------------------------------------------------------------------------------------|--------|---------------------------------------------------------| ------------------------------------------------------------------------------------------------------------------------------ | +|------------------------------------------------------------------------------------------|-------- |-----------------------------------------------------------| ------------------------------------------------------------------------------------------------------------------------------ | | aws.service-account | string | | AWS Role | | postgres.``.uri | URI | | Postgres database configuration | | elasticsearch.dsn | URI | | Elasticsearch connection URI | @@ -42,7 +42,7 @@ While we have some basic types (string, number, bool ...), we also have some com | jobs.``.spec.template.annotations | Map | firstannotations=X, anotherannotations=Y | Configure the annotations on specific jobs'modules | | jobs.``.init-containers.``.run-as | Map | user=X, group=X | Configure the security context for init containers in jobs by specifying the user and group IDs to run as | | jobs.``.containers.``.run-as | Map | user=X, group=X | Configure the security context for containers in jobs by specifying the user and group IDs to run as | -| registries.``.endpoint | string | | Specify a custom endpoint for a specific docker repository | +| registries.``.endpoint | string | example.com?pullSecret=foo | Specify a custom endpoint for a specific docker repository | | registries.``.images.``.rewrite | string | formancehq/example | Allow to rewrite the image path | | search.batching | Map | period=1s, count=10 | Override default batching parameters | | services.``.annotations | Map | | Allow to specify custom annotations to apply on created k8s services | diff --git a/docs/09-Configuration reference/02-Custom Resource Definitions.md b/docs/09-Configuration reference/02-Custom Resource Definitions.md index f50502fb7..abc15e1a9 100644 --- a/docs/09-Configuration reference/02-Custom Resource Definitions.md +++ b/docs/09-Configuration reference/02-Custom Resource Definitions.md @@ -1760,6 +1760,7 @@ Benthos is the Schema for the benthos API | `resourceRequirements` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#resourcerequirements-v1-core)_ | | | | | `batching` _[Batching](#batching)_ | | | | | `initContainers` _[Container](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#container-v1-core) array_ | | | | +| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#localobjectreference-v1-core) array_ | | | | ###### Batching diff --git a/go.mod b/go.mod index 61e0ec49d..1ee7dec53 100644 --- a/go.mod +++ b/go.mod @@ -32,7 +32,7 @@ require ( require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.8.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -59,7 +59,6 @@ require ( github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/spf13/pflag v1.0.6 // indirect - go.uber.org/mock v0.5.0 go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect diff --git a/go.sum b/go.sum index 03b7ce6d7..f7dd58ebc 100644 --- a/go.sum +++ b/go.sum @@ -117,8 +117,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= -go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_benthos.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_benthos.formance.com.yaml index a4a746f85..9e6c0059d 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_benthos.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_benthos.formance.com.yaml @@ -76,6 +76,21 @@ spec: Allow to enable dev mode on the module Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) type: boolean + imagePullSecrets: + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + type: array initContainers: items: description: A single application container that you want to run diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_stargates.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_stargates.formance.com.yaml index be7ab0efa..de0c5daff 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_stargates.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_stargates.formance.com.yaml @@ -105,7 +105,6 @@ spec: - organizationID - serverURL - stackID - - tls type: object status: description: StargateStatus defines the observed state of Stargate diff --git a/internal/resources/auths/deployment.go b/internal/resources/auths/deployment.go index 229d4824d..937ed8845 100644 --- a/internal/resources/auths/deployment.go +++ b/internal/resources/auths/deployment.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "github.com/formancehq/operator/internal/resources/registries" "github.com/formancehq/go-libs/v2/collectionutils" "github.com/formancehq/operator/api/formance.com/v1beta1" @@ -30,7 +31,7 @@ func HashFromHash(o ...string) string { } func createDeployment(ctx Context, stack *v1beta1.Stack, auth *v1beta1.Auth, database *v1beta1.Database, - configMap *corev1.ConfigMap, image string, version string, clients []*v1beta1.AuthClient) error { + configMap *corev1.ConfigMap, imageConfiguration *registries.ImageConfiguration, version string, clients []*v1beta1.AuthClient) error { annotations := map[string]string{ "config-hash": HashFromConfigMaps(configMap), } @@ -150,11 +151,12 @@ func createDeployment(ctx Context, stack *v1beta1.Stack, auth *v1beta1.Auth, dat Annotations: annotations, }, Spec: corev1.PodSpec{ + ImagePullSecrets: imageConfiguration.PullSecrets, Containers: []corev1.Container{{ Name: "auth", Args: []string{"serve"}, Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), VolumeMounts: []corev1.VolumeMount{ NewVolumeMount("config", "/config", true), }, diff --git a/internal/resources/auths/init.go b/internal/resources/auths/init.go index 1e9c08fac..00da7f708 100644 --- a/internal/resources/auths/init.go +++ b/internal/resources/auths/init.go @@ -17,14 +17,13 @@ limitations under the License. package auths import ( + "github.com/davecgh/go-spew/spew" . "github.com/formancehq/go-libs/v2/collectionutils" "github.com/formancehq/operator/api/formance.com/v1beta1" . "github.com/formancehq/operator/internal/core" "github.com/formancehq/operator/internal/resources/databases" "github.com/formancehq/operator/internal/resources/gatewayhttpapis" - "github.com/formancehq/operator/internal/resources/jobs" "github.com/formancehq/operator/internal/resources/registries" - "github.com/formancehq/operator/internal/resources/settings" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" @@ -79,26 +78,14 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, auth *v1beta1.Auth, version st return NewPendingError().WithMessage("database is not ready") } - image, err := registries.GetImage(ctx, stack, "auth", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "auth", version) if err != nil { - return errors.Wrap(err, "resolving image") + return errors.Wrap(err, "resolving image configuration") } + spew.Dump(imageConfiguration) if IsGreaterOrEqual(version, "v2.0.0-rc.5") && databases.GetSavedModuleVersion(database) != version { - serviceAccountName, err := settings.GetAWSServiceAccount(ctx, stack.Name) - if err != nil { - return errors.Wrap(err, "getting service account name") - } - - migrateContainer, err := databases.MigrateDatabaseContainer(ctx, stack, image, database) - if err != nil { - return errors.Wrap(err, "creating migrate container") - } - - if err := jobs.Handle(ctx, auth, "migrate", - migrateContainer, - jobs.WithServiceAccount(serviceAccountName), - ); err != nil { + if err := databases.Migrate(ctx, stack, auth, imageConfiguration, database); err != nil { return err } @@ -107,7 +94,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, auth *v1beta1.Auth, version st } } - if err := createDeployment(ctx, stack, auth, database, configMap, image, version, authClients); err != nil { + if err := createDeployment(ctx, stack, auth, database, configMap, imageConfiguration, version, authClients); err != nil { return errors.Wrap(err, "creating deployment") } diff --git a/internal/resources/benthos/controller.go b/internal/resources/benthos/controller.go index 9455afad6..fc2329f4b 100644 --- a/internal/resources/benthos/controller.go +++ b/internal/resources/benthos/controller.go @@ -320,10 +320,11 @@ func createDeployment(ctx Context, stack *v1beta1.Stack, b *v1beta1.Benthos) err Annotations: podAnnotations, }, Spec: corev1.PodSpec{ - InitContainers: b.Spec.InitContainers, + ImagePullSecrets: append(benthosImage.PullSecrets, b.Spec.ImagePullSecrets...), + InitContainers: b.Spec.InitContainers, Containers: []corev1.Container{{ Name: "benthos", - Image: benthosImage, + Image: benthosImage.GetFullImageName(), Env: env, Command: cmd, Ports: []corev1.ContainerPort{{ diff --git a/internal/resources/brokerconsumers/controller.go b/internal/resources/brokerconsumers/controller.go index a6bbe2430..34bf2bcf1 100644 --- a/internal/resources/brokerconsumers/controller.go +++ b/internal/resources/brokerconsumers/controller.go @@ -187,7 +187,7 @@ func createServiceNatsConsumer(ctx core.Context, stack *v1beta1.Stack, consumer } err = jobs.Handle(ctx, consumer, "cc-"+service, corev1.Container{ - Image: natsBoxImage, + Image: natsBoxImage.GetFullImageName(), Name: "create-consumer", Args: core.ShellScript(script), Env: []corev1.EnvVar{ @@ -196,7 +196,9 @@ func createServiceNatsConsumer(ctx core.Context, stack *v1beta1.Stack, consumer core.Env("NAME", consumer.Spec.QueriedBy), core.Env("SERVICE", service), }, - }) + }, + jobs.WithImagePullSecrets(natsBoxImage.PullSecrets), + ) condition := v1beta1.NewCondition(ConditionTypeNatsServiceConsumerCreated, consumer.Generation). SetReason(service) @@ -243,7 +245,7 @@ func createStackNatsConsumer(ctx core.Context, stack *v1beta1.Stack, consumer *v } err = jobs.Handle(ctx, consumer, "create-consumer", corev1.Container{ - Image: natsBoxImage, + Image: natsBoxImage.GetFullImageName(), Name: "create-consumer", Args: core.ShellScript(script), Env: []corev1.EnvVar{ @@ -257,7 +259,9 @@ func createStackNatsConsumer(ctx core.Context, stack *v1beta1.Stack, consumer *v }), " ", )), }, - }) + }, + jobs.WithImagePullSecrets(natsBoxImage.PullSecrets), + ) if err != nil { consumer.GetConditions().AppendOrReplace(v1beta1.Condition{ Type: ConditionTypeNatsStackConsumerCreated, diff --git a/internal/resources/brokers/reconcile.go b/internal/resources/brokers/reconcile.go index 84775b1ac..6c1e4b8b5 100644 --- a/internal/resources/brokers/reconcile.go +++ b/internal/resources/brokers/reconcile.go @@ -120,7 +120,7 @@ func detectBrokerModeByCheckingExistentStreams(ctx core.Context, stack *v1beta1. hasLegacyStream := false if err := jobs.Handle(ctx, broker, "detect-mode", corev1.Container{ - Image: natsBoxImage, + Image: natsBoxImage.GetFullImageName(), Name: "detect-mode", Args: core.ShellScript(script), Env: []corev1.EnvVar{ @@ -155,6 +155,7 @@ func detectBrokerModeByCheckingExistentStreams(ctx core.Context, stack *v1beta1. } return false }), + jobs.WithImagePullSecrets(natsBoxImage.PullSecrets), ); err != nil { return false, err } @@ -197,14 +198,16 @@ func deleteBroker(ctx core.Context, broker *v1beta1.Broker) error { } return jobs.Handle(ctx, broker, "delete-streams", corev1.Container{ - Image: natsBoxImage, + Image: natsBoxImage.GetFullImageName(), Name: "delete-streams", Args: core.ShellScript(script), Env: []corev1.EnvVar{ core.Env("NATS_URI", fmt.Sprintf("nats://%s", broker.Status.URI.Host)), core.Env("STACK", broker.Spec.Stack), }, - }) + }, + jobs.WithImagePullSecrets(natsBoxImage.PullSecrets), + ) } func createOneStreamByStack(ctx core.Context, stack *v1beta1.Stack, broker *v1beta1.Broker, uri *v1beta1.URI) error { @@ -232,7 +235,7 @@ func createOneStreamByStack(ctx core.Context, stack *v1beta1.Stack, broker *v1be } return jobs.Handle(ctx, broker, "create-stream", corev1.Container{ - Image: natsBoxImage, + Image: natsBoxImage.GetFullImageName(), Name: "create-topic", Args: core.ShellScript(script), Env: []corev1.EnvVar{ @@ -245,7 +248,9 @@ func createOneStreamByStack(ctx core.Context, stack *v1beta1.Stack, broker *v1be return "1" }()), }, - }) + }, + jobs.WithImagePullSecrets(natsBoxImage.PullSecrets), + ) } func createOneStreamByTopic(ctx core.Context, stack *v1beta1.Stack, broker *v1beta1.Broker, brokerURI *v1beta1.URI) error { @@ -291,7 +296,7 @@ func createNatsTopic(ctx core.Context, stack *v1beta1.Stack, broker *v1beta1.Bro } return jobs.Handle(ctx, broker, "create-topic-"+topic.Spec.Service, corev1.Container{ - Image: natsBoxImage, + Image: natsBoxImage.GetFullImageName(), Name: "create-topic", Args: core.ShellScript(script), Env: []corev1.EnvVar{ @@ -305,5 +310,7 @@ func createNatsTopic(ctx core.Context, stack *v1beta1.Stack, broker *v1beta1.Bro return "1" }()), }, - }) + }, + jobs.WithImagePullSecrets(natsBoxImage.PullSecrets), + ) } diff --git a/internal/resources/caddy/caddy.go b/internal/resources/caddy/caddy.go index c6ab4bf3f..abb142b70 100644 --- a/internal/resources/caddy/caddy.go +++ b/internal/resources/caddy/caddy.go @@ -3,6 +3,7 @@ package caddy import ( "bytes" "fmt" + "github.com/formancehq/operator/internal/resources/registries" "strings" "text/template" @@ -18,7 +19,14 @@ import ( "k8s.io/apimachinery/pkg/types" ) -func DeploymentTemplate(ctx core.Context, stack *v1beta1.Stack, owner v1beta1.Object, caddyfile *v1.ConfigMap, image string, env []v1.EnvVar) (*appsv1.Deployment, error) { +func DeploymentTemplate( + ctx core.Context, + stack *v1beta1.Stack, + owner v1beta1.Object, + caddyfile *v1.ConfigMap, + imageConfiguration *registries.ImageConfiguration, + env []v1.EnvVar, +) (*appsv1.Deployment, error) { t := &appsv1.Deployment{} otlpEnv, err := settings.GetOTELEnvVars(ctx, stack.Name, core.LowerCamelCaseKind(ctx, owner), ",") @@ -52,6 +60,7 @@ func DeploymentTemplate(ctx core.Context, stack *v1beta1.Stack, owner v1beta1.Ob }, }, } + t.Spec.Template.Spec.ImagePullSecrets = imageConfiguration.PullSecrets t.Spec.Template.Spec.Containers = []v1.Container{ { Name: "gateway", @@ -61,7 +70,7 @@ func DeploymentTemplate(ctx core.Context, stack *v1beta1.Stack, owner v1beta1.Ob "--config", "/gateway/Caddyfile", "--adapter", "caddyfile", }, - Image: image, + Image: imageConfiguration.GetFullImageName(), Env: env, VolumeMounts: []v1.VolumeMount{ core.NewVolumeMount("caddyfile", "/gateway", true), diff --git a/internal/resources/databases/init.go b/internal/resources/databases/init.go index 7936116e5..6fef88c26 100644 --- a/internal/resources/databases/init.go +++ b/internal/resources/databases/init.go @@ -138,7 +138,7 @@ func Delete(ctx core.Context, database *v1beta1.Database) error { func handleDatabaseJob(ctx core.Context, stack *v1beta1.Stack, database *v1beta1.Database, name string, args ...string) error { - operatorUtilsImage, err := registries.GetImage(ctx, stack, "operator-utils", ctx.GetPlatform().UtilsVersion) + operatorUtilsImage, err := registries.GetFormanceImage(ctx, stack, "operator-utils", ctx.GetPlatform().UtilsVersion) if err != nil { return err } @@ -169,12 +169,13 @@ func handleDatabaseJob(ctx core.Context, stack *v1beta1.Stack, database *v1beta1 return jobs.Handle(ctx, database, name, v1.Container{ Name: name, - Image: operatorUtilsImage, + Image: operatorUtilsImage.GetFullImageName(), Args: args, Env: env, }, jobs.Mutator(core.WithAnnotations[*batchv1.Job](annotations)), jobs.WithServiceAccount(serviceAccountName), + jobs.WithImagePullSecrets(operatorUtilsImage.PullSecrets), ) } diff --git a/internal/resources/databases/migrate.go b/internal/resources/databases/migrate.go index 3239e856c..272cf6b7b 100644 --- a/internal/resources/databases/migrate.go +++ b/internal/resources/databases/migrate.go @@ -2,6 +2,9 @@ package databases import ( "fmt" + "github.com/formancehq/operator/internal/resources/registries" + "github.com/formancehq/operator/internal/resources/settings" + "github.com/pkg/errors" "github.com/formancehq/operator/api/formance.com/v1beta1" "github.com/formancehq/operator/internal/core" @@ -9,43 +12,35 @@ import ( v1 "k8s.io/api/core/v1" ) -type MigrationConfiguration struct { - Command []string - AdditionalEnv []v1.EnvVar -} - -func MigrateDatabaseContainer(ctx core.Context, stack *v1beta1.Stack, image string, database *v1beta1.Database, options ...func(m *MigrationConfiguration)) (v1.Container, error) { - m := &MigrationConfiguration{} - for _, option := range options { - option(m) - } - args := m.Command - if len(args) == 0 { - args = []string{"migrate"} - } +func Migrate( + ctx core.Context, + stack *v1beta1.Stack, + owner v1beta1.Dependent, + imageConfiguration *registries.ImageConfiguration, + database *v1beta1.Database, + options ...jobs.HandleJobOption, +) error { + args := []string{"migrate"} env, err := GetPostgresEnvVars(ctx, stack, database) if err != nil { - return v1.Container{}, err + return err } - if m.AdditionalEnv != nil { - env = append(env, m.AdditionalEnv...) + serviceAccountName, err := settings.GetAWSServiceAccount(ctx, stack.Name) + if err != nil { + return errors.Wrap(err, "getting service account name") } - return v1.Container{ + return jobs.Handle(ctx, owner, fmt.Sprintf("%s-migration", database.Spec.Service), v1.Container{ Name: "migrate", - Image: image, + Image: imageConfiguration.GetFullImageName(), Args: args, Env: env, - }, nil -} - -func Migrate(ctx core.Context, stack *v1beta1.Stack, image string, database *v1beta1.Database, options ...func(m *MigrationConfiguration)) error { - container, err := MigrateDatabaseContainer(ctx, stack, image, database, options...) - if err != nil { - return err - } - - return jobs.Handle(ctx, database, fmt.Sprintf("%s-migration", database.Name), container) + }, + append(options, + jobs.WithImagePullSecrets(imageConfiguration.PullSecrets), + jobs.WithServiceAccount(serviceAccountName), + )..., + ) } diff --git a/internal/resources/gateways/deployment.go b/internal/resources/gateways/deployment.go index 83ccc8ee8..e40c9271c 100644 --- a/internal/resources/gateways/deployment.go +++ b/internal/resources/gateways/deployment.go @@ -26,12 +26,12 @@ func createDeployment(ctx core.Context, stack *v1beta1.Stack, env = append(env, brokerEnvVar...) } - image, err := registries.GetImage(ctx, stack, "gateway", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "gateway", version) if err != nil { return err } - caddyTpl, err := caddy.DeploymentTemplate(ctx, stack, gateway, caddyfileConfigMap, image, env) + caddyTpl, err := caddy.DeploymentTemplate(ctx, stack, gateway, caddyfileConfigMap, imageConfiguration, env) if err != nil { return err } diff --git a/internal/resources/jobs/job.go b/internal/resources/jobs/job.go index 04e5e8898..8ddefc474 100644 --- a/internal/resources/jobs/job.go +++ b/internal/resources/jobs/job.go @@ -47,6 +47,13 @@ func WithServiceAccount(serviceAccountName string) HandleJobOption { }) } +func WithEnvVars(envVars ...v1.EnvVar) HandleJobOption { + return Mutator(func(t *batchv1.Job) error { + t.Spec.Template.Spec.Containers[0].Env = append(t.Spec.Template.Spec.Containers[0].Env, envVars...) + return nil + }) +} + func withRunAs(ctx core.Context, owner v1beta1.Dependent) HandleJobOption { return Mutator(func(job *batchv1.Job) error { kind := strings.ToLower(owner.GetObjectKind().GroupVersionKind().Kind) @@ -90,6 +97,13 @@ func WithValidator(v func(job *batchv1.Job) bool) HandleJobOption { } } +func WithImagePullSecrets(imagePullSecrets []v1.LocalObjectReference) HandleJobOption { + return Mutator(func(t *batchv1.Job) error { + t.Spec.Template.Spec.ImagePullSecrets = append(t.Spec.Template.Spec.ImagePullSecrets, imagePullSecrets...) + return nil + }) +} + var defaultOptions = []HandleJobOption{ WithValidator(func(job *batchv1.Job) bool { return job.Status.Succeeded > 0 diff --git a/internal/resources/ledgers/deployments.go b/internal/resources/ledgers/deployments.go index c7c0b147b..fde656202 100644 --- a/internal/resources/ledgers/deployments.go +++ b/internal/resources/ledgers/deployments.go @@ -16,14 +16,12 @@ import ( "github.com/formancehq/operator/internal/resources/applications" "github.com/formancehq/operator/internal/resources/databases" "github.com/formancehq/operator/internal/resources/gateways" - "github.com/formancehq/operator/internal/resources/jobs" "github.com/formancehq/operator/internal/resources/registries" "github.com/formancehq/operator/internal/resources/services" "github.com/formancehq/operator/internal/resources/settings" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" ) const ( @@ -74,17 +72,17 @@ func hasDeploymentStrategyChanged(ctx core.Context, stack *v1beta1.Stack, ledger } } -func installLedger(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, database *v1beta1.Database, image string, version string, isV2 bool) (err error) { +func installLedger(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, database *v1beta1.Database, imageConfiguration *registries.ImageConfiguration, version string, isV2 bool) (err error) { if !semver.IsValid(version) || semver.Compare(version, "v2.2.0-alpha") > 0 { if err := uninstallLedgerMonoWriterMultipleReader(ctx, stack); err != nil { return err } - if err := installLedgerStateless(ctx, stack, ledger, database, image); err != nil { + if err := installLedgerStateless(ctx, stack, ledger, database, imageConfiguration); err != nil { return err } if !semver.IsValid(version) || semver.Compare(version, "v2.3.0-alpha") > 0 { - if err := installLedgerWorker(ctx, stack, ledger, database, image); err != nil { + if err := installLedgerWorker(ctx, stack, ledger, database, imageConfiguration); err != nil { return err } } @@ -106,22 +104,28 @@ func installLedger(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledge switch deploymentStrategySettings { case v1beta1.DeploymentStrategySingle: - return installLedgerSingleInstance(ctx, stack, ledger, database, image, isV2) + return installLedgerSingleInstance(ctx, stack, ledger, database, imageConfiguration, isV2) case v1beta1.DeploymentStrategyMonoWriterMultipleReader: - return installLedgerMonoWriterMultipleReader(ctx, stack, ledger, database, image, isV2) + return installLedgerMonoWriterMultipleReader(ctx, stack, ledger, database, imageConfiguration, isV2) default: return fmt.Errorf("unknown deployment strategy %s", deploymentStrategySettings) } } -func installLedgerSingleInstance(ctx core.Context, stack *v1beta1.Stack, - ledger *v1beta1.Ledger, database *v1beta1.Database, image string, v2 bool) error { +func installLedgerSingleInstance( + ctx core.Context, + stack *v1beta1.Stack, + ledger *v1beta1.Ledger, + database *v1beta1.Database, + imageConfiguration *registries.ImageConfiguration, + v2 bool, +) error { container, err := createLedgerContainerFull(ctx, stack, v2) if err != nil { return err } - err = setCommonAPIContainerConfiguration(ctx, stack, ledger, image, database, container, v2) + err = setCommonAPIContainerConfiguration(ctx, stack, ledger, imageConfiguration, database, container, v2) if err != nil { return err } @@ -150,8 +154,7 @@ func installLedgerSingleInstance(ctx core.Context, stack *v1beta1.Stack, return nil } -func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, - ledger *v1beta1.Ledger, database *v1beta1.Database, version string) error { +func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, database *v1beta1.Database, imageConfiguration *registries.ImageConfiguration, ) error { container := corev1.Container{ Name: "ledger", } @@ -233,7 +236,7 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, container.Env = append(container.Env, core.Env("BULK_MAX_SIZE", fmt.Sprint(*bulkMaxSize))) } - err = setCommonAPIContainerConfiguration(ctx, stack, ledger, version, database, &container, true) + err = setCommonAPIContainerConfiguration(ctx, stack, ledger, imageConfiguration, database, &container, true) if err != nil { return err } @@ -262,14 +265,13 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, Install(ctx) } -func installLedgerWorker(ctx core.Context, stack *v1beta1.Stack, - ledger *v1beta1.Ledger, database *v1beta1.Database, image string) error { +func installLedgerWorker(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, database *v1beta1.Database, imageConfiguration *registries.ImageConfiguration) error { container := corev1.Container{ Name: "ledger-worker", Args: []string{"worker"}, } - err := setCommonContainerConfiguration(ctx, stack, ledger, image, database, &container, true) + err := setCommonContainerConfiguration(ctx, stack, ledger, imageConfiguration, database, &container, true) if err != nil { return err } @@ -299,23 +301,10 @@ func installLedgerWorker(ctx core.Context, stack *v1beta1.Stack, Install(ctx) } -func getUpgradeContainer(ctx core.Context, stack *v1beta1.Stack, database *v1beta1.Database, image, version string) (corev1.Container, error) { - return databases.MigrateDatabaseContainer(ctx, stack, image, database, - func(m *databases.MigrationConfiguration) { - if core.IsLower(version, "v2.0.0-rc.6") { - m.Command = []string{"buckets", "upgrade-all"} - } - m.AdditionalEnv = []corev1.EnvVar{ - core.Env("STORAGE_POSTGRES_CONN_STRING", "$(POSTGRES_URI)"), - } - }, - ) -} - -func installLedgerMonoWriterMultipleReader(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, database *v1beta1.Database, image string, v2 bool) error { +func installLedgerMonoWriterMultipleReader(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, database *v1beta1.Database, imageConfiguration *registries.ImageConfiguration, v2 bool) error { createDeployment := func(name string, container corev1.Container, replicas uint64) error { - err := setCommonAPIContainerConfiguration(ctx, stack, ledger, image, database, &container, v2) + err := setCommonAPIContainerConfiguration(ctx, stack, ledger, imageConfiguration, database, &container, v2) if err != nil { return err } @@ -416,7 +405,7 @@ func createDeployment(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Le Install(ctx) } -func setCommonContainerConfiguration(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, image string, database *v1beta1.Database, container *corev1.Container, v2 bool) error { +func setCommonContainerConfiguration(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, imageConfiguration *registries.ImageConfiguration, database *v1beta1.Database, container *corev1.Container, v2 bool) error { prefix := "" if !v2 { @@ -436,7 +425,7 @@ func setCommonContainerConfiguration(ctx core.Context, stack *v1beta1.Stack, led } env = append(env, postgresEnvVar...) - container.Image = image + container.Image = imageConfiguration.GetFullImageName() container.Env = append(container.Env, env...) container.Env = append(container.Env, core.Env(fmt.Sprintf("%sSTORAGE_POSTGRES_CONN_STRING", prefix), fmt.Sprintf("$(%sPOSTGRES_URI)", prefix))) container.Env = append(container.Env, core.Env(fmt.Sprintf("%sSTORAGE_DRIVER", prefix), "postgres")) @@ -444,14 +433,14 @@ func setCommonContainerConfiguration(ctx core.Context, stack *v1beta1.Stack, led return nil } -func setCommonAPIContainerConfiguration(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, image string, database *v1beta1.Database, container *corev1.Container, v2 bool) error { +func setCommonAPIContainerConfiguration(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, imageConfiguration *registries.ImageConfiguration, database *v1beta1.Database, container *corev1.Container, v2 bool) error { prefix := "" if !v2 { prefix = "NUMARY_" } - if err := setCommonContainerConfiguration(ctx, stack, ledger, image, database, container, v2); err != nil { + if err := setCommonContainerConfiguration(ctx, stack, ledger, imageConfiguration, database, container, v2); err != nil { return err } @@ -568,7 +557,7 @@ func createGatewayDeployment(ctx core.Context, stack *v1beta1.Stack, ledger *v1b env := make([]corev1.EnvVar, 0) env = append(env, core.GetDevEnvVars(stack, ledger)...) - caddyImage, err := registries.GetCaddyImage(ctx, stack, "2.7.6-alpine") + caddyImage, err := registries.GetCaddyImage(ctx, stack) if err != nil { return err } @@ -582,35 +571,4 @@ func createGatewayDeployment(ctx core.Context, stack *v1beta1.Stack, ledger *v1b return applications. New(ledger, tpl). Install(ctx) -} - -func migrate(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, database *v1beta1.Database, image, version string) error { - serviceAccountName, err := settings.GetAWSServiceAccount(ctx, stack.Name) - if err != nil { - return err - } - - upgradeContainer, err := getUpgradeContainer(ctx, stack, database, image, version) - if err != nil { - return err - } - - return jobs.Handle(ctx, ledger, "migrate-v2", upgradeContainer, - jobs.PreCreate(func() error { - list := &appsv1.DeploymentList{} - if err := ctx.GetClient().List(ctx, list, client.InNamespace(stack.Name)); err != nil { - return err - } - - for _, item := range list.Items { - if controller := metav1.GetControllerOf(&item); controller != nil && controller.UID == ledger.GetUID() { - if err := ctx.GetClient().Delete(ctx, &item); err != nil { - return err - } - } - } - return nil - }), - jobs.WithServiceAccount(serviceAccountName), - ) -} +} \ No newline at end of file diff --git a/internal/resources/ledgers/init.go b/internal/resources/ledgers/init.go index 790f78dcb..d9fca522d 100644 --- a/internal/resources/ledgers/init.go +++ b/internal/resources/ledgers/init.go @@ -19,6 +19,9 @@ package ledgers import ( _ "embed" "fmt" + "github.com/formancehq/operator/internal/resources/jobs" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/formancehq/operator/api/formance.com/v1beta1" . "github.com/formancehq/operator/internal/core" @@ -46,7 +49,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, versio return err } - image, err := registries.GetImage(ctx, stack, "ledger", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "ledger", version) if err != nil { return err } @@ -93,7 +96,37 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, versio } if isV2 && databases.GetSavedModuleVersion(database) != version { - err := migrate(ctx, stack, ledger, database, image, version) + err := databases.Migrate( + ctx, + stack, + ledger, + imageConfiguration, + database, + jobs.Mutator(func(t *batchv1.Job) error { + if IsLower(version, "v2.0.0-rc.6") { + t.Spec.Template.Spec.Containers[0].Command = []string{"buckets", "upgrade-all"} + } + t.Spec.Template.Spec.Containers[0].Env = append(t.Spec.Template.Spec.Containers[0].Env, Env("STORAGE_POSTGRES_CONN_STRING", "$(POSTGRES_URI)")) + + return nil + }), + jobs.PreCreate(func() error { + list := &appsv1.DeploymentList{} + if err := ctx.GetClient().List(ctx, list, client.InNamespace(stack.Name)); err != nil { + return err + } + + for _, item := range list.Items { + if controller := metav1.GetControllerOf(&item); controller != nil && controller.UID == ledger.GetUID() { + if err := ctx.GetClient().Delete(ctx, &item); err != nil { + return err + } + } + } + + return nil + }), + ) if err != nil { isV2_2 := !semver.IsValid(version) || semver.Compare(version, "v2.2.0-alpha") > 0 if !isV2_2 { @@ -101,7 +134,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, versio } if IsApplicationError(err) { // Start the ledger even if migrations are not terminated - return installLedger(ctx, stack, ledger, database, image, version, isV2) + return installLedger(ctx, stack, ledger, database, imageConfiguration, version, isV2) } return err @@ -111,7 +144,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, ledger *v1beta1.Ledger, versio } } - return installLedger(ctx, stack, ledger, database, image, version, isV2) + return installLedger(ctx, stack, ledger, database, imageConfiguration, version, isV2) } func init() { diff --git a/internal/resources/orchestrations/deployments.go b/internal/resources/orchestrations/deployments.go index 99de8c43f..ff660a4d4 100644 --- a/internal/resources/orchestrations/deployments.go +++ b/internal/resources/orchestrations/deployments.go @@ -2,6 +2,7 @@ package orchestrations import ( "fmt" + "github.com/formancehq/operator/internal/resources/registries" "strings" "github.com/formancehq/operator/internal/core" @@ -46,9 +47,15 @@ func createAuthClient(ctx Context, stack *v1beta1.Stack, orchestration *v1beta1. }) } -func createDeployment(ctx Context, stack *v1beta1.Stack, orchestration *v1beta1.Orchestration, - database *v1beta1.Database, client *v1beta1.AuthClient, - consumer *v1beta1.BrokerConsumer, image string) error { +func createDeployment( + ctx Context, + stack *v1beta1.Stack, + orchestration *v1beta1.Orchestration, + database *v1beta1.Database, + client *v1beta1.AuthClient, + consumer *v1beta1.BrokerConsumer, + imageConfiguration *registries.ImageConfiguration, +) error { env := make([]corev1.EnvVar, 0) otlpEnv, err := settings.GetOTELEnvVars(ctx, stack.Name, LowerCamelCaseKind(ctx, orchestration), " ") @@ -177,11 +184,12 @@ func createDeployment(ctx Context, stack *v1beta1.Stack, orchestration *v1beta1. Spec: appsv1.DeploymentSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ + ImagePullSecrets: imageConfiguration.PullSecrets, ServiceAccountName: serviceAccountName, Containers: []corev1.Container{{ Name: "api", Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), Ports: []corev1.ContainerPort{applications.StandardHTTPPort()}, LivenessProbe: applications.DefaultLiveness("http"), }}, diff --git a/internal/resources/orchestrations/init.go b/internal/resources/orchestrations/init.go index dc6cda43d..a9deef068 100644 --- a/internal/resources/orchestrations/init.go +++ b/internal/resources/orchestrations/init.go @@ -23,9 +23,7 @@ import ( "github.com/formancehq/operator/internal/resources/brokertopics" "github.com/formancehq/operator/internal/resources/databases" "github.com/formancehq/operator/internal/resources/gatewayhttpapis" - "github.com/formancehq/operator/internal/resources/jobs" "github.com/formancehq/operator/internal/resources/registries" - "github.com/formancehq/operator/internal/resources/settings" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" @@ -60,26 +58,14 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, o *v1beta1.Orchestration, vers return NewPendingError().WithMessage("database not ready") } - image, err := registries.GetImage(ctx, stack, "orchestration", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "orchestration", version) if err != nil { return errors.Wrap(err, "resolving image") } if IsGreaterOrEqual(version, "v2.0.0-rc.5") && databases.GetSavedModuleVersion(database) != version { - serviceAccountName, err := settings.GetAWSServiceAccount(ctx, stack.Name) - if err != nil { - return errors.Wrap(err, "getting service account name") - } - - migrateContainer, err := databases.MigrateDatabaseContainer(ctx, stack, image, database) - if err != nil { - return errors.Wrap(err, "creating migrate container") - } - if err := jobs.Handle(ctx, o, "migrate", - migrateContainer, - jobs.WithServiceAccount(serviceAccountName), - ); err != nil { + if err := databases.Migrate(ctx, stack, o, imageConfiguration, database); err != nil { return err } @@ -89,7 +75,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, o *v1beta1.Orchestration, vers } if consumer.Status.Ready { - if err := createDeployment(ctx, stack, o, database, authClient, consumer, image); err != nil { + if err := createDeployment(ctx, stack, o, database, authClient, consumer, imageConfiguration); err != nil { return err } } else { diff --git a/internal/resources/payments/deployments.go b/internal/resources/payments/deployments.go index 935977d69..625d90fb0 100644 --- a/internal/resources/payments/deployments.go +++ b/internal/resources/payments/deployments.go @@ -187,8 +187,14 @@ func uninstallPaymentsReadAndConnectors(ctx core.Context, stack *v1beta1.Stack) return nil } -func createFullDeployment(ctx core.Context, stack *v1beta1.Stack, - payments *v1beta1.Payments, database *v1beta1.Database, image string, v3 bool) error { +func createFullDeployment( + ctx core.Context, + stack *v1beta1.Stack, + payments *v1beta1.Payments, + database *v1beta1.Database, + imageConfiguration *registries.ImageConfiguration, + v3 bool, +) error { env, err := commonEnvVars(ctx, stack, payments, database) if err != nil { @@ -246,7 +252,7 @@ func createFullDeployment(ctx core.Context, stack *v1beta1.Stack, containerName = "payments-api" appOpts = applications.WithProbePath("/_healthcheck") - err := createWorkerDeployment(ctx, stack, payments, database, image, env, appOpts) + err := createWorkerDeployment(ctx, stack, payments, database, imageConfiguration, env, appOpts) if err != nil { return err } @@ -261,11 +267,12 @@ func createFullDeployment(ctx core.Context, stack *v1beta1.Stack, Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ ServiceAccountName: serviceAccountName, + ImagePullSecrets: imageConfiguration.PullSecrets, Containers: []v1.Container{{ Name: containerName, Args: []string{"serve"}, Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), LivenessProbe: applications.DefaultLiveness("http", appOpts), Ports: []v1.ContainerPort{applications.StandardHTTPPort()}, }}, @@ -283,15 +290,7 @@ func createFullDeployment(ctx core.Context, stack *v1beta1.Stack, return nil } -func createWorkerDeployment( - ctx core.Context, - stack *v1beta1.Stack, - payments *v1beta1.Payments, - database *v1beta1.Database, - image string, - env []v1.EnvVar, - appOpts applications.ProbeOpts, -) error { +func createWorkerDeployment(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.Payments, database *v1beta1.Database, imageConfiguration *registries.ImageConfiguration, env []v1.EnvVar, appOpts applications.ProbeOpts, ) error { serviceAccountName, err := settings.GetAWSServiceAccount(ctx, stack.Name) if err != nil { return err @@ -306,11 +305,12 @@ func createWorkerDeployment( Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ ServiceAccountName: serviceAccountName, + ImagePullSecrets: imageConfiguration.PullSecrets, Containers: []v1.Container{{ Name: "payments-worker", Args: []string{"worker"}, Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), LivenessProbe: applications.DefaultLiveness("http", appOpts), Ports: []v1.ContainerPort{applications.StandardHTTPPort()}, }}, @@ -328,7 +328,7 @@ func createWorkerDeployment( return nil } -func createReadDeployment(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.Payments, database *v1beta1.Database, image string) error { +func createReadDeployment(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.Payments, database *v1beta1.Database, imageConfiguration *registries.ImageConfiguration) error { env, err := commonEnvVars(ctx, stack, payments, database) if err != nil { @@ -355,11 +355,12 @@ func createReadDeployment(ctx core.Context, stack *v1beta1.Stack, payments *v1be Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ ServiceAccountName: serviceAccountName, + ImagePullSecrets: imageConfiguration.PullSecrets, Containers: []v1.Container{{ Name: "api", Args: []string{"api", "serve"}, Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), LivenessProbe: applications.DefaultLiveness("http", applications.WithProbePath("/_health")), Ports: []v1.ContainerPort{applications.StandardHTTPPort()}, }}, @@ -382,8 +383,7 @@ func createReadDeployment(ctx core.Context, stack *v1beta1.Stack, payments *v1be return nil } -func createConnectorsDeployment(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.Payments, - database *v1beta1.Database, image string) error { +func createConnectorsDeployment(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.Payments, database *v1beta1.Database, imageConfiguration *registries.ImageConfiguration) error { env, err := commonEnvVars(ctx, stack, payments, database) if err != nil { @@ -429,11 +429,12 @@ func createConnectorsDeployment(ctx core.Context, stack *v1beta1.Stack, payments Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ ServiceAccountName: serviceAccountName, + ImagePullSecrets: imageConfiguration.PullSecrets, Containers: []v1.Container{{ Name: "connectors", Args: []string{"connectors", "serve"}, Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), Ports: []v1.ContainerPort{applications.StandardHTTPPort()}, LivenessProbe: applications.DefaultLiveness("http", applications.WithProbePath("/_health")), @@ -471,7 +472,7 @@ func createGateway(ctx core.Context, stack *v1beta1.Stack, p *v1beta1.Payments) env = append(env, core.GetDevEnvVars(stack, p)...) - caddyImage, err := registries.GetCaddyImage(ctx, stack, "2.7.6-alpine") + caddyImage, err := registries.GetCaddyImage(ctx, stack) if err != nil { return err } diff --git a/internal/resources/payments/finalizer.go b/internal/resources/payments/finalizer.go index 20aa870f1..c7f9fc861 100644 --- a/internal/resources/payments/finalizer.go +++ b/internal/resources/payments/finalizer.go @@ -29,7 +29,7 @@ func Clean(ctx core.Context, t *v1beta1.Payments) error { return nil } - image, err := registries.GetImage(ctx, stack, "payments", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "payments", version) if err != nil { return err } @@ -45,6 +45,6 @@ func Clean(ctx core.Context, t *v1beta1.Payments) error { Env: append(env, core.Env("STACK", t.GetStack()), ), - Image: image, - }) + Image: imageConfiguration.GetFullImageName(), + }, jobs.WithImagePullSecrets(imageConfiguration.PullSecrets)) } diff --git a/internal/resources/payments/init.go b/internal/resources/payments/init.go index ca7861ade..82056c564 100644 --- a/internal/resources/payments/init.go +++ b/internal/resources/payments/init.go @@ -22,7 +22,6 @@ import ( "github.com/formancehq/operator/internal/resources/jobs" "github.com/formancehq/operator/internal/resources/registries" - "github.com/formancehq/operator/internal/resources/settings" "github.com/pkg/errors" batchv1 "k8s.io/api/batch/v1" @@ -53,7 +52,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, p *v1beta1.Payments, version s return NewPendingError().WithMessage("database not ready") } - image, err := registries.GetImage(ctx, stack, "payments", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "payments", version) if err != nil { return err } @@ -64,25 +63,8 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, p *v1beta1.Payments, version s return err } - serviceAccountName, err := settings.GetAWSServiceAccount(ctx, stack.Name) - if err != nil { - return err - } - - migrateContainer, err := databases.MigrateDatabaseContainer(ctx, stack, image, database, - func(m *databases.MigrationConfiguration) { - m.AdditionalEnv = []corev1.EnvVar{ - Env("CONFIG_ENCRYPTION_KEY", encryptionKey), - } - }, - ) - if err != nil { - return err - } - - if err := jobs.Handle(ctx, p, "migrate", - migrateContainer, - jobs.WithServiceAccount(serviceAccountName), + if err := databases.Migrate(ctx, stack, p, imageConfiguration, database, + jobs.WithEnvVars(Env("CONFIG_ENCRYPTION_KEY", encryptionKey)), ); err != nil { return err } @@ -95,16 +77,16 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, p *v1beta1.Payments, version s healthEndpoint := "_health" switch { case semver.IsValid(version) && semver.Compare(version, "v1.0.0-alpha") < 0: - if err := createFullDeployment(ctx, stack, p, database, image, false); err != nil { + if err := createFullDeployment(ctx, stack, p, database, imageConfiguration, false); err != nil { return err } case semver.IsValid(version) && semver.Compare(version, "v1.0.0-alpha") >= 0 && semver.Compare(version, "v3.0.0") < 0: - if err := createReadDeployment(ctx, stack, p, database, image); err != nil { + if err := createReadDeployment(ctx, stack, p, database, imageConfiguration); err != nil { return err } - if err := createConnectorsDeployment(ctx, stack, p, database, image); err != nil { + if err := createConnectorsDeployment(ctx, stack, p, database, imageConfiguration); err != nil { return err } if err := createGateway(ctx, stack, p); err != nil { @@ -116,7 +98,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, p *v1beta1.Payments, version s return err } - if err := createFullDeployment(ctx, stack, p, database, image, true); err != nil { + if err := createFullDeployment(ctx, stack, p, database, imageConfiguration, true); err != nil { return err } } diff --git a/internal/resources/reconciliations/deployments.go b/internal/resources/reconciliations/deployments.go index 19c3d4071..e42ee6c14 100644 --- a/internal/resources/reconciliations/deployments.go +++ b/internal/resources/reconciliations/deployments.go @@ -8,14 +8,21 @@ import ( "github.com/formancehq/operator/internal/resources/auths" "github.com/formancehq/operator/internal/resources/databases" "github.com/formancehq/operator/internal/resources/gateways" + "github.com/formancehq/operator/internal/resources/registries" "github.com/formancehq/operator/internal/resources/settings" appsv1 "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func createDeployment(ctx core.Context, stack *v1beta1.Stack, reconciliation *v1beta1.Reconciliation, - database *v1beta1.Database, authClient *v1beta1.AuthClient, image string) error { +func createDeployment( + ctx core.Context, + stack *v1beta1.Stack, + reconciliation *v1beta1.Reconciliation, + database *v1beta1.Database, + authClient *v1beta1.AuthClient, + imageConfiguration *registries.ImageConfiguration, +) error { env := make([]v1.EnvVar, 0) otlpEnv, err := settings.GetOTELEnvVars(ctx, stack.Name, core.LowerCamelCaseKind(ctx, reconciliation), " ") if err != nil { @@ -58,11 +65,12 @@ func createDeployment(ctx core.Context, stack *v1beta1.Stack, reconciliation *v1 Spec: appsv1.DeploymentSpec{ Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ + ImagePullSecrets: imageConfiguration.PullSecrets, ServiceAccountName: serviceAccountName, Containers: []v1.Container{{ Name: "reconciliation", Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), Ports: []v1.ContainerPort{applications.StandardHTTPPort()}, LivenessProbe: applications.DefaultLiveness("http"), }}, diff --git a/internal/resources/reconciliations/init.go b/internal/resources/reconciliations/init.go index 6c4fa62ec..b490b3e6b 100644 --- a/internal/resources/reconciliations/init.go +++ b/internal/resources/reconciliations/init.go @@ -22,9 +22,7 @@ import ( "github.com/formancehq/operator/internal/resources/authclients" "github.com/formancehq/operator/internal/resources/databases" "github.com/formancehq/operator/internal/resources/gatewayhttpapis" - "github.com/formancehq/operator/internal/resources/jobs" "github.com/formancehq/operator/internal/resources/registries" - "github.com/formancehq/operator/internal/resources/settings" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" @@ -48,26 +46,14 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, reconciliation *v1beta1.Reconc if database.Status.Ready { - image, err := registries.GetImage(ctx, stack, "reconciliation", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "reconciliation", version) if err != nil { return errors.Wrap(err, "resolving image") } if IsGreaterOrEqual(version, "v2.0.0-rc.5") && databases.GetSavedModuleVersion(database) != version { - serviceAccountName, err := settings.GetAWSServiceAccount(ctx, stack.Name) - if err != nil { - return errors.Wrap(err, "resolving service account") - } - - migrateContainer, err := databases.MigrateDatabaseContainer(ctx, stack, image, database) - if err != nil { - return errors.Wrap(err, "creating migration container") - } - if err := jobs.Handle(ctx, reconciliation, "migrate", - migrateContainer, - jobs.WithServiceAccount(serviceAccountName), - ); err != nil { + if err := databases.Migrate(ctx, stack, reconciliation, imageConfiguration, database); err != nil { return err } @@ -76,7 +62,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, reconciliation *v1beta1.Reconc } } - if err := createDeployment(ctx, stack, reconciliation, database, authClient, image); err != nil { + if err := createDeployment(ctx, stack, reconciliation, database, authClient, imageConfiguration); err != nil { return err } } diff --git a/internal/resources/registries/image.go b/internal/resources/registries/image.go index 0903c4c7d..5719b45a4 100644 --- a/internal/resources/registries/image.go +++ b/internal/resources/registries/image.go @@ -21,37 +21,36 @@ func NormalizeVersion(version string) string { return version } -func GetImage(ctx core.Context, stack *v1beta1.Stack, name, version string) (string, error) { - return TranslateImage(stack.Name, NewImageSettingsOverrider(ctx), - fmt.Sprintf("ghcr.io/formancehq/%s:%s", name, NormalizeVersion(version))) +func GetFormanceImage(ctx core.Context, stack *v1beta1.Stack, name, version string) (*ImageConfiguration, error) { + return GetImageConfiguration( + ctx, + stack.Name, + fmt.Sprintf("ghcr.io/formancehq/%s:%s", name, NormalizeVersion(version)), + ) } -func GetBenthosImage(ctx core.Context, stack *v1beta1.Stack, version string) (string, error) { - return TranslateImage(stack.Name, NewImageSettingsOverrider(ctx), - fmt.Sprintf("public.ecr.aws/formance-internal/jeffail/benthos:%s", NormalizeVersion(version))) +func GetBenthosImage(ctx core.Context, stack *v1beta1.Stack, version string) (*ImageConfiguration, error) { + return GetImageConfiguration( + ctx, + stack.Name, + fmt.Sprintf("public.ecr.aws/formance-internal/jeffail/benthos:%s", NormalizeVersion(version)), + ) } -func GetNatsBoxImage(ctx core.Context, stack *v1beta1.Stack, version string) (string, error) { - return TranslateImage(stack.Name, NewImageSettingsOverrider(ctx), - fmt.Sprintf("docker.io/natsio/nats-box:%s", NormalizeVersion(version))) +func GetNatsBoxImage(ctx core.Context, stack *v1beta1.Stack, version string) (*ImageConfiguration, error) { + return GetImageConfiguration( + ctx, + stack.Name, + fmt.Sprintf("docker.io/natsio/nats-box:%s", NormalizeVersion(version)), + ) } -func GetCaddyImage(ctx core.Context, stack *v1beta1.Stack, version string) (string, error) { - image := fmt.Sprintf("docker.io/caddy/caddy:%s", NormalizeVersion(version)) - newCaddyImage, err := TranslateImage(stack.Name, NewImageSettingsOverrider(ctx), - image) - if err != nil { - return "", err - } - +func GetCaddyImage(ctx core.Context, stack *v1beta1.Stack) (*ImageConfiguration, error) { defaultCaddyImage := "caddy:2.7.6-alpine" - caddyImage, err := settings.GetStringOrDefault(ctx, stack.Name, defaultCaddyImage, "caddy", "image") + selectedCaddyImage, err := settings.GetStringOrDefault(ctx, stack.Name, defaultCaddyImage, "caddy", "image") if err != nil { - return "", err - } - if newCaddyImage != image && caddyImage == defaultCaddyImage { - caddyImage = newCaddyImage + return nil, err } - return caddyImage, nil + return GetImageConfiguration(ctx, stack.Name, selectedCaddyImage) } diff --git a/internal/resources/registries/registries.go b/internal/resources/registries/registries.go index d390bd3a8..3a14775e8 100644 --- a/internal/resources/registries/registries.go +++ b/internal/resources/registries/registries.go @@ -2,6 +2,7 @@ package registries import ( "fmt" + v1 "k8s.io/api/core/v1" "strings" "github.com/formancehq/operator/internal/resources/settings" @@ -14,69 +15,80 @@ import ( // docker.io//: // version: "v2.0.0-rc.35-scratch@sha256:4a29620448a90f3ae50d2e375c993b86ef141ead4b6ac1edd1674e9ff6b933f8" // docker.io//:v2.0.0-rc.35-scratch@sha256:4a29620448a90f3ae50d2e375c993b86ef141ead4b6ac1edd1674e9ff6b933f8 -type imageOrigin struct { - Registry string - Image string - Version string +type ImageConfiguration struct { + Registry string + Image string + Version string + PullSecrets []v1.LocalObjectReference } -func (o imageOrigin) String() string { - return fmt.Sprintf("%s/%s:%s", o.Registry, o.Image, o.Version) -} - -//go:generate mockgen -source ./registries.go -destination ./registries_generated.go -package registries . ImageSettingsOverrider -type ImageSettingsOverrider interface { - OverrideWithSetting(*imageOrigin, string) error -} - -type defaultImageSettingOverrider struct { - ctx core.Context -} - -func NewImageSettingsOverrider(ctx core.Context) ImageSettingsOverrider { - return &defaultImageSettingOverrider{ctx: ctx} -} - -func (is *defaultImageSettingOverrider) OverrideWithSetting(o *imageOrigin, stackName string) (err error) { - imageOverride, err := settings.GetStringOrEmpty(is.ctx, stackName, "registries", o.Registry, "images", o.Image, "rewrite") - if err != nil { - return err - } - if imageOverride != "" { - o.Image = imageOverride +func (cfg *ImageConfiguration) GetFullImageName() string { + ret := "" + if cfg.Registry != "" { + ret += cfg.Registry + "/" } + ret += cfg.Image + ":" + cfg.Version - registryEndpoint, err := settings.GetStringOrEmpty(is.ctx, stackName, "registries", o.Registry, "endpoint") - if err != nil { - return err - } - if registryEndpoint != "" { - o.Registry = registryEndpoint - } + return ret +} - return nil +func (o *ImageConfiguration) String() string { + return fmt.Sprintf("%s/%s:%s", o.Registry, o.Image, o.Version) } -func TranslateImage( +func GetImageConfiguration( + ctx core.Context, stackName string, - settingsOverrider ImageSettingsOverrider, image string, -) (string, error) { +) (*ImageConfiguration, error) { repository, version, found := strings.Cut(image, ":") if !found { - return "", fmt.Errorf("invalid image format: %s", image) + return nil, fmt.Errorf("invalid image format: %s", image) } organizationImage := strings.SplitN(repository, "/", 2) - origin := &imageOrigin{ - Registry: organizationImage[0], - Image: organizationImage[1], + registry := organizationImage[0] + imageWithoutRegistry := organizationImage[1] + + ret := &ImageConfiguration{ + Registry: registry, + Image: imageWithoutRegistry, Version: version, } - if err := settingsOverrider.OverrideWithSetting(origin, stackName); err != nil { - return "", err + imageOverride, err := settings.GetStringOrEmpty(ctx, stackName, "registries", registry, "images", imageWithoutRegistry, "rewrite") + if err != nil { + return nil, err + } + if imageOverride != "" { + ret.Image = imageOverride + } + + registryEndpoint, err := settings.GetStringOrEmpty(ctx, stackName, "registries", registry, "endpoint") + if err != nil { + return nil, err + } + if registryEndpoint != "" { + parts := strings.SplitN(registryEndpoint, "?", 2) + ret.Registry = parts[0] + if len(parts) > 1 { + parametersPairs := strings.Split(parts[1], ",") + for _, pair := range parametersPairs { + parts := strings.SplitN(pair, "=", 2) + if len(parts) != 2 { + return nil, fmt.Errorf("invalid registry endpoint parameter: %s", pair) + } + switch parts[0] { + case "pullSecret": + ret.PullSecrets = append(ret.PullSecrets, v1.LocalObjectReference{ + Name: parts[1], + }) + default: + return nil, fmt.Errorf("unknown registry endpoint parameter: %s", parts[0]) + } + } + } } - return origin.String(), nil + return ret, nil } diff --git a/internal/resources/registries/registries_generated.go b/internal/resources/registries/registries_generated.go deleted file mode 100644 index 808d33f32..000000000 --- a/internal/resources/registries/registries_generated.go +++ /dev/null @@ -1,53 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: ./registries.go -// -// Generated by this command: -// -// mockgen -source ./registries.go -destination ./registries_generated.go -package registries . ImageSettingsOverrider -// - -// Package registries is a generated GoMock package. -package registries - -import ( - reflect "reflect" - - gomock "go.uber.org/mock/gomock" -) - -// MockImageSettingsOverrider is a mock of ImageSettingsOverrider interface. -type MockImageSettingsOverrider struct { - ctrl *gomock.Controller - recorder *MockImageSettingsOverriderMockRecorder -} - -// MockImageSettingsOverriderMockRecorder is the mock recorder for MockImageSettingsOverrider. -type MockImageSettingsOverriderMockRecorder struct { - mock *MockImageSettingsOverrider -} - -// NewMockImageSettingsOverrider creates a new mock instance. -func NewMockImageSettingsOverrider(ctrl *gomock.Controller) *MockImageSettingsOverrider { - mock := &MockImageSettingsOverrider{ctrl: ctrl} - mock.recorder = &MockImageSettingsOverriderMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockImageSettingsOverrider) EXPECT() *MockImageSettingsOverriderMockRecorder { - return m.recorder -} - -// OverrideWithSetting mocks base method. -func (m *MockImageSettingsOverrider) OverrideWithSetting(arg0 *imageOrigin, arg1 string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OverrideWithSetting", arg0, arg1) - ret0, _ := ret[0].(error) - return ret0 -} - -// OverrideWithSetting indicates an expected call of OverrideWithSetting. -func (mr *MockImageSettingsOverriderMockRecorder) OverrideWithSetting(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OverrideWithSetting", reflect.TypeOf((*MockImageSettingsOverrider)(nil).OverrideWithSetting), arg0, arg1) -} diff --git a/internal/resources/registries/registries_test.go b/internal/resources/registries/registries_test.go deleted file mode 100644 index c304d723d..000000000 --- a/internal/resources/registries/registries_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package registries_test - -import ( - "testing" - - "github.com/formancehq/operator/internal/resources/registries" - "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" -) - -func TestTranslateImage(t *testing.T) { - ctrl := gomock.NewController(t) - t.Cleanup(ctrl.Finish) - - type testCase struct { - url string - } - // ghcr.io//: - // public.ecr.aws//jeffail/benthos: - // docker.io//: - // version: "v2.0.0-rc.35-scratch@sha256:4a29620448a90f3ae50d2e375c993b86ef141ead4b6ac1edd1674e9ff6b933f8" - // docker.io//:v2.0.0-rc.35-scratch@sha256:4a29620448a90f3ae50d2e375c993b86ef141ead4b6ac1edd1674e9ff6b933f8 - testCases := []testCase{ - { - url: "ghcr.io/formancehq/operator:latest", - }, - { - url: "public.ecr.aws/formance-internal/jeffail/benthos:latest", - }, - { - url: "docker.io/natsio/nats-box:latest", - }, - { - url: "docker.io/caddy/caddy:2.7.6-alpine", - }, - { - url: "ghcr.io/formancehq/operator-utils:v2.0.0-rc.35-scratch@sha256:4a29620448a90f3ae50d2e375c993b86ef141ead4b6ac1edd1674e9ff6b933f8", - }, - } - - for _, tc := range testCases { - mockImageSettingsOverrider := registries.NewMockImageSettingsOverrider(ctrl) - mockImageSettingsOverrider.EXPECT().OverrideWithSetting(gomock.Any(), gomock.Any()).Return(nil) - - fullImageString, err := registries.TranslateImage("stackName", mockImageSettingsOverrider, tc.url) - require.NoError(t, err) - require.Equal(t, tc.url, fullImageString) - } -} diff --git a/internal/resources/searches/init.go b/internal/resources/searches/init.go index 82d5e6f4a..bed2b1022 100644 --- a/internal/resources/searches/init.go +++ b/internal/resources/searches/init.go @@ -109,7 +109,7 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, search *v1beta1.Search, versio } env = append(env, authEnvVars...) - image, err := GetImage(ctx, stack, "search", version) + imageConfiguration, err := GetFormanceImage(ctx, stack, "search", version) if err != nil { return err } @@ -150,10 +150,11 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, search *v1beta1.Search, versio t.Spec.DevProperties = search.Spec.DevProperties t.Spec.InitContainers = []corev1.Container{{ Name: "init-mapping", - Image: image, + Image: imageConfiguration.GetFullImageName(), Args: []string{"init-mapping"}, Env: env, }} + t.Spec.ImagePullSecrets = imageConfiguration.PullSecrets return nil }, @@ -179,9 +180,10 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, search *v1beta1.Search, versio }, Spec: corev1.PodSpec{ ServiceAccountName: serviceAccountName, + ImagePullSecrets: imageConfiguration.PullSecrets, Containers: []corev1.Container{{ Name: "search", - Image: image, + Image: imageConfiguration.GetFullImageName(), Ports: []corev1.ContainerPort{applications.StandardHTTPPort()}, Env: env, LivenessProbe: applications.DefaultLiveness("http"), diff --git a/internal/resources/stargates/deployment.go b/internal/resources/stargates/deployment.go index 605302476..20bd80e19 100644 --- a/internal/resources/stargates/deployment.go +++ b/internal/resources/stargates/deployment.go @@ -42,7 +42,7 @@ func createDeployment(ctx core.Context, stack *v1beta1.Stack, stargate *v1beta1. env = append(env, core.Env("TLS_ENABLED", "false")) } - image, err := registries.GetImage(ctx, stack, "stargate", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "stargate", version) if err != nil { return err } @@ -55,10 +55,11 @@ func createDeployment(ctx core.Context, stack *v1beta1.Stack, stargate *v1beta1. Spec: appsv1.DeploymentSpec{ Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ + ImagePullSecrets: imageConfiguration.PullSecrets, Containers: []v1.Container{{ Name: "stargate", Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), Ports: []v1.ContainerPort{applications.StandardHTTPPort()}, LivenessProbe: applications.DefaultLiveness("http"), }}, diff --git a/internal/resources/wallets/deployment.go b/internal/resources/wallets/deployment.go index c56a6892c..00a410f5e 100644 --- a/internal/resources/wallets/deployment.go +++ b/internal/resources/wallets/deployment.go @@ -40,7 +40,7 @@ func createDeployment(ctx core.Context, stack *v1beta1.Stack, wallets *v1beta1.W } env = append(env, authEnvVars...) - image, err := registries.GetImage(ctx, stack, "wallets", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "wallets", version) if err != nil { return err } @@ -53,11 +53,12 @@ func createDeployment(ctx core.Context, stack *v1beta1.Stack, wallets *v1beta1.W Spec: appsv1.DeploymentSpec{ Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ + ImagePullSecrets: imageConfiguration.PullSecrets, Containers: []v1.Container{{ Name: "wallets", Args: []string{"serve"}, Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), Ports: []v1.ContainerPort{applications.StandardHTTPPort()}, LivenessProbe: applications.DefaultLiveness("http"), }}, diff --git a/internal/resources/webhooks/deployment.go b/internal/resources/webhooks/deployment.go index fea128c22..9d1d64a2f 100644 --- a/internal/resources/webhooks/deployment.go +++ b/internal/resources/webhooks/deployment.go @@ -71,7 +71,7 @@ func deploymentEnvVars(ctx core.Context, stack *v1beta1.Stack, webhooks *v1beta1 func createAPIDeployment(ctx core.Context, stack *v1beta1.Stack, webhooks *v1beta1.Webhooks, database *v1beta1.Database, consumer *v1beta1.BrokerConsumer, version string, withWorker bool) error { - image, err := registries.GetImage(ctx, stack, "webhooks", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "webhooks", version) if err != nil { return err } @@ -111,10 +111,11 @@ func createAPIDeployment(ctx core.Context, stack *v1beta1.Stack, webhooks *v1bet Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ ServiceAccountName: serviceAccountName, + ImagePullSecrets: imageConfiguration.PullSecrets, Containers: []v1.Container{{ Name: "api", Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), Args: args, Ports: []v1.ContainerPort{applications.StandardHTTPPort()}, LivenessProbe: applications.DefaultLiveness("http"), @@ -127,9 +128,16 @@ func createAPIDeployment(ctx core.Context, stack *v1beta1.Stack, webhooks *v1bet Install(ctx) } -func createWorkerDeployment(ctx core.Context, stack *v1beta1.Stack, webhooks *v1beta1.Webhooks, database *v1beta1.Database, consumer *v1beta1.BrokerConsumer, version string) error { +func createWorkerDeployment( + ctx core.Context, + stack *v1beta1.Stack, + webhooks *v1beta1.Webhooks, + database *v1beta1.Database, + consumer *v1beta1.BrokerConsumer, + version string, +) error { - image, err := registries.GetImage(ctx, stack, "webhooks", version) + imageConfiguration, err := registries.GetFormanceImage(ctx, stack, "webhooks", version) if err != nil { return err } @@ -157,11 +165,12 @@ func createWorkerDeployment(ctx core.Context, stack *v1beta1.Stack, webhooks *v1 Spec: appsv1.DeploymentSpec{ Template: v1.PodTemplateSpec{ Spec: v1.PodSpec{ + ImagePullSecrets: imageConfiguration.PullSecrets, ServiceAccountName: serviceAccountName, Containers: []v1.Container{{ Name: "worker", Env: env, - Image: image, + Image: imageConfiguration.GetFullImageName(), Args: []string{"worker"}, }}, }, diff --git a/internal/resources/webhooks/init.go b/internal/resources/webhooks/init.go index 150af57b5..b354291ae 100644 --- a/internal/resources/webhooks/init.go +++ b/internal/resources/webhooks/init.go @@ -22,9 +22,7 @@ import ( "github.com/formancehq/operator/internal/resources/brokerconsumers" "github.com/formancehq/operator/internal/resources/databases" "github.com/formancehq/operator/internal/resources/gatewayhttpapis" - "github.com/formancehq/operator/internal/resources/jobs" "github.com/formancehq/operator/internal/resources/registries" - "github.com/formancehq/operator/internal/resources/settings" "github.com/pkg/errors" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" @@ -53,28 +51,17 @@ func Reconcile(ctx Context, stack *v1beta1.Stack, webhooks *v1beta1.Webhooks, ve return NewPendingError().WithMessage("database not ready") } - image, err := registries.GetImage(ctx, stack, "webhooks", version) + image, err := registries.GetFormanceImage(ctx, stack, "webhooks", version) if err != nil { return errors.Wrap(err, "resolving image") } if IsGreaterOrEqual(version, "v2.0.0-rc.5") && databases.GetSavedModuleVersion(database) != version { - serviceAccountName, err := settings.GetAWSServiceAccount(ctx, stack.Name) - if err != nil { - return errors.Wrap(err, "resolving service account") - } - - migrateContainer, err := databases.MigrateDatabaseContainer(ctx, stack, image, database) - if err != nil { - return errors.Wrap(err, "creating migration container") - } - if err := jobs.Handle(ctx, webhooks, "migrate", - migrateContainer, - jobs.WithServiceAccount(serviceAccountName), - ); err != nil { + if err := databases.Migrate(ctx, stack, webhooks, image, database); err != nil { return err } + if err := databases.SaveModuleVersion(ctx, database, version); err != nil { return errors.Wrap(err, "saving module version in database object") }