8000 Implementation of AWS::ECR::Repository resource provider for CloudFor… · codeperl/localstack@8006704 · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit 8006704

Browse files
authored
Implementation of AWS::ECR::Repository resource provider for CloudFormation (localstack#9302)
* Refactor ECR Repository plugin to create mock repositories
1 parent e7ddddd commit 8006704

File tree

6 files changed

+398
-0
lines changed

6 files changed

+398
-0
lines changed

localstack/services/cloudformation/resource_provider.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
"AWS::DynamoDB::Table": "ResourceProvider",
6767
"AWS::CloudWatch::Alarm": "ResourceProvider",
6868
"AWS::CloudWatch::CompositeAlarm": "ResourceProvider",
69+
"AWS::ECR::Repository": "ResourceProvider",
6970
}
7071

7172

localstack/services/ecr/__init__.py

Whitespace-only changes.

localstack/services/ecr/resource_providers/__init__.py

Whitespace-only changes.
Lines changed: 167 additions & 0 deletions
+
LifecyclePolicy: Optional[LifecyclePolicy]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# LocalStack Resource Provider Scaffolding v2
2+
from __future__ import annotations
3+
4+
import logging
5+
from pathlib import Path
6+
from typing import Optional, TypedDict
7+
8+
import localstack.services.cloudformation.provider_utils as util
9+
from localstack.services.cloudformation.resource_provider import (
10+
OperationStatus,
11+
ProgressEvent,
12+
ResourceProvider,
13+
ResourceRequest,
14+
)
15+
from localstack.utils.aws import arns
16+
17+
LOG = logging.getLogger(__name__)
18+
19+
# simple mock state
20+
default_repos_per_stack = {}
21+
22+
23+
class ECRRepositoryProperties(TypedDict):
24+
Arn: Optional[str]
25+
EncryptionConfiguration: Optional[EncryptionConfiguration]
26+
ImageScanningConfiguration: Optional[ImageScanningConfiguration]
27+
ImageTagMutability: Optional[str]
28
29+
RepositoryName: Optional[str]
30+
RepositoryPolicyText: Optional[dict | str]
31+
RepositoryUri: Optional[str]
32+
Tags: Optional[list[Tag]]
33+
34+
35+
class LifecyclePolicy(TypedDict):
36+
LifecyclePolicyText: Optional[str]
37+
RegistryId: Optional[str]
38+
39+
40+
class Tag(TypedDict):
41+
Key: Optional[str]
42+
Value: Optional[str]
43+
44+
45+
class ImageScanningConfiguration(TypedDict):
46+
ScanOnPush: Optional[bool]
47+
48+
49+
class EncryptionConfiguration(TypedDict):
50+
EncryptionType: Optional[str]
51+
KmsKey: Optional[str]
52+
53+
54+
REPEATED_INVOCATION = "repeated_invocation"
55+
56+
57+
class ECRRepositoryProvider(ResourceProvider[ECRRepositoryProperties]):
58+
59+
TYPE = "AWS::ECR::Repository" # Autogenerated. Don't change
60+
SCHEMA = util.get_schema_path(Path(__file__)) # Autogenerated. Don't change
61+
62+
def create(
63+
self,
64+
request: ResourceRequest[ECRRepositoryProperties],
65+
) -> ProgressEvent[ECRRepositoryProperties]:
66+
"""
67+
Create a new resource.
68+
69+
Primary identifier fields:
70+
- /properties/RepositoryName
71+
72+
Create-only properties:
73+
- /properties/RepositoryName
74+
- /properties/EncryptionConfiguration
75+
- /properties/EncryptionConfiguration/EncryptionType
76+
- /properties/EncryptionConfiguration/KmsKey
77+
78+
Read-only properties:
79+
- /properties/Arn
80+
- /properties/RepositoryUri
81+
82+
IAM permissions required:
83+
- ecr:CreateRepository
84+
- ecr:PutLifecyclePolicy
85+
- ecr:SetRepositoryPolicy
86+
- ecr:TagResource
87+
- kms:DescribeKey
88+
- kms:CreateGrant
89+
- kms:RetireGrant
90+
91+
"""
92+
model = request.desired_state
93+
94+
default_repos_per_stack[request.stack_name] = model["RepositoryName"]
95+
LOG.warning(
96+
"Creating a Mock ECR Repository for CloudFormation. This is only intended to be used for allowing a successful CDK bootstrap and does not provision any underlying ECR repository."
97+
)
98+
model.update(
99+
{
100+
"Arn": arns.get_ecr_repository_arn(model["RepositoryName"]),
101+
"RepositoryUri": "http://localhost:4566",
102+
"ImageTagMutability": "MUTABLE",
103+
"ImageScanningConfiguration": {"scanOnPush": True},
104+
}
105+
)
106+
return ProgressEvent(
107+
status=OperationStatus.SUCCESS,
108+
resource_model=model,
109+
custom_context=request.custom_context,
110+
)
111+
112+
def read(
113+
self,
114+
request: ResourceRequest[ECRRepositoryProperties],
115+
) -> ProgressEvent[ECRRepositoryProperties]:
116+
"""
117+
Fetch resource information
118+
119+
IAM permissions required:
120+
- ecr:DescribeRepositories
121+
- ecr:GetLifecyclePolicy
122+
- ecr:GetRepositoryPolicy
123+
- ecr:ListTagsForResource
124+
"""
125+
raise NotImplementedError
126+
127+
def delete(
128+
self,
129+
request: ResourceRequest[ECRRepositoryProperties],
130+
) -> ProgressEvent[ECRRepositoryProperties]:
131+
"""
132+
Delete a resource
133+
134+
IAM permissions required:
135+
- ecr:DeleteRepository
136+
- kms:RetireGrant
137+
"""
138+
if default_repos_per_stack.get(request.stack_name):
139+
del default_repos_per_stack[request.stack_name]
140+
141+
return ProgressEvent(
142+
status=OperationStatus.SUCCESS,
143+
resource_model=request.desired_state,
144+
custom_context=request.custom_context,
145+
)
146+
147+
def update(
148+
self,
149+
request: ResourceRequest[ECRRepositoryProperties],
150+
) -> ProgressEvent[ECRRepositoryProperties]:
151+
"""
152+
Update a resource
153+
154+
IAM permissions required:
155+
- ecr:PutLifecyclePolicy
156+
- ecr:SetRepositoryPolicy
157+
- ecr:TagResource
158+
- ecr:UntagResource
159+
- ecr:DeleteLifecyclePolicy
160+
- ecr:DeleteRepositoryPolicy
161+
- ecr:PutImageScanningConfiguration
162+
- ecr:PutImageTagMutability
163+
- kms:DescribeKey
164+
- kms:CreateGrant
165+
- kms:RetireGrant
166+
"""
167+
raise NotImplementedError
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
{
2+
"typeName": "AWS::ECR::Repository",
3+
"description": "The AWS::ECR::Repository resource specifies an Amazon Elastic Container Registry (Amazon ECR) repository, where users can push and pull Docker images. For more information, see https://docs.aws.amazon.com/AmazonECR/latest/userguide/Repositories.html",
4+
"sourceUrl": "https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-ecr.git",
5+
"definitions": {
6+
"LifecyclePolicy": {
7+
"type": "object",
8+
"description": "The LifecyclePolicy property type specifies a lifecycle policy. For information about lifecycle policy syntax, see https://docs.aws.amazon.com/AmazonECR/latest/userguide/LifecyclePolicies.html",
9+
"properties": {
10+
"LifecyclePolicyText": {
11+
"$ref": "#/definitions/LifecyclePolicyText"
12+
},
13+
"RegistryId": {
14+
"$ref": "#/definitions/RegistryId"
15+
}
16+
},
17+
"additionalProperties": false
18+
},
19+
"LifecyclePolicyText": {
20+
"type": "string",
21+
"description": "The JSON repository policy text to apply to the repository.",
22+
"minLength": 100,
23+
"maxLength": 30720
24+
},
25+
"RegistryId": {
26+
"type": "string",
27+
"description": "The AWS account ID associated with the registry that contains the repository. If you do not specify a registry, the default registry is assumed. ",
28+
"minLength": 12,
29+
"maxLength": 12,
30+
"pattern": "^[0-9]{12}$"
31+
},
32+
"Tag": {
33+
"description": "A key-value pair to associate with a resource.",
34+
"type": "object",
35+
"properties": {
36+
"Key": {
37+
< F438 span class="pl-ent">"type": "string",
38+
"description": "The key name of the tag. You can specify a value that is 1 to 127 Unicode characters in length and cannot be prefixed with aws:. You can use any of the following characters: the set of Unicode letters, digits, whitespace, _, ., /, =, +, and -. ",
39+
"minLength": 1,
40+
"maxLength": 127
41+
},
42+
"Value": {
43+
"type": "string",
44+
"description": "The value for the tag. You can specify a value that is 1 to 255 Unicode characters in length and cannot be prefixed with aws:. You can use any of the following characters: the set of Unicode letters, digits, whitespace, _, ., /, =, +, and -. ",
45+
"minLength": 1,
46+
"maxLength": 255
47+
}
48+
},
49+
"required": [
50+
"Value",
51+
"Key"
52+
],
53+
"additionalProperties": false
54+
},
55+
"ImageScanningConfiguration": {
56+
"type": "object",
57+
"description": "The image scanning configuration for the repository. This setting determines whether images are scanned for known vulnerabilities after being pushed to the repository.",
58+
"properties": {
59+
"ScanOnPush": {
60+
"$ref": "#/definitions/ScanOnPush"
61+
}
62+
},
63+
"additionalProperties": false
64+
},
65+
"ScanOnPush": {
66+
"type": "boolean",
67+
"description": "The setting that determines whether images are scanned after being pushed to a repository."
68+
},
69+
"EncryptionConfiguration": {
70+
"type": "object",
71+
"description": "The encryption configuration for the repository. This determines how the contents of your repository are encrypted at rest.\n\nBy default, when no encryption configuration is set or the AES256 encryption type is used, Amazon ECR uses server-side encryption with Amazon S3-managed encryption keys which encrypts your data at rest using an AES-256 encryption algorithm. This does not require any action on your part.\n\nFor more information, see https://docs.aws.amazon.com/AmazonECR/latest/userguide/encryption-at-rest.html",
72+
"properties": {
73+
"EncryptionType": {
74+
"$ref": "#/definitions/EncryptionType"
75+
},
76+
"KmsKey": {
77+
"$ref": "#/definitions/KmsKey"
78+
}
79+
},
80+
"required": [
81+
"EncryptionType"
82+
],
83+
"additionalProperties": false
84+
},
85+
"EncryptionType": {
86+
"type": "string",
87+
"description": "The encryption type to use.",
88+
"enum": [
89+
"AES256",
90+
"KMS"
91+
]
92+
},
93+
"KmsKey": {
94+
"type": "string",
95+
"description": "If you use the KMS encryption type, specify the CMK to use for encryption. The alias, key ID, or full ARN of the CMK can be specified. The key must exist in the same Region as the repository. If no key is specified, the default AWS managed CMK for Amazon ECR will be used.",
96+
"minLength": 1,
97+
"maxLength": 2048
98+
}
99+
},
100+
"properties": {
101+
"LifecyclePolicy": {
102+
"$ref": "#/definitions/LifecyclePolicy"
103+
},
104+
"RepositoryName": {
105+
"type": "string",
106+
"description": "The name to use for the repository. The repository name may be specified on its own (such as nginx-web-app) or it can be prepended with a namespace to group the repository into a category (such as project-a/nginx-web-app). If you don't specify a name, AWS CloudFormation generates a unique physical ID and uses that ID for the repository name. For more information, see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-name.html.",
107+
"minLength": 2,
108+
"maxLength": 256,
109+
"pattern": "^(?=.{2,256}$)((?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*)$"
110+
},
111+
"RepositoryPolicyText": {
112+
"type": [
113+
"object",
114+
"string"
115+
],
116+
"description": "The JSON repository policy text to apply to the repository. For more information, see https://docs.aws.amazon.com/AmazonECR/latest/userguide/RepositoryPolicyExamples.html in the Amazon Elastic Container Registry User Guide. "
117+
},
118+
"Tags": {
119+
"type": "array",
120+
"maxItems": 50,
121+
"uniqueItems": true,
122+
"insertionOrder": false,
123+
"description": "An array of key-value pairs to apply to this resource.",
124+
"items": {
125+
"$ref": "#/definitions/Tag"
126+
}
127+
},
128+
"Arn": {
129+
"type": "string"
130+
},
131+
"RepositoryUri": {
132+
"type": "string"
133+
},
134+
"ImageTagMutability": {
135+
"type": "string",
136+
"description": "The image tag mutability setting for the repository.",
137+
"enum": [
138+
"MUTABLE",
139+
"IMMUTABLE"
140+
]
141+
},
142+
"ImageScanningConfiguration": {
143+
"$ref": "#/definitions/ImageScanningConfiguration"
144+
},
145+
"EncryptionConfiguration": {
146+
"$ref": "#/definitions/EncryptionConfiguration"
147+
}
148+
},
149+
"createOnlyProperties": [
150+
"/properties/RepositoryName",
151+
"/properties/EncryptionConfiguration",
152+
"/properties/EncryptionConfiguration/EncryptionType",
153+
"/properties/EncryptionConfiguration/KmsKey"
154+
],
155+
"readOnlyProperties": [
156+
"/properties/Arn",
157+
"/properties/RepositoryUri"
158+
],
159+
"primaryIdentifier": [
160+
"/properties/RepositoryName"
161+
],
162+
"handlers": {
163+
"create": {
164+
"permissions": [
165+
"ecr:CreateRepository",
166+
"ecr:PutLifecyclePolicy",
167+
"ecr:SetRepositoryPolicy",
168+
"ecr:TagResource",
169+
"kms:DescribeKey",
170+
"kms:CreateGrant",
171+
"kms:RetireGrant"
172+
]
173+
},
174+
"read": {
175+
"permissions": [
176+
"ecr:DescribeRepositories",
177+
"ecr:GetLifecyclePolicy",
178+
"ecr:GetRepositoryPolicy",
179+
"ecr:ListTagsForResource"
180+
]
181+
},
182+
"update": {
183+
"permissions": [
184+
"ecr:PutLifecyclePolicy",
185+
"ecr:SetRepositoryPolicy",
186+
"ecr:TagResource",
187+
"ecr:UntagResource",
188+
"ecr:DeleteLifecyclePolicy",
189+
"ecr:DeleteRepositoryPolicy",
190+
"ecr:PutImageScanningConfiguration",
191+
"ecr:PutImageTagMutability",
192+
"kms:DescribeKey",
193+
"kms:CreateGrant",
194+
"kms:RetireGrant"
195+
]
196+
},
197+
"delete": {
198+
"permissions": [
199+
"ecr:DeleteRepository",
200+
"kms:RetireGrant"
201+
]
202+
},
203+
"list": {
204+
"permissions": [
205+
"ecr:DescribeRepositories"
206+
]
207+
}
208+
},
209+
"additionalProperties": false
210+
}

0 commit comments

Comments
 (0)
0