Skip to content

Commit c23e3c9

Browse files
authored
Drop pydantic and use dataclasses instead. (#24)
1 parent bda6fa4 commit c23e3c9

File tree

15 files changed

+1089
-863
lines changed

15 files changed

+1089
-863
lines changed

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
repos:
22
- repo: https://github.com/pre-commit/pre-commit-hooks
3-
rev: v4.4.0
3+
rev: v4.5.0
44
hooks:
55
- id: end-of-file-fixer
66
- id: trailing-whitespace
@@ -17,14 +17,14 @@ repos:
1717
- id: fix-byte-order-marker
1818

1919
- repo: https://github.com/asottile/pyupgrade
20-
rev: v3.10.1
20+
rev: v3.15.0
2121
hooks:
2222
- id: pyupgrade
2323
args: [ "--py38-plus" ]
2424
exclude: ^ecs_files_composer/input.py|docs/
2525

2626
- repo: https://github.com/psf/black
27-
rev: 23.7.0
27+
rev: 23.10.0
2828
hooks:
2929
- id: black
3030
- repo: https://github.com/pycqa/isort

Dockerfile

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
ARG ARCH=
2-
ARG PY_VERSION=3.9
2+
ARG PY_VERSION=3.10
33
ARG BASE_IMAGE=public.ecr.aws/docker/library/python:${PY_VERSION}-slim
44
ARG LAMBDA_IMAGE=public.ecr.aws/lambda/python:latest
55

@@ -9,14 +9,13 @@ WORKDIR /opt
99
RUN yum install gcc -y
1010
COPY ecs_files_composer /opt/ecs_files_composer
1111
COPY poetry.lock pyproject.toml MANIFEST.in README.rst LICENSE /opt/
12-
RUN python -m pip install pip -U; python -m pip install poetry; poetry build
12+
RUN python -m pip install pip -U; python -m pip install poetry; poetry build; poetry export -o /opt/requirements.txt
1313

1414

1515
FROM $BASE_IMAGE
16-
1716
COPY --from=builder /opt/dist/*.whl ${LAMBDA_TASK_ROOT:-/app/}/dist/
18-
19-
RUN python -m pip install pip -U --no-cache-dir; \
20-
python -m pip install --no-cache-dir /app/dist/*.whl
17+
COPY --from=builder /opt/requirements.txt ${LAMBDA_TASK_ROOT:-/app/}/requirements.txt
18+
RUN python -m pip install pip -U --no-cache-dir; pip install --no-cache-dir -r /app/requirements.txt
19+
RUN python -m pip install --no-cache-dir /app/dist/*.whl
2120
WORKDIR /
2221
ENTRYPOINT ["python", "-m", "ecs_files_composer.cli"]

docs/commands.rst

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
.. meta::
2+
:description: Files Commands
3+
:keywords: Configuration, commands
4+
5+
.. _commands_docs:
6+
7+
Commands
8+
=========
9+
10+
.. warning::
11+
12+
When using docker, the container user is root to simplify access to filesystem.
13+
14+
Within files, you have the ability to run `post` commands, which are commands to run after writing the file to disk
15+
was done successfully.
16+
17+
18+
Commands can come in handy to change permissions on files and all sorts of things so that the application that will
19+
read/consume the file & folders will have permissions to do so.
20+
21+
Commands can be written in 2 ways
22+
23+
* a simple string: will execute the command, won't output the result
24+
* a mapping, with the command, and options
25+
26+
27+
Using the mapping option
28+
-------------------------
29+
30+
As of 2.0, the available options are
31+
32+
* display_output: bool
33+
* ignore_error: bool
34+
35+
36+
display_output
37+
^^^^^^^^^^^^^^^
38+
39+
As its name would suggest, this will log the output of the command.
40+
41+
.. warning::
42+
43+
Use carefully as it won't be filtering out any secret values & details
44+
45+
ignore_error
46+
^^^^^^^^^^^^^^^
47+
48+
You can already set error conditions and ignore at the top level of the file. This option allows for a localized setting.
49+
For example, if every other commands must succeed but one of them can fail without causing an error, you would set this to true
50+
51+
In the example below, we want to see the content of `/tmp/testing/toto.txt` which we know must work because
52+
it will be rendered.
53+
54+
However, file `/tmp/init/init.con` might not exist on the file system, so if it doesn't, we ignore.
55+
56+
.. code-block:: yaml
57+
58+
files:
59+
/tmp/testing/toto.txt:
60+
content: |
61+
HELLO YOU
62+
context: plain
63+
commands:
64+
post:
65+
- chown 1000:1000 -R /opt/files
66+
- command: ls /tmp/
67+
display_output: true
68+
- command: cat /tmp/init/init.con
69+
display_output: true
70+
ignore_error: true

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ docker-compose
8888
input
8989
features
9090
jinja2_functions_filters
91+
commands
9192
certificates
9293
examples
9394
modules

ecs-files-input.json

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,31 @@
284284
"type": "array",
285285
"description": "List of commands to run",
286286
"items": {
287-
"type": "string",
288-
"description": "Shell command to run"
287+
"oneOf": [
288+
{
289+
"type": "string",
290+
"description": "Shell command to run"
291+
},
292+
{
293+
"type": "object",
294+
"description": "Command to run with options",
295+
"properties": {
296+
"command": {
297+
"type": "string"
298+
},
299+
"display_output": {
300+
"type": "boolean",
301+
"default": false,
302+
"description": "Displays the command output"
303+
},
304+
"ignore_error": {
305+
"type": "boolean",
306+
"description": "Ignore if command failed",
307+
"default": false
308+
}
309+
}
310+
}
311+
]
289312
}
290313
},
291314
"X509CertDef": {

ecs_files_composer/aws_mgmt.py

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ def create_session_from_creds(tmp_creds: dict, region: str = None):
2323
"""
2424
creds = tmp_creds["Credentials"]
2525
params = {
26-
"aws_access_key_id": creds["AccessKeyId"],
27-
"aws_secret_access_key": creds["SecretAccessKey"],
26+
"aws_AccessKeyId": creds["AccessKeyId"],
27+
"aws_SecretAccessKey": creds["SecretAccessKey"],
2828
"aws_session_token": creds["SessionToken"],
2929
}
3030
if region:
31-
params["region_name"] = region
31+
params["RegionName"] = region
3232
return boto3.session.Session(**params)
3333

3434

@@ -43,23 +43,23 @@ def set_session_from_iam_object(iam_config_object, source_session: Session = Non
4343
"""
4444
if source_session is None:
4545
source_session = boto3.Session()
46-
if not iam_config_object.access_key_id and not iam_config_object.secret_access_key:
46+
if not iam_config_object.AccessKeyId and not iam_config_object.SecretAccessKey:
4747
params = {
48-
"RoleArn": iam_config_object.role_arn,
49-
"RoleSessionName": f"{iam_config_object.session_name}@AwsResourceHandlerInit",
48+
"RoleArn": iam_config_object.RoleArn,
49+
"RoleSessionName": f"{iam_config_object.SessionName}@AwsResourceHandlerInit",
5050
}
51-
if iam_config_object.external_id:
52-
params["ExternalId"] = iam_config_object.external_id
51+
if iam_config_object.ExternalId:
52+
params["ExternalId"] = iam_config_object.ExternalId
5353
tmp_creds = source_session.client("sts").assume_role(**params)
5454
client_session = create_session_from_creds(
55-
tmp_creds, region=iam_config_object.region_name
55+
tmp_creds, region=iam_config_object.RegionName
5656
)
5757
else:
5858
client_session = boto3.session.Session(
59-
aws_access_key_id=iam_config_object.access_key_id,
60-
aws_secret_access_key=iam_config_object.secret_access_key,
61-
aws_session_token=iam_config_object.session_token
62-
if iam_config_object.session_token
59+
aws_access_key_id=iam_config_object.AccessKeyId,
60+
aws_secret_access_key=iam_config_object.SecretAccessKey,
61+
aws_session_token=iam_config_object.SessionToken
62+
if iam_config_object.SessionToken
6363
else None,
6464
)
6565
return client_session
@@ -72,38 +72,38 @@ class AwsResourceHandler:
7272

7373
def __init__(
7474
self,
75-
role_arn=None,
76-
external_id=None,
75+
RoleArn=None,
76+
ExternalId=None,
7777
region=None,
7878
iam_config_object=None,
7979
client_session_override=None,
8080
):
8181
"""
82-
:param str role_arn:
83-
:param str external_id:
82+
:param str RoleArn:
83+
:param str ExternalId:
8484
:param str region:
8585
:param ecs_files_composer.input.IamOverrideDef iam_config_object:
8686
"""
8787
self.session = Session()
8888
self.client_session = Session()
8989
if client_session_override:
9090
self.client_session = client_session_override
91-
elif not client_session_override and (role_arn or iam_config_object):
92-
if role_arn and not iam_config_object:
91+
elif not client_session_override and (RoleArn or iam_config_object):
92+
if RoleArn and not iam_config_object:
9393
params = {
94-
"RoleArn": role_arn,
94+
"RoleArn": RoleArn,
9595
"RoleSessionName": "EcsConfigComposer@AwsResourceHandlerInit",
9696
}
97-
if external_id:
98-
params["ExternalId"] = external_id
97+
if ExternalId:
98+
params["ExternalId"] = ExternalId
9999
tmp_creds = self.session.client("sts").assume_role(**params)
100100
self.client_session = create_session_from_creds(
101101
tmp_creds, region=region
102102
)
103103
elif (
104104
iam_config_object
105-
and hasattr(iam_config_object, "role_arn")
106-
and iam_config_object.role_arn
105+
and hasattr(iam_config_object, "RoleArn")
106+
and iam_config_object.RoleArn
107107
):
108108
self.client_session = set_session_from_iam_object(
109109
iam_config_object, self.session
@@ -120,14 +120,14 @@ class S3Fetcher(AwsResourceHandler):
120120

121121
def __init__(
122122
self,
123-
role_arn=None,
124-
external_id=None,
123+
RoleArn=None,
124+
ExternalId=None,
125125
region=None,
126126
iam_config_object=None,
127127
client_session_override=None,
128128
):
129129
super().__init__(
130-
role_arn, external_id, region, iam_config_object, client_session_override
130+
RoleArn, ExternalId, region, iam_config_object, client_session_override
131131
)
132132

133133
@property
@@ -173,14 +173,14 @@ class SsmFetcher(AwsResourceHandler):
173173

174174
def __init__(
175175
self,
176-
role_arn=None,
177-
external_id=None,
176+
RoleArn=None,
177+
ExternalId=None,
178178
region=None,
179179
iam_config_object=None,
180180
client_session_override=None,
181181
):
182182
super().__init__(
183-
role_arn, external_id, region, iam_config_object, client_session_override
183+
RoleArn, ExternalId, region, iam_config_object, client_session_override
184184
)
185185
self.client = self.client_session.client("ssm")
186186

@@ -212,14 +212,14 @@ class SecretFetcher(AwsResourceHandler):
212212

213213
def __init__(
214214
self,
215-
role_arn=None,
216-
external_id=None,
215+
RoleArn=None,
216+
ExternalId=None,
217217
region=None,
218218
iam_config_object=None,
219219
client_session_override=None,
220220
):
221221
super().__init__(
222-
role_arn, external_id, region, iam_config_object, client_session_override
222+
RoleArn, ExternalId, region, iam_config_object, client_session_override
223223
)
224224
self.client = self.client_session.client("secretsmanager")
225225

@@ -230,13 +230,13 @@ def get_content(self, secret):
230230
:param input.SecretDef secret:
231231
:return:
232232
"""
233-
secret_id = expandvars(secret.secret_id)
233+
secret_id = expandvars(secret.SecretId)
234234
params = {"SecretId": secret_id}
235235
LOG.debug(f"Retrieving secretsmanager://{secret_id}")
236-
if secret.version_id:
237-
params["VersionId"] = secret.version_id
238-
if secret.version_stage:
239-
params["VersionStage"] = secret.version_stage
236+
if secret.VersionId:
237+
params["VersionId"] = secret.VersionId
238+
if secret.VersionStage:
239+
params["VersionStage"] = secret.VersionStage
240240
try:
241241
parameter = self.client.get_secret_value(**params)
242242
return parameter["SecretString"]

0 commit comments

Comments
 (0)