Skip to content

Commit 4f09f41

Browse files
Add evergreen function to promote and release kubectl plugin
1 parent 3e6b20b commit 4f09f41

File tree

4 files changed

+227
-0
lines changed

4 files changed

+227
-0
lines changed

.evergreen-functions.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,17 @@ functions:
571571
working_dir: src/github.com/mongodb/mongodb-kubernetes
572572
binary: scripts/dev/run_python.sh scripts/release/kubectl-mongodb/python/build_kubectl_plugin.py
573573

574+
promote_kubectl_plugin_and_release:
575+
- command: subprocess.exec
576+
type: setup
577+
params:
578+
include_expansions_in_env:
579+
- GH_TOKEN
580+
env:
581+
GH_TOKEN: ${GH_TOKEN}
582+
working_dir: src/github.com/mongodb/mongodb-kubernetes
583+
binary: scripts/evergreen/run_python.sh scripts/release/kubectl-mongodb/python/promote_kubectl_plugin.py --release_version ${release_version} --staging_commit ${staging_commit_sha}
584+
574585
build_and_push_appdb_database:
575586
- command: subprocess.exec
576587
params:

.evergreen.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,18 @@ tasks:
394394
image_name: agent
395395
all_agents: "--all-agents"
396396

397+
- name: release_kubectl_plugin
398+
commands:
399+
- func: clone
400+
- func: setup_building_host
401+
- command: github.generate_token
402+
params:
403+
expansion_name: GH_TOKEN
404+
- func: promote_kubectl_plugin_and_release
405+
vars:
406+
release_version: 1.3.3
407+
staging_commit_sha: b29fb4ace63eec7102f8f034fd6c553b5d75c1a1
408+
397409
- name: build_test_image
398410
commands:
399411
- func: clone
@@ -1624,6 +1636,12 @@ buildvariants:
16241636
tasks:
16251637
- name: generate_perf_tasks_30_thread
16261638

1639+
- name: kubectl_plugin_release
1640+
run_on:
1641+
- ubuntu2204-small
1642+
tasks:
1643+
- name: release_kubectl_plugin
1644+
16271645
### Prerequisites for E2E test suite
16281646

16291647
- name: init_test_run

scripts/release/kubectl-mongodb/python/build_kubectl_plugin.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,23 @@ def upload_artifacts_to_s3(s3_bucket: str, version: str):
7272
for root, _, files in os.walk(GORELEASER_DIST_DIR):
7373
for filename in files:
7474
local_path = os.path.join(root, filename)
75+
<<<<<<< HEAD
7576
s3_key = s3_path(local_path, version)
77+
=======
78+
s3_key = s3_path(local_path)
79+
80+
print(f"Uploading artifact {local_path} to s3://{DEV_S3_BUCKET_NAME}/{s3_key}")
81+
>>>>>>> a23bed690 (Add evergreen function to promote and release kubectl plugin)
7682

7783
logger.info(f"Uploading artifact {local_path} to s3://{s3_bucket}/{s3_key}")
7884
try:
85+
<<<<<<< HEAD
7986
s3_client.upload_file(local_path, s3_bucket, s3_key)
8087
logger.info(f"Successfully uploaded the artifact {filename}")
88+
=======
89+
s3_client.upload_file(local_path, DEV_S3_BUCKET_NAME, s3_key)
90+
print(f"Successfully uploaded the artifact {filename}")
91+
>>>>>>> a23bed690 (Add evergreen function to promote and release kubectl plugin)
8192
uploaded_files += 1
8293
except Exception as e:
8394
logger.debug(f"ERROR: Failed to upload file {filename}: {e}")
@@ -86,12 +97,24 @@ def upload_artifacts_to_s3(s3_bucket: str, version: str):
8697
logger.info(f"Successfully uploaded {uploaded_files} kubectl-mongodb plugin artifacts to S3.")
8798

8899

100+
<<<<<<< HEAD
89101
# s3_path returns the path where the artifacts should be uploaded to in S3 object store.
90102
# For dev workflows it's going to be `kubectl-mongodb/{evg-patch-id}/{goreleaser-artifact}`,
91103
# for staging workflows it would be `kubectl-mongodb/{commit-sha}/{goreleaser-artifact}`.
92104
# The `version` string has the correct version (either patch id or commit sha), based on the BuildScenario.
93105
def s3_path(local_path: str, version: str):
94106
return f"{S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{version}/{local_path}"
107+
=======
108+
def s3_path(local_path: str):
109+
commit_sha = os.environ.get(COMMIT_SHA_ENV_VAR, "").strip()
110+
if commit_sha == "":
111+
print(
112+
f"Error: The commit sha environment variable {COMMIT_SHA_ENV_VAR} is not set. It's required to form the S3 Path."
113+
)
114+
sys.exit(1)
115+
116+
return f"{S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{commit_sha}/{local_path}"
117+
>>>>>>> a23bed690 (Add evergreen function to promote and release kubectl plugin)
95118

96119

97120
# download_plugin_for_tests_image downloads just the linux amd64 version of the binary and places it
@@ -103,6 +126,7 @@ def download_plugin_for_tests_image(build_scenario: BuildScenario, s3_bucket: st
103126
logger.debug(f"An error occurred connecting to S3 to download kubectl plugin for tests image: {e}")
104127
return
105128

129+
<<<<<<< HEAD
106130
plugin_path = f"{S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{version}/dist/kubectl-mongodb_linux_amd64_v1/kubectl-mongodb"
107131

108132
logger.info(f"Downloading s3://{s3_bucket}/{plugin_path} to {LOCAL_KUBECTL_PLUGIN_PATH}")
@@ -115,12 +139,31 @@ def download_plugin_for_tests_image(build_scenario: BuildScenario, s3_bucket: st
115139
except ClientError as e:
116140
if e.response["Error"]["Code"] == "404":
117141
logger.debug(f"ERROR: Artifact not found at s3://{s3_bucket}/{plugin_path} ")
142+
=======
143+
commit_sha = os.environ.get(COMMIT_SHA_ENV_VAR, "").strip()
144+
if commit_sha == "":
145+
print("Error: The commit sha environment variable is not set. It's required to form the S3 Path.")
146+
sys.exit(1)
147+
148+
local_file_path = "docker/mongodb-kubernetes-tests/multi-cluster-kube-config-creator_linux"
149+
150+
bucket_path = f"{S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{commit_sha}/dist/kubectl-mongodb_linux_amd64_v1/kubectl-mongodb"
151+
print(f"Downloading s3://{DEV_S3_BUCKET_NAME}/{bucket_path} to {local_file_path}")
152+
153+
try:
154+
s3_client.download_file(DEV_S3_BUCKET_NAME, bucket_path, local_file_path)
155+
print(f"Successfully downloaded artifact to {local_file_path}")
156+
except ClientError as e:
157+
if e.response["Error"]["Code"] == "404":
158+
print(f"ERROR: Artifact not found at s3://{DEV_S3_BUCKET_NAME}/{bucket_path} ")
159+
>>>>>>> a23bed690 (Add evergreen function to promote and release kubectl plugin)
118160
else:
119161
logger.debug(f"ERROR: Failed to download artifact. S3 Client Error: {e}")
120162
except Exception as e:
121163
logger.debug(f"An unexpected error occurred during download: {e}")
122164

123165

166+
124167
def main():
125168
build_scenario = BuildScenario.infer_scenario_from_environment()
126169
kubectl_plugin_build_info = load_build_info(build_scenario).binaries[KUBECTL_PLUGIN_BINARY_NAME]
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import argparse
2+
import os
3+
import sys
4+
import tarfile
5+
6+
import boto3
7+
import build_kubectl_plugin
8+
from botocore.exceptions import ClientError, NoCredentialsError, PartialCredentialsError
9+
from github import Github, GithubException
10+
11+
GITHUB_REPO = "mongodb/mongodb-kubernetes"
12+
GITHUB_TOKEN = os.environ.get("GH_TOKEN")
13+
14+
LOCAL_ARTIFACTS_DIR = "artifacts"
15+
16+
17+
def main():
18+
parser = argparse.ArgumentParser()
19+
parser.add_argument(
20+
"--release_version",
21+
required=True,
22+
help="product release version, ideally should match with github tag/release.",
23+
)
24+
parser.add_argument("--staging_commit", required=True, help="staging commit that we want to promote to release.")
25+
26+
args = parser.parse_args()
27+
download_artifacts_from_s3(args.release_version, args.staging_commit)
28+
arcs = create_tarballs()
29+
# promote to release s3 bucket
30+
print(f"created archives are {arcs}")
31+
upload_assets_to_github_release(arcs, args.release_version)
32+
33+
34+
def s3_artifacts_path_to_local_path(commit_sha: str):
35+
return {
36+
f"{build_kubectl_plugin.S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{commit_sha}/dist/kubectl-mongodb_darwin_amd64_v1/": "kubectl-mongodb_darwin_amd64_v1",
37+
f"{build_kubectl_plugin.S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{commit_sha}/dist/kubectl-mongodb_darwin_arm64/": "kubectl-mongodb_darwin_arm64",
38+
f"{build_kubectl_plugin.S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{commit_sha}/dist/kubectl-mongodb_linux_amd64_v1/": "kubectl-mongodb_linux_amd64_v1",
39+
f"{build_kubectl_plugin.S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{commit_sha}/dist/kubectl-mongodb_linux_arm64/": "kubectl-mongodb_linux_arm64",
40+
}
41+
42+
43+
def download_artifacts_from_s3(release_version: str, commit_sha: str):
44+
print(f"Starting download of artifacts from S3 bucket: {build_kubectl_plugin.DEV_S3_BUCKET_NAME}")
45+
46+
try:
47+
s3_client = boto3.client("s3", region_name=build_kubectl_plugin.AWS_REGION)
48+
except (NoCredentialsError, PartialCredentialsError):
49+
print("ERROR: AWS credentials were not set.")
50+
sys.exit(1)
51+
except Exception as e:
52+
print(f"An error occurred connecting to S3: {e}")
53+
sys.exit(1)
54+
55+
artifacts_to_promote = s3_artifacts_path_to_local_path(commit_sha)
56+
57+
# Create the local temporary directory if it doesn't exist
58+
os.makedirs(LOCAL_ARTIFACTS_DIR, exist_ok=True)
59+
60+
download_count = 0
61+
for s3_artifact_dir, local_subdir in artifacts_to_promote.items():
62+
print(f"Copying from s3://{build_kubectl_plugin.DEV_S3_BUCKET_NAME}/{s3_artifact_dir} to {local_subdir}/")
63+
try:
64+
paginator = s3_client.get_paginator("list_objects_v2")
65+
pages = paginator.paginate(Bucket=build_kubectl_plugin.DEV_S3_BUCKET_NAME, Prefix=s3_artifact_dir)
66+
67+
for page in pages:
68+
if "Contents" not in page:
69+
continue
70+
for obj in page["Contents"]:
71+
s3_key = obj["Key"]
72+
if s3_key.endswith("/"):
73+
continue
74+
75+
# Get the path of the file relative to its S3 prefix, this would mostly be the object name itself
76+
# if s3_artifact_dir doesn't container directories and has just the objects.
77+
relative_path = os.path.relpath(s3_key, s3_artifact_dir)
78+
79+
final_local_path = os.path.join(LOCAL_ARTIFACTS_DIR, local_subdir, relative_path)
80+
81+
# Create the local directory structure if it doesn't exist
82+
os.makedirs(os.path.dirname(final_local_path), exist_ok=True)
83+
84+
print(f"Downloading {s3_key} to {final_local_path}")
85+
s3_client.download_file(build_kubectl_plugin.DEV_S3_BUCKET_NAME, s3_key, final_local_path)
86+
download_count += 1
87+
88+
except ClientError as e:
89+
print(f"ERROR: Failed to list or download from prefix '{s3_artifact_dir}'. S3 Client Error: {e}")
90+
return False
91+
92+
print("All the artifacts have been downloaded successfully.")
93+
return True
94+
95+
96+
def create_tarballs():
97+
print(f"Creating archives for subdirectories in {LOCAL_ARTIFACTS_DIR}")
98+
created_archives = []
99+
original_cwd = os.getcwd()
100+
try:
101+
os.chdir(LOCAL_ARTIFACTS_DIR)
102+
103+
for dir_name in os.listdir("."):
104+
if os.path.isdir(dir_name):
105+
archive_name = f"{dir_name}.tar.gz"
106+
107+
with tarfile.open(archive_name, "w:gz") as tar:
108+
tar.add(dir_name)
109+
110+
full_archive_path = os.path.join(original_cwd, LOCAL_ARTIFACTS_DIR, archive_name)
111+
print(f"Successfully created archive at {full_archive_path}")
112+
created_archives.append(full_archive_path)
113+
114+
except Exception as e:
115+
print(f"ERROR: Failed to create tar.gz archives: {e}")
116+
return []
117+
finally:
118+
os.chdir(original_cwd)
119+
120+
return created_archives
121+
122+
123+
def upload_assets_to_github_release(asset_paths, release_version: str):
124+
if not GITHUB_TOKEN:
125+
print("ERROR: GITHUB_TOKEN environment variable not set.")
126+
sys.exit(1)
127+
128+
try:
129+
g = Github(GITHUB_TOKEN)
130+
repo = g.get_repo(GITHUB_REPO)
131+
except GithubException as e:
132+
print(f"ERROR: Could not connect to GitHub or find repository '{GITHUB_REPO}', Error {e}.")
133+
sys.exit(1)
134+
135+
try:
136+
release = repo.get_release(release_version)
137+
except GithubException as e:
138+
print(
139+
f"ERROR: Could not find release with tag '{release_version}'. Please ensure release exists already. Error: {e}"
140+
)
141+
return
142+
143+
for asset_path in asset_paths:
144+
asset_name = os.path.basename(asset_path)
145+
print(f"Uploading artifact '{asset_name}' to github release as asset")
146+
try:
147+
release.upload_asset(path=asset_path, name=asset_name, content_type="application/gzip")
148+
except GithubException as e:
149+
print(f"ERROR: Failed to upload asset {asset_name}. Error: {e}")
150+
except Exception as e:
151+
print(f"An unexpected error occurred during upload of {asset_name}: {e}")
152+
153+
154+
if __name__ == "__main__":
155+
main()

0 commit comments

Comments
 (0)