Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rfc30/number #8

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
a559048
formatting: run pre-commit on all files (#2236)
Velfi Jan 20, 2023
4436d9a
Remove old service builder machinery (#2161)
hlbarber Jan 20, 2023
4257a18
Add changelog entry for "Remove old service builder machinery" (#2242)
hlbarber Jan 23, 2023
2f4bc33
Dense maps cannot deserialize null values (#2239)
82marbag Jan 23, 2023
48ce90d
Dense lists cannot deserialize null (#2240)
82marbag Jan 23, 2023
701d294
Update changelog
aws-sdk-rust-ci Jan 24, 2023
d301e65
Add changelog entry about #2200 (#2250)
jjant Jan 25, 2023
ebdf597
Fix `OperationExtensionFuture` poll order (#2247)
hlbarber Jan 25, 2023
31ea931
Bump version to 0.54.1 in `gradle.properties` (#2249)
jjant Jan 25, 2023
0965f12
Update changelog
aws-sdk-rust-ci Jan 25, 2023
41ca31b
Add CI action to test aws-sdk-services (#2251)
rcoh Jan 25, 2023
f7c417c
Newtype FromRequest::Future (#2244)
hlbarber Jan 27, 2023
c217058
Add RFC: Providing fallback credentials on timeout (#2218)
ysaito1001 Jan 27, 2023
e6c3a4b
Replace PR bot's diff tool with one that supports pagination (#2245)
jdisanti Jan 27, 2023
980b5c4
Add fallback_on_interrupt to the ProvideCredentials trait (#2246)
ysaito1001 Jan 27, 2023
7ad342a
Copy non-service integration tests into SDK root tests directory (#2255)
jdisanti Jan 27, 2023
efd1508
Update the event stream section in RFC30 (#2243)
thomas-k-cameron Jan 27, 2023
861d1d8
Python: Support `document` type (#2188)
unexge Jan 30, 2023
c04c6ab
Add `Data limit exceeded` to build image throttle messages (#2260)
jdisanti Jan 30, 2023
392fa2a
Update smoketest models (#2252)
jdisanti Jan 30, 2023
1e9e877
Make minor fixes to the crate claim workflow (#2259)
jdisanti Jan 31, 2023
52cb0fc
Add support for `@uniqueItems` (#2232)
david-perez Feb 1, 2023
7a0bcc2
Update mentions to codegen configuration key in changelog (#2166)
david-perez Feb 1, 2023
d9c0b2e
Change the release flow to use release branches (#2253)
LukeMathWalker Feb 1, 2023
bed7b97
Reduce Docker image rebuilds (#2269)
jdisanti Feb 1, 2023
a6ef078
Remove teams from `publisher` ownership list (#2257)
jdisanti Feb 1, 2023
681d3b3
Add static stability support to IMDS credentials provider (#2258)
ysaito1001 Feb 2, 2023
074464e
Increase build image backoff time and attempts (#2267)
jdisanti Feb 2, 2023
cfd1627
Must set a member in unions (#2241)
82marbag Feb 2, 2023
031ad59
Add `runs-on` (#2273)
LukeMathWalker Feb 2, 2023
bf3575f
Add `runs-on` (#2275)
LukeMathWalker Feb 2, 2023
2a913a7
Fix job trigger. Clarify that short SHAs won't work. (#2278)
LukeMathWalker Feb 2, 2023
36d3116
Clarify what type of reference we are trying to push. (#2279)
LukeMathWalker Feb 2, 2023
097f1ca
Update gradle properties for dry runs as well. (#2280)
LukeMathWalker Feb 2, 2023
2695c7c
Get verbose logging from the branch script. (#2281)
LukeMathWalker Feb 2, 2023
1b87953
Fix trigger for following jobs. (#2282)
LukeMathWalker Feb 2, 2023
344bf3e
Fix action paths. (#2283)
LukeMathWalker Feb 2, 2023
20c4839
We need to checkout in the `smithy-rs` folder because that's an assum…
LukeMathWalker Feb 2, 2023
2682708
Use action-arguments for arguments. (#2285)
LukeMathWalker Feb 2, 2023
649f758
Fix if condition. (#2286)
LukeMathWalker Feb 2, 2023
bdabbf0
Persist the modified gradle.properties outside of the Docker context …
LukeMathWalker Feb 2, 2023
20e12f6
Use larger machines for the slowest CI jobs. (#2263)
LukeMathWalker Feb 2, 2023
27429c8
Fix paths. (#2288)
LukeMathWalker Feb 2, 2023
d9efa6b
Commit if modified (#2289)
LukeMathWalker Feb 2, 2023
3ccb2d7
Set user name and email when committing (#2290)
LukeMathWalker Feb 2, 2023
edb7158
`git push origin` fails if there is nothing to push. (#2291)
LukeMathWalker Feb 2, 2023
6d34454
Use curly braces to group together the commit and push action (#2292)
LukeMathWalker Feb 2, 2023
97daba2
Fix syntax error when grouping commands. (#2293)
LukeMathWalker Feb 2, 2023
9b7c065
[release-branches] Fix the reference that gets checked out (#2294)
LukeMathWalker Feb 2, 2023
ac7fdf2
Fix broken doc link to `tokio_stream::Stream` (#2271)
ysaito1001 Feb 2, 2023
17f9a87
Use docker login when possible (#2265)
rcoh Feb 2, 2023
afa9edb
Simplify `AdHocSection` (#2272)
jdisanti Feb 2, 2023
df5abcf
Fix CI on main and don't acquire Docker login for forks (#2295)
jdisanti Feb 3, 2023
85d8819
Collect more diagnostics. (#2297)
LukeMathWalker Feb 3, 2023
e1991fa
[release-branches] Fix working directory (#2298)
LukeMathWalker Feb 3, 2023
47f6bd8
Clone does not preserve uncommitted changes. This was leading to the …
LukeMathWalker Feb 3, 2023
3ee5d06
Make `OperationExtension` store the absolute shape ID (#2276)
hlbarber Feb 3, 2023
b9b80c3
Retrieve the output from outside the Docker context (#2300)
LukeMathWalker Feb 3, 2023
a06f21b
Fix image tagging in CI on main (#2301)
jdisanti Feb 3, 2023
f8a799d
Fix handling of repeated headers in AWS request canonicalization (#2261)
nipunn1313 Feb 3, 2023
7bf9251
Remove usage of always empty writable in `JsonParserGenerator` (#2192)
david-perez Feb 3, 2023
ca449e2
Merge remote-tracking branch 'origin/main' into unstable-serde-support
jdisanti Feb 3, 2023
d596fe4
fix
thomas-k-cameron Feb 4, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/actions/docker-build/action.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# Use this action to execute the action scripts in tools/ci-build/scripts within the Docker build image.
# Use this action to execute the action scripts in tools/ci-scripts.
name: smithy-rs Docker Build
description: Run Docker build command for smithy-rs
inputs:
# The name of the script in tools/ci-build/scripts to run
# The name of the script in tools/ci-scripts to run
action:
description: What action to run in the Docker build
required: true
Expand Down Expand Up @@ -43,7 +43,7 @@ runs:
# from attempting to download an image from ECR since it will already exist,
# which enables testing build image modifications as part of the pull request.
if [[ -d smithy-rs-base-image ]]; then
IMAGE_TAG="$(./smithy-rs/tools/ci-build/tools-hash)"
IMAGE_TAG="$(./smithy-rs/.github/scripts/docker-image-hash)"
docker load -i smithy-rs-base-image/smithy-rs-base-image
docker tag "smithy-rs-base-image:${IMAGE_TAG}" "smithy-rs-base-image:local"
fi
Expand All @@ -52,7 +52,7 @@ runs:
# or from ECR. We disable building the image from scratch so that any mistakes in the CI
# configuration won't cause each individual action to build its own image, which would
# drastically increase the total CI time. Fail fast!
ALLOW_LOCAL_BUILD=false ./smithy-rs/tools/ci-build/acquire-build-image
ALLOW_LOCAL_BUILD=false ./smithy-rs/.github/scripts/acquire-build-image
# This runs the commands from the matrix strategy
- name: Run ${{ inputs.action }}
shell: bash
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import subprocess
import sys
import time
import unittest
import base64

REMOTE_BASE_IMAGE_NAME = "public.ecr.aws/w0m4q9l7/github-awslabs-smithy-rs-ci"
LOCAL_BASE_IMAGE_NAME = "smithy-rs-base-image"
Expand Down Expand Up @@ -41,33 +42,48 @@ class Platform(Enum):

# Script context
class Context:
def __init__(self, start_path, script_path, tools_path, user_id, image_tag, allow_local_build, github_actions):
def __init__(self, start_path, script_path, tools_path, user_id, image_tag, allow_local_build, github_actions,
encrypted_docker_password, docker_passphrase):
self.start_path = start_path
self.script_path = script_path
self.tools_path = tools_path
self.docker_image_path = tools_path + "/ci-build"
self.user_id = user_id
self.image_tag = image_tag
self.allow_local_build = allow_local_build
self.github_actions = github_actions
self.encrypted_docker_password = encrypted_docker_password
self.docker_passphrase = docker_passphrase

@staticmethod
def default():
start_path = os.path.realpath(os.curdir)
script_path = os.path.dirname(os.path.realpath(__file__))
tools_path = get_cmd_output("git rev-parse --show-toplevel", cwd=script_path)[1] + "/tools"
user_id = get_cmd_output("id -u")[1]
image_tag = get_cmd_output("./ci-build/tools-hash", cwd=tools_path)[1]
image_tag = get_cmd_output("./docker-image-hash", cwd=script_path)[1]
allow_local_build = os.getenv("ALLOW_LOCAL_BUILD") != "false"
github_actions = os.getenv("GITHUB_ACTIONS") == "true"
encrypted_docker_password = os.getenv("ENCRYPTED_DOCKER_PASSWORD") or None
docker_passphrase = os.getenv("DOCKER_LOGIN_TOKEN_PASSPHRASE") or None

print(f"Start path: {start_path}")
print(f"Script path: {script_path}")
print(f"Tools path: {tools_path}")
print(f"User ID: {user_id}")
print(f"Required base image tag: {image_tag}")
print(f"Allow local build: {allow_local_build}")
print(f"Running in GitHub Actions: {github_actions}")
return Context(start_path, script_path, tools_path, user_id, image_tag, allow_local_build, github_actions)
return Context(start_path=start_path, script_path=script_path, tools_path=tools_path, user_id=user_id,
image_tag=image_tag, allow_local_build=allow_local_build, github_actions=github_actions,
encrypted_docker_password=encrypted_docker_password, docker_passphrase=docker_passphrase)


def output_contains_any(stdout, stderr, messages):
for message in messages:
if message in stdout or message in stderr:
return True
return False

# Mockable shell commands
class Shell:
Expand All @@ -83,6 +99,9 @@ class Shell:
(status, _, _) = get_cmd_output(f"docker inspect \"{image_name}:{image_tag}\"", check=False)
return status == 0

def docker_login(self, password):
get_cmd_output("docker login --username AWS --password-stdin public.ecr.aws", input=password.encode('utf-8'))

# Pulls the requested `image_name` with `image_tag`. Returns `DockerPullResult`.
def docker_pull(self, image_name, image_tag):
(status, stdout, stderr) = get_cmd_output(f"docker pull \"{image_name}:{image_tag}\"", check=False)
Expand All @@ -93,30 +112,28 @@ class Shell:
print(stderr)
print("-------------------")

not_found_message = "not found: manifest unknown"
throttle_message = "toomanyrequests: Rate exceeded"
not_found_messages = ["not found: manifest unknown"]
throttle_messages = ["toomanyrequests:"]
retryable_messages = ["net/http: TLS handshake timeout"]
if status == 0:
return DockerPullResult.SUCCESS
elif throttle_message in stdout or throttle_message in stderr:
elif output_contains_any(stdout, stderr, throttle_messages):
return DockerPullResult.ERROR_THROTTLED
elif not_found_message in stdout or not_found_message in stderr:
elif output_contains_any(stdout, stderr, not_found_messages):
return DockerPullResult.NOT_FOUND
else:
for message in retryable_messages:
if message in stdout or message in stderr:
return DockerPullResult.RETRYABLE_ERROR
elif output_contains_any(stdout, stderr, retryable_messages):
return DockerPullResult.RETRYABLE_ERROR
return DockerPullResult.UNKNOWN_ERROR

# Builds the base image with the Dockerfile in `path` and tags with with `image_tag`
def docker_build_base_image(self, image_tag, path):
run(f"docker build -t \"smithy-rs-base-image:{image_tag}\" .", cwd=path)

# Builds the local build image
def docker_build_build_image(self, user_id, script_path):
def docker_build_build_image(self, user_id, docker_image_path):
run(
f"docker build -t smithy-rs-build-image --file add-local-user.dockerfile --build-arg=USER_ID={user_id} .",
cwd=script_path
cwd=docker_image_path
)

# Saves the Docker image named `image_name` with `image_tag` to `output_path`
Expand All @@ -129,10 +146,10 @@ class Shell:


# Pulls a Docker image and retries if it gets throttled
def docker_pull_with_retry(shell, image_name, image_tag, throttle_sleep_time=45, retryable_error_sleep_time=1):
def docker_pull_with_retry(shell, image_name, image_tag, throttle_sleep_time=120, retryable_error_sleep_time=1):
if shell.platform() == Platform.ARM_64:
return DockerPullResult.REMOTE_ARCHITECTURE_MISMATCH
for attempt in range(1, 5):
for attempt in range(1, 6):
announce(f"Attempting to pull remote image {image_name}:{image_tag} (attempt {attempt})...")
result = shell.docker_pull(image_name, image_tag)
if result == DockerPullResult.ERROR_THROTTLED:
Expand All @@ -154,17 +171,39 @@ def run(command, cwd=None):


# Returns (status, output) from a shell command
def get_cmd_output(command, cwd=None, check=True):
def get_cmd_output(command, cwd=None, check=True, **kwargs):
if isinstance(command, str):
command = shlex.split(command)

result = subprocess.run(
shlex.split(command),
command,
capture_output=True,
check=check,
cwd=cwd
check=False,
cwd=cwd,
**kwargs
)
return (result.returncode, result.stdout.decode("utf-8").strip(), result.stderr.decode("utf-8").strip())
stdout = result.stdout.decode("utf-8").strip()
stderr = result.stderr.decode("utf-8").strip()
if check and result.returncode != 0:
raise Exception(f"failed to run '{command}.\n{stdout}\n{stderr}")

return result.returncode, stdout, stderr


def decrypt_and_login(shell, secret, passphrase):
decoded = base64.b64decode(secret, validate=True)
if not passphrase:
raise Exception("a secret was set but no passphrase was set (or it was empty)")
(code, password, err) = get_cmd_output(
["gpg", "--decrypt", "--batch", "--quiet", "--passphrase", passphrase, "--output", "-"],
input=decoded)
shell.docker_login(password)
print("Docker login success!")


def acquire_build_image(context=Context.default(), shell=Shell()):
if context.encrypted_docker_password is not None:
decrypt_and_login(shell, context.encrypted_docker_password, context.docker_passphrase)
# If the image doesn't already exist locally, then look remotely
if not shell.docker_image_exists_locally(LOCAL_BASE_IMAGE_NAME, context.image_tag):
announce("Base image not found locally.")
Expand All @@ -183,7 +222,7 @@ def acquire_build_image(context=Context.default(), shell=Shell()):
return 1

announce("Building a new image locally.")
shell.docker_build_base_image(context.image_tag, context.tools_path)
shell.docker_build_base_image(context.image_tag, context.docker_image_path)

if context.github_actions:
announce("Saving base image for use in later jobs...")
Expand All @@ -200,20 +239,23 @@ def acquire_build_image(context=Context.default(), shell=Shell()):

announce("Creating local build image...")
shell.docker_tag(LOCAL_BASE_IMAGE_NAME, context.image_tag, LOCAL_BASE_IMAGE_NAME, LOCAL_TAG)
shell.docker_build_build_image(context.user_id, context.script_path)
shell.docker_build_build_image(context.user_id, context.docker_image_path)
return 0


class SelfTest(unittest.TestCase):
def test_context(self, allow_local_build=False, github_actions=False):
def test_context(self, github_actions=False, allow_local_build=False, encrypted_docker_password=None,
docker_passphrase=None):
return Context(
start_path="/tmp/test/start-path",
script_path="/tmp/test/script-path",
tools_path="/tmp/test/tools-path",
user_id="123",
image_tag="someimagetag",
encrypted_docker_password=encrypted_docker_password,
docker_passphrase=docker_passphrase,
github_actions=github_actions,
allow_local_build=allow_local_build,
github_actions=github_actions
)

def mock_shell(self):
Expand All @@ -225,6 +267,7 @@ class SelfTest(unittest.TestCase):
shell.docker_pull = MagicMock()
shell.docker_save = MagicMock()
shell.docker_tag = MagicMock()
shell.docker_login = MagicMock()
return shell

def test_retry_architecture_mismatch(self):
Expand All @@ -241,6 +284,13 @@ class SelfTest(unittest.TestCase):
)
)

def test_docker_login(self):
shell = self.mock_shell()
acquire_build_image(self.test_context(
encrypted_docker_password="jA0ECQMCvYU/JxsX3g/70j0BxbLLW8QaFWWb/DqY9gPhTuEN/xdYVxaoDnV6Fha+lAWdT7xN0qZr5DHPBalLfVvvM1SEXRBI8qnfXyGI",
docker_passphrase="secret"), shell)
shell.docker_login.assert_called_with("payload")

def test_retry_immediate_success(self):
shell = self.mock_shell()
shell.docker_pull.side_effect = [DockerPullResult.SUCCESS]
Expand Down Expand Up @@ -368,7 +418,7 @@ class SelfTest(unittest.TestCase):

shell.docker_image_exists_locally.assert_called_once()
shell.docker_tag.assert_called_with(LOCAL_BASE_IMAGE_NAME, "someimagetag", LOCAL_BASE_IMAGE_NAME, LOCAL_TAG)
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/script-path")
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/tools-path/ci-build")

# When:
# - the base image doesn't exist locally
Expand All @@ -385,10 +435,10 @@ class SelfTest(unittest.TestCase):

self.assertEqual(0, acquire_build_image(context, shell))
shell.docker_image_exists_locally.assert_called_once()
shell.docker_build_base_image.assert_called_with("someimagetag", "/tmp/test/tools-path")
shell.docker_build_base_image.assert_called_with("someimagetag", "/tmp/test/tools-path/ci-build")
shell.docker_save.assert_not_called()
shell.docker_tag.assert_called_with(LOCAL_BASE_IMAGE_NAME, "someimagetag", LOCAL_BASE_IMAGE_NAME, LOCAL_TAG)
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/script-path")
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/tools-path/ci-build")

# When:
# - the base image doesn't exist locally
Expand All @@ -405,10 +455,10 @@ class SelfTest(unittest.TestCase):

self.assertEqual(0, acquire_build_image(context, shell))
shell.docker_image_exists_locally.assert_called_once()
shell.docker_build_base_image.assert_called_with("someimagetag", "/tmp/test/tools-path")
shell.docker_build_base_image.assert_called_with("someimagetag", "/tmp/test/tools-path/ci-build")
shell.docker_save.assert_not_called()
shell.docker_tag.assert_called_with(LOCAL_BASE_IMAGE_NAME, "someimagetag", LOCAL_BASE_IMAGE_NAME, LOCAL_TAG)
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/script-path")
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/tools-path/ci-build")

# When:
# - the base image doesn't exist locally
Expand All @@ -425,14 +475,14 @@ class SelfTest(unittest.TestCase):

self.assertEqual(0, acquire_build_image(context, shell))
shell.docker_image_exists_locally.assert_called_once()
shell.docker_build_base_image.assert_called_with("someimagetag", "/tmp/test/tools-path")
shell.docker_build_base_image.assert_called_with("someimagetag", "/tmp/test/tools-path/ci-build")
shell.docker_save.assert_called_with(
LOCAL_BASE_IMAGE_NAME,
"someimagetag",
"/tmp/test/start-path/smithy-rs-base-image"
)
shell.docker_tag.assert_called_with(LOCAL_BASE_IMAGE_NAME, "someimagetag", LOCAL_BASE_IMAGE_NAME, LOCAL_TAG)
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/script-path")
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/tools-path/ci-build")

# When:
# - the base image doesn't exist locally
Expand Down Expand Up @@ -472,7 +522,7 @@ class SelfTest(unittest.TestCase):
call(REMOTE_BASE_IMAGE_NAME, "someimagetag", LOCAL_BASE_IMAGE_NAME, "someimagetag"),
call(LOCAL_BASE_IMAGE_NAME, "someimagetag", LOCAL_BASE_IMAGE_NAME, LOCAL_TAG)
])
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/script-path")
shell.docker_build_build_image.assert_called_with("123", "/tmp/test/tools-path/ci-build")


def main():
Expand Down
File renamed without changes.
Loading