Skip to content

Commit 1b61956

Browse files
Consume build_scenario via build_info for registry repo and other info
1 parent 067b257 commit 1b61956

File tree

7 files changed

+181
-81
lines changed

7 files changed

+181
-81
lines changed

.evergreen-functions.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,8 @@ functions:
227227
working_dir: src/github.com/mongodb/mongodb-kubernetes
228228
add_to_path:
229229
- ${workdir}/bin
230-
binary: scripts/dev/helm_registry_login.sh
230+
- ${PROJECT_DIR}/bin
231+
binary: scripts/dev/run_python.sh scripts/release/helm_registry_login.py
231232

232233
# Logs into all used registries
233234
configure_docker_auth: &configure_docker_auth

.evergreen.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,11 +438,11 @@ tasks:
438438
- name: publish_helm_chart
439439
commands:
440440
- func: clone
441+
- func: python_venv
441442
- func: setup_kubectl
442443
- func: setup_aws
443444
- func: prepare_aws
444445
- func: helm_registry_login
445-
- func: python_venv
446446
- func: publish_helm_chart
447447

448448
- name: prepare_aws

build_info.json

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,15 +345,20 @@
345345
"helm-charts": {
346346
"mongodb-kubernetes": {
347347
"patch": {
348-
"repositories": ["268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/helm-charts"]
348+
"registry": "268558157000.dkr.ecr.us-east-1.amazonaws.com",
349+
"region": "us-east-1",
350+
"repository": "dev/mongodb/helm-charts"
349351
},
350352
"staging": {
351353
"sign": true,
352-
"repositories": ["268558157000.dkr.ecr.us-east-1.amazonaws.com/staging/helm-charts"]
354+
"registry": "268558157000.dkr.ecr.us-east-1.amazonaws.com",
355+
"region": "us-east-1",
356+
"repository": "staging/mongodb/helm-charts"
353357
},
354358
"release": {
355359
"sign": true,
356-
"repositories": ["quay.io/mongodb/helm-charts"]
360+
"registry": "quay.io",
361+
"repository": "mongodb/helm-charts"
357362
}
358363
}
359364
}

scripts/dev/helm_registry_login.sh

Lines changed: 0 additions & 39 deletions
This file was deleted.

scripts/publish_helm_chart.py

Lines changed: 75 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,39 @@
1-
import subprocess
21
import os
2+
import subprocess
3+
import sys
4+
35
import yaml
46

57
from lib.base_logger import logger
8+
from scripts.release.build.build_info import *
69

710
CHART_DIR = "helm_chart"
811

9-
OCI_REGISTRY = "oci://268558157000.dkr.ecr.us-east-1.amazonaws.com/dev/helm-charts"
1012

11-
def run_command(command: list[str], description: str):
13+
def run_command(command: list[str]):
1214
try:
13-
subprocess.run(command, check=True, text=True, capture_output=False)
14-
logger.info(f"Command {' '.join(command)} executed successfully.")
15+
# Using capture_output=True to grab stdout/stderr for better error logging.
16+
process = subprocess.run(command, check=True, text=True, capture_output=True)
17+
logger.info(f"Successfully executed: {' '.join(command)}")
18+
if process.stdout:
19+
logger.info(process.stdout)
1520
except subprocess.CalledProcessError as e:
16-
logger.error(f"Error executing command: {' '.join(command)}")
17-
raise RuntimeError(f"{description} failed.") from e
21+
raise RuntimeError(f"Command {' '.join(command)} failed. Stderr: {e.stderr.strip()}") from e
1822
except FileNotFoundError:
19-
raise FileNotFoundError("Error: 'helm' command not found. Ensure Helm CLI is installed and in your PATH.")
23+
raise FileNotFoundError(f"Error: {command[0]} command not found. Ensure {command[0]} is installed and in your PATH.")
2024

25+
26+
# update_chart_and_get_metadata updates the helm chart's Chart.yaml and sets the version
27+
# to either evg patch id or commit which is set in OPERATOR_VERSION.
2128
def update_chart_and_get_metadata(chart_dir: str) -> tuple[str, str]:
2229
chart_path = os.path.join(chart_dir, "Chart.yaml")
23-
version_id = os.environ.get('version_id')
30+
version_id = os.environ.get("OPERATOR_VERSION")
2431
if not version_id:
25-
raise ValueError("Error: Environment variable 'version_id' must be set to determine the chart version to publish.")
26-
27-
new_version = f"0.0.0+{version_id}"
32+
raise ValueError(
33+
"Error: Environment variable 'OPERATOR_VERSION' must be set to determine the chart version to publish."
34+
)
2835

36+
new_version = f"0.0.0+{version_id}"
2937
logger.info(f"New helm chart version will be: {new_version}")
3038

3139
if not os.path.exists(chart_path):
@@ -35,44 +43,76 @@ def update_chart_and_get_metadata(chart_dir: str) -> tuple[str, str]:
3543
)
3644

3745
try:
38-
with open(chart_path, 'r') as f:
46+
with open(chart_path, "r") as f:
3947
data = yaml.safe_load(f)
4048

41-
chart_name = data.get('name')
49+
chart_name = data.get("name")
4250
if not chart_name:
43-
raise ValueError("Chart.yaml is missing required 'name' field.")
51+
raise ValueError("Chart.yaml is missing required 'name' field.")
4452

45-
data['version'] = new_version
46-
47-
with open(chart_path, 'w') as f:
48-
yaml.safe_dump(data, f, sort_keys=False)
53+
data["version"] = new_version
4954

50-
logger.info(f"Successfully updated version for chart '{chart_name}' to '{new_version}' before publishing it.")
51-
return chart_name, new_version
55+
with open(chart_path, "w") as f:
56+
yaml.safe_dump(data, f, sort_keys=False)
5257

58+
logger.info(f"Successfully updated version for chart '{chart_name}' to '{new_version}'.")
59+
return chart_name, new_version
5360
except Exception as e:
5461
raise RuntimeError(f"Failed to read or update Chart.yaml: {e}")
5562

56-
def publish_helm_chart():
63+
64+
def get_oci_registry(chart_info: HelmChartInfo) -> str:
65+
registry = chart_info.registry
66+
repo = chart_info.repository
67+
68+
if not registry:
69+
raise ValueError("Error: registry doesn't seem to be set in HelmChartInfo.")
70+
71+
if not repo:
72+
raise ValueError("Error: reposiotry doesn't seem to be set in HelmChartInfo.")
73+
74+
75+
oci_registry = f"oci://{registry}/{repo}"
76+
logger.info(f"Determined OCI Registry: {oci_registry}")
77+
return oci_registry
78+
79+
80+
def publish_helm_chart(chart_info: HelmChartInfo):
5781
try:
82+
oci_registry = get_oci_registry(chart_info)
5883
chart_name, chart_version = update_chart_and_get_metadata(CHART_DIR)
59-
6084
tgz_filename = f"{chart_name}-{chart_version}.tgz"
61-
logger.info(f"Packaging chart: {chart_name} with Version: {chart_version}")
6285

63-
package_command = ["helm", "package", CHART_DIR]
64-
run_command(package_command, f"Packaging chart '{CHART_DIR}'")
86+
try:
87+
logger.info(f"Packaging chart: {chart_name} with Version: {chart_version}")
88+
package_command = ["helm", "package", CHART_DIR]
89+
run_command(package_command)
90+
91+
logger.info(f"Pushing chart to registry: {oci_registry}")
92+
push_command = ["helm", "push", tgz_filename, oci_registry]
93+
run_command(push_command)
6594

66-
push_command = ["helm", "push", tgz_filename, OCI_REGISTRY]
67-
run_command(push_command, f"Pushing '{tgz_filename}' to '{OCI_REGISTRY}'")
95+
logger.info(f"Helm Chart {chart_name}:{chart_version} was published successfully!")
96+
finally:
97+
# Cleanup the local .tgz file regardless of push success/failure
98+
if os.path.exists(tgz_filename):
99+
logger.info(f"Cleaning up local file: {tgz_filename}")
100+
os.remove(tgz_filename)
68101

69-
if os.path.exists(tgz_filename):
70-
logger.info(f"\nCleaning up local file: {tgz_filename}")
71-
os.remove(tgz_filename)
72-
73-
logger(f"Helm Chart {chart_name}:{chart_version} was published successfully!")
74102
except (FileNotFoundError, RuntimeError, ValueError) as e:
75-
logger.error(f"\Failed publishing the helm chart: {e}")
103+
raise Exception(f"Failed publishing the helm chart {e}")
104+
105+
106+
def main():
107+
build_scenario = os.environ.get("BUILD_SCENARIO")
108+
build_info = load_build_info(build_scenario)
109+
110+
return publish_helm_chart(build_info.helm_charts["mongodb-kubernetes"])
111+
76112

77113
if __name__ == "__main__":
78-
publish_helm_chart()
114+
try:
115+
main()
116+
except Exception as e:
117+
logger.error(f"Failure in the helm publishing process {e}")
118+
sys.exit(1)

scripts/release/build/build_info.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ class BinaryInfo:
3737

3838
@dataclass
3939
class HelmChartInfo:
40-
repositories: List[str]
40+
repository: str
41+
registry: str
42+
region: str
4143
sign: bool = False
4244

4345

@@ -101,8 +103,10 @@ def load_build_info(scenario: BuildScenario) -> BuildInfo:
101103
continue
102104

103105
helm_charts[name] = HelmChartInfo(
104-
repositories=scenario_data["repositories"],
106+
repository=scenario_data.get("repository"),
105107
sign=scenario_data.get("sign", False),
108+
registry=scenario_data.get("registry"),
109+
region=scenario_data.get("region")
106110
)
107111

108112
return BuildInfo(images=images, binaries=binaries, helm_charts=helm_charts)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import os
2+
import sys
3+
import subprocess
4+
from lib.base_logger import logger
5+
from scripts.release.build.build_info import load_build_info
6+
7+
def helm_registry_login(helm_registry: str, region: str):
8+
logger.info(f"Attempting to log into ECR registry: {helm_registry}, using helm registry login.")
9+
10+
aws_command = [
11+
"aws",
12+
"ecr",
13+
"get-login-password",
14+
"--region",
15+
region
16+
]
17+
18+
# as we can see the password is being provided by stdin, that would mean we will have to
19+
# pipe the aws_command (it figures out the password) into helm_command.
20+
helm_command = [
21+
"helm",
22+
"registry",
23+
"login",
24+
"--username",
25+
"AWS",
26+
"--password-stdin",
27+
helm_registry
28+
]
29+
30+
try:
31+
logger.info("Starting AWS ECR credential retrieval.")
32+
aws_proc = subprocess.Popen(
33+
aws_command,
34+
stdout=subprocess.PIPE,
35+
stderr=subprocess.PIPE,
36+
text=True # Treat input/output as text strings
37+
)
38+
39+
logger.info("Starting Helm registry login.")
40+
helm_proc = subprocess.Popen(
41+
helm_command,
42+
stdin=aws_proc.stdout,
43+
stdout=subprocess.PIPE,
44+
stderr=subprocess.PIPE,
45+
text=True
46+
)
47+
48+
# Close the stdout stream of aws_proc in the parent process
49+
# to prevent resource leakage (only needed if you plan to do more processing)
50+
aws_proc.stdout.close()
51+
52+
# Wait for the Helm command (helm_proc) to finish and capture its output
53+
helm_stdout, helm_stderr = helm_proc.communicate()
54+
55+
# Wait for the AWS process to finish as well
56+
aws_proc.wait()
57+
58+
if aws_proc.returncode != 0:
59+
_, aws_stderr = aws_proc.communicate()
60+
raise Exception(f"aws command to get password failed. Error: {aws_stderr}")
61+
62+
if helm_proc.returncode == 0:
63+
logger.info("Login to helm registry was successful.")
64+
logger.info(helm_stdout.strip())
65+
else:
66+
raise Exception(f"Login to helm registry failed, Exit code: {helm_proc.returncode}, Error: {helm_stderr.strip()}")
67+
68+
except FileNotFoundError as e:
69+
# This catches errors if 'aws' or 'helm' are not in the PATH
70+
raise Exception(f"Command not found. Please ensure '{e.filename}' is installed and in your system's PATH.")
71+
except Exception as e:
72+
raise Exception(f"An unexpected error occurred: {e}.")
73+
74+
75+
def main():
76+
build_scenario = os.environ.get("BUILD_SCENARIO")
77+
build_info = load_build_info(build_scenario)
78+
79+
80+
registry = build_info.helm_charts["mongodb-kubernetes"].registry
81+
region = build_info.helm_charts["mongodb-kubernetes"].region
82+
return helm_registry_login(registry, region)
83+
84+
if __name__ == "__main__":
85+
try:
86+
main()
87+
except Exception as e:
88+
logger.error(f"Failed while logging in to the helm registry. Error: {e}")
89+
sys.exit(1)

0 commit comments

Comments
 (0)