Skip to content

Commit 45ff358

Browse files
committed
Tests done
1 parent 4b3ea7c commit 45ff358

File tree

7 files changed

+466
-34
lines changed

7 files changed

+466
-34
lines changed

python/example_code/ecr/ecr_getting_started.py

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
Shows how to use the AWS SDK for Python (Boto3) with Amazon Elastic Container Registry (Amazon ECR) to perform
88
basic operations.
99
10-
This Boto3 code example requires an IAM Role that has permissions to interact with the Amazon ECR service.
10+
To demonstrate granting permissions with a policy, an AWS Identity and Access Management (IAM) role Amazon Resource Name (ARN)
11+
can be passed as a script argument.
1112
1213
To create an IAM role, see:
1314
@@ -27,7 +28,7 @@
2728

2829
script_dir = os.path.dirname(os.path.abspath(__file__))
2930

30-
# Add relative path to include ecrWrapper.
31+
# Add relative path to include ecr_wrapper.
3132
sys.path.append(os.path.dirname(script_dir))
3233
from ecr_wrapper import ECRWrapper
3334

@@ -71,7 +72,7 @@ def __init__(
7172
self.ecr_wrapper = ecr_wrapper
7273
self.docker_client = docker_client
7374
self.tag = "echo-text"
74-
self.repo_name = "ecr-basics"
75+
self.repository_name = "ecr-basics"
7576
self.docker_image = None
7677
self.full_tag_name = None
7778
self.repository = None
@@ -110,8 +111,8 @@ def run(self, role_arn: str) -> None:
110111
to store, manage, and deploy Docker container images.
111112
"""
112113
)
113-
print(f"Creating a repository named {self.repo_name}")
114-
self.repository = ecr_wrapper.create_repository(self.repo_name)
114+
print(f"Creating a repository named {self.repository_name}")
115+
self.repository = self.ecr_wrapper.create_repository(self.repository_name)
115116
print(f"The ARN of the ECR repository is {self.repository['repositoryArn']}")
116117
repository_uri = self.repository["repositoryUri"]
117118
press_enter_to_continue()
@@ -128,7 +129,7 @@ def run(self, role_arn: str) -> None:
128129
)
129130
print(f"Building a docker image from 'docker_files/Dockerfile'")
130131
self.full_tag_name = f"{repository_uri}:{self.tag}"
131-
self.docker_image = docker_client.images.build(
132+
self.docker_image = self.docker_client.images.build(
132133
path="docker_files", tag=self.full_tag_name
133134
)[0]
134135
self.docker_image.tag(repository=repository_uri, tag=self.tag)
@@ -153,6 +154,7 @@ def run(self, role_arn: str) -> None:
153154
repository.
154155
"""
155156
)
157+
156158
self.grant_role_download_access(role_arn)
157159
print(f"Download access granted to the IAM role ARN {role_arn}")
158160
press_enter_to_continue()
@@ -165,7 +167,8 @@ def run(self, role_arn: str) -> None:
165167
Now we will retrieve the ECR policy to ensure it was successfully set.
166168
"""
167169
)
168-
policy_text = ecr_wrapper.get_repository_policy(self.repo_name)
170+
171+
policy_text = self.ecr_wrapper.get_repository_policy(self.repository_name)
169172
print("Policy Text:")
170173
print(f"{policy_text}")
171174
press_enter_to_continue()
@@ -184,7 +187,8 @@ def run(self, role_arn: str) -> None:
184187
ECR repository, such as pushing, pulling, or managing your Docker images.
185188
"""
186189
)
187-
authorization_token = ecr_wrapper.get_authorization_token()
190+
191+
authorization_token = self.ecr_wrapper.get_authorization_token()
188192
print("Authorization token retrieved.")
189193
press_enter_to_continue()
190194
print_dashes()
@@ -199,7 +203,9 @@ def run(self, role_arn: str) -> None:
199203
correct container image from the ECR repository.
200204
"""
201205
)
202-
repository_descriptions = ecr_wrapper.describe_repositories([self.repo_name])
206+
repository_descriptions = self.ecr_wrapper.describe_repositories(
207+
[self.repository_name]
208+
)
203209
repository_uri = repository_descriptions[0]["repositoryUri"]
204210
print(f"Repository URI found: {repository_uri}")
205211
press_enter_to_continue()
@@ -229,14 +235,12 @@ def run(self, role_arn: str) -> None:
229235
230236
The method uses the authorization token to create an `AuthConfig` object, which is used to authenticate
231237
the Docker client when pushing the image. Finally, the method tags the Docker image with the specified
232-
repository name and image tag, and then pushes the image to the ECR repository using the Docker client.
238+
repository name and image image_tag, and then pushes the image to the ECR repository using the Docker client.
233239
"""
234240
)
235241
decoded_authorization = base64.b64decode(authorization_token).decode("utf-8")
236242
username, password = decoded_authorization.split(":")
237243

238-
print(f"username {username}\n{password}")
239-
240244
resp = self.docker_client.api.push(
241245
repository=repository_uri,
242246
auth_config={"username": username, "password": password},
@@ -250,7 +254,9 @@ def run(self, role_arn: str) -> None:
250254
print_dashes()
251255

252256
print("* Verify if the image is in the ECR Repository.")
253-
image_descriptions = ecr_wrapper.describe_images(self.repo_name, [self.tag])
257+
image_descriptions = self.ecr_wrapper.describe_images(
258+
self.repository_name, [self.tag]
259+
)
254260
if len(image_descriptions) > 0:
255261
print("Image found in ECR Repository.")
256262
else:
@@ -273,7 +279,7 @@ def run(self, role_arn: str) -> None:
273279
274280
2. Describe the image using this command:
275281
276-
aws ecr describe-images --repository-name {self.repo_name} --image-ids imageTag={self.tag}
282+
aws ecr describe-images --repository-name {self.repository_name} --image-ids imageTag={self.tag}
277283
278284
3. Run the Docker container and view the output using this command:
279285
@@ -291,11 +297,11 @@ def cleanup(self, ask: bool):
291297
if self.repository is not None and (
292298
not ask
293299
or q.ask(
294-
f"Would you like to delete the ECR repository '{self.repo_name}? (y/n) "
300+
f"Would you like to delete the ECR repository '{self.repository_name}? (y/n) "
295301
)
296302
):
297-
print(f"Deleting the ECR repository '{self.repo_name}'.")
298-
self.ecr_wrapper.delete_repository(self.repo_name)
303+
print(f"Deleting the ECR repository '{self.repository_name}'.")
304+
self.ecr_wrapper.delete_repository(self.repository_name)
299305

300306
if self.full_tag_name is not None and (
301307
not ask
@@ -325,7 +331,9 @@ def grant_role_download_access(self, role_arn: str):
325331
],
326332
}
327333

328-
self.ecr_wrapper.set_repository_policy(self.repo_name, json.dumps(policy_json))
334+
self.ecr_wrapper.set_repository_policy(
335+
self.repository_name, json.dumps(policy_json)
336+
)
329337

330338
# snippet-end:[python.example_code.ecr.grant_role_download_access]
331339

@@ -350,7 +358,10 @@ def put_expiration_policy(self):
350358
]
351359
}
352360

353-
self.ecr_wrapper.put_lifecycle_policy(self.repo_name, json.dumps(policy_json))
361+
self.ecr_wrapper.put_lifecycle_policy(
362+
self.repository_name, json.dumps(policy_json)
363+
)
364+
354365
# snippet-end:[python.example_code.ecr.put_expiration_policy]
355366

356367

@@ -374,15 +385,15 @@ def put_expiration_policy(self):
374385
no_art = args.no_art
375386
iam_role_arn = args.iam_role_arn
376387
demo = None
377-
docker_client = None
388+
a_docker_client = None
378389
try:
379-
docker_client = docker.from_env()
380-
if not docker_client.ping():
390+
a_docker_client = docker.from_env()
391+
if not a_docker_client.ping():
381392
raise docker.errors.DockerException("Docker is not running.")
382393
except docker.errors.DockerException as err:
383394
logging.error(
384395
"""
385-
The Python Docker could not be created.
396+
The Python Docker client could not be created.
386397
Do you have Docker installed and running?
387398
Here is the error message:
388399
%s
@@ -391,8 +402,8 @@ def put_expiration_policy(self):
391402
)
392403
sys.exit("Error with Docker.")
393404
try:
394-
ecr_wrapper = ECRWrapper.from_client()
395-
demo = ECRGettingStarted(ecr_wrapper, docker_client)
405+
an_ecr_wrapper = ECRWrapper.from_client()
406+
demo = ECRGettingStarted(an_ecr_wrapper, a_docker_client)
396407
demo.run(iam_role_arn)
397408

398409
except Exception as exception:

python/example_code/ecr/ecr_wrapper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def create_repository(self, repository_name: str) -> dict[str, any]:
5252
response = self.ecr_client.describe_repositories(
5353
repositoryNames=[repository_name]
5454
)
55-
return response["repository"]
55+
return self.describe_repositories([repository_name])[0]
5656
else:
5757
logger.error(
5858
"Error creating repository %s. Here's why %s",

python/example_code/ecr/hello/hello_ecr.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import argparse
77
from boto3 import client
88

9-
def hello_ecr(ecr_client : client, repository_name :str) -> None:
9+
10+
def hello_ecr(ecr_client: client, repository_name: str) -> None:
1011
"""
1112
Use the AWS SDK for Python (Boto3) to create an Amazon Elastic Container Registry (Amazon ECR)
1213
client and list the images in a repository.
@@ -17,9 +18,13 @@ def hello_ecr(ecr_client : client, repository_name :str) -> None:
1718
the low-level Amazon ECR service API.
1819
:param repository_name: The name of an Amazon ECR repository in your account.
1920
"""
20-
print(f"Hello, Amazon ECR! Let's list some images in the repository '{repository_name}':\n")
21+
print(
22+
f"Hello, Amazon ECR! Let's list some images in the repository '{repository_name}':\n"
23+
)
2124
paginator = ecr_client.get_paginator("list_images")
22-
page_iterator = paginator.paginate(repositoryName=repository_name, PaginationConfig={"MaxItems": 10})
25+
page_iterator = paginator.paginate(
26+
repositoryName=repository_name, PaginationConfig={"MaxItems": 10}
27+
)
2328

2429
image_names: [str] = []
2530
for page in page_iterator:
@@ -32,17 +37,14 @@ def hello_ecr(ecr_client : client, repository_name :str) -> None:
3237

3338

3439
if __name__ == "__main__":
35-
parser = argparse.ArgumentParser(
36-
description="Run hello Amazon ECR."
37-
)
40+
parser = argparse.ArgumentParser(description="Run hello Amazon ECR.")
3841
parser.add_argument(
3942
"--repository-name",
4043
type=str,
4144
help="the name of an Amazon ECR repository in your account.",
42-
required=True
45+
required=True,
4346
)
4447
args = parser.parse_args()
4548

46-
4749
hello_ecr(boto3.client("ecr"), args.repository_name)
4850
# snippet-end:[python.example_code.ecr.Hello]
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
"""
5+
Contains common test fixtures used to run unit tests.
6+
"""
7+
8+
import sys
9+
10+
import boto3
11+
import pytest
12+
import os
13+
14+
15+
script_dir = os.path.dirname(os.path.abspath(__file__))
16+
17+
sys.path.append(script_dir)
18+
import ecr_getting_started
19+
from ecr_wrapper import ECRWrapper
20+
21+
# Add relative path to include demo_tools in this code example without need for setup.
22+
sys.path.append(os.path.join(script_dir, "../.."))
23+
24+
from test_tools.fixtures.common import *
25+
26+
27+
class MockDockerImage:
28+
def __init__(self):
29+
self.repository = None
30+
self.image_tag = (None,)
31+
self.path = None
32+
33+
def tag(self, repository: str, tag: str) -> None:
34+
assert repository == self.repository, "MockDockerImage.tag"
35+
assert tag == self.image_tag, "MockDockerImage.tag"
36+
37+
def build(self, path: str, tag: str) -> tuple["MockDockerImage", None]:
38+
assert path == self.path, "MockDockerImage.build"
39+
assert tag == f"{self.repository}:{self.image_tag}", "MockDockerImage.build"
40+
return self, None
41+
42+
def remove(self, tag: str) -> None:
43+
assert tag == f"{self.repository}:{self.image_tag}", "MockDockerImage.remove"
44+
pass
45+
46+
47+
class MockDockerAPI:
48+
def __init__(self):
49+
self.repository = None
50+
self.tag = (None,)
51+
self.username = None
52+
self.password = None
53+
54+
def push(
55+
self,
56+
repository: str,
57+
auth_config: dict[str, str],
58+
tag: str,
59+
stream: bool,
60+
decode: bool,
61+
) -> list[str]:
62+
assert repository == self.repository, "MockDockerAPI.push"
63+
assert auth_config["username"] == self.username, "MockDockerAPI.push"
64+
assert auth_config["password"] == self.password, "MockDockerAPI.push"
65+
assert tag == self.tag, "MockDockerAPI.push"
66+
assert stream == True, "MockDockerAPI.push"
67+
assert decode == True, "MockDockerAPI.push"
68+
return ["pushing", "push complete"]
69+
70+
71+
class MockDockerClient:
72+
def __init__(self):
73+
self.images = MockDockerImage()
74+
self.api = MockDockerAPI()
75+
76+
def set_mocking_values(self, repository, tag, path, username, password):
77+
self.images.repository = repository
78+
self.images.image_tag = tag
79+
self.images.path = path
80+
self.api.repository = repository
81+
self.api.tag = tag
82+
self.api.username = username
83+
self.api.password = password
84+
85+
86+
class ScenarioData:
87+
def __init__(
88+
self,
89+
ecr_client,
90+
mock_docker_client,
91+
ecr_stubber,
92+
):
93+
self.ecr_client = ecr_client
94+
self.mock_docker_client = mock_docker_client
95+
self.ecr_stubber = ecr_stubber
96+
self.scenario = ecr_getting_started.ECRGettingStarted(
97+
ecr_wrapper=ECRWrapper(self.ecr_client),
98+
docker_client=self.mock_docker_client,
99+
)
100+
101+
102+
@pytest.fixture
103+
def scenario_data(make_stubber):
104+
ecr_client = boto3.client("ecr")
105+
mock_docker_client = MockDockerClient()
106+
ecr_stubber = make_stubber(ecr_client)
107+
return ScenarioData(
108+
ecr_client,
109+
mock_docker_client,
110+
ecr_stubber,
111+
)

0 commit comments

Comments
 (0)