Skip to content

Commit 72fa6a7

Browse files
mvsusppengk19
authored andcommitted
change: allow only one integration test run per time (aws#880)
1 parent 6a972d3 commit 72fa6a7

File tree

2 files changed

+124
-1
lines changed

2 files changed

+124
-1
lines changed

buildspec.yml

+7-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ phases:
99
commands:
1010
# run linters
1111
- tox -e flake8,pylint
12-
1312
# run package and docbuild checks
1413
- tox -e twine
1514
- tox -e sphinx
@@ -34,7 +33,14 @@ phases:
3433
# run integration tests
3534
- |
3635
if has-matching-changes "tests/" "src/*.py" "setup.py" "setup.cfg" "buildspec.yml"; then
36+
python3 -u ci-scripts/queue_build.py
3737
IGNORE_COVERAGE=- tox -e py36,py27 -- tests/integ -n 24 --boxed --reruns 2
3838
else
3939
echo "skipping integration tests"
4040
fi
41+
post_build:
42+
finally:
43+
- FILENAME=$(ls ci-lock/)
44+
- ACCOUNT=$(aws sts get-caller-identity --output text | awk '{print $1}')
45+
- S3_BUCKET_DIR=s3://sagemaker-us-west-2-${ACCOUNT}/ci-lock/
46+
- aws s3 rm ${S3_BUCKET_DIR}${FILENAME}

ci-scripts/queue_build.py

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License"). You
4+
# may not use this file except in compliance with the License. A copy of
5+
# the License is located at
6+
#
7+
# http://aws.amazon.com/apache2.0/
8+
#
9+
# or in the "license" file accompanying this file. This file is
10+
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
11+
# ANY KIND, either express or implied. See the License for the specific
12+
# language governing permissions and limitations under the License.
13+
from __future__ import absolute_import
14+
15+
import os
16+
import time
17+
import boto3
18+
19+
account = boto3.client("sts").get_caller_identity()["Account"]
20+
bucket_name = "sagemaker-us-west-2-%s" % account
21+
22+
23+
def queue_build():
24+
build_id = os.environ.get("CODEBUILD_BUILD_ID", "CODEBUILD-BUILD-ID")
25+
source_version = os.environ.get("CODEBUILD_SOURCE_VERSION", "CODEBUILD-SOURCE-VERSION").replace(
26+
"/", "-"
27+
)
28+
ticket_number = int(1000 * time.time())
29+
filename = "%s_%s_%s" % (ticket_number, build_id, source_version)
30+
31+
print("Created queue ticket %s" % ticket_number)
32+
33+
_write_ticket(filename)
34+
files = _list_tickets()
35+
_cleanup_tickets_older_than_8_hours(files)
36+
_wait_for_other_builds(files, ticket_number)
37+
38+
39+
def _build_info_from_file(file):
40+
filename = file.key.split("/")[1]
41+
ticket_number, build_id, source_version = filename.split("_")
42+
return int(ticket_number), build_id, source_version
43+
44+
45+
def _wait_for_other_builds(files, ticket_number):
46+
newfiles = list(filter(lambda file: not _file_older_than(file), files))
47+
sorted_files = list(sorted(newfiles, key=lambda y: y.key))
48+
49+
print("build queue status:")
50+
print()
51+
52+
for order, file in enumerate(sorted_files):
53+
file_ticket_number, build_id, source_version = _build_info_from_file(file)
54+
print(
55+
"%s -> %s %s, ticket number: %s" % (order, build_id, source_version, file_ticket_number)
56+
)
57+
58+
for file in sorted_files:
59+
file_ticket_number, build_id, source_version = _build_info_from_file(file)
60+
61+
if file_ticket_number == ticket_number:
62+
63+
break
64+
else:
65+
while True:
66+
client = boto3.client("codebuild")
67+
response = client.batch_get_builds(ids=[build_id])
68+
build_status = response["builds"][0]["buildStatus"]
69+
70+
if build_status == "IN_PROGRESS":
71+
print(
72+
"waiting on build %s %s %s" % (build_id, source_version, file_ticket_number)
73+
)
74+
time.sleep(30)
75+
else:
76+
print("build %s finished, deleting lock" % build_id)
77+
file.delete()
78+
break
79+
80+
81+
def _cleanup_tickets_older_than_8_hours(files):
82+
oldfiles = list(filter(_file_older_than, files))
83+
for file in oldfiles:
84+
print("object %s older than 8 hours. Deleting" % file.key)
85+
file.delete()
86+
return files
87+
88+
89+
def _list_tickets():
90+
s3 = boto3.resource("s3")
91+
bucket = s3.Bucket(bucket_name)
92+
objects = [file for file in bucket.objects.filter(Prefix="ci-lock/")]
93+
files = list(filter(lambda x: x != "ci-lock/", objects))
94+
return files
95+
96+
97+
def _file_older_than(file):
98+
timelimit = 1000 * 60 * 60 * 8
99+
100+
file_ticket_number, build_id, source_version = _build_info_from_file(file)
101+
102+
return int(time.time()) - file_ticket_number > timelimit
103+
104+
105+
def _write_ticket(ticket_number):
106+
107+
if not os.path.exists("ci-lock"):
108+
os.mkdir("ci-lock")
109+
110+
filename = "ci-lock/" + ticket_number
111+
with open(filename, "w") as file:
112+
file.write(ticket_number)
113+
boto3.Session().resource("s3").Object(bucket_name, filename).upload_file(filename)
114+
115+
116+
if __name__ == "__main__":
117+
queue_build()

0 commit comments

Comments
 (0)