Skip to content

Commit a23bed6

Browse files
Add evergreen function to promote and release kubectl plugin
1 parent 54615f9 commit a23bed6

File tree

4 files changed

+198
-9
lines changed

4 files changed

+198
-9
lines changed

.evergreen-functions.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,17 @@ functions:
543543
working_dir: src/github.com/mongodb/mongodb-kubernetes
544544
binary: scripts/evergreen/run_python.sh scripts/release/kubectl-mongodb/python/build_kubectl_plugin.py
545545

546+
promote_kubectl_plugin_and_release:
547+
- command: subprocess.exec
548+
type: setup
549+
params:
550+
include_expansions_in_env:
551+
- GH_TOKEN
552+
env:
553+
GH_TOKEN: ${GH_TOKEN}
554+
working_dir: src/github.com/mongodb/mongodb-kubernetes
555+
binary: scripts/evergreen/run_python.sh scripts/release/kubectl-mongodb/python/promote_kubectl_plugin.py --release_version ${release_version} --staging_commit ${staging_commit_sha}
556+
546557
build_and_push_appdb_database:
547558
- command: subprocess.exec
548559
params:

.evergreen.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,18 @@ tasks:
418418
skip_tags: release
419419
all_agents: true
420420

421+
- name: release_kubectl_plugin
422+
commands:
423+
- func: clone
424+
- func: setup_building_host
425+
- command: github.generate_token
426+
params:
427+
expansion_name: GH_TOKEN
428+
- func: promote_kubectl_plugin_and_release
429+
vars:
430+
release_version: 1.3.3
431+
staging_commit_sha: b29fb4ace63eec7102f8f034fd6c553b5d75c1a1
432+
421433
- name: build_test_image
422434
commands:
423435
- func: clone
@@ -1651,6 +1663,12 @@ buildvariants:
16511663
tasks:
16521664
- name: generate_perf_tasks_30_thread
16531665

1666+
- name: kubectl_plugin_release
1667+
run_on:
1668+
- ubuntu2204-small
1669+
tasks:
1670+
- name: release_kubectl_plugin
1671+
16541672
### Prerequisites for E2E test suite
16551673

16561674
- name: init_test_run

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

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77

88
# from lib.base_logger import logger
99

10-
S3_BUCKET_NAME = "mongodb-kubernetes-dev"
10+
DEV_S3_BUCKET_NAME = "mongodb-kubernetes-dev"
11+
STAGING_S3_BUCKET_NAME = "mongodb-kubernetes-staging"
12+
RELEASE_S3_BUCKET_NAME = "mongodb-kubernetes-release"
13+
1114
AWS_REGION = "eu-north-1"
1215
S3_BUCKET_KUBECTL_PLUGIN_SUBPATH = "kubectl-mongodb"
1316

@@ -62,10 +65,10 @@ def upload_artifacts_to_s3():
6265
local_path = os.path.join(root, filename)
6366
s3_key = s3_path(local_path)
6467

65-
print(f"Uploading artifact {local_path} to s3://{S3_BUCKET_NAME}/{s3_key}")
68+
print(f"Uploading artifact {local_path} to s3://{DEV_S3_BUCKET_NAME}/{s3_key}")
6669

6770
try:
68-
s3_client.upload_file(local_path, S3_BUCKET_NAME, s3_key)
71+
s3_client.upload_file(local_path, DEV_S3_BUCKET_NAME, s3_key)
6972
print(f"Successfully uploaded the artifact {filename}")
7073
uploaded_files += 1
7174
except Exception as e:
@@ -78,7 +81,9 @@ def upload_artifacts_to_s3():
7881
def s3_path(local_path: str):
7982
commit_sha = os.environ.get(COMMIT_SHA_ENV_VAR, "").strip()
8083
if commit_sha == "":
81-
print(f"Error: The commit sha environment variable {COMMIT_SHA_ENV_VAR} is not set. It's required to form the S3 Path.")
84+
print(
85+
f"Error: The commit sha environment variable {COMMIT_SHA_ENV_VAR} is not set. It's required to form the S3 Path."
86+
)
8287
sys.exit(1)
8388

8489
return f"{S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{commit_sha}/{local_path}"
@@ -91,7 +96,6 @@ def download_plugin_for_tests_image():
9196
print(f"An error occurred connecting to S3 to download kubectl plugin for tests image: {e}")
9297
return
9398

94-
9599
commit_sha = os.environ.get(COMMIT_SHA_ENV_VAR, "").strip()
96100
if commit_sha == "":
97101
print("Error: The commit sha environment variable is not set. It's required to form the S3 Path.")
@@ -100,19 +104,20 @@ def download_plugin_for_tests_image():
100104
local_file_path = "docker/mongodb-kubernetes-tests/multi-cluster-kube-config-creator_linux"
101105

102106
bucket_path = f"{S3_BUCKET_KUBECTL_PLUGIN_SUBPATH}/{commit_sha}/dist/kubectl-mongodb_linux_amd64_v1/kubectl-mongodb"
103-
print(f"Downloading s3://{S3_BUCKET_NAME}/{bucket_path} to {local_file_path}")
107+
print(f"Downloading s3://{DEV_S3_BUCKET_NAME}/{bucket_path} to {local_file_path}")
104108

105109
try:
106-
s3_client.download_file(S3_BUCKET_NAME, bucket_path, local_file_path)
110+
s3_client.download_file(DEV_S3_BUCKET_NAME, bucket_path, local_file_path)
107111
print(f"Successfully downloaded artifact to {local_file_path}")
108112
except ClientError as e:
109-
if e.response['Error']['Code'] == '404':
110-
print(f"ERROR: Artifact not found at s3://{S3_BUCKET_NAME}/{bucket_path} ")
113+
if e.response["Error"]["Code"] == "404":
114+
print(f"ERROR: Artifact not found at s3://{DEV_S3_BUCKET_NAME}/{bucket_path} ")
111115
else:
112116
print(f"ERROR: Failed to download artifact. S3 Client Error: {e}")
113117
except Exception as e:
114118
print(f"An unexpected error occurred during download: {e}")
115119

120+
116121
def main():
117122
run_goreleaser()
118123
upload_artifacts_to_s3()
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)