From ca0c0072ed06246737509aeced4fba0b66a1043a Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 10:45:24 +0200 Subject: [PATCH 01/49] baseline refactoring --- .../construct/database_construction.go | 11 ++++------- .../operator/database_statefulset_options.go | 4 ++-- docker/mongodb-agent/Dockerfile | 2 ++ docker/mongodb-agent/agent-launcher-shim.sh | 19 +++++++++++++++++++ go.mod | 4 ++++ go.sum | 5 +++++ .../kube/podtemplatespec/podspec_template.go | 12 ++++++++---- pkg/util/constants.go | 1 + scripts/dev/print_operator_env.sh | 4 ++++ 9 files changed, 49 insertions(+), 13 deletions(-) create mode 100755 docker/mongodb-agent/agent-launcher-shim.sh diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 7194c643c..f3e307701 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -489,8 +489,7 @@ func buildDatabaseStatefulSetConfigurationFunction(mdb databaseStatefulSetSource if architectures.IsRunningStaticArchitecture(mdb.GetAnnotations()) { shareProcessNs = func(sts *appsv1.StatefulSet) { - a := true - sts.Spec.Template.Spec.ShareProcessNamespace = &a + sts.Spec.Template.Spec.ShareProcessNamespace = ptr.To(true) } secondContainerModification = podtemplatespec.WithContainerByIndex(1, container.WithVolumeMounts(volumeMounts)) } @@ -697,7 +696,7 @@ func buildMongoDBPodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseSt container.WithCommand([]string{"bash", "-c", "tail -F -n0 ${MDB_LOG_FILE_MONGODB} mongodb_marker"}), containerSecurityContext, )} - staticContainerMongodContainerModification = podtemplatespec.WithContainerByIndex(1, mongodModification...) + staticContainerMongodContainerModification = podtemplatespec.WithContainer(util.DatabaseContainerName, mongodModification...) // We are not setting the database-scripts volume on purpose, // since we don't need to copy things from the init container over. @@ -726,19 +725,17 @@ func buildMongoDBPodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseSt databaseContainerModifications = append(databaseContainerModifications, modification) } - serviceAccountName := getServiceAccountName(opts) - mods := []podtemplatespec.Modification{ sharedDatabaseConfiguration(opts, mdb), podtemplatespec.WithServiceAccount(util.MongoDBServiceAccount), - podtemplatespec.WithServiceAccount(serviceAccountName), + podtemplatespec.WithServiceAccount(getServiceAccountName(opts)), podtemplatespec.WithVolumes(volumes), podtemplatespec.WithContainerByIndex(0, databaseContainerModifications...), staticContainerMongodContainerModification, } if len(initContainerModifications) > 0 { - mods = append(mods, podtemplatespec.WithInitContainerByIndex(0, initContainerModifications...)) + mods = append(mods, podtemplatespec.WithInitContainer(InitDatabaseContainerName, initContainerModifications...)) } return podtemplatespec.Apply(mods...) diff --git a/controllers/operator/database_statefulset_options.go b/controllers/operator/database_statefulset_options.go index 0526cb865..d60bb1747 100644 --- a/controllers/operator/database_statefulset_options.go +++ b/controllers/operator/database_statefulset_options.go @@ -100,10 +100,10 @@ func WithDefaultConfigSrvStorageSize() func(options *construct.DatabaseStatefulS } } -// WithInitDatabaseNonStaticImage sets the InitDatabaseNonStaticImage field. +// WithInitDatabaseNonStaticImage sets the InitDatabaseImage field. func WithInitDatabaseNonStaticImage(image string) func(*construct.DatabaseStatefulSetOptions) { return func(opts *construct.DatabaseStatefulSetOptions) { - opts.InitDatabaseNonStaticImage = image + opts.InitDatabaseImage = image } } diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index 08d8746d8..c9f424552 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -18,6 +18,8 @@ COPY --from=base /data/readinessprobe /opt/scripts/readinessprobe COPY --from=base /data/version-upgrade-hook /opt/scripts/version-upgrade-hook COPY --from=base /data/agent-launcher-lib.sh /opt/scripts/agent-launcher-lib.sh COPY --from=base /data/agent-launcher.sh /opt/scripts/agent-launcher.sh +COPY agent-launcher-shim.sh /agent-launcher-shim.sh +RUN chmod +x /agent-launcher-shim.sh COPY --from=base /data/LICENSE /licenses/LICENSE # Replace libcurl-minimal and curl-minimal with the full versions diff --git a/docker/mongodb-agent/agent-launcher-shim.sh b/docker/mongodb-agent/agent-launcher-shim.sh new file mode 100755 index 000000000..3f49c02ba --- /dev/null +++ b/docker/mongodb-agent/agent-launcher-shim.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -e + +# Wait for agent-launcher container to start +echo "Waiting for agent-launcher container to be ready..." +while [ ! -d "/proc/$(pgrep -f 'tail -F -n0 /dev/null' | head -n1)/root/opt/scripts" ]; do + sleep 1 +done + +# Copy agent launcher scripts +echo "Copying agent launcher scripts..." +cp -r /proc/$(pgrep -f 'tail -F -n0 /dev/null' | head -n1)/root/opt/scripts/* /opt/scripts/ + +# Make scripts executable +chmod +x /opt/scripts/*.sh + +# Start the agent launcher +echo "Starting agent launcher..." +exec /opt/scripts/agent-launcher.sh diff --git a/go.mod b/go.mod index f2246cc30..616c508a1 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,8 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.7 github.com/hashicorp/vault/api v1.16.0 github.com/imdario/mergo v0.3.15 + github.com/onsi/ginkgo/v2 v2.17.1 + github.com/onsi/gomega v1.32.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.22.0 github.com/r3labs/diff/v3 v3.0.1 @@ -54,6 +56,7 @@ require ( github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -61,6 +64,7 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect + github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect diff --git a/go.sum b/go.sum index 48aa3fef3..b7ec791f4 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,9 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -110,6 +113,7 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4= github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -284,6 +288,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go b/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go index 355730375..e109b6d42 100644 --- a/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go +++ b/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go @@ -39,7 +39,7 @@ func NOOP() Modification { } // WithContainer applies the modifications to the container with the provided name -func WithContainer(name string, containerfunc func(*corev1.Container)) Modification { +func WithContainer(name string, funcs ...func(*corev1.Container)) Modification { return func(podTemplateSpec *corev1.PodTemplateSpec) { idx := findIndexByName(name, podTemplateSpec.Spec.Containers) if idx == notFound { @@ -48,7 +48,9 @@ func WithContainer(name string, containerfunc func(*corev1.Container)) Modificat idx = len(podTemplateSpec.Spec.Containers) - 1 } c := &podTemplateSpec.Spec.Containers[idx] - containerfunc(c) + for _, f := range funcs { + f(c) + } } } @@ -67,7 +69,7 @@ func WithContainerByIndex(index int, funcs ...func(container *corev1.Container)) } // WithInitContainer applies the modifications to the init container with the provided name -func WithInitContainer(name string, containerfunc func(*corev1.Container)) Modification { +func WithInitContainer(name string, funcs ...func(*corev1.Container)) Modification { return func(podTemplateSpec *corev1.PodTemplateSpec) { idx := findIndexByName(name, podTemplateSpec.Spec.InitContainers) if idx == notFound { @@ -76,7 +78,9 @@ func WithInitContainer(name string, containerfunc func(*corev1.Container)) Modif idx = len(podTemplateSpec.Spec.InitContainers) - 1 } c := &podTemplateSpec.Spec.InitContainers[idx] - containerfunc(c) + for _, f := range funcs { + f(c) + } } } diff --git a/pkg/util/constants.go b/pkg/util/constants.go index 4cc19cdc6..37d84d071 100644 --- a/pkg/util/constants.go +++ b/pkg/util/constants.go @@ -89,6 +89,7 @@ const ( BackupDaemonContainerName = "mongodb-backup-daemon" DatabaseContainerName = "mongodb-enterprise-database" AgentContainerName = "mongodb-agent" + AgentContainerUtilitiesName = "mongodb-agent-operator-utilities" InitOpsManagerContainerName = "mongodb-kubernetes-init-ops-manager" PvcNameData = "data" PvcMountPathData = "/data" diff --git a/scripts/dev/print_operator_env.sh b/scripts/dev/print_operator_env.sh index c66bdf824..b1aa85cfb 100755 --- a/scripts/dev/print_operator_env.sh +++ b/scripts/dev/print_operator_env.sh @@ -99,6 +99,10 @@ MDB_SEARCH_COMMUNITY_REPO_URL=\"${MDB_SEARCH_COMMUNITY_REPO_URL}\" if [[ "${MDB_MAX_CONCURRENT_RECONCILES:-""}" != "" ]]; then echo "MDB_MAX_CONCURRENT_RECONCILES=${MDB_MAX_CONCURRENT_RECONCILES}" fi + + if [[ "${OPERATOR_NAME:-""}" != "" ]]; then + echo "OPERATOR_NAME=${OPERATOR_NAME}" + fi } print_operator_env From 08c2c49eca9cccc7205447e71d28cece59ec9009 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 11:25:48 +0200 Subject: [PATCH 02/49] first refactoring --- .../construct/database_construction.go | 113 +++++++++++------- pkg/util/constants.go | 2 +- 2 files changed, 70 insertions(+), 45 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index f3e307701..14270bb96 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -105,10 +105,10 @@ type DatabaseStatefulSetOptions struct { StsType StsType AdditionalMongodConfig *mdbv1.AdditionalMongodConfig - InitDatabaseNonStaticImage string - DatabaseNonStaticImage string - MongodbImage string - AgentImage string + InitDatabaseImage string + DatabaseNonStaticImage string + MongodbImage string + AgentImage string Annotations map[string]string VaultConfig vault.VaultConfiguration @@ -665,6 +665,63 @@ func getVolumesAndVolumeMounts(mdb databaseStatefulSetSource, databaseOpts Datab // buildMongoDBPodTemplateSpec constructs the podTemplateSpec for the MongoDB resource func buildMongoDBPodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseStatefulSetSource) podtemplatespec.Modification { + if architectures.IsRunningStaticArchitecture(mdb.GetAnnotations()) { + return buildStaticArchitecturePodTemplateSpec(opts, mdb) + } else { + return buildNonStaticArchitecturePodTemplateSpec(opts, mdb) + } +} + +// buildStaticArchitecturePodTemplateSpec constructs the podTemplateSpec for static architecture +func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseStatefulSetSource) podtemplatespec.Modification { + var volumes []corev1.Volume + + _, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications() + + // Static architecture containers: agent container and mongod container + agentContainerModifications := []func(*corev1.Container){container.Apply( + container.WithName(util.AgentContainerName), + container.WithImage(opts.AgentImage), + container.WithEnvs(databaseEnvVars(opts)...), + containerSecurityContext, + )} + + mongodContainerModifications := []func(*corev1.Container){container.Apply( + container.WithName(util.DatabaseContainerName), + container.WithArgs([]string{""}), + container.WithImage(opts.MongodbImage), + container.WithEnvs(databaseEnvVars(opts)...), + container.WithCommand([]string{"bash", "-c", "tail -F -n0 ${MDB_LOG_FILE_MONGODB} mongodb_marker"}), + containerSecurityContext, + )} + + // Handle hostname override for static architecture + if opts.HostNameOverrideConfigmapName != "" { + volumes = append(volumes, statefulset.CreateVolumeFromConfigMap(opts.HostNameOverrideConfigmapName, opts.HostNameOverrideConfigmapName)) + hostnameOverrideModification := container.WithVolumeMounts([]corev1.VolumeMount{ + { + Name: opts.HostNameOverrideConfigmapName, + MountPath: "/opt/scripts/config", + }, + }) + agentContainerModifications = append(agentContainerModifications, hostnameOverrideModification) + mongodContainerModifications = append(mongodContainerModifications, hostnameOverrideModification) + } + + mods := []podtemplatespec.Modification{ + sharedDatabaseConfiguration(opts, mdb), + podtemplatespec.WithServiceAccount(util.MongoDBServiceAccount), + podtemplatespec.WithServiceAccount(getServiceAccountName(opts)), + podtemplatespec.WithVolumes(volumes), + podtemplatespec.WithContainerByIndex(0, agentContainerModifications...), + podtemplatespec.WithContainerByIndex(1, mongodContainerModifications...), + } + + return podtemplatespec.Apply(mods...) +} + +// buildNonStaticArchitecturePodTemplateSpec constructs the podTemplateSpec for non-static architecture +func buildNonStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseStatefulSetSource) podtemplatespec.Modification { // scripts volume is shared by the init container and the AppDB, so the startup // script can be copied over scriptsVolume := statefulset.CreateVolumeFromEmptyDir("database-scripts") @@ -673,7 +730,9 @@ func buildMongoDBPodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseSt volumes := []corev1.Volume{scriptsVolume} volumeMounts := []corev1.VolumeMount{databaseScriptsVolumeMount} - initContainerModifications := []func(*corev1.Container){buildDatabaseInitContainer(opts.InitDatabaseNonStaticImage)} + // Non-static architecture: init container and database container + initContainerModifications := []func(*corev1.Container){buildDatabaseInitContainer(opts.InitDatabaseImage)} + databaseContainerModifications := []func(*corev1.Container){container.Apply( container.WithName(util.DatabaseContainerName), container.WithImage(opts.DatabaseNonStaticImage), @@ -682,47 +741,17 @@ func buildMongoDBPodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseSt container.WithVolumeMounts(volumeMounts), )} - _, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications() - - staticContainerMongodContainerModification := podtemplatespec.NOOP() - if architectures.IsRunningStaticArchitecture(mdb.GetAnnotations()) { - // we don't use initContainers therefore, we reset it here - initContainerModifications = []func(*corev1.Container){} - mongodModification := []func(*corev1.Container){container.Apply( - container.WithName(util.DatabaseContainerName), - container.WithArgs([]string{""}), - container.WithImage(opts.MongodbImage), - container.WithEnvs(databaseEnvVars(opts)...), - container.WithCommand([]string{"bash", "-c", "tail -F -n0 ${MDB_LOG_FILE_MONGODB} mongodb_marker"}), - containerSecurityContext, - )} - staticContainerMongodContainerModification = podtemplatespec.WithContainer(util.DatabaseContainerName, mongodModification...) - - // We are not setting the database-scripts volume on purpose, - // since we don't need to copy things from the init container over. - databaseContainerModifications = []func(*corev1.Container){container.Apply( - container.WithName(util.AgentContainerName), - container.WithImage(opts.AgentImage), - container.WithEnvs(databaseEnvVars(opts)...), - containerSecurityContext, - )} - } - + // Handle hostname override for non-static architecture if opts.HostNameOverrideConfigmapName != "" { volumes = append(volumes, statefulset.CreateVolumeFromConfigMap(opts.HostNameOverrideConfigmapName, opts.HostNameOverrideConfigmapName)) - modification := container.WithVolumeMounts([]corev1.VolumeMount{ + hostnameOverrideModification := container.WithVolumeMounts([]corev1.VolumeMount{ { Name: opts.HostNameOverrideConfigmapName, MountPath: "/opt/scripts/config", }, }) - - // we only need to add the volume modification if we actually use an init container - if len(initContainerModifications) > 0 { - initContainerModifications = append(initContainerModifications, modification) - } - - databaseContainerModifications = append(databaseContainerModifications, modification) + initContainerModifications = append(initContainerModifications, hostnameOverrideModification) + databaseContainerModifications = append(databaseContainerModifications, hostnameOverrideModification) } mods := []podtemplatespec.Modification{ @@ -731,11 +760,7 @@ func buildMongoDBPodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseSt podtemplatespec.WithServiceAccount(getServiceAccountName(opts)), podtemplatespec.WithVolumes(volumes), podtemplatespec.WithContainerByIndex(0, databaseContainerModifications...), - staticContainerMongodContainerModification, - } - - if len(initContainerModifications) > 0 { - mods = append(mods, podtemplatespec.WithInitContainer(InitDatabaseContainerName, initContainerModifications...)) + podtemplatespec.WithInitContainerByIndex(0, initContainerModifications...), } return podtemplatespec.Apply(mods...) diff --git a/pkg/util/constants.go b/pkg/util/constants.go index 37d84d071..c649eda4e 100644 --- a/pkg/util/constants.go +++ b/pkg/util/constants.go @@ -89,7 +89,7 @@ const ( BackupDaemonContainerName = "mongodb-backup-daemon" DatabaseContainerName = "mongodb-enterprise-database" AgentContainerName = "mongodb-agent" - AgentContainerUtilitiesName = "mongodb-agent-operator-utilities" + AgentContainerUtilitiesName = "mongodb-agent-operator-utilities" InitOpsManagerContainerName = "mongodb-kubernetes-init-ops-manager" PvcNameData = "data" PvcMountPathData = "/data" From 35c5f5319c3ba4834bb58c02ad75ef648d4f56c3 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 11:49:36 +0200 Subject: [PATCH 03/49] first refactoring --- controllers/operator/construct/database_construction.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 14270bb96..c5d09f111 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -678,7 +678,6 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb _, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications() - // Static architecture containers: agent container and mongod container agentContainerModifications := []func(*corev1.Container){container.Apply( container.WithName(util.AgentContainerName), container.WithImage(opts.AgentImage), @@ -695,7 +694,6 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb containerSecurityContext, )} - // Handle hostname override for static architecture if opts.HostNameOverrideConfigmapName != "" { volumes = append(volumes, statefulset.CreateVolumeFromConfigMap(opts.HostNameOverrideConfigmapName, opts.HostNameOverrideConfigmapName)) hostnameOverrideModification := container.WithVolumeMounts([]corev1.VolumeMount{ @@ -730,7 +728,6 @@ func buildNonStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, volumes := []corev1.Volume{scriptsVolume} volumeMounts := []corev1.VolumeMount{databaseScriptsVolumeMount} - // Non-static architecture: init container and database container initContainerModifications := []func(*corev1.Container){buildDatabaseInitContainer(opts.InitDatabaseImage)} databaseContainerModifications := []func(*corev1.Container){container.Apply( @@ -741,7 +738,6 @@ func buildNonStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, container.WithVolumeMounts(volumeMounts), )} - // Handle hostname override for non-static architecture if opts.HostNameOverrideConfigmapName != "" { volumes = append(volumes, statefulset.CreateVolumeFromConfigMap(opts.HostNameOverrideConfigmapName, opts.HostNameOverrideConfigmapName)) hostnameOverrideModification := container.WithVolumeMounts([]corev1.VolumeMount{ From cb04b20a6c3c57065b12bb4f9ff5ba9f9f699b76 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 11:50:55 +0200 Subject: [PATCH 04/49] first refactoring --- .../pkg/kube/podtemplatespec/podspec_template.go | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go b/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go index e109b6d42..355730375 100644 --- a/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go +++ b/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go @@ -39,7 +39,7 @@ func NOOP() Modification { } // WithContainer applies the modifications to the container with the provided name -func WithContainer(name string, funcs ...func(*corev1.Container)) Modification { +func WithContainer(name string, containerfunc func(*corev1.Container)) Modification { return func(podTemplateSpec *corev1.PodTemplateSpec) { idx := findIndexByName(name, podTemplateSpec.Spec.Containers) if idx == notFound { @@ -48,9 +48,7 @@ func WithContainer(name string, funcs ...func(*corev1.Container)) Modification { idx = len(podTemplateSpec.Spec.Containers) - 1 } c := &podTemplateSpec.Spec.Containers[idx] - for _, f := range funcs { - f(c) - } + containerfunc(c) } } @@ -69,7 +67,7 @@ func WithContainerByIndex(index int, funcs ...func(container *corev1.Container)) } // WithInitContainer applies the modifications to the init container with the provided name -func WithInitContainer(name string, funcs ...func(*corev1.Container)) Modification { +func WithInitContainer(name string, containerfunc func(*corev1.Container)) Modification { return func(podTemplateSpec *corev1.PodTemplateSpec) { idx := findIndexByName(name, podTemplateSpec.Spec.InitContainers) if idx == notFound { @@ -78,9 +76,7 @@ func WithInitContainer(name string, funcs ...func(*corev1.Container)) Modificati idx = len(podTemplateSpec.Spec.InitContainers) - 1 } c := &podTemplateSpec.Spec.InitContainers[idx] - for _, f := range funcs { - f(c) - } + containerfunc(c) } } From 43ed3864cff054f3fde77757742bf5b79766eaf7 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 13:01:29 +0200 Subject: [PATCH 05/49] add agent container --- .../operator/construct/database_construction.go | 11 +++++++++++ .../mongodbmultireplicaset_controller_test.go | 2 +- .../operator/mongodbreplicaset_controller_test.go | 2 +- .../operator/mongodbshardedcluster_controller_test.go | 2 +- .../operator/mongodbstandalone_controller_test.go | 2 +- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index c5d09f111..b1b010785 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -694,6 +694,15 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb containerSecurityContext, )} + agentUtilitiesHolderModifications := []func(*corev1.Container){container.Apply( + container.WithName(util.AgentContainerUtilitiesName), + container.WithArgs([]string{""}), + container.WithImage(opts.InitDatabaseImage), + container.WithEnvs(databaseEnvVars(opts)...), + container.WithCommand([]string{"bash", "-c", "tail -f /dev/null"}), + containerSecurityContext, + )} + if opts.HostNameOverrideConfigmapName != "" { volumes = append(volumes, statefulset.CreateVolumeFromConfigMap(opts.HostNameOverrideConfigmapName, opts.HostNameOverrideConfigmapName)) hostnameOverrideModification := container.WithVolumeMounts([]corev1.VolumeMount{ @@ -704,6 +713,7 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb }) agentContainerModifications = append(agentContainerModifications, hostnameOverrideModification) mongodContainerModifications = append(mongodContainerModifications, hostnameOverrideModification) + agentUtilitiesHolderModifications = append(agentUtilitiesHolderModifications, hostnameOverrideModification) } mods := []podtemplatespec.Modification{ @@ -713,6 +723,7 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb podtemplatespec.WithVolumes(volumes), podtemplatespec.WithContainerByIndex(0, agentContainerModifications...), podtemplatespec.WithContainerByIndex(1, mongodContainerModifications...), + podtemplatespec.WithContainerByIndex(2, agentUtilitiesHolderModifications...), } return podtemplatespec.Apply(mods...) diff --git a/controllers/operator/mongodbmultireplicaset_controller_test.go b/controllers/operator/mongodbmultireplicaset_controller_test.go index 806ace443..fd615ddea 100644 --- a/controllers/operator/mongodbmultireplicaset_controller_test.go +++ b/controllers/operator/mongodbmultireplicaset_controller_test.go @@ -163,7 +163,7 @@ func TestMultiReplicaSetClusterReconcileContainerImagesWithStaticArchitecture(t require.NoError(t, err) assert.Len(t, sts.Spec.Template.Spec.InitContainers, 0) - require.Len(t, sts.Spec.Template.Spec.Containers, 2) + require.Len(t, sts.Spec.Template.Spec.Containers, 3) // Version from OM + operator version assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1_9.9.9-test", sts.Spec.Template.Spec.Containers[0].Image) diff --git a/controllers/operator/mongodbreplicaset_controller_test.go b/controllers/operator/mongodbreplicaset_controller_test.go index 4c9abb64c..440ce4f1f 100644 --- a/controllers/operator/mongodbreplicaset_controller_test.go +++ b/controllers/operator/mongodbreplicaset_controller_test.go @@ -148,7 +148,7 @@ func TestReplicaSetClusterReconcileContainerImagesWithStaticArchitecture(t *test assert.NoError(t, err) assert.Len(t, sts.Spec.Template.Spec.InitContainers, 0) - require.Len(t, sts.Spec.Template.Spec.Containers, 2) + require.Len(t, sts.Spec.Template.Spec.Containers, 3) // Version from OM + operator version assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1_9.9.9-test", sts.Spec.Template.Spec.Containers[0].Image) diff --git a/controllers/operator/mongodbshardedcluster_controller_test.go b/controllers/operator/mongodbshardedcluster_controller_test.go index 8404ebabb..802447439 100644 --- a/controllers/operator/mongodbshardedcluster_controller_test.go +++ b/controllers/operator/mongodbshardedcluster_controller_test.go @@ -319,7 +319,7 @@ func TestShardedClusterReconcileContainerImagesWithStaticArchitecture(t *testing assert.NoError(t, err) assert.Len(t, sts.Spec.Template.Spec.InitContainers, 0) - require.Len(t, sts.Spec.Template.Spec.Containers, 2) + require.Len(t, sts.Spec.Template.Spec.Containers, 3) // Version from OM + operator version assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1_9.9.9-test", sts.Spec.Template.Spec.Containers[0].Image) diff --git a/controllers/operator/mongodbstandalone_controller_test.go b/controllers/operator/mongodbstandalone_controller_test.go index 1663b24bd..220c0655d 100644 --- a/controllers/operator/mongodbstandalone_controller_test.go +++ b/controllers/operator/mongodbstandalone_controller_test.go @@ -128,7 +128,7 @@ func TestStandaloneClusterReconcileContainerImagesWithStaticArchitecture(t *test assert.NoError(t, err) assert.Len(t, sts.Spec.Template.Spec.InitContainers, 0) - require.Len(t, sts.Spec.Template.Spec.Containers, 2) + require.Len(t, sts.Spec.Template.Spec.Containers, 3) // Version from OM + operator version assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1_9.9.9-test", sts.Spec.Template.Spec.Containers[0].Image) From 99a1ec870481bc29130f0c3bd4f5f8547b7c1374 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 13:20:44 +0200 Subject: [PATCH 06/49] remove operator suffix --- controllers/operator/common_controller.go | 5 +- .../construct/database_construction.go | 77 ++++++------------- 2 files changed, 25 insertions(+), 57 deletions(-) diff --git a/controllers/operator/common_controller.go b/controllers/operator/common_controller.go index 3fb753d47..bf9cf2ec0 100644 --- a/controllers/operator/common_controller.go +++ b/controllers/operator/common_controller.go @@ -47,7 +47,6 @@ import ( "github.com/mongodb/mongodb-kubernetes/pkg/util/architectures" "github.com/mongodb/mongodb-kubernetes/pkg/util/env" "github.com/mongodb/mongodb-kubernetes/pkg/util/stringutil" - "github.com/mongodb/mongodb-kubernetes/pkg/util/versionutil" "github.com/mongodb/mongodb-kubernetes/pkg/vault" ) @@ -684,9 +683,7 @@ func (r *ReconcileCommonController) getAgentVersion(conn om.Connection, omVersio return "", err } else { log.Debugf("Using agent version %s", agentVersion) - currentOperatorVersion := versionutil.StaticContainersOperatorVersion() - log.Debugf("Using Operator version: %s", currentOperatorVersion) - return agentVersion + "_" + currentOperatorVersion, nil + return agentVersion, nil } } diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index b1b010785..9a8d9a336 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -665,11 +665,14 @@ func getVolumesAndVolumeMounts(mdb databaseStatefulSetSource, databaseOpts Datab // buildMongoDBPodTemplateSpec constructs the podTemplateSpec for the MongoDB resource func buildMongoDBPodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseStatefulSetSource) podtemplatespec.Modification { + var modifications podtemplatespec.Modification if architectures.IsRunningStaticArchitecture(mdb.GetAnnotations()) { - return buildStaticArchitecturePodTemplateSpec(opts, mdb) + modifications = buildStaticArchitecturePodTemplateSpec(opts, mdb) } else { - return buildNonStaticArchitecturePodTemplateSpec(opts, mdb) + modifications = buildNonStaticArchitecturePodTemplateSpec(opts, mdb) } + sharedModifications := sharedDatabaseConfiguration(opts) + return podtemplatespec.Apply(sharedModifications, modifications) } // buildStaticArchitecturePodTemplateSpec constructs the podTemplateSpec for static architecture @@ -682,12 +685,21 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb container.WithName(util.AgentContainerName), container.WithImage(opts.AgentImage), container.WithEnvs(databaseEnvVars(opts)...), + container.WithArgs([]string{}), + container.WithImagePullPolicy(corev1.PullPolicy(env.ReadOrPanic(util.AutomationAgentImagePullPolicy))), // nolint:forbidigo + container.WithLivenessProbe(DatabaseLivenessProbe()), + container.WithEnvs(startupParametersToAgentFlag(opts.AgentConfig.StartupParameters)), + container.WithEnvs(logConfigurationToEnvVars(opts.AgentConfig.StartupParameters, opts.AdditionalMongodConfig)...), + container.WithEnvs(staticContainersEnvVars(mdb)...), + container.WithEnvs(readinessEnvironmentVariablesToEnvVars(opts.AgentConfig.ReadinessProbe.EnvironmentVariables)...), + container.WithCommand([]string{"/opt/scripts/agent-launcher-shim.sh"}), containerSecurityContext, )} mongodContainerModifications := []func(*corev1.Container){container.Apply( container.WithName(util.DatabaseContainerName), - container.WithArgs([]string{""}), + container.WithArgs([]string{"tail -F -n0 \"${MDB_LOG_FILE_MONGODB}\""}), + container.WithResourceRequirements(buildRequirementsFromPodSpec(*opts.PodSpec)), container.WithImage(opts.MongodbImage), container.WithEnvs(databaseEnvVars(opts)...), container.WithCommand([]string{"bash", "-c", "tail -F -n0 ${MDB_LOG_FILE_MONGODB} mongodb_marker"}), @@ -717,7 +729,6 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb } mods := []podtemplatespec.Modification{ - sharedDatabaseConfiguration(opts, mdb), podtemplatespec.WithServiceAccount(util.MongoDBServiceAccount), podtemplatespec.WithServiceAccount(getServiceAccountName(opts)), podtemplatespec.WithVolumes(volumes), @@ -747,6 +758,12 @@ func buildNonStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, container.WithEnvs(databaseEnvVars(opts)...), container.WithCommand([]string{"/opt/scripts/agent-launcher.sh"}), container.WithVolumeMounts(volumeMounts), + container.WithImagePullPolicy(corev1.PullPolicy(env.ReadOrPanic(util.AutomationAgentImagePullPolicy))), // nolint:forbidigo + container.WithLivenessProbe(DatabaseLivenessProbe()), + container.WithEnvs(startupParametersToAgentFlag(opts.AgentConfig.StartupParameters)), + container.WithEnvs(logConfigurationToEnvVars(opts.AgentConfig.StartupParameters, opts.AdditionalMongodConfig)...), + container.WithEnvs(staticContainersEnvVars(mdb)...), + container.WithEnvs(readinessEnvironmentVariablesToEnvVars(opts.AgentConfig.ReadinessProbe.EnvironmentVariables)...), )} if opts.HostNameOverrideConfigmapName != "" { @@ -762,7 +779,7 @@ func buildNonStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, } mods := []podtemplatespec.Modification{ - sharedDatabaseConfiguration(opts, mdb), + sharedDatabaseConfiguration(opts), podtemplatespec.WithServiceAccount(util.MongoDBServiceAccount), podtemplatespec.WithServiceAccount(getServiceAccountName(opts)), podtemplatespec.WithVolumes(volumes), @@ -790,56 +807,14 @@ func getServiceAccountName(opts DatabaseStatefulSetOptions) string { // sharedDatabaseConfiguration is a function which applies all the shared configuration // between the appDb and MongoDB resources -func sharedDatabaseConfiguration(opts DatabaseStatefulSetOptions, mdb databaseStatefulSetSource) podtemplatespec.Modification { - configurePodSpecSecurityContext, configureContainerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications() +func sharedDatabaseConfiguration(opts DatabaseStatefulSetOptions) podtemplatespec.Modification { + configurePodSpecSecurityContext, _ := podtemplatespec.WithDefaultSecurityContextsModifications() pullSecretsConfigurationFunc := podtemplatespec.NOOP() if pullSecrets, ok := env.Read(util.ImagePullSecrets); ok { // nolint:forbidigo pullSecretsConfigurationFunc = podtemplatespec.WithImagePullSecrets(pullSecrets) } - agentModification := podtemplatespec.WithContainerByIndex(0, - container.Apply( - container.WithResourceRequirements(buildRequirementsFromPodSpec(*opts.PodSpec)), - container.WithPorts([]corev1.ContainerPort{{ContainerPort: opts.ServicePort}}), - container.WithImagePullPolicy(corev1.PullPolicy(env.ReadOrPanic(util.AutomationAgentImagePullPolicy))), // nolint:forbidigo - container.WithLivenessProbe(DatabaseLivenessProbe()), - container.WithEnvs(startupParametersToAgentFlag(opts.AgentConfig.StartupParameters)), - container.WithEnvs(logConfigurationToEnvVars(opts.AgentConfig.StartupParameters, opts.AdditionalMongodConfig)...), - container.WithEnvs(readinessEnvironmentVariablesToEnvVars(opts.AgentConfig.ReadinessProbe.EnvironmentVariables)...), - configureContainerSecurityContext, - ), - ) - - staticMongodModification := podtemplatespec.NOOP() - if architectures.IsRunningStaticArchitecture(mdb.GetAnnotations()) { - // The mongod - staticMongodModification = podtemplatespec.WithContainerByIndex(1, - container.Apply( - container.WithArgs([]string{"tail -F -n0 \"${MDB_LOG_FILE_MONGODB}\""}), - container.WithResourceRequirements(buildRequirementsFromPodSpec(*opts.PodSpec)), - container.WithPorts([]corev1.ContainerPort{{ContainerPort: opts.ServicePort}}), - container.WithImagePullPolicy(corev1.PullPolicy(env.ReadOrPanic(util.AutomationAgentImagePullPolicy))), // nolint:forbidigo - container.WithEnvs(startupParametersToAgentFlag(opts.AgentConfig.StartupParameters)), - container.WithEnvs(logConfigurationToEnvVars(opts.AgentConfig.StartupParameters, opts.AdditionalMongodConfig)...), - configureContainerSecurityContext, - ), - ) - agentModification = podtemplatespec.WithContainerByIndex(0, - container.Apply( - container.WithImagePullPolicy(corev1.PullPolicy(env.ReadOrPanic(util.AutomationAgentImagePullPolicy))), // nolint:forbidigo - container.WithLivenessProbe(DatabaseLivenessProbe()), - container.WithEnvs(startupParametersToAgentFlag(opts.AgentConfig.StartupParameters)), - container.WithEnvs(logConfigurationToEnvVars(opts.AgentConfig.StartupParameters, opts.AdditionalMongodConfig)...), - container.WithEnvs(staticContainersEnvVars(mdb)...), - container.WithEnvs(readinessEnvironmentVariablesToEnvVars(opts.AgentConfig.ReadinessProbe.EnvironmentVariables)...), - container.WithArgs([]string{}), - container.WithCommand([]string{"/opt/scripts/agent-launcher.sh"}), - configureContainerSecurityContext, - ), - ) - } - return podtemplatespec.Apply( podtemplatespec.WithPodLabels(defaultPodLabels(opts.ServiceName, opts.Name)), podtemplatespec.WithTerminationGracePeriodSeconds(util.DefaultPodTerminationPeriodSeconds), @@ -847,10 +822,6 @@ func sharedDatabaseConfiguration(opts DatabaseStatefulSetOptions, mdb databaseSt configurePodSpecSecurityContext, podtemplatespec.WithAffinity(opts.Name, PodAntiAffinityLabelKey, 100), podtemplatespec.WithTopologyKey(opts.PodSpec.GetTopologyKeyOrDefault(), 0), - // The Agent - agentModification, - // AgentLoggingMongodConfig if static container - staticMongodModification, ) } From 7de5edb2ca0b3b04b8c21209e11862febd7c5dc2 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 13:39:55 +0200 Subject: [PATCH 07/49] remove operator suffix from agents --- docker/mongodb-agent-non-matrix/Dockerfile | 60 --------- .../Dockerfile.builder | 11 -- docker/mongodb-agent/Dockerfile | 44 +++---- docker/mongodb-agent/Dockerfile.builder | 40 ++---- inventories/agent.yaml | 114 +++++++++--------- inventories/agent_non_matrix.yaml | 64 ---------- pipeline.py | 58 +++------ 7 files changed, 101 insertions(+), 290 deletions(-) delete mode 100644 docker/mongodb-agent-non-matrix/Dockerfile delete mode 100644 docker/mongodb-agent-non-matrix/Dockerfile.builder delete mode 100644 inventories/agent_non_matrix.yaml diff --git a/docker/mongodb-agent-non-matrix/Dockerfile b/docker/mongodb-agent-non-matrix/Dockerfile deleted file mode 100644 index e1c1caff2..000000000 --- a/docker/mongodb-agent-non-matrix/Dockerfile +++ /dev/null @@ -1,60 +0,0 @@ -ARG imagebase -FROM ${imagebase} as base - -FROM registry.access.redhat.com/ubi9/ubi-minimal - -ARG version - -LABEL name="MongoDB Agent" \ - version="${version}" \ - summary="MongoDB Agent" \ - description="MongoDB Agent" \ - vendor="MongoDB" \ - release="1" \ - maintainer="support@mongodb.com" - -# Replace libcurl-minimal and curl-minimal with the full versions -# https://bugzilla.redhat.com/show_bug.cgi?id=1994521 -RUN microdnf install -y libssh libpsl libbrotli \ - && microdnf download curl libcurl \ - && rpm -Uvh --nodeps --replacefiles "*curl*$( uname -i ).rpm" \ - && microdnf remove -y libcurl-minimal curl-minimal - -RUN microdnf install -y --disableplugin=subscription-manager --setopt=install_weak_deps=0 nss_wrapper -# Copy-pasted from https://www.mongodb.com/docs/manual/tutorial/install-mongodb-enterprise-on-red-hat-tarball/ -RUN microdnf install -y --disableplugin=subscription-manager \ - cyrus-sasl cyrus-sasl-gssapi cyrus-sasl-plain krb5-libs openldap openssl xz-libs -# Dependencies for the Agent -RUN microdnf install -y --disableplugin=subscription-manager --setopt=install_weak_deps=0 \ - net-snmp \ - net-snmp-agent-libs -RUN microdnf install -y --disableplugin=subscription-manager \ - hostname tar gzip procps jq \ - && microdnf upgrade -y \ - && rm -rf /var/lib/apt/lists/* - -RUN mkdir -p /agent \ - && mkdir -p /var/lib/mongodb-mms-automation \ - && mkdir -p /var/log/mongodb-mms-automation/ \ - && chmod -R +wr /var/log/mongodb-mms-automation/ \ - # ensure that the agent user can write the logs in OpenShift - && touch /var/log/mongodb-mms-automation/readiness.log \ - && chmod ugo+rw /var/log/mongodb-mms-automation/readiness.log - - -COPY --from=base /data/mongodb-agent.tar.gz /agent -COPY --from=base /data/mongodb-tools.tgz /agent -COPY --from=base /data/LICENSE /licenses/LICENSE - -RUN tar xfz /agent/mongodb-agent.tar.gz \ - && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ - && chmod +x /agent/mongodb-agent \ - && mkdir -p /var/lib/automation/config \ - && chmod -R +r /var/lib/automation/config \ - && rm /agent/mongodb-agent.tar.gz \ - && rm -r mongodb-mms-automation-agent-* - -RUN tar xfz /agent/mongodb-tools.tgz --directory /var/lib/mongodb-mms-automation/ && rm /agent/mongodb-tools.tgz - -USER 2000 -CMD ["/agent/mongodb-agent", "-cluster=/var/lib/automation/config/automation-config.json"] diff --git a/docker/mongodb-agent-non-matrix/Dockerfile.builder b/docker/mongodb-agent-non-matrix/Dockerfile.builder deleted file mode 100644 index ab929133e..000000000 --- a/docker/mongodb-agent-non-matrix/Dockerfile.builder +++ /dev/null @@ -1,11 +0,0 @@ -FROM scratch - -ARG agent_version -ARG agent_distro -ARG tools_distro -ARG tools_version - -ADD https://mciuploads.s3.amazonaws.com/mms-automation/mongodb-mms-build-agent/builds/automation-agent/prod/mongodb-mms-automation-agent-${agent_version}.${agent_distro}.tar.gz /data/mongodb-agent.tar.gz -ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro}-${tools_version}.tgz /data/mongodb-tools.tgz - -COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index c9f424552..e1c1caff2 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -13,15 +13,6 @@ LABEL name="MongoDB Agent" \ release="1" \ maintainer="support@mongodb.com" -COPY --from=base /data/probe.sh /opt/scripts/probe.sh -COPY --from=base /data/readinessprobe /opt/scripts/readinessprobe -COPY --from=base /data/version-upgrade-hook /opt/scripts/version-upgrade-hook -COPY --from=base /data/agent-launcher-lib.sh /opt/scripts/agent-launcher-lib.sh -COPY --from=base /data/agent-launcher.sh /opt/scripts/agent-launcher.sh -COPY agent-launcher-shim.sh /agent-launcher-shim.sh -RUN chmod +x /agent-launcher-shim.sh -COPY --from=base /data/LICENSE /licenses/LICENSE - # Replace libcurl-minimal and curl-minimal with the full versions # https://bugzilla.redhat.com/show_bug.cgi?id=1994521 RUN microdnf install -y libssh libpsl libbrotli \ @@ -42,25 +33,28 @@ RUN microdnf install -y --disableplugin=subscription-manager \ && microdnf upgrade -y \ && rm -rf /var/lib/apt/lists/* +RUN mkdir -p /agent \ + && mkdir -p /var/lib/mongodb-mms-automation \ + && mkdir -p /var/log/mongodb-mms-automation/ \ + && chmod -R +wr /var/log/mongodb-mms-automation/ \ + # ensure that the agent user can write the logs in OpenShift + && touch /var/log/mongodb-mms-automation/readiness.log \ + && chmod ugo+rw /var/log/mongodb-mms-automation/readiness.log -COPY --from=base /data/mongodb_tools_ubi.tgz /tools/mongodb_tools.tgz -COPY --from=base /data/mongodb_agent_ubi.tgz /agent/mongodb_agent.tgz -RUN tar xfz /tools/mongodb_tools.tgz -RUN mv mongodb-database-tools-*/bin/* /tools -RUN chmod +x /tools/* -RUN rm /tools/mongodb_tools.tgz -RUN rm -rf /mongodb-database-tools-* +COPY --from=base /data/mongodb-agent.tar.gz /agent +COPY --from=base /data/mongodb-tools.tgz /agent +COPY --from=base /data/LICENSE /licenses/LICENSE -RUN tar xfz /agent/mongodb_agent.tgz -RUN mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent -RUN chmod +x /agent/mongodb-agent -RUN rm /agent/mongodb_agent.tgz -RUN rm -rf mongodb-mms-automation-agent-* +RUN tar xfz /agent/mongodb-agent.tar.gz \ + && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ + && chmod +x /agent/mongodb-agent \ + && mkdir -p /var/lib/automation/config \ + && chmod -R +r /var/lib/automation/config \ + && rm /agent/mongodb-agent.tar.gz \ + && rm -r mongodb-mms-automation-agent-* -RUN mkdir -p /var/lib/automation/config -RUN chmod -R +r /var/lib/automation/config +RUN tar xfz /agent/mongodb-tools.tgz --directory /var/lib/mongodb-mms-automation/ && rm /agent/mongodb-tools.tgz USER 2000 - -HEALTHCHECK --timeout=30s CMD ls /opt/scripts/readinessprobe || exit 1 +CMD ["/agent/mongodb-agent", "-cluster=/var/lib/automation/config/automation-config.json"] diff --git a/docker/mongodb-agent/Dockerfile.builder b/docker/mongodb-agent/Dockerfile.builder index bfdf4c969..ab929133e 100644 --- a/docker/mongodb-agent/Dockerfile.builder +++ b/docker/mongodb-agent/Dockerfile.builder @@ -1,37 +1,11 @@ -# the init database image gets supplied by pipeline.py and corresponds to the operator version we want to release -# the agent with. This enables us to release the agent for older operator. -ARG init_database_image -FROM ${init_database_image} as init_database - -FROM public.ecr.aws/docker/library/golang:1.24 as dependency_downloader - -WORKDIR /go/src/github.com/mongodb/mongodb-kubernetes/ - -COPY go.mod go.sum ./ - -RUN go mod download - -FROM public.ecr.aws/docker/library/golang:1.24 as readiness_builder - -WORKDIR /go/src/github.com/mongodb/mongodb-kubernetes/ - -COPY --from=dependency_downloader /go/pkg /go/pkg -COPY . /go/src/github.com/mongodb/mongodb-kubernetes - -RUN CGO_ENABLED=0 GOFLAGS=-buildvcs=false go build -o /readinessprobe ./mongodb-community-operator/cmd/readiness/main.go -RUN CGO_ENABLED=0 GOFLAGS=-buildvcs=false go build -o /version-upgrade-hook ./mongodb-community-operator/cmd/versionhook/main.go - FROM scratch -ARG mongodb_tools_url_ubi -ARG mongodb_agent_url_ubi -COPY --from=readiness_builder /readinessprobe /data/ -COPY --from=readiness_builder /version-upgrade-hook /data/ +ARG agent_version +ARG agent_distro +ARG tools_distro +ARG tools_version -ADD ${mongodb_tools_url_ubi} /data/mongodb_tools_ubi.tgz -ADD ${mongodb_agent_url_ubi} /data/mongodb_agent_ubi.tgz +ADD https://mciuploads.s3.amazonaws.com/mms-automation/mongodb-mms-build-agent/builds/automation-agent/prod/mongodb-mms-automation-agent-${agent_version}.${agent_distro}.tar.gz /data/mongodb-agent.tar.gz +ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro}-${tools_version}.tgz /data/mongodb-tools.tgz -COPY --from=init_database /probes/probe.sh /data/probe.sh -COPY --from=init_database /scripts/agent-launcher-lib.sh /data/ -COPY --from=init_database /scripts/agent-launcher.sh /data/ -COPY --from=init_database /licenses/LICENSE /data/ +COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE diff --git a/inventories/agent.yaml b/inventories/agent.yaml index 3e7fa7d00..b2d0aaae1 100644 --- a/inventories/agent.yaml +++ b/inventories/agent.yaml @@ -3,58 +3,62 @@ vars: s3_bucket: s3://enterprise-operator-dockerfiles/dockerfiles/mongodb-agent images: -- name: mongodb-agent - vars: - context: . - template_context: docker/mongodb-agent - platform: linux/amd64 - - stages: - - name: mongodb-agent-build-context - task_type: docker_build - dockerfile: docker/mongodb-agent/Dockerfile.builder - buildargs: - mongodb_tools_url_ubi: $(inputs.params.mongodb_tools_url_ubi) - mongodb_agent_url_ubi: $(inputs.params.mongodb_agent_url_ubi) - init_database_image: $(inputs.params.init_database_image) - output: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version)-context - - - name: mongodb-agent-build-context-release - task_type: docker_build - tags: ["release"] - dockerfile: docker/mongodb-agent/Dockerfile.builder - buildargs: - mongodb_tools_url_ubi: $(inputs.params.mongodb_tools_url_ubi) - mongodb_agent_url_ubi: $(inputs.params.mongodb_agent_url_ubi) - init_database_image: $(inputs.params.init_database_image) - output: - - registry: $(inputs.params.quay_registry) - tag: $(inputs.params.version)-context - - - name: mongodb-agent-build-ubi - task_type: docker_build - buildargs: - imagebase: $(inputs.params.registry)/mongodb-agent-ubi:$(inputs.params.version)-context - version: $(inputs.params.version) - dockerfile: docker/mongodb-agent/Dockerfile - output: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version) - - - name: master-latest - task_type: tag_image - tags: [ "master" ] - source: - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version) - destination: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.agent_version)_latest - - - name: mongodb-agent-template-ubi - task_type: dockerfile_template - tags: ["release"] - output: - - dockerfile: $(inputs.params.s3_bucket)/$(inputs.params.version)/ubi/Dockerfile + - name: mongodb-agent + vars: + context: . + template_context: docker/mongodb-agent-non-matrix + + platform: linux/$(inputs.params.architecture) + stages: + - name: mongodb-agent-context + task_type: docker_build + dockerfile: docker/mongodb-agent-non-matrix/Dockerfile.builder + tags: [ "ubi" ] + buildargs: + agent_version: $(inputs.params.version) + tools_version: $(inputs.params.tools_version) + agent_distro: $(inputs.params.agent_distro) + tools_distro: $(inputs.params.tools_distro) + + labels: + quay.expires-after: 48h + + output: + - registry: $(inputs.params.registry)/mongodb-agent-ubi + tag: $(inputs.params.version)-context-$(inputs.params.architecture) + + - name: mongodb-agent-build-context-release + task_type: docker_build + tags: ["release"] + dockerfile: docker/mongodb-agent-non-matrix/Dockerfile.builder + buildargs: + agent_version: $(inputs.params.version) + tools_version: $(inputs.params.tools_version) + agent_distro: $(inputs.params.agent_distro) + tools_distro: $(inputs.params.tools_distro) + output: + - registry: $(inputs.params.quay_registry) + tag: $(inputs.params.version)-context-$(inputs.params.architecture) + + - name: mongodb-agent-build + task_type: docker_build + tags: [ "ubi" ] + buildargs: + imagebase: $(inputs.params.registry)/mongodb-agent-ubi:$(inputs.params.version)-context-$(inputs.params.architecture) + version: $(inputs.params.version) + dockerfile: docker/mongodb-agent-non-matrix/Dockerfile + + labels: + quay.expires-after: 48h + + output: + - registry: $(inputs.params.registry)/mongodb-agent-ubi + tag: $(inputs.params.version)-$(inputs.params.architecture) + - registry: $(inputs.params.registry)/mongodb-agent-ubi + tag: latest-$(inputs.params.architecture) + + - name: mongodb-agent-template-ubi + task_type: dockerfile_template + tags: ["release"] + output: + - dockerfile: $(inputs.params.s3_bucket)/$(inputs.params.version)/ubi/Dockerfile diff --git a/inventories/agent_non_matrix.yaml b/inventories/agent_non_matrix.yaml deleted file mode 100644 index 21df88d92..000000000 --- a/inventories/agent_non_matrix.yaml +++ /dev/null @@ -1,64 +0,0 @@ -vars: - quay_registry: quay.io/mongodb/mongodb-agent-ubi - s3_bucket: s3://enterprise-operator-dockerfiles/dockerfiles/mongodb-agent - -images: - - name: mongodb-agent - vars: - context: . - template_context: docker/mongodb-agent-non-matrix - - platform: linux/$(inputs.params.architecture) - stages: - - name: mongodb-agent-context - task_type: docker_build - dockerfile: docker/mongodb-agent-non-matrix/Dockerfile.builder - tags: [ "ubi" ] - buildargs: - agent_version: $(inputs.params.version) - tools_version: $(inputs.params.tools_version) - agent_distro: $(inputs.params.agent_distro) - tools_distro: $(inputs.params.tools_distro) - - labels: - quay.expires-after: 48h - - output: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version)-context-$(inputs.params.architecture) - - - name: mongodb-agent-build-context-release - task_type: docker_build - tags: ["release"] - dockerfile: docker/mongodb-agent-non-matrix/Dockerfile.builder - buildargs: - agent_version: $(inputs.params.version) - tools_version: $(inputs.params.tools_version) - agent_distro: $(inputs.params.agent_distro) - tools_distro: $(inputs.params.tools_distro) - output: - - registry: $(inputs.params.quay_registry) - tag: $(inputs.params.version)-context-$(inputs.params.architecture) - - - name: mongodb-agent-build - task_type: docker_build - tags: [ "ubi" ] - buildargs: - imagebase: $(inputs.params.registry)/mongodb-agent-ubi:$(inputs.params.version)-context-$(inputs.params.architecture) - version: $(inputs.params.version) - dockerfile: docker/mongodb-agent-non-matrix/Dockerfile - - labels: - quay.expires-after: 48h - - output: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version)-$(inputs.params.architecture) - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: latest-$(inputs.params.architecture) - - - name: mongodb-agent-template-ubi - task_type: dockerfile_template - tags: ["release"] - output: - - dockerfile: $(inputs.params.s3_bucket)/$(inputs.params.version)/ubi/Dockerfile \ No newline at end of file diff --git a/pipeline.py b/pipeline.py index d2fc46fcf..2dcef8d26 100755 --- a/pipeline.py +++ b/pipeline.py @@ -1153,7 +1153,6 @@ def build_upgrade_hook_image(build_configuration: BuildConfiguration): def build_agent_in_sonar( build_configuration: BuildConfiguration, image_version, - init_database_image, mongodb_tools_url_ubi, mongodb_agent_url_ubi: str, agent_version, @@ -1162,7 +1161,6 @@ def build_agent_in_sonar( "version": image_version, "mongodb_tools_url_ubi": mongodb_tools_url_ubi, "mongodb_agent_url_ubi": mongodb_agent_url_ubi, - "init_database_image": init_database_image, } agent_quay_registry = QUAY_REGISTRY_URL + f"/mongodb-agent-ubi" @@ -1228,7 +1226,7 @@ def build_multi_arch_agent_in_sonar( build_image_generic( config=build_configuration, image_name="mongodb-agent", - inventory_file="inventories/agent_non_matrix.yaml", + inventory_file="inventories/agent.yaml", multi_arch_args_list=joined_args, registry_address=quay_agent_registry if is_release else ecr_agent_registry, is_multi_arch=True, # We for pushing manifest anyway, even if arm64 is skipped in patches @@ -1242,19 +1240,18 @@ def build_agent_default_case(build_configuration: BuildConfiguration): See more information in the function: build_agent_on_agent_bump """ - release = get_release() + release_json = get_release() - operator_version = get_git_release_tag() is_release = build_configuration.is_release_step_executed() # We need to release [all agents x latest operator] on operator releases if is_release: - agent_versions_to_build = gather_all_supported_agent_versions(release) + agent_versions_to_build = gather_all_supported_agent_versions(release_json) # We only need [latest agents (for each OM major version and for CM) x patch ID] for patches else: - agent_versions_to_build = gather_latest_agent_versions(release) + agent_versions_to_build = gather_latest_agent_versions(release_json) - logger.info(f"Building Agent versions: {agent_versions_to_build} for Operator versions: {operator_version}") + logger.info(f"Building Agent versions: {agent_versions_to_build}") tasks_queue = Queue() max_workers = 1 @@ -1276,8 +1273,8 @@ def build_agent_default_case(build_configuration: BuildConfiguration): agent_version[1], ) ) - _build_agent_operator( - agent_version, build_configuration, executor, operator_version, tasks_queue, is_release + _add_to_agent_queue( + agent_version, build_configuration, executor, tasks_queue ) queue_exception_handling(tasks_queue) @@ -1292,18 +1289,12 @@ def build_agent_on_agent_bump(build_configuration: BuildConfiguration): - operator releases - OM/CM bumps via PCT - We don't require building a full matrix on e2e test runs and operator releases. - "Operator releases" and "e2e test runs" require only the latest operator x agents - - In OM/CM bumps, we release a new agent which we potentially require to release to older operators as well. - This function takes care of that. + In OM/CM bumps, we release a new agent. """ release = get_release() is_release = build_configuration.is_release_step_executed() if build_configuration.all_agents: - # We need to release [all agents x latest operator] on operator releases to make e2e tests work - # This was changed previously in https://github.com/mongodb/mongodb-kubernetes/pull/3960 agent_versions_to_build = gather_all_supported_agent_versions(release) else: # we only need to release the latest images, we don't need to re-push old images, as we don't clean them up anymore. @@ -1346,11 +1337,10 @@ def build_agent_on_agent_bump(build_configuration: BuildConfiguration): agent_version[1], ) ) - for operator_version in get_supported_operator_versions(): - logger.info(f"Building Agent versions: {agent_version} for Operator versions: {operator_version}") - _build_agent_operator( - agent_version, build_configuration, executor, operator_version, tasks_queue, is_release - ) + logger.info(f"Building Agent versions: {agent_version}") + _add_to_agent_queue( + agent_version, build_configuration, executor, tasks_queue + ) queue_exception_handling(tasks_queue) @@ -1386,37 +1376,21 @@ def queue_exception_handling(tasks_queue): ) -def _build_agent_operator( +def _add_to_agent_queue( agent_version: Tuple[str, str], build_configuration: BuildConfiguration, executor: ProcessPoolExecutor, - operator_version: str, tasks_queue: Queue, - use_quay: bool = False, ): - agent_distro = "rhel9_x86_64" tools_version = agent_version[1] - tools_distro = get_tools_distro(tools_version)["amd"] - image_version = f"{agent_version[0]}_{operator_version}" - mongodb_tools_url_ubi = ( - f"https://downloads.mongodb.org/tools/db/mongodb-database-tools-{tools_distro}-{tools_version}.tgz" - ) - mongodb_agent_url_ubi = f"https://mciuploads.s3.amazonaws.com/mms-automation/mongodb-mms-build-agent/builds/automation-agent/prod/mongodb-mms-automation-agent-{agent_version[0]}.{agent_distro}.tar.gz" - # We use Quay if not in a patch - # We could rely on input params (quay_registry or registry), but it makes templating more complex in the inventory - non_quay_registry = os.environ.get("REGISTRY", "268558157000.dkr.ecr.us-east-1.amazonaws.com/dev") - base_init_database_repo = QUAY_REGISTRY_URL if use_quay else non_quay_registry - init_database_image = f"{base_init_database_repo}/mongodb-kubernetes-init-database:{operator_version}" + image_version = f"{agent_version[0]}" tasks_queue.put( executor.submit( - build_agent_in_sonar, + build_multi_arch_agent_in_sonar, build_configuration, image_version, - init_database_image, - mongodb_tools_url_ubi, - mongodb_agent_url_ubi, - agent_version[0], + tools_version, ) ) From ac515aa27888e49cde30ec374b2264077034b7bc Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 14:19:24 +0200 Subject: [PATCH 08/49] remove init container dep and fix agent yaml --- .evergreen.yml | 3 --- inventories/agent.yaml | 8 ++++---- pipeline.py | 8 ++++++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.evergreen.yml b/.evergreen.yml index 058c0ea1f..e3223f121 100644 --- a/.evergreen.yml +++ b/.evergreen.yml @@ -462,9 +462,6 @@ tasks: skip_tags: ubuntu,release - name: build_agent_images_ubi - depends_on: - - name: build_init_database_image_ubi - variant: init_test_run commands: - func: clone - func: setup_building_host diff --git a/inventories/agent.yaml b/inventories/agent.yaml index b2d0aaae1..69959adae 100644 --- a/inventories/agent.yaml +++ b/inventories/agent.yaml @@ -6,13 +6,13 @@ images: - name: mongodb-agent vars: context: . - template_context: docker/mongodb-agent-non-matrix + template_context: docker/mongodb-agent platform: linux/$(inputs.params.architecture) stages: - name: mongodb-agent-context task_type: docker_build - dockerfile: docker/mongodb-agent-non-matrix/Dockerfile.builder + dockerfile: docker/mongodb-agent/Dockerfile.builder tags: [ "ubi" ] buildargs: agent_version: $(inputs.params.version) @@ -30,7 +30,7 @@ images: - name: mongodb-agent-build-context-release task_type: docker_build tags: ["release"] - dockerfile: docker/mongodb-agent-non-matrix/Dockerfile.builder + dockerfile: docker/mongodb-agent/Dockerfile.builder buildargs: agent_version: $(inputs.params.version) tools_version: $(inputs.params.tools_version) @@ -46,7 +46,7 @@ images: buildargs: imagebase: $(inputs.params.registry)/mongodb-agent-ubi:$(inputs.params.version)-context-$(inputs.params.architecture) version: $(inputs.params.version) - dockerfile: docker/mongodb-agent-non-matrix/Dockerfile + dockerfile: docker/mongodb-agent/Dockerfile labels: quay.expires-after: 48h diff --git a/pipeline.py b/pipeline.py index 2dcef8d26..e38df2c75 100755 --- a/pipeline.py +++ b/pipeline.py @@ -306,10 +306,14 @@ def create_and_push_manifest(image: str, tag: str, architectures: list[str]) -> This method calls docker directly on the command line, this is different from the rest of the code which uses Sonar as an interface to docker. We decided to keep this asymmetry for now, as Sonar will be removed soon. """ + docker_cmd = shutil.which("docker") + if docker_cmd is None: + raise Exception("Docker executable not found in PATH") + final_manifest = image + ":" + tag args = [ - "docker", + docker_cmd, "manifest", "create", final_manifest, @@ -325,7 +329,7 @@ def create_and_push_manifest(image: str, tag: str, architectures: list[str]) -> if cp.returncode != 0: raise Exception(cp.stderr) - args = ["docker", "manifest", "push", final_manifest] + args = [docker_cmd, "manifest", "push", final_manifest] args_str = " ".join(args) logger.info(f"pushing new manifest: {args_str}") cp = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) From 8a325819c9e609caf8e5de67abfe9fa6884e7859 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 16:28:43 +0200 Subject: [PATCH 09/49] make docker work locally and make agent building work locally --- docker/mongodb-agent/Dockerfile.builder | 1 + lib/sonar/builders/docker.py | 14 +- pipeline.py | 174 +++++++++++------------- 3 files changed, 95 insertions(+), 94 deletions(-) diff --git a/docker/mongodb-agent/Dockerfile.builder b/docker/mongodb-agent/Dockerfile.builder index ab929133e..3a15e7e15 100644 --- a/docker/mongodb-agent/Dockerfile.builder +++ b/docker/mongodb-agent/Dockerfile.builder @@ -9,3 +9,4 @@ ADD https://mciuploads.s3.amazonaws.com/mms-automation/mongodb-mms-build-agent/b ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro}-${tools_version}.tgz /data/mongodb-tools.tgz COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE +COPY ./docker/mongodb-agent/agent-launcher-shim.sh /opt/scripts diff --git a/lib/sonar/builders/docker.py b/lib/sonar/builders/docker.py index 80a5daf8b..14c2bf91a 100644 --- a/lib/sonar/builders/docker.py +++ b/lib/sonar/builders/docker.py @@ -1,4 +1,5 @@ import random +import shutil import subprocess from typing import Dict, Optional @@ -101,7 +102,12 @@ def get_docker_build_cli_args( labels=Optional[Dict[str, str]], platform=Optional[str], ): - args = ["docker", "buildx", "build", "--load", "--progress", "plain", path, "-f", dockerfile, "-t", tag] + # Find docker executable dynamically to work across different environments + docker_cmd = shutil.which("docker") + if docker_cmd is None: + raise Exception("Docker executable not found in PATH") + + args = [docker_cmd, "buildx", "build", "--load", "--progress", "plain", path, "-f", dockerfile, "-t", tag] if buildargs is not None: for k, v in buildargs.items(): args.append("--build-arg") @@ -174,13 +180,17 @@ def check_registry_image_exists(repository, tag): @TRACER.start_as_current_span("docker_push") def docker_push(registry: str, tag: str): + docker_cmd = shutil.which("docker") + if docker_cmd is None: + raise Exception("Docker executable not found in PATH") + def inner_docker_push(should_raise=False): # We can't use docker-py here # as it doesn't support DOCKER_CONTENT_TRUST # env variable, which could be needed cp = subprocess.run( - ["docker", "push", f"{registry}:{tag}"], + [docker_cmd, "push", f"{registry}:{tag}"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, ) diff --git a/pipeline.py b/pipeline.py index e38df2c75..ee5c59013 100755 --- a/pipeline.py +++ b/pipeline.py @@ -14,6 +14,7 @@ import sys import tarfile import time +import traceback from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor from dataclasses import dataclass from datetime import datetime, timedelta, timezone @@ -110,6 +111,7 @@ class BuildConfiguration: architecture: Optional[List[str]] = None sign: bool = False all_agents: bool = False + agent_to_build: str = "" pipeline: bool = True debug: bool = True @@ -163,6 +165,7 @@ def operator_build_configuration( sign: bool = False, all_agents: bool = False, parallel_factor: int = 0, + agent_to_build: str = "", ) -> BuildConfiguration: bc = BuildConfiguration( image_type=os.environ.get("distro", DEFAULT_IMAGE_TYPE), @@ -177,6 +180,7 @@ def operator_build_configuration( architecture=architecture, sign=sign, parallel_factor=parallel_factor, + agent_to_build=agent_to_build, ) logger.info(f"is_running_in_patch: {is_running_in_patch()}") @@ -527,14 +531,10 @@ def build_operator_image(build_configuration: BuildConfiguration): current_span.set_attribute("mck.image_name", image_name) current_span.set_attribute("mck.architecture", architectures) - ecr_registry = os.environ.get("BASE_REPO_URL", "268558157000.dkr.ecr.us-east-1.amazonaws.com/dev") - base_repo = QUAY_REGISTRY_URL if build_configuration.is_release_step_executed() else ecr_registry - build_image_generic( config=build_configuration, image_name=image_name, inventory_file="inventory.yaml", - registry_address=f"{base_repo}/{image_name}", multi_arch_args_list=multi_arch_args_list, is_multi_arch=True, ) @@ -676,7 +676,6 @@ def args_for_daily_image(image_name: str) -> Dict[str, str]: image_config("init-ops-manager", ubi_suffix=""), image_config("mongodb-kubernetes", name_prefix="", ubi_suffix=""), image_config("ops-manager", name_prefix="mongodb-enterprise-"), - image_config("mongodb-agent", name_prefix="", ubi_suffix="-ubi", base_suffix="-ubi"), image_config( image_name="mongodb-kubernetes-operator", name_prefix="", @@ -694,6 +693,13 @@ def args_for_daily_image(image_name: str) -> Dict[str, str]: ubi_suffix="", s3_bucket="enterprise-operator-dockerfiles", ), + image_config( + image_name="mongodb-agent", + name_prefix="", + s3_bucket="enterprise-operator-dockerfiles", + ubi_suffix="-ubi", + base_suffix="-ubi", + ), ] images = {k: v for k, v in image_configs} @@ -1026,53 +1032,52 @@ def build_image_generic( it signs and verifies the context image. The release process uses the daily images build process. """ + try: + if not multi_arch_args_list: + multi_arch_args_list = [extra_args or {}] - if not multi_arch_args_list: - multi_arch_args_list = [extra_args or {}] - - version = multi_arch_args_list[0].get("version", "") # the version is the same in multi-arch for each item - registry = f"{QUAY_REGISTRY_URL}/mongodb-kubernetes-{image_name}" if not registry_address else registry_address - - for args in multi_arch_args_list: # in case we are building multiple architectures - args["quay_registry"] = registry - sonar_build_image(image_name, config, args, inventory_file, False) - if is_multi_arch: - # we only push the manifests of the context images here, - # since daily rebuilds will push the manifests for the proper images later - architectures = [v["architecture"] for v in multi_arch_args_list] - create_and_push_manifest(registry_address, f"{version}-context", architectures=architectures) - if not config.is_release_step_executed(): - # Normally daily rebuild would create and push the manifests for the non-context images. - # But since we don't run daily rebuilds on ecr image builds, we can do that step instead here. - # We only need to push manifests for multi-arch images. - create_and_push_manifest(registry_address, version, architectures=architectures) - - # Sign and verify the context image if on releases if requied. - if config.sign and config.is_release_step_executed(): - sign_and_verify_context_image(registry, version) + version = multi_arch_args_list[0].get("version", "") + if config.is_release_step_executed(): + registry = f"{QUAY_REGISTRY_URL}/mongodb-kubernetes-{image_name}" + else: + registry = f"{config.base_repository}/mongodb-kubernetes-{image_name}" - span = trace.get_current_span() - span.set_attribute("mck.image.image_name", image_name) - span.set_attribute("mck.image.version", version) - span.set_attribute("mck.image.is_release", config.is_release_step_executed()) - span.set_attribute("mck.image.is_multi_arch", is_multi_arch) + if registry_address: + registry = registry_address - # Release step. Release images via the daily image process. - if config.is_release_step_executed() and version and QUAY_REGISTRY_URL in registry: - logger.info( - f"finished building context images, releasing them now via daily builds process for" - f" image: {image_name} and version: {version}!" - ) - # Sleep for a random time between 0 and 5 seconds to distribute daily builds better, - # as we do a lot of things there that require network connections like: - # - Kondukto uploads, downloads - # - image verification and signings - # - manifest creations - # - docker image pushes - # - etc. - if is_run_in_parallel: - time.sleep(random.uniform(0, 5)) - build_image_daily(image_name, version, version)(config) + for args in multi_arch_args_list: + sonar_build_image(image_name, config, args, inventory_file, False) + + if is_multi_arch: + architectures = [v["architecture"] for v in multi_arch_args_list] + create_and_push_manifest(registry, f"{version}-context", architectures=architectures) + if not config.is_release_step_executed(): + create_and_push_manifest(registry, version, architectures=architectures) + + if config.sign and config.is_release_step_executed(): + sign_and_verify_context_image(registry, version) + + span = trace.get_current_span() + span.set_attribute("mck.image.image_name", image_name) + span.set_attribute("mck.image.version", version) + span.set_attribute("mck.image.is_release", config.is_release_step_executed()) + span.set_attribute("mck.image.is_multi_arch", is_multi_arch) + + if config.is_release_step_executed() and version and QUAY_REGISTRY_URL in registry: + logger.info( + f"finished building context images, releasing them now via daily builds process for" + f" image: {image_name} and version: {version}!" + ) + if is_run_in_parallel: + time.sleep(random.uniform(0, 5)) + build_image_daily(image_name, version, version)(config) + + except Exception as e: + logger.error(f"Error during build_image_generic for image {image_name}: {e}") + logger.error(f"Full traceback for build_image_generic error:") + for line in traceback.format_exception(type(e), e, e.__traceback__): + logger.error(line.rstrip()) + raise def sign_and_verify_context_image(registry, version): @@ -1127,15 +1132,11 @@ def build_community_image(build_configuration: BuildConfiguration, image_type: s } multi_arch_args_list.append(arch_args) - ecr_registry = os.environ.get("BASE_REPO_URL", "268558157000.dkr.ecr.us-east-1.amazonaws.com/dev") - base_repo = QUAY_REGISTRY_URL if build_configuration.is_release_step_executed() else ecr_registry - build_image_generic( config=build_configuration, image_name=image_name, multi_arch_args_list=multi_arch_args_list, inventory_file=inventory_file, - registry_address=f"{base_repo}/{image_name}", is_multi_arch=True, # We for pushing manifest anyway, even if arm64 is skipped in patches ) @@ -1154,33 +1155,6 @@ def build_upgrade_hook_image(build_configuration: BuildConfiguration): build_community_image(build_configuration, "upgrade-hook") -def build_agent_in_sonar( - build_configuration: BuildConfiguration, - image_version, - mongodb_tools_url_ubi, - mongodb_agent_url_ubi: str, - agent_version, -): - args = { - "version": image_version, - "mongodb_tools_url_ubi": mongodb_tools_url_ubi, - "mongodb_agent_url_ubi": mongodb_agent_url_ubi, - } - - agent_quay_registry = QUAY_REGISTRY_URL + f"/mongodb-agent-ubi" - args["quay_registry"] = agent_quay_registry - args["agent_version"] = agent_version - - build_image_generic( - config=build_configuration, - image_name="mongodb-agent", - inventory_file="inventories/agent.yaml", - extra_args=args, - registry_address=agent_quay_registry, - is_run_in_parallel=True, - ) - - def build_multi_arch_agent_in_sonar( build_configuration: BuildConfiguration, image_version, @@ -1218,8 +1192,7 @@ def build_multi_arch_agent_in_sonar( arch_arm["tools_distro"] = "rhel93-aarch64" arch_amd["tools_distro"] = "rhel93-x86_64" - ecr_registry = os.environ.get("REGISTRY", "268558157000.dkr.ecr.us-east-1.amazonaws.com/dev") - ecr_agent_registry = ecr_registry + f"/mongodb-agent-ubi" + ecr_agent_registry = build_configuration.base_repository + f"/mongodb-agent-ubi" quay_agent_registry = QUAY_REGISTRY_URL + f"/mongodb-agent-ubi" joined_args = [args | arch_amd] @@ -1232,7 +1205,7 @@ def build_multi_arch_agent_in_sonar( image_name="mongodb-agent", inventory_file="inventories/agent.yaml", multi_arch_args_list=joined_args, - registry_address=quay_agent_registry if is_release else ecr_agent_registry, + registry_address=quay_agent_registry if is_release else ecr_agent_registry, # this is usually done by the method but it doesn't work for agent images as it follows their own naming pattern is_multi_arch=True, # We for pushing manifest anyway, even if arm64 is skipped in patches is_run_in_parallel=True, ) @@ -1253,7 +1226,7 @@ def build_agent_default_case(build_configuration: BuildConfiguration): agent_versions_to_build = gather_all_supported_agent_versions(release_json) # We only need [latest agents (for each OM major version and for CM) x patch ID] for patches else: - agent_versions_to_build = gather_latest_agent_versions(release_json) + agent_versions_to_build = gather_latest_agent_versions(release_json, build_configuration.agent_to_build) logger.info(f"Building Agent versions: {agent_versions_to_build}") @@ -1295,16 +1268,16 @@ def build_agent_on_agent_bump(build_configuration: BuildConfiguration): In OM/CM bumps, we release a new agent. """ - release = get_release() + release_json = get_release() is_release = build_configuration.is_release_step_executed() if build_configuration.all_agents: - agent_versions_to_build = gather_all_supported_agent_versions(release) + agent_versions_to_build = gather_all_supported_agent_versions(release_json) else: # we only need to release the latest images, we don't need to re-push old images, as we don't clean them up anymore. - agent_versions_to_build = gather_latest_agent_versions(release) + agent_versions_to_build = gather_latest_agent_versions(release_json, build_configuration.agent_to_build) - legacy_agent_versions_to_build = release["supportedImages"]["mongodb-agent"]["versions"] + legacy_agent_versions_to_build = release_json["supportedImages"]["mongodb-agent"]["versions"] tasks_queue = Queue() max_workers = 1 @@ -1365,7 +1338,12 @@ def queue_exception_handling(tasks_queue): exceptions_found = True exception_count += 1 exception_types.add(type(task.exception()).__name__) - logger.fatal(f"The following exception has been found when building: {task.exception()}") + + exception_info = task.exception() + logger.fatal(f"=== THREAD EXCEPTION DETAILS ===") + logger.fatal(f"Exception Type: {type(exception_info).__name__}") + logger.fatal(f"Exception Message: {str(exception_info)}") + logger.fatal(f"=== END THREAD EXCEPTION DETAILS ===") span.set_attribute("mck.agent.queue.exceptions_count", exception_count) span.set_attribute( @@ -1415,7 +1393,7 @@ def gather_all_supported_agent_versions(release: Dict) -> List[Tuple[str, str]]: return sorted(list(set(agent_versions_to_build))) -def gather_latest_agent_versions(release: Dict) -> List[Tuple[str, str]]: +def gather_latest_agent_versions(release: Dict, agent_to_build: str = "") -> List[Tuple[str, str]]: """ This function is used when we release a new agent via OM bump. That means we will need to release that agent with all supported operators. @@ -1457,6 +1435,11 @@ def gather_latest_agent_versions(release: Dict) -> List[Tuple[str, str]]: # https://jira.mongodb.org/browse/CLOUDP-297377 agent_versions_to_build.append(("107.0.12.8669-1", "100.10.0")) + if agent_to_build != "": + for agent_tuple in agent_versions_to_build: + if agent_tuple[0] == agent_to_build: + return [agent_tuple] + return sorted(list(set(agent_versions_to_build))) @@ -1545,11 +1528,12 @@ def build_all_images( architecture: Optional[List[str]] = None, sign: bool = False, all_agents: bool = False, + agent_to_build: str = "", parallel_factor: int = 0, ): """Builds all the images in the `images` list.""" build_configuration = operator_build_configuration( - builder, parallel, debug, architecture, sign, all_agents, parallel_factor + builder, parallel, debug, architecture, sign, all_agents, parallel_factor, agent_to_build ) if sign: mongodb_artifactory_login() @@ -1612,7 +1596,12 @@ def main(): action="store_true", default=False, help="optional parameter to be able to push " - "all non operator suffixed agents, even if we are not in a release", + "all non operator suffixed agents, even if we are not in a release", + ) + parser.add_argument( + "--build-one-agent", + default="", + help="optional parameter to push one agent", ) args = parser.parse_args() @@ -1639,6 +1628,7 @@ def main(): architecture=args.arch, sign=args.sign, all_agents=args.all_agents, + agent_to_build=args.build_one_agent, parallel_factor=args.parallel_factor, ) From ed9d21c53d98b639f66367918f6809128991cc76 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 16:47:48 +0200 Subject: [PATCH 10/49] make docker work locally and make agent building work locally --- docker/mongodb-agent/Dockerfile | 2 ++ docker/mongodb-agent/Dockerfile.builder | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index e1c1caff2..a0d0c66a4 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -41,10 +41,12 @@ RUN mkdir -p /agent \ && touch /var/log/mongodb-mms-automation/readiness.log \ && chmod ugo+rw /var/log/mongodb-mms-automation/readiness.log +RUN mkdir -p /opt/scripts COPY --from=base /data/mongodb-agent.tar.gz /agent COPY --from=base /data/mongodb-tools.tgz /agent COPY --from=base /data/LICENSE /licenses/LICENSE +COPY --from=base /data/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh RUN tar xfz /agent/mongodb-agent.tar.gz \ && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ diff --git a/docker/mongodb-agent/Dockerfile.builder b/docker/mongodb-agent/Dockerfile.builder index 3a15e7e15..22632fdfa 100644 --- a/docker/mongodb-agent/Dockerfile.builder +++ b/docker/mongodb-agent/Dockerfile.builder @@ -9,4 +9,4 @@ ADD https://mciuploads.s3.amazonaws.com/mms-automation/mongodb-mms-build-agent/b ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro}-${tools_version}.tgz /data/mongodb-tools.tgz COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE -COPY ./docker/mongodb-agent/agent-launcher-shim.sh /opt/scripts +COPY ./docker/mongodb-agent/agent-launcher-shim.sh /data/agent-launcher-shim.sh From 52a14f89d2f4491a81b214e5f9358e0ee7009f0e Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 17:00:15 +0200 Subject: [PATCH 11/49] make docker work locally and make agent building work locally --- docker/mongodb-agent/Dockerfile | 2 +- docker/mongodb-agent/Dockerfile.builder | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index a0d0c66a4..afc715846 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -46,7 +46,7 @@ RUN mkdir -p /opt/scripts COPY --from=base /data/mongodb-agent.tar.gz /agent COPY --from=base /data/mongodb-tools.tgz /agent COPY --from=base /data/LICENSE /licenses/LICENSE -COPY --from=base /data/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh +COPY --from=base /opt/scripts/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh RUN tar xfz /agent/mongodb-agent.tar.gz \ && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ diff --git a/docker/mongodb-agent/Dockerfile.builder b/docker/mongodb-agent/Dockerfile.builder index 22632fdfa..979f593ff 100644 --- a/docker/mongodb-agent/Dockerfile.builder +++ b/docker/mongodb-agent/Dockerfile.builder @@ -9,4 +9,4 @@ ADD https://mciuploads.s3.amazonaws.com/mms-automation/mongodb-mms-build-agent/b ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro}-${tools_version}.tgz /data/mongodb-tools.tgz COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE -COPY ./docker/mongodb-agent/agent-launcher-shim.sh /data/agent-launcher-shim.sh +COPY ./docker/mongodb-agent/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh From 8f06d460e88bbbaf8814df0b3e2628b4c37b4224 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 18:49:15 +0200 Subject: [PATCH 12/49] fix pipeline and fix stati cunit test --- .../construct/database_construction.go | 2 +- .../mongodbmultireplicaset_controller_test.go | 6 ++-- .../mongodbreplicaset_controller_test.go | 6 ++-- .../mongodbshardedcluster_controller_test.go | 6 ++-- .../mongodbstandalone_controller_test.go | 6 ++-- pipeline.py | 29 ++++++++++--------- 6 files changed, 28 insertions(+), 27 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 9a8d9a336..320a36419 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -669,7 +669,7 @@ func buildMongoDBPodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseSt if architectures.IsRunningStaticArchitecture(mdb.GetAnnotations()) { modifications = buildStaticArchitecturePodTemplateSpec(opts, mdb) } else { - modifications = buildNonStaticArchitecturePodTemplateSpec(opts, mdb) + modifications = buildNonStaticArchitecturePodTemplateSpec(opts, mdb) } sharedModifications := sharedDatabaseConfiguration(opts) return podtemplatespec.Apply(sharedModifications, modifications) diff --git a/controllers/operator/mongodbmultireplicaset_controller_test.go b/controllers/operator/mongodbmultireplicaset_controller_test.go index fd615ddea..9eb1095ad 100644 --- a/controllers/operator/mongodbmultireplicaset_controller_test.go +++ b/controllers/operator/mongodbmultireplicaset_controller_test.go @@ -165,9 +165,9 @@ func TestMultiReplicaSetClusterReconcileContainerImagesWithStaticArchitecture(t assert.Len(t, sts.Spec.Template.Spec.InitContainers, 0) require.Len(t, sts.Spec.Template.Spec.Containers, 3) - // Version from OM + operator version - assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1_9.9.9-test", sts.Spec.Template.Spec.Containers[0].Image) - assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[1].Image) + // Version from OM + assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1", sts.Spec.Template.Spec.Containers[0].Image) + assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[2].Image) }) } } diff --git a/controllers/operator/mongodbreplicaset_controller_test.go b/controllers/operator/mongodbreplicaset_controller_test.go index 440ce4f1f..bf93f7616 100644 --- a/controllers/operator/mongodbreplicaset_controller_test.go +++ b/controllers/operator/mongodbreplicaset_controller_test.go @@ -150,9 +150,9 @@ func TestReplicaSetClusterReconcileContainerImagesWithStaticArchitecture(t *test assert.Len(t, sts.Spec.Template.Spec.InitContainers, 0) require.Len(t, sts.Spec.Template.Spec.Containers, 3) - // Version from OM + operator version - assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1_9.9.9-test", sts.Spec.Template.Spec.Containers[0].Image) - assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[1].Image) + // Version from OM + assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1", sts.Spec.Template.Spec.Containers[0].Image) + assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[2].Image) } func buildReplicaSetWithCustomProjectName(rsName string) (*mdbv1.MongoDB, *corev1.ConfigMap, string) { diff --git a/controllers/operator/mongodbshardedcluster_controller_test.go b/controllers/operator/mongodbshardedcluster_controller_test.go index 802447439..af328e5b5 100644 --- a/controllers/operator/mongodbshardedcluster_controller_test.go +++ b/controllers/operator/mongodbshardedcluster_controller_test.go @@ -321,9 +321,9 @@ func TestShardedClusterReconcileContainerImagesWithStaticArchitecture(t *testing assert.Len(t, sts.Spec.Template.Spec.InitContainers, 0) require.Len(t, sts.Spec.Template.Spec.Containers, 3) - // Version from OM + operator version - assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1_9.9.9-test", sts.Spec.Template.Spec.Containers[0].Image) - assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[1].Image) + // Version from OM + assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1", sts.Spec.Template.Spec.Containers[0].Image) + assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[2].Image) }) } } diff --git a/controllers/operator/mongodbstandalone_controller_test.go b/controllers/operator/mongodbstandalone_controller_test.go index 220c0655d..f807be6a6 100644 --- a/controllers/operator/mongodbstandalone_controller_test.go +++ b/controllers/operator/mongodbstandalone_controller_test.go @@ -130,9 +130,9 @@ func TestStandaloneClusterReconcileContainerImagesWithStaticArchitecture(t *test assert.Len(t, sts.Spec.Template.Spec.InitContainers, 0) require.Len(t, sts.Spec.Template.Spec.Containers, 3) - // Version from OM + operator version - assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1_9.9.9-test", sts.Spec.Template.Spec.Containers[0].Image) - assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[1].Image) + // Version from OM + assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1", sts.Spec.Template.Spec.Containers[0].Image) + assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[2].Image) } // TestOnAddStandaloneWithDelay checks the reconciliation on standalone creation with some "delay" in getting diff --git a/pipeline.py b/pipeline.py index ee5c59013..867e57223 100755 --- a/pipeline.py +++ b/pipeline.py @@ -536,6 +536,7 @@ def build_operator_image(build_configuration: BuildConfiguration): image_name=image_name, inventory_file="inventory.yaml", multi_arch_args_list=multi_arch_args_list, + with_image_base=False, is_multi_arch=True, ) @@ -1023,7 +1024,7 @@ def build_image_generic( image_name: str, inventory_file: str, extra_args: dict = None, - registry_address: str = None, + with_image_base: bool = True, is_multi_arch: bool = False, multi_arch_args_list: list = None, is_run_in_parallel: bool = False, @@ -1031,19 +1032,22 @@ def build_image_generic( """Build image generic builds context images and is used for triggering release. During releases it signs and verifies the context image. The release process uses the daily images build process. + The with_image_base parameter determines whether the image being built should include a base image prefix. + When set to True, the function prepends "mongodb-kubernetes-" to the image name """ + image_base = "" + if with_image_base: + image_base = "mongodb-kubernetes-" + try: if not multi_arch_args_list: multi_arch_args_list = [extra_args or {}] version = multi_arch_args_list[0].get("version", "") if config.is_release_step_executed(): - registry = f"{QUAY_REGISTRY_URL}/mongodb-kubernetes-{image_name}" + registry = f"{QUAY_REGISTRY_URL}/{image_base}{image_name}" else: - registry = f"{config.base_repository}/mongodb-kubernetes-{image_name}" - - if registry_address: - registry = registry_address + registry = f"{config.base_repository}/{image_base}{image_name}" for args in multi_arch_args_list: sonar_build_image(image_name, config, args, inventory_file, False) @@ -1135,6 +1139,7 @@ def build_community_image(build_configuration: BuildConfiguration, image_type: s build_image_generic( config=build_configuration, image_name=image_name, + with_image_base=False, multi_arch_args_list=multi_arch_args_list, inventory_file=inventory_file, is_multi_arch=True, # We for pushing manifest anyway, even if arm64 is skipped in patches @@ -1205,7 +1210,7 @@ def build_multi_arch_agent_in_sonar( image_name="mongodb-agent", inventory_file="inventories/agent.yaml", multi_arch_args_list=joined_args, - registry_address=quay_agent_registry if is_release else ecr_agent_registry, # this is usually done by the method but it doesn't work for agent images as it follows their own naming pattern + with_image_base=False, is_multi_arch=True, # We for pushing manifest anyway, even if arm64 is skipped in patches is_run_in_parallel=True, ) @@ -1250,9 +1255,7 @@ def build_agent_default_case(build_configuration: BuildConfiguration): agent_version[1], ) ) - _add_to_agent_queue( - agent_version, build_configuration, executor, tasks_queue - ) + _add_to_agent_queue(agent_version, build_configuration, executor, tasks_queue) queue_exception_handling(tasks_queue) @@ -1315,9 +1318,7 @@ def build_agent_on_agent_bump(build_configuration: BuildConfiguration): ) ) logger.info(f"Building Agent versions: {agent_version}") - _add_to_agent_queue( - agent_version, build_configuration, executor, tasks_queue - ) + _add_to_agent_queue(agent_version, build_configuration, executor, tasks_queue) queue_exception_handling(tasks_queue) @@ -1596,7 +1597,7 @@ def main(): action="store_true", default=False, help="optional parameter to be able to push " - "all non operator suffixed agents, even if we are not in a release", + "all non operator suffixed agents, even if we are not in a release", ) parser.add_argument( "--build-one-agent", From c84e54d146104aeb900f77ba1f79f370ef541278 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 18:57:40 +0200 Subject: [PATCH 13/49] fix pipeline for om --- pipeline.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pipeline.py b/pipeline.py index 867e57223..0b2ff9a10 100755 --- a/pipeline.py +++ b/pipeline.py @@ -1014,7 +1014,7 @@ def build_om_image(build_configuration: BuildConfiguration): image_name="ops-manager", inventory_file="inventories/om.yaml", extra_args=args, - registry_address=f"{QUAY_REGISTRY_URL}/mongodb-enterprise-ops-manager", + registry_address_override=f"{QUAY_REGISTRY_URL}/mongodb-enterprise-ops-manager", ) @@ -1028,6 +1028,7 @@ def build_image_generic( is_multi_arch: bool = False, multi_arch_args_list: list = None, is_run_in_parallel: bool = False, + registry_address_override: str = "", ): """Build image generic builds context images and is used for triggering release. During releases it signs and verifies the context image. @@ -1049,6 +1050,9 @@ def build_image_generic( else: registry = f"{config.base_repository}/{image_base}{image_name}" + if registry_address_override: + registry = registry_address_override + for args in multi_arch_args_list: sonar_build_image(image_name, config, args, inventory_file, False) From e38b4910dfbe966ea3c2e6f5bec6deb094ee784b Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 19:00:34 +0200 Subject: [PATCH 14/49] repush all ecr images --- lib/sonar/builders/docker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sonar/builders/docker.py b/lib/sonar/builders/docker.py index 14c2bf91a..cff3eff4a 100644 --- a/lib/sonar/builders/docker.py +++ b/lib/sonar/builders/docker.py @@ -209,7 +209,7 @@ def inner_docker_push(should_raise=False): # Instead of doing the hack here, we should instead either: # - make sonar aware of context images # - move the logic out of sonar to pipeline.py to all the places where we build context images - if "-context" in tag and image_exists(registry, tag): + if "-context" in tag and image_exists(registry, tag) and "ecr" not in registry: logger.info(f"Image: {tag} in registry: {registry} already exists skipping pushing it") else: logger.info("Image does not exist remotely or is not a context image, pushing it!") From 1e48f2a0313f77b5151672c5edb2900ff02d3e17 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 19:21:34 +0200 Subject: [PATCH 15/49] unify agent names --- inventories/agent.yaml | 2 +- pipeline.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/inventories/agent.yaml b/inventories/agent.yaml index 69959adae..2f01ed7c1 100644 --- a/inventories/agent.yaml +++ b/inventories/agent.yaml @@ -3,7 +3,7 @@ vars: s3_bucket: s3://enterprise-operator-dockerfiles/dockerfiles/mongodb-agent images: - - name: mongodb-agent + - name: mongodb-agent-ubi vars: context: . template_context: docker/mongodb-agent diff --git a/pipeline.py b/pipeline.py index 0b2ff9a10..e997798b5 100755 --- a/pipeline.py +++ b/pipeline.py @@ -1201,8 +1201,6 @@ def build_multi_arch_agent_in_sonar( arch_arm["tools_distro"] = "rhel93-aarch64" arch_amd["tools_distro"] = "rhel93-x86_64" - ecr_agent_registry = build_configuration.base_repository + f"/mongodb-agent-ubi" - quay_agent_registry = QUAY_REGISTRY_URL + f"/mongodb-agent-ubi" joined_args = [args | arch_amd] # Only include arm64 if we shouldn't skip it @@ -1211,7 +1209,7 @@ def build_multi_arch_agent_in_sonar( build_image_generic( config=build_configuration, - image_name="mongodb-agent", + image_name="mongodb-agent-ubi", inventory_file="inventories/agent.yaml", multi_arch_args_list=joined_args, with_image_base=False, From c11bf3277c2114b78d15f76fd947aa3d4cb721bb Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 16 Jul 2025 19:46:48 +0200 Subject: [PATCH 16/49] add dummy probes --- .../construct/database_construction.go | 8 +-- docker/mongodb-agent/Dockerfile | 7 +++ docker/mongodb-agent/agent-launcher-shim.sh | 53 +++++++++++++++++-- 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 320a36419..35cb1738c 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -683,11 +683,11 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb agentContainerModifications := []func(*corev1.Container){container.Apply( container.WithName(util.AgentContainerName), - container.WithImage(opts.AgentImage), + container.WithImage("268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/nnguyen-kops/mongodb-agent-ubi:latest-amd64"), container.WithEnvs(databaseEnvVars(opts)...), container.WithArgs([]string{}), container.WithImagePullPolicy(corev1.PullPolicy(env.ReadOrPanic(util.AutomationAgentImagePullPolicy))), // nolint:forbidigo - container.WithLivenessProbe(DatabaseLivenessProbe()), + container.WithLivenessProbe(DatabaseLivenessProbe()), // TODO: this also needs to be copied over somehow container.WithEnvs(startupParametersToAgentFlag(opts.AgentConfig.StartupParameters)), container.WithEnvs(logConfigurationToEnvVars(opts.AgentConfig.StartupParameters, opts.AdditionalMongodConfig)...), container.WithEnvs(staticContainersEnvVars(mdb)...), @@ -1021,7 +1021,7 @@ func DatabaseLivenessProbe() probes.Modification { probes.WithFailureThreshold(6), ) } - +// TODO: make this work for static no matrix func DatabaseReadinessProbe() probes.Modification { return probes.Apply( probes.WithExecCommand([]string{databaseReadinessProbeCommand}), @@ -1030,7 +1030,7 @@ func DatabaseReadinessProbe() probes.Modification { probes.WithPeriodSeconds(5), ) } - +// TODO: make this work for static no matrix func DatabaseStartupProbe() probes.Modification { return probes.Apply( probes.WithExecCommand([]string{databaseLivenessProbeCommand}), diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index afc715846..148bef80f 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -48,6 +48,13 @@ COPY --from=base /data/mongodb-tools.tgz /agent COPY --from=base /data/LICENSE /licenses/LICENSE COPY --from=base /opt/scripts/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh +# Copy dummy probe scripts to prevent failures before real probes are copied +COPY dummy-probe.sh /opt/scripts/probe.sh +COPY dummy-readinessprobe /opt/scripts/readinessprobe + +# Make all scripts executable +RUN chmod +x /opt/scripts/*.sh /opt/scripts/readinessprobe + RUN tar xfz /agent/mongodb-agent.tar.gz \ && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ && chmod +x /agent/mongodb-agent \ diff --git a/docker/mongodb-agent/agent-launcher-shim.sh b/docker/mongodb-agent/agent-launcher-shim.sh index 3f49c02ba..144f860f6 100755 --- a/docker/mongodb-agent/agent-launcher-shim.sh +++ b/docker/mongodb-agent/agent-launcher-shim.sh @@ -1,18 +1,65 @@ #!/bin/bash set -e +INIT_PID=$(pgrep -f 'tail -F -n0 /dev/null' | head -n1) +TIMEOUT_SECONDS=300 # 5 minutes timeout +WAIT_COUNT=0 + # Wait for agent-launcher container to start echo "Waiting for agent-launcher container to be ready..." -while [ ! -d "/proc/$(pgrep -f 'tail -F -n0 /dev/null' | head -n1)/root/opt/scripts" ]; do +while [ ! -d "/proc/${INIT_PID}/root/opt/scripts" ]; do sleep 1 + WAIT_COUNT=$((WAIT_COUNT + 1)) + + if [ $WAIT_COUNT -ge $TIMEOUT_SECONDS ]; then + echo "ERROR: Timeout waiting for init container after ${TIMEOUT_SECONDS} seconds" + echo "Init container PID: ${INIT_PID}" + echo "Expected directory: /proc/${INIT_PID}/root/opt/scripts" + exit 1 + fi + + if [ $((WAIT_COUNT % 30)) -eq 0 ]; then + echo "Still waiting for init container... (${WAIT_COUNT}/${TIMEOUT_SECONDS} seconds)" + fi done +echo "Init container ready after ${WAIT_COUNT} seconds" + # Copy agent launcher scripts echo "Copying agent launcher scripts..." -cp -r /proc/$(pgrep -f 'tail -F -n0 /dev/null' | head -n1)/root/opt/scripts/* /opt/scripts/ +if ! cp -r /proc/"${INIT_PID}"/root/opt/scripts/* /opt/scripts/; then + echo "ERROR: Failed to copy agent launcher scripts" + exit 1 +fi + +# Copy probe scripts from the init-database container for readiness and liveness +echo "Copying probe scripts..." +if [ -f "/proc/${INIT_PID}/root/probes/readinessprobe" ]; then + if cp /proc/"${INIT_PID}"/root/probes/readinessprobe /opt/scripts/readinessprobe; then + echo "Replaced dummy readinessprobe with real one" + else + echo "ERROR: Failed to copy readinessprobe" + exit 1 + fi +else + echo "ERROR: readinessprobe not found in init container at /proc/${INIT_PID}/root/probes/readinessprobe" + exit 1 +fi + +if [ -f "/proc/${INIT_PID}/root/probes/probe.sh" ]; then + if cp /proc/"${INIT_PID}"/root/probes/probe.sh /opt/scripts/probe.sh; then + echo "Replaced dummy probe.sh with real one (liveness probe)" + else + echo "ERROR: Failed to copy probe.sh" + exit 1 + fi +else + echo "ERROR: probe.sh not found in init container at /proc/${INIT_PID}/root/probes/probe.sh" + exit 1 +fi # Make scripts executable -chmod +x /opt/scripts/*.sh +chmod +x /opt/scripts/*.sh /opt/scripts/readinessprobe # Start the agent launcher echo "Starting agent launcher..." From d49c870bf22282d1c41f0465d9121388360603f2 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 17 Jul 2025 09:50:36 +0200 Subject: [PATCH 17/49] add dummy probes --- docker/mongodb-agent/dummy-probe.sh | 5 +++++ docker/mongodb-agent/dummy-readinessprobe | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 docker/mongodb-agent/dummy-probe.sh create mode 100644 docker/mongodb-agent/dummy-readinessprobe diff --git a/docker/mongodb-agent/dummy-probe.sh b/docker/mongodb-agent/dummy-probe.sh new file mode 100644 index 000000000..794f255ee --- /dev/null +++ b/docker/mongodb-agent/dummy-probe.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# Dummy probe script that returns success until real probe is copied +# This prevents container startup failures during probe script copying phase +echo "Using dummy probe - waiting for real probe script to be copied" +exit 0 diff --git a/docker/mongodb-agent/dummy-readinessprobe b/docker/mongodb-agent/dummy-readinessprobe new file mode 100644 index 000000000..737d67e21 --- /dev/null +++ b/docker/mongodb-agent/dummy-readinessprobe @@ -0,0 +1,5 @@ +#!/bin/bash +# Dummy readiness probe that returns success until real probe is copied +# This prevents container startup failures during probe script copying phase +echo "Using dummy readiness probe - waiting for real probe script to be copied" +exit 0 From 86f42d8375b0a20f2ffe96df754f1323012d64b8 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 17 Jul 2025 09:53:58 +0200 Subject: [PATCH 18/49] add dummy probes --- docker/mongodb-agent/Dockerfile | 4 ++-- docker/mongodb-agent/Dockerfile.builder | 2 ++ .../{dummy-readinessprobe => dummy-readinessprobe.sh} | 0 3 files changed, 4 insertions(+), 2 deletions(-) rename docker/mongodb-agent/{dummy-readinessprobe => dummy-readinessprobe.sh} (100%) diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index 148bef80f..bfd10acdd 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -49,8 +49,8 @@ COPY --from=base /data/LICENSE /licenses/LICENSE COPY --from=base /opt/scripts/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh # Copy dummy probe scripts to prevent failures before real probes are copied -COPY dummy-probe.sh /opt/scripts/probe.sh -COPY dummy-readinessprobe /opt/scripts/readinessprobe +COPY --from=base /opt/scripts/dummy-probe.sh /opt/scripts/probe.sh +COPY --from=base /opt/scripts/dummy-readinessprobe /opt/scripts/readinessprobe # Make all scripts executable RUN chmod +x /opt/scripts/*.sh /opt/scripts/readinessprobe diff --git a/docker/mongodb-agent/Dockerfile.builder b/docker/mongodb-agent/Dockerfile.builder index 979f593ff..11846cea4 100644 --- a/docker/mongodb-agent/Dockerfile.builder +++ b/docker/mongodb-agent/Dockerfile.builder @@ -10,3 +10,5 @@ ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE COPY ./docker/mongodb-agent/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh +COPY ./docker/mongodb-agent/dummy-probe.sh /opt/scripts/dummy-probe.sh +COPY ./docker/mongodb-agent/dummy-readinessprobe.sh /opt/scripts/dummy-readinessprobe.sh diff --git a/docker/mongodb-agent/dummy-readinessprobe b/docker/mongodb-agent/dummy-readinessprobe.sh similarity index 100% rename from docker/mongodb-agent/dummy-readinessprobe rename to docker/mongodb-agent/dummy-readinessprobe.sh From 823cc59db83f45e17bc37736117acdaf96116a45 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 17 Jul 2025 09:54:36 +0200 Subject: [PATCH 19/49] add dummy probes --- docker/mongodb-agent/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index bfd10acdd..d67821b0f 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -50,7 +50,7 @@ COPY --from=base /opt/scripts/agent-launcher-shim.sh /opt/scripts/agent-launcher # Copy dummy probe scripts to prevent failures before real probes are copied COPY --from=base /opt/scripts/dummy-probe.sh /opt/scripts/probe.sh -COPY --from=base /opt/scripts/dummy-readinessprobe /opt/scripts/readinessprobe +COPY --from=base /opt/scripts/dummy-readinessprobe.sh /opt/scripts/readinessprobe # Make all scripts executable RUN chmod +x /opt/scripts/*.sh /opt/scripts/readinessprobe From 62e45ef877399fd60e3b0a9ac40a01e2878f6128 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 17 Jul 2025 10:34:42 +0200 Subject: [PATCH 20/49] add dummy probes --- docker/mongodb-agent/agent-launcher-shim.sh | 31 ++++++++++++-------- docker/mongodb-agent/dummy-probe.sh | 6 ++-- docker/mongodb-agent/dummy-readinessprobe.sh | 8 ++--- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/docker/mongodb-agent/agent-launcher-shim.sh b/docker/mongodb-agent/agent-launcher-shim.sh index 144f860f6..b5e1b6371 100755 --- a/docker/mongodb-agent/agent-launcher-shim.sh +++ b/docker/mongodb-agent/agent-launcher-shim.sh @@ -1,20 +1,27 @@ #!/bin/bash set -e -INIT_PID=$(pgrep -f 'tail -F -n0 /dev/null' | head -n1) +# Configuration variables +INIT_PID=$(pgrep -f 'tail -f /dev/null' | head -n1) TIMEOUT_SECONDS=300 # 5 minutes timeout WAIT_COUNT=0 +# Path variables +INIT_CONTAINER_ROOT="/proc/${INIT_PID}/root" +INIT_SCRIPTS_DIR="${INIT_CONTAINER_ROOT}/scripts" +INIT_PROBES_DIR="${INIT_CONTAINER_ROOT}/probes" +TARGET_SCRIPTS_DIR="/opt/scripts" + # Wait for agent-launcher container to start echo "Waiting for agent-launcher container to be ready..." -while [ ! -d "/proc/${INIT_PID}/root/opt/scripts" ]; do +while [ ! -d "${INIT_SCRIPTS_DIR}" ]; do sleep 1 WAIT_COUNT=$((WAIT_COUNT + 1)) if [ $WAIT_COUNT -ge $TIMEOUT_SECONDS ]; then echo "ERROR: Timeout waiting for init container after ${TIMEOUT_SECONDS} seconds" echo "Init container PID: ${INIT_PID}" - echo "Expected directory: /proc/${INIT_PID}/root/opt/scripts" + echo "Expected directory: ${INIT_SCRIPTS_DIR}" exit 1 fi @@ -27,40 +34,40 @@ echo "Init container ready after ${WAIT_COUNT} seconds" # Copy agent launcher scripts echo "Copying agent launcher scripts..." -if ! cp -r /proc/"${INIT_PID}"/root/opt/scripts/* /opt/scripts/; then +if ! cp -r "${INIT_SCRIPTS_DIR}"/* "${TARGET_SCRIPTS_DIR}"/; then echo "ERROR: Failed to copy agent launcher scripts" exit 1 fi # Copy probe scripts from the init-database container for readiness and liveness echo "Copying probe scripts..." -if [ -f "/proc/${INIT_PID}/root/probes/readinessprobe" ]; then - if cp /proc/"${INIT_PID}"/root/probes/readinessprobe /opt/scripts/readinessprobe; then +if [ -f "${INIT_PROBES_DIR}/readinessprobe" ]; then + if cp "${INIT_PROBES_DIR}"/* "${TARGET_SCRIPTS_DIR}"/; then echo "Replaced dummy readinessprobe with real one" else echo "ERROR: Failed to copy readinessprobe" exit 1 fi else - echo "ERROR: readinessprobe not found in init container at /proc/${INIT_PID}/root/probes/readinessprobe" + echo "ERROR: readinessprobe not found in init container at ${INIT_PROBES_DIR}/readinessprobe" exit 1 fi -if [ -f "/proc/${INIT_PID}/root/probes/probe.sh" ]; then - if cp /proc/"${INIT_PID}"/root/probes/probe.sh /opt/scripts/probe.sh; then +if [ -f "${INIT_PROBES_DIR}/probe.sh" ]; then + if cp "${INIT_PROBES_DIR}"/probe.sh "${TARGET_SCRIPTS_DIR}"/probe.sh; then echo "Replaced dummy probe.sh with real one (liveness probe)" else echo "ERROR: Failed to copy probe.sh" exit 1 fi else - echo "ERROR: probe.sh not found in init container at /proc/${INIT_PID}/root/probes/probe.sh" + echo "ERROR: probe.sh not found in init container at ${INIT_PROBES_DIR}/probe.sh" exit 1 fi # Make scripts executable -chmod +x /opt/scripts/*.sh /opt/scripts/readinessprobe +chmod +x "${TARGET_SCRIPTS_DIR}"/*.sh "${TARGET_SCRIPTS_DIR}"/readinessprobe # Start the agent launcher echo "Starting agent launcher..." -exec /opt/scripts/agent-launcher.sh +exec "${TARGET_SCRIPTS_DIR}"/agent-launcher.sh diff --git a/docker/mongodb-agent/dummy-probe.sh b/docker/mongodb-agent/dummy-probe.sh index 794f255ee..911135f1b 100644 --- a/docker/mongodb-agent/dummy-probe.sh +++ b/docker/mongodb-agent/dummy-probe.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Dummy probe script that returns success until real probe is copied -# This prevents container startup failures during probe script copying phase -echo "Using dummy probe - waiting for real probe script to be copied" +# Dummy liveness probe that returns success to keep container alive during script copying +# This prevents container from being killed while waiting for real probe scripts +echo "Using dummy liveness probe - keeping container alive until real probe script is copied" exit 0 diff --git a/docker/mongodb-agent/dummy-readinessprobe.sh b/docker/mongodb-agent/dummy-readinessprobe.sh index 737d67e21..e93b0bc84 100644 --- a/docker/mongodb-agent/dummy-readinessprobe.sh +++ b/docker/mongodb-agent/dummy-readinessprobe.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Dummy readiness probe that returns success until real probe is copied -# This prevents container startup failures during probe script copying phase -echo "Using dummy readiness probe - waiting for real probe script to be copied" -exit 0 +# Dummy readiness probe that returns NOT READY until real probe is copied +# Container should not be marked ready until real probe scripts are available +echo "Using dummy readiness probe - container not ready until real probe script is copied" +exit 1 From ae23cfd1c276fd16f3343073f727b654bf5a8201 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 17 Jul 2025 11:37:01 +0200 Subject: [PATCH 21/49] update launcher and use different paths and make things writable --- .../construct/database_construction.go | 22 +- docker/mongodb-agent/Dockerfile | 10 +- docker/mongodb-agent/agent-launcher-shim.sh | 233 +++++++++++++----- 3 files changed, 197 insertions(+), 68 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 35cb1738c..de2608b55 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -519,6 +519,8 @@ func buildDatabaseStatefulSetConfigurationFunction(mdb databaseStatefulSetSource podtemplatespec.WithPodLabels(podLabels), podtemplatespec.WithContainerByIndex(0, sharedDatabaseContainerFunc(databaseImage, *opts.PodSpec, volumeMounts, configureContainerSecurityContext, opts.ServicePort)), secondContainerModification, + podtemplatespec.WithContainerByIndex(1, container.WithVolumeMounts(volumeMounts)), + podtemplatespec.WithContainerByIndex(2, container.WithVolumeMounts(volumeMounts)), volumesFunc, configurePodSpecSecurityContext, configureImagePullSecrets, @@ -677,9 +679,14 @@ func buildMongoDBPodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseSt // buildStaticArchitecturePodTemplateSpec constructs the podTemplateSpec for static architecture func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb databaseStatefulSetSource) podtemplatespec.Modification { - var volumes []corev1.Volume + // scripts volume is needed for agent-launcher-shim.sh to copy scripts + scriptsVolume := statefulset.CreateVolumeFromEmptyDir("database-scripts") + databaseScriptsVolumeMount := databaseScriptsVolumeMount(false) // writable for shim script - _, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications() + volumes := []corev1.Volume{scriptsVolume} + volumeMounts := []corev1.VolumeMount{databaseScriptsVolumeMount} + + _, configureContainerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications() agentContainerModifications := []func(*corev1.Container){container.Apply( container.WithName(util.AgentContainerName), @@ -687,13 +694,14 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb container.WithEnvs(databaseEnvVars(opts)...), container.WithArgs([]string{}), container.WithImagePullPolicy(corev1.PullPolicy(env.ReadOrPanic(util.AutomationAgentImagePullPolicy))), // nolint:forbidigo - container.WithLivenessProbe(DatabaseLivenessProbe()), // TODO: this also needs to be copied over somehow + container.WithLivenessProbe(DatabaseLivenessProbe()), container.WithEnvs(startupParametersToAgentFlag(opts.AgentConfig.StartupParameters)), container.WithEnvs(logConfigurationToEnvVars(opts.AgentConfig.StartupParameters, opts.AdditionalMongodConfig)...), container.WithEnvs(staticContainersEnvVars(mdb)...), container.WithEnvs(readinessEnvironmentVariablesToEnvVars(opts.AgentConfig.ReadinessProbe.EnvironmentVariables)...), - container.WithCommand([]string{"/opt/scripts/agent-launcher-shim.sh"}), - containerSecurityContext, + container.WithCommand([]string{"/usr/local/bin/agent-launcher-shim.sh"}), + container.WithVolumeMounts(volumeMounts), + configureContainerSecurityContext, )} mongodContainerModifications := []func(*corev1.Container){container.Apply( @@ -703,7 +711,7 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb container.WithImage(opts.MongodbImage), container.WithEnvs(databaseEnvVars(opts)...), container.WithCommand([]string{"bash", "-c", "tail -F -n0 ${MDB_LOG_FILE_MONGODB} mongodb_marker"}), - containerSecurityContext, + configureContainerSecurityContext, )} agentUtilitiesHolderModifications := []func(*corev1.Container){container.Apply( @@ -712,7 +720,7 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb container.WithImage(opts.InitDatabaseImage), container.WithEnvs(databaseEnvVars(opts)...), container.WithCommand([]string{"bash", "-c", "tail -f /dev/null"}), - containerSecurityContext, + configureContainerSecurityContext, )} if opts.HostNameOverrideConfigmapName != "" { diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index d67821b0f..da48bd0b9 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -46,14 +46,14 @@ RUN mkdir -p /opt/scripts COPY --from=base /data/mongodb-agent.tar.gz /agent COPY --from=base /data/mongodb-tools.tgz /agent COPY --from=base /data/LICENSE /licenses/LICENSE -COPY --from=base /opt/scripts/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh +COPY --from=base /opt/scripts/agent-launcher-shim.sh /usr/local/bin/agent-launcher-shim.sh -# Copy dummy probe scripts to prevent failures before real probes are copied -COPY --from=base /opt/scripts/dummy-probe.sh /opt/scripts/probe.sh -COPY --from=base /opt/scripts/dummy-readinessprobe.sh /opt/scripts/readinessprobe +# Copy dummy probe scripts to a safe location that won't be overwritten by volume mount +COPY --from=base /opt/scripts/dummy-probe.sh /usr/local/bin/dummy-probe.sh +COPY --from=base /opt/scripts/dummy-readinessprobe.sh /usr/local/bin/dummy-readinessprobe # Make all scripts executable -RUN chmod +x /opt/scripts/*.sh /opt/scripts/readinessprobe +RUN chmod +x /usr/local/bin/agent-launcher-shim.sh /usr/local/bin/dummy-probe.sh /usr/local/bin/dummy-readinessprobe RUN tar xfz /agent/mongodb-agent.tar.gz \ && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ diff --git a/docker/mongodb-agent/agent-launcher-shim.sh b/docker/mongodb-agent/agent-launcher-shim.sh index b5e1b6371..eeee54aca 100755 --- a/docker/mongodb-agent/agent-launcher-shim.sh +++ b/docker/mongodb-agent/agent-launcher-shim.sh @@ -2,72 +2,193 @@ set -e # Configuration variables -INIT_PID=$(pgrep -f 'tail -f /dev/null' | head -n1) TIMEOUT_SECONDS=300 # 5 minutes timeout -WAIT_COUNT=0 - -# Path variables -INIT_CONTAINER_ROOT="/proc/${INIT_PID}/root" -INIT_SCRIPTS_DIR="${INIT_CONTAINER_ROOT}/scripts" -INIT_PROBES_DIR="${INIT_CONTAINER_ROOT}/probes" TARGET_SCRIPTS_DIR="/opt/scripts" -# Wait for agent-launcher container to start -echo "Waiting for agent-launcher container to be ready..." -while [ ! -d "${INIT_SCRIPTS_DIR}" ]; do - sleep 1 - WAIT_COUNT=$((WAIT_COUNT + 1)) - - if [ $WAIT_COUNT -ge $TIMEOUT_SECONDS ]; then - echo "ERROR: Timeout waiting for init container after ${TIMEOUT_SECONDS} seconds" - echo "Init container PID: ${INIT_PID}" - echo "Expected directory: ${INIT_SCRIPTS_DIR}" - exit 1 +setup_dummy_probes() { + echo "Setting up dummy probe scripts..." + cp /usr/local/bin/dummy-probe.sh "${TARGET_SCRIPTS_DIR}"/probe.sh + cp /usr/local/bin/dummy-readinessprobe "${TARGET_SCRIPTS_DIR}"/readinessprobe + echo "Dummy probe scripts ready" +} + +# Find the init container process with retries +find_init_container() { + echo "Looking for init/utilities container process..." + for attempt in {1..5}; do + local pid=$(pgrep -f 'tail -f /dev/null' | head -n1) + if [ -n "$pid" ]; then + echo "Found init container process with PID: ${pid} (attempt ${attempt})" + echo "$pid" + return 0 + fi + echo "Attempt ${attempt}: No process found, retrying in 1 second..." + sleep 1 + done + return 1 +} + +# Check if agent launcher already exists in image +check_existing_scripts() { + if [ -f "${TARGET_SCRIPTS_DIR}/agent-launcher.sh" ]; then + echo "Agent launcher script already exists in image" + return 0 + else + echo "ERROR: No init container found and no agent-launcher.sh in image" + echo "Available processes:" + ps aux + return 1 fi +} + +# Wait for init container directories to be ready +wait_for_init_container() { + local init_scripts_dir="$1" + local init_container_root="$2" + local init_pid="$3" + local wait_count=0 - if [ $((WAIT_COUNT % 30)) -eq 0 ]; then - echo "Still waiting for init container... (${WAIT_COUNT}/${TIMEOUT_SECONDS} seconds)" + if [ -d "${init_scripts_dir}" ]; then + echo "Scripts directory found immediately: ${init_scripts_dir}" + return 0 fi -done - -echo "Init container ready after ${WAIT_COUNT} seconds" - -# Copy agent launcher scripts -echo "Copying agent launcher scripts..." -if ! cp -r "${INIT_SCRIPTS_DIR}"/* "${TARGET_SCRIPTS_DIR}"/; then - echo "ERROR: Failed to copy agent launcher scripts" - exit 1 -fi - -# Copy probe scripts from the init-database container for readiness and liveness -echo "Copying probe scripts..." -if [ -f "${INIT_PROBES_DIR}/readinessprobe" ]; then - if cp "${INIT_PROBES_DIR}"/* "${TARGET_SCRIPTS_DIR}"/; then - echo "Replaced dummy readinessprobe with real one" + + echo "Scripts directory not found, waiting..." + echo "Waiting for agent-launcher container to be ready..." + + while [ ! -d "${init_scripts_dir}" ]; do + sleep 1 + wait_count=$((wait_count + 1)) + + if [ $wait_count -ge $TIMEOUT_SECONDS ]; then + echo "ERROR: Timeout waiting for init container after ${TIMEOUT_SECONDS} seconds" + echo "Init container PID: ${init_pid}" + echo "Expected directory: ${init_scripts_dir}" + echo "Available directories in init container root:" + ls -la "${init_container_root}/" 2>/dev/null || echo "Cannot list init container root" + echo "Process still running?" + ps -p "${init_pid}" || echo "Process ${init_pid} no longer exists" + return 1 + fi + + if [ $((wait_count % 30)) -eq 0 ]; then + echo "Still waiting for init container... (${wait_count}/${TIMEOUT_SECONDS} seconds)" + echo "Current init container root contents:" + ls -la "${init_container_root}/" 2>/dev/null || echo "Cannot access ${init_container_root}" + fi + done + + echo "Init container ready after ${wait_count} seconds" + return 0 +} + +# Copy agent launcher scripts from init container +copy_agent_scripts() { + local init_scripts_dir="$1" + + echo "Copying agent launcher scripts..." + echo "Available files in ${init_scripts_dir}:" + ls -la "${init_scripts_dir}/" 2>/dev/null || echo "Cannot list scripts directory" + + if ! cp -r "${init_scripts_dir}"/* "${TARGET_SCRIPTS_DIR}"/; then + echo "ERROR: Failed to copy agent launcher scripts" + return 1 + fi + + echo "Agent launcher scripts copied successfully" + return 0 +} + +# Copy probe scripts from init container +copy_probe_scripts() { + local init_probes_dir="$1" + + echo "Copying probe scripts..." + echo "Available files in ${init_probes_dir}:" + ls -la "${init_probes_dir}/" 2>/dev/null || echo "Probes directory not found" + + # Copy readiness probe + if [ -f "${init_probes_dir}/readinessprobe" ]; then + if cp "${init_probes_dir}"/* "${TARGET_SCRIPTS_DIR}"/; then + echo "Replaced dummy readinessprobe with real one" + else + echo "ERROR: Failed to copy readinessprobe" + return 1 + fi else - echo "ERROR: Failed to copy readinessprobe" - exit 1 + echo "WARNING: readinessprobe not found in init container at ${init_probes_dir}/readinessprobe" + echo "Keeping dummy readiness probe" fi -else - echo "ERROR: readinessprobe not found in init container at ${INIT_PROBES_DIR}/readinessprobe" - exit 1 -fi - -if [ -f "${INIT_PROBES_DIR}/probe.sh" ]; then - if cp "${INIT_PROBES_DIR}"/probe.sh "${TARGET_SCRIPTS_DIR}"/probe.sh; then - echo "Replaced dummy probe.sh with real one (liveness probe)" + + # Copy liveness probe + if [ -f "${init_probes_dir}/probe.sh" ]; then + if cp "${init_probes_dir}"/probe.sh "${TARGET_SCRIPTS_DIR}"/probe.sh; then + echo "Replaced dummy probe.sh with real one (liveness probe)" + else + echo "ERROR: Failed to copy probe.sh" + return 1 + fi else - echo "ERROR: Failed to copy probe.sh" - exit 1 + echo "WARNING: probe.sh not found in init container at ${init_probes_dir}/probe.sh" + echo "Keeping dummy liveness probe" fi -else - echo "ERROR: probe.sh not found in init container at ${INIT_PROBES_DIR}/probe.sh" - exit 1 -fi -# Make scripts executable -chmod +x "${TARGET_SCRIPTS_DIR}"/*.sh "${TARGET_SCRIPTS_DIR}"/readinessprobe + return 0 +} # Start the agent launcher -echo "Starting agent launcher..." -exec "${TARGET_SCRIPTS_DIR}"/agent-launcher.sh +start_agent_launcher() { + echo "Starting agent launcher..." + echo "Final contents of ${TARGET_SCRIPTS_DIR}:" + ls -la "${TARGET_SCRIPTS_DIR}/" + + if [ -f "${TARGET_SCRIPTS_DIR}/agent-launcher.sh" ]; then + exec "${TARGET_SCRIPTS_DIR}"/agent-launcher.sh + else + echo "ERROR: agent-launcher.sh not found at ${TARGET_SCRIPTS_DIR}/agent-launcher.sh" + return 1 + fi +} + +# Main execution flow +main() { + # Step 1: Setup dummy probes immediately + setup_dummy_probes + + # Step 2: Try to find init container + if ! init_pid=$(find_init_container); then + echo "No init container found after 5 attempts. Checking if scripts already exist in image..." + + if ! check_existing_scripts; then + exit 1 + fi + + else + # Step 3: Setup paths and wait for init container + init_container_root="/proc/${init_pid}/root" + init_scripts_dir="${init_container_root}/scripts" + init_probes_dir="${init_container_root}/probes" + + if ! wait_for_init_container "$init_scripts_dir" "$init_container_root" "$init_pid"; then + exit 1 + fi + + # Step 4: Copy scripts from init container + if ! copy_agent_scripts "$init_scripts_dir"; then + exit 1 + fi + + if ! copy_probe_scripts "$init_probes_dir"; then + exit 1 + fi + + # Step 5: Make scripts executable + chmod +x "${TARGET_SCRIPTS_DIR}"/*.sh "${TARGET_SCRIPTS_DIR}"/readinessprobe 2>/dev/null || true + fi + + # Step 6: Start the agent launcher + start_agent_launcher +} + +# Run main function +main "$@" From c5511bef6f526444e31b21e9251f00b016f68ee0 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 17 Jul 2025 11:37:34 +0200 Subject: [PATCH 22/49] linter --- controllers/operator/construct/database_construction.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index de2608b55..752047f2e 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -1029,6 +1029,7 @@ func DatabaseLivenessProbe() probes.Modification { probes.WithFailureThreshold(6), ) } + // TODO: make this work for static no matrix func DatabaseReadinessProbe() probes.Modification { return probes.Apply( @@ -1038,6 +1039,7 @@ func DatabaseReadinessProbe() probes.Modification { probes.WithPeriodSeconds(5), ) } + // TODO: make this work for static no matrix func DatabaseStartupProbe() probes.Modification { return probes.Apply( From 4e97519274487fa281395803f4a290310653358f Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Mon, 21 Jul 2025 14:48:51 +0200 Subject: [PATCH 23/49] fix container index ordering --- .../construct/database_construction.go | 40 ++++++++++--------- .../kube/podtemplatespec/podspec_template.go | 13 ++++++ 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 752047f2e..14bcd11be 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -487,24 +487,39 @@ func buildDatabaseStatefulSetConfigurationFunction(mdb databaseStatefulSetSource shareProcessNs := statefulset.NOOP() secondContainerModification := podtemplatespec.NOOP() + var databaseImage string + var staticMods []podtemplatespec.Modification if architectures.IsRunningStaticArchitecture(mdb.GetAnnotations()) { shareProcessNs = func(sts *appsv1.StatefulSet) { sts.Spec.Template.Spec.ShareProcessNamespace = ptr.To(true) } - secondContainerModification = podtemplatespec.WithContainerByIndex(1, container.WithVolumeMounts(volumeMounts)) - } - - var databaseImage string - if architectures.IsRunningStaticArchitecture(mdb.GetAnnotations()) { + staticMods = append(staticMods, podtemplatespec.WithContainerByIndex(1, container.WithVolumeMounts(volumeMounts))) + staticMods = append(staticMods, podtemplatespec.WithContainerByIndex(2, container.WithVolumeMounts(volumeMounts))) databaseImage = opts.AgentImage } else { databaseImage = opts.DatabaseNonStaticImage } + podTemplateModifications := []podtemplatespec.Modification{ + podTemplateAnnotationFunc, + podtemplatespec.WithAffinity(podAffinity, PodAntiAffinityLabelKey, 100), + podtemplatespec.WithTerminationGracePeriodSeconds(util.DefaultPodTerminationPeriodSeconds), + podtemplatespec.WithPodLabels(podLabels), + podtemplatespec.WithContainerByIndex(0, sharedDatabaseContainerFunc(databaseImage, *opts.PodSpec, volumeMounts, configureContainerSecurityContext, opts.ServicePort)), + secondContainerModification, + volumesFunc, + configurePodSpecSecurityContext, + configureImagePullSecrets, + podTemplateSpecFunc, + } + podTemplateModifications = append(podTemplateModifications, staticMods...) + return statefulset.Apply( + // StatefulSet metadata statefulset.WithLabels(ssLabels), statefulset.WithName(stsName), statefulset.WithNamespace(mdb.GetNamespace()), + // StatefulSet spec statefulset.WithMatchLabels(podLabels), statefulset.WithServiceName(opts.ServiceName), statefulset.WithReplicas(opts.Replicas), @@ -512,20 +527,7 @@ func buildDatabaseStatefulSetConfigurationFunction(mdb databaseStatefulSetSource annotationFunc, volumeClaimFuncs, shareProcessNs, - statefulset.WithPodSpecTemplate(podtemplatespec.Apply( - podTemplateAnnotationFunc, - podtemplatespec.WithAffinity(podAffinity, PodAntiAffinityLabelKey, 100), - podtemplatespec.WithTerminationGracePeriodSeconds(util.DefaultPodTerminationPeriodSeconds), - podtemplatespec.WithPodLabels(podLabels), - podtemplatespec.WithContainerByIndex(0, sharedDatabaseContainerFunc(databaseImage, *opts.PodSpec, volumeMounts, configureContainerSecurityContext, opts.ServicePort)), - secondContainerModification, - podtemplatespec.WithContainerByIndex(1, container.WithVolumeMounts(volumeMounts)), - podtemplatespec.WithContainerByIndex(2, container.WithVolumeMounts(volumeMounts)), - volumesFunc, - configurePodSpecSecurityContext, - configureImagePullSecrets, - podTemplateSpecFunc, - )), + statefulset.WithPodSpecTemplate(podtemplatespec.Apply(podTemplateModifications...)), ) } diff --git a/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go b/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go index 355730375..1b17f69b0 100644 --- a/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go +++ b/mongodb-community-operator/pkg/kube/podtemplatespec/podspec_template.go @@ -66,6 +66,19 @@ func WithContainerByIndex(index int, funcs ...func(container *corev1.Container)) } } +// WithContainerByIndexIfExists applies the modifications to the container with the provided index +// only if the container already exists. If the index is out of range, no changes are made. +func WithContainerByIndexIfExists(index int, funcs ...func(container *corev1.Container)) func(podTemplateSpec *corev1.PodTemplateSpec) { + return func(podTemplateSpec *corev1.PodTemplateSpec) { + if index < len(podTemplateSpec.Spec.Containers) { + c := &podTemplateSpec.Spec.Containers[index] + for _, f := range funcs { + f(c) + } + } + } +} + // WithInitContainer applies the modifications to the init container with the provided name func WithInitContainer(name string, containerfunc func(*corev1.Container)) Modification { return func(podTemplateSpec *corev1.PodTemplateSpec) { From 6382c69f6adf3e7b00ce76cf3ede56840936cc67 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Mon, 21 Jul 2025 15:06:39 +0200 Subject: [PATCH 24/49] move to linking --- docker/mongodb-agent/agent-launcher-shim.sh | 54 ++++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/docker/mongodb-agent/agent-launcher-shim.sh b/docker/mongodb-agent/agent-launcher-shim.sh index eeee54aca..56cde07c4 100755 --- a/docker/mongodb-agent/agent-launcher-shim.sh +++ b/docker/mongodb-agent/agent-launcher-shim.sh @@ -15,8 +15,9 @@ setup_dummy_probes() { # Find the init container process with retries find_init_container() { echo "Looking for init/utilities container process..." - for attempt in {1..5}; do - local pid=$(pgrep -f 'tail -f /dev/null' | head -n1) + for attempt in {1..10}; do + local pid + pid=$(pgrep -f 'tail -f /dev/null' | head -n1) if [ -n "$pid" ]; then echo "Found init container process with PID: ${pid} (attempt ${attempt})" echo "$pid" @@ -82,37 +83,42 @@ wait_for_init_container() { return 0 } -# Copy agent launcher scripts from init container -copy_agent_scripts() { +# Create symlinks to agent launcher scripts from init container +symlink_agent_scripts() { local init_scripts_dir="$1" - echo "Copying agent launcher scripts..." + echo "Creating symlinks to agent launcher scripts..." echo "Available files in ${init_scripts_dir}:" ls -la "${init_scripts_dir}/" 2>/dev/null || echo "Cannot list scripts directory" - if ! cp -r "${init_scripts_dir}"/* "${TARGET_SCRIPTS_DIR}"/; then - echo "ERROR: Failed to copy agent launcher scripts" - return 1 - fi + # Create symlinks for all files in the scripts directory + for script_file in "${init_scripts_dir}"/*; do + local filename + filename=$(basename "${script_file}") + if ! ln -sf "${script_file}" "${TARGET_SCRIPTS_DIR}/${filename}"; then + echo "ERROR: Failed to create symlink for ${filename}" + return 1 + fi + done - echo "Agent launcher scripts copied successfully" + echo "Agent launcher script symlinks created successfully" return 0 } -# Copy probe scripts from init container -copy_probe_scripts() { +# Create symlinks to probe scripts from init container +symlink_probe_scripts() { local init_probes_dir="$1" - echo "Copying probe scripts..." + echo "Creating symlinks to probe scripts..." echo "Available files in ${init_probes_dir}:" ls -la "${init_probes_dir}/" 2>/dev/null || echo "Probes directory not found" - # Copy readiness probe + # Create symlink for readiness probe if [ -f "${init_probes_dir}/readinessprobe" ]; then - if cp "${init_probes_dir}"/* "${TARGET_SCRIPTS_DIR}"/; then - echo "Replaced dummy readinessprobe with real one" + if ln -sf "${init_probes_dir}/readinessprobe" "${TARGET_SCRIPTS_DIR}/readinessprobe"; then + echo "Replaced dummy readinessprobe with symlink to real one" else - echo "ERROR: Failed to copy readinessprobe" + echo "ERROR: Failed to create symlink for readinessprobe" return 1 fi else @@ -120,12 +126,12 @@ copy_probe_scripts() { echo "Keeping dummy readiness probe" fi - # Copy liveness probe + # Create symlink for liveness probe if [ -f "${init_probes_dir}/probe.sh" ]; then - if cp "${init_probes_dir}"/probe.sh "${TARGET_SCRIPTS_DIR}"/probe.sh; then - echo "Replaced dummy probe.sh with real one (liveness probe)" + if ln -sf "${init_probes_dir}/probe.sh" "${TARGET_SCRIPTS_DIR}/probe.sh"; then + echo "Replaced dummy probe.sh with symlink to real one (liveness probe)" else - echo "ERROR: Failed to copy probe.sh" + echo "ERROR: Failed to create symlink for probe.sh" return 1 fi else @@ -173,12 +179,12 @@ main() { exit 1 fi - # Step 4: Copy scripts from init container - if ! copy_agent_scripts "$init_scripts_dir"; then + # Step 4: Create symlinks to scripts from init container + if ! symlink_agent_scripts "$init_scripts_dir"; then exit 1 fi - if ! copy_probe_scripts "$init_probes_dir"; then + if ! symlink_probe_scripts "$init_probes_dir"; then exit 1 fi From c01249b7e181be70c6cc9e0c9a4bda004658fa6b Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Mon, 21 Jul 2025 17:13:45 +0200 Subject: [PATCH 25/49] move to linking and cleanup and make it work --- .../construct/database_construction.go | 2 +- docker/mongodb-agent/agent-launcher-shim.sh | 200 +++++------------- 2 files changed, 55 insertions(+), 147 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 14bcd11be..aca709624 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -721,7 +721,7 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb container.WithArgs([]string{""}), container.WithImage(opts.InitDatabaseImage), container.WithEnvs(databaseEnvVars(opts)...), - container.WithCommand([]string{"bash", "-c", "tail -f /dev/null"}), + container.WithCommand([]string{"bash", "-c", "touch /tmp/agent-utilities-holder_marker && tail -F -n0 /tmp/agent-utilities-holder_marker"}), configureContainerSecurityContext, )} diff --git a/docker/mongodb-agent/agent-launcher-shim.sh b/docker/mongodb-agent/agent-launcher-shim.sh index 56cde07c4..f91f31424 100755 --- a/docker/mongodb-agent/agent-launcher-shim.sh +++ b/docker/mongodb-agent/agent-launcher-shim.sh @@ -1,200 +1,108 @@ #!/bin/bash set -e -# Configuration variables -TIMEOUT_SECONDS=300 # 5 minutes timeout -TARGET_SCRIPTS_DIR="/opt/scripts" +SCRIPTS_DIR="/opt/scripts" +# Set up dummy probe scripts +# liveness always returns success +# readiness always returns failure setup_dummy_probes() { echo "Setting up dummy probe scripts..." - cp /usr/local/bin/dummy-probe.sh "${TARGET_SCRIPTS_DIR}"/probe.sh - cp /usr/local/bin/dummy-readinessprobe "${TARGET_SCRIPTS_DIR}"/readinessprobe + cp /usr/local/bin/dummy-probe.sh "$SCRIPTS_DIR/probe.sh" + cp /usr/local/bin/dummy-readinessprobe "$SCRIPTS_DIR/readinessprobe" echo "Dummy probe scripts ready" } -# Find the init container process with retries +# wait max 5m find_init_container() { - echo "Looking for init/utilities container process..." - for attempt in {1..10}; do + for i in {1..150}; do local pid - pid=$(pgrep -f 'tail -f /dev/null' | head -n1) - if [ -n "$pid" ]; then - echo "Found init container process with PID: ${pid} (attempt ${attempt})" + pid=$(pgrep -f "agent-utilities-holder_marker" | head -n1) + if [[ -n "$pid" && -d "/proc/$pid/root/scripts" ]]; then echo "$pid" return 0 fi - echo "Attempt ${attempt}: No process found, retrying in 1 second..." - sleep 1 + echo "Waiting for init container... (attempt $i)" >&2 + sleep 2 done return 1 } -# Check if agent launcher already exists in image -check_existing_scripts() { - if [ -f "${TARGET_SCRIPTS_DIR}/agent-launcher.sh" ]; then - echo "Agent launcher script already exists in image" - return 0 - else - echo "ERROR: No init container found and no agent-launcher.sh in image" - echo "Available processes:" - ps aux - return 1 - fi -} - -# Wait for init container directories to be ready -wait_for_init_container() { +link_agent_scripts() { local init_scripts_dir="$1" - local init_container_root="$2" - local init_pid="$3" - local wait_count=0 - - if [ -d "${init_scripts_dir}" ]; then - echo "Scripts directory found immediately: ${init_scripts_dir}" - return 0 - fi - echo "Scripts directory not found, waiting..." - echo "Waiting for agent-launcher container to be ready..." - - while [ ! -d "${init_scripts_dir}" ]; do - sleep 1 - wait_count=$((wait_count + 1)) - - if [ $wait_count -ge $TIMEOUT_SECONDS ]; then - echo "ERROR: Timeout waiting for init container after ${TIMEOUT_SECONDS} seconds" - echo "Init container PID: ${init_pid}" - echo "Expected directory: ${init_scripts_dir}" - echo "Available directories in init container root:" - ls -la "${init_container_root}/" 2>/dev/null || echo "Cannot list init container root" - echo "Process still running?" - ps -p "${init_pid}" || echo "Process ${init_pid} no longer exists" + echo "Linking agent launcher scripts..." + for script in agent-launcher.sh agent-launcher-lib.sh; do + if [[ ! -f "$init_scripts_dir/$script" ]]; then + echo "ERROR: $script not found in init container" return 1 fi - - if [ $((wait_count % 30)) -eq 0 ]; then - echo "Still waiting for init container... (${wait_count}/${TIMEOUT_SECONDS} seconds)" - echo "Current init container root contents:" - ls -la "${init_container_root}/" 2>/dev/null || echo "Cannot access ${init_container_root}" - fi + ln -sf "$init_scripts_dir/$script" "$SCRIPTS_DIR/$script" + echo "Linked $script" done - - echo "Init container ready after ${wait_count} seconds" - return 0 } -# Create symlinks to agent launcher scripts from init container -symlink_agent_scripts() { - local init_scripts_dir="$1" - - echo "Creating symlinks to agent launcher scripts..." - echo "Available files in ${init_scripts_dir}:" - ls -la "${init_scripts_dir}/" 2>/dev/null || echo "Cannot list scripts directory" - - # Create symlinks for all files in the scripts directory - for script_file in "${init_scripts_dir}"/*; do - local filename - filename=$(basename "${script_file}") - if ! ln -sf "${script_file}" "${TARGET_SCRIPTS_DIR}/${filename}"; then - echo "ERROR: Failed to create symlink for ${filename}" - return 1 - fi - done - - echo "Agent launcher script symlinks created successfully" - return 0 -} - -# Create symlinks to probe scripts from init container -symlink_probe_scripts() { +# Link probe scripts from init container and replacing dummy ones +link_probe_scripts() { local init_probes_dir="$1" - echo "Creating symlinks to probe scripts..." - echo "Available files in ${init_probes_dir}:" - ls -la "${init_probes_dir}/" 2>/dev/null || echo "Probes directory not found" - - # Create symlink for readiness probe - if [ -f "${init_probes_dir}/readinessprobe" ]; then - if ln -sf "${init_probes_dir}/readinessprobe" "${TARGET_SCRIPTS_DIR}/readinessprobe"; then - echo "Replaced dummy readinessprobe with symlink to real one" + echo "Linking probe scripts..." + for probe in probe.sh readinessprobe; do + if [[ -f "$init_probes_dir/$probe" ]]; then + ln -sf "$init_probes_dir/$probe" "$SCRIPTS_DIR/$probe" + echo "Replaced dummy $probe with real one" else - echo "ERROR: Failed to create symlink for readinessprobe" - return 1 - fi - else - echo "WARNING: readinessprobe not found in init container at ${init_probes_dir}/readinessprobe" - echo "Keeping dummy readiness probe" - fi - - # Create symlink for liveness probe - if [ -f "${init_probes_dir}/probe.sh" ]; then - if ln -sf "${init_probes_dir}/probe.sh" "${TARGET_SCRIPTS_DIR}/probe.sh"; then - echo "Replaced dummy probe.sh with symlink to real one (liveness probe)" - else - echo "ERROR: Failed to create symlink for probe.sh" - return 1 + echo "WARNING: $probe not found in init container" + exit 1 fi - else - echo "WARNING: probe.sh not found in init container at ${init_probes_dir}/probe.sh" - echo "Keeping dummy liveness probe" - fi - - return 0 + done } -# Start the agent launcher -start_agent_launcher() { +start_agent() { echo "Starting agent launcher..." - echo "Final contents of ${TARGET_SCRIPTS_DIR}:" - ls -la "${TARGET_SCRIPTS_DIR}/" + echo "Final contents of $SCRIPTS_DIR:" + ls -la "$SCRIPTS_DIR" - if [ -f "${TARGET_SCRIPTS_DIR}/agent-launcher.sh" ]; then - exec "${TARGET_SCRIPTS_DIR}"/agent-launcher.sh + if [[ -f "$SCRIPTS_DIR/agent-launcher.sh" ]]; then + echo "Found agent-launcher.sh, executing..." + exec "$SCRIPTS_DIR/agent-launcher.sh" else - echo "ERROR: agent-launcher.sh not found at ${TARGET_SCRIPTS_DIR}/agent-launcher.sh" - return 1 + echo "ERROR: agent-launcher.sh not found" + exit 1 fi } -# Main execution flow main() { - # Step 1: Setup dummy probes immediately setup_dummy_probes - # Step 2: Try to find init container - if ! init_pid=$(find_init_container); then - echo "No init container found after 5 attempts. Checking if scripts already exist in image..." + if init_pid=$(find_init_container); then + echo "Found init container with PID: $init_pid" - if ! check_existing_scripts; then - exit 1 - fi + init_root="/proc/$init_pid/root" + init_scripts="$init_root/scripts" + init_probes="$init_root/probes" - else - # Step 3: Setup paths and wait for init container - init_container_root="/proc/${init_pid}/root" - init_scripts_dir="${init_container_root}/scripts" - init_probes_dir="${init_container_root}/probes" - - if ! wait_for_init_container "$init_scripts_dir" "$init_container_root" "$init_pid"; then + # Verify scripts directory exists + if [[ ! -d "$init_scripts" ]]; then + echo "ERROR: Scripts directory $init_scripts not found" exit 1 fi - # Step 4: Create symlinks to scripts from init container - if ! symlink_agent_scripts "$init_scripts_dir"; then + # Verify scripts directory exists + if [[ ! -d "$init_probes" ]]; then + echo "ERROR: Scripts directory $init_probes not found" exit 1 fi - if ! symlink_probe_scripts "$init_probes_dir"; then + # Link scripts from init container + link_agent_scripts "$init_scripts" + link_probe_scripts "$init_probes" + else + echo "No init container found exiting" exit 1 - fi - - # Step 5: Make scripts executable - chmod +x "${TARGET_SCRIPTS_DIR}"/*.sh "${TARGET_SCRIPTS_DIR}"/readinessprobe 2>/dev/null || true fi - # Step 6: Start the agent launcher - start_agent_launcher + start_agent } -# Run main function main "$@" From 38ad9579d3b5d7926437b1bb8392ae6748ce0777 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Mon, 21 Jul 2025 17:34:53 +0200 Subject: [PATCH 26/49] cleanup some tests --- controllers/operator/construct/database_construction.go | 4 +--- controllers/operator/mongodbopsmanager_controller_test.go | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index aca709624..d5c36841a 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -692,7 +692,7 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb agentContainerModifications := []func(*corev1.Container){container.Apply( container.WithName(util.AgentContainerName), - container.WithImage("268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/nnguyen-kops/mongodb-agent-ubi:latest-amd64"), + container.WithImage(opts.AgentImage), container.WithEnvs(databaseEnvVars(opts)...), container.WithArgs([]string{}), container.WithImagePullPolicy(corev1.PullPolicy(env.ReadOrPanic(util.AutomationAgentImagePullPolicy))), // nolint:forbidigo @@ -1032,7 +1032,6 @@ func DatabaseLivenessProbe() probes.Modification { ) } -// TODO: make this work for static no matrix func DatabaseReadinessProbe() probes.Modification { return probes.Apply( probes.WithExecCommand([]string{databaseReadinessProbeCommand}), @@ -1042,7 +1041,6 @@ func DatabaseReadinessProbe() probes.Modification { ) } -// TODO: make this work for static no matrix func DatabaseStartupProbe() probes.Modification { return probes.Apply( probes.WithExecCommand([]string{databaseLivenessProbeCommand}), diff --git a/controllers/operator/mongodbopsmanager_controller_test.go b/controllers/operator/mongodbopsmanager_controller_test.go index 83b26b4df..e11d59bcc 100644 --- a/controllers/operator/mongodbopsmanager_controller_test.go +++ b/controllers/operator/mongodbopsmanager_controller_test.go @@ -590,9 +590,6 @@ func TestOpsManagerReconcileContainerImagesWithStaticArchitecture(t *testing.T) require.Len(t, appDBSts.Spec.Template.Spec.InitContainers, 0) require.Len(t, appDBSts.Spec.Template.Spec.Containers, 3) - - // Version from the mapping file (agent version + operator version) - assert.Contains(t, appDBSts.Spec.Template.Spec.Containers[0].Image, "-1_9.9.9-test") assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-appdb-database-ubi@sha256:MONGODB_SHA", appDBSts.Spec.Template.Spec.Containers[1].Image) // In static architecture this container is a copy of agent container assert.Equal(t, appDBSts.Spec.Template.Spec.Containers[0].Image, appDBSts.Spec.Template.Spec.Containers[2].Image) From c7749e46820d90a9b638afef35761e29c02482ad Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Tue, 22 Jul 2025 11:46:08 +0200 Subject: [PATCH 27/49] fix unit test --- .../operator/construct/construction_test.go | 6 +- .../construct/database_construction.go | 5 +- .../mongodbmultireplicaset_controller_test.go | 3 +- .../mongodbreplicaset_controller_test.go | 28 ++++- .../mongodbshardedcluster_controller_test.go | 117 +++--------------- .../mongodbstandalone_controller_test.go | 3 +- 6 files changed, 48 insertions(+), 114 deletions(-) diff --git a/controllers/operator/construct/construction_test.go b/controllers/operator/construct/construction_test.go index 6108b1c8e..0382abb6d 100644 --- a/controllers/operator/construct/construction_test.go +++ b/controllers/operator/construct/construction_test.go @@ -28,20 +28,20 @@ func TestBuildStatefulSet_PersistentFlagStatic(t *testing.T) { mdb := mdbv1.NewReplicaSetBuilder().SetPersistent(nil).Build() set := DatabaseStatefulSet(*mdb, ReplicaSetOptions(GetPodEnvOptions()), zap.S()) assert.Len(t, set.Spec.VolumeClaimTemplates, 1) - assert.Len(t, set.Spec.Template.Spec.Containers[0].VolumeMounts, 7) + assert.Len(t, set.Spec.Template.Spec.Containers[0].VolumeMounts, 8) assert.Len(t, set.Spec.Template.Spec.Containers[1].VolumeMounts, 7) mdb = mdbv1.NewReplicaSetBuilder().SetPersistent(util.BooleanRef(true)).Build() set = DatabaseStatefulSet(*mdb, ReplicaSetOptions(GetPodEnvOptions()), zap.S()) assert.Len(t, set.Spec.VolumeClaimTemplates, 1) - assert.Len(t, set.Spec.Template.Spec.Containers[0].VolumeMounts, 7) + assert.Len(t, set.Spec.Template.Spec.Containers[0].VolumeMounts, 8) assert.Len(t, set.Spec.Template.Spec.Containers[1].VolumeMounts, 7) // If no persistence is set then we still mount init scripts mdb = mdbv1.NewReplicaSetBuilder().SetPersistent(util.BooleanRef(false)).Build() set = DatabaseStatefulSet(*mdb, ReplicaSetOptions(GetPodEnvOptions()), zap.S()) assert.Len(t, set.Spec.VolumeClaimTemplates, 0) - assert.Len(t, set.Spec.Template.Spec.Containers[0].VolumeMounts, 7) + assert.Len(t, set.Spec.Template.Spec.Containers[0].VolumeMounts, 8) assert.Len(t, set.Spec.Template.Spec.Containers[1].VolumeMounts, 7) } diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index d5c36841a..7aa3ad691 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -366,7 +366,8 @@ func DatabaseStatefulSetHelper(mdb databaseStatefulSetSource, stsOpts *DatabaseS stsOpts.ExtraEnvs = extraEnvs templateFunc := buildMongoDBPodTemplateSpec(*stsOpts, mdb) - return statefulset.New(buildDatabaseStatefulSetConfigurationFunction(mdb, templateFunc, *stsOpts, log)) + sts := statefulset.New(buildDatabaseStatefulSetConfigurationFunction(mdb, templateFunc, *stsOpts, log)) + return sts } // buildVaultDatabaseSecretsToInject fully constructs the DatabaseSecretsToInject required to @@ -512,7 +513,7 @@ func buildDatabaseStatefulSetConfigurationFunction(mdb databaseStatefulSetSource configureImagePullSecrets, podTemplateSpecFunc, } - podTemplateModifications = append(podTemplateModifications, staticMods...) + podTemplateModifications = append(podTemplateModifications, staticMods...) return statefulset.Apply( // StatefulSet metadata diff --git a/controllers/operator/mongodbmultireplicaset_controller_test.go b/controllers/operator/mongodbmultireplicaset_controller_test.go index 9eb1095ad..21a6b1c99 100644 --- a/controllers/operator/mongodbmultireplicaset_controller_test.go +++ b/controllers/operator/mongodbmultireplicaset_controller_test.go @@ -166,8 +166,7 @@ func TestMultiReplicaSetClusterReconcileContainerImagesWithStaticArchitecture(t require.Len(t, sts.Spec.Template.Spec.Containers, 3) // Version from OM - assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1", sts.Spec.Template.Spec.Containers[0].Image) - assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[2].Image) + VerifyStaticContainers(t, sts.Spec.Template.Spec.Containers) }) } } diff --git a/controllers/operator/mongodbreplicaset_controller_test.go b/controllers/operator/mongodbreplicaset_controller_test.go index bf93f7616..64c3f724c 100644 --- a/controllers/operator/mongodbreplicaset_controller_test.go +++ b/controllers/operator/mongodbreplicaset_controller_test.go @@ -151,8 +151,26 @@ func TestReplicaSetClusterReconcileContainerImagesWithStaticArchitecture(t *test require.Len(t, sts.Spec.Template.Spec.Containers, 3) // Version from OM - assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1", sts.Spec.Template.Spec.Containers[0].Image) - assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[2].Image) + VerifyStaticContainers(t, sts.Spec.Template.Spec.Containers) +} + +func VerifyStaticContainers(t *testing.T, containers []corev1.Container) { + agentContainerImage := findContainerImage(containers, util.AgentContainerName) + require.NotNil(t, agentContainerImage, "Agent container not found") + assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1", agentContainerImage) + + mongoContainerImage := findContainerImage(containers, util.DatabaseContainerName) + require.NotNil(t, mongoContainerImage, "MongoDB container not found") + assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", mongoContainerImage) +} + +func findContainerImage(containers []corev1.Container, containerName string) string { + for _, container := range containers { + if container.Name == containerName { + return container.Image + } + } + return "" } func buildReplicaSetWithCustomProjectName(rsName string) (*mdbv1.MongoDB, *corev1.ConfigMap, string) { @@ -538,9 +556,9 @@ func TestReplicaSetCustomPodSpecTemplateStatic(t *testing.T) { assertPodSpecSts(t, &statefulSet, podSpec.NodeName, podSpec.Hostname, podSpec.RestartPolicy) podSpecTemplate := statefulSet.Spec.Template.Spec - assert.Len(t, podSpecTemplate.Containers, 3, "Should have 3 containers now") - assert.Equal(t, util.AgentContainerName, podSpecTemplate.Containers[0].Name, "Database container should always be first") - assert.Equal(t, "my-custom-container", podSpecTemplate.Containers[2].Name, "Custom container should be second") + assert.Len(t, podSpecTemplate.Containers, 4, "Should have 4 containers now") + assert.Equal(t, util.AgentContainerName, podSpecTemplate.Containers[0].Name, "Agent container should be first alphabetically") + assert.Equal(t, "my-custom-container", podSpecTemplate.Containers[len(podSpecTemplate.Containers)-1].Name, "Custom container should be last") } func TestFeatureControlPolicyAndTagAddedWithNewerOpsManager(t *testing.T) { diff --git a/controllers/operator/mongodbshardedcluster_controller_test.go b/controllers/operator/mongodbshardedcluster_controller_test.go index af328e5b5..457627226 100644 --- a/controllers/operator/mongodbshardedcluster_controller_test.go +++ b/controllers/operator/mongodbshardedcluster_controller_test.go @@ -322,8 +322,7 @@ func TestShardedClusterReconcileContainerImagesWithStaticArchitecture(t *testing require.Len(t, sts.Spec.Template.Spec.Containers, 3) // Version from OM - assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1", sts.Spec.Template.Spec.Containers[0].Image) - assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[2].Image) + VerifyStaticContainers(t, sts.Spec.Template.Spec.Containers) }) } } @@ -928,22 +927,22 @@ func TestShardedCustomPodSpecTemplate(t *testing.T) { assertPodSpecSts(t, &statefulSetScConfig, configSrvPodSpec.NodeName, configSrvPodSpec.Hostname, configSrvPodSpec.RestartPolicy) podSpecTemplateSc0 := statefulSetSc0.Spec.Template.Spec - assert.Len(t, podSpecTemplateSc0.Containers, 2, "Should have 2 containers now") + assert.Len(t, podSpecTemplateSc0.Containers, 2, "Should have 3 containers now") assert.Equal(t, util.DatabaseContainerName, podSpecTemplateSc0.Containers[0].Name, "Database container should always be first") assert.Equal(t, "my-custom-container-sc", podSpecTemplateSc0.Containers[1].Name, "Custom container should be second") podSpecTemplateSc1 := statefulSetSc1.Spec.Template.Spec - assert.Len(t, podSpecTemplateSc1.Containers, 2, "Should have 2 containers now") + assert.Len(t, podSpecTemplateSc1.Containers, 2, "Should have 3 containers now") assert.Equal(t, util.DatabaseContainerName, podSpecTemplateSc1.Containers[0].Name, "Database container should always be first") assert.Equal(t, "my-custom-container-sc", podSpecTemplateSc1.Containers[1].Name, "Custom container should be second") podSpecTemplateMongoS := statefulSetMongoS.Spec.Template.Spec - assert.Len(t, podSpecTemplateMongoS.Containers, 2, "Should have 2 containers now") + assert.Len(t, podSpecTemplateMongoS.Containers, 2, "Should have 3 containers now") assert.Equal(t, util.DatabaseContainerName, podSpecTemplateMongoS.Containers[0].Name, "Database container should always be first") assert.Equal(t, "my-custom-container-mongos", podSpecTemplateMongoS.Containers[1].Name, "Custom container should be second") podSpecTemplateScConfig := statefulSetScConfig.Spec.Template.Spec - assert.Len(t, podSpecTemplateScConfig.Containers, 2, "Should have 2 containers now") + assert.Len(t, podSpecTemplateScConfig.Containers, 2, "Should have 3 containers now") assert.Equal(t, util.DatabaseContainerName, podSpecTemplateScConfig.Containers[0].Name, "Database container should always be first") assert.Equal(t, "my-custom-container-config", podSpecTemplateScConfig.Containers[1].Name, "Custom container should be second") } @@ -1027,24 +1026,24 @@ func TestShardedCustomPodStaticSpecTemplate(t *testing.T) { assertPodSpecSts(t, &statefulSetScConfig, configSrvPodSpec.NodeName, configSrvPodSpec.Hostname, configSrvPodSpec.RestartPolicy) podSpecTemplateSc0 := statefulSetSc0.Spec.Template.Spec - assert.Len(t, podSpecTemplateSc0.Containers, 3, "Should have 2 containers now") - assert.Equal(t, util.AgentContainerName, podSpecTemplateSc0.Containers[0].Name, "Database container should always be first") - assert.Equal(t, "my-custom-container-sc", podSpecTemplateSc0.Containers[2].Name, "Custom container should be second") + assert.Len(t, podSpecTemplateSc0.Containers, 4, "Should have 4 containers (3 base + 1 custom)") + assert.Equal(t, util.AgentContainerName, podSpecTemplateSc0.Containers[0].Name, "Agent container should be first alphabetically") + assert.Equal(t, "my-custom-container-sc", podSpecTemplateSc0.Containers[len(podSpecTemplateSc0.Containers)-1].Name, "Custom container should be last") podSpecTemplateSc1 := statefulSetSc1.Spec.Template.Spec - assert.Len(t, podSpecTemplateSc1.Containers, 3, "Should have 2 containers now") - assert.Equal(t, util.AgentContainerName, podSpecTemplateSc1.Containers[0].Name, "Database container should always be first") - assert.Equal(t, "my-custom-container-sc", podSpecTemplateSc1.Containers[2].Name, "Custom container should be second") + assert.Len(t, podSpecTemplateSc1.Containers, 4, "Should have 4 containers (3 base + 1 custom)") + assert.Equal(t, util.AgentContainerName, podSpecTemplateSc1.Containers[0].Name, "Agent container should be first alphabetically") + assert.Equal(t, "my-custom-container-sc", podSpecTemplateSc1.Containers[len(podSpecTemplateSc1.Containers)-1].Name, "Custom container should be last") podSpecTemplateMongoS := statefulSetMongoS.Spec.Template.Spec - assert.Len(t, podSpecTemplateMongoS.Containers, 3, "Should have 2 containers now") - assert.Equal(t, util.AgentContainerName, podSpecTemplateMongoS.Containers[0].Name, "Database container should always be first") - assert.Equal(t, "my-custom-container-mongos", podSpecTemplateMongoS.Containers[2].Name, "Custom container should be second") + assert.Len(t, podSpecTemplateMongoS.Containers, 4, "Should have 4 containers (3 base + 1 custom)") + assert.Equal(t, util.AgentContainerName, podSpecTemplateMongoS.Containers[0].Name, "Agent container should be first alphabetically") + assert.Equal(t, "my-custom-container-mongos", podSpecTemplateMongoS.Containers[len(podSpecTemplateMongoS.Containers)-1].Name, "Custom container should be last") podSpecTemplateScConfig := statefulSetScConfig.Spec.Template.Spec - assert.Len(t, podSpecTemplateScConfig.Containers, 3, "Should have 2 containers now") - assert.Equal(t, util.AgentContainerName, podSpecTemplateScConfig.Containers[0].Name, "Database container should always be first") - assert.Equal(t, "my-custom-container-config", podSpecTemplateScConfig.Containers[2].Name, "Custom container should be second") + assert.Len(t, podSpecTemplateScConfig.Containers, 4, "Should have 4 containers (3 base + 1 custom)") + assert.Equal(t, util.AgentContainerName, podSpecTemplateScConfig.Containers[0].Name, "Agent container should be first alphabetically") + assert.Equal(t, "my-custom-container-config", podSpecTemplateScConfig.Containers[len(podSpecTemplateScConfig.Containers)-1].Name, "Custom container should be last") } func TestFeatureControlsNoAuth(t *testing.T) { @@ -1793,88 +1792,6 @@ func SingleClusterShardedScalingWithOverridesTestCase(t *testing.T, tc SingleClu } } -func TestSingleClusterShardedScalingWithOverrides(t *testing.T) { - scDefaultName := test.SCBuilderDefaultName + "-" - testCases := []SingleClusterShardedScalingTestCase{ - { - name: "Basic sample test", - scalingSteps: []SingleClusterShardedScalingStep{ - { - name: "Initial scaling", - shardCount: 3, - mongodsPerShardCount: 3, - shardOverrides: map[string]int{ - scDefaultName + "0": 5, - }, - expectedShardDistribution: []int{ - 5, - 3, - 3, - }, - }, - { - name: "Scale up mongodsPerShard", - shardCount: 3, - mongodsPerShardCount: 5, - shardOverrides: map[string]int{ - scDefaultName + "0": 5, - }, - expectedShardDistribution: []int{ - 5, - 5, - 5, - }, - }, - }, - }, - { - // This operation works in unit test only - // In e2e tests, the operator is waiting for uncreated hostnames to be ready - name: "Scale overrides up and down", - scalingSteps: []SingleClusterShardedScalingStep{ - { - name: "Initial deployment", - shardCount: 4, - mongodsPerShardCount: 2, - shardOverrides: map[string]int{ - scDefaultName + "0": 3, - scDefaultName + "1": 3, - scDefaultName + "3": 2, - }, - expectedShardDistribution: []int{ - 3, - 3, - 2, // Not overridden - 2, - }, - }, - { - name: "Scale overrides", - shardCount: 4, - mongodsPerShardCount: 2, - shardOverrides: map[string]int{ - scDefaultName + "0": 2, // Scaled down - scDefaultName + "1": 2, // Scaled down - scDefaultName + "3": 3, // Scaled up - }, - expectedShardDistribution: []int{ - 2, // Scaled down - 2, // Scaled down - 2, // Not overridden - 3, // Scaled up - }, - }, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - SingleClusterShardedScalingWithOverridesTestCase(t, tc) - }) - } -} - func generateHostsWithDistributionSingleCluster(stsName string, namespace string, memberCount int, clusterDomain string, externalClusterDomain string) ([]string, []string) { var hosts []string var podNames []string diff --git a/controllers/operator/mongodbstandalone_controller_test.go b/controllers/operator/mongodbstandalone_controller_test.go index f807be6a6..f6438ed68 100644 --- a/controllers/operator/mongodbstandalone_controller_test.go +++ b/controllers/operator/mongodbstandalone_controller_test.go @@ -131,8 +131,7 @@ func TestStandaloneClusterReconcileContainerImagesWithStaticArchitecture(t *test require.Len(t, sts.Spec.Template.Spec.Containers, 3) // Version from OM - assert.Equal(t, "quay.io/mongodb/mongodb-agent-ubi:12.0.30.7791-1", sts.Spec.Template.Spec.Containers[0].Image) - assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-server:@sha256:MONGODB_DATABASE", sts.Spec.Template.Spec.Containers[2].Image) + VerifyStaticContainers(t, sts.Spec.Template.Spec.Containers) } // TestOnAddStandaloneWithDelay checks the reconciliation on standalone creation with some "delay" in getting From bdc1087b8985015735ae920ec766042bc4219e79 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 23 Jul 2025 14:50:34 +0200 Subject: [PATCH 28/49] add appdb support --- .../operator/construct/appdb_construction.go | 19 ++-- docker/mongodb-agent/Dockerfile | 1 + docker/mongodb-agent/Dockerfile.builder | 1 + docker/mongodb-agent/agent-launcher-shim.sh | 91 ++---------------- docker/mongodb-agent/setup-agent-files.sh | 95 +++++++++++++++++++ .../construct/build_statefulset_test.go | 8 +- .../construct/mongodbstatefulset.go | 86 ++++++++++------- .../controllers/replica_set_controller.go | 2 +- 8 files changed, 174 insertions(+), 129 deletions(-) create mode 100755 docker/mongodb-agent/setup-agent-files.sh diff --git a/controllers/operator/construct/appdb_construction.go b/controllers/operator/construct/appdb_construction.go index 6056e25af..d8b0f0266 100644 --- a/controllers/operator/construct/appdb_construction.go +++ b/controllers/operator/construct/appdb_construction.go @@ -122,6 +122,12 @@ func appDbPodSpec(initContainerImage string, om om.MongoDBOpsManager) podtemplat construct.AgentName, container.WithResourceRequirements(buildRequirementsFromPodSpec(*appdbPodSpec)), ) + automationUtilitiesPodTemplateFunc := podtemplatespec.WithContainer( + util.AgentContainerUtilitiesName, + container.WithResourceRequirements(buildRequirementsFromPodSpec(*appdbPodSpec)), + ) + scriptsVolumeMount := statefulset.CreateVolumeMount("agent-scripts", "/opt/scripts", statefulset.WithReadOnly(false)) + hooksVolumeMount := statefulset.CreateVolumeMount("hooks", "/hooks", statefulset.WithReadOnly(false)) initUpdateFunc := podtemplatespec.NOOP() if !architectures.IsRunningStaticArchitecture(om.Annotations) { @@ -130,8 +136,6 @@ func appDbPodSpec(initContainerImage string, om om.MongoDBOpsManager) podtemplat // volumes of different containers. initUpdateFunc = func(templateSpec *corev1.PodTemplateSpec) { templateSpec.Spec.InitContainers = []corev1.Container{} - scriptsVolumeMount := statefulset.CreateVolumeMount("agent-scripts", "/opt/scripts", statefulset.WithReadOnly(false)) - hooksVolumeMount := statefulset.CreateVolumeMount("hooks", "/hooks", statefulset.WithReadOnly(false)) podtemplatespec.WithInitContainer(InitAppDbContainerName, buildAppDBInitContainer(initContainerImage, []corev1.VolumeMount{scriptsVolumeMount, hooksVolumeMount}))(templateSpec) } } @@ -139,6 +143,7 @@ func appDbPodSpec(initContainerImage string, om om.MongoDBOpsManager) podtemplat return podtemplatespec.Apply( mongoPodTemplateFunc, automationPodTemplateFunc, + automationUtilitiesPodTemplateFunc, initUpdateFunc, ) } @@ -390,7 +395,7 @@ func AppDbStatefulSet(opsManager om.MongoDBOpsManager, podVars *env.PodEnvVars, } // We copy the Automation Agent command from community and add the agent startup parameters - automationAgentCommand := construct.AutomationAgentCommand(true, opsManager.Spec.AppDB.GetAgentLogLevel(), opsManager.Spec.AppDB.GetAgentLogFile(), opsManager.Spec.AppDB.GetAgentMaxLogFileDurationHours()) + automationAgentCommand := construct.AutomationAgentCommand(true, true, opsManager.Spec.AppDB.GetAgentLogLevel(), opsManager.Spec.AppDB.GetAgentLogFile(), opsManager.Spec.AppDB.GetAgentMaxLogFileDurationHours()) idx := len(automationAgentCommand) - 1 automationAgentCommand[idx] += appDb.AutomationAgent.StartupParameters.ToCommandLineArgs() @@ -403,12 +408,12 @@ func AppDbStatefulSet(opsManager om.MongoDBOpsManager, podVars *env.PodEnvVars, MountPath: "/var/lib/automation/config/acVersion", } - // Here we ask to craete init containers which also creates required volumens. + // Here we ask to create init containers which also creates required volumens. // Note that we provide empty images for init containers. They are not important // at this stage beucase later we will define our own init containers for non-static architecture. - mod := construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&opsManager.Spec.AppDB, scaler, opts.MongodbImage, opts.AgentImage, "", "", true) + mod := construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&opsManager.Spec.AppDB, scaler, opts.MongodbImage, opts.AgentImage, "", "", true, opts.InitAppDBImage) if architectures.IsRunningStaticArchitecture(opsManager.Annotations) { - mod = construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&opsManager.Spec.AppDB, scaler, opts.MongodbImage, opts.AgentImage, "", "", false) + mod = construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&opsManager.Spec.AppDB, scaler, opts.MongodbImage, opts.AgentImage, "", "", false, opts.InitAppDBImage) } sts := statefulset.New( @@ -516,7 +521,7 @@ func addMonitoringContainer(appDB om.AppDBSpec, podVars env.PodEnvVars, opts App } // Construct the command by concatenating: // 1. The base command - from community - command := construct.MongodbUserCommandWithAPIKeyExport + command := construct.GetMongodbUserCommandWithAPIKeyExport(false) command += "agent/mongodb-agent" command += " -healthCheckFilePath=" + monitoringAgentHealthStatusFilePathValue command += " -serveStatusPort=5001" diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index da48bd0b9..78d00c5f4 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -47,6 +47,7 @@ COPY --from=base /data/mongodb-agent.tar.gz /agent COPY --from=base /data/mongodb-tools.tgz /agent COPY --from=base /data/LICENSE /licenses/LICENSE COPY --from=base /opt/scripts/agent-launcher-shim.sh /usr/local/bin/agent-launcher-shim.sh +COPY --from=base /opt/scripts/setup-agent-files.sh /usr/local/bin/setup-agent-files.sh # Copy dummy probe scripts to a safe location that won't be overwritten by volume mount COPY --from=base /opt/scripts/dummy-probe.sh /usr/local/bin/dummy-probe.sh diff --git a/docker/mongodb-agent/Dockerfile.builder b/docker/mongodb-agent/Dockerfile.builder index 11846cea4..ac4dd31f0 100644 --- a/docker/mongodb-agent/Dockerfile.builder +++ b/docker/mongodb-agent/Dockerfile.builder @@ -10,5 +10,6 @@ ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE COPY ./docker/mongodb-agent/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh +COPY ./docker/mongodb-agent/setup-agent-files.sh /opt/scripts/setup-agent-files.sh COPY ./docker/mongodb-agent/dummy-probe.sh /opt/scripts/dummy-probe.sh COPY ./docker/mongodb-agent/dummy-readinessprobe.sh /opt/scripts/dummy-readinessprobe.sh diff --git a/docker/mongodb-agent/agent-launcher-shim.sh b/docker/mongodb-agent/agent-launcher-shim.sh index f91f31424..4a3e62de9 100755 --- a/docker/mongodb-agent/agent-launcher-shim.sh +++ b/docker/mongodb-agent/agent-launcher-shim.sh @@ -3,62 +3,8 @@ set -e SCRIPTS_DIR="/opt/scripts" -# Set up dummy probe scripts -# liveness always returns success -# readiness always returns failure -setup_dummy_probes() { - echo "Setting up dummy probe scripts..." - cp /usr/local/bin/dummy-probe.sh "$SCRIPTS_DIR/probe.sh" - cp /usr/local/bin/dummy-readinessprobe "$SCRIPTS_DIR/readinessprobe" - echo "Dummy probe scripts ready" -} - -# wait max 5m -find_init_container() { - for i in {1..150}; do - local pid - pid=$(pgrep -f "agent-utilities-holder_marker" | head -n1) - if [[ -n "$pid" && -d "/proc/$pid/root/scripts" ]]; then - echo "$pid" - return 0 - fi - echo "Waiting for init container... (attempt $i)" >&2 - sleep 2 - done - return 1 -} - -link_agent_scripts() { - local init_scripts_dir="$1" - - echo "Linking agent launcher scripts..." - for script in agent-launcher.sh agent-launcher-lib.sh; do - if [[ ! -f "$init_scripts_dir/$script" ]]; then - echo "ERROR: $script not found in init container" - return 1 - fi - ln -sf "$init_scripts_dir/$script" "$SCRIPTS_DIR/$script" - echo "Linked $script" - done -} - -# Link probe scripts from init container and replacing dummy ones -link_probe_scripts() { - local init_probes_dir="$1" - - echo "Linking probe scripts..." - for probe in probe.sh readinessprobe; do - if [[ -f "$init_probes_dir/$probe" ]]; then - ln -sf "$init_probes_dir/$probe" "$SCRIPTS_DIR/$probe" - echo "Replaced dummy $probe with real one" - else - echo "WARNING: $probe not found in init container" - exit 1 - fi - done -} - -start_agent() { +# Function to start the agent launcher +start_agent_launcher() { echo "Starting agent launcher..." echo "Final contents of $SCRIPTS_DIR:" ls -la "$SCRIPTS_DIR" @@ -73,36 +19,13 @@ start_agent() { } main() { - setup_dummy_probes - - if init_pid=$(find_init_container); then - echo "Found init container with PID: $init_pid" - - init_root="/proc/$init_pid/root" - init_scripts="$init_root/scripts" - init_probes="$init_root/probes" - - # Verify scripts directory exists - if [[ ! -d "$init_scripts" ]]; then - echo "ERROR: Scripts directory $init_scripts not found" - exit 1 - fi - - # Verify scripts directory exists - if [[ ! -d "$init_probes" ]]; then - echo "ERROR: Scripts directory $init_probes not found" - exit 1 - fi - - # Link scripts from init container - link_agent_scripts "$init_scripts" - link_probe_scripts "$init_probes" - else - echo "No init container found exiting" - exit 1 + echo "Running setup-agent-files.sh..." + if ! $SCRIPTS_DIR/setup-agent-files.sh; then + echo "ERROR: Failed to set up agent files" + exit 1 fi - start_agent + start_agent_launcher } main "$@" diff --git a/docker/mongodb-agent/setup-agent-files.sh b/docker/mongodb-agent/setup-agent-files.sh new file mode 100755 index 000000000..6a1b8a007 --- /dev/null +++ b/docker/mongodb-agent/setup-agent-files.sh @@ -0,0 +1,95 @@ +#!/bin/bash +set -e + +SCRIPTS_DIR="/opt/scripts" + +# Set up dummy probe scripts +# liveness always returns success +# readiness always returns failure +setup_dummy_probes() { + echo "Setting up dummy probe scripts..." + cp /usr/local/bin/dummy-probe.sh "$SCRIPTS_DIR/probe.sh" + cp /usr/local/bin/dummy-readinessprobe "$SCRIPTS_DIR/readinessprobe" + echo "Dummy probe scripts ready" +} + +# wait max 5m for init container to be ready +find_init_container() { + for i in {1..150}; do + local pid + pid=$(pgrep -f "agent-utilities-holder_marker" | head -n1) + if [[ -n "$pid" && -d "/proc/$pid/root/scripts" ]]; then + echo "$pid" + return 0 + fi + echo "Waiting for init container... (attempt $i)" >&2 + sleep 2 + done + return 1 +} + +link_agent_scripts() { + local init_scripts_dir="$1" + + echo "Linking agent launcher scripts..." + for script in agent-launcher.sh agent-launcher-lib.sh; do + ln -sf "$init_scripts_dir/$script" "$SCRIPTS_DIR/$script" + echo "Linked $script" + done +} + +# Link probe scripts from init container, replacing dummy ones +link_probe_scripts() { + local init_probes_dir="$1" + + echo "Linking probe scripts..." + for probe in probe.sh readinessprobe; do + if [[ -f "$init_probes_dir/$probe" ]]; then + ln -sf "$init_probes_dir/$probe" "$SCRIPTS_DIR/$probe" + echo "Replaced dummy $probe with real one" + else + echo "WARNING: $probe not found in init container" + exit 1 + fi + done +} + +# Main function to set up all files +main() { + setup_dummy_probes + + if init_pid=$(find_init_container); then + echo "Found init container with PID: $init_pid" + + init_root="/proc/$init_pid/root" + init_scripts="$init_root/scripts" + init_probes="$init_root/probes" + + # Verify scripts directory exists + if [[ ! -d "$init_scripts" ]]; then + echo "ERROR: Scripts directory $init_scripts not found" + exit 1 + fi + + # Verify probes directory exists + if [[ ! -d "$init_probes" ]]; then + echo "ERROR: Probes directory $init_probes not found" + exit 1 + fi + + # Link scripts from init container + link_agent_scripts "$init_scripts" + link_probe_scripts "$init_probes" + + echo "File setup completed successfully" + exit 0 + else + echo "No init container found" + exit 1 + fi +} + +# Only run main if script is executed directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/mongodb-community-operator/controllers/construct/build_statefulset_test.go b/mongodb-community-operator/controllers/construct/build_statefulset_test.go index 42aaa27f8..4d032d5bf 100644 --- a/mongodb-community-operator/controllers/construct/build_statefulset_test.go +++ b/mongodb-community-operator/controllers/construct/build_statefulset_test.go @@ -34,7 +34,7 @@ func newTestReplicaSet() mdbv1.MongoDBCommunity { func TestMultipleCalls_DoNotCauseSideEffects(t *testing.T) { mdb := newTestReplicaSet() - stsFunc := BuildMongoDBReplicaSetStatefulSetModificationFunction(&mdb, &mdb, "fake-mongodbImage", "fake-agentImage", "fake-versionUpgradeHookImage", "fake-readinessProbeImage", true) + stsFunc := BuildMongoDBReplicaSetStatefulSetModificationFunction(&mdb, &mdb, "fake-mongodbImage", "fake-agentImage", "fake-versionUpgradeHookImage", "fake-readinessProbeImage", true, "") sts := &appsv1.StatefulSet{} t.Run("1st Call", func(t *testing.T) { @@ -55,7 +55,7 @@ func TestManagedSecurityContext(t *testing.T) { t.Setenv(podtemplatespec.ManagedSecurityContextEnv, "true") mdb := newTestReplicaSet() - stsFunc := BuildMongoDBReplicaSetStatefulSetModificationFunction(&mdb, &mdb, "fake-mongodbImage", "fake-agentImage", "fake-versionUpgradeHookImage", "fake-readinessProbeImage", true) + stsFunc := BuildMongoDBReplicaSetStatefulSetModificationFunction(&mdb, &mdb, "fake-mongodbImage", "fake-agentImage", "fake-versionUpgradeHookImage", "fake-readinessProbeImage", true, "") sts := &appsv1.StatefulSet{} stsFunc(sts) @@ -83,14 +83,14 @@ func TestMongod_Container(t *testing.T) { } func TestMongoDBAgentCommand(t *testing.T) { - cmd := AutomationAgentCommand(false, mdbv1.LogLevelInfo, "testfile", 24) + cmd := AutomationAgentCommand(false, false, mdbv1.LogLevelInfo, "testfile", 24) baseCmd := MongodbUserCommand + BaseAgentCommand() + " -cluster=" + clusterFilePath + automationAgentOptions assert.Len(t, cmd, 3) assert.Equal(t, cmd[0], "/bin/bash") assert.Equal(t, cmd[1], "-c") assert.Equal(t, cmd[2], baseCmd+" -logFile testfile -logLevel INFO -maxLogFileDurationHrs 24") - cmd = AutomationAgentCommand(false, mdbv1.LogLevelInfo, "/dev/stdout", 24) + cmd = AutomationAgentCommand(false, false, mdbv1.LogLevelInfo, "/dev/stdout", 24) assert.Len(t, cmd, 3) assert.Equal(t, cmd[0], "/bin/bash") assert.Equal(t, cmd[1], "-c") diff --git a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go index bf0a16807..d80f35f98 100644 --- a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go +++ b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go @@ -20,6 +20,7 @@ import ( "github.com/mongodb/mongodb-kubernetes/mongodb-community-operator/pkg/readiness/config" "github.com/mongodb/mongodb-kubernetes/mongodb-community-operator/pkg/util/scale" "github.com/mongodb/mongodb-kubernetes/pkg/statefulset" + "github.com/mongodb/mongodb-kubernetes/pkg/util" ) var OfficialMongodbRepoUrls = []string{"docker.io/mongodb", "quay.io/mongodb"} @@ -76,18 +77,6 @@ export NSS_WRAPPER_PASSWD=/tmp/passwd export LD_PRELOAD=libnss_wrapper.so export NSS_WRAPPER_GROUP=/etc/group fi -` - //nolint:gosec //The credentials path is hardcoded in the container. - MongodbUserCommandWithAPIKeyExport = `current_uid=$(id -u) -AGENT_API_KEY="$(cat /mongodb-automation/agent-api-key/agentApiKey)" -declare -r current_uid -if ! grep -q "${current_uid}" /etc/passwd ; then -sed -e "s/^mongodb:/builder:/" /etc/passwd > /tmp/passwd -echo "mongodb:x:$(id -u):$(id -g):,,,:/:/bin/bash" >> /tmp/passwd -export NSS_WRAPPER_PASSWD=/tmp/passwd -export LD_PRELOAD=libnss_wrapper.so -export NSS_WRAPPER_GROUP=/etc/group -fi ` ) @@ -130,7 +119,7 @@ type MongoDBStatefulSetOwner interface { // BuildMongoDBReplicaSetStatefulSetModificationFunction builds the parts of the replica set that are common between every resource that implements // MongoDBStatefulSetOwner. // It doesn't configure TLS or additional containers/env vars that the statefulset might need. -func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSetOwner, scaler scale.ReplicaSetScaler, mongodbImage, agentImage, versionUpgradeHookImage, readinessProbeImage string, withInitContainers bool) statefulset.Modification { +func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSetOwner, scaler scale.ReplicaSetScaler, mongodbImage, agentImage, versionUpgradeHookImage, readinessProbeImage string, withInitContainers bool, initAppDBImage string) statefulset.Modification { labels := map[string]string{ "app": mdb.ServiceName(), } @@ -167,27 +156,23 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe } mongodVolumeMounts := []corev1.VolumeMount{mongodHealthStatusVolumeMount, keyFileVolumeVolumeMountMongod, tmpVolumeMount} - hooksVolumeMod := podtemplatespec.NOOP() - scriptsVolumeMod := podtemplatespec.NOOP() + hooksVolume = statefulset.CreateVolumeFromEmptyDir("hooks") + hooksVolumeMount := statefulset.CreateVolumeMount(hooksVolume.Name, "/hooks", statefulset.WithReadOnly(false)) + scriptsVolume = statefulset.CreateVolumeFromEmptyDir("agent-scripts") + scriptsVolumeMount := statefulset.CreateVolumeMount(scriptsVolume.Name, "/opt/scripts", statefulset.WithReadOnly(false)) - // This is temporary code; - // once we make the operator fully deploy static workloads, we will remove those init containers. - if withInitContainers { - // hooks volume is only required on the mongod pod. - hooksVolume = statefulset.CreateVolumeFromEmptyDir("hooks") - hooksVolumeMount := statefulset.CreateVolumeMount(hooksVolume.Name, "/hooks", statefulset.WithReadOnly(false)) - - // scripts volume is only required on the mongodb-agent pod. - scriptsVolume = statefulset.CreateVolumeFromEmptyDir("agent-scripts") - scriptsVolumeMount := statefulset.CreateVolumeMount(scriptsVolume.Name, "/opt/scripts", statefulset.WithReadOnly(false)) - - upgradeInitContainer = podtemplatespec.WithInitContainer(versionUpgradeHookName, versionUpgradeHookInit([]corev1.VolumeMount{hooksVolumeMount}, versionUpgradeHookImage)) - readinessInitContainer = podtemplatespec.WithInitContainer(ReadinessProbeContainerName, readinessProbeInit([]corev1.VolumeMount{scriptsVolumeMount}, readinessProbeImage)) - scriptsVolumeMod = podtemplatespec.WithVolume(scriptsVolume) - hooksVolumeMod = podtemplatespec.WithVolume(hooksVolume) + scriptsVolumeMod := podtemplatespec.WithVolume(scriptsVolume) + hooksVolumeMod := podtemplatespec.WithVolume(hooksVolume) + withStaticContainerModification := podtemplatespec.NOOP() + // we need the upgrade hook and readinessProbe either via init containers or via a side-car and /proc access + if withInitContainers { mongodVolumeMounts = append(mongodVolumeMounts, hooksVolumeMount) mongodbAgentVolumeMounts = append(mongodbAgentVolumeMounts, scriptsVolumeMount) + upgradeInitContainer = podtemplatespec.WithInitContainer(versionUpgradeHookName, versionUpgradeHookInit([]corev1.VolumeMount{hooksVolumeMount}, versionUpgradeHookImage)) + readinessInitContainer = podtemplatespec.WithInitContainer(ReadinessProbeContainerName, readinessProbeInit([]corev1.VolumeMount{scriptsVolumeMount}, readinessProbeImage)) + } else { + withStaticContainerModification = podtemplatespec.WithContainer(util.AgentContainerUtilitiesName, mongodbAgentUtilitiesContainer([]corev1.VolumeMount{hooksVolumeMount, scriptsVolumeMount}, initAppDBImage)) } dataVolumeClaim := statefulset.NOOP() @@ -251,6 +236,7 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe podtemplatespec.WithServiceAccount(mongodbDatabaseServiceAccountName), podtemplatespec.WithContainer(AgentName, mongodbAgentContainer(mdb.AutomationConfigSecretName(), mongodbAgentVolumeMounts, agentLogLevel, agentLogFile, agentMaxLogFileDurationHours, agentImage)), podtemplatespec.WithContainer(MongodbName, mongodbContainer(mongodbImage, mongodVolumeMounts, mdb.GetMongodConfiguration())), + withStaticContainerModification, upgradeInitContainer, readinessInitContainer, ), @@ -263,7 +249,7 @@ func BaseAgentCommand() string { // AutomationAgentCommand withAgentAPIKeyExport detects whether we want to deploy this agent with the agent api key exported // it can be used to register the agent with OM. -func AutomationAgentCommand(withAgentAPIKeyExport bool, logLevel mdbv1.LogLevel, logFile string, maxLogFileDurationHours int) []string { +func AutomationAgentCommand(withStatic bool, withAgentAPIKeyExport bool, logLevel mdbv1.LogLevel, logFile string, maxLogFileDurationHours int) []string { // This is somewhat undocumented at https://www.mongodb.com/docs/ops-manager/current/reference/mongodb-agent-settings/ // Not setting the -logFile option make the mongodb-agent log to stdout. Setting -logFile /dev/stdout will result in // an error by the agent trying to open /dev/stdout-verbose and still trying to do log rotation. @@ -277,11 +263,31 @@ func AutomationAgentCommand(withAgentAPIKeyExport bool, logLevel mdbv1.LogLevel, } if withAgentAPIKeyExport { - return []string{"/bin/bash", "-c", MongodbUserCommandWithAPIKeyExport + BaseAgentCommand() + " -cluster=" + clusterFilePath + automationAgentOptions + agentLogOptions} + return []string{"/bin/bash", "-c", GetMongodbUserCommandWithAPIKeyExport(withStatic) + BaseAgentCommand() + " -cluster=" + clusterFilePath + automationAgentOptions + agentLogOptions} } return []string{"/bin/bash", "-c", MongodbUserCommand + BaseAgentCommand() + " -cluster=" + clusterFilePath + automationAgentOptions + agentLogOptions} } +func GetMongodbUserCommandWithAPIKeyExport(withStatic bool) string { + agentPrepareScript := "" + if withStatic { + agentPrepareScript = "/opt/scripts/setup-agent-files.sh\n" + } + + //nolint:gosec //The credentials path is hardcoded in the container. + return fmt.Sprintf(`%scurrent_uid=$(id -u) +AGENT_API_KEY="$(cat /mongodb-automation/agent-api-key/agentApiKey)" +declare -r current_uid +if ! grep -q "${current_uid}" /etc/passwd ; then +sed -e "s/^mongodb:/builder:/" /etc/passwd > /tmp/passwd +echo "mongodb:x:$(id -u):$(id -g):,,,:/:/bin/bash" >> /tmp/passwd +export NSS_WRAPPER_PASSWD=/tmp/passwd +export LD_PRELOAD=libnss_wrapper.so +export NSS_WRAPPER_GROUP=/etc/group +fi +`, agentPrepareScript) +} + func mongodbAgentContainer(automationConfigSecretName string, volumeMounts []corev1.VolumeMount, logLevel mdbv1.LogLevel, logFile string, maxLogFileDurationHours int, agentImage string) container.Modification { _, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications() return container.Apply( @@ -291,7 +297,7 @@ func mongodbAgentContainer(automationConfigSecretName string, volumeMounts []cor container.WithReadinessProbe(DefaultReadiness()), container.WithResourceRequirements(resourcerequirements.Defaults()), container.WithVolumeMounts(volumeMounts), - container.WithCommand(AutomationAgentCommand(false, logLevel, logFile, maxLogFileDurationHours)), + container.WithCommand(AutomationAgentCommand(false, false, logLevel, logFile, maxLogFileDurationHours)), containerSecurityContext, container.WithEnvs( corev1.EnvVar{ @@ -319,6 +325,20 @@ func mongodbAgentContainer(automationConfigSecretName string, volumeMounts []cor ) } +func mongodbAgentUtilitiesContainer(volumeMounts []corev1.VolumeMount, initDatabaseImage string) container.Modification { + _, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications() + return container.Apply( + container.WithName(util.AgentContainerUtilitiesName), + container.WithImage(initDatabaseImage), + container.WithImagePullPolicy(corev1.PullAlways), + container.WithResourceRequirements(resourcerequirements.Defaults()), + container.WithVolumeMounts(volumeMounts), + container.WithCommand([]string{"bash", "-c", "touch /tmp/agent-utilities-holder_marker && tail -F -n0 /tmp/agent-utilities-holder_marker"}), + container.WithArgs([]string{""}), + containerSecurityContext, + ) +} + func versionUpgradeHookInit(volumeMount []corev1.VolumeMount, versionUpgradeHookImage string) container.Modification { _, containerSecurityContext := podtemplatespec.WithDefaultSecurityContextsModifications() return container.Apply( diff --git a/mongodb-community-operator/controllers/replica_set_controller.go b/mongodb-community-operator/controllers/replica_set_controller.go index 6c0190fb0..ba3e5b168 100644 --- a/mongodb-community-operator/controllers/replica_set_controller.go +++ b/mongodb-community-operator/controllers/replica_set_controller.go @@ -792,7 +792,7 @@ func getMongodConfigSearchModification(search *searchv1.MongoDBSearch) automatio // buildStatefulSetModificationFunction takes a MongoDB resource and converts it into // the corresponding stateful set func buildStatefulSetModificationFunction(mdb mdbv1.MongoDBCommunity, mongodbImage, agentImage, versionUpgradeHookImage, readinessProbeImage string) statefulset.Modification { - commonModification := construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&mdb, &mdb, mongodbImage, agentImage, versionUpgradeHookImage, readinessProbeImage, true) + commonModification := construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&mdb, &mdb, mongodbImage, agentImage, versionUpgradeHookImage, readinessProbeImage, true, "") return statefulset.Apply( commonModification, statefulset.WithOwnerReference(mdb.GetOwnerReferences()), From 12066cb60cced7c92d4f4cb1142100084946474e Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 23 Jul 2025 15:49:52 +0200 Subject: [PATCH 29/49] make appdb work --- .../operator/construct/appdb_construction.go | 2 +- .../operator/construct/database_construction.go | 2 +- .../tests/opsmanager/om_jvm_params.py | 2 +- .../controllers/construct/mongodbstatefulset.go | 14 +++++++++++--- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/controllers/operator/construct/appdb_construction.go b/controllers/operator/construct/appdb_construction.go index d8b0f0266..829f444af 100644 --- a/controllers/operator/construct/appdb_construction.go +++ b/controllers/operator/construct/appdb_construction.go @@ -410,7 +410,7 @@ func AppDbStatefulSet(opsManager om.MongoDBOpsManager, podVars *env.PodEnvVars, // Here we ask to create init containers which also creates required volumens. // Note that we provide empty images for init containers. They are not important - // at this stage beucase later we will define our own init containers for non-static architecture. + // at this stage because later we will define our own init containers for non-static architecture. mod := construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&opsManager.Spec.AppDB, scaler, opts.MongodbImage, opts.AgentImage, "", "", true, opts.InitAppDBImage) if architectures.IsRunningStaticArchitecture(opsManager.Annotations) { mod = construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&opsManager.Spec.AppDB, scaler, opts.MongodbImage, opts.AgentImage, "", "", false, opts.InitAppDBImage) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 7aa3ad691..3bcc99e25 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -722,7 +722,7 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb container.WithArgs([]string{""}), container.WithImage(opts.InitDatabaseImage), container.WithEnvs(databaseEnvVars(opts)...), - container.WithCommand([]string{"bash", "-c", "touch /tmp/agent-utilities-holder_marker && tail -F -n0 /tmp/agent-utilities-holder_marker"}), + container.WithCommand([]string{"bash", "-c", "touch /opt/scripts/agent-utilities-holder_marker && tail -F -n0 /opt/scripts/agent-utilities-holder_marker"}), configureContainerSecurityContext, )} diff --git a/docker/mongodb-kubernetes-tests/tests/opsmanager/om_jvm_params.py b/docker/mongodb-kubernetes-tests/tests/opsmanager/om_jvm_params.py index 69616ae9b..6cdfa8aa4 100644 --- a/docker/mongodb-kubernetes-tests/tests/opsmanager/om_jvm_params.py +++ b/docker/mongodb-kubernetes-tests/tests/opsmanager/om_jvm_params.py @@ -8,7 +8,7 @@ from kubetester.opsmanager import MongoDBOpsManager from kubetester.phase import Phase from pytest import fixture, mark -from tests.conftest import assert_log_rotation_process, is_multi_cluster +from tests.conftest import is_multi_cluster from tests.opsmanager.withMonitoredAppDB.conftest import enable_multi_cluster_deployment OM_CONF_PATH_DIR = "mongodb-ops-manager/conf/mms.conf" diff --git a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go index d80f35f98..1389d200e 100644 --- a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go +++ b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go @@ -6,6 +6,7 @@ import ( "strconv" "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -164,6 +165,7 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe scriptsVolumeMod := podtemplatespec.WithVolume(scriptsVolume) hooksVolumeMod := podtemplatespec.WithVolume(hooksVolume) withStaticContainerModification := podtemplatespec.NOOP() + shareProcessNs := statefulset.NOOP() // we need the upgrade hook and readinessProbe either via init containers or via a side-car and /proc access if withInitContainers { @@ -172,7 +174,12 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe upgradeInitContainer = podtemplatespec.WithInitContainer(versionUpgradeHookName, versionUpgradeHookInit([]corev1.VolumeMount{hooksVolumeMount}, versionUpgradeHookImage)) readinessInitContainer = podtemplatespec.WithInitContainer(ReadinessProbeContainerName, readinessProbeInit([]corev1.VolumeMount{scriptsVolumeMount}, readinessProbeImage)) } else { - withStaticContainerModification = podtemplatespec.WithContainer(util.AgentContainerUtilitiesName, mongodbAgentUtilitiesContainer([]corev1.VolumeMount{hooksVolumeMount, scriptsVolumeMount}, initAppDBImage)) + staticMounts := []corev1.VolumeMount{hooksVolumeMount, scriptsVolumeMount} + withStaticContainerModification = podtemplatespec.WithContainer(util.AgentContainerUtilitiesName, mongodbAgentUtilitiesContainer(staticMounts, initAppDBImage)) + mongodbAgentVolumeMounts = append(mongodbAgentVolumeMounts, staticMounts...) + shareProcessNs = func(sts *appsv1.StatefulSet) { + sts.Spec.Template.Spec.ShareProcessNamespace = ptr.To(true) + } } dataVolumeClaim := statefulset.NOOP() @@ -223,6 +230,7 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe dataVolumeClaim, logVolumeClaim, singleModeVolumeClaim, + shareProcessNs, statefulset.WithPodSpecTemplate( podtemplatespec.Apply( podSecurityContext, @@ -271,7 +279,7 @@ func AutomationAgentCommand(withStatic bool, withAgentAPIKeyExport bool, logLeve func GetMongodbUserCommandWithAPIKeyExport(withStatic bool) string { agentPrepareScript := "" if withStatic { - agentPrepareScript = "/opt/scripts/setup-agent-files.sh\n" + agentPrepareScript = "/usr/local/bin/setup-agent-files.sh\n" } //nolint:gosec //The credentials path is hardcoded in the container. @@ -333,7 +341,7 @@ func mongodbAgentUtilitiesContainer(volumeMounts []corev1.VolumeMount, initDatab container.WithImagePullPolicy(corev1.PullAlways), container.WithResourceRequirements(resourcerequirements.Defaults()), container.WithVolumeMounts(volumeMounts), - container.WithCommand([]string{"bash", "-c", "touch /tmp/agent-utilities-holder_marker && tail -F -n0 /tmp/agent-utilities-holder_marker"}), + container.WithCommand([]string{"bash", "-c", "touch /opt/scripts/agent-utilities-holder_marker && tail -F -n0 /opt/scripts/agent-utilities-holder_marker"}), container.WithArgs([]string{""}), containerSecurityContext, ) From 9d575191c774e1547683bfce4a2fa8e815530d6a Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 23 Jul 2025 16:23:48 +0200 Subject: [PATCH 30/49] make appdb work and ensure tmp mount --- .../operator/construct/appdb_construction.go | 14 +++----------- .../operator/construct/construction_test.go | 1 + .../operator/construct/database_construction.go | 2 +- .../operator/mongodbopsmanager_controller_test.go | 4 ++-- .../controllers/construct/mongodbstatefulset.go | 5 +++-- 5 files changed, 10 insertions(+), 16 deletions(-) diff --git a/controllers/operator/construct/appdb_construction.go b/controllers/operator/construct/appdb_construction.go index 829f444af..700883685 100644 --- a/controllers/operator/construct/appdb_construction.go +++ b/controllers/operator/construct/appdb_construction.go @@ -122,10 +122,6 @@ func appDbPodSpec(initContainerImage string, om om.MongoDBOpsManager) podtemplat construct.AgentName, container.WithResourceRequirements(buildRequirementsFromPodSpec(*appdbPodSpec)), ) - automationUtilitiesPodTemplateFunc := podtemplatespec.WithContainer( - util.AgentContainerUtilitiesName, - container.WithResourceRequirements(buildRequirementsFromPodSpec(*appdbPodSpec)), - ) scriptsVolumeMount := statefulset.CreateVolumeMount("agent-scripts", "/opt/scripts", statefulset.WithReadOnly(false)) hooksVolumeMount := statefulset.CreateVolumeMount("hooks", "/hooks", statefulset.WithReadOnly(false)) @@ -143,7 +139,6 @@ func appDbPodSpec(initContainerImage string, om om.MongoDBOpsManager) podtemplat return podtemplatespec.Apply( mongoPodTemplateFunc, automationPodTemplateFunc, - automationUtilitiesPodTemplateFunc, initUpdateFunc, ) } @@ -395,7 +390,7 @@ func AppDbStatefulSet(opsManager om.MongoDBOpsManager, podVars *env.PodEnvVars, } // We copy the Automation Agent command from community and add the agent startup parameters - automationAgentCommand := construct.AutomationAgentCommand(true, true, opsManager.Spec.AppDB.GetAgentLogLevel(), opsManager.Spec.AppDB.GetAgentLogFile(), opsManager.Spec.AppDB.GetAgentMaxLogFileDurationHours()) + automationAgentCommand := construct.AutomationAgentCommand(architectures.IsRunningStaticArchitecture(opsManager.Annotations), true, opsManager.Spec.AppDB.GetAgentLogLevel(), opsManager.Spec.AppDB.GetAgentLogFile(), opsManager.Spec.AppDB.GetAgentMaxLogFileDurationHours()) idx := len(automationAgentCommand) - 1 automationAgentCommand[idx] += appDb.AutomationAgent.StartupParameters.ToCommandLineArgs() @@ -408,13 +403,10 @@ func AppDbStatefulSet(opsManager om.MongoDBOpsManager, podVars *env.PodEnvVars, MountPath: "/var/lib/automation/config/acVersion", } - // Here we ask to create init containers which also creates required volumens. + // Here we ask to create init containers which also creates required volumes. // Note that we provide empty images for init containers. They are not important // at this stage because later we will define our own init containers for non-static architecture. - mod := construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&opsManager.Spec.AppDB, scaler, opts.MongodbImage, opts.AgentImage, "", "", true, opts.InitAppDBImage) - if architectures.IsRunningStaticArchitecture(opsManager.Annotations) { - mod = construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&opsManager.Spec.AppDB, scaler, opts.MongodbImage, opts.AgentImage, "", "", false, opts.InitAppDBImage) - } + mod := construct.BuildMongoDBReplicaSetStatefulSetModificationFunction(&opsManager.Spec.AppDB, scaler, opts.MongodbImage, opts.AgentImage, "", "", !architectures.IsRunningStaticArchitecture(opsManager.Annotations), opts.InitAppDBImage) sts := statefulset.New( mod, diff --git a/controllers/operator/construct/construction_test.go b/controllers/operator/construct/construction_test.go index 0382abb6d..c5dd99979 100644 --- a/controllers/operator/construct/construction_test.go +++ b/controllers/operator/construct/construction_test.go @@ -111,6 +111,7 @@ func TestBuildStatefulSet_PersistentVolumeClaimSingleStatic(t *testing.T) { {Name: util.PvcNameData, MountPath: util.PvcMountPathData, SubPath: util.PvcNameData}, {Name: util.PvcNameData, MountPath: util.PvcMountPathJournal, SubPath: util.PvcNameJournal}, {Name: util.PvcNameData, MountPath: util.PvcMountPathLogs, SubPath: util.PvcNameLogs}, + {Name: PvcNameDatabaseScripts, MountPath: PvcMountPathScripts, ReadOnly: false}, }) } diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 3bcc99e25..7aa3ad691 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -722,7 +722,7 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb container.WithArgs([]string{""}), container.WithImage(opts.InitDatabaseImage), container.WithEnvs(databaseEnvVars(opts)...), - container.WithCommand([]string{"bash", "-c", "touch /opt/scripts/agent-utilities-holder_marker && tail -F -n0 /opt/scripts/agent-utilities-holder_marker"}), + container.WithCommand([]string{"bash", "-c", "touch /tmp/agent-utilities-holder_marker && tail -F -n0 /tmp/agent-utilities-holder_marker"}), configureContainerSecurityContext, )} diff --git a/controllers/operator/mongodbopsmanager_controller_test.go b/controllers/operator/mongodbopsmanager_controller_test.go index e11d59bcc..07291dabb 100644 --- a/controllers/operator/mongodbopsmanager_controller_test.go +++ b/controllers/operator/mongodbopsmanager_controller_test.go @@ -589,10 +589,10 @@ func TestOpsManagerReconcileContainerImagesWithStaticArchitecture(t *testing.T) require.NoError(t, err) require.Len(t, appDBSts.Spec.Template.Spec.InitContainers, 0) - require.Len(t, appDBSts.Spec.Template.Spec.Containers, 3) + require.Len(t, appDBSts.Spec.Template.Spec.Containers, 4) assert.Equal(t, "quay.io/mongodb/mongodb-enterprise-appdb-database-ubi@sha256:MONGODB_SHA", appDBSts.Spec.Template.Spec.Containers[1].Image) // In static architecture this container is a copy of agent container - assert.Equal(t, appDBSts.Spec.Template.Spec.Containers[0].Image, appDBSts.Spec.Template.Spec.Containers[2].Image) + assert.Equal(t, appDBSts.Spec.Template.Spec.Containers[0].Image, appDBSts.Spec.Template.Spec.Containers[3].Image) } func TestOpsManagerConnectionString_IsPassedAsSecretRef(t *testing.T) { diff --git a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go index 1389d200e..94960ba52 100644 --- a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go +++ b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go @@ -168,13 +168,14 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe shareProcessNs := statefulset.NOOP() // we need the upgrade hook and readinessProbe either via init containers or via a side-car and /proc access + // if we don't use init containers we need to use static containers if withInitContainers { mongodVolumeMounts = append(mongodVolumeMounts, hooksVolumeMount) mongodbAgentVolumeMounts = append(mongodbAgentVolumeMounts, scriptsVolumeMount) upgradeInitContainer = podtemplatespec.WithInitContainer(versionUpgradeHookName, versionUpgradeHookInit([]corev1.VolumeMount{hooksVolumeMount}, versionUpgradeHookImage)) readinessInitContainer = podtemplatespec.WithInitContainer(ReadinessProbeContainerName, readinessProbeInit([]corev1.VolumeMount{scriptsVolumeMount}, readinessProbeImage)) } else { - staticMounts := []corev1.VolumeMount{hooksVolumeMount, scriptsVolumeMount} + staticMounts := []corev1.VolumeMount{hooksVolumeMount, scriptsVolumeMount, tmpVolumeMount} withStaticContainerModification = podtemplatespec.WithContainer(util.AgentContainerUtilitiesName, mongodbAgentUtilitiesContainer(staticMounts, initAppDBImage)) mongodbAgentVolumeMounts = append(mongodbAgentVolumeMounts, staticMounts...) shareProcessNs = func(sts *appsv1.StatefulSet) { @@ -341,7 +342,7 @@ func mongodbAgentUtilitiesContainer(volumeMounts []corev1.VolumeMount, initDatab container.WithImagePullPolicy(corev1.PullAlways), container.WithResourceRequirements(resourcerequirements.Defaults()), container.WithVolumeMounts(volumeMounts), - container.WithCommand([]string{"bash", "-c", "touch /opt/scripts/agent-utilities-holder_marker && tail -F -n0 /opt/scripts/agent-utilities-holder_marker"}), + container.WithCommand([]string{"bash", "-c", "touch /tmp/agent-utilities-holder_marker && tail -F -n0 /tmp/agent-utilities-holder_marker"}), container.WithArgs([]string{""}), containerSecurityContext, ) From d10f8522efaa7927f6a6048f3e00ec099c865196 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 23 Jul 2025 16:53:17 +0200 Subject: [PATCH 31/49] fix launcher path for setup script and fix docker unit tests --- docker/mongodb-agent/agent-launcher-shim.sh | 2 +- lib/sonar/test/test_build.py | 7 ++++--- lib/sonar/test/test_docker.py | 19 +++++++++-------- pipeline_test.py | 23 +++++++++++++-------- 4 files changed, 29 insertions(+), 22 deletions(-) diff --git a/docker/mongodb-agent/agent-launcher-shim.sh b/docker/mongodb-agent/agent-launcher-shim.sh index 4a3e62de9..fda61405b 100755 --- a/docker/mongodb-agent/agent-launcher-shim.sh +++ b/docker/mongodb-agent/agent-launcher-shim.sh @@ -20,7 +20,7 @@ start_agent_launcher() { main() { echo "Running setup-agent-files.sh..." - if ! $SCRIPTS_DIR/setup-agent-files.sh; then + if ! /usr/local/bin/setup-agent-files.sh; then echo "ERROR: Failed to set up agent files" exit 1 fi diff --git a/lib/sonar/test/test_build.py b/lib/sonar/test/test_build.py index 99d98b709..bb1bd848b 100644 --- a/lib/sonar/test/test_build.py +++ b/lib/sonar/test/test_build.py @@ -111,12 +111,13 @@ def test_platform_is_passed_to_docker_build(_docker_build, _docker_tag): _docker_build.assert_called() -def test_get_docker_build_cli_args(): - assert "docker buildx build --load --progress plain . -f dockerfile -t image:latest" == " ".join( +@patch("sonar.builders.docker.shutil.which", return_value="/mock/path/to/docker") +def test_get_docker_build_cli_args(mock_which): + assert "/mock/path/to/docker buildx build --load --progress plain . -f dockerfile -t image:latest" == " ".join( get_docker_build_cli_args(".", "dockerfile", "image:latest", None, None, None) ) assert ( - "docker buildx build --load --progress plain . -f dockerfile -t image:latest --build-arg a=1 --build-arg long_arg=long_value --label l1=v1 --label l2=v2 --platform linux/amd64" + "/mock/path/to/docker buildx build --load --progress plain . -f dockerfile -t image:latest --build-arg a=1 --build-arg long_arg=long_value --label l1=v1 --label l2=v2 --platform linux/amd64" == " ".join( get_docker_build_cli_args( ".", diff --git a/lib/sonar/test/test_docker.py b/lib/sonar/test/test_docker.py index e36840df0..370ed667c 100644 --- a/lib/sonar/test/test_docker.py +++ b/lib/sonar/test/test_docker.py @@ -1,5 +1,5 @@ from types import SimpleNamespace -from unittest.mock import Mock, call +from unittest.mock import Mock, call, patch import pytest from pytest_mock import MockerFixture @@ -8,7 +8,8 @@ from ..builders.docker import docker_push -def test_docker_push_is_retried(mocker: MockerFixture): +@patch("sonar.builders.docker.shutil.which", return_value="/mock/path/to/docker") +def test_docker_push_is_retried(mock_which, mocker: MockerFixture): a = SimpleNamespace(returncode=1, stderr="some-error") sp = mocker.patch("sonar.builders.docker.subprocess") sp.PIPE = "|PIPE|" @@ -20,16 +21,16 @@ def test_docker_push_is_retried(mocker: MockerFixture): # docker push is called 4 times, the last time it is called, it raises an exception sp.run.assert_has_calls( [ - call(["docker", "push", "reg:tag"], stdout="|PIPE|", stderr="|PIPE|"), - call(["docker", "push", "reg:tag"], stdout="|PIPE|", stderr="|PIPE|"), - call(["docker", "push", "reg:tag"], stdout="|PIPE|", stderr="|PIPE|"), - call(["docker", "push", "reg:tag"], stdout="|PIPE|", stderr="|PIPE|"), + call(["/mock/path/to/docker", "push", "reg:tag"], stdout="|PIPE|", stderr="|PIPE|"), + call(["/mock/path/to/docker", "push", "reg:tag"], stdout="|PIPE|", stderr="|PIPE|"), + call(["/mock/path/to/docker", "push", "reg:tag"], stdout="|PIPE|", stderr="|PIPE|"), + call(["/mock/path/to/docker", "push", "reg:tag"], stdout="|PIPE|", stderr="|PIPE|"), ] ) -def test_docker_push_is_retried_and_works(mocker: MockerFixture): - +@patch("sonar.builders.docker.shutil.which", return_value="/mock/path/to/docker") +def test_docker_push_is_retried_and_works(mock_which, mocker: MockerFixture): ok = SimpleNamespace(returncode=0) sp = mocker.patch("sonar.builders.docker.subprocess") sp.PIPE = "|PIPE|" @@ -39,7 +40,7 @@ def test_docker_push_is_retried_and_works(mocker: MockerFixture): docker_push("reg", "tag") sp.run.assert_called_once_with( - ["docker", "push", "reg:tag"], + ["/mock/path/to/docker", "push", "reg:tag"], stdout="|PIPE|", stderr="|PIPE|", ) diff --git a/pipeline_test.py b/pipeline_test.py index 68b7e3a8e..c400bd6fb 100644 --- a/pipeline_test.py +++ b/pipeline_test.py @@ -257,8 +257,9 @@ def test_all_retries_fail(self, mock_sleep, mock_run): self.assertEqual(mock_sleep.call_count, 2) +@patch("pipeline.shutil.which", return_value="/mock/path/to/docker") @patch("subprocess.run") -def test_create_and_push_manifest_success(mock_run): +def test_create_and_push_manifest_success(mock_run, mock_which): """Test successful creation and pushing of manifest with multiple architectures.""" # Setup mock to return success for both calls mock_run.return_value = subprocess.CompletedProcess(args=[], returncode=0, stdout=b"", stderr=b"") @@ -276,7 +277,7 @@ def test_create_and_push_manifest_success(mock_run): # Verify first call - create manifest create_call_args = mock_run.call_args_list[0][0][0] assert create_call_args == [ - "docker", + "/mock/path/to/docker", "manifest", "create", "test/image:1.0.0", @@ -288,11 +289,12 @@ def test_create_and_push_manifest_success(mock_run): # Verify second call - push manifest push_call_args = mock_run.call_args_list[1][0][0] - assert push_call_args == ["docker", "manifest", "push", f"{image}:{tag}"] + assert push_call_args == ["/mock/path/to/docker", "manifest", "push", f"{image}:{tag}"] +@patch("pipeline.shutil.which", return_value="/mock/path/to/docker") @patch("subprocess.run") -def test_create_and_push_manifest_single_arch(mock_run): +def test_create_and_push_manifest_single_arch(mock_run, mock_which): """Test manifest creation with a single architecture.""" # Setup mock to return success for both calls mock_run.return_value = subprocess.CompletedProcess(args=[], returncode=0, stdout=b"", stderr=b"") @@ -307,11 +309,12 @@ def test_create_and_push_manifest_single_arch(mock_run): # Verify first call - create manifest (should only include one architecture) create_call_args = mock_run.call_args_list[0][0][0] - assert " ".join(create_call_args) == f"docker manifest create {image}:{tag} --amend {image}:{tag}-amd64" + assert " ".join(create_call_args) == "/mock/path/to/docker manifest create test/image:1.0.0 --amend test/image:1.0.0-amd64" +@patch("pipeline.shutil.which", return_value="/mock/path/to/docker") @patch("subprocess.run") -def test_create_and_push_manifest_create_error(mock_run): +def test_create_and_push_manifest_create_error(mock_run, mock_which): """Test error handling when manifest creation fails.""" # Setup mock to return error for create call mock_run.return_value = subprocess.CompletedProcess( @@ -332,13 +335,14 @@ def test_create_and_push_manifest_create_error(mock_run): assert mock_run.call_count == 1 # Only the create call, not the push call +@patch("pipeline.shutil.which", return_value="/mock/path/to/docker") @patch("subprocess.run") -def test_create_and_push_manifest_push_error(mock_run): +def test_create_and_push_manifest_push_error(mock_run, mock_which): """Test error handling when manifest push fails.""" # Setup mock to return success for create but error for push mock_run.side_effect = [ subprocess.CompletedProcess(args=[], returncode=0, stdout=b"", stderr=b""), # create success - subprocess.CompletedProcess(args=[], returncode=1, stdout=b"", stderr=b"Error pushing manifest"), # push error + subprocess.CompletedProcess(args=[], returncode=1, stdout=b"", stderr=b"Push failed"), # push fails ] # Call function with test parameters @@ -352,5 +356,6 @@ def test_create_and_push_manifest_push_error(mock_run): with pytest.raises(Exception) as exc_info: create_and_push_manifest(image, tag, architectures) - assert "Error pushing manifest" in str(exc_info.value) + # The function raises the stderr directly, so we should check for the exact error message + assert "Push failed" in str(exc_info.value) assert mock_run.call_count == 2 # Both create and push calls From 668918286c65738eb0a56b13635b986f27eada05 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 23 Jul 2025 17:32:18 +0200 Subject: [PATCH 32/49] fix e2e tests and fix linter --- .../sharded_cluster_custom_podspec.py | 22 ++++++++++++------- .../standalone/standalone_custom_podspec.py | 14 +++++++----- .../mongodb_deployment_vault.py | 2 +- .../tests/vaultintegration/vault_tls.py | 2 +- pipeline_test.py | 5 ++++- 5 files changed, 28 insertions(+), 17 deletions(-) diff --git a/docker/mongodb-kubernetes-tests/tests/shardedcluster/sharded_cluster_custom_podspec.py b/docker/mongodb-kubernetes-tests/tests/shardedcluster/sharded_cluster_custom_podspec.py index 909bb0761..3a882e02b 100644 --- a/docker/mongodb-kubernetes-tests/tests/shardedcluster/sharded_cluster_custom_podspec.py +++ b/docker/mongodb-kubernetes-tests/tests/shardedcluster/sharded_cluster_custom_podspec.py @@ -101,16 +101,22 @@ def test_stateful_sets_spec_updated(sc: MongoDB): if is_default_architecture_static(): containers = shard0_sts.spec.template.spec.containers - assert len(containers) == 3 - assert containers[0].name == "mongodb-agent" - assert containers[1].name == "mongodb-enterprise-database" - assert containers[2].name == "sharded-cluster-sidecar-override" + container_names = [container.name for container in containers] + + assert len(containers) == 4 + assert "mongodb-agent" in container_names + assert "mongodb-enterprise-database" in container_names + assert "mongodb-agent-operator-utilities" in container_names + assert "sharded-cluster-sidecar-override" in container_names containers = shard1_sts.spec.template.spec.containers - assert len(containers) == 3 - assert containers[0].name == "mongodb-agent" - assert containers[1].name == "mongodb-enterprise-database" - assert containers[2].name == "sharded-cluster-sidecar" + container_names = [container.name for container in containers] + + assert len(containers) == 4 + assert "mongodb-agent" in container_names + assert "mongodb-enterprise-database" in container_names + assert "mongodb-agent-operator-utilities" in container_names + assert "sharded-cluster-sidecar" in container_names resources = containers[2].resources else: diff --git a/docker/mongodb-kubernetes-tests/tests/standalone/standalone_custom_podspec.py b/docker/mongodb-kubernetes-tests/tests/standalone/standalone_custom_podspec.py index 66080f0e5..895dcbe13 100644 --- a/docker/mongodb-kubernetes-tests/tests/standalone/standalone_custom_podspec.py +++ b/docker/mongodb-kubernetes-tests/tests/standalone/standalone_custom_podspec.py @@ -26,16 +26,18 @@ def test_stateful_set_spec_updated(standalone, namespace): assert_stateful_set_podspec(sts.spec.template.spec, weight=50, topology_key="mykey", grace_period_seconds=10) containers = sts.spec.template.spec.containers + container_names = [container.name for container in containers] if is_default_architecture_static(): - assert len(containers) == 3 - assert containers[0].name == "mongodb-agent" - assert containers[1].name == "mongodb-enterprise-database" - assert containers[2].name == "standalone-sidecar" + assert len(containers) == 4 + assert "mongodb-agent" in container_names + assert "mongodb-enterprise-database" in container_names + assert "mongodb-agent-operator-utilities" in container_names + assert "standalone-sidecar" in container_names else: assert len(containers) == 2 - assert containers[0].name == "mongodb-enterprise-database" - assert containers[1].name == "standalone-sidecar" + assert "standalone-sidecar" in container_names + assert "mongodb-agent" in container_names labels = sts.spec.template.metadata.labels assert labels["label1"] == "value1" diff --git a/docker/mongodb-kubernetes-tests/tests/vaultintegration/mongodb_deployment_vault.py b/docker/mongodb-kubernetes-tests/tests/vaultintegration/mongodb_deployment_vault.py index d9dd72b65..b6ad82285 100644 --- a/docker/mongodb-kubernetes-tests/tests/vaultintegration/mongodb_deployment_vault.py +++ b/docker/mongodb-kubernetes-tests/tests/vaultintegration/mongodb_deployment_vault.py @@ -357,7 +357,7 @@ def test_mdb_created(replica_set: MongoDB, namespace: str): for pod_name in get_pods(MDB_RESOURCE + "-{}", 3): pod = client.CoreV1Api().read_namespaced_pod(pod_name, namespace) if is_default_architecture_static(): - assert len(pod.spec.containers) == 3 + assert len(pod.spec.containers) == 4 else: assert len(pod.spec.containers) == 2 diff --git a/docker/mongodb-kubernetes-tests/tests/vaultintegration/vault_tls.py b/docker/mongodb-kubernetes-tests/tests/vaultintegration/vault_tls.py index 86ea083b9..2c6c9dc7d 100644 --- a/docker/mongodb-kubernetes-tests/tests/vaultintegration/vault_tls.py +++ b/docker/mongodb-kubernetes-tests/tests/vaultintegration/vault_tls.py @@ -313,7 +313,7 @@ def test_mdb_created(replica_set: MongoDB, namespace: str): for pod_name in get_pods(MDB_RESOURCE + "-{}", 3): pod = client.CoreV1Api().read_namespaced_pod(pod_name, namespace) if is_default_architecture_static(): - assert len(pod.spec.containers) == 3 + assert len(pod.spec.containers) == 4 else: assert len(pod.spec.containers) == 2 diff --git a/pipeline_test.py b/pipeline_test.py index c400bd6fb..dab707faa 100644 --- a/pipeline_test.py +++ b/pipeline_test.py @@ -309,7 +309,10 @@ def test_create_and_push_manifest_single_arch(mock_run, mock_which): # Verify first call - create manifest (should only include one architecture) create_call_args = mock_run.call_args_list[0][0][0] - assert " ".join(create_call_args) == "/mock/path/to/docker manifest create test/image:1.0.0 --amend test/image:1.0.0-amd64" + assert ( + " ".join(create_call_args) + == "/mock/path/to/docker manifest create test/image:1.0.0 --amend test/image:1.0.0-amd64" + ) @patch("pipeline.shutil.which", return_value="/mock/path/to/docker") From 57681ad05bef846f74d11d40994ce76972b652cd Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 24 Jul 2025 11:58:50 +0200 Subject: [PATCH 33/49] fix monitoring and tests --- controllers/operator/construct/appdb_construction.go | 6 +++--- docker/mongodb-kubernetes-tests/kubetester/kubetester.py | 7 +++++++ .../tests/shardedcluster/sharded_cluster_custom_podspec.py | 2 +- .../tests/standalone/standalone_custom_podspec.py | 2 +- .../tests/vaultintegration/om_backup_vault.py | 4 ++-- .../tests/vaultintegration/om_deployment_vault.py | 6 +++--- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/controllers/operator/construct/appdb_construction.go b/controllers/operator/construct/appdb_construction.go index 700883685..22cdcaf3d 100644 --- a/controllers/operator/construct/appdb_construction.go +++ b/controllers/operator/construct/appdb_construction.go @@ -380,7 +380,7 @@ func AppDbStatefulSet(opsManager om.MongoDBOpsManager, podVars *env.PodEnvVars, externalDomain := appDb.GetExternalDomainForMemberCluster(scaler.MemberClusterName()) if ShouldEnableMonitoring(podVars) { - monitoringModification = addMonitoringContainer(*appDb, *podVars, opts, externalDomain, log) + monitoringModification = addMonitoringContainer(*appDb, *podVars, opts, externalDomain, architectures.IsRunningStaticArchitecture(opsManager.Annotations), log) } else { // Otherwise, let's remove for now every podTemplateSpec related to monitoring // We will apply them when enabling monitoring @@ -490,7 +490,7 @@ func getVolumeMountIndexByName(mounts []corev1.VolumeMount, name string) int { // addMonitoringContainer returns a podtemplatespec modification that adds the monitoring container to the AppDB Statefulset. // Note that this replicates some code from the functions that do this for the base AppDB Statefulset. After many iterations // this was deemed to be an acceptable compromise to make code clearer and more maintainable. -func addMonitoringContainer(appDB om.AppDBSpec, podVars env.PodEnvVars, opts AppDBStatefulSetOptions, externalDomain *string, log *zap.SugaredLogger) podtemplatespec.Modification { +func addMonitoringContainer(appDB om.AppDBSpec, podVars env.PodEnvVars, opts AppDBStatefulSetOptions, externalDomain *string, isStatic bool, log *zap.SugaredLogger) podtemplatespec.Modification { var monitoringAcVolume corev1.Volume var monitoringACFunc podtemplatespec.Modification @@ -513,7 +513,7 @@ func addMonitoringContainer(appDB om.AppDBSpec, podVars env.PodEnvVars, opts App } // Construct the command by concatenating: // 1. The base command - from community - command := construct.GetMongodbUserCommandWithAPIKeyExport(false) + command := construct.GetMongodbUserCommandWithAPIKeyExport(isStatic) command += "agent/mongodb-agent" command += " -healthCheckFilePath=" + monitoringAgentHealthStatusFilePathValue command += " -serveStatusPort=5001" diff --git a/docker/mongodb-kubernetes-tests/kubetester/kubetester.py b/docker/mongodb-kubernetes-tests/kubetester/kubetester.py index c2147bedc..85ba33f08 100644 --- a/docker/mongodb-kubernetes-tests/kubetester/kubetester.py +++ b/docker/mongodb-kubernetes-tests/kubetester/kubetester.py @@ -69,6 +69,13 @@ def is_default_architecture_static() -> bool: return os.getenv("MDB_DEFAULT_ARCHITECTURE", "non-static") == "static" +def assert_container_count(current_container_count: int, expected_counter_without_static: int): + if is_default_architecture_static(): + assert current_container_count == expected_counter_without_static + 1 + else: + assert current_container_count == expected_counter_without_static + + def get_default_architecture() -> str: return "static" if is_default_architecture_static() else "non-static" diff --git a/docker/mongodb-kubernetes-tests/tests/shardedcluster/sharded_cluster_custom_podspec.py b/docker/mongodb-kubernetes-tests/tests/shardedcluster/sharded_cluster_custom_podspec.py index 3a882e02b..efffcc770 100644 --- a/docker/mongodb-kubernetes-tests/tests/shardedcluster/sharded_cluster_custom_podspec.py +++ b/docker/mongodb-kubernetes-tests/tests/shardedcluster/sharded_cluster_custom_podspec.py @@ -118,7 +118,7 @@ def test_stateful_sets_spec_updated(sc: MongoDB): assert "mongodb-agent-operator-utilities" in container_names assert "sharded-cluster-sidecar" in container_names - resources = containers[2].resources + resources = containers[3].resources else: containers = shard1_sts.spec.template.spec.containers assert len(containers) == 2 diff --git a/docker/mongodb-kubernetes-tests/tests/standalone/standalone_custom_podspec.py b/docker/mongodb-kubernetes-tests/tests/standalone/standalone_custom_podspec.py index 895dcbe13..5aebc1ea7 100644 --- a/docker/mongodb-kubernetes-tests/tests/standalone/standalone_custom_podspec.py +++ b/docker/mongodb-kubernetes-tests/tests/standalone/standalone_custom_podspec.py @@ -37,7 +37,7 @@ def test_stateful_set_spec_updated(standalone, namespace): else: assert len(containers) == 2 assert "standalone-sidecar" in container_names - assert "mongodb-agent" in container_names + assert "mongodb-enterprise-database" in container_names labels = sts.spec.template.metadata.labels assert labels["label1"] == "value1" diff --git a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py index 991cd5a82..e469edea6 100644 --- a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py +++ b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py @@ -15,7 +15,7 @@ from kubetester.awss3client import AwsS3Client, s3_endpoint from kubetester.certs import create_mongodb_tls_certs, create_ops_manager_tls_certs from kubetester.http import https_endpoint_is_reachable -from kubetester.kubetester import KubernetesTester +from kubetester.kubetester import KubernetesTester, assert_container_count from kubetester.kubetester import fixture as yaml_fixture from kubetester.kubetester import get_pods from kubetester.mongodb import MongoDB @@ -452,7 +452,7 @@ def test_appdb_reached_running_and_pod_count(ops_manager: MongoDBOpsManager, nam # check AppDB has 4 containers(+1 because of vault-agent) for pod_name in get_pods(ops_manager.name + "-db-{}", 3): pod = client.CoreV1Api().read_namespaced_pod(pod_name, namespace) - assert len(pod.spec.containers) == 4 + assert_container_count(pod.spec.containers, 4) @mark.e2e_vault_setup_om_backup diff --git a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py index 7d3c87ba6..36bcae687 100644 --- a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py +++ b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py @@ -12,9 +12,9 @@ read_secret, ) from kubetester.certs import create_mongodb_tls_certs, create_ops_manager_tls_certs -from kubetester.kubetester import KubernetesTester +from kubetester.kubetester import KubernetesTester, assert_container_count from kubetester.kubetester import fixture as yaml_fixture -from kubetester.kubetester import get_pods +from kubetester.kubetester import get_pods, is_default_architecture_static from kubetester.operator import Operator from kubetester.opsmanager import MongoDBOpsManager from kubetester.phase import Phase @@ -277,7 +277,7 @@ def test_appdb_reached_running_and_pod_count(ops_manager: MongoDBOpsManager, nam # check AppDB has 4 containers(+1 because of vault-agent) for pod_name in get_pods(ops_manager.name + "-db-{}", 3): pod = client.CoreV1Api().read_namespaced_pod(pod_name, namespace) - assert len(pod.spec.containers) == 4 + assert_container_count(pod.spec.containers, 4) @mark.e2e_vault_setup_om From 41e9d780a81bfc08acf867cd545434070ff12a21 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 24 Jul 2025 12:02:43 +0200 Subject: [PATCH 34/49] add wip context handling --- .../mongodb-agent/Dockerfile.rebuild-context | 21 + test_ecr_real_rebuild.py | 373 ++++++++++++++++++ test_rebuild_ecr_unit.py | 297 ++++++++++++++ test_single_agent_rebuild.py | 370 +++++++++++++++++ 4 files changed, 1061 insertions(+) create mode 100644 docker/mongodb-agent/Dockerfile.rebuild-context create mode 100644 test_ecr_real_rebuild.py create mode 100644 test_rebuild_ecr_unit.py create mode 100644 test_single_agent_rebuild.py diff --git a/docker/mongodb-agent/Dockerfile.rebuild-context b/docker/mongodb-agent/Dockerfile.rebuild-context new file mode 100644 index 000000000..cba68e328 --- /dev/null +++ b/docker/mongodb-agent/Dockerfile.rebuild-context @@ -0,0 +1,21 @@ +# Temporary Dockerfile for rebuilding existing agent context images +# This Dockerfile uses an existing context image as base and adds the new script files +# that were recently added to the repository but may not be in older context images. + +ARG OLD_CONTEXT_IMAGE +FROM ${OLD_CONTEXT_IMAGE} + +# Copy the new script files that need to be added to all agents +# Use --chmod to set permissions during copy to avoid permission conflicts +COPY --chmod=755 ./docker/mongodb-agent/dummy-probe.sh /opt/scripts/dummy-probe.sh +COPY --chmod=755 ./docker/mongodb-agent/dummy-readinessprobe.sh /opt/scripts/dummy-readinessprobe.sh +COPY --chmod=755 ./docker/mongodb-agent/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh +COPY --chmod=755 ./docker/mongodb-agent/setup-agent-files.sh /opt/scripts/setup-agent-files.sh + +# Verify files are present and executable +RUN ls -la /opt/scripts/ && \ + test -x /opt/scripts/dummy-probe.sh && \ + test -x /opt/scripts/dummy-readinessprobe.sh && \ + test -x /opt/scripts/agent-launcher-shim.sh && \ + test -x /opt/scripts/setup-agent-files.sh && \ + echo "All script files are present and executable" diff --git a/test_ecr_real_rebuild.py b/test_ecr_real_rebuild.py new file mode 100644 index 000000000..f907f91e4 --- /dev/null +++ b/test_ecr_real_rebuild.py @@ -0,0 +1,373 @@ +#!/usr/bin/env python3 + +""" +ECR Real Rebuild Test Script + +This script tests the rebuild process using your actual ECR repositories: +- Base image: 268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi: +- Target image: 268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed: + +Usage: + # Make sure you're logged in to ECR first + make aws_login + + # Run the test + python3 test_ecr_real_rebuild.py + + # Or test with specific agent version + python3 test_ecr_real_rebuild.py --agent-version 108.0.7.8810-1 +""" + +import argparse +import json +import os +import shutil +import subprocess +import sys +from typing import Dict, Optional, Tuple + + +def find_docker_executable() -> str: + """Find docker executable dynamically to work across different environments.""" + docker_cmd = shutil.which("docker") + if docker_cmd is None: + raise Exception("Docker executable not found in PATH") + return docker_cmd + + +def load_release_json() -> Dict: + """Load and parse the release.json file.""" + try: + with open("release.json", "r") as f: + return json.load(f) + except FileNotFoundError: + print("Error: release.json not found. Run this script from the project root.") + sys.exit(1) + except json.JSONDecodeError as e: + print(f"Error parsing release.json: {e}") + sys.exit(1) + + +def get_latest_agent_version(release_data: Dict) -> Optional[Tuple[str, str]]: + """Get the latest agent version and tools version.""" + mongodb_agent = release_data.get("supportedImages", {}).get("mongodb-agent", {}) + ops_manager_mapping = mongodb_agent.get("opsManagerMapping", {}).get("ops_manager", {}) + + if not ops_manager_mapping: + return None + + # Get the latest OpsManager version (highest version number) + latest_om_version = max(ops_manager_mapping.keys(), key=lambda x: [int(i) for i in x.split(".")]) + latest_details = ops_manager_mapping[latest_om_version] + + agent_version = latest_details.get("agent_version") + tools_version = latest_details.get("tools_version") + + if agent_version and tools_version: + return (agent_version, tools_version) + + return None + + +def test_ecr_real_rebuild(docker_cmd: str, agent_version: str) -> bool: + """Test rebuild process using real ECR repositories.""" + + base_image = f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi:{agent_version}" + target_image = f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed:{agent_version}" + + print(f"Base image: {base_image}") + print(f"Target image: {target_image}") + + try: + # Step 1: Pull the existing base image (force amd64 platform) + print(f"\n{'='*60}") + print("STEP 1: Pulling existing base image from ECR") + print(f"{'='*60}") + + pull_cmd = [docker_cmd, "pull", "--platform", "linux/amd64", base_image] + print(f"Running: {' '.join(pull_cmd)}") + result = subprocess.run(pull_cmd, check=True, capture_output=True, text=True) + print("✓ Base image pull successful!") + + # Step 2: Build the rebuilt image using the temporary Dockerfile (force amd64 platform) + print(f"\n{'='*60}") + print("STEP 2: Building rebuilt image with new script files") + print(f"{'='*60}") + + build_cmd = [ + docker_cmd, + "build", + "--platform", + "linux/amd64", + "-f", + "docker/mongodb-agent/Dockerfile.rebuild-context", + "--build-arg", + f"OLD_CONTEXT_IMAGE={base_image}", + "-t", + target_image, + ".", + ] + + print(f"Running: {' '.join(build_cmd)}") + result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) + print("✓ Rebuild successful!") + + # Step 3: Verify new files are present in rebuilt image + print(f"\n{'='*60}") + print("STEP 3: Verifying new files are present") + print(f"{'='*60}") + + verify_cmd = [ + docker_cmd, + "run", + "--rm", + "--platform", + "linux/amd64", + target_image, + "ls", + "-la", + "/opt/scripts/", + ] + print(f"Running: {' '.join(verify_cmd)}") + result = subprocess.run(verify_cmd, check=True, capture_output=True, text=True) + print("Files in /opt/scripts/:") + print(result.stdout) + + # Check for expected files + expected_files = ["dummy-probe.sh", "dummy-readinessprobe.sh", "agent-launcher-shim.sh", "setup-agent-files.sh"] + + missing_files = [] + for expected_file in expected_files: + if expected_file not in result.stdout: + missing_files.append(expected_file) + + if missing_files: + print(f"ERROR: Missing expected files: {missing_files}") + return False + + print("✓ All expected files are present!") + + # Step 4: Test dummy scripts functionality + print(f"\n{'='*60}") + print("STEP 4: Testing dummy probe scripts functionality") + print(f"{'='*60}") + + # Test dummy-probe.sh (should exit 0) + probe_test_cmd = [ + docker_cmd, + "run", + "--rm", + "--platform", + "linux/amd64", + target_image, + "/opt/scripts/dummy-probe.sh", + ] + print("Testing dummy-probe.sh (should exit 0)...") + result = subprocess.run(probe_test_cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f"ERROR: dummy-probe.sh failed with exit code {result.returncode}") + print(f"Stdout: {result.stdout}") + print(f"Stderr: {result.stderr}") + return False + print("✓ dummy-probe.sh works correctly (exits 0)!") + + # Test dummy-readinessprobe.sh (should exit 1) + readiness_test_cmd = [ + docker_cmd, + "run", + "--rm", + "--platform", + "linux/amd64", + target_image, + "/opt/scripts/dummy-readinessprobe.sh", + ] + print("Testing dummy-readinessprobe.sh (should exit 1)...") + result = subprocess.run(readiness_test_cmd, capture_output=True, text=True) + if result.returncode != 1: + print(f"ERROR: dummy-readinessprobe.sh should exit 1 but exited {result.returncode}") + print(f"Stdout: {result.stdout}") + print(f"Stderr: {result.stderr}") + return False + print("✓ dummy-readinessprobe.sh works correctly (exits 1)!") + + # Step 5: Push the rebuilt image to ECR + print(f"\n{'='*60}") + print("STEP 5: Pushing rebuilt image to ECR") + print(f"{'='*60}") + + push_cmd = [docker_cmd, "push", target_image] + print(f"Running: {' '.join(push_cmd)}") + result = subprocess.run(push_cmd, check=True, capture_output=True, text=True) + print("✓ Push to ECR successful!") + + # Step 6: Verify the pushed image by pulling it fresh + print(f"\n{'='*60}") + print("STEP 6: Verifying pushed image by pulling fresh copy") + print(f"{'='*60}") + + # Remove local copy first + remove_cmd = [docker_cmd, "rmi", target_image] + subprocess.run(remove_cmd, capture_output=True, text=True) + + # Pull fresh copy (force amd64 platform) + pull_fresh_cmd = [docker_cmd, "pull", "--platform", "linux/amd64", target_image] + print(f"Running: {' '.join(pull_fresh_cmd)}") + result = subprocess.run(pull_fresh_cmd, check=True, capture_output=True, text=True) + print("✓ Fresh pull successful!") + + # Verify files are still there + verify_fresh_cmd = [ + docker_cmd, + "run", + "--rm", + "--platform", + "linux/amd64", + target_image, + "ls", + "-la", + "/opt/scripts/", + ] + result = subprocess.run(verify_fresh_cmd, check=True, capture_output=True, text=True) + + for expected_file in expected_files: + if expected_file not in result.stdout: + print(f"ERROR: {expected_file} missing in fresh pulled image!") + return False + + print("✓ Fresh pulled image has all expected files!") + + return True + + except subprocess.CalledProcessError as e: + print(f"Error during ECR rebuild test:") + print(f"Command: {' '.join(e.cmd)}") + print(f"Return code: {e.returncode}") + print(f"Stdout: {e.stdout}") + print(f"Stderr: {e.stderr}") + return False + + +def show_comparison(docker_cmd: str, agent_version: str): + """Show comparison between base and rebuilt images.""" + + base_image = f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi:{agent_version}" + target_image = f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed:{agent_version}" + + print(f"\n{'='*60}") + print("COMPARISON: Base vs Rebuilt Image") + print(f"{'='*60}") + + try: + print(f"\nBase image files ({agent_version}):") + base_cmd = [docker_cmd, "run", "--rm", "--platform", "linux/amd64", base_image, "ls", "-la", "/opt/scripts/"] + result = subprocess.run(base_cmd, capture_output=True, text=True) + print(result.stdout) + + print(f"\nRebuilt image files ({agent_version}):") + rebuilt_cmd = [ + docker_cmd, + "run", + "--rm", + "--platform", + "linux/amd64", + target_image, + "ls", + "-la", + "/opt/scripts/", + ] + result = subprocess.run(rebuilt_cmd, capture_output=True, text=True) + print(result.stdout) + + except subprocess.CalledProcessError as e: + print(f"Error during comparison: {e}") + + +def main(): + """Main function for ECR real rebuild testing.""" + parser = argparse.ArgumentParser(description="Test ECR real rebuild with specific agent version") + parser.add_argument("--agent-version", help="Specific agent version to test (defaults to latest)") + + args = parser.parse_args() + + print("MongoDB Agent Context Image Rebuild - ECR Real Test") + print("=" * 60) + + # Check if temporary Dockerfile exists + dockerfile_path = "docker/mongodb-agent/Dockerfile.rebuild-context" + try: + with open(dockerfile_path, "r"): + pass + except FileNotFoundError: + print(f"Error: {dockerfile_path} not found.") + print("Please create the temporary Dockerfile first.") + sys.exit(1) + + # Find docker executable + try: + docker_cmd = find_docker_executable() + print(f"Using docker executable: {docker_cmd}") + except Exception as e: + print(f"Error: {e}") + sys.exit(1) + + # Determine agent version to use + if args.agent_version: + agent_version = args.agent_version + print(f"Using specified agent version: {agent_version}") + else: + # Load release.json and get latest agent version + release_data = load_release_json() + latest_version = get_latest_agent_version(release_data) + if not latest_version: + print("Error: Could not find any agent versions in release.json") + sys.exit(1) + + agent_version, tools_version = latest_version + print(f"Using latest agent version: {agent_version} (tools: {tools_version})") + + print("\nThis test will:") + print("1. Pull existing base image from ECR") + print("2. Build rebuilt image with new script files") + print("3. Verify new files are present and functional") + print("4. Push rebuilt image to ECR") + print("5. Verify pushed image by pulling fresh copy") + print("6. Show comparison between base and rebuilt images") + + print(f"\nBase image: 268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi:{agent_version}") + print(f"Target image: 268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed:{agent_version}") + + # Ask for confirmation + response = input(f"\nProceed with ECR real rebuild test? (y/N): ") + if response.lower() != "y": + print("Aborted.") + sys.exit(0) + + # Run the test + if test_ecr_real_rebuild(docker_cmd, agent_version): + print(f"\n{'='*60}") + print("✓ ECR REAL REBUILD TEST SUCCESSFUL!") + print("=" * 60) + print("The rebuild process works correctly with real ECR repositories.") + print("Your rebuilt agent image is now available at:") + print(f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed:{agent_version}") + + # Show comparison + show_comparison(docker_cmd, agent_version) + + print(f"\n{'='*60}") + print("NEXT STEPS:") + print("=" * 60) + print("1. Verify the rebuilt image works in your applications") + print("2. If satisfied, you can run this process on all agent versions") + print("3. For production, use: AGENT_REBUILD_REGISTRY=quay.io/mongodb") + + else: + print(f"\n{'='*60}") + print("✗ ECR REAL REBUILD TEST FAILED!") + print("=" * 60) + print("Please check the error messages above and fix issues.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/test_rebuild_ecr_unit.py b/test_rebuild_ecr_unit.py new file mode 100644 index 000000000..d2528db92 --- /dev/null +++ b/test_rebuild_ecr_unit.py @@ -0,0 +1,297 @@ +#!/usr/bin/env python3 + +""" +Unit test script for ECR to test agent context image rebuild process. + +This script creates a mock context image in your ECR account and tests +the rebuild process before running it against the real Quay images in CI. + +Usage: + # Uses default ECR registry or set custom one + export ECR_REGISTRY=custom-account.dkr.ecr.us-east-1.amazonaws.com # optional + python3 test_rebuild_ecr_unit.py +""" + +import json +import os +import shutil +import subprocess +import sys +from typing import Dict, Optional, Tuple + + +def find_docker_executable() -> str: + """Find docker executable dynamically to work across different environments.""" + docker_cmd = shutil.which("docker") + if docker_cmd is None: + raise Exception("Docker executable not found in PATH") + return docker_cmd + + +def get_ecr_registry() -> str: + """Get ECR registry from environment variable or use default.""" + default_ecr_registry = "268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi" + ecr_registry = os.getenv("ECR_REGISTRY", default_ecr_registry) + return ecr_registry + + +def create_mock_context_image(docker_cmd: str, ecr_registry: str) -> str: + """Create a mock context image in ECR for testing.""" + + # Use a simple base image and create the expected directory structure + mock_dockerfile_content = """ +FROM registry.access.redhat.com/ubi9/ubi-minimal + +# Create the directory structure that a real context image would have +RUN mkdir -p /data /opt/scripts + +# Create mock agent and tools files (empty for testing) +RUN touch /data/mongodb-agent.tar.gz /data/mongodb-tools.tgz /data/LICENSE + +# Create basic versions of the old scripts (without the new ones) +RUN echo '#!/bin/bash' > /opt/scripts/agent-launcher-shim.sh && \ + echo 'echo "Old agent launcher shim"' >> /opt/scripts/agent-launcher-shim.sh && \ + echo '#!/bin/bash' > /opt/scripts/setup-agent-files.sh && \ + echo 'echo "Old setup agent files"' >> /opt/scripts/setup-agent-files.sh && \ + chmod +x /opt/scripts/agent-launcher-shim.sh /opt/scripts/setup-agent-files.sh + +# Note: Intentionally NOT including dummy-probe.sh and dummy-readinessprobe.sh +# to simulate an old context image that needs these files added +""" + + mock_image_name = f"{ecr_registry}/test-mongodb-agent-context" + + print(f"Creating mock context image: {mock_image_name}") + + try: + # Create temporary Dockerfile for mock image + with open("Dockerfile.mock-context", "w") as f: + f.write(mock_dockerfile_content) + + # Build the mock context image + build_cmd = [docker_cmd, "build", "-f", "Dockerfile.mock-context", "-t", mock_image_name, "."] + + print(f"Building mock image: {' '.join(build_cmd)}") + result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) + print("Mock image build successful!") + + # Push to ECR + push_cmd = [docker_cmd, "push", mock_image_name] + print(f"Pushing to ECR: {' '.join(push_cmd)}") + result = subprocess.run(push_cmd, check=True, capture_output=True, text=True) + print("Mock image push successful!") + + # Clean up temporary Dockerfile + os.remove("Dockerfile.mock-context") + + return mock_image_name + + except subprocess.CalledProcessError as e: + print(f"Error creating mock context image:") + print(f"Command: {' '.join(e.cmd)}") + print(f"Return code: {e.returncode}") + print(f"Stdout: {e.stdout}") + print(f"Stderr: {e.stderr}") + + # Clean up temporary Dockerfile + try: + os.remove("Dockerfile.mock-context") + except: + pass + + return None + + +def test_rebuild_with_mock_image(docker_cmd: str, mock_image_name: str) -> bool: + """Test the rebuild process using the mock context image.""" + + test_tag = f"{mock_image_name}-rebuilt" + + print(f"\nTesting rebuild with mock image: {mock_image_name}") + print(f"Test rebuilt tag: {test_tag}") + + try: + # Build the rebuilt image using our temporary Dockerfile + build_cmd = [ + docker_cmd, + "build", + "-f", + "docker/mongodb-agent/Dockerfile.rebuild-context", + "--build-arg", + f"OLD_CONTEXT_IMAGE={mock_image_name}", + "-t", + test_tag, + ".", + ] + + print(f"Building rebuilt image: {' '.join(build_cmd)}") + result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) + print("Rebuild successful!") + + # Verify the new files are present + print("\nVerifying new files are present...") + verify_cmd = [docker_cmd, "run", "--rm", test_tag, "ls", "-la", "/opt/scripts/"] + print(f"Running: {' '.join(verify_cmd)}") + result = subprocess.run(verify_cmd, check=True, capture_output=True, text=True) + print("Files in /opt/scripts/:") + print(result.stdout) + + # Check for the new files that should have been added + expected_new_files = ["dummy-probe.sh", "dummy-readinessprobe.sh"] + + expected_updated_files = ["agent-launcher-shim.sh", "setup-agent-files.sh"] + + missing_files = [] + for expected_file in expected_new_files + expected_updated_files: + if expected_file not in result.stdout: + missing_files.append(expected_file) + + if missing_files: + print(f"ERROR: Missing expected files: {missing_files}") + return False + + print("✓ All expected files are present!") + + # Test that the new dummy scripts work + print("\nTesting dummy probe scripts...") + + # Test dummy-probe.sh (should exit 0) + probe_test_cmd = [docker_cmd, "run", "--rm", test_tag, "/opt/scripts/dummy-probe.sh"] + result = subprocess.run(probe_test_cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f"ERROR: dummy-probe.sh failed with exit code {result.returncode}") + return False + print("✓ dummy-probe.sh works correctly!") + + # Test dummy-readinessprobe.sh (should exit 1) + readiness_test_cmd = [docker_cmd, "run", "--rm", test_tag, "/opt/scripts/dummy-readinessprobe.sh"] + result = subprocess.run(readiness_test_cmd, capture_output=True, text=True) + if result.returncode != 1: + print(f"ERROR: dummy-readinessprobe.sh should exit 1 but exited {result.returncode}") + return False + print("✓ dummy-readinessprobe.sh works correctly!") + + # Clean up test image + print(f"\nCleaning up test image: {test_tag}") + cleanup_cmd = [docker_cmd, "rmi", test_tag] + subprocess.run(cleanup_cmd, check=True, capture_output=True, text=True) + print("Test image cleanup successful!") + + return True + + except subprocess.CalledProcessError as e: + print(f"Error during rebuild test:") + print(f"Command: {' '.join(e.cmd)}") + print(f"Return code: {e.returncode}") + print(f"Stdout: {e.stdout}") + print(f"Stderr: {e.stderr}") + + # Try to clean up test image if it exists + try: + cleanup_cmd = [docker_cmd, "rmi", test_tag] + subprocess.run(cleanup_cmd, capture_output=True, text=True) + except: + pass + + return False + + +def cleanup_mock_image(docker_cmd: str, mock_image_name: str): + """Clean up the mock context image from ECR.""" + print(f"\nCleaning up mock image: {mock_image_name}") + try: + # Remove local image + cleanup_cmd = [docker_cmd, "rmi", mock_image_name] + subprocess.run(cleanup_cmd, capture_output=True, text=True) + print("Local mock image cleanup successful!") + + print("Note: You may want to manually delete the image from ECR console to avoid charges.") + + except Exception as e: + print(f"Warning: Could not clean up mock image: {e}") + + +def main(): + """Main function for ECR unit testing.""" + print("MongoDB Agent Context Image Rebuild - ECR Unit Test") + print("=" * 60) + + # Check if temporary Dockerfile exists + dockerfile_path = "docker/mongodb-agent/Dockerfile.rebuild-context" + try: + with open(dockerfile_path, "r"): + pass + except FileNotFoundError: + print(f"Error: {dockerfile_path} not found.") + print("Please create the temporary Dockerfile first.") + sys.exit(1) + + # Find docker executable + try: + docker_cmd = find_docker_executable() + print(f"Using docker executable: {docker_cmd}") + except Exception as e: + print(f"Error: {e}") + sys.exit(1) + + # Get ECR registry (uses default or environment override) + ecr_registry = get_ecr_registry() + print(f"Using ECR registry: {ecr_registry}") + + print("\nThis test will:") + print("1. Create a mock context image in your ECR account") + print("2. Test the rebuild process with the mock image") + print("3. Verify new files are added correctly") + print("4. Clean up test artifacts") + + # Ask for confirmation + response = input(f"\nProceed with ECR unit test? (y/N): ") + if response.lower() != "y": + print("Aborted.") + sys.exit(0) + + mock_image_name = None + + try: + # Step 1: Create mock context image + print(f"\n" + "=" * 60) + print("STEP 1: Creating mock context image in ECR") + print("=" * 60) + + mock_image_name = create_mock_context_image(docker_cmd, ecr_registry) + if not mock_image_name: + print("Failed to create mock context image.") + sys.exit(1) + + # Step 2: Test rebuild process + print(f"\n" + "=" * 60) + print("STEP 2: Testing rebuild process") + print("=" * 60) + + if test_rebuild_with_mock_image(docker_cmd, mock_image_name): + print(f"\n" + "=" * 60) + print("✓ ECR UNIT TEST SUCCESSFUL!") + print("=" * 60) + print("The rebuild process works correctly with ECR.") + print("You can now run this in CI against Quay with confidence.") + print("\nTo run against Quay in CI:") + print(" export AGENT_REBUILD_REGISTRY=quay.io/mongodb") + print(" python3 rebuild_agent_context_images.py") + else: + print(f"\n" + "=" * 60) + print("✗ ECR UNIT TEST FAILED!") + print("=" * 60) + print("Please fix the issues before running in CI.") + sys.exit(1) + + finally: + # Step 3: Cleanup + if mock_image_name: + print(f"\n" + "=" * 60) + print("STEP 3: Cleaning up") + print("=" * 60) + cleanup_mock_image(docker_cmd, mock_image_name) + + +if __name__ == "__main__": + main() diff --git a/test_single_agent_rebuild.py b/test_single_agent_rebuild.py new file mode 100644 index 000000000..be2497d7b --- /dev/null +++ b/test_single_agent_rebuild.py @@ -0,0 +1,370 @@ +#!/usr/bin/env python3 + +""" +Single agent rebuild test script. + +This script allows you to test the rebuild process with individual agent versions +for easier testing and debugging. You can specify which agent version to test +or let it pick the latest one automatically. + +Usage: + # Test with latest agent version + python3 test_single_agent_rebuild.py + + # Test with specific agent version + python3 test_single_agent_rebuild.py --agent-version 108.0.7.8810-1 --tools-version 100.12.0 + + # Use custom registry (defaults to your ECR) + export AGENT_REBUILD_REGISTRY=268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi + python3 test_single_agent_rebuild.py +""" + +import argparse +import json +import os +import shutil +import subprocess +import sys +from typing import Dict, Optional, Tuple + + +def find_docker_executable() -> str: + """Find docker executable dynamically to work across different environments.""" + docker_cmd = shutil.which("docker") + if docker_cmd is None: + raise Exception("Docker executable not found in PATH") + return docker_cmd + + +def load_release_json() -> Dict: + """Load and parse the release.json file.""" + try: + with open("release.json", "r") as f: + return json.load(f) + except FileNotFoundError: + print("Error: release.json not found. Run this script from the project root.") + sys.exit(1) + except json.JSONDecodeError as e: + print(f"Error parsing release.json: {e}") + sys.exit(1) + + +def get_latest_agent_version(release_data: Dict) -> Optional[Tuple[str, str]]: + """Get the latest agent version and tools version.""" + mongodb_agent = release_data.get("supportedImages", {}).get("mongodb-agent", {}) + ops_manager_mapping = mongodb_agent.get("opsManagerMapping", {}).get("ops_manager", {}) + + if not ops_manager_mapping: + return None + + # Get the latest OpsManager version (highest version number) + latest_om_version = max(ops_manager_mapping.keys(), key=lambda x: [int(i) for i in x.split(".")]) + latest_details = ops_manager_mapping[latest_om_version] + + agent_version = latest_details.get("agent_version") + tools_version = latest_details.get("tools_version") + + if agent_version and tools_version: + return (agent_version, tools_version) + + return None + + +def get_all_agent_versions(release_data: Dict) -> list[Tuple[str, str]]: + """Get all available agent versions for selection.""" + mongodb_agent = release_data.get("supportedImages", {}).get("mongodb-agent", {}) + ops_manager_mapping = mongodb_agent.get("opsManagerMapping", {}).get("ops_manager", {}) + + agent_versions = [] + for om_version, details in ops_manager_mapping.items(): + agent_version = details.get("agent_version") + tools_version = details.get("tools_version") + + if agent_version and tools_version: + agent_versions.append((agent_version, tools_version)) + + # Remove duplicates while preserving order + seen = set() + unique_versions = [] + for agent_ver, tools_ver in agent_versions: + key = (agent_ver, tools_ver) + if key not in seen: + seen.add(key) + unique_versions.append(key) + + return unique_versions + + +def get_registry_config() -> str: + """Get registry configuration from environment or default to ECR.""" + return os.getenv("AGENT_REBUILD_REGISTRY", "268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi") + + +def build_context_image_name(agent_version: str, tools_version: str, variant: str = "ubi") -> str: + """Build the context image name for a given agent and tools version.""" + return f"mongodb-kubernetes-mongodb-agent-context-{agent_version}-{tools_version}-{variant}" + + +def create_mock_context_image(docker_cmd: str, registry: str, agent_version: str, tools_version: str) -> str: + """Create a mock context image for testing (simulates an old context image without new scripts).""" + + # Create a mock context image that simulates an old one without the new dummy scripts + mock_dockerfile_content = f""" +FROM registry.access.redhat.com/ubi9/ubi-minimal + +# Create the directory structure that a real context image would have +RUN mkdir -p /data /opt/scripts + +# Create mock agent and tools files (empty for testing) +RUN touch /data/mongodb-agent.tar.gz /data/mongodb-tools.tgz /data/LICENSE + +# Create basic versions of the old scripts (without the new dummy probe scripts) +RUN echo '#!/bin/bash' > /opt/scripts/agent-launcher-shim.sh && \ + echo 'echo "Old agent launcher shim for {agent_version}"' >> /opt/scripts/agent-launcher-shim.sh && \ + echo '#!/bin/bash' > /opt/scripts/setup-agent-files.sh && \ + echo 'echo "Old setup agent files for {agent_version}"' >> /opt/scripts/setup-agent-files.sh && \ + chmod +x /opt/scripts/agent-launcher-shim.sh /opt/scripts/setup-agent-files.sh + +# Add a label to identify this as a mock image +LABEL mock_agent_version="{agent_version}" mock_tools_version="{tools_version}" + +# Note: Intentionally NOT including dummy-probe.sh and dummy-readinessprobe.sh +# to simulate an old context image that needs these files added +""" + + context_image_name = build_context_image_name(agent_version, tools_version) + mock_image_name = f"{registry}/{context_image_name}-mock" + + print(f"Creating mock context image: {mock_image_name}") + + try: + # Create temporary Dockerfile for mock image + with open("Dockerfile.mock-single-agent", "w") as f: + f.write(mock_dockerfile_content) + + # Build the mock context image + build_cmd = [docker_cmd, "build", "-f", "Dockerfile.mock-single-agent", "-t", mock_image_name, "."] + + print(f"Building mock image: {' '.join(build_cmd)}") + result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) + print("Mock image build successful!") + + # Clean up temporary Dockerfile + os.remove("Dockerfile.mock-single-agent") + + return mock_image_name + + except subprocess.CalledProcessError as e: + print(f"Error creating mock context image:") + print(f"Command: {' '.join(e.cmd)}") + print(f"Return code: {e.returncode}") + print(f"Stdout: {e.stdout}") + print(f"Stderr: {e.stderr}") + + # Clean up temporary Dockerfile + try: + os.remove("Dockerfile.mock-single-agent") + except: + pass + + return None + + +def test_single_agent_rebuild(docker_cmd: str, registry: str, agent_version: str, tools_version: str) -> bool: + """Test rebuild process for a single agent version.""" + + print(f"\n{'='*60}") + print(f"Testing Agent: {agent_version} with Tools: {tools_version}") + print(f"{'='*60}") + + # Step 1: Create mock context image + print("\nStep 1: Creating mock context image...") + mock_image_name = create_mock_context_image(docker_cmd, registry, agent_version, tools_version) + if not mock_image_name: + return False + + try: + # Step 2: Test rebuild process + print("\nStep 2: Testing rebuild process...") + context_image_name = build_context_image_name(agent_version, tools_version) + rebuilt_image_name = f"{registry}/{context_image_name}-rebuilt" + + build_cmd = [ + docker_cmd, + "build", + "-f", + "docker/mongodb-agent/Dockerfile.rebuild-context", + "--build-arg", + f"OLD_CONTEXT_IMAGE={mock_image_name}", + "-t", + rebuilt_image_name, + ".", + ] + + print(f"Building rebuilt image: {' '.join(build_cmd)}") + result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) + print("Rebuild successful!") + + # Step 3: Verify new files are present + print("\nStep 3: Verifying new files are present...") + verify_cmd = [docker_cmd, "run", "--rm", rebuilt_image_name, "ls", "-la", "/opt/scripts/"] + print(f"Running: {' '.join(verify_cmd)}") + result = subprocess.run(verify_cmd, check=True, capture_output=True, text=True) + print("Files in /opt/scripts/:") + print(result.stdout) + + # Check for expected files + expected_files = ["dummy-probe.sh", "dummy-readinessprobe.sh", "agent-launcher-shim.sh", "setup-agent-files.sh"] + + missing_files = [] + for expected_file in expected_files: + if expected_file not in result.stdout: + missing_files.append(expected_file) + + if missing_files: + print(f"ERROR: Missing expected files: {missing_files}") + return False + + print("✓ All expected files are present!") + + # Step 4: Test dummy scripts functionality + print("\nStep 4: Testing dummy probe scripts...") + + # Test dummy-probe.sh (should exit 0) + probe_test_cmd = [docker_cmd, "run", "--rm", rebuilt_image_name, "/opt/scripts/dummy-probe.sh"] + result = subprocess.run(probe_test_cmd, capture_output=True, text=True) + if result.returncode != 0: + print(f"ERROR: dummy-probe.sh failed with exit code {result.returncode}") + return False + print("✓ dummy-probe.sh works correctly (exits 0)!") + + # Test dummy-readinessprobe.sh (should exit 1) + readiness_test_cmd = [docker_cmd, "run", "--rm", rebuilt_image_name, "/opt/scripts/dummy-readinessprobe.sh"] + result = subprocess.run(readiness_test_cmd, capture_output=True, text=True) + if result.returncode != 1: + print(f"ERROR: dummy-readinessprobe.sh should exit 1 but exited {result.returncode}") + return False + print("✓ dummy-readinessprobe.sh works correctly (exits 1)!") + + print(f"\n✓ SUCCESS: Agent {agent_version} rebuild test passed!") + return True + + except subprocess.CalledProcessError as e: + print(f"Error during rebuild test:") + print(f"Command: {' '.join(e.cmd)}") + print(f"Return code: {e.returncode}") + print(f"Stdout: {e.stdout}") + print(f"Stderr: {e.stderr}") + return False + + finally: + # Cleanup + print(f"\nStep 5: Cleaning up test images...") + try: + if mock_image_name: + cleanup_cmd = [docker_cmd, "rmi", mock_image_name] + subprocess.run(cleanup_cmd, capture_output=True, text=True) + print(f"Cleaned up mock image: {mock_image_name}") + + context_image_name = build_context_image_name(agent_version, tools_version) + rebuilt_image_name = f"{registry}/{context_image_name}-rebuilt" + cleanup_cmd = [docker_cmd, "rmi", rebuilt_image_name] + subprocess.run(cleanup_cmd, capture_output=True, text=True) + print(f"Cleaned up rebuilt image: {rebuilt_image_name}") + except: + pass + + +def main(): + """Main function for single agent testing.""" + parser = argparse.ArgumentParser(description="Test agent context image rebuild with single agent") + parser.add_argument("--agent-version", help="Specific agent version to test") + parser.add_argument( + "--tools-version", help="Specific tools version to test (required if agent-version is specified)" + ) + parser.add_argument("--list-agents", action="store_true", help="List all available agent versions") + parser.add_argument("--registry", help="Registry to use (overrides AGENT_REBUILD_REGISTRY env var)") + + args = parser.parse_args() + + print("MongoDB Agent Context Image Rebuild - Single Agent Test") + print("=" * 60) + + # Check if temporary Dockerfile exists + dockerfile_path = "docker/mongodb-agent/Dockerfile.rebuild-context" + try: + with open(dockerfile_path, "r"): + pass + except FileNotFoundError: + print(f"Error: {dockerfile_path} not found.") + print("Please create the temporary Dockerfile first.") + sys.exit(1) + + # Find docker executable + try: + docker_cmd = find_docker_executable() + print(f"Using docker executable: {docker_cmd}") + except Exception as e: + print(f"Error: {e}") + sys.exit(1) + + # Get registry configuration + registry = args.registry or get_registry_config() + print(f"Using registry: {registry}") + + # Load release.json + release_data = load_release_json() + + # Handle list agents option + if args.list_agents: + agent_versions = get_all_agent_versions(release_data) + print(f"\nAvailable agent versions ({len(agent_versions)} total):") + for i, (agent_ver, tools_ver) in enumerate(agent_versions, 1): + print(f" {i:2d}. Agent: {agent_ver}, Tools: {tools_ver}") + sys.exit(0) + + # Determine which agent version to test + if args.agent_version and args.tools_version: + agent_version = args.agent_version + tools_version = args.tools_version + print(f"\nTesting specified agent version:") + print(f" Agent: {agent_version}") + print(f" Tools: {tools_version}") + elif args.agent_version and not args.tools_version: + print("Error: --tools-version is required when --agent-version is specified") + sys.exit(1) + else: + # Use latest agent version + latest_version = get_latest_agent_version(release_data) + if not latest_version: + print("Error: Could not find any agent versions in release.json") + sys.exit(1) + + agent_version, tools_version = latest_version + print(f"\nTesting latest agent version:") + print(f" Agent: {agent_version}") + print(f" Tools: {tools_version}") + + # Ask for confirmation + response = input(f"\nProceed with single agent rebuild test? (y/N): ") + if response.lower() != "y": + print("Aborted.") + sys.exit(0) + + # Run the test + if test_single_agent_rebuild(docker_cmd, registry, agent_version, tools_version): + print(f"\n{'='*60}") + print("✓ SINGLE AGENT TEST SUCCESSFUL!") + print("=" * 60) + print("The rebuild process works correctly for this agent.") + print("You can now test other agents or run the full rebuild.") + else: + print(f"\n{'='*60}") + print("✗ SINGLE AGENT TEST FAILED!") + print("=" * 60) + print("Please fix the issues before testing other agents.") + sys.exit(1) + + +if __name__ == "__main__": + main() From 208235411a57188a5f3f72e2d566548d8ec0e955 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 24 Jul 2025 14:12:54 +0200 Subject: [PATCH 35/49] fix appdb assert costs --- .../tests/vaultintegration/om_backup_vault.py | 2 +- .../tests/vaultintegration/om_deployment_vault.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py index e469edea6..803081603 100644 --- a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py +++ b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py @@ -452,7 +452,7 @@ def test_appdb_reached_running_and_pod_count(ops_manager: MongoDBOpsManager, nam # check AppDB has 4 containers(+1 because of vault-agent) for pod_name in get_pods(ops_manager.name + "-db-{}", 3): pod = client.CoreV1Api().read_namespaced_pod(pod_name, namespace) - assert_container_count(pod.spec.containers, 4) + assert_container_count(len(pod.spec.containers), 4) @mark.e2e_vault_setup_om_backup diff --git a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py index 36bcae687..460378c72 100644 --- a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py +++ b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py @@ -277,7 +277,7 @@ def test_appdb_reached_running_and_pod_count(ops_manager: MongoDBOpsManager, nam # check AppDB has 4 containers(+1 because of vault-agent) for pod_name in get_pods(ops_manager.name + "-db-{}", 3): pod = client.CoreV1Api().read_namespaced_pod(pod_name, namespace) - assert_container_count(pod.spec.containers, 4) + assert_container_count(len(pod.spec.containers), 4) @mark.e2e_vault_setup_om From f8fd45123f43bd4adaceb6ddcbda74b03ed3f7f7 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 24 Jul 2025 15:43:38 +0200 Subject: [PATCH 36/49] remove not used agent --- config/manager/manager.yaml | 8 -------- .../operator/mongodbshardedcluster_controller_test.go | 1 - helm_chart/values-openshift.yaml | 4 ---- public/mongodb-kubernetes-openshift.yaml | 8 -------- release.json | 4 ---- 5 files changed, 25 deletions(-) diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml index 3e4f72934..6e3db67d2 100644 --- a/config/manager/manager.yaml +++ b/config/manager/manager.yaml @@ -130,14 +130,6 @@ spec: value: "quay.io/mongodb/mongodb-kubernetes-init-ops-manager:1.2.0" - name: RELATED_IMAGE_INIT_APPDB_IMAGE_REPOSITORY_1_2_0 value: "quay.io/mongodb/mongodb-kubernetes-init-appdb:1.2.0" - - name: RELATED_IMAGE_AGENT_IMAGE_107_0_10_8627_1 - value: "quay.io/mongodb/mongodb-agent-ubi:107.0.10.8627-1" - - name: RELATED_IMAGE_AGENT_IMAGE_107_0_10_8627_1_1_0_1 - value: "quay.io/mongodb/mongodb-agent-ubi:107.0.10.8627-1_1.0.1" - - name: RELATED_IMAGE_AGENT_IMAGE_107_0_10_8627_1_1_1_0 - value: "quay.io/mongodb/mongodb-agent-ubi:107.0.10.8627-1_1.1.0" - - name: RELATED_IMAGE_AGENT_IMAGE_107_0_10_8627_1_1_2_0 - value: "quay.io/mongodb/mongodb-agent-ubi:107.0.10.8627-1_1.2.0" - name: RELATED_IMAGE_AGENT_IMAGE_107_0_11_8645_1 value: "quay.io/mongodb/mongodb-agent-ubi:107.0.11.8645-1" - name: RELATED_IMAGE_AGENT_IMAGE_107_0_11_8645_1_1_0_1 diff --git a/controllers/operator/mongodbshardedcluster_controller_test.go b/controllers/operator/mongodbshardedcluster_controller_test.go index 457627226..a4fb3df25 100644 --- a/controllers/operator/mongodbshardedcluster_controller_test.go +++ b/controllers/operator/mongodbshardedcluster_controller_test.go @@ -1719,7 +1719,6 @@ func computeSingleClusterShardOverridesFromDistribution(shardOverridesDistributi } type SingleClusterShardedScalingTestCase struct { - name string scalingSteps []SingleClusterShardedScalingStep } diff --git a/helm_chart/values-openshift.yaml b/helm_chart/values-openshift.yaml index 21d0b74c3..0fd1f1e86 100644 --- a/helm_chart/values-openshift.yaml +++ b/helm_chart/values-openshift.yaml @@ -98,10 +98,6 @@ relatedImages: - 8.0.0-ubi8 - 8.0.0-ubi9 agent: - - 107.0.10.8627-1 - - 107.0.10.8627-1_1.0.1 - - 107.0.10.8627-1_1.1.0 - - 107.0.10.8627-1_1.2.0 - 107.0.11.8645-1 - 107.0.11.8645-1_1.0.1 - 107.0.11.8645-1_1.1.0 diff --git a/public/mongodb-kubernetes-openshift.yaml b/public/mongodb-kubernetes-openshift.yaml index f5dbe1864..01d89b3c5 100644 --- a/public/mongodb-kubernetes-openshift.yaml +++ b/public/mongodb-kubernetes-openshift.yaml @@ -412,14 +412,6 @@ spec: value: "quay.io/mongodb/mongodb-kubernetes-init-ops-manager:1.2.0" - name: RELATED_IMAGE_INIT_APPDB_IMAGE_REPOSITORY_1_2_0 value: "quay.io/mongodb/mongodb-kubernetes-init-appdb:1.2.0" - - name: RELATED_IMAGE_AGENT_IMAGE_107_0_10_8627_1 - value: "quay.io/mongodb/mongodb-agent-ubi:107.0.10.8627-1" - - name: RELATED_IMAGE_AGENT_IMAGE_107_0_10_8627_1_1_0_1 - value: "quay.io/mongodb/mongodb-agent-ubi:107.0.10.8627-1_1.0.1" - - name: RELATED_IMAGE_AGENT_IMAGE_107_0_10_8627_1_1_1_0 - value: "quay.io/mongodb/mongodb-agent-ubi:107.0.10.8627-1_1.1.0" - - name: RELATED_IMAGE_AGENT_IMAGE_107_0_10_8627_1_1_2_0 - value: "quay.io/mongodb/mongodb-agent-ubi:107.0.10.8627-1_1.2.0" - name: RELATED_IMAGE_AGENT_IMAGE_107_0_11_8645_1 value: "quay.io/mongodb/mongodb-agent-ubi:107.0.11.8645-1" - name: RELATED_IMAGE_AGENT_IMAGE_107_0_11_8645_1_1_0_1 diff --git a/release.json b/release.json index ed926bfb3..d809001bb 100644 --- a/release.json +++ b/release.json @@ -120,10 +120,6 @@ "agent_version": "12.0.35.7911-1", "tools_version": "100.10.0" }, - "7.0.10": { - "agent_version": "107.0.10.8627-1", - "tools_version": "100.9.5" - }, "7.0.11": { "agent_version": "107.0.11.8645-1", "tools_version": "100.10.0" From ba4755de17be0c1391fac9f67ea9735a716474ed Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Fri, 25 Jul 2025 10:10:37 +0200 Subject: [PATCH 37/49] fix appdb spec --- .../kubetester/kubetester.py | 2 +- .../om_ops_manager_pod_spec.py | 43 +++++++++++-------- .../tests/vaultintegration/om_backup_vault.py | 4 +- .../vaultintegration/om_deployment_vault.py | 4 +- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/docker/mongodb-kubernetes-tests/kubetester/kubetester.py b/docker/mongodb-kubernetes-tests/kubetester/kubetester.py index 85ba33f08..2b0c5c596 100644 --- a/docker/mongodb-kubernetes-tests/kubetester/kubetester.py +++ b/docker/mongodb-kubernetes-tests/kubetester/kubetester.py @@ -69,7 +69,7 @@ def is_default_architecture_static() -> bool: return os.getenv("MDB_DEFAULT_ARCHITECTURE", "non-static") == "static" -def assert_container_count(current_container_count: int, expected_counter_without_static: int): +def assert_container_count_with_static(current_container_count: int, expected_counter_without_static: int): if is_default_architecture_static(): assert current_container_count == expected_counter_without_static + 1 else: diff --git a/docker/mongodb-kubernetes-tests/tests/opsmanager/withMonitoredAppDB/om_ops_manager_pod_spec.py b/docker/mongodb-kubernetes-tests/tests/opsmanager/withMonitoredAppDB/om_ops_manager_pod_spec.py index 8d593eedd..649411802 100644 --- a/docker/mongodb-kubernetes-tests/tests/opsmanager/withMonitoredAppDB/om_ops_manager_pod_spec.py +++ b/docker/mongodb-kubernetes-tests/tests/opsmanager/withMonitoredAppDB/om_ops_manager_pod_spec.py @@ -9,6 +9,7 @@ from kubernetes import client from kubetester import try_load from kubetester.custom_podspec import assert_volume_mounts_are_equal +from kubetester.kubetester import assert_container_count_with_static from kubetester.kubetester import fixture as yaml_fixture from kubetester.kubetester import is_default_architecture_static from kubetester.opsmanager import MongoDBOpsManager @@ -79,19 +80,26 @@ def test_backup_1_pod_becomes_ready(self, ops_manager: MongoDBOpsManager): def test_appdb_pod_template_containers(self, ops_manager: MongoDBOpsManager): appdb_sts = ops_manager.read_appdb_statefulset() - assert len(appdb_sts.spec.template.spec.containers) == 4 + assert_container_count_with_static(len(appdb_sts.spec.template.spec.containers), 4) assert appdb_sts.spec.template.spec.service_account_name == APPDB_SA_NAME - appdb_agent_container = appdb_sts.spec.template.spec.containers[2] - assert appdb_agent_container.name == "mongodb-agent" - assert appdb_agent_container.resources.limits["cpu"] == "750m" - assert appdb_agent_container.resources.limits["memory"] == "850M" - - assert appdb_sts.spec.template.spec.containers[0].name == "appdb-sidecar" - assert appdb_sts.spec.template.spec.containers[0].image == "busybox" - assert appdb_sts.spec.template.spec.containers[0].command == ["sleep"] - assert appdb_sts.spec.template.spec.containers[0].args == ["infinity"] + found_agent_container = False + found_sidecar_container = False + for container in appdb_sts.spec.template.spec.containers: + if container.name == "mongodb-agent": + found_agent_container = True + appdb_agent_container = container + assert appdb_agent_container.resources.limits["cpu"] == "750m" + assert appdb_agent_container.resources.limits["memory"] == "850M" + elif container.name == "appdb-sidecar": + found_sidecar_container = True + assert container.image == "busybox" + assert container.command == ["sleep"] + assert container.args == ["infinity"] + + assert found_agent_container, "mongodb-agent container not found" + assert found_sidecar_container, "appdb-sidecar container not found" def test_appdb_persistence(self, ops_manager: MongoDBOpsManager, namespace: str): # appdb pod volume claim template @@ -362,16 +370,15 @@ def test_backup_1_pod_becomes_ready(self, ops_manager: MongoDBOpsManager): def test_appdb_pod_template(self, ops_manager: MongoDBOpsManager): appdb_sts = ops_manager.read_appdb_statefulset() - assert len(appdb_sts.spec.template.spec.containers) == 4 - - appdb_mongod_container = appdb_sts.spec.template.spec.containers[1] - assert appdb_mongod_container.name == "mongod" + assert_container_count_with_static(len(appdb_sts.spec.template.spec.containers), 4) - appdb_agent_container = appdb_sts.spec.template.spec.containers[2] - assert appdb_agent_container.name == "mongodb-agent" + # Find each container by name instead of position + containers_by_name = {c.name: c for c in appdb_sts.spec.template.spec.containers} - appdb_agent_monitoring_container = appdb_sts.spec.template.spec.containers[3] - assert appdb_agent_monitoring_container.name == "mongodb-agent-monitoring" + # Check that all required containers exist + assert "mongod" in containers_by_name, "mongod container not found" + assert "mongodb-agent" in containers_by_name, "mongodb-agent container not found" + assert "mongodb-agent-monitoring" in containers_by_name, "mongodb-agent-monitoring container not found" assert appdb_sts.spec.template.metadata.annotations == {"annotation1": "val"} diff --git a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py index 803081603..ca555b181 100644 --- a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py +++ b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_backup_vault.py @@ -15,7 +15,7 @@ from kubetester.awss3client import AwsS3Client, s3_endpoint from kubetester.certs import create_mongodb_tls_certs, create_ops_manager_tls_certs from kubetester.http import https_endpoint_is_reachable -from kubetester.kubetester import KubernetesTester, assert_container_count +from kubetester.kubetester import KubernetesTester, assert_container_count_with_static from kubetester.kubetester import fixture as yaml_fixture from kubetester.kubetester import get_pods from kubetester.mongodb import MongoDB @@ -452,7 +452,7 @@ def test_appdb_reached_running_and_pod_count(ops_manager: MongoDBOpsManager, nam # check AppDB has 4 containers(+1 because of vault-agent) for pod_name in get_pods(ops_manager.name + "-db-{}", 3): pod = client.CoreV1Api().read_namespaced_pod(pod_name, namespace) - assert_container_count(len(pod.spec.containers), 4) + assert_container_count_with_static(len(pod.spec.containers), 4) @mark.e2e_vault_setup_om_backup diff --git a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py index 460378c72..75bb5b3a2 100644 --- a/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py +++ b/docker/mongodb-kubernetes-tests/tests/vaultintegration/om_deployment_vault.py @@ -12,7 +12,7 @@ read_secret, ) from kubetester.certs import create_mongodb_tls_certs, create_ops_manager_tls_certs -from kubetester.kubetester import KubernetesTester, assert_container_count +from kubetester.kubetester import KubernetesTester, assert_container_count_with_static from kubetester.kubetester import fixture as yaml_fixture from kubetester.kubetester import get_pods, is_default_architecture_static from kubetester.operator import Operator @@ -277,7 +277,7 @@ def test_appdb_reached_running_and_pod_count(ops_manager: MongoDBOpsManager, nam # check AppDB has 4 containers(+1 because of vault-agent) for pod_name in get_pods(ops_manager.name + "-db-{}", 3): pod = client.CoreV1Api().read_namespaced_pod(pod_name, namespace) - assert_container_count(len(pod.spec.containers), 4) + assert_container_count_with_static(len(pod.spec.containers), 4) @mark.e2e_vault_setup_om From a976ddb78ee840e4cd4e603990c9ede89a4da880 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Fri, 25 Jul 2025 10:22:16 +0200 Subject: [PATCH 38/49] fix appdb spec --- .../om_ops_manager_pod_spec.py | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/docker/mongodb-kubernetes-tests/tests/opsmanager/withMonitoredAppDB/om_ops_manager_pod_spec.py b/docker/mongodb-kubernetes-tests/tests/opsmanager/withMonitoredAppDB/om_ops_manager_pod_spec.py index 649411802..3258ebbd1 100644 --- a/docker/mongodb-kubernetes-tests/tests/opsmanager/withMonitoredAppDB/om_ops_manager_pod_spec.py +++ b/docker/mongodb-kubernetes-tests/tests/opsmanager/withMonitoredAppDB/om_ops_manager_pod_spec.py @@ -84,22 +84,19 @@ def test_appdb_pod_template_containers(self, ops_manager: MongoDBOpsManager): assert appdb_sts.spec.template.spec.service_account_name == APPDB_SA_NAME - found_agent_container = False - found_sidecar_container = False - for container in appdb_sts.spec.template.spec.containers: - if container.name == "mongodb-agent": - found_agent_container = True - appdb_agent_container = container - assert appdb_agent_container.resources.limits["cpu"] == "750m" - assert appdb_agent_container.resources.limits["memory"] == "850M" - elif container.name == "appdb-sidecar": - found_sidecar_container = True - assert container.image == "busybox" - assert container.command == ["sleep"] - assert container.args == ["infinity"] - - assert found_agent_container, "mongodb-agent container not found" - assert found_sidecar_container, "appdb-sidecar container not found" + containers_by_name = {container.name: container for container in appdb_sts.spec.template.spec.containers} + + assert "mongodb-agent" in containers_by_name, "mongodb-agent container not found" + assert "appdb-sidecar" in containers_by_name, "appdb-sidecar container not found" + + appdb_agent_container = containers_by_name["mongodb-agent"] + assert appdb_agent_container.resources.limits["cpu"] == "750m" + assert appdb_agent_container.resources.limits["memory"] == "850M" + + appdb_sidecar_container = containers_by_name["appdb-sidecar"] + assert appdb_sidecar_container.image == "busybox" + assert appdb_sidecar_container.command == ["sleep"] + assert appdb_sidecar_container.args == ["infinity"] def test_appdb_persistence(self, ops_manager: MongoDBOpsManager, namespace: str): # appdb pod volume claim template From 58a5ba7718c73c199043261193e97ff3360510e7 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Fri, 25 Jul 2025 10:22:46 +0200 Subject: [PATCH 39/49] remove rebuild logic --- .../mongodb-agent/Dockerfile.rebuild-context | 21 - test_ecr_real_rebuild.py | 373 ------------------ test_rebuild_ecr_unit.py | 297 -------------- test_single_agent_rebuild.py | 370 ----------------- 4 files changed, 1061 deletions(-) delete mode 100644 docker/mongodb-agent/Dockerfile.rebuild-context delete mode 100644 test_ecr_real_rebuild.py delete mode 100644 test_rebuild_ecr_unit.py delete mode 100644 test_single_agent_rebuild.py diff --git a/docker/mongodb-agent/Dockerfile.rebuild-context b/docker/mongodb-agent/Dockerfile.rebuild-context deleted file mode 100644 index cba68e328..000000000 --- a/docker/mongodb-agent/Dockerfile.rebuild-context +++ /dev/null @@ -1,21 +0,0 @@ -# Temporary Dockerfile for rebuilding existing agent context images -# This Dockerfile uses an existing context image as base and adds the new script files -# that were recently added to the repository but may not be in older context images. - -ARG OLD_CONTEXT_IMAGE -FROM ${OLD_CONTEXT_IMAGE} - -# Copy the new script files that need to be added to all agents -# Use --chmod to set permissions during copy to avoid permission conflicts -COPY --chmod=755 ./docker/mongodb-agent/dummy-probe.sh /opt/scripts/dummy-probe.sh -COPY --chmod=755 ./docker/mongodb-agent/dummy-readinessprobe.sh /opt/scripts/dummy-readinessprobe.sh -COPY --chmod=755 ./docker/mongodb-agent/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh -COPY --chmod=755 ./docker/mongodb-agent/setup-agent-files.sh /opt/scripts/setup-agent-files.sh - -# Verify files are present and executable -RUN ls -la /opt/scripts/ && \ - test -x /opt/scripts/dummy-probe.sh && \ - test -x /opt/scripts/dummy-readinessprobe.sh && \ - test -x /opt/scripts/agent-launcher-shim.sh && \ - test -x /opt/scripts/setup-agent-files.sh && \ - echo "All script files are present and executable" diff --git a/test_ecr_real_rebuild.py b/test_ecr_real_rebuild.py deleted file mode 100644 index f907f91e4..000000000 --- a/test_ecr_real_rebuild.py +++ /dev/null @@ -1,373 +0,0 @@ -#!/usr/bin/env python3 - -""" -ECR Real Rebuild Test Script - -This script tests the rebuild process using your actual ECR repositories: -- Base image: 268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi: -- Target image: 268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed: - -Usage: - # Make sure you're logged in to ECR first - make aws_login - - # Run the test - python3 test_ecr_real_rebuild.py - - # Or test with specific agent version - python3 test_ecr_real_rebuild.py --agent-version 108.0.7.8810-1 -""" - -import argparse -import json -import os -import shutil -import subprocess -import sys -from typing import Dict, Optional, Tuple - - -def find_docker_executable() -> str: - """Find docker executable dynamically to work across different environments.""" - docker_cmd = shutil.which("docker") - if docker_cmd is None: - raise Exception("Docker executable not found in PATH") - return docker_cmd - - -def load_release_json() -> Dict: - """Load and parse the release.json file.""" - try: - with open("release.json", "r") as f: - return json.load(f) - except FileNotFoundError: - print("Error: release.json not found. Run this script from the project root.") - sys.exit(1) - except json.JSONDecodeError as e: - print(f"Error parsing release.json: {e}") - sys.exit(1) - - -def get_latest_agent_version(release_data: Dict) -> Optional[Tuple[str, str]]: - """Get the latest agent version and tools version.""" - mongodb_agent = release_data.get("supportedImages", {}).get("mongodb-agent", {}) - ops_manager_mapping = mongodb_agent.get("opsManagerMapping", {}).get("ops_manager", {}) - - if not ops_manager_mapping: - return None - - # Get the latest OpsManager version (highest version number) - latest_om_version = max(ops_manager_mapping.keys(), key=lambda x: [int(i) for i in x.split(".")]) - latest_details = ops_manager_mapping[latest_om_version] - - agent_version = latest_details.get("agent_version") - tools_version = latest_details.get("tools_version") - - if agent_version and tools_version: - return (agent_version, tools_version) - - return None - - -def test_ecr_real_rebuild(docker_cmd: str, agent_version: str) -> bool: - """Test rebuild process using real ECR repositories.""" - - base_image = f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi:{agent_version}" - target_image = f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed:{agent_version}" - - print(f"Base image: {base_image}") - print(f"Target image: {target_image}") - - try: - # Step 1: Pull the existing base image (force amd64 platform) - print(f"\n{'='*60}") - print("STEP 1: Pulling existing base image from ECR") - print(f"{'='*60}") - - pull_cmd = [docker_cmd, "pull", "--platform", "linux/amd64", base_image] - print(f"Running: {' '.join(pull_cmd)}") - result = subprocess.run(pull_cmd, check=True, capture_output=True, text=True) - print("✓ Base image pull successful!") - - # Step 2: Build the rebuilt image using the temporary Dockerfile (force amd64 platform) - print(f"\n{'='*60}") - print("STEP 2: Building rebuilt image with new script files") - print(f"{'='*60}") - - build_cmd = [ - docker_cmd, - "build", - "--platform", - "linux/amd64", - "-f", - "docker/mongodb-agent/Dockerfile.rebuild-context", - "--build-arg", - f"OLD_CONTEXT_IMAGE={base_image}", - "-t", - target_image, - ".", - ] - - print(f"Running: {' '.join(build_cmd)}") - result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) - print("✓ Rebuild successful!") - - # Step 3: Verify new files are present in rebuilt image - print(f"\n{'='*60}") - print("STEP 3: Verifying new files are present") - print(f"{'='*60}") - - verify_cmd = [ - docker_cmd, - "run", - "--rm", - "--platform", - "linux/amd64", - target_image, - "ls", - "-la", - "/opt/scripts/", - ] - print(f"Running: {' '.join(verify_cmd)}") - result = subprocess.run(verify_cmd, check=True, capture_output=True, text=True) - print("Files in /opt/scripts/:") - print(result.stdout) - - # Check for expected files - expected_files = ["dummy-probe.sh", "dummy-readinessprobe.sh", "agent-launcher-shim.sh", "setup-agent-files.sh"] - - missing_files = [] - for expected_file in expected_files: - if expected_file not in result.stdout: - missing_files.append(expected_file) - - if missing_files: - print(f"ERROR: Missing expected files: {missing_files}") - return False - - print("✓ All expected files are present!") - - # Step 4: Test dummy scripts functionality - print(f"\n{'='*60}") - print("STEP 4: Testing dummy probe scripts functionality") - print(f"{'='*60}") - - # Test dummy-probe.sh (should exit 0) - probe_test_cmd = [ - docker_cmd, - "run", - "--rm", - "--platform", - "linux/amd64", - target_image, - "/opt/scripts/dummy-probe.sh", - ] - print("Testing dummy-probe.sh (should exit 0)...") - result = subprocess.run(probe_test_cmd, capture_output=True, text=True) - if result.returncode != 0: - print(f"ERROR: dummy-probe.sh failed with exit code {result.returncode}") - print(f"Stdout: {result.stdout}") - print(f"Stderr: {result.stderr}") - return False - print("✓ dummy-probe.sh works correctly (exits 0)!") - - # Test dummy-readinessprobe.sh (should exit 1) - readiness_test_cmd = [ - docker_cmd, - "run", - "--rm", - "--platform", - "linux/amd64", - target_image, - "/opt/scripts/dummy-readinessprobe.sh", - ] - print("Testing dummy-readinessprobe.sh (should exit 1)...") - result = subprocess.run(readiness_test_cmd, capture_output=True, text=True) - if result.returncode != 1: - print(f"ERROR: dummy-readinessprobe.sh should exit 1 but exited {result.returncode}") - print(f"Stdout: {result.stdout}") - print(f"Stderr: {result.stderr}") - return False - print("✓ dummy-readinessprobe.sh works correctly (exits 1)!") - - # Step 5: Push the rebuilt image to ECR - print(f"\n{'='*60}") - print("STEP 5: Pushing rebuilt image to ECR") - print(f"{'='*60}") - - push_cmd = [docker_cmd, "push", target_image] - print(f"Running: {' '.join(push_cmd)}") - result = subprocess.run(push_cmd, check=True, capture_output=True, text=True) - print("✓ Push to ECR successful!") - - # Step 6: Verify the pushed image by pulling it fresh - print(f"\n{'='*60}") - print("STEP 6: Verifying pushed image by pulling fresh copy") - print(f"{'='*60}") - - # Remove local copy first - remove_cmd = [docker_cmd, "rmi", target_image] - subprocess.run(remove_cmd, capture_output=True, text=True) - - # Pull fresh copy (force amd64 platform) - pull_fresh_cmd = [docker_cmd, "pull", "--platform", "linux/amd64", target_image] - print(f"Running: {' '.join(pull_fresh_cmd)}") - result = subprocess.run(pull_fresh_cmd, check=True, capture_output=True, text=True) - print("✓ Fresh pull successful!") - - # Verify files are still there - verify_fresh_cmd = [ - docker_cmd, - "run", - "--rm", - "--platform", - "linux/amd64", - target_image, - "ls", - "-la", - "/opt/scripts/", - ] - result = subprocess.run(verify_fresh_cmd, check=True, capture_output=True, text=True) - - for expected_file in expected_files: - if expected_file not in result.stdout: - print(f"ERROR: {expected_file} missing in fresh pulled image!") - return False - - print("✓ Fresh pulled image has all expected files!") - - return True - - except subprocess.CalledProcessError as e: - print(f"Error during ECR rebuild test:") - print(f"Command: {' '.join(e.cmd)}") - print(f"Return code: {e.returncode}") - print(f"Stdout: {e.stdout}") - print(f"Stderr: {e.stderr}") - return False - - -def show_comparison(docker_cmd: str, agent_version: str): - """Show comparison between base and rebuilt images.""" - - base_image = f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi:{agent_version}" - target_image = f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed:{agent_version}" - - print(f"\n{'='*60}") - print("COMPARISON: Base vs Rebuilt Image") - print(f"{'='*60}") - - try: - print(f"\nBase image files ({agent_version}):") - base_cmd = [docker_cmd, "run", "--rm", "--platform", "linux/amd64", base_image, "ls", "-la", "/opt/scripts/"] - result = subprocess.run(base_cmd, capture_output=True, text=True) - print(result.stdout) - - print(f"\nRebuilt image files ({agent_version}):") - rebuilt_cmd = [ - docker_cmd, - "run", - "--rm", - "--platform", - "linux/amd64", - target_image, - "ls", - "-la", - "/opt/scripts/", - ] - result = subprocess.run(rebuilt_cmd, capture_output=True, text=True) - print(result.stdout) - - except subprocess.CalledProcessError as e: - print(f"Error during comparison: {e}") - - -def main(): - """Main function for ECR real rebuild testing.""" - parser = argparse.ArgumentParser(description="Test ECR real rebuild with specific agent version") - parser.add_argument("--agent-version", help="Specific agent version to test (defaults to latest)") - - args = parser.parse_args() - - print("MongoDB Agent Context Image Rebuild - ECR Real Test") - print("=" * 60) - - # Check if temporary Dockerfile exists - dockerfile_path = "docker/mongodb-agent/Dockerfile.rebuild-context" - try: - with open(dockerfile_path, "r"): - pass - except FileNotFoundError: - print(f"Error: {dockerfile_path} not found.") - print("Please create the temporary Dockerfile first.") - sys.exit(1) - - # Find docker executable - try: - docker_cmd = find_docker_executable() - print(f"Using docker executable: {docker_cmd}") - except Exception as e: - print(f"Error: {e}") - sys.exit(1) - - # Determine agent version to use - if args.agent_version: - agent_version = args.agent_version - print(f"Using specified agent version: {agent_version}") - else: - # Load release.json and get latest agent version - release_data = load_release_json() - latest_version = get_latest_agent_version(release_data) - if not latest_version: - print("Error: Could not find any agent versions in release.json") - sys.exit(1) - - agent_version, tools_version = latest_version - print(f"Using latest agent version: {agent_version} (tools: {tools_version})") - - print("\nThis test will:") - print("1. Pull existing base image from ECR") - print("2. Build rebuilt image with new script files") - print("3. Verify new files are present and functional") - print("4. Push rebuilt image to ECR") - print("5. Verify pushed image by pulling fresh copy") - print("6. Show comparison between base and rebuilt images") - - print(f"\nBase image: 268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi:{agent_version}") - print(f"Target image: 268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed:{agent_version}") - - # Ask for confirmation - response = input(f"\nProceed with ECR real rebuild test? (y/N): ") - if response.lower() != "y": - print("Aborted.") - sys.exit(0) - - # Run the test - if test_ecr_real_rebuild(docker_cmd, agent_version): - print(f"\n{'='*60}") - print("✓ ECR REAL REBUILD TEST SUCCESSFUL!") - print("=" * 60) - print("The rebuild process works correctly with real ECR repositories.") - print("Your rebuilt agent image is now available at:") - print(f"268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi-repushed:{agent_version}") - - # Show comparison - show_comparison(docker_cmd, agent_version) - - print(f"\n{'='*60}") - print("NEXT STEPS:") - print("=" * 60) - print("1. Verify the rebuilt image works in your applications") - print("2. If satisfied, you can run this process on all agent versions") - print("3. For production, use: AGENT_REBUILD_REGISTRY=quay.io/mongodb") - - else: - print(f"\n{'='*60}") - print("✗ ECR REAL REBUILD TEST FAILED!") - print("=" * 60) - print("Please check the error messages above and fix issues.") - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/test_rebuild_ecr_unit.py b/test_rebuild_ecr_unit.py deleted file mode 100644 index d2528db92..000000000 --- a/test_rebuild_ecr_unit.py +++ /dev/null @@ -1,297 +0,0 @@ -#!/usr/bin/env python3 - -""" -Unit test script for ECR to test agent context image rebuild process. - -This script creates a mock context image in your ECR account and tests -the rebuild process before running it against the real Quay images in CI. - -Usage: - # Uses default ECR registry or set custom one - export ECR_REGISTRY=custom-account.dkr.ecr.us-east-1.amazonaws.com # optional - python3 test_rebuild_ecr_unit.py -""" - -import json -import os -import shutil -import subprocess -import sys -from typing import Dict, Optional, Tuple - - -def find_docker_executable() -> str: - """Find docker executable dynamically to work across different environments.""" - docker_cmd = shutil.which("docker") - if docker_cmd is None: - raise Exception("Docker executable not found in PATH") - return docker_cmd - - -def get_ecr_registry() -> str: - """Get ECR registry from environment variable or use default.""" - default_ecr_registry = "268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi" - ecr_registry = os.getenv("ECR_REGISTRY", default_ecr_registry) - return ecr_registry - - -def create_mock_context_image(docker_cmd: str, ecr_registry: str) -> str: - """Create a mock context image in ECR for testing.""" - - # Use a simple base image and create the expected directory structure - mock_dockerfile_content = """ -FROM registry.access.redhat.com/ubi9/ubi-minimal - -# Create the directory structure that a real context image would have -RUN mkdir -p /data /opt/scripts - -# Create mock agent and tools files (empty for testing) -RUN touch /data/mongodb-agent.tar.gz /data/mongodb-tools.tgz /data/LICENSE - -# Create basic versions of the old scripts (without the new ones) -RUN echo '#!/bin/bash' > /opt/scripts/agent-launcher-shim.sh && \ - echo 'echo "Old agent launcher shim"' >> /opt/scripts/agent-launcher-shim.sh && \ - echo '#!/bin/bash' > /opt/scripts/setup-agent-files.sh && \ - echo 'echo "Old setup agent files"' >> /opt/scripts/setup-agent-files.sh && \ - chmod +x /opt/scripts/agent-launcher-shim.sh /opt/scripts/setup-agent-files.sh - -# Note: Intentionally NOT including dummy-probe.sh and dummy-readinessprobe.sh -# to simulate an old context image that needs these files added -""" - - mock_image_name = f"{ecr_registry}/test-mongodb-agent-context" - - print(f"Creating mock context image: {mock_image_name}") - - try: - # Create temporary Dockerfile for mock image - with open("Dockerfile.mock-context", "w") as f: - f.write(mock_dockerfile_content) - - # Build the mock context image - build_cmd = [docker_cmd, "build", "-f", "Dockerfile.mock-context", "-t", mock_image_name, "."] - - print(f"Building mock image: {' '.join(build_cmd)}") - result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) - print("Mock image build successful!") - - # Push to ECR - push_cmd = [docker_cmd, "push", mock_image_name] - print(f"Pushing to ECR: {' '.join(push_cmd)}") - result = subprocess.run(push_cmd, check=True, capture_output=True, text=True) - print("Mock image push successful!") - - # Clean up temporary Dockerfile - os.remove("Dockerfile.mock-context") - - return mock_image_name - - except subprocess.CalledProcessError as e: - print(f"Error creating mock context image:") - print(f"Command: {' '.join(e.cmd)}") - print(f"Return code: {e.returncode}") - print(f"Stdout: {e.stdout}") - print(f"Stderr: {e.stderr}") - - # Clean up temporary Dockerfile - try: - os.remove("Dockerfile.mock-context") - except: - pass - - return None - - -def test_rebuild_with_mock_image(docker_cmd: str, mock_image_name: str) -> bool: - """Test the rebuild process using the mock context image.""" - - test_tag = f"{mock_image_name}-rebuilt" - - print(f"\nTesting rebuild with mock image: {mock_image_name}") - print(f"Test rebuilt tag: {test_tag}") - - try: - # Build the rebuilt image using our temporary Dockerfile - build_cmd = [ - docker_cmd, - "build", - "-f", - "docker/mongodb-agent/Dockerfile.rebuild-context", - "--build-arg", - f"OLD_CONTEXT_IMAGE={mock_image_name}", - "-t", - test_tag, - ".", - ] - - print(f"Building rebuilt image: {' '.join(build_cmd)}") - result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) - print("Rebuild successful!") - - # Verify the new files are present - print("\nVerifying new files are present...") - verify_cmd = [docker_cmd, "run", "--rm", test_tag, "ls", "-la", "/opt/scripts/"] - print(f"Running: {' '.join(verify_cmd)}") - result = subprocess.run(verify_cmd, check=True, capture_output=True, text=True) - print("Files in /opt/scripts/:") - print(result.stdout) - - # Check for the new files that should have been added - expected_new_files = ["dummy-probe.sh", "dummy-readinessprobe.sh"] - - expected_updated_files = ["agent-launcher-shim.sh", "setup-agent-files.sh"] - - missing_files = [] - for expected_file in expected_new_files + expected_updated_files: - if expected_file not in result.stdout: - missing_files.append(expected_file) - - if missing_files: - print(f"ERROR: Missing expected files: {missing_files}") - return False - - print("✓ All expected files are present!") - - # Test that the new dummy scripts work - print("\nTesting dummy probe scripts...") - - # Test dummy-probe.sh (should exit 0) - probe_test_cmd = [docker_cmd, "run", "--rm", test_tag, "/opt/scripts/dummy-probe.sh"] - result = subprocess.run(probe_test_cmd, capture_output=True, text=True) - if result.returncode != 0: - print(f"ERROR: dummy-probe.sh failed with exit code {result.returncode}") - return False - print("✓ dummy-probe.sh works correctly!") - - # Test dummy-readinessprobe.sh (should exit 1) - readiness_test_cmd = [docker_cmd, "run", "--rm", test_tag, "/opt/scripts/dummy-readinessprobe.sh"] - result = subprocess.run(readiness_test_cmd, capture_output=True, text=True) - if result.returncode != 1: - print(f"ERROR: dummy-readinessprobe.sh should exit 1 but exited {result.returncode}") - return False - print("✓ dummy-readinessprobe.sh works correctly!") - - # Clean up test image - print(f"\nCleaning up test image: {test_tag}") - cleanup_cmd = [docker_cmd, "rmi", test_tag] - subprocess.run(cleanup_cmd, check=True, capture_output=True, text=True) - print("Test image cleanup successful!") - - return True - - except subprocess.CalledProcessError as e: - print(f"Error during rebuild test:") - print(f"Command: {' '.join(e.cmd)}") - print(f"Return code: {e.returncode}") - print(f"Stdout: {e.stdout}") - print(f"Stderr: {e.stderr}") - - # Try to clean up test image if it exists - try: - cleanup_cmd = [docker_cmd, "rmi", test_tag] - subprocess.run(cleanup_cmd, capture_output=True, text=True) - except: - pass - - return False - - -def cleanup_mock_image(docker_cmd: str, mock_image_name: str): - """Clean up the mock context image from ECR.""" - print(f"\nCleaning up mock image: {mock_image_name}") - try: - # Remove local image - cleanup_cmd = [docker_cmd, "rmi", mock_image_name] - subprocess.run(cleanup_cmd, capture_output=True, text=True) - print("Local mock image cleanup successful!") - - print("Note: You may want to manually delete the image from ECR console to avoid charges.") - - except Exception as e: - print(f"Warning: Could not clean up mock image: {e}") - - -def main(): - """Main function for ECR unit testing.""" - print("MongoDB Agent Context Image Rebuild - ECR Unit Test") - print("=" * 60) - - # Check if temporary Dockerfile exists - dockerfile_path = "docker/mongodb-agent/Dockerfile.rebuild-context" - try: - with open(dockerfile_path, "r"): - pass - except FileNotFoundError: - print(f"Error: {dockerfile_path} not found.") - print("Please create the temporary Dockerfile first.") - sys.exit(1) - - # Find docker executable - try: - docker_cmd = find_docker_executable() - print(f"Using docker executable: {docker_cmd}") - except Exception as e: - print(f"Error: {e}") - sys.exit(1) - - # Get ECR registry (uses default or environment override) - ecr_registry = get_ecr_registry() - print(f"Using ECR registry: {ecr_registry}") - - print("\nThis test will:") - print("1. Create a mock context image in your ECR account") - print("2. Test the rebuild process with the mock image") - print("3. Verify new files are added correctly") - print("4. Clean up test artifacts") - - # Ask for confirmation - response = input(f"\nProceed with ECR unit test? (y/N): ") - if response.lower() != "y": - print("Aborted.") - sys.exit(0) - - mock_image_name = None - - try: - # Step 1: Create mock context image - print(f"\n" + "=" * 60) - print("STEP 1: Creating mock context image in ECR") - print("=" * 60) - - mock_image_name = create_mock_context_image(docker_cmd, ecr_registry) - if not mock_image_name: - print("Failed to create mock context image.") - sys.exit(1) - - # Step 2: Test rebuild process - print(f"\n" + "=" * 60) - print("STEP 2: Testing rebuild process") - print("=" * 60) - - if test_rebuild_with_mock_image(docker_cmd, mock_image_name): - print(f"\n" + "=" * 60) - print("✓ ECR UNIT TEST SUCCESSFUL!") - print("=" * 60) - print("The rebuild process works correctly with ECR.") - print("You can now run this in CI against Quay with confidence.") - print("\nTo run against Quay in CI:") - print(" export AGENT_REBUILD_REGISTRY=quay.io/mongodb") - print(" python3 rebuild_agent_context_images.py") - else: - print(f"\n" + "=" * 60) - print("✗ ECR UNIT TEST FAILED!") - print("=" * 60) - print("Please fix the issues before running in CI.") - sys.exit(1) - - finally: - # Step 3: Cleanup - if mock_image_name: - print(f"\n" + "=" * 60) - print("STEP 3: Cleaning up") - print("=" * 60) - cleanup_mock_image(docker_cmd, mock_image_name) - - -if __name__ == "__main__": - main() diff --git a/test_single_agent_rebuild.py b/test_single_agent_rebuild.py deleted file mode 100644 index be2497d7b..000000000 --- a/test_single_agent_rebuild.py +++ /dev/null @@ -1,370 +0,0 @@ -#!/usr/bin/env python3 - -""" -Single agent rebuild test script. - -This script allows you to test the rebuild process with individual agent versions -for easier testing and debugging. You can specify which agent version to test -or let it pick the latest one automatically. - -Usage: - # Test with latest agent version - python3 test_single_agent_rebuild.py - - # Test with specific agent version - python3 test_single_agent_rebuild.py --agent-version 108.0.7.8810-1 --tools-version 100.12.0 - - # Use custom registry (defaults to your ECR) - export AGENT_REBUILD_REGISTRY=268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi - python3 test_single_agent_rebuild.py -""" - -import argparse -import json -import os -import shutil -import subprocess -import sys -from typing import Dict, Optional, Tuple - - -def find_docker_executable() -> str: - """Find docker executable dynamically to work across different environments.""" - docker_cmd = shutil.which("docker") - if docker_cmd is None: - raise Exception("Docker executable not found in PATH") - return docker_cmd - - -def load_release_json() -> Dict: - """Load and parse the release.json file.""" - try: - with open("release.json", "r") as f: - return json.load(f) - except FileNotFoundError: - print("Error: release.json not found. Run this script from the project root.") - sys.exit(1) - except json.JSONDecodeError as e: - print(f"Error parsing release.json: {e}") - sys.exit(1) - - -def get_latest_agent_version(release_data: Dict) -> Optional[Tuple[str, str]]: - """Get the latest agent version and tools version.""" - mongodb_agent = release_data.get("supportedImages", {}).get("mongodb-agent", {}) - ops_manager_mapping = mongodb_agent.get("opsManagerMapping", {}).get("ops_manager", {}) - - if not ops_manager_mapping: - return None - - # Get the latest OpsManager version (highest version number) - latest_om_version = max(ops_manager_mapping.keys(), key=lambda x: [int(i) for i in x.split(".")]) - latest_details = ops_manager_mapping[latest_om_version] - - agent_version = latest_details.get("agent_version") - tools_version = latest_details.get("tools_version") - - if agent_version and tools_version: - return (agent_version, tools_version) - - return None - - -def get_all_agent_versions(release_data: Dict) -> list[Tuple[str, str]]: - """Get all available agent versions for selection.""" - mongodb_agent = release_data.get("supportedImages", {}).get("mongodb-agent", {}) - ops_manager_mapping = mongodb_agent.get("opsManagerMapping", {}).get("ops_manager", {}) - - agent_versions = [] - for om_version, details in ops_manager_mapping.items(): - agent_version = details.get("agent_version") - tools_version = details.get("tools_version") - - if agent_version and tools_version: - agent_versions.append((agent_version, tools_version)) - - # Remove duplicates while preserving order - seen = set() - unique_versions = [] - for agent_ver, tools_ver in agent_versions: - key = (agent_ver, tools_ver) - if key not in seen: - seen.add(key) - unique_versions.append(key) - - return unique_versions - - -def get_registry_config() -> str: - """Get registry configuration from environment or default to ECR.""" - return os.getenv("AGENT_REBUILD_REGISTRY", "268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/mongodb-agent-ubi") - - -def build_context_image_name(agent_version: str, tools_version: str, variant: str = "ubi") -> str: - """Build the context image name for a given agent and tools version.""" - return f"mongodb-kubernetes-mongodb-agent-context-{agent_version}-{tools_version}-{variant}" - - -def create_mock_context_image(docker_cmd: str, registry: str, agent_version: str, tools_version: str) -> str: - """Create a mock context image for testing (simulates an old context image without new scripts).""" - - # Create a mock context image that simulates an old one without the new dummy scripts - mock_dockerfile_content = f""" -FROM registry.access.redhat.com/ubi9/ubi-minimal - -# Create the directory structure that a real context image would have -RUN mkdir -p /data /opt/scripts - -# Create mock agent and tools files (empty for testing) -RUN touch /data/mongodb-agent.tar.gz /data/mongodb-tools.tgz /data/LICENSE - -# Create basic versions of the old scripts (without the new dummy probe scripts) -RUN echo '#!/bin/bash' > /opt/scripts/agent-launcher-shim.sh && \ - echo 'echo "Old agent launcher shim for {agent_version}"' >> /opt/scripts/agent-launcher-shim.sh && \ - echo '#!/bin/bash' > /opt/scripts/setup-agent-files.sh && \ - echo 'echo "Old setup agent files for {agent_version}"' >> /opt/scripts/setup-agent-files.sh && \ - chmod +x /opt/scripts/agent-launcher-shim.sh /opt/scripts/setup-agent-files.sh - -# Add a label to identify this as a mock image -LABEL mock_agent_version="{agent_version}" mock_tools_version="{tools_version}" - -# Note: Intentionally NOT including dummy-probe.sh and dummy-readinessprobe.sh -# to simulate an old context image that needs these files added -""" - - context_image_name = build_context_image_name(agent_version, tools_version) - mock_image_name = f"{registry}/{context_image_name}-mock" - - print(f"Creating mock context image: {mock_image_name}") - - try: - # Create temporary Dockerfile for mock image - with open("Dockerfile.mock-single-agent", "w") as f: - f.write(mock_dockerfile_content) - - # Build the mock context image - build_cmd = [docker_cmd, "build", "-f", "Dockerfile.mock-single-agent", "-t", mock_image_name, "."] - - print(f"Building mock image: {' '.join(build_cmd)}") - result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) - print("Mock image build successful!") - - # Clean up temporary Dockerfile - os.remove("Dockerfile.mock-single-agent") - - return mock_image_name - - except subprocess.CalledProcessError as e: - print(f"Error creating mock context image:") - print(f"Command: {' '.join(e.cmd)}") - print(f"Return code: {e.returncode}") - print(f"Stdout: {e.stdout}") - print(f"Stderr: {e.stderr}") - - # Clean up temporary Dockerfile - try: - os.remove("Dockerfile.mock-single-agent") - except: - pass - - return None - - -def test_single_agent_rebuild(docker_cmd: str, registry: str, agent_version: str, tools_version: str) -> bool: - """Test rebuild process for a single agent version.""" - - print(f"\n{'='*60}") - print(f"Testing Agent: {agent_version} with Tools: {tools_version}") - print(f"{'='*60}") - - # Step 1: Create mock context image - print("\nStep 1: Creating mock context image...") - mock_image_name = create_mock_context_image(docker_cmd, registry, agent_version, tools_version) - if not mock_image_name: - return False - - try: - # Step 2: Test rebuild process - print("\nStep 2: Testing rebuild process...") - context_image_name = build_context_image_name(agent_version, tools_version) - rebuilt_image_name = f"{registry}/{context_image_name}-rebuilt" - - build_cmd = [ - docker_cmd, - "build", - "-f", - "docker/mongodb-agent/Dockerfile.rebuild-context", - "--build-arg", - f"OLD_CONTEXT_IMAGE={mock_image_name}", - "-t", - rebuilt_image_name, - ".", - ] - - print(f"Building rebuilt image: {' '.join(build_cmd)}") - result = subprocess.run(build_cmd, check=True, capture_output=True, text=True) - print("Rebuild successful!") - - # Step 3: Verify new files are present - print("\nStep 3: Verifying new files are present...") - verify_cmd = [docker_cmd, "run", "--rm", rebuilt_image_name, "ls", "-la", "/opt/scripts/"] - print(f"Running: {' '.join(verify_cmd)}") - result = subprocess.run(verify_cmd, check=True, capture_output=True, text=True) - print("Files in /opt/scripts/:") - print(result.stdout) - - # Check for expected files - expected_files = ["dummy-probe.sh", "dummy-readinessprobe.sh", "agent-launcher-shim.sh", "setup-agent-files.sh"] - - missing_files = [] - for expected_file in expected_files: - if expected_file not in result.stdout: - missing_files.append(expected_file) - - if missing_files: - print(f"ERROR: Missing expected files: {missing_files}") - return False - - print("✓ All expected files are present!") - - # Step 4: Test dummy scripts functionality - print("\nStep 4: Testing dummy probe scripts...") - - # Test dummy-probe.sh (should exit 0) - probe_test_cmd = [docker_cmd, "run", "--rm", rebuilt_image_name, "/opt/scripts/dummy-probe.sh"] - result = subprocess.run(probe_test_cmd, capture_output=True, text=True) - if result.returncode != 0: - print(f"ERROR: dummy-probe.sh failed with exit code {result.returncode}") - return False - print("✓ dummy-probe.sh works correctly (exits 0)!") - - # Test dummy-readinessprobe.sh (should exit 1) - readiness_test_cmd = [docker_cmd, "run", "--rm", rebuilt_image_name, "/opt/scripts/dummy-readinessprobe.sh"] - result = subprocess.run(readiness_test_cmd, capture_output=True, text=True) - if result.returncode != 1: - print(f"ERROR: dummy-readinessprobe.sh should exit 1 but exited {result.returncode}") - return False - print("✓ dummy-readinessprobe.sh works correctly (exits 1)!") - - print(f"\n✓ SUCCESS: Agent {agent_version} rebuild test passed!") - return True - - except subprocess.CalledProcessError as e: - print(f"Error during rebuild test:") - print(f"Command: {' '.join(e.cmd)}") - print(f"Return code: {e.returncode}") - print(f"Stdout: {e.stdout}") - print(f"Stderr: {e.stderr}") - return False - - finally: - # Cleanup - print(f"\nStep 5: Cleaning up test images...") - try: - if mock_image_name: - cleanup_cmd = [docker_cmd, "rmi", mock_image_name] - subprocess.run(cleanup_cmd, capture_output=True, text=True) - print(f"Cleaned up mock image: {mock_image_name}") - - context_image_name = build_context_image_name(agent_version, tools_version) - rebuilt_image_name = f"{registry}/{context_image_name}-rebuilt" - cleanup_cmd = [docker_cmd, "rmi", rebuilt_image_name] - subprocess.run(cleanup_cmd, capture_output=True, text=True) - print(f"Cleaned up rebuilt image: {rebuilt_image_name}") - except: - pass - - -def main(): - """Main function for single agent testing.""" - parser = argparse.ArgumentParser(description="Test agent context image rebuild with single agent") - parser.add_argument("--agent-version", help="Specific agent version to test") - parser.add_argument( - "--tools-version", help="Specific tools version to test (required if agent-version is specified)" - ) - parser.add_argument("--list-agents", action="store_true", help="List all available agent versions") - parser.add_argument("--registry", help="Registry to use (overrides AGENT_REBUILD_REGISTRY env var)") - - args = parser.parse_args() - - print("MongoDB Agent Context Image Rebuild - Single Agent Test") - print("=" * 60) - - # Check if temporary Dockerfile exists - dockerfile_path = "docker/mongodb-agent/Dockerfile.rebuild-context" - try: - with open(dockerfile_path, "r"): - pass - except FileNotFoundError: - print(f"Error: {dockerfile_path} not found.") - print("Please create the temporary Dockerfile first.") - sys.exit(1) - - # Find docker executable - try: - docker_cmd = find_docker_executable() - print(f"Using docker executable: {docker_cmd}") - except Exception as e: - print(f"Error: {e}") - sys.exit(1) - - # Get registry configuration - registry = args.registry or get_registry_config() - print(f"Using registry: {registry}") - - # Load release.json - release_data = load_release_json() - - # Handle list agents option - if args.list_agents: - agent_versions = get_all_agent_versions(release_data) - print(f"\nAvailable agent versions ({len(agent_versions)} total):") - for i, (agent_ver, tools_ver) in enumerate(agent_versions, 1): - print(f" {i:2d}. Agent: {agent_ver}, Tools: {tools_ver}") - sys.exit(0) - - # Determine which agent version to test - if args.agent_version and args.tools_version: - agent_version = args.agent_version - tools_version = args.tools_version - print(f"\nTesting specified agent version:") - print(f" Agent: {agent_version}") - print(f" Tools: {tools_version}") - elif args.agent_version and not args.tools_version: - print("Error: --tools-version is required when --agent-version is specified") - sys.exit(1) - else: - # Use latest agent version - latest_version = get_latest_agent_version(release_data) - if not latest_version: - print("Error: Could not find any agent versions in release.json") - sys.exit(1) - - agent_version, tools_version = latest_version - print(f"\nTesting latest agent version:") - print(f" Agent: {agent_version}") - print(f" Tools: {tools_version}") - - # Ask for confirmation - response = input(f"\nProceed with single agent rebuild test? (y/N): ") - if response.lower() != "y": - print("Aborted.") - sys.exit(0) - - # Run the test - if test_single_agent_rebuild(docker_cmd, registry, agent_version, tools_version): - print(f"\n{'='*60}") - print("✓ SINGLE AGENT TEST SUCCESSFUL!") - print("=" * 60) - print("The rebuild process works correctly for this agent.") - print("You can now test other agents or run the full rebuild.") - else: - print(f"\n{'='*60}") - print("✗ SINGLE AGENT TEST FAILED!") - print("=" * 60) - print("Please fix the issues before testing other agents.") - sys.exit(1) - - -if __name__ == "__main__": - main() From ee2bbc8cc1f40deb36173ac5578610664029ef57 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Tue, 5 Aug 2025 14:13:46 +0200 Subject: [PATCH 40/49] fix merge --- docker/mongodb-agent-non-matrix/Dockerfile | 75 --------------- .../Dockerfile.builder | 15 --- .../mongodb-agent-non-matrix/Dockerfile.old | 60 ------------ docker/mongodb-agent-non-matrix/README.md | 17 ---- .../agent-launcher-shim.sh | 31 ------ .../mongodb-agent-non-matrix/dummy-probe.sh | 5 - .../dummy-readinessprobe.sh | 5 - .../setup-agent-files.sh | 95 ------------------- go.sum | 32 +++++++ pipeline.py | 52 +++++----- 10 files changed, 58 insertions(+), 329 deletions(-) delete mode 100644 docker/mongodb-agent-non-matrix/Dockerfile delete mode 100644 docker/mongodb-agent-non-matrix/Dockerfile.builder delete mode 100644 docker/mongodb-agent-non-matrix/Dockerfile.old delete mode 100644 docker/mongodb-agent-non-matrix/README.md delete mode 100644 docker/mongodb-agent-non-matrix/agent-launcher-shim.sh delete mode 100644 docker/mongodb-agent-non-matrix/dummy-probe.sh delete mode 100644 docker/mongodb-agent-non-matrix/dummy-readinessprobe.sh delete mode 100644 docker/mongodb-agent-non-matrix/setup-agent-files.sh diff --git a/docker/mongodb-agent-non-matrix/Dockerfile b/docker/mongodb-agent-non-matrix/Dockerfile deleted file mode 100644 index dadfc7099..000000000 --- a/docker/mongodb-agent-non-matrix/Dockerfile +++ /dev/null @@ -1,75 +0,0 @@ -FROM scratch AS base - -ARG agent_version -ARG agent_distro -ARG tools_version -ARG tools_distro - -ADD https://mciuploads.s3.amazonaws.com/mms-automation/mongodb-mms-build-agent/builds/automation-agent/prod/mongodb-mms-automation-agent-${agent_version}.${agent_distro}.tar.gz /data/mongodb-agent.tar.gz -ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro}-${tools_version}.tgz /data/mongodb-tools.tgz - -COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE - -FROM registry.access.redhat.com/ubi9/ubi-minimal - -ARG version - -LABEL name="MongoDB Agent" \ - version="${version}" \ - summary="MongoDB Agent" \ - description="MongoDB Agent" \ - vendor="MongoDB" \ - release="1" \ - maintainer="support@mongodb.com" - -# Replace libcurl-minimal and curl-minimal with the full versions -# https://bugzilla.redhat.com/show_bug.cgi?id=1994521 -RUN microdnf install -y libssh libpsl libbrotli \ - && microdnf download curl libcurl \ - && rpm -Uvh --nodeps --replacefiles "*curl*$( uname -i ).rpm" \ - && microdnf remove -y libcurl-minimal curl-minimal - -RUN microdnf install -y --disableplugin=subscription-manager --setopt=install_weak_deps=0 nss_wrapper -# Copy-pasted from https://www.mongodb.com/docs/manual/tutorial/install-mongodb-enterprise-on-red-hat-tarball/ -RUN microdnf install -y --disableplugin=subscription-manager \ - cyrus-sasl cyrus-sasl-gssapi cyrus-sasl-plain krb5-libs openldap openssl xz-libs -# Dependencies for the Agent -RUN microdnf install -y --disableplugin=subscription-manager --setopt=install_weak_deps=0 \ - net-snmp \ - net-snmp-agent-libs -RUN microdnf install -y --disableplugin=subscription-manager \ - hostname tar gzip procps jq \ - && microdnf upgrade -y \ - && rm -rf /var/lib/apt/lists/* - -RUN mkdir -p /agent \ - && mkdir -p /var/lib/mongodb-mms-automation \ - && mkdir -p /var/log/mongodb-mms-automation/ \ - && chmod -R +wr /var/log/mongodb-mms-automation/ \ - # ensure that the agent user can write the logs in OpenShift - && touch /var/log/mongodb-mms-automation/readiness.log \ - && chmod ugo+rw /var/log/mongodb-mms-automation/readiness.log - - -COPY --from=base /data/mongodb-agent.tar.gz /agent -COPY --from=base /data/mongodb-tools.tgz /agent -COPY --from=base /data/LICENSE /licenses/LICENSE - -# Copy scripts to a safe location that won't be overwritten by volume mount -COPY --from=base /opt/scripts/agent-launcher-shim.sh /usr/local/bin/agent-launcher-shim.sh -COPY --from=base /opt/scripts/setup-agent-files.sh /usr/local/bin/setup-agent-files.sh -COPY --from=base /opt/scripts/dummy-probe.sh /usr/local/bin/dummy-probe.sh -COPY --from=base /opt/scripts/dummy-readinessprobe.sh /usr/local/bin/dummy-readinessprobe - -RUN tar xfz /agent/mongodb-agent.tar.gz \ - && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ - && chmod +x /agent/mongodb-agent \ - && mkdir -p /var/lib/automation/config \ - && chmod -R +r /var/lib/automation/config \ - && rm /agent/mongodb-agent.tar.gz \ - && rm -r mongodb-mms-automation-agent-* - -RUN tar xfz /agent/mongodb-tools.tgz --directory /var/lib/mongodb-mms-automation/ && rm /agent/mongodb-tools.tgz - -USER 2000 -CMD ["/agent/mongodb-agent", "-cluster=/var/lib/automation/config/automation-config.json"] diff --git a/docker/mongodb-agent-non-matrix/Dockerfile.builder b/docker/mongodb-agent-non-matrix/Dockerfile.builder deleted file mode 100644 index ac4dd31f0..000000000 --- a/docker/mongodb-agent-non-matrix/Dockerfile.builder +++ /dev/null @@ -1,15 +0,0 @@ -FROM scratch - -ARG agent_version -ARG agent_distro -ARG tools_distro -ARG tools_version - -ADD https://mciuploads.s3.amazonaws.com/mms-automation/mongodb-mms-build-agent/builds/automation-agent/prod/mongodb-mms-automation-agent-${agent_version}.${agent_distro}.tar.gz /data/mongodb-agent.tar.gz -ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro}-${tools_version}.tgz /data/mongodb-tools.tgz - -COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE -COPY ./docker/mongodb-agent/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh -COPY ./docker/mongodb-agent/setup-agent-files.sh /opt/scripts/setup-agent-files.sh -COPY ./docker/mongodb-agent/dummy-probe.sh /opt/scripts/dummy-probe.sh -COPY ./docker/mongodb-agent/dummy-readinessprobe.sh /opt/scripts/dummy-readinessprobe.sh diff --git a/docker/mongodb-agent-non-matrix/Dockerfile.old b/docker/mongodb-agent-non-matrix/Dockerfile.old deleted file mode 100644 index e1c1caff2..000000000 --- a/docker/mongodb-agent-non-matrix/Dockerfile.old +++ /dev/null @@ -1,60 +0,0 @@ -ARG imagebase -FROM ${imagebase} as base - -FROM registry.access.redhat.com/ubi9/ubi-minimal - -ARG version - -LABEL name="MongoDB Agent" \ - version="${version}" \ - summary="MongoDB Agent" \ - description="MongoDB Agent" \ - vendor="MongoDB" \ - release="1" \ - maintainer="support@mongodb.com" - -# Replace libcurl-minimal and curl-minimal with the full versions -# https://bugzilla.redhat.com/show_bug.cgi?id=1994521 -RUN microdnf install -y libssh libpsl libbrotli \ - && microdnf download curl libcurl \ - && rpm -Uvh --nodeps --replacefiles "*curl*$( uname -i ).rpm" \ - && microdnf remove -y libcurl-minimal curl-minimal - -RUN microdnf install -y --disableplugin=subscription-manager --setopt=install_weak_deps=0 nss_wrapper -# Copy-pasted from https://www.mongodb.com/docs/manual/tutorial/install-mongodb-enterprise-on-red-hat-tarball/ -RUN microdnf install -y --disableplugin=subscription-manager \ - cyrus-sasl cyrus-sasl-gssapi cyrus-sasl-plain krb5-libs openldap openssl xz-libs -# Dependencies for the Agent -RUN microdnf install -y --disableplugin=subscription-manager --setopt=install_weak_deps=0 \ - net-snmp \ - net-snmp-agent-libs -RUN microdnf install -y --disableplugin=subscription-manager \ - hostname tar gzip procps jq \ - && microdnf upgrade -y \ - && rm -rf /var/lib/apt/lists/* - -RUN mkdir -p /agent \ - && mkdir -p /var/lib/mongodb-mms-automation \ - && mkdir -p /var/log/mongodb-mms-automation/ \ - && chmod -R +wr /var/log/mongodb-mms-automation/ \ - # ensure that the agent user can write the logs in OpenShift - && touch /var/log/mongodb-mms-automation/readiness.log \ - && chmod ugo+rw /var/log/mongodb-mms-automation/readiness.log - - -COPY --from=base /data/mongodb-agent.tar.gz /agent -COPY --from=base /data/mongodb-tools.tgz /agent -COPY --from=base /data/LICENSE /licenses/LICENSE - -RUN tar xfz /agent/mongodb-agent.tar.gz \ - && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ - && chmod +x /agent/mongodb-agent \ - && mkdir -p /var/lib/automation/config \ - && chmod -R +r /var/lib/automation/config \ - && rm /agent/mongodb-agent.tar.gz \ - && rm -r mongodb-mms-automation-agent-* - -RUN tar xfz /agent/mongodb-tools.tgz --directory /var/lib/mongodb-mms-automation/ && rm /agent/mongodb-tools.tgz - -USER 2000 -CMD ["/agent/mongodb-agent", "-cluster=/var/lib/automation/config/automation-config.json"] diff --git a/docker/mongodb-agent-non-matrix/README.md b/docker/mongodb-agent-non-matrix/README.md deleted file mode 100644 index 79dc0d2d5..000000000 --- a/docker/mongodb-agent-non-matrix/README.md +++ /dev/null @@ -1,17 +0,0 @@ -### Building locally - -For building the MongoDB Agent (non-static) image locally use the example command: - -TODO: What to do with label quay.expires-after=48h? -```bash -AGENT_VERSION="108.0.7.8810-1" -TOOLS_VERSION="100.12.0" -AGENT_DISTRO="rhel9_x86_64" -TOOLS_DISTRO="rhel93-x86_64" -docker buildx build --load --progress plain . -f docker/mongodb-agent/Dockerfile -t "mongodb-agent:${AGENT_VERSION}" \ - --build-arg version="${VERSION}" \ - --build-arg agent_version="${AGENT_VERSION}" \ - --build-arg tools_version="${TOOLS_VERSION}" \ - --build-arg agent_distro="${AGENT_DISTRO}" \ - --build-arg tools_distro="${TOOLS_DISTRO}" -``` diff --git a/docker/mongodb-agent-non-matrix/agent-launcher-shim.sh b/docker/mongodb-agent-non-matrix/agent-launcher-shim.sh deleted file mode 100644 index fda61405b..000000000 --- a/docker/mongodb-agent-non-matrix/agent-launcher-shim.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -set -e - -SCRIPTS_DIR="/opt/scripts" - -# Function to start the agent launcher -start_agent_launcher() { - echo "Starting agent launcher..." - echo "Final contents of $SCRIPTS_DIR:" - ls -la "$SCRIPTS_DIR" - - if [[ -f "$SCRIPTS_DIR/agent-launcher.sh" ]]; then - echo "Found agent-launcher.sh, executing..." - exec "$SCRIPTS_DIR/agent-launcher.sh" - else - echo "ERROR: agent-launcher.sh not found" - exit 1 - fi -} - -main() { - echo "Running setup-agent-files.sh..." - if ! /usr/local/bin/setup-agent-files.sh; then - echo "ERROR: Failed to set up agent files" - exit 1 - fi - - start_agent_launcher -} - -main "$@" diff --git a/docker/mongodb-agent-non-matrix/dummy-probe.sh b/docker/mongodb-agent-non-matrix/dummy-probe.sh deleted file mode 100644 index 911135f1b..000000000 --- a/docker/mongodb-agent-non-matrix/dummy-probe.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# Dummy liveness probe that returns success to keep container alive during script copying -# This prevents container from being killed while waiting for real probe scripts -echo "Using dummy liveness probe - keeping container alive until real probe script is copied" -exit 0 diff --git a/docker/mongodb-agent-non-matrix/dummy-readinessprobe.sh b/docker/mongodb-agent-non-matrix/dummy-readinessprobe.sh deleted file mode 100644 index e93b0bc84..000000000 --- a/docker/mongodb-agent-non-matrix/dummy-readinessprobe.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# Dummy readiness probe that returns NOT READY until real probe is copied -# Container should not be marked ready until real probe scripts are available -echo "Using dummy readiness probe - container not ready until real probe script is copied" -exit 1 diff --git a/docker/mongodb-agent-non-matrix/setup-agent-files.sh b/docker/mongodb-agent-non-matrix/setup-agent-files.sh deleted file mode 100644 index 6a1b8a007..000000000 --- a/docker/mongodb-agent-non-matrix/setup-agent-files.sh +++ /dev/null @@ -1,95 +0,0 @@ -#!/bin/bash -set -e - -SCRIPTS_DIR="/opt/scripts" - -# Set up dummy probe scripts -# liveness always returns success -# readiness always returns failure -setup_dummy_probes() { - echo "Setting up dummy probe scripts..." - cp /usr/local/bin/dummy-probe.sh "$SCRIPTS_DIR/probe.sh" - cp /usr/local/bin/dummy-readinessprobe "$SCRIPTS_DIR/readinessprobe" - echo "Dummy probe scripts ready" -} - -# wait max 5m for init container to be ready -find_init_container() { - for i in {1..150}; do - local pid - pid=$(pgrep -f "agent-utilities-holder_marker" | head -n1) - if [[ -n "$pid" && -d "/proc/$pid/root/scripts" ]]; then - echo "$pid" - return 0 - fi - echo "Waiting for init container... (attempt $i)" >&2 - sleep 2 - done - return 1 -} - -link_agent_scripts() { - local init_scripts_dir="$1" - - echo "Linking agent launcher scripts..." - for script in agent-launcher.sh agent-launcher-lib.sh; do - ln -sf "$init_scripts_dir/$script" "$SCRIPTS_DIR/$script" - echo "Linked $script" - done -} - -# Link probe scripts from init container, replacing dummy ones -link_probe_scripts() { - local init_probes_dir="$1" - - echo "Linking probe scripts..." - for probe in probe.sh readinessprobe; do - if [[ -f "$init_probes_dir/$probe" ]]; then - ln -sf "$init_probes_dir/$probe" "$SCRIPTS_DIR/$probe" - echo "Replaced dummy $probe with real one" - else - echo "WARNING: $probe not found in init container" - exit 1 - fi - done -} - -# Main function to set up all files -main() { - setup_dummy_probes - - if init_pid=$(find_init_container); then - echo "Found init container with PID: $init_pid" - - init_root="/proc/$init_pid/root" - init_scripts="$init_root/scripts" - init_probes="$init_root/probes" - - # Verify scripts directory exists - if [[ ! -d "$init_scripts" ]]; then - echo "ERROR: Scripts directory $init_scripts not found" - exit 1 - fi - - # Verify probes directory exists - if [[ ! -d "$init_probes" ]]; then - echo "ERROR: Probes directory $init_probes not found" - exit 1 - fi - - # Link scripts from init container - link_agent_scripts "$init_scripts" - link_probe_scripts "$init_probes" - - echo "File setup completed successfully" - exit 0 - else - echo "No init container found" - exit 1 - fi -} - -# Only run main if script is executed directly -if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then - main "$@" -fi diff --git a/go.sum b/go.sum index b7ec791f4..9ef0404ec 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,7 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -36,8 +37,11 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= @@ -87,6 +91,7 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -99,6 +104,7 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= @@ -110,12 +116,15 @@ github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0S github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4= github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA= +github.com/hashicorp/vault/api v1.20.0/go.mod h1:GZ4pcjfzoOWpkJ3ijHNpEoAxKEsBJnVljyTe3jM2Sms= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -192,6 +201,7 @@ github.com/r3labs/diff/v3 v3.0.1 h1:CBKqf3XmNRHXKmdU7mZP1w7TV0pDyVCis1AUHtA4Xtg= github.com/r3labs/diff/v3 v3.0.1/go.mod h1:f1S9bourRbiM66NskseyUdo0fTmEE0qKrikYJX63dgo= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= @@ -199,6 +209,8 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk= github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -243,18 +255,29 @@ go.mongodb.org/atlas v0.38.0 h1:zfwymq20GqivGwxPZfypfUDry+WwMGVui97z1d8V4bU= go.mongodb.org/atlas v0.38.0/go.mod h1:DJYtM+vsEpPEMSkQzJnFHrT0sP7ev6cseZc/GGjJYG8= go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ= go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= 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/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= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -262,6 +285,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -272,6 +296,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -281,6 +306,7 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -308,6 +334,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -318,6 +345,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -326,6 +354,9 @@ golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSm golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -380,3 +411,4 @@ sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+s sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/pipeline.py b/pipeline.py index 58c48a2a6..2aac7fe40 100755 --- a/pipeline.py +++ b/pipeline.py @@ -1040,19 +1040,19 @@ def build_image_generic( if with_image_base: image_base = "mongodb-kubernetes-" - try: - if not multi_arch_args_list: - multi_arch_args_list = [extra_args or {}] + if not multi_arch_args_list: + multi_arch_args_list = [extra_args or {}] + version = multi_arch_args_list[0].get("version", "") - version = multi_arch_args_list[0].get("version", "") - if config.is_release_step_executed(): - registry = f"{QUAY_REGISTRY_URL}/{image_base}{image_name}" - else: - registry = f"{config.base_repository}/{image_base}{image_name}" + if config.is_release_step_executed(): + registry = f"{QUAY_REGISTRY_URL}/{image_base}{image_name}" + else: + registry = f"{config.base_repository}/{image_base}{image_name}" - if registry_address_override: - registry = registry_address_override + if registry_address_override: + registry = registry_address_override + try: for args in multi_arch_args_list: # in case we are building multiple architectures args["quay_registry"] = registry sonar_build_image(image_name, config, args, inventory_file, False) @@ -1085,24 +1085,24 @@ def build_image_generic( f"Skipping tagging and pushing {registry}:{version} as {latest_tag} tag; is_running_in_patch={is_running_in_patch()}, is_running_in_evg_pipeline={is_running_in_evg_pipeline()}" ) - # Sign and verify the context image if on releases if required. - if config.sign and config.is_release_step_executed(): - sign_and_verify_context_image(registry, version) + # Sign and verify the context image if on releases if required. + if config.sign and config.is_release_step_executed(): + sign_and_verify_context_image(registry, version) - span = trace.get_current_span() - span.set_attribute("mck.image.image_name", image_name) - span.set_attribute("mck.image.version", version) - span.set_attribute("mck.image.is_release", config.is_release_step_executed()) - span.set_attribute("mck.image.is_multi_arch", is_multi_arch) + span = trace.get_current_span() + span.set_attribute("mck.image.image_name", image_name) + span.set_attribute("mck.image.version", version) + span.set_attribute("mck.image.is_release", config.is_release_step_executed()) + span.set_attribute("mck.image.is_multi_arch", is_multi_arch) - if config.is_release_step_executed() and version and QUAY_REGISTRY_URL in registry: - logger.info( - f"finished building context images, releasing them now via daily builds process for" - f" image: {image_name} and version: {version}!" - ) - if is_run_in_parallel: - time.sleep(random.uniform(0, 5)) - build_image_daily(image_name, version, version)(config) + if config.is_release_step_executed() and version and QUAY_REGISTRY_URL in registry: + logger.info( + f"finished building context images, releasing them now via daily builds process for" + f" image: {image_name} and version: {version}!" + ) + if is_run_in_parallel: + time.sleep(random.uniform(0, 5)) + build_image_daily(image_name, version, version)(config) except Exception as e: logger.error(f"Error during build_image_generic for image {image_name}: {e}") From 46c40763510260d7e7ddfff0db8eae2bc8fe1b0c Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Tue, 5 Aug 2025 16:53:01 +0200 Subject: [PATCH 41/49] fix merge --- go.mod | 4 -- go.sum | 70 +++++++++--------- inventories/agent.yaml | 114 ++++++++++++++++-------------- inventories/agent_non_matrix.yaml | 64 ----------------- pipeline.py | 2 +- 5 files changed, 97 insertions(+), 157 deletions(-) delete mode 100644 inventories/agent_non_matrix.yaml diff --git a/go.mod b/go.mod index e3fb11adf..c166d8d9a 100644 --- a/go.mod +++ b/go.mod @@ -13,8 +13,6 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.8 github.com/hashicorp/vault/api v1.20.0 github.com/imdario/mergo v0.3.15 - github.com/onsi/ginkgo/v2 v2.17.1 - github.com/onsi/gomega v1.32.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.22.0 github.com/r3labs/diff/v3 v3.0.1 @@ -62,7 +60,6 @@ require ( github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -70,7 +67,6 @@ require ( github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect diff --git a/go.sum b/go.sum index 9ef0404ec..cb2a27f2f 100644 --- a/go.sum +++ b/go.sum @@ -10,9 +10,6 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -38,9 +35,9 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= @@ -57,6 +54,8 @@ github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= +github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -91,6 +90,7 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= @@ -102,8 +102,7 @@ github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVH github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= -github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= @@ -114,16 +113,14 @@ github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9 github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= -github.com/hashicorp/vault/api v1.16.0 h1:nbEYGJiAPGzT9U4oWgaaB0g+Rj8E59QuHKyA5LhwQN4= -github.com/hashicorp/vault/api v1.16.0/go.mod h1:KhuUhzOD8lDSk29AtzNjgAu2kxRA9jL9NAbkFlqvkBA= +github.com/hashicorp/vault/api v1.20.0 h1:KQMHElgudOsr+IbJgmbjHnCTxEpKs9LnozA1D3nozU4= github.com/hashicorp/vault/api v1.20.0/go.mod h1:GZ4pcjfzoOWpkJ3ijHNpEoAxKEsBJnVljyTe3jM2Sms= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -199,17 +196,17 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/r3labs/diff/v3 v3.0.1 h1:CBKqf3XmNRHXKmdU7mZP1w7TV0pDyVCis1AUHtA4Xtg= github.com/r3labs/diff/v3 v3.0.1/go.mod h1:f1S9bourRbiM66NskseyUdo0fTmEE0qKrikYJX63dgo= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= -github.com/spf13/cast v1.8.0 h1:gEN9K4b8Xws4EX0+a0reLmhq8moKn7ntRlQYgjPeCDk= -github.com/spf13/cast v1.8.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -253,16 +250,23 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mongodb.org/atlas v0.38.0 h1:zfwymq20GqivGwxPZfypfUDry+WwMGVui97z1d8V4bU= go.mongodb.org/atlas v0.38.0/go.mod h1:DJYtM+vsEpPEMSkQzJnFHrT0sP7ev6cseZc/GGjJYG8= -go.mongodb.org/mongo-driver v1.17.3 h1:TQyXhnsWfWtgAhMtOgtYHMTkZIfBTpMTsMnd9ZBeHxQ= -go.mongodb.org/mongo-driver v1.17.3/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= @@ -270,21 +274,22 @@ 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= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= +go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= -golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -294,8 +299,7 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= @@ -304,8 +308,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -314,7 +317,6 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -332,8 +334,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= -golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -343,8 +344,7 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -354,8 +354,13 @@ golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSm golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g= +google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8= +google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw= google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -409,6 +414,5 @@ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMm sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/inventories/agent.yaml b/inventories/agent.yaml index 42f5eaa21..bcb2d5889 100644 --- a/inventories/agent.yaml +++ b/inventories/agent.yaml @@ -3,58 +3,62 @@ vars: s3_bucket: s3://enterprise-operator-dockerfiles/dockerfiles/mongodb-agent images: -- name: mongodb-agent - vars: - context: . - template_context: docker/mongodb-agent - platform: linux/amd64 - - stages: - - name: mongodb-agent-build-context - task_type: docker_build - dockerfile: docker/mongodb-agent/Dockerfile.builder - buildargs: - mongodb_tools_url_ubi: $(inputs.params.mongodb_tools_url_ubi) - mongodb_agent_url_ubi: $(inputs.params.mongodb_agent_url_ubi) - init_database_image: $(inputs.params.init_database_image) - output: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version)-context - - - name: mongodb-agent-build-context-release - task_type: docker_build - tags: ["release"] - dockerfile: docker/mongodb-agent/Dockerfile.builder - buildargs: - mongodb_tools_url_ubi: $(inputs.params.mongodb_tools_url_ubi) - mongodb_agent_url_ubi: $(inputs.params.mongodb_agent_url_ubi) - init_database_image: $(inputs.params.init_database_image) - output: - - registry: $(inputs.params.quay_registry) - tag: $(inputs.params.version)-context - - - name: mongodb-agent-build-ubi - task_type: docker_build - buildargs: - imagebase: $(inputs.params.registry)/mongodb-agent-ubi:$(inputs.params.version)-context - version: $(inputs.params.version) - dockerfile: docker/mongodb-agent/Dockerfile.old - output: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version) - - - name: master-latest - task_type: tag_image - tags: [ "master" ] - source: - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version) - destination: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.agent_version)_latest - - - name: mongodb-agent-template-ubi - task_type: dockerfile_template - tags: ["release"] - output: - - dockerfile: $(inputs.params.s3_bucket)/$(inputs.params.version)/ubi/Dockerfile + - name: mongodb-agent + vars: + context: . + template_context: docker/mongodb-agent + + platform: linux/$(inputs.params.architecture) + stages: + - name: mongodb-agent-context + task_type: docker_build + dockerfile: docker/mongodb-agent/Dockerfile.builder + tags: [ "ubi" ] + buildargs: + agent_version: $(inputs.params.version) + tools_version: $(inputs.params.tools_version) + agent_distro: $(inputs.params.agent_distro) + tools_distro: $(inputs.params.tools_distro) + + labels: + quay.expires-after: 48h + + output: + - registry: $(inputs.params.registry)/mongodb-agent-ubi + tag: $(inputs.params.version)-context-$(inputs.params.architecture) + + - name: mongodb-agent-build-context-release + task_type: docker_build + tags: ["release"] + dockerfile: docker/mongodb-agent/Dockerfile.builder + buildargs: + agent_version: $(inputs.params.version) + tools_version: $(inputs.params.tools_version) + agent_distro: $(inputs.params.agent_distro) + tools_distro: $(inputs.params.tools_distro) + output: + - registry: $(inputs.params.quay_registry) + tag: $(inputs.params.version)-context-$(inputs.params.architecture) + + - name: mongodb-agent-build + task_type: docker_build + tags: [ "ubi" ] + buildargs: + imagebase: $(inputs.params.registry)/mongodb-agent-ubi:$(inputs.params.version)-context-$(inputs.params.architecture) + version: $(inputs.params.version) + dockerfile: docker/mongodb-agent/Dockerfile.old + + labels: + quay.expires-after: 48h + + output: + - registry: $(inputs.params.registry)/mongodb-agent-ubi + tag: $(inputs.params.version)-$(inputs.params.architecture) + - registry: $(inputs.params.registry)/mongodb-agent-ubi + tag: latest-$(inputs.params.architecture) + + - name: mongodb-agent-template-ubi + task_type: dockerfile_template + tags: ["release"] + output: + - dockerfile: $(inputs.params.s3_bucket)/$(inputs.params.version)/ubi/Dockerfile diff --git a/inventories/agent_non_matrix.yaml b/inventories/agent_non_matrix.yaml deleted file mode 100644 index 08531d9ed..000000000 --- a/inventories/agent_non_matrix.yaml +++ /dev/null @@ -1,64 +0,0 @@ -vars: - quay_registry: quay.io/mongodb/mongodb-agent-ubi - s3_bucket: s3://enterprise-operator-dockerfiles/dockerfiles/mongodb-agent - -images: - - name: mongodb-agent - vars: - context: . - template_context: docker/mongodb-agent-non-matrix - - platform: linux/$(inputs.params.architecture) - stages: - - name: mongodb-agent-context - task_type: docker_build - dockerfile: docker/mongodb-agent-non-matrix/Dockerfile.builder - tags: [ "ubi" ] - buildargs: - agent_version: $(inputs.params.version) - tools_version: $(inputs.params.tools_version) - agent_distro: $(inputs.params.agent_distro) - tools_distro: $(inputs.params.tools_distro) - - labels: - quay.expires-after: 48h - - output: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version)-context-$(inputs.params.architecture) - - - name: mongodb-agent-build-context-release - task_type: docker_build - tags: ["release"] - dockerfile: docker/mongodb-agent-non-matrix/Dockerfile.builder - buildargs: - agent_version: $(inputs.params.version) - tools_version: $(inputs.params.tools_version) - agent_distro: $(inputs.params.agent_distro) - tools_distro: $(inputs.params.tools_distro) - output: - - registry: $(inputs.params.quay_registry) - tag: $(inputs.params.version)-context-$(inputs.params.architecture) - - - name: mongodb-agent-build - task_type: docker_build - tags: [ "ubi" ] - buildargs: - imagebase: $(inputs.params.registry)/mongodb-agent-ubi:$(inputs.params.version)-context-$(inputs.params.architecture) - version: $(inputs.params.version) - dockerfile: docker/mongodb-agent-non-matrix/Dockerfile.old - - labels: - quay.expires-after: 48h - - output: - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: $(inputs.params.version)-$(inputs.params.architecture) - - registry: $(inputs.params.registry)/mongodb-agent-ubi - tag: latest-$(inputs.params.architecture) - - - name: mongodb-agent-template-ubi - task_type: dockerfile_template - tags: ["release"] - output: - - dockerfile: $(inputs.params.s3_bucket)/$(inputs.params.version)/ubi/Dockerfile diff --git a/pipeline.py b/pipeline.py index 2aac7fe40..7723c4dd0 100755 --- a/pipeline.py +++ b/pipeline.py @@ -1233,7 +1233,7 @@ def build_multi_arch_agent_in_sonar( build_image_generic( config=build_configuration, - image_name="mongodb-agent-ubi", + image_name="mongodb-agent", inventory_file="inventories/agent.yaml", multi_arch_args_list=joined_args, with_image_base=False, From 2d1d9150657990afdc391a30d76aaba822fd6fef Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Tue, 5 Aug 2025 17:16:42 +0200 Subject: [PATCH 42/49] fix merge --- docker/mongodb-agent/Dockerfile | 53 ++++++++--------------------- docker/mongodb-agent/Dockerfile.old | 47 ++++++++++++------------- 2 files changed, 38 insertions(+), 62 deletions(-) diff --git a/docker/mongodb-agent/Dockerfile b/docker/mongodb-agent/Dockerfile index a843f3bc7..cd5eccf08 100644 --- a/docker/mongodb-agent/Dockerfile +++ b/docker/mongodb-agent/Dockerfile @@ -1,40 +1,19 @@ -# the init database image gets supplied by pipeline.py and corresponds to the operator version we want to release -# the agent with. This enables us to release the agent for older operator. -ARG init_database_image -FROM ${init_database_image} AS init_database - -FROM public.ecr.aws/docker/library/golang:1.24 AS dependency_downloader - -WORKDIR /go/src/github.com/mongodb/mongodb-kubernetes/ - -COPY go.mod go.sum ./ - -RUN go mod download - -FROM public.ecr.aws/docker/library/golang:1.24 AS readiness_builder - -WORKDIR /go/src/github.com/mongodb/mongodb-kubernetes/ - -COPY --from=dependency_downloader /go/pkg /go/pkg -COPY . /go/src/github.com/mongodb/mongodb-kubernetes - -RUN CGO_ENABLED=0 GOFLAGS=-buildvcs=false go build -o /readinessprobe ./mongodb-community-operator/cmd/readiness/main.go -RUN CGO_ENABLED=0 GOFLAGS=-buildvcs=false go build -o /version-upgrade-hook ./mongodb-community-operator/cmd/versionhook/main.go - FROM scratch AS base -ARG mongodb_tools_url_ubi -ARG mongodb_agent_url_ubi -COPY --from=readiness_builder /readinessprobe /data/ -COPY --from=readiness_builder /version-upgrade-hook /data/ +ARG agent_version +ARG agent_distro +ARG tools_version +ARG tools_distro -ADD ${mongodb_tools_url_ubi} /data/mongodb_tools_ubi.tgz -ADD ${mongodb_agent_url_ubi} /data/mongodb_agent_ubi.tgz +ADD https://mciuploads.s3.amazonaws.com/mms-automation/mongodb-mms-build-agent/builds/automation-agent/prod/mongodb-mms-automation-agent-${agent_version}.${agent_distro}.tar.gz /data/mongodb-agent.tar.gz +ADD https://downloads.mongodb.org/tools/db/mongodb-database-tools-${tools_distro}-${tools_version}.tgz /data/mongodb-tools.tgz -COPY --from=init_database /probes/probe.sh /data/probe.sh -COPY --from=init_database /scripts/agent-launcher-lib.sh /data/ -COPY --from=init_database /scripts/agent-launcher.sh /data/ -COPY --from=init_database /licenses/LICENSE /data/ +COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE +COPY ./docker/mongodb-kubernetes-init-database/content/LICENSE /data/LICENSE +COPY ./docker/mongodb-agent/agent-launcher-shim.sh /opt/scripts/agent-launcher-shim.sh +COPY ./docker/mongodb-agent/setup-agent-files.sh /opt/scripts/setup-agent-files.sh +COPY ./docker/mongodb-agent/dummy-probe.sh /opt/scripts/dummy-probe.sh +COPY ./docker/mongodb-agent/dummy-readinessprobe.sh /opt/scripts/dummy-readinessprobe.sh FROM registry.access.redhat.com/ubi9/ubi-minimal @@ -76,21 +55,17 @@ RUN mkdir -p /agent \ && touch /var/log/mongodb-mms-automation/readiness.log \ && chmod ugo+rw /var/log/mongodb-mms-automation/readiness.log -RUN mkdir -p /opt/scripts COPY --from=base /data/mongodb-agent.tar.gz /agent COPY --from=base /data/mongodb-tools.tgz /agent COPY --from=base /data/LICENSE /licenses/LICENSE + +# Copy scripts to a safe location that won't be overwritten by volume mount COPY --from=base /opt/scripts/agent-launcher-shim.sh /usr/local/bin/agent-launcher-shim.sh COPY --from=base /opt/scripts/setup-agent-files.sh /usr/local/bin/setup-agent-files.sh - -# Copy dummy probe scripts to a safe location that won't be overwritten by volume mount COPY --from=base /opt/scripts/dummy-probe.sh /usr/local/bin/dummy-probe.sh COPY --from=base /opt/scripts/dummy-readinessprobe.sh /usr/local/bin/dummy-readinessprobe -# Make all scripts executable -RUN chmod +x /usr/local/bin/agent-launcher-shim.sh /usr/local/bin/dummy-probe.sh /usr/local/bin/dummy-readinessprobe - RUN tar xfz /agent/mongodb-agent.tar.gz \ && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ && chmod +x /agent/mongodb-agent \ diff --git a/docker/mongodb-agent/Dockerfile.old b/docker/mongodb-agent/Dockerfile.old index 08d8746d8..80d5c8da6 100644 --- a/docker/mongodb-agent/Dockerfile.old +++ b/docker/mongodb-agent/Dockerfile.old @@ -13,13 +13,6 @@ LABEL name="MongoDB Agent" \ release="1" \ maintainer="support@mongodb.com" -COPY --from=base /data/probe.sh /opt/scripts/probe.sh -COPY --from=base /data/readinessprobe /opt/scripts/readinessprobe -COPY --from=base /data/version-upgrade-hook /opt/scripts/version-upgrade-hook -COPY --from=base /data/agent-launcher-lib.sh /opt/scripts/agent-launcher-lib.sh -COPY --from=base /data/agent-launcher.sh /opt/scripts/agent-launcher.sh -COPY --from=base /data/LICENSE /licenses/LICENSE - # Replace libcurl-minimal and curl-minimal with the full versions # https://bugzilla.redhat.com/show_bug.cgi?id=1994521 RUN microdnf install -y libssh libpsl libbrotli \ @@ -40,25 +33,33 @@ RUN microdnf install -y --disableplugin=subscription-manager \ && microdnf upgrade -y \ && rm -rf /var/lib/apt/lists/* +RUN mkdir -p /agent \ + && mkdir -p /var/lib/mongodb-mms-automation \ + && mkdir -p /var/log/mongodb-mms-automation/ \ + && chmod -R +wr /var/log/mongodb-mms-automation/ \ + # ensure that the agent user can write the logs in OpenShift + && touch /var/log/mongodb-mms-automation/readiness.log \ + && chmod ugo+rw /var/log/mongodb-mms-automation/readiness.log -COPY --from=base /data/mongodb_tools_ubi.tgz /tools/mongodb_tools.tgz -COPY --from=base /data/mongodb_agent_ubi.tgz /agent/mongodb_agent.tgz +COPY --from=base /data/mongodb-agent.tar.gz /agent +COPY --from=base /data/mongodb-tools.tgz /agent +COPY --from=base /data/LICENSE /licenses/LICENSE -RUN tar xfz /tools/mongodb_tools.tgz -RUN mv mongodb-database-tools-*/bin/* /tools -RUN chmod +x /tools/* -RUN rm /tools/mongodb_tools.tgz -RUN rm -rf /mongodb-database-tools-* +# Copy scripts to a safe location that won't be overwritten by volume mount +COPY --from=base /opt/scripts/agent-launcher-shim.sh /usr/local/bin/agent-launcher-shim.sh +COPY --from=base /opt/scripts/setup-agent-files.sh /usr/local/bin/setup-agent-files.sh +COPY --from=base /opt/scripts/dummy-probe.sh /usr/local/bin/dummy-probe.sh +COPY --from=base /opt/scripts/dummy-readinessprobe.sh /usr/local/bin/dummy-readinessprobe -RUN tar xfz /agent/mongodb_agent.tgz -RUN mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent -RUN chmod +x /agent/mongodb-agent -RUN rm /agent/mongodb_agent.tgz -RUN rm -rf mongodb-mms-automation-agent-* +RUN tar xfz /agent/mongodb-agent.tar.gz \ + && mv mongodb-mms-automation-agent-*/mongodb-mms-automation-agent /agent/mongodb-agent \ + && chmod +x /agent/mongodb-agent \ + && mkdir -p /var/lib/automation/config \ + && chmod -R +r /var/lib/automation/config \ + && rm /agent/mongodb-agent.tar.gz \ + && rm -r mongodb-mms-automation-agent-* -RUN mkdir -p /var/lib/automation/config -RUN chmod -R +r /var/lib/automation/config +RUN tar xfz /agent/mongodb-tools.tgz --directory /var/lib/mongodb-mms-automation/ && rm /agent/mongodb-tools.tgz USER 2000 - -HEALTHCHECK --timeout=30s CMD ls /opt/scripts/readinessprobe || exit 1 +CMD ["/agent/mongodb-agent", "-cluster=/var/lib/automation/config/automation-config.json"] From b926669cacb7e5081aefe8dac6a0ffbb9db68d48 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Tue, 5 Aug 2025 17:28:52 +0200 Subject: [PATCH 43/49] fix merge --- inventories/agent.yaml | 2 +- pipeline.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/inventories/agent.yaml b/inventories/agent.yaml index bcb2d5889..876e4027b 100644 --- a/inventories/agent.yaml +++ b/inventories/agent.yaml @@ -3,7 +3,7 @@ vars: s3_bucket: s3://enterprise-operator-dockerfiles/dockerfiles/mongodb-agent images: - - name: mongodb-agent + - name: mongodb-agent-ubi vars: context: . template_context: docker/mongodb-agent diff --git a/pipeline.py b/pipeline.py index 7723c4dd0..2aac7fe40 100755 --- a/pipeline.py +++ b/pipeline.py @@ -1233,7 +1233,7 @@ def build_multi_arch_agent_in_sonar( build_image_generic( config=build_configuration, - image_name="mongodb-agent", + image_name="mongodb-agent-ubi", inventory_file="inventories/agent.yaml", multi_arch_args_list=joined_args, with_image_base=False, From 7c8f6e6dfb3685b3403ec699d68ed87031b0617c Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 6 Aug 2025 11:10:44 +0200 Subject: [PATCH 44/49] add release notes and add keyfile for all containers --- ...ing_changing_container_setup_of_static_architecture.md | 8 ++++++++ controllers/operator/construct/appdb_construction.go | 6 ++++++ controllers/operator/construct/database_construction.go | 1 + 3 files changed, 15 insertions(+) create mode 100644 changelog/20250806_breaking_changing_container_setup_of_static_architecture.md diff --git a/changelog/20250806_breaking_changing_container_setup_of_static_architecture.md b/changelog/20250806_breaking_changing_container_setup_of_static_architecture.md new file mode 100644 index 000000000..182601f90 --- /dev/null +++ b/changelog/20250806_breaking_changing_container_setup_of_static_architecture.md @@ -0,0 +1,8 @@ +--- +title: Changing container setup of static architecture +kind: breaking +date: 2025-08-06 +--- + +This change fixes the current complex and difficult-to-maintain architecture for stateful set containers, which relies on an "agent matrix" to map operator and agent versions which led to a sheer amount of images. +We solve this by shifting to a 3-container setup. This new design eliminates the need for the operator-version/agent-version matrix by adding one additional container containing all required binaries. This architecture maps to what we already do with the mongodb-database container. diff --git a/controllers/operator/construct/appdb_construction.go b/controllers/operator/construct/appdb_construction.go index 22cdcaf3d..d6c296db0 100644 --- a/controllers/operator/construct/appdb_construction.go +++ b/controllers/operator/construct/appdb_construction.go @@ -233,6 +233,12 @@ func CAConfigMapName(appDb om.AppDBSpec, log *zap.SugaredLogger) string { // and volumemounts for TLS. func tlsVolumes(appDb om.AppDBSpec, podVars *env.PodEnvVars, log *zap.SugaredLogger) podtemplatespec.Modification { volumesToAdd, volumeMounts := getTLSVolumesAndVolumeMounts(appDb, podVars, log) + + // Add agent API key volume mount if not using vault and monitoring is enabled + if !vault.IsVaultSecretBackend() && ShouldEnableMonitoring(podVars) { + volumeMounts = append(volumeMounts, statefulset.CreateVolumeMount(AgentAPIKeyVolumeName, AgentAPIKeySecretPath)) + } + volumesFunc := func(spec *corev1.PodTemplateSpec) { for _, v := range volumesToAdd { podtemplatespec.WithVolume(v)(spec) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 7aa3ad691..5f8c67f2c 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -494,6 +494,7 @@ func buildDatabaseStatefulSetConfigurationFunction(mdb databaseStatefulSetSource shareProcessNs = func(sts *appsv1.StatefulSet) { sts.Spec.Template.Spec.ShareProcessNamespace = ptr.To(true) } + staticMods = append(staticMods, podtemplatespec.WithContainerByIndex(0, container.WithVolumeMounts(volumeMounts))) staticMods = append(staticMods, podtemplatespec.WithContainerByIndex(1, container.WithVolumeMounts(volumeMounts))) staticMods = append(staticMods, podtemplatespec.WithContainerByIndex(2, container.WithVolumeMounts(volumeMounts))) databaseImage = opts.AgentImage From 7ca0741a41212d53665af33123c96f80629d86fd Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Wed, 6 Aug 2025 13:46:19 +0200 Subject: [PATCH 45/49] fix release notes --- ..._changing_container_setup_of_static_architecture.md | 4 ++-- .../operator/construct/database_construction.go | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/changelog/20250806_breaking_changing_container_setup_of_static_architecture.md b/changelog/20250806_breaking_changing_container_setup_of_static_architecture.md index 182601f90..dfcd789d1 100644 --- a/changelog/20250806_breaking_changing_container_setup_of_static_architecture.md +++ b/changelog/20250806_breaking_changing_container_setup_of_static_architecture.md @@ -4,5 +4,5 @@ kind: breaking date: 2025-08-06 --- -This change fixes the current complex and difficult-to-maintain architecture for stateful set containers, which relies on an "agent matrix" to map operator and agent versions which led to a sheer amount of images. -We solve this by shifting to a 3-container setup. This new design eliminates the need for the operator-version/agent-version matrix by adding one additional container containing all required binaries. This architecture maps to what we already do with the mongodb-database container. +* This change fixes the current complex and difficult-to-maintain architecture for stateful set containers, which relies on an "agent matrix" to map operator and agent versions which led to a sheer amount of images. +* We solve this by shifting to a 3-container setup. This new design eliminates the need for the operator-version/agent-version matrix by adding one additional container containing all required binaries. This architecture maps to what we already do with the mongodb-database container. diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 5f8c67f2c..348922ae3 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -494,9 +494,13 @@ func buildDatabaseStatefulSetConfigurationFunction(mdb databaseStatefulSetSource shareProcessNs = func(sts *appsv1.StatefulSet) { sts.Spec.Template.Spec.ShareProcessNamespace = ptr.To(true) } - staticMods = append(staticMods, podtemplatespec.WithContainerByIndex(0, container.WithVolumeMounts(volumeMounts))) - staticMods = append(staticMods, podtemplatespec.WithContainerByIndex(1, container.WithVolumeMounts(volumeMounts))) - staticMods = append(staticMods, podtemplatespec.WithContainerByIndex(2, container.WithVolumeMounts(volumeMounts))) + // Add volume mounts to all containers in static architecture + // This runs after all containers have been added to the spec + staticMods = append(staticMods, func(spec *corev1.PodTemplateSpec) { + for i := range spec.Spec.Containers { + container.WithVolumeMounts(volumeMounts)(&spec.Spec.Containers[i]) + } + }) databaseImage = opts.AgentImage } else { databaseImage = opts.DatabaseNonStaticImage From 580aea535b93116f3dafac7f792380fc7776d524 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 7 Aug 2025 10:06:58 +0200 Subject: [PATCH 46/49] fix mongod pid handling by redirecting as shared processnamespace doesn't redirect it --- .../construct/database_construction.go | 1 - docker/mongodb-agent/agent-launcher-shim.sh | 4 ++++ .../construct/mongodbstatefulset.go | 22 ++++++++++++++++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/controllers/operator/construct/database_construction.go b/controllers/operator/construct/database_construction.go index 348922ae3..d4ae74ab7 100644 --- a/controllers/operator/construct/database_construction.go +++ b/controllers/operator/construct/database_construction.go @@ -714,7 +714,6 @@ func buildStaticArchitecturePodTemplateSpec(opts DatabaseStatefulSetOptions, mdb mongodContainerModifications := []func(*corev1.Container){container.Apply( container.WithName(util.DatabaseContainerName), - container.WithArgs([]string{"tail -F -n0 \"${MDB_LOG_FILE_MONGODB}\""}), container.WithResourceRequirements(buildRequirementsFromPodSpec(*opts.PodSpec)), container.WithImage(opts.MongodbImage), container.WithEnvs(databaseEnvVars(opts)...), diff --git a/docker/mongodb-agent/agent-launcher-shim.sh b/docker/mongodb-agent/agent-launcher-shim.sh index fda61405b..4d735bad6 100755 --- a/docker/mongodb-agent/agent-launcher-shim.sh +++ b/docker/mongodb-agent/agent-launcher-shim.sh @@ -3,6 +3,9 @@ set -e SCRIPTS_DIR="/opt/scripts" +# Note: Signal handling is now managed by agent-launcher.sh which becomes PID 1 +# after exec. The cleanup function in agent-launcher.sh includes lock file cleanup. + # Function to start the agent launcher start_agent_launcher() { echo "Starting agent launcher..." @@ -11,6 +14,7 @@ start_agent_launcher() { if [[ -f "$SCRIPTS_DIR/agent-launcher.sh" ]]; then echo "Found agent-launcher.sh, executing..." + echo "Note: agent-launcher.sh will become PID 1 and handle all signal processing including cleanup" exec "$SCRIPTS_DIR/agent-launcher.sh" else echo "ERROR: agent-launcher.sh not found" diff --git a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go index 94960ba52..4e94ebbbb 100644 --- a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go +++ b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go @@ -403,6 +403,21 @@ func readinessProbeInit(volumeMount []corev1.VolumeMount, readinessProbeImage st func mongodbContainer(mongodbImage string, volumeMounts []corev1.VolumeMount, additionalMongoDBConfig mdbv1.MongodConfiguration) container.Modification { filePath := additionalMongoDBConfig.GetDBDataDir() + "/" + automationMongodConfFileName mongoDbCommand := fmt.Sprintf(` +# Signal handler for graceful shutdown +cleanup() { + echo "MongoDB container received SIGTERM, shutting down gracefully..." + if [ -n "$MONGOD_PID" ] && kill -0 "$MONGOD_PID" 2>/dev/null; then + echo "Sending SIGTERM to mongod process $MONGOD_PID" + kill -TERM "$MONGOD_PID" + wait "$MONGOD_PID" + echo "mongod process has exited" + fi + exit 0 +} + +# Set up signal handler +trap cleanup SIGTERM + if [ -e "/hooks/version-upgrade" ]; then #run post-start hook to handle version changes (if exists) /hooks/version-upgrade @@ -422,7 +437,12 @@ sleep 15 # start mongod with this configuration echo "Starting mongod..." -exec mongod -f %s; +mongod -f %s & +MONGOD_PID=$! +echo "Started mongod with PID $MONGOD_PID" + +# Wait for mongod to finish +wait "$MONGOD_PID" `, filePath, keyfileFilePath, filePath) containerCommand := []string{ From c7e9fa5a6688eaedbda0b6a8ee38c31011ff7856 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 7 Aug 2025 12:11:34 +0200 Subject: [PATCH 47/49] add static and non static handling, change log file, re-add tests --- ...container_setup_of_static_architecture.md} | 2 +- .../mongodbshardedcluster_controller_test.go | 83 +++++++++++++++++++ lib/sonar/builders/docker.py | 2 +- .../construct/build_statefulset_test.go | 2 +- .../construct/mongodbstatefulset.go | 68 +++++++++++---- .../construct/mongodbstatefulset_test.go | 54 ++++++++++++ 6 files changed, 194 insertions(+), 17 deletions(-) rename changelog/{20250806_breaking_changing_container_setup_of_static_architecture.md => 20250806_other_changing_container_setup_of_static_architecture.md} (97%) diff --git a/changelog/20250806_breaking_changing_container_setup_of_static_architecture.md b/changelog/20250806_other_changing_container_setup_of_static_architecture.md similarity index 97% rename from changelog/20250806_breaking_changing_container_setup_of_static_architecture.md rename to changelog/20250806_other_changing_container_setup_of_static_architecture.md index dfcd789d1..f09d0636b 100644 --- a/changelog/20250806_breaking_changing_container_setup_of_static_architecture.md +++ b/changelog/20250806_other_changing_container_setup_of_static_architecture.md @@ -1,6 +1,6 @@ --- title: Changing container setup of static architecture -kind: breaking +kind: other date: 2025-08-06 --- diff --git a/controllers/operator/mongodbshardedcluster_controller_test.go b/controllers/operator/mongodbshardedcluster_controller_test.go index a4fb3df25..3fc1547e4 100644 --- a/controllers/operator/mongodbshardedcluster_controller_test.go +++ b/controllers/operator/mongodbshardedcluster_controller_test.go @@ -1719,6 +1719,7 @@ func computeSingleClusterShardOverridesFromDistribution(shardOverridesDistributi } type SingleClusterShardedScalingTestCase struct { + name string scalingSteps []SingleClusterShardedScalingStep } @@ -1791,6 +1792,88 @@ func SingleClusterShardedScalingWithOverridesTestCase(t *testing.T, tc SingleClu } } +func TestSingleClusterShardedScalingWithOverrides(t *testing.T) { + scDefaultName := test.SCBuilderDefaultName + "-" + testCases := []SingleClusterShardedScalingTestCase{ + { + name: "Basic sample test", + scalingSteps: []SingleClusterShardedScalingStep{ + { + name: "Initial scaling", + shardCount: 3, + mongodsPerShardCount: 3, + shardOverrides: map[string]int{ + scDefaultName + "0": 5, + }, + expectedShardDistribution: []int{ + 5, + 3, + 3, + }, + }, + { + name: "Scale up mongodsPerShard", + shardCount: 3, + mongodsPerShardCount: 5, + shardOverrides: map[string]int{ + scDefaultName + "0": 5, + }, + expectedShardDistribution: []int{ + 5, + 5, + 5, + }, + }, + }, + }, + { + // This operation works in unit test only + // In e2e tests, the operator is waiting for uncreated hostnames to be ready + name: "Scale overrides up and down", + scalingSteps: []SingleClusterShardedScalingStep{ + { + name: "Initial deployment", + shardCount: 4, + mongodsPerShardCount: 2, + shardOverrides: map[string]int{ + scDefaultName + "0": 3, + scDefaultName + "1": 3, + scDefaultName + "3": 2, + }, + expectedShardDistribution: []int{ + 3, + 3, + 2, // Not overridden + 2, + }, + }, + { + name: "Scale overrides", + shardCount: 4, + mongodsPerShardCount: 2, + shardOverrides: map[string]int{ + scDefaultName + "0": 2, // Scaled down + scDefaultName + "1": 2, // Scaled down + scDefaultName + "3": 3, // Scaled up + }, + expectedShardDistribution: []int{ + 2, // Scaled down + 2, // Scaled down + 2, // Not overridden + 3, // Scaled up + }, + }, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + SingleClusterShardedScalingWithOverridesTestCase(t, tc) + }) + } +} + func generateHostsWithDistributionSingleCluster(stsName string, namespace string, memberCount int, clusterDomain string, externalClusterDomain string) ([]string, []string) { var hosts []string var podNames []string diff --git a/lib/sonar/builders/docker.py b/lib/sonar/builders/docker.py index cff3eff4a..14c2bf91a 100644 --- a/lib/sonar/builders/docker.py +++ b/lib/sonar/builders/docker.py @@ -209,7 +209,7 @@ def inner_docker_push(should_raise=False): # Instead of doing the hack here, we should instead either: # - make sonar aware of context images # - move the logic out of sonar to pipeline.py to all the places where we build context images - if "-context" in tag and image_exists(registry, tag) and "ecr" not in registry: + if "-context" in tag and image_exists(registry, tag): logger.info(f"Image: {tag} in registry: {registry} already exists skipping pushing it") else: logger.info("Image does not exist remotely or is not a context image, pushing it!") diff --git a/mongodb-community-operator/controllers/construct/build_statefulset_test.go b/mongodb-community-operator/controllers/construct/build_statefulset_test.go index 4d032d5bf..c96e18741 100644 --- a/mongodb-community-operator/controllers/construct/build_statefulset_test.go +++ b/mongodb-community-operator/controllers/construct/build_statefulset_test.go @@ -65,7 +65,7 @@ func TestManagedSecurityContext(t *testing.T) { func TestMongod_Container(t *testing.T) { const mongodbImageMock = "fake-mongodbImage" - c := container.New(mongodbContainer(mongodbImageMock, []corev1.VolumeMount{}, mdbv1.NewMongodConfiguration())) + c := container.New(mongodbContainer(mongodbImageMock, []corev1.VolumeMount{}, mdbv1.NewMongodConfiguration(), false)) t.Run("Has correct Env vars", func(t *testing.T) { assert.Len(t, c.Env, 1) diff --git a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go index 4e94ebbbb..e0243e910 100644 --- a/mongodb-community-operator/controllers/construct/mongodbstatefulset.go +++ b/mongodb-community-operator/controllers/construct/mongodbstatefulset.go @@ -244,7 +244,7 @@ func BuildMongoDBReplicaSetStatefulSetModificationFunction(mdb MongoDBStatefulSe podtemplatespec.WithVolume(keyFileVolume), podtemplatespec.WithServiceAccount(mongodbDatabaseServiceAccountName), podtemplatespec.WithContainer(AgentName, mongodbAgentContainer(mdb.AutomationConfigSecretName(), mongodbAgentVolumeMounts, agentLogLevel, agentLogFile, agentMaxLogFileDurationHours, agentImage)), - podtemplatespec.WithContainer(MongodbName, mongodbContainer(mongodbImage, mongodVolumeMounts, mdb.GetMongodConfiguration())), + podtemplatespec.WithContainer(MongodbName, mongodbContainer(mongodbImage, mongodVolumeMounts, mdb.GetMongodConfiguration(), !withInitContainers)), withStaticContainerModification, upgradeInitContainer, readinessInitContainer, @@ -400,24 +400,64 @@ func readinessProbeInit(volumeMount []corev1.VolumeMount, readinessProbeImage st ) } -func mongodbContainer(mongodbImage string, volumeMounts []corev1.VolumeMount, additionalMongoDBConfig mdbv1.MongodConfiguration) container.Modification { - filePath := additionalMongoDBConfig.GetDBDataDir() + "/" + automationMongodConfFileName - mongoDbCommand := fmt.Sprintf(` -# Signal handler for graceful shutdown +// buildSignalHandling returns the signal handling setup for static architecture +func buildSignalHandling() string { + return fmt.Sprintf(` +# Signal handler for graceful shutdown in shared PID namespace cleanup() { + # Important! Keep this in sync with DefaultPodTerminationPeriodSeconds constant from constants.go + termination_timeout_seconds=%d + echo "MongoDB container received SIGTERM, shutting down gracefully..." + if [ -n "$MONGOD_PID" ] && kill -0 "$MONGOD_PID" 2>/dev/null; then echo "Sending SIGTERM to mongod process $MONGOD_PID" - kill -TERM "$MONGOD_PID" - wait "$MONGOD_PID" + kill -15 "$MONGOD_PID" + + echo "Waiting until mongod process is shutdown. Note, that if mongod process fails to shutdown in the time specified by the 'terminationGracePeriodSeconds' property (default ${termination_timeout_seconds} seconds) then the container will be killed by Kubernetes." + + # Use the same robust waiting mechanism as agent-launcher-lib.sh + # We cannot use 'wait' for processes started in background, use spinning loop + while [ -e "/proc/${MONGOD_PID}" ]; do + sleep 0.1 + done + echo "mongod process has exited" fi + + echo "MongoDB container shutdown complete" exit 0 } -# Set up signal handler +# Set up signal handler for static architecture trap cleanup SIGTERM +`, util.DefaultPodTerminationPeriodSeconds) +} + +// buildMongodExecution returns the mongod execution command based on architecture +// in static we run /pause as pid1 and we need to ensure to redirect sigterm to the mongod process +func buildMongodExecution(filePath string, isStatic bool) string { + if isStatic { + return fmt.Sprintf(`mongod -f %s & +MONGOD_PID=$! +echo "Started mongod with PID $MONGOD_PID" +# Wait for mongod to finish +wait "$MONGOD_PID"`, filePath) + } + return fmt.Sprintf("exec mongod -f %s", filePath) +} + +// buildMongodbCommand constructs the complete MongoDB container command +func buildMongodbCommand(filePath string, isStatic bool) string { + signalHandling := "" + if isStatic { + signalHandling = buildSignalHandling() + } + + mongodExec := buildMongodExecution(filePath, isStatic) + + return fmt.Sprintf(`%s if [ -e "/hooks/version-upgrade" ]; then #run post-start hook to handle version changes (if exists) /hooks/version-upgrade @@ -437,13 +477,13 @@ sleep 15 # start mongod with this configuration echo "Starting mongod..." -mongod -f %s & -MONGOD_PID=$! -echo "Started mongod with PID $MONGOD_PID" +%s +`, signalHandling, filePath, keyfileFilePath, mongodExec) +} -# Wait for mongod to finish -wait "$MONGOD_PID" -`, filePath, keyfileFilePath, filePath) +func mongodbContainer(mongodbImage string, volumeMounts []corev1.VolumeMount, additionalMongoDBConfig mdbv1.MongodConfiguration, isStatic bool) container.Modification { + filePath := additionalMongoDBConfig.GetDBDataDir() + "/" + automationMongodConfFileName + mongoDbCommand := buildMongodbCommand(filePath, isStatic) containerCommand := []string{ "/bin/sh", diff --git a/mongodb-community-operator/controllers/construct/mongodbstatefulset_test.go b/mongodb-community-operator/controllers/construct/mongodbstatefulset_test.go index ed93b1ec8..adb2ad9cc 100644 --- a/mongodb-community-operator/controllers/construct/mongodbstatefulset_test.go +++ b/mongodb-community-operator/controllers/construct/mongodbstatefulset_test.go @@ -7,6 +7,7 @@ import ( corev1 "k8s.io/api/core/v1" + mdbv1 "github.com/mongodb/mongodb-kubernetes/mongodb-community-operator/api/v1" "github.com/mongodb/mongodb-kubernetes/mongodb-community-operator/pkg/readiness/config" ) @@ -98,3 +99,56 @@ func TestCollectEnvVars(t *testing.T) { }) } } + +func TestMongodbContainer_SignalHandling(t *testing.T) { + tests := []struct { + name string + isStatic bool + wantExec bool + }{ + { + name: "Non-static architecture uses exec mongod", + isStatic: false, + wantExec: true, + }, + { + name: "Static architecture uses trap and background mongod", + isStatic: true, + wantExec: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mongodConfig := mdbv1.NewMongodConfiguration() + mongodConfig.SetOption("storage.dbPath", "/data") + + containerMod := mongodbContainer("test-image", []corev1.VolumeMount{}, mongodConfig, tt.isStatic) + + testContainer := &corev1.Container{} + containerMod(testContainer) + + assert.Len(t, testContainer.Command, 3) + assert.Equal(t, "/bin/sh", testContainer.Command[0]) + assert.Equal(t, "-c", testContainer.Command[1]) + commandScript := testContainer.Command[2] + + if tt.isStatic { + assert.Contains(t, commandScript, "trap cleanup SIGTERM", "Static architecture should include signal trap") + assert.Contains(t, commandScript, "cleanup() {", "Static architecture should include cleanup function") + assert.Contains(t, commandScript, "mongod -f /data/automation-mongod.conf &", "Static architecture should run mongod in background") + assert.Contains(t, commandScript, "wait \"$MONGOD_PID\"", "Static architecture should wait for mongod process") + assert.Contains(t, commandScript, "termination_timeout_seconds", "Static architecture should include timeout configuration") + assert.Contains(t, commandScript, "while [ -e \"/proc/${MONGOD_PID}\" ]", "Static architecture should include robust process waiting") + assert.Contains(t, commandScript, "kill -15 \"$MONGOD_PID\"", "Static architecture should send SIGTERM to mongod") + } else { + assert.NotContains(t, commandScript, "trap cleanup SIGTERM", "Non-static architecture should not include signal trap") + assert.NotContains(t, commandScript, "cleanup() {", "Non-static architecture should not include cleanup function") + assert.Contains(t, commandScript, "exec mongod -f /data/automation-mongod.conf", "Non-static architecture should exec mongod") + } + + assert.Contains(t, commandScript, "Waiting for config and keyfile files to be created by the agent", "Should wait for agent files") + assert.Contains(t, commandScript, "Starting mongod...", "Should start mongod") + }) + } +} From 0cf761a54ee9abee5b30d87f2b068819a1eab20d Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Thu, 7 Aug 2025 13:49:02 +0200 Subject: [PATCH 48/49] rename file to feature --- ..._feature_changing_container_setup_of_static_architecture.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename changelog/{20250806_other_changing_container_setup_of_static_architecture.md => 20250806_feature_changing_container_setup_of_static_architecture.md} (97%) diff --git a/changelog/20250806_other_changing_container_setup_of_static_architecture.md b/changelog/20250806_feature_changing_container_setup_of_static_architecture.md similarity index 97% rename from changelog/20250806_other_changing_container_setup_of_static_architecture.md rename to changelog/20250806_feature_changing_container_setup_of_static_architecture.md index f09d0636b..e2c27611a 100644 --- a/changelog/20250806_other_changing_container_setup_of_static_architecture.md +++ b/changelog/20250806_feature_changing_container_setup_of_static_architecture.md @@ -1,6 +1,6 @@ --- title: Changing container setup of static architecture -kind: other +kind: feature date: 2025-08-06 --- From 89866b79233745e27ade51dc2d9fd0e73c6124e5 Mon Sep 17 00:00:00 2001 From: Nam Nguyen Date: Fri, 8 Aug 2025 16:07:34 +0200 Subject: [PATCH 49/49] change rn --- ...0806_fix_changing_container_setup_of_static_architecture.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename changelog/{20250806_feature_changing_container_setup_of_static_architecture.md => 20250806_fix_changing_container_setup_of_static_architecture.md} (97%) diff --git a/changelog/20250806_feature_changing_container_setup_of_static_architecture.md b/changelog/20250806_fix_changing_container_setup_of_static_architecture.md similarity index 97% rename from changelog/20250806_feature_changing_container_setup_of_static_architecture.md rename to changelog/20250806_fix_changing_container_setup_of_static_architecture.md index e2c27611a..928a9799b 100644 --- a/changelog/20250806_feature_changing_container_setup_of_static_architecture.md +++ b/changelog/20250806_fix_changing_container_setup_of_static_architecture.md @@ -1,6 +1,6 @@ --- title: Changing container setup of static architecture -kind: feature +kind: fix date: 2025-08-06 ---