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.
Files changed (108) hide show
  1. aws_mu-0.20250611.3/.ci/.gitignore +2 -0
  2. aws_mu-0.20250611.3/.ci/pytest.ini +7 -0
  3. aws_mu-0.20250611.3/.circleci/config.yml +39 -0
  4. aws_mu-0.20250611.3/.copier-answers-py.yaml +19 -0
  5. aws_mu-0.20250611.3/.coveragerc +18 -0
  6. aws_mu-0.20250611.3/.dockerignore +6 -0
  7. aws_mu-0.20250611.3/.editorconfig +38 -0
  8. aws_mu-0.20250611.3/.github/workflows/nox.yaml +47 -0
  9. aws_mu-0.20250611.3/.github/workflows/pypi.yaml +60 -0
  10. aws_mu-0.20250611.3/.gitignore +39 -0
  11. aws_mu-0.20250611.3/.pre-commit-config.yaml +34 -0
  12. aws_mu-0.20250611.3/.python-version +1 -0
  13. aws_mu-0.20250611.3/PKG-INFO +242 -0
  14. aws_mu-0.20250611.3/ci/.gitignore +2 -0
  15. aws_mu-0.20250611.3/env-config.yaml +28 -0
  16. aws_mu-0.20250611.3/examples/apprunner/Dockerfile +20 -0
  17. aws_mu-0.20250611.3/examples/apprunner/app.py +50 -0
  18. aws_mu-0.20250611.3/examples/apprunner/compose.yaml +18 -0
  19. aws_mu-0.20250611.3/examples/apprunner/mu.toml +7 -0
  20. aws_mu-0.20250611.3/examples/apprunner/pyproject.toml +3 -0
  21. aws_mu-0.20250611.3/examples/apprunner/requirements.txt +2 -0
  22. aws_mu-0.20250611.3/examples/flask/Dockerfile +20 -0
  23. aws_mu-0.20250611.3/examples/flask/app.py +50 -0
  24. aws_mu-0.20250611.3/examples/flask/compose.yaml +18 -0
  25. aws_mu-0.20250611.3/examples/flask/mu.toml +9 -0
  26. aws_mu-0.20250611.3/examples/flask/pyproject.toml +3 -0
  27. aws_mu-0.20250611.3/examples/flask/requirements.txt +2 -0
  28. aws_mu-0.20250611.3/examples/mu_hello/Dockerfile +15 -0
  29. aws_mu-0.20250611.3/examples/mu_hello/compose.yaml +20 -0
  30. aws_mu-0.20250611.3/examples/mu_hello/mu.toml +26 -0
  31. aws_mu-0.20250611.3/examples/mu_hello/mu_hello.py +39 -0
  32. aws_mu-0.20250611.3/examples/mu_hello/pyproject.toml +3 -0
  33. aws_mu-0.20250611.3/examples/mu_hello/requirements.txt +1 -0
  34. aws_mu-0.20250611.3/examples/tasker/Dockerfile +22 -0
  35. aws_mu-0.20250611.3/examples/tasker/app.py +26 -0
  36. aws_mu-0.20250611.3/examples/tasker/compose.yaml +18 -0
  37. aws_mu-0.20250611.3/examples/tasker/handler.py +11 -0
  38. aws_mu-0.20250611.3/examples/tasker/mu.toml +3 -0
  39. aws_mu-0.20250611.3/examples/tasker/pyproject.toml +3 -0
  40. aws_mu-0.20250611.3/examples/tasker/requirements.txt +3 -0
  41. aws_mu-0.20250611.3/hatch.toml +18 -0
  42. aws_mu-0.20250611.3/misc/lambda-logs-example.txt +44 -0
  43. aws_mu-0.20250611.3/mise.toml +23 -0
  44. aws_mu-0.20250611.3/noxfile.py +46 -0
  45. aws_mu-0.20250611.3/pyproject.toml +74 -0
  46. aws_mu-0.20250611.3/readme.md +225 -0
  47. aws_mu-0.20250611.3/ruff.toml +94 -0
  48. aws_mu-0.20250611.3/src/conftest.py +45 -0
  49. aws_mu-0.20250611.3/src/mu/__init__.py +2 -0
  50. aws_mu-0.20250611.3/src/mu/cli/__init__.py +2 -0
  51. aws_mu-0.20250611.3/src/mu/cli/aws.py +164 -0
  52. aws_mu-0.20250611.3/src/mu/cli/core.py +196 -0
  53. aws_mu-0.20250611.3/src/mu/config.py +228 -0
  54. aws_mu-0.20250611.3/src/mu/exc.py +10 -0
  55. aws_mu-0.20250611.3/src/mu/handler.py +139 -0
  56. aws_mu-0.20250611.3/src/mu/handlers/diagnostics.py +23 -0
  57. aws_mu-0.20250611.3/src/mu/libs/__init__.py +0 -0
  58. aws_mu-0.20250611.3/src/mu/libs/api_gateway.py +89 -0
  59. aws_mu-0.20250611.3/src/mu/libs/auth.py +27 -0
  60. aws_mu-0.20250611.3/src/mu/libs/aws_recs.py +94 -0
  61. aws_mu-0.20250611.3/src/mu/libs/concurrent.py +93 -0
  62. aws_mu-0.20250611.3/src/mu/libs/ec2.py +28 -0
  63. aws_mu-0.20250611.3/src/mu/libs/ecr.py +310 -0
  64. aws_mu-0.20250611.3/src/mu/libs/ecs.py +86 -0
  65. aws_mu-0.20250611.3/src/mu/libs/gateway.py +322 -0
  66. aws_mu-0.20250611.3/src/mu/libs/iam.py +275 -0
  67. aws_mu-0.20250611.3/src/mu/libs/lamb.py +755 -0
  68. aws_mu-0.20250611.3/src/mu/libs/logs.py +69 -0
  69. aws_mu-0.20250611.3/src/mu/libs/orgs.py +12 -0
  70. aws_mu-0.20250611.3/src/mu/libs/sqs.py +121 -0
  71. aws_mu-0.20250611.3/src/mu/libs/status.py +103 -0
  72. aws_mu-0.20250611.3/src/mu/libs/sts.py +14 -0
  73. aws_mu-0.20250611.3/src/mu/libs/testing.py +120 -0
  74. aws_mu-0.20250611.3/src/mu/libs/utils.py +176 -0
  75. aws_mu-0.20250611.3/src/mu/tasks.py +98 -0
  76. aws_mu-0.20250611.3/src/mu/version.py +1 -0
  77. aws_mu-0.20250611.3/src/mu_tasks_lib.py +29 -0
  78. aws_mu-0.20250611.3/src/mu_tests/__init__.py +0 -0
  79. aws_mu-0.20250611.3/src/mu_tests/conftest.py +35 -0
  80. aws_mu-0.20250611.3/src/mu_tests/data/__init__.py +0 -0
  81. aws_mu-0.20250611.3/src/mu_tests/data/event_wsgi.py +55 -0
  82. aws_mu-0.20250611.3/src/mu_tests/data/exc-extras.txt +19 -0
  83. aws_mu-0.20250611.3/src/mu_tests/data/log_events.py +36 -0
  84. aws_mu-0.20250611.3/src/mu_tests/data/platform-report.txt +6 -0
  85. aws_mu-0.20250611.3/src/mu_tests/data/platform-start.txt +1 -0
  86. aws_mu-0.20250611.3/src/mu_tests/data/text-message.txt +2 -0
  87. aws_mu-0.20250611.3/src/mu_tests/data/unhandled-exc.txt +25 -0
  88. aws_mu-0.20250611.3/src/mu_tests/fake.py +124 -0
  89. aws_mu-0.20250611.3/src/mu_tests/mocking.py +263 -0
  90. aws_mu-0.20250611.3/src/mu_tests/pkg-sqs/pyproject.toml +13 -0
  91. aws_mu-0.20250611.3/src/mu_tests/pkg1/pyproject.toml +10 -0
  92. aws_mu-0.20250611.3/src/mu_tests/pkg2/mu.toml +3 -0
  93. aws_mu-0.20250611.3/src/mu_tests/pkg2/pyproject.toml +2 -0
  94. aws_mu-0.20250611.3/src/mu_tests/test_config.py +63 -0
  95. aws_mu-0.20250611.3/src/mu_tests/test_ecr.py +84 -0
  96. aws_mu-0.20250611.3/src/mu_tests/test_ecs.py +33 -0
  97. aws_mu-0.20250611.3/src/mu_tests/test_handler.py +84 -0
  98. aws_mu-0.20250611.3/src/mu_tests/test_iam.py +75 -0
  99. aws_mu-0.20250611.3/src/mu_tests/test_lamb.py +256 -0
  100. aws_mu-0.20250611.3/src/mu_tests/test_libs_gateway.py +498 -0
  101. aws_mu-0.20250611.3/src/mu_tests/test_libs_utils.py +23 -0
  102. aws_mu-0.20250611.3/src/mu_tests/test_sqs.py +82 -0
  103. aws_mu-0.20250611.3/src/mu_tests/test_tasks.py +110 -0
  104. aws_mu-0.20250611.3/tasks/bump +80 -0
  105. aws_mu-0.20250611.3/tasks/create-ci-iam-role.py +235 -0
  106. aws_mu-0.20250611.3/tasks/create-testing-acm-cert.py +32 -0
  107. aws_mu-0.20250611.3/tox.ini +70 -0
  108. aws_mu-0.20250611.3/uv.lock +1378 -0
@@ -0,0 +1,2 @@
1
+ artifacts
2
+ test-reports
@@ -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,6 @@
1
+ ./events
2
+ ./misc
3
+ ./requirements
4
+ ./*.*
5
+ *.pyc
6
+ .git
@@ -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
+ [![nox](https://github.com/level12/mu/actions/workflows/nox.yaml/badge.svg)](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,2 @@
1
+ artifacts
2
+ test-reports
@@ -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