AWS-Mu 0.20250611.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aws_mu-0.20250611.3/.ci/.gitignore +2 -0
- aws_mu-0.20250611.3/.ci/pytest.ini +7 -0
- aws_mu-0.20250611.3/.circleci/config.yml +39 -0
- aws_mu-0.20250611.3/.copier-answers-py.yaml +19 -0
- aws_mu-0.20250611.3/.coveragerc +18 -0
- aws_mu-0.20250611.3/.dockerignore +6 -0
- aws_mu-0.20250611.3/.editorconfig +38 -0
- aws_mu-0.20250611.3/.github/workflows/nox.yaml +47 -0
- aws_mu-0.20250611.3/.github/workflows/pypi.yaml +60 -0
- aws_mu-0.20250611.3/.gitignore +39 -0
- aws_mu-0.20250611.3/.pre-commit-config.yaml +34 -0
- aws_mu-0.20250611.3/.python-version +1 -0
- aws_mu-0.20250611.3/PKG-INFO +242 -0
- aws_mu-0.20250611.3/ci/.gitignore +2 -0
- aws_mu-0.20250611.3/env-config.yaml +28 -0
- aws_mu-0.20250611.3/examples/apprunner/Dockerfile +20 -0
- aws_mu-0.20250611.3/examples/apprunner/app.py +50 -0
- aws_mu-0.20250611.3/examples/apprunner/compose.yaml +18 -0
- aws_mu-0.20250611.3/examples/apprunner/mu.toml +7 -0
- aws_mu-0.20250611.3/examples/apprunner/pyproject.toml +3 -0
- aws_mu-0.20250611.3/examples/apprunner/requirements.txt +2 -0
- aws_mu-0.20250611.3/examples/flask/Dockerfile +20 -0
- aws_mu-0.20250611.3/examples/flask/app.py +50 -0
- aws_mu-0.20250611.3/examples/flask/compose.yaml +18 -0
- aws_mu-0.20250611.3/examples/flask/mu.toml +9 -0
- aws_mu-0.20250611.3/examples/flask/pyproject.toml +3 -0
- aws_mu-0.20250611.3/examples/flask/requirements.txt +2 -0
- aws_mu-0.20250611.3/examples/mu_hello/Dockerfile +15 -0
- aws_mu-0.20250611.3/examples/mu_hello/compose.yaml +20 -0
- aws_mu-0.20250611.3/examples/mu_hello/mu.toml +26 -0
- aws_mu-0.20250611.3/examples/mu_hello/mu_hello.py +39 -0
- aws_mu-0.20250611.3/examples/mu_hello/pyproject.toml +3 -0
- aws_mu-0.20250611.3/examples/mu_hello/requirements.txt +1 -0
- aws_mu-0.20250611.3/examples/tasker/Dockerfile +22 -0
- aws_mu-0.20250611.3/examples/tasker/app.py +26 -0
- aws_mu-0.20250611.3/examples/tasker/compose.yaml +18 -0
- aws_mu-0.20250611.3/examples/tasker/handler.py +11 -0
- aws_mu-0.20250611.3/examples/tasker/mu.toml +3 -0
- aws_mu-0.20250611.3/examples/tasker/pyproject.toml +3 -0
- aws_mu-0.20250611.3/examples/tasker/requirements.txt +3 -0
- aws_mu-0.20250611.3/hatch.toml +18 -0
- aws_mu-0.20250611.3/misc/lambda-logs-example.txt +44 -0
- aws_mu-0.20250611.3/mise.toml +23 -0
- aws_mu-0.20250611.3/noxfile.py +46 -0
- aws_mu-0.20250611.3/pyproject.toml +74 -0
- aws_mu-0.20250611.3/readme.md +225 -0
- aws_mu-0.20250611.3/ruff.toml +94 -0
- aws_mu-0.20250611.3/src/conftest.py +45 -0
- aws_mu-0.20250611.3/src/mu/__init__.py +2 -0
- aws_mu-0.20250611.3/src/mu/cli/__init__.py +2 -0
- aws_mu-0.20250611.3/src/mu/cli/aws.py +164 -0
- aws_mu-0.20250611.3/src/mu/cli/core.py +196 -0
- aws_mu-0.20250611.3/src/mu/config.py +228 -0
- aws_mu-0.20250611.3/src/mu/exc.py +10 -0
- aws_mu-0.20250611.3/src/mu/handler.py +139 -0
- aws_mu-0.20250611.3/src/mu/handlers/diagnostics.py +23 -0
- aws_mu-0.20250611.3/src/mu/libs/__init__.py +0 -0
- aws_mu-0.20250611.3/src/mu/libs/api_gateway.py +89 -0
- aws_mu-0.20250611.3/src/mu/libs/auth.py +27 -0
- aws_mu-0.20250611.3/src/mu/libs/aws_recs.py +94 -0
- aws_mu-0.20250611.3/src/mu/libs/concurrent.py +93 -0
- aws_mu-0.20250611.3/src/mu/libs/ec2.py +28 -0
- aws_mu-0.20250611.3/src/mu/libs/ecr.py +310 -0
- aws_mu-0.20250611.3/src/mu/libs/ecs.py +86 -0
- aws_mu-0.20250611.3/src/mu/libs/gateway.py +322 -0
- aws_mu-0.20250611.3/src/mu/libs/iam.py +275 -0
- aws_mu-0.20250611.3/src/mu/libs/lamb.py +755 -0
- aws_mu-0.20250611.3/src/mu/libs/logs.py +69 -0
- aws_mu-0.20250611.3/src/mu/libs/orgs.py +12 -0
- aws_mu-0.20250611.3/src/mu/libs/sqs.py +121 -0
- aws_mu-0.20250611.3/src/mu/libs/status.py +103 -0
- aws_mu-0.20250611.3/src/mu/libs/sts.py +14 -0
- aws_mu-0.20250611.3/src/mu/libs/testing.py +120 -0
- aws_mu-0.20250611.3/src/mu/libs/utils.py +176 -0
- aws_mu-0.20250611.3/src/mu/tasks.py +98 -0
- aws_mu-0.20250611.3/src/mu/version.py +1 -0
- aws_mu-0.20250611.3/src/mu_tasks_lib.py +29 -0
- aws_mu-0.20250611.3/src/mu_tests/__init__.py +0 -0
- aws_mu-0.20250611.3/src/mu_tests/conftest.py +35 -0
- aws_mu-0.20250611.3/src/mu_tests/data/__init__.py +0 -0
- aws_mu-0.20250611.3/src/mu_tests/data/event_wsgi.py +55 -0
- aws_mu-0.20250611.3/src/mu_tests/data/exc-extras.txt +19 -0
- aws_mu-0.20250611.3/src/mu_tests/data/log_events.py +36 -0
- aws_mu-0.20250611.3/src/mu_tests/data/platform-report.txt +6 -0
- aws_mu-0.20250611.3/src/mu_tests/data/platform-start.txt +1 -0
- aws_mu-0.20250611.3/src/mu_tests/data/text-message.txt +2 -0
- aws_mu-0.20250611.3/src/mu_tests/data/unhandled-exc.txt +25 -0
- aws_mu-0.20250611.3/src/mu_tests/fake.py +124 -0
- aws_mu-0.20250611.3/src/mu_tests/mocking.py +263 -0
- aws_mu-0.20250611.3/src/mu_tests/pkg-sqs/pyproject.toml +13 -0
- aws_mu-0.20250611.3/src/mu_tests/pkg1/pyproject.toml +10 -0
- aws_mu-0.20250611.3/src/mu_tests/pkg2/mu.toml +3 -0
- aws_mu-0.20250611.3/src/mu_tests/pkg2/pyproject.toml +2 -0
- aws_mu-0.20250611.3/src/mu_tests/test_config.py +63 -0
- aws_mu-0.20250611.3/src/mu_tests/test_ecr.py +84 -0
- aws_mu-0.20250611.3/src/mu_tests/test_ecs.py +33 -0
- aws_mu-0.20250611.3/src/mu_tests/test_handler.py +84 -0
- aws_mu-0.20250611.3/src/mu_tests/test_iam.py +75 -0
- aws_mu-0.20250611.3/src/mu_tests/test_lamb.py +256 -0
- aws_mu-0.20250611.3/src/mu_tests/test_libs_gateway.py +498 -0
- aws_mu-0.20250611.3/src/mu_tests/test_libs_utils.py +23 -0
- aws_mu-0.20250611.3/src/mu_tests/test_sqs.py +82 -0
- aws_mu-0.20250611.3/src/mu_tests/test_tasks.py +110 -0
- aws_mu-0.20250611.3/tasks/bump +80 -0
- aws_mu-0.20250611.3/tasks/create-ci-iam-role.py +235 -0
- aws_mu-0.20250611.3/tasks/create-testing-acm-cert.py +32 -0
- aws_mu-0.20250611.3/tox.ini +70 -0
- aws_mu-0.20250611.3/uv.lock +1378 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
[pytest]
|
|
2
|
+
# default value for pytest 6.0 and specifying it avoids a deprecation warning
|
|
3
|
+
junit_family=xunit2
|
|
4
|
+
filterwarnings =
|
|
5
|
+
# Any errors not noted here should cause pytest to throw an error. It seems like this should be
|
|
6
|
+
# last in the list, but warnings that match multiple lines will apply the last line matched.
|
|
7
|
+
error
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
jobs:
|
|
3
|
+
build:
|
|
4
|
+
docker:
|
|
5
|
+
- image: level12/python-test-multi
|
|
6
|
+
- image: postgres:13
|
|
7
|
+
environment:
|
|
8
|
+
# Ok for CI, potentially UNSAFE in other applications. Don't blindly copy & paste
|
|
9
|
+
# without considering implications.
|
|
10
|
+
POSTGRES_HOST_AUTH_METHOD: trust
|
|
11
|
+
steps:
|
|
12
|
+
- checkout
|
|
13
|
+
|
|
14
|
+
- run:
|
|
15
|
+
name: debugging info
|
|
16
|
+
command: |
|
|
17
|
+
ls -al
|
|
18
|
+
|
|
19
|
+
- run:
|
|
20
|
+
name: install testing helpers needed at OS level
|
|
21
|
+
command: >
|
|
22
|
+
python3.9 -m pip install --upgrade --force-reinstall --quiet tox
|
|
23
|
+
|
|
24
|
+
- run:
|
|
25
|
+
name: version checks
|
|
26
|
+
command: |
|
|
27
|
+
python3.9 --version
|
|
28
|
+
python3.9 -m tox --version
|
|
29
|
+
|
|
30
|
+
- run:
|
|
31
|
+
name: run tox
|
|
32
|
+
command: python3.9 -m tox
|
|
33
|
+
|
|
34
|
+
- store_test_results:
|
|
35
|
+
path: .ci/test-reports/
|
|
36
|
+
|
|
37
|
+
- run:
|
|
38
|
+
name: push code coverage
|
|
39
|
+
command: bash <(curl -s https://codecov.io/bash) -X coveragepy -t
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Changes here will be overwritten by Copier
|
|
2
|
+
#
|
|
3
|
+
# Updating `_src` could be helpful, see notes at:
|
|
4
|
+
# https://github.com/level12/coppy/wiki#creating-a-project
|
|
5
|
+
#
|
|
6
|
+
# Otherwise, NEVER EDIT MANUALLY
|
|
7
|
+
_commit: v1.20250523.1
|
|
8
|
+
_src_path: gh:level12/coppy
|
|
9
|
+
author_email: randy.syring@level12.io
|
|
10
|
+
author_name: Randy Syring
|
|
11
|
+
gh_org: level12
|
|
12
|
+
gh_repo: mu
|
|
13
|
+
hatch_version_tag_sign: true
|
|
14
|
+
project_name: Mu
|
|
15
|
+
py_module: mu
|
|
16
|
+
python_version: '3.13'
|
|
17
|
+
script_name: mu
|
|
18
|
+
use_circleci: false
|
|
19
|
+
use_gh_nox: true
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# .coveragerc to control coverage.py
|
|
2
|
+
[run]
|
|
3
|
+
branch = True
|
|
4
|
+
|
|
5
|
+
[report]
|
|
6
|
+
# Regexes for lines to exclude from consideration
|
|
7
|
+
exclude_lines =
|
|
8
|
+
# Have to re-enable the standard pragma
|
|
9
|
+
pragma: no cover
|
|
10
|
+
|
|
11
|
+
# testing assertions usually used with exceptions
|
|
12
|
+
assert False
|
|
13
|
+
|
|
14
|
+
# patterns for running cli
|
|
15
|
+
cli_entry()
|
|
16
|
+
|
|
17
|
+
[html]
|
|
18
|
+
directory = ci/coverage-html
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# This is the "top-most" .editorconfig for this project.
|
|
2
|
+
# Like a `.gitignore` file, you can place additional
|
|
3
|
+
# .editorconfig files in specific directories, if you need
|
|
4
|
+
# local settings. However, this directive specifies that
|
|
5
|
+
# no "global" settings will be used (settings from higher-
|
|
6
|
+
# up in the directory hierarchy, wherever that may be)
|
|
7
|
+
root = true
|
|
8
|
+
|
|
9
|
+
# Set the default whitespace settings for all files
|
|
10
|
+
[*]
|
|
11
|
+
|
|
12
|
+
# Use UNIX-style line endings
|
|
13
|
+
end_of_line = lf
|
|
14
|
+
|
|
15
|
+
# 4-space indents
|
|
16
|
+
indent_size = 4
|
|
17
|
+
indent_style = space
|
|
18
|
+
|
|
19
|
+
# end all files with a newline
|
|
20
|
+
insert_final_newline = true
|
|
21
|
+
|
|
22
|
+
# trim whitespace from the ends of lines
|
|
23
|
+
trim_trailing_whitespace = true
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
[*.py]
|
|
27
|
+
# ensure Python source files are utf-8
|
|
28
|
+
charset = utf-8
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
[*.{yml,yaml}]
|
|
32
|
+
# Set two-space indents for YAML files
|
|
33
|
+
indent_size = 2
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
[Makefile]
|
|
37
|
+
# Makefiles *must* use tabs!
|
|
38
|
+
indent_style = tab
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Nox
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
pull_request:
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
# Limit this workflow to a single run at a time per-branch to avoid wasting worker resources
|
|
11
|
+
concurrency:
|
|
12
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: true
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
nox:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
|
|
23
|
+
# Runs all steps inside this container
|
|
24
|
+
container:
|
|
25
|
+
image: ghcr.io/level12/ubuntu-mive:24-3.12
|
|
26
|
+
options: --user root
|
|
27
|
+
|
|
28
|
+
env:
|
|
29
|
+
UV_LINK_MODE: copy
|
|
30
|
+
MU_TEST_ACCT_ID: '429829037495'
|
|
31
|
+
|
|
32
|
+
steps:
|
|
33
|
+
- name: Checkout Code
|
|
34
|
+
uses: actions/checkout@v4
|
|
35
|
+
|
|
36
|
+
- name: Mark repo as safe for Git
|
|
37
|
+
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
38
|
+
|
|
39
|
+
- name: Configure AWS Credentials
|
|
40
|
+
uses: aws-actions/configure-aws-credentials@v4
|
|
41
|
+
with:
|
|
42
|
+
role-to-assume: arn:aws:iam::429829037495:role/mu-github-ci-role
|
|
43
|
+
aws-region: us-east-2
|
|
44
|
+
|
|
45
|
+
- name: Run Tests
|
|
46
|
+
run: |
|
|
47
|
+
uv run --only-group nox -- nox
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Example:
|
|
2
|
+
# - https://github.com/pallets/flask/blob/main/.github/workflows/tests.yaml
|
|
3
|
+
# TODO:
|
|
4
|
+
# GH release
|
|
5
|
+
# Environment protection
|
|
6
|
+
# - https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment
|
|
7
|
+
# Separate build & release
|
|
8
|
+
|
|
9
|
+
name: PyPI publish
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
on:
|
|
13
|
+
push:
|
|
14
|
+
tags:
|
|
15
|
+
- 'v*.*.*'
|
|
16
|
+
workflow_dispatch:
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
build:
|
|
21
|
+
name: Build and publish
|
|
22
|
+
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
|
|
25
|
+
# TODO: recommended best practice
|
|
26
|
+
# environment:
|
|
27
|
+
# name: pypi-publish
|
|
28
|
+
# url: https://pypi.org/p/mu
|
|
29
|
+
|
|
30
|
+
permissions:
|
|
31
|
+
# required for pypa/gh-action-pypi-publish
|
|
32
|
+
id-token: write
|
|
33
|
+
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
|
|
37
|
+
# https://docs.astral.sh/uv/guides/integration/github/#setting-up-python
|
|
38
|
+
- name: Install uv
|
|
39
|
+
uses: astral-sh/setup-uv@v5
|
|
40
|
+
with:
|
|
41
|
+
enable-cache: true
|
|
42
|
+
cache-dependency-glob: "uv.lock"
|
|
43
|
+
|
|
44
|
+
- name: "Set up Python"
|
|
45
|
+
uses: actions/setup-python@v5
|
|
46
|
+
with:
|
|
47
|
+
python-version-file: ".python-version"
|
|
48
|
+
|
|
49
|
+
- name: Python prep & build
|
|
50
|
+
run: |
|
|
51
|
+
uv sync --locked
|
|
52
|
+
|
|
53
|
+
uv run hatch --version
|
|
54
|
+
|
|
55
|
+
echo "Project version: `uv run hatch version`"
|
|
56
|
+
|
|
57
|
+
uv run hatch build
|
|
58
|
+
|
|
59
|
+
- name: Publish package distributions to PyPI
|
|
60
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
*.pyc
|
|
3
|
+
*.egg-info
|
|
4
|
+
.venv
|
|
5
|
+
|
|
6
|
+
# Tox/Nox/Tests/Coverage
|
|
7
|
+
/.nox
|
|
8
|
+
/.tox
|
|
9
|
+
/ci/coverage-html
|
|
10
|
+
*.coverage
|
|
11
|
+
/coverage.xml
|
|
12
|
+
*.pytests.xml
|
|
13
|
+
.pytest_cache
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Editor Clutter
|
|
17
|
+
.vscode
|
|
18
|
+
.idea
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Build related
|
|
22
|
+
dist
|
|
23
|
+
/build
|
|
24
|
+
npm-debug.log
|
|
25
|
+
.*-cache
|
|
26
|
+
node_modules
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Local dev files
|
|
30
|
+
/mise.local.toml
|
|
31
|
+
/tmp
|
|
32
|
+
|
|
33
|
+
# Terraform
|
|
34
|
+
*.tfstate*
|
|
35
|
+
tf.plan
|
|
36
|
+
.terraform
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
# Project specific
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
repos:
|
|
3
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
4
|
+
rev: v5.0.0
|
|
5
|
+
hooks:
|
|
6
|
+
- id: check-merge-conflict
|
|
7
|
+
- id: check-ast
|
|
8
|
+
types: [ python ]
|
|
9
|
+
- id: debug-statements
|
|
10
|
+
types: [ python ]
|
|
11
|
+
- id: trailing-whitespace
|
|
12
|
+
- id: end-of-file-fixer
|
|
13
|
+
- id: check-added-large-files
|
|
14
|
+
- id: check-yaml
|
|
15
|
+
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
|
16
|
+
rev: v0.11.13
|
|
17
|
+
hooks:
|
|
18
|
+
# i.e. `ruff check`
|
|
19
|
+
- id: ruff
|
|
20
|
+
# i.e. `ruff format --check`
|
|
21
|
+
- id: ruff-format
|
|
22
|
+
# Due to the Ruff config we use (see comment in pyproject.yaml), it's possible that the
|
|
23
|
+
# formatter creates linting failures. By only doing a check here, it forces the dev to run
|
|
24
|
+
# the formatter before pre-commit runs (presumably on save through their editor) and then
|
|
25
|
+
# the linting check above would always catch a problem created by the formatter.
|
|
26
|
+
args: [ --check ]
|
|
27
|
+
- repo: https://github.com/level12/pre-commit-hooks
|
|
28
|
+
rev: v0.20250226.1
|
|
29
|
+
hooks:
|
|
30
|
+
- id: check-ruff-versions
|
|
31
|
+
- repo: https://github.com/astral-sh/uv-pre-commit
|
|
32
|
+
rev: 0.7.12
|
|
33
|
+
hooks:
|
|
34
|
+
- id: uv-lock
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: aws-mu
|
|
3
|
+
Version: 0.20250611.3
|
|
4
|
+
Author-email: Randy Syring <randy.syring@level12.io>
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: arrow>=1.3.0
|
|
7
|
+
Requires-Dist: awsgi2>=1.0.2
|
|
8
|
+
Requires-Dist: blazeutils>=0.7.0
|
|
9
|
+
Requires-Dist: boto3>=1.38.34
|
|
10
|
+
Requires-Dist: click>=8.2.1
|
|
11
|
+
Requires-Dist: colorlog>=6.9.0
|
|
12
|
+
Requires-Dist: cryptography>=45.0.4
|
|
13
|
+
Requires-Dist: docker>=7.1.0
|
|
14
|
+
Requires-Dist: methodtools>=0.4.7
|
|
15
|
+
Requires-Dist: requests>=2.32.4
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# Mu
|
|
19
|
+
[](https://github.com/level12/mu/actions/workflows/nox.yaml)
|
|
20
|
+
|
|
21
|
+
AWS Lambda support for Python projects.
|
|
22
|
+
|
|
23
|
+
## Project Setup
|
|
24
|
+
|
|
25
|
+
To use mu, a project needs a `pyproject.toml` and either
|
|
26
|
+
|
|
27
|
+
1. a `mu.toml` in the same directory (takes precedence); or
|
|
28
|
+
2. `tools.mu` sections in the `pyproject.toml`
|
|
29
|
+
|
|
30
|
+
It also needs
|
|
31
|
+
|
|
32
|
+
* Dockerfile
|
|
33
|
+
* compose.yaml (or docker-compose.yaml if you insist)
|
|
34
|
+
* An entry point in the app for the lambda events
|
|
35
|
+
|
|
36
|
+
An example application with these required elements can be found at:
|
|
37
|
+
[mu_hello](https://github.com/level12/mu/tree/master/mu_hello)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## Usage: Local
|
|
41
|
+
|
|
42
|
+
Let's demonstrate usage with [`mu_hello`](https://github.com/level12/mu/tree/master/mu_hello).
|
|
43
|
+
Assuming you have copied that source locally and are in the directory:
|
|
44
|
+
|
|
45
|
+
```shell
|
|
46
|
+
$ mu build
|
|
47
|
+
$ docker compose up mu-hello
|
|
48
|
+
|
|
49
|
+
# Watch current shell for log output and, in a new shell, run:
|
|
50
|
+
$ mu invoke --local
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
That command should have output like:
|
|
54
|
+
```
|
|
55
|
+
{'context': {'aws_request_id': '83fd7a58-5f6d-45e1-8092-b509c4f60898',
|
|
56
|
+
'function_name': 'test_function',
|
|
57
|
+
'function_version': '$LATEST',
|
|
58
|
+
'invoked_function_arn': 'arn:aws:lambda:us-east-1:012345678912:function:test_function',
|
|
59
|
+
'log_group_name': '/aws/lambda/Functions',
|
|
60
|
+
'log_stream_name': '$LATEST',
|
|
61
|
+
'memory_limit_in_mb': '3008',
|
|
62
|
+
'remaining_time': 299967},
|
|
63
|
+
'error': None,
|
|
64
|
+
'event': {'action-args': [], 'do-action': 'diagnostics'}}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
And the first shell should have output like:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
11 Jun 2024 19:28:28,809 [INFO] (rapid) INIT START(type: on-demand, phase: init)
|
|
71
|
+
...
|
|
72
|
+
11 Jun 2024 19:28:28,843 [INFO] (rapid) INVOKE RTDONE(status: success, produced bytes: 0, duration: 0.724000ms)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Now invoke the hello command:
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
$ mu invoke --local hello
|
|
79
|
+
'Hello World from mu_hello'
|
|
80
|
+
|
|
81
|
+
# with arguments
|
|
82
|
+
$ mu invoke --local hello 'Capt. Picard'
|
|
83
|
+
'Hello Capt. Picard from mu_Hello'
|
|
84
|
+
|
|
85
|
+
# call a Click command
|
|
86
|
+
$ mu invoke --local cli
|
|
87
|
+
47
|
|
88
|
+
|
|
89
|
+
# And you should see the following in the docker shell
|
|
90
|
+
'Hello Alpha Quadrant from mu_Hello'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Usage: AWS
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
This is assuming you are (still) in the `mu_hello` directory and have AWS auth setup. `aws sts
|
|
97
|
+
get-caller-identity` should be working.
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
Verify AWS auth:
|
|
101
|
+
$ mu auth-check
|
|
102
|
+
Account: 429812345678
|
|
103
|
+
Region: us-east-2
|
|
104
|
+
Organization owner: you@example.com
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Note that mu has the concept of an "environment" which is used when naming objects to support
|
|
108
|
+
provision and deployment for beta, prod, etc. There is a default environment that is part of the
|
|
109
|
+
mu config and defaults to `you.your-host`.
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
# Ensure IAM and ECR infra. is in place for the enterprise environment
|
|
114
|
+
$ mu provision enterprise
|
|
115
|
+
info Role created: starfleet-mu-hello-lambda-enterprise
|
|
116
|
+
info Policy created: starfleet-mu-hello-lambda-enterprise-logs
|
|
117
|
+
info Policy created: starfleet-mu-hello-lambda-enterprise-ecr-repo
|
|
118
|
+
info Repository created: starfleet-mu-hello-enterprise
|
|
119
|
+
info Waiting 0.1s for role to be ready
|
|
120
|
+
info Waiting 0.25s for role to be ready
|
|
121
|
+
...[snip]...
|
|
122
|
+
info Provision finished for env: enterprise
|
|
123
|
+
|
|
124
|
+
# Build and push image, setup aws lambda
|
|
125
|
+
$ mu deploy --build enterprise
|
|
126
|
+
info docker compose build --pull
|
|
127
|
+
[+] Building 0.3s (10/10)
|
|
128
|
+
...[snip docker output]...
|
|
129
|
+
info Tagged, pushing...
|
|
130
|
+
info Tagged and pushed: 429829037495.dkr.ecr.us-east-2.amazonaws.com/starfleet-mu-hello-enterprise mu-hello-2024-06-11T21.31.09
|
|
131
|
+
info Deploying: 429829037495.dkr.ecr.us-east-2.amazonaws.com/starfleet-mu-hello-enterprise:mu-hello-2024-06-11T21.31.09
|
|
132
|
+
info Lambda function created: starfleet-mu-hello-handler-enterprise
|
|
133
|
+
info Function arn: arn:aws:lambda:us-east-2:429829037495:function:starfleet-mu-hello-handler-enterprise
|
|
134
|
+
info Waiting for lambda to be updated: starfleet-mu-hello-handler-enterprise
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
$ mu invoke --env enterprise
|
|
138
|
+
{'context': {'aws_request_id': 'cc44e34f-b7f1-4f2a-a314-e4dd2513b229'
|
|
139
|
+
...[snip]...
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
## Usage: Async Tasks
|
|
144
|
+
|
|
145
|
+
Async task workers without a broker/queue:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from flask import Flask
|
|
149
|
+
import mu
|
|
150
|
+
|
|
151
|
+
app = Flask(__name__)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@mu.task
|
|
155
|
+
def ping_task(a, *, b):
|
|
156
|
+
print('ping_task()', a, b)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
@app.route('/ping')
|
|
160
|
+
def ping():
|
|
161
|
+
# ping_task() will be called through async lambda invokation
|
|
162
|
+
ping_task.invoke(1, b=2)
|
|
163
|
+
return 'ok'
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
@mu.task(lambda_func='this-app-bigger-lambda')
|
|
167
|
+
def crunch_big_numbers(a, b, c):
|
|
168
|
+
""" You can change the lambda name but it still needs to be this app. """
|
|
169
|
+
print('crunch_big_numbers()', a, b, c)
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Be mindeful of:
|
|
174
|
+
|
|
175
|
+
- [async invocation](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html)
|
|
176
|
+
- [retries](https://docs.aws.amazon.com/lambda/latest/dg/invocation-retries.html)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
## Dev
|
|
180
|
+
|
|
181
|
+
### Copier Template
|
|
182
|
+
|
|
183
|
+
Project structure and tooling mostly derives from the [Coppy](https://github.com/level12/coppy),
|
|
184
|
+
see its documentation for context and additional instructions.
|
|
185
|
+
|
|
186
|
+
This project can be updated from the upstream repo, see
|
|
187
|
+
[Updating a Project](https://github.com/level12/coppy?tab=readme-ov-file#updating-a-project).
|
|
188
|
+
|
|
189
|
+
### Project Setup
|
|
190
|
+
|
|
191
|
+
From zero to hero (passing tests that is):
|
|
192
|
+
|
|
193
|
+
1. Ensure [host dependencies](https://github.com/level12/coppy/wiki/Mise) are installed
|
|
194
|
+
|
|
195
|
+
2. Sync [project](https://docs.astral.sh/uv/concepts/projects/) virtualenv w/ lock file:
|
|
196
|
+
|
|
197
|
+
`uv sync`
|
|
198
|
+
|
|
199
|
+
3. Configure pre-commit:
|
|
200
|
+
|
|
201
|
+
`pre-commit install`
|
|
202
|
+
|
|
203
|
+
4. Run tests w/ `nox` or `pytest` but see notes just below first.
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
### Testing
|
|
207
|
+
|
|
208
|
+
#### Credentials
|
|
209
|
+
|
|
210
|
+
This project has a lot of integration tests that use live AWS. You SHOULD have a dedicated AWS
|
|
211
|
+
**account** for mu testing.
|
|
212
|
+
|
|
213
|
+
An [env-config](https://github.com/level12/env-config) config is present which will use aws-vault
|
|
214
|
+
and a "mu-test" profile to load AWS creds. But, you can use any method you prefer to setup
|
|
215
|
+
[credentials for boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/credentials.html).
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
#### Running tests
|
|
219
|
+
|
|
220
|
+
- Setup AWS credentials (see notes above)
|
|
221
|
+
- Add `mise.local.toml` to override `MU_TEST_ACCT_ID`
|
|
222
|
+
- `nox` or `pytest`
|
|
223
|
+
- Some integration tests are marked as such (other integration tests should get marked)
|
|
224
|
+
- `pytest -m 'not integration'` ...` will skip integration tests
|
|
225
|
+
- `pytest -m 'integration'` ...` will target integration tests
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
### Versions
|
|
229
|
+
|
|
230
|
+
Versions are date based. A `bump` action exists to help manage versions:
|
|
231
|
+
|
|
232
|
+
```shell
|
|
233
|
+
|
|
234
|
+
# Show current version
|
|
235
|
+
mise bump --show
|
|
236
|
+
|
|
237
|
+
# Bump version based on date, tag, and push:
|
|
238
|
+
mise bump
|
|
239
|
+
|
|
240
|
+
# See other options
|
|
241
|
+
mise bump -- --help
|
|
242
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Example AWS CONFIG
|
|
2
|
+
#
|
|
3
|
+
#
|
|
4
|
+
# [profile example-org]
|
|
5
|
+
# region = us-east-2
|
|
6
|
+
# output = json
|
|
7
|
+
# mfa_serial = arn:aws:iam::...
|
|
8
|
+
# credential_process = env-config-aws example-org
|
|
9
|
+
# envconfig_1pass = op://example-org/Employee/aws-secrets-item
|
|
10
|
+
|
|
11
|
+
# [profile mu-test]
|
|
12
|
+
# source_profile = example-org
|
|
13
|
+
# role_arn = arn:aws:iam::429829037495:role/OrganizationAccountAccessRole
|
|
14
|
+
# region = us-east-2
|
|
15
|
+
|
|
16
|
+
# [profile mu-ci]
|
|
17
|
+
# source_profile = example-org
|
|
18
|
+
# role_arn = arn:aws:iam::429829037495:role/mu-github-ci-role
|
|
19
|
+
# region = us-east-2
|
|
20
|
+
|
|
21
|
+
profile:
|
|
22
|
+
aws-mu-test:
|
|
23
|
+
AWS_PROFILE: mu-test
|
|
24
|
+
aws-mu-ci:
|
|
25
|
+
AWS_PROFILE: mu-ci
|
|
26
|
+
pypi:
|
|
27
|
+
HATCH_INDEX_USER: '__token__'
|
|
28
|
+
HATCH_INDEX_AUTH: 'op://private/pypi.python.org/api-token'
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
FROM public.ecr.aws/lambda/python:3.12
|
|
2
|
+
|
|
3
|
+
WORKDIR ${LAMBDA_TASK_ROOT}
|
|
4
|
+
|
|
5
|
+
# Install the apps's dependencies. This should include mu.
|
|
6
|
+
COPY requirements.txt /tmp/requirements.txt
|
|
7
|
+
|
|
8
|
+
# Its deliberate that this is below requirements. It means these packages will
|
|
9
|
+
# get updated every time our apps' packages get updated.
|
|
10
|
+
RUN pip install --break-system-packages -U pip uv
|
|
11
|
+
|
|
12
|
+
RUN uv pip install --python=/var/lang/bin/python --no-cache-dir -r /tmp/requirements.txt
|
|
13
|
+
|
|
14
|
+
# Now everything to do with the app
|
|
15
|
+
COPY app.py ./
|
|
16
|
+
|
|
17
|
+
# Uncomment this to get the CMD to be updated in the image.
|
|
18
|
+
# RUN echo 'd' > /tmp/annoying.txt
|
|
19
|
+
|
|
20
|
+
CMD ["app.lambda_handler"]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from os import environ
|
|
3
|
+
|
|
4
|
+
import boto3
|
|
5
|
+
from flask import Flask
|
|
6
|
+
|
|
7
|
+
import mu
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
log = logging.getLogger()
|
|
11
|
+
|
|
12
|
+
app = Flask(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@app.route('/')
|
|
16
|
+
def hello_world():
|
|
17
|
+
return '<p>Hello, <strong>World</strong>!</p>'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@app.route('/sqs')
|
|
21
|
+
def sqs():
|
|
22
|
+
sqs = boto3.client('sqs', region_name='us-east-2')
|
|
23
|
+
queue_prefix = environ.get('MU_RESOURCE_IDENT')
|
|
24
|
+
queue_name = f'{queue_prefix}-celery'
|
|
25
|
+
response = sqs.get_queue_url(QueueName=queue_name)
|
|
26
|
+
|
|
27
|
+
return str((response.get('QueueUrl'), environ.get('MU_ENV')))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.route('/log')
|
|
31
|
+
def logs_example():
|
|
32
|
+
log.error('This is an error')
|
|
33
|
+
log.warning('This is a warning')
|
|
34
|
+
log.info('This is an info log')
|
|
35
|
+
log.debug('This is a debug log')
|
|
36
|
+
|
|
37
|
+
return 'Logs emitted at debug, info, warning, and error levels'
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@app.route('/error')
|
|
41
|
+
def error():
|
|
42
|
+
raise RuntimeError('Deliberate runtime error')
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ActionHandler(mu.ActionHandler):
|
|
46
|
+
wsgi_app = app
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
# The entry point for AWS lambda has to be a function
|
|
50
|
+
lambda_handler = ActionHandler.on_event
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
services:
|
|
2
|
+
app:
|
|
3
|
+
image: mu-flask:latest
|
|
4
|
+
container_name: mu-flask
|
|
5
|
+
# The build key is important is it keeps our local docker building new images when changes
|
|
6
|
+
# are made to the project. Without it, once its built, it will keep using the image
|
|
7
|
+
# currently in docker.
|
|
8
|
+
build:
|
|
9
|
+
context: ../..
|
|
10
|
+
dockerfile: examples/flask/Dockerfile
|
|
11
|
+
ports:
|
|
12
|
+
- "127.0.0.1:8080:8080"
|
|
13
|
+
# Use this with `docker compose run` if you need to explore the AWS python image
|
|
14
|
+
runnable:
|
|
15
|
+
image: mu-flask:latest
|
|
16
|
+
entrypoint: /bin/bash
|
|
17
|
+
tty: true
|
|
18
|
+
stdin_open: true
|