From 1ac04d24a1a09e03517979b7ef74005aee4a6d77 Mon Sep 17 00:00:00 2001 From: Simon Baeumer Date: Mon, 12 May 2025 14:35:15 +0200 Subject: [PATCH 1/7] Add build_tag_id_prefix and deprecate pin_tag_at --- .evergreen-functions.yml | 1 - .evergreen-periodic-builds.yaml | 7 +++++++ .evergreen.yml | 7 +++++++ pipeline.py | 11 ++++++++++- 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.evergreen-functions.yml b/.evergreen-functions.yml index 98a898321..819a1f274 100644 --- a/.evergreen-functions.yml +++ b/.evergreen-functions.yml @@ -29,7 +29,6 @@ variables: - otel_collector_endpoint - otel_parent_id - otel_trace_id - - pin_tag_at - registry - requester - skip_tags diff --git a/.evergreen-periodic-builds.yaml b/.evergreen-periodic-builds.yaml index 1c50a283b..46f67ee48 100644 --- a/.evergreen-periodic-builds.yaml +++ b/.evergreen-periodic-builds.yaml @@ -3,10 +3,17 @@ include: - filename: .evergreen-tasks.yml parameters: + # Deprecated: do not use pin_tag_at parameter, this was used to pin the image tag to a specific time, + # but resulted in overwritten image tags which causes quay to garbage collect + # untagged images. This caused a release image to be missing. - key: pin_tag_at value: 00:00 description: Pin tags at this time of the day. Midnight by default. + - key: build_tag_id_prefix + value: release + description: Prefix for periodic builds for the image. This identifies a periodic build. + variables: - &setup_group setup_group_can_fail_task: true diff --git a/.evergreen.yml b/.evergreen.yml index 78e2fbf80..4fc0a655f 100644 --- a/.evergreen.yml +++ b/.evergreen.yml @@ -180,10 +180,17 @@ parameters: value: "true" description: set this to false to suppress retries on failure + # Deprecated: do not use pin_tag_at parameter, this was used to pin the image tag to a specific time, + # but resulted in overwritten image tags which causes quay to garbage collect + # untagged images. This caused a release image to be missing. - key: pin_tag_at value: 10:00 description: Pin tags at this time of the day. Midnight by default for periodic and 10 for releases. + - key: build_tag_id_prefix + value: release + description: Prefix for release builds for the image. This identifies a release build. + - key: OVERRIDE_VERSION_ID value: "" description: "Patch id to reuse images from other Evergreen build" diff --git a/pipeline.py b/pipeline.py index e9603c37a..31fe0e4a6 100755 --- a/pipeline.py +++ b/pipeline.py @@ -200,6 +200,9 @@ class MissingEnvironmentVariable(Exception): pass +# Deprecated: do not use pin_tag_at parameter, this was used to pin the image tag to a specific time, +# but resulted in overwritten image tags which causes quay to garbage collect +# untagged images. This caused a release image to be missing. def should_pin_at() -> Optional[Tuple[str, str]]: """Gets the value of the pin_tag_at to tag the images with. @@ -239,6 +242,11 @@ def build_id() -> str: """ + try: + build_tag_id_prefix = os.environ["build_tag_id_prefix"] + except KeyError: + pass + date = datetime.now(timezone.utc) try: created_at = os.environ["created_at"] @@ -246,6 +254,7 @@ def build_id() -> str: except KeyError: pass + # Deprecated: do not use should_pin_at(). Use the suffix instead. hour, minute = should_pin_at() if hour and minute: logger.info(f"we are pinning to, hour: {hour}, minute: {minute}") @@ -255,7 +264,7 @@ def build_id() -> str: string_time = date.strftime("%Y%m%dT%H%M%SZ") - return string_time + return f"{build_tag_id_prefix}-{string_time}" def get_release() -> Dict: From c73d831e6469391116192683defe3cf757886b51 Mon Sep 17 00:00:00 2001 From: Simon Baeumer Date: Mon, 12 May 2025 14:50:54 +0200 Subject: [PATCH 2/7] Improve naming and formatting --- .evergreen-functions.yml | 1 + .evergreen-periodic-builds.yaml | 4 ++-- .evergreen.yml | 4 ++-- pipeline.py | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.evergreen-functions.yml b/.evergreen-functions.yml index 819a1f274..74582366e 100644 --- a/.evergreen-functions.yml +++ b/.evergreen-functions.yml @@ -29,6 +29,7 @@ variables: - otel_collector_endpoint - otel_parent_id - otel_trace_id + - build_tag_type - registry - requester - skip_tags diff --git a/.evergreen-periodic-builds.yaml b/.evergreen-periodic-builds.yaml index 46f67ee48..0221c273e 100644 --- a/.evergreen-periodic-builds.yaml +++ b/.evergreen-periodic-builds.yaml @@ -10,9 +10,9 @@ parameters: value: 00:00 description: Pin tags at this time of the day. Midnight by default. - - key: build_tag_id_prefix + - key: build_tag_type value: release - description: Prefix for periodic builds for the image. This identifies a periodic build. + description: The build type, this is added to the image tag. Used for periodic and release builds. variables: - &setup_group diff --git a/.evergreen.yml b/.evergreen.yml index 4fc0a655f..9f87709b2 100644 --- a/.evergreen.yml +++ b/.evergreen.yml @@ -187,9 +187,9 @@ parameters: value: 10:00 description: Pin tags at this time of the day. Midnight by default for periodic and 10 for releases. - - key: build_tag_id_prefix + - key: build_tag_type value: release - description: Prefix for release builds for the image. This identifies a release build. + description: The build type, this is added to the image tag. Used for periodic and release builds. - key: OVERRIDE_VERSION_ID value: "" diff --git a/pipeline.py b/pipeline.py index 31fe0e4a6..c5dac2701 100755 --- a/pipeline.py +++ b/pipeline.py @@ -243,7 +243,7 @@ def build_id() -> str: """ try: - build_tag_id_prefix = os.environ["build_tag_id_prefix"] + build_tag_type = os.environ["build_tag_type"] except KeyError: pass @@ -264,7 +264,7 @@ def build_id() -> str: string_time = date.strftime("%Y%m%dT%H%M%SZ") - return f"{build_tag_id_prefix}-{string_time}" + return f"{string_time}-{build_tag_type}" def get_release() -> Dict: From 46fe845316228622d7814cdba7862351e1189c59 Mon Sep 17 00:00:00 2001 From: Simon Baeumer Date: Mon, 12 May 2025 15:37:44 +0200 Subject: [PATCH 3/7] periodic --- .evergreen-periodic-builds.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen-periodic-builds.yaml b/.evergreen-periodic-builds.yaml index 0221c273e..8f6bcc7cb 100644 --- a/.evergreen-periodic-builds.yaml +++ b/.evergreen-periodic-builds.yaml @@ -11,7 +11,7 @@ parameters: description: Pin tags at this time of the day. Midnight by default. - key: build_tag_type - value: release + value: periodic description: The build type, this is added to the image tag. Used for periodic and release builds. variables: From a151b948b36aa64ccec63b982dede791c77d7afb Mon Sep 17 00:00:00 2001 From: Simon Baeumer Date: Tue, 13 May 2025 10:30:12 +0200 Subject: [PATCH 4/7] Use version_id instead of datetime --- .evergreen-functions.yml | 2 +- .evergreen-periodic-builds.yaml | 7 ---- .evergreen.yml | 7 ---- pipeline.py | 58 +++++---------------------------- pipeline_test.py | 15 +++++++++ 5 files changed, 25 insertions(+), 64 deletions(-) diff --git a/.evergreen-functions.yml b/.evergreen-functions.yml index 74582366e..7d54521db 100644 --- a/.evergreen-functions.yml +++ b/.evergreen-functions.yml @@ -9,6 +9,7 @@ variables: - PKCS11_URI - branch_name - build_id + - build_tag_type - build_variant - distro - e2e_cloud_qa_apikey_owner_ubi_cloudqa @@ -29,7 +30,6 @@ variables: - otel_collector_endpoint - otel_parent_id - otel_trace_id - - build_tag_type - registry - requester - skip_tags diff --git a/.evergreen-periodic-builds.yaml b/.evergreen-periodic-builds.yaml index 8f6bcc7cb..9fa46be77 100644 --- a/.evergreen-periodic-builds.yaml +++ b/.evergreen-periodic-builds.yaml @@ -3,13 +3,6 @@ include: - filename: .evergreen-tasks.yml parameters: - # Deprecated: do not use pin_tag_at parameter, this was used to pin the image tag to a specific time, - # but resulted in overwritten image tags which causes quay to garbage collect - # untagged images. This caused a release image to be missing. - - key: pin_tag_at - value: 00:00 - description: Pin tags at this time of the day. Midnight by default. - - key: build_tag_type value: periodic description: The build type, this is added to the image tag. Used for periodic and release builds. diff --git a/.evergreen.yml b/.evergreen.yml index 9f87709b2..a141e401a 100644 --- a/.evergreen.yml +++ b/.evergreen.yml @@ -180,13 +180,6 @@ parameters: value: "true" description: set this to false to suppress retries on failure - # Deprecated: do not use pin_tag_at parameter, this was used to pin the image tag to a specific time, - # but resulted in overwritten image tags which causes quay to garbage collect - # untagged images. This caused a release image to be missing. - - key: pin_tag_at - value: 10:00 - description: Pin tags at this time of the day. Midnight by default for periodic and 10 for releases. - - key: build_tag_type value: release description: The build type, this is added to the image tag. Used for periodic and release builds. diff --git a/pipeline.py b/pipeline.py index c5dac2701..fdc7e6b86 100755 --- a/pipeline.py +++ b/pipeline.py @@ -199,72 +199,32 @@ def is_running_in_evg_pipeline(): class MissingEnvironmentVariable(Exception): pass - -# Deprecated: do not use pin_tag_at parameter, this was used to pin the image tag to a specific time, -# but resulted in overwritten image tags which causes quay to garbage collect -# untagged images. This caused a release image to be missing. -def should_pin_at() -> Optional[Tuple[str, str]]: - """Gets the value of the pin_tag_at to tag the images with. - - Returns its value split on :. - """ - # We need to return something so `partition` does not raise - # AttributeError - is_patch = is_running_in_patch() - - try: - pinned = os.environ["pin_tag_at"] - except KeyError: - raise MissingEnvironmentVariable(f"pin_tag_at environment variable does not exist, but is required") - if is_patch: - if pinned == "00:00": - raise Exception("Pinning to midnight during a patch is not supported. Please pin to another date!") - - hour, _, minute = pinned.partition(":") - return hour, minute - - def is_running_in_patch(): is_patch = os.environ.get("is_patch") return is_patch is not None and is_patch.lower() == "true" def build_id() -> str: - """Returns the current UTC time in ISO8601 date format. - - If running in Evergreen and `created_at` expansion is defined, use the - datetime defined in that variable instead. - - It is possible to pin this time at midnight (00:00) for periodic builds. If - running a manual build, then the Evergreen `pin_tag_at` variable needs to be - set to the empty string, in which case, the image tag suffix will correspond - to the current timestamp. - + """Returns the build id used for the image tag. + The build id is configurable `build_tag_type` and `version_id` in evergreen. """ + build_tag_type = "" try: build_tag_type = os.environ["build_tag_type"] except KeyError: pass - date = datetime.now(timezone.utc) + version_id = "" try: - created_at = os.environ["created_at"] - date = datetime.strptime(created_at, "%y_%m_%d_%H_%M_%S") + version_id = os.environ["version_id"] except KeyError: - pass + raise MissingEnvironmentVariable("Missing environment variable `version_id`") - # Deprecated: do not use should_pin_at(). Use the suffix instead. - hour, minute = should_pin_at() - if hour and minute: - logger.info(f"we are pinning to, hour: {hour}, minute: {minute}") - date = date.replace(hour=int(hour), minute=int(minute), second=0) + if build_tag_type == "": + return version_id else: - logger.warning(f"hour and minute cannot be extracted from provided pin_tag_at env, pinning to now") - - string_time = date.strftime("%Y%m%dT%H%M%SZ") - - return f"{string_time}-{build_tag_type}" + return f"{version_id}-{build_tag_type}" def get_release() -> Dict: diff --git a/pipeline_test.py b/pipeline_test.py index 671ad105e..4c4a640a0 100644 --- a/pipeline_test.py +++ b/pipeline_test.py @@ -324,3 +324,18 @@ def test_create_and_push_manifest_push_error(mock_run): assert "Error pushing manifest" in str(exc_info.value) assert mock_run.call_count == 2 # Both create and push calls + +def test_build_id(): + from pipeline import build_id + + os.environ["version_id"] = "abcdefg" + os.environ["build_tag_type"] = "release" + id = build_id() + + assert id == "abcdefg-release" + + os.environ["version_id"] = "abcdefg" + os.environ["build_tag_type"] = "" + id = build_id() + + assert id == "abcdefg" From b9ade1c55fde8468a6d6cdb4b5fdef24fcf91e9d Mon Sep 17 00:00:00 2001 From: Simon Baeumer Date: Tue, 13 May 2025 10:43:20 +0200 Subject: [PATCH 5/7] Fix linter --- pipeline.py | 4 ++-- pipeline_test.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/pipeline.py b/pipeline.py index fdc7e6b86..5377ec882 100755 --- a/pipeline.py +++ b/pipeline.py @@ -199,6 +199,7 @@ def is_running_in_evg_pipeline(): class MissingEnvironmentVariable(Exception): pass + def is_running_in_patch(): is_patch = os.environ.get("is_patch") return is_patch is not None and is_patch.lower() == "true" @@ -206,7 +207,7 @@ def is_running_in_patch(): def build_id() -> str: """Returns the build id used for the image tag. - The build id is configurable `build_tag_type` and `version_id` in evergreen. + The build id is configurable `build_tag_type` and `version_id` in evergreen. """ build_tag_type = "" @@ -215,7 +216,6 @@ def build_id() -> str: except KeyError: pass - version_id = "" try: version_id = os.environ["version_id"] except KeyError: diff --git a/pipeline_test.py b/pipeline_test.py index 4c4a640a0..53cf9a540 100644 --- a/pipeline_test.py +++ b/pipeline_test.py @@ -325,6 +325,7 @@ def test_create_and_push_manifest_push_error(mock_run): assert "Error pushing manifest" in str(exc_info.value) assert mock_run.call_count == 2 # Both create and push calls + def test_build_id(): from pipeline import build_id From 03e8ce80e0c85f1d0e9c95fad0d568916b2b0b2b Mon Sep 17 00:00:00 2001 From: Simon Baeumer Date: Thu, 15 May 2025 15:52:59 +0200 Subject: [PATCH 6/7] WIP --- pipeline.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/pipeline.py b/pipeline.py index 5377ec882..92b615180 100755 --- a/pipeline.py +++ b/pipeline.py @@ -713,7 +713,8 @@ def should_skip_arm64(): """ return is_running_in_evg_pipeline() and is_running_in_patch() - +# build_image_daily is always called, it is not only used for daily builds. build_image_generic calls +# build_image_daily for the release and PR builds too. def build_image_daily( image_name: str, # corresponds to the image_name in the release.json min_version: str = None, @@ -774,6 +775,7 @@ def inner(build_configuration: BuildConfiguration): args = args_for_daily_image(image_name) args["build_id"] = build_id() + # TODO: add span for build_id completed_versions = set() @@ -1392,6 +1394,9 @@ def gather_latest_agent_versions(release: Dict) -> List[Tuple[str, str]]: return sorted(list(set(agent_versions_to_build))) +# First a context image is created, a ops-manager-context:v1.33 +# Daily builds exist because to mitigate CVEs as soon as possible and overwrite existing tags. +# Contexts are used by customers without using the operating image. def get_builder_function_for_image_name() -> Dict[str, Callable]: """Returns a dictionary of image names that can be built.""" @@ -1413,7 +1418,8 @@ def get_builder_function_for_image_name() -> Dict[str, Callable]: "init-database": build_init_database, "init-ops-manager": build_init_om_image, # - # Daily builds + # Daily builds re-use context images from non-daily builds. Daily builds are only executed daily, + # all other builds are executed on release, patches and PRs. "operator-daily": build_image_daily("mongodb-kubernetes"), "appdb-daily": build_image_daily("appdb"), "database-daily": build_image_daily("database"), From c3c7e4953af2a5dd102f1d48b44ffd43b28ddbb1 Mon Sep 17 00:00:00 2001 From: Simon Baeumer Date: Fri, 16 May 2025 14:51:25 +0200 Subject: [PATCH 7/7] WIP --- pipeline.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pipeline.py b/pipeline.py index 92b615180..be31748fa 100755 --- a/pipeline.py +++ b/pipeline.py @@ -1394,9 +1394,6 @@ def gather_latest_agent_versions(release: Dict) -> List[Tuple[str, str]]: return sorted(list(set(agent_versions_to_build))) -# First a context image is created, a ops-manager-context:v1.33 -# Daily builds exist because to mitigate CVEs as soon as possible and overwrite existing tags. -# Contexts are used by customers without using the operating image. def get_builder_function_for_image_name() -> Dict[str, Callable]: """Returns a dictionary of image names that can be built.""" @@ -1418,8 +1415,7 @@ def get_builder_function_for_image_name() -> Dict[str, Callable]: "init-database": build_init_database, "init-ops-manager": build_init_om_image, # - # Daily builds re-use context images from non-daily builds. Daily builds are only executed daily, - # all other builds are executed on release, patches and PRs. + # Daily builds "operator-daily": build_image_daily("mongodb-kubernetes"), "appdb-daily": build_image_daily("appdb"), "database-daily": build_image_daily("database"),