Skip to content

Commit fb532b3

Browse files
committed
Support S3Uri and ComposeXUri paths to S3
1 parent cd68491 commit fb532b3

File tree

5 files changed

+104
-25
lines changed

5 files changed

+104
-25
lines changed

ecs-files-input.json

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@
4141
}
4242
},
4343
"definitions": {
44+
"S3Uri": {
45+
"type": "string",
46+
"description": "s3://bucket-name/path/to/file simple syntax. Does not support IamOverride",
47+
"pattern": "^s3://([a-zA-Z\\d\\-.]+)/([\\S]+)$"
48+
},
49+
"ComposeXUri": {
50+
"type": "string",
51+
"description": "bucket_name::path/to/file format used in other compose-x projects",
52+
"pattern": "([a-zA-Z\\-\\d.]+)::([\\S]+)$"
53+
},
4454
"FileDef": {
4555
"type": "object",
4656
"additionalProperties": true,
@@ -175,11 +185,31 @@
175185
},
176186
"S3Def": {
177187
"type": "object",
178-
"required": [
179-
"BucketName",
180-
"Key"
188+
"oneOf": [
189+
{
190+
"required": [
191+
"BucketName",
192+
"Key"
193+
]
194+
},
195+
{
196+
"required": [
197+
"S3Uri"
198+
]
199+
},
200+
{
201+
"required": [
202+
"ComposeXUri"
203+
]
204+
}
181205
],
182206
"properties": {
207+
"S3Uri": {
208+
"$ref": "#/definitions/S3Uri"
209+
},
210+
"ComposeXUri": {
211+
"$ref": "#/definitions/ComposeXUri"
212+
},
183213
"BucketName": {
184214
"type": "string",
185215
"description": "Name of the S3 Bucket"

ecs_files_composer/aws_mgmt.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ class S3Fetcher(AwsResourceHandler):
115115
Class to handle S3 actions
116116
"""
117117

118-
bucket_re = re.compile(r"(?:s3://)(?P<bucket>[a-z0-9-.]+)/(?P<key>[\S]+$)")
118+
bucket_re = re.compile(r"^s3://(?P<bucket>[a-zA-Z\d\-.]+)/(?P<key>[\S]+)$")
119+
compose_x_re = re.compile(r"^(?P<bucket>[a-zA-Z\d\-.]+)::(?P<key>[\S]+)$")
119120

120121
def __init__(
121122
self,
@@ -128,21 +129,30 @@ def __init__(
128129
super().__init__(
129130
role_arn, external_id, region, iam_config_object, client_session_override
130131
)
131-
self.client = self.client_session.client("s3")
132132

133-
def get_content(self, s3_uri=None, s3_bucket=None, s3_key=None):
133+
@property
134+
def client(self):
135+
return self.client_session.client("s3")
136+
137+
def get_content(
138+
self,
139+
s3_uri: str = None,
140+
s3_bucket: str = None,
141+
s3_key: str = None,
142+
composex_uri: str = None,
143+
):
134144
"""
135145
Retrieves a file in a temp dir and returns content
136146
137-
:param str s3_uri:
138-
:param str s3_bucket:
139-
:param str s3_key:
140147
:return: The Stream Body for the file, allowing to do various things
141148
"""
142149

143-
if s3_uri and self.bucket_re.match(s3_uri).groups():
150+
if s3_uri and self.bucket_re.match(s3_uri):
144151
s3_bucket = self.bucket_re.match(s3_uri).group("bucket")
145152
s3_key = self.bucket_re.match(s3_uri).group("key")
153+
elif composex_uri and self.compose_x_re.match(composex_uri):
154+
s3_bucket = self.compose_x_re.match(composex_uri).group("bucket")
155+
s3_key = self.compose_x_re.match(composex_uri).group("key")
146156
try:
147157
file_r = self.client.get_object(Bucket=s3_bucket, Key=s3_key)
148158
file_content = file_r["Body"]
@@ -158,7 +168,7 @@ class SsmFetcher(AwsResourceHandler):
158168
"""
159169

160170
arn_re = re.compile(
161-
r"(?:^arn:aws(?:-[a-z]+)?:ssm:[\S]+:[0-9]+:parameter)(?P<name>/[\S]+)$"
171+
r"^arn:aws(?:-[a-z]+)?:ssm:[\S]+:[\d]{12}:parameter(?P<name>/[\S]+)$"
162172
)
163173

164174
def __init__(

ecs_files_composer/files_mgmt.py

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,33 @@ def handle_s3_source(self, iam_override=None, session_override=None):
118118
:param boto3.session.Session session_override:
119119
:return:
120120
"""
121-
bucket_name = expandvars(self.source.s3.bucket_name)
122-
key = expandvars(self.source.s3.key)
123-
LOG.debug(f"Retrieving s3://{bucket_name}/{key}")
124-
if self.source.s3.iam_override:
125-
fetcher = S3Fetcher(iam_config_object=self.source.s3.iam_override)
121+
from ecs_files_composer.input import S3Def1
122+
123+
if not isinstance(self.source.s3.__root__, S3Def1):
124+
raise TypeError(
125+
"S3 source is not of type S3Def1", type(self.source.s3.__root__)
126+
)
127+
128+
if self.source.s3.__root__.iam_override:
129+
fetcher = S3Fetcher(iam_config_object=self.source.s3.__root__.iam_override)
126130
elif iam_override:
127131
fetcher = S3Fetcher(iam_config_object=iam_override)
128132
elif session_override:
129133
fetcher = S3Fetcher(client_session_override=session_override)
130134
else:
131135
fetcher = S3Fetcher()
132-
self.content = fetcher.get_content(s3_bucket=bucket_name, s3_key=key)
136+
if self.source.s3.__root__.s3_uri:
137+
self.content = fetcher.get_content(
138+
s3_uri=self.source.s3.__root__.s3_uri.__root__
139+
)
140+
elif self.source.s3.__root__.compose_x_uri:
141+
self.content = fetcher.get_content(
142+
composex_uri=self.source.s3.__root__.compose_x_uri.__root__
143+
)
144+
else:
145+
bucket_name = expandvars(self.source.s3.__root__.bucket_name)
146+
key = expandvars(self.source.s3.__root__.key)
147+
self.content = fetcher.get_content(s3_bucket=bucket_name, s3_key=key)
133148

134149
def handle_secret_source(self, iam_override=None, session_override=None):
135150
"""

ecs_files_composer/input.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
11
# generated by datamodel-codegen:
22
# filename: ecs-files-input.json
3-
# timestamp: 2022-07-28T10:48:50+00:00
3+
# timestamp: 2022-08-07T22:11:46+00:00
44

55
from __future__ import annotations
66

77
from enum import Enum
8-
from typing import Dict, List, Optional
8+
from typing import Any, Dict, List, Optional, Union
99

1010
from pydantic import AnyUrl, BaseModel, EmailStr, Extra, Field, constr
1111

1212

13+
class S3Uri(BaseModel):
14+
__root__: str = Field(
15+
...,
16+
description="s3://bucket-name/path/to/file simple syntax. Does not support IamOverride",
17+
regex="^s3://([a-zA-Z\\d\\-.]+)/([\\S]+)$",
18+
)
19+
20+
21+
class ComposeXUri(BaseModel):
22+
__root__: str = Field(
23+
...,
24+
description="bucket_name::path/to/file format used in other compose-x projects",
25+
regex="([a-zA-Z\\-\\d.]+)::([\\S]+)$",
26+
)
27+
28+
1329
class Encoding(Enum):
1430
base64 = "base64"
1531
plain = "plain"
@@ -136,19 +152,27 @@ class SecretDef(BaseModel):
136152
iam_override: Optional[IamOverrideDef] = Field(None, alias="IamOverride")
137153

138154

139-
class S3Def(BaseModel):
140-
bucket_name: str = Field(
141-
..., alias="BucketName", description="Name of the S3 Bucket"
155+
class S3Def1(BaseModel):
156+
s3_uri: Optional[S3Uri] = Field(None, alias="S3Uri")
157+
compose_x_uri: Optional[ComposeXUri] = Field(None, alias="ComposeXUri")
158+
bucket_name: Optional[str] = Field(
159+
None, alias="BucketName", description="Name of the S3 Bucket"
142160
)
143161
bucket_region: Optional[str] = Field(
144162
None,
145163
alias="BucketRegion",
146164
description="S3 Region to use. Default will ignore or retrieve via s3:GetBucketLocation",
147165
)
148-
key: str = Field(..., alias="Key", description="Full path to the file to retrieve")
166+
key: Optional[str] = Field(
167+
None, alias="Key", description="Full path to the file to retrieve"
168+
)
149169
iam_override: Optional[IamOverrideDef] = Field(None, alias="IamOverride")
150170

151171

172+
class S3Def(BaseModel):
173+
__root__: Union[S3Def1, Any, Any, Any]
174+
175+
152176
class SourceDef(BaseModel):
153177
url: Optional[UrlDef] = Field(None, alias="Url")
154178
ssm: Optional[SsmDef] = Field(None, alias="Ssm")

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ keywords=["aws", "ecs", "k8s", "secrets", "certbot"]
2121

2222
[tool.poetry.dependencies]
2323
python = "^3.8"
24-
boto3 = "^1.23.2"
24+
boto3 = "^1.24"
2525
pydantic = {extras = ["email"], version = "^1.9.0"}
2626
pyOpenSSL = "^22"
2727
requests = "^2.27.1"
2828
PyYAML = "^6.0"
2929
Jinja2 = "^3.1.2"
30-
jsonschema = "^4.5.1"
30+
jsonschema = "^4"
3131
compose-x-common = "^1.0"
3232
certbot-aws-store = "^0.2.2"
3333

0 commit comments

Comments
 (0)