af-cicd 0.1.4__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.
- af_cicd-0.1.4/PKG-INFO +101 -0
- af_cicd-0.1.4/README.md +83 -0
- af_cicd-0.1.4/allfly/__init__.py +0 -0
- af_cicd-0.1.4/allfly/aws/__init__.py +0 -0
- af_cicd-0.1.4/allfly/aws/core.py +36 -0
- af_cicd-0.1.4/allfly/aws/ecr.py +110 -0
- af_cicd-0.1.4/allfly/aws/ecs.py +80 -0
- af_cicd-0.1.4/allfly/aws/lambdas.py +18 -0
- af_cicd-0.1.4/allfly/aws/ssm.py +19 -0
- af_cicd-0.1.4/allfly/cicd.py +314 -0
- af_cicd-0.1.4/allfly/commands/__init__.py +0 -0
- af_cicd-0.1.4/allfly/commands/aws.py +39 -0
- af_cicd-0.1.4/allfly/commands/constants.py +8 -0
- af_cicd-0.1.4/allfly/commands/docker.py +105 -0
- af_cicd-0.1.4/allfly/commands/git.py +121 -0
- af_cicd-0.1.4/allfly/commands/orchestrations.py +163 -0
- af_cicd-0.1.4/allfly/commands/slack.py +78 -0
- af_cicd-0.1.4/allfly/commands/terraform.py +90 -0
- af_cicd-0.1.4/allfly/config.py +98 -0
- af_cicd-0.1.4/allfly/models.py +117 -0
- af_cicd-0.1.4/allfly/readme.md +26 -0
- af_cicd-0.1.4/allfly/utils.py +135 -0
- af_cicd-0.1.4/pyproject.toml +37 -0
af_cicd-0.1.4/PKG-INFO
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: af-cicd
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: shared cicd tooling
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: hello
|
|
7
|
+
Author-email: hello@allfly.io
|
|
8
|
+
Requires-Python: >=3.13,<4.0
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Dist: boto3 (>=1.35.5,<2.0.0)
|
|
14
|
+
Requires-Dist: inquirer (>=3.3.0,<4.0.0)
|
|
15
|
+
Requires-Dist: slack-sdk (>=3.34.0,<4.0.0)
|
|
16
|
+
Requires-Dist: typer[slim] (>=0.20.0,<0.21.0)
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# tools-cicd
|
|
20
|
+
share cicd scripts
|
|
21
|
+
|
|
22
|
+
# Running tool locally
|
|
23
|
+
|
|
24
|
+
## Example:
|
|
25
|
+
```shell
|
|
26
|
+
AWS_PROFILE=dev-admin-terraform poetry run cicd --help
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
# Release Procedures
|
|
30
|
+
- This project uses "trunk" based development off of `master`.
|
|
31
|
+
- PRs are allowed but always folded back to `master`.
|
|
32
|
+
- For now, releasing is manual, no automation.
|
|
33
|
+
- **To release**:
|
|
34
|
+
- Ensure all your features are ready on `master`
|
|
35
|
+
- *You should not have any staged changes!*
|
|
36
|
+
- In a terminal run `make version v={major|minor|patch}`
|
|
37
|
+
- **Do not include a number! Poetry will auto-rev the value accordingly**
|
|
38
|
+
- That's it
|
|
39
|
+
- This will create a new tag in Git ready for use
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Multi-Repository Release Coordination
|
|
43
|
+
|
|
44
|
+
The `quest-v2` project includes a coordinated release script that allows you to trigger deployments across all related Quest v2 repositories simultaneously, rather than having to manually trigger each repository's release workflow individually.
|
|
45
|
+
|
|
46
|
+
### Prerequisites
|
|
47
|
+
|
|
48
|
+
1. **GitHub CLI**: Install the GitHub CLI tool
|
|
49
|
+
```bash
|
|
50
|
+
# macOS
|
|
51
|
+
brew install gh
|
|
52
|
+
|
|
53
|
+
# Ubuntu/Debian
|
|
54
|
+
sudo apt install gh
|
|
55
|
+
|
|
56
|
+
# Windows
|
|
57
|
+
winget install GitHub.cli
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
2. **Authentication**: Authenticate with GitHub
|
|
61
|
+
```bash
|
|
62
|
+
gh auth login
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
3. **Script Setup**: Navigate to the quest-v2 directory and make the script executable
|
|
66
|
+
```bash
|
|
67
|
+
cd quest-v2
|
|
68
|
+
chmod +x release-all.sh
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Usage
|
|
72
|
+
|
|
73
|
+
From the `quest-v2` directory, the script supports promoting from `develop` to `qa`:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Promote to QA
|
|
77
|
+
./release-all.sh
|
|
78
|
+
|
|
79
|
+
# Show help and options
|
|
80
|
+
./release-all.sh --help
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### What it does
|
|
84
|
+
|
|
85
|
+
The script will:
|
|
86
|
+
1. Trigger the "Release" workflow on all three Quest v2 repositories:
|
|
87
|
+
- `allfly-quest-ui`
|
|
88
|
+
- `allfly-quest-core-api`
|
|
89
|
+
- `gds-api`
|
|
90
|
+
2. Promote code from `develop` branch to `qa`
|
|
91
|
+
3. Provide real-time status updates and links to monitor progress
|
|
92
|
+
4. Display a summary of successful and failed releases
|
|
93
|
+
|
|
94
|
+
### Monitoring
|
|
95
|
+
|
|
96
|
+
After triggering the releases, you can monitor progress through:
|
|
97
|
+
- The provided GitHub Actions URLs in the script output
|
|
98
|
+
- GitHub's Actions tab in each repository
|
|
99
|
+
- Your configured Slack notifications (if enabled)
|
|
100
|
+
|
|
101
|
+
> **Note**: The script requires appropriate permissions to trigger workflows on all three Quest v2 repositories. Ensure your GitHub account has the necessary access rights.
|
af_cicd-0.1.4/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# tools-cicd
|
|
2
|
+
share cicd scripts
|
|
3
|
+
|
|
4
|
+
# Running tool locally
|
|
5
|
+
|
|
6
|
+
## Example:
|
|
7
|
+
```shell
|
|
8
|
+
AWS_PROFILE=dev-admin-terraform poetry run cicd --help
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
# Release Procedures
|
|
12
|
+
- This project uses "trunk" based development off of `master`.
|
|
13
|
+
- PRs are allowed but always folded back to `master`.
|
|
14
|
+
- For now, releasing is manual, no automation.
|
|
15
|
+
- **To release**:
|
|
16
|
+
- Ensure all your features are ready on `master`
|
|
17
|
+
- *You should not have any staged changes!*
|
|
18
|
+
- In a terminal run `make version v={major|minor|patch}`
|
|
19
|
+
- **Do not include a number! Poetry will auto-rev the value accordingly**
|
|
20
|
+
- That's it
|
|
21
|
+
- This will create a new tag in Git ready for use
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Multi-Repository Release Coordination
|
|
25
|
+
|
|
26
|
+
The `quest-v2` project includes a coordinated release script that allows you to trigger deployments across all related Quest v2 repositories simultaneously, rather than having to manually trigger each repository's release workflow individually.
|
|
27
|
+
|
|
28
|
+
### Prerequisites
|
|
29
|
+
|
|
30
|
+
1. **GitHub CLI**: Install the GitHub CLI tool
|
|
31
|
+
```bash
|
|
32
|
+
# macOS
|
|
33
|
+
brew install gh
|
|
34
|
+
|
|
35
|
+
# Ubuntu/Debian
|
|
36
|
+
sudo apt install gh
|
|
37
|
+
|
|
38
|
+
# Windows
|
|
39
|
+
winget install GitHub.cli
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
2. **Authentication**: Authenticate with GitHub
|
|
43
|
+
```bash
|
|
44
|
+
gh auth login
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
3. **Script Setup**: Navigate to the quest-v2 directory and make the script executable
|
|
48
|
+
```bash
|
|
49
|
+
cd quest-v2
|
|
50
|
+
chmod +x release-all.sh
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Usage
|
|
54
|
+
|
|
55
|
+
From the `quest-v2` directory, the script supports promoting from `develop` to `qa`:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# Promote to QA
|
|
59
|
+
./release-all.sh
|
|
60
|
+
|
|
61
|
+
# Show help and options
|
|
62
|
+
./release-all.sh --help
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### What it does
|
|
66
|
+
|
|
67
|
+
The script will:
|
|
68
|
+
1. Trigger the "Release" workflow on all three Quest v2 repositories:
|
|
69
|
+
- `allfly-quest-ui`
|
|
70
|
+
- `allfly-quest-core-api`
|
|
71
|
+
- `gds-api`
|
|
72
|
+
2. Promote code from `develop` branch to `qa`
|
|
73
|
+
3. Provide real-time status updates and links to monitor progress
|
|
74
|
+
4. Display a summary of successful and failed releases
|
|
75
|
+
|
|
76
|
+
### Monitoring
|
|
77
|
+
|
|
78
|
+
After triggering the releases, you can monitor progress through:
|
|
79
|
+
- The provided GitHub Actions URLs in the script output
|
|
80
|
+
- GitHub's Actions tab in each repository
|
|
81
|
+
- Your configured Slack notifications (if enabled)
|
|
82
|
+
|
|
83
|
+
> **Note**: The script requires appropriate permissions to trigger workflows on all three Quest v2 repositories. Ensure your GitHub account has the necessary access rights.
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
import boto3
|
|
4
|
+
|
|
5
|
+
from allfly.utils import get_exit_code, run_shell_command, stdout
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AWSCore:
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def get_current_user_region():
|
|
12
|
+
current_session = boto3.session.Session()
|
|
13
|
+
current_region = (
|
|
14
|
+
current_session.region_name if current_session.region_name else "us-east-1"
|
|
15
|
+
)
|
|
16
|
+
stdout(f"Current region: {current_region}")
|
|
17
|
+
return current_region
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def is_aws_profile_is_active(profile: str):
|
|
21
|
+
return get_exit_code(f'aws s3 ls --profile {profile}') == 0
|
|
22
|
+
|
|
23
|
+
@staticmethod
|
|
24
|
+
def setup_aws_creds(cicd: bool = False):
|
|
25
|
+
"""
|
|
26
|
+
In CI/CD environments, there are no AWS profiles, so we don't need to set the AWS_PROFILE environment variable
|
|
27
|
+
"""
|
|
28
|
+
aws_profile = os.environ.get('AWS_PROFILE', None)
|
|
29
|
+
stdout(f"AWS_PROFILE is set to: {aws_profile}")
|
|
30
|
+
if aws_profile and not cicd:
|
|
31
|
+
# If the AWS profile is not active, re-authenticate with AWS
|
|
32
|
+
if not AWSCore.is_aws_profile_is_active(aws_profile):
|
|
33
|
+
stdout(
|
|
34
|
+
f'AWS profile {aws_profile} is not active. Re-authenticating with AWS...'
|
|
35
|
+
)
|
|
36
|
+
run_shell_command(f'aws sso login --profile {aws_profile}')
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import boto3
|
|
2
|
+
from botocore.client import BaseClient
|
|
3
|
+
|
|
4
|
+
from allfly.utils import stdout, stderr
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AwsEcr:
|
|
8
|
+
ecr: BaseClient
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.ecr = boto3.client("ecr")
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
def build_ecr_image_url(app_name: str, image_tag: str, ecr_account_id: str) -> str:
|
|
15
|
+
return f"{ecr_account_id}.dkr.ecr.us-east-1.amazonaws.com/{app_name}:{image_tag}"
|
|
16
|
+
|
|
17
|
+
def promote_ecr_docker_tag(
|
|
18
|
+
self, app_name: str, ecr_account_id: str, source_branch_tag: str, target_branch_tag: str
|
|
19
|
+
) -> str:
|
|
20
|
+
"""
|
|
21
|
+
Re-tag an ECR image without having to pull and push.
|
|
22
|
+
Based on https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-retag.html
|
|
23
|
+
|
|
24
|
+
return the full image URL of the container to be used in the next environment
|
|
25
|
+
"""
|
|
26
|
+
stdout("Re-tagging image...")
|
|
27
|
+
|
|
28
|
+
# First, we need to get all associated images for the source (from) environment
|
|
29
|
+
associated_version_tag = self.get_next_image_tag(
|
|
30
|
+
ecr_account_id=ecr_account_id,
|
|
31
|
+
app_name=app_name,
|
|
32
|
+
source_branch_tag=source_branch_tag
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# Now, we need to get the imageManifest; unfortunately, another call
|
|
36
|
+
get_image_response = self.ecr.batch_get_image(
|
|
37
|
+
registryId=ecr_account_id,
|
|
38
|
+
repositoryName=app_name,
|
|
39
|
+
imageIds=[{"imageTag": associated_version_tag}],
|
|
40
|
+
)
|
|
41
|
+
images = get_image_response.get("images")
|
|
42
|
+
if not images:
|
|
43
|
+
raise Exception(
|
|
44
|
+
f"Failed to get image, could not find image with tag {source_branch_tag}"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
image = images[0]
|
|
48
|
+
image_manifest = image.get("imageManifest")
|
|
49
|
+
|
|
50
|
+
# Now, we re-tag for AWS (to) environment
|
|
51
|
+
stdout(f"Re-tagging {associated_version_tag} now to {target_branch_tag}")
|
|
52
|
+
try:
|
|
53
|
+
self.ecr.put_image(
|
|
54
|
+
registryId=ecr_account_id,
|
|
55
|
+
repositoryName=app_name,
|
|
56
|
+
imageManifest=image_manifest,
|
|
57
|
+
imageTag=target_branch_tag,
|
|
58
|
+
)
|
|
59
|
+
except self.ecr.exceptions.ImageAlreadyExistsException as e:
|
|
60
|
+
stderr(f"Image tag already {target_branch_tag} exists with that manifest, that's okay.")
|
|
61
|
+
|
|
62
|
+
return self.build_ecr_image_url(
|
|
63
|
+
app_name=app_name,
|
|
64
|
+
image_tag=associated_version_tag,
|
|
65
|
+
ecr_account_id=ecr_account_id,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
def get_next_image_tag(self,
|
|
69
|
+
ecr_account_id: str,
|
|
70
|
+
app_name: str,
|
|
71
|
+
source_branch_tag: str):
|
|
72
|
+
"""
|
|
73
|
+
the purpose of this function is to get the image tag that is associated with the previous environment
|
|
74
|
+
|
|
75
|
+
for example: from develop to qa, one might see
|
|
76
|
+
found associated tag develop
|
|
77
|
+
found associated tag v.2025.01.13.212928.18
|
|
78
|
+
|
|
79
|
+
v.2025.01.13.212928.18 would be returned to promote to qa
|
|
80
|
+
"""
|
|
81
|
+
describe_image_response = self.ecr.describe_images(
|
|
82
|
+
registryId=ecr_account_id,
|
|
83
|
+
repositoryName=app_name,
|
|
84
|
+
imageIds=[{"imageTag": source_branch_tag}],
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# To do things right, we need to get the v. version associated with the previous environment so it's passed
|
|
88
|
+
# on to the next environment
|
|
89
|
+
stdout(f"looking for versioned image associated to tag {source_branch_tag}")
|
|
90
|
+
image_details = describe_image_response.get("imageDetails")
|
|
91
|
+
if not image_details:
|
|
92
|
+
raise Exception(
|
|
93
|
+
f"Failed to describe image for {source_branch_tag}; no images returned"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
aws_image = image_details[0]
|
|
97
|
+
|
|
98
|
+
associated_version_tag = None
|
|
99
|
+
image_tags = aws_image.get("imageTags")
|
|
100
|
+
for tag in image_tags:
|
|
101
|
+
stdout(f"found associated tag {tag}")
|
|
102
|
+
if tag.startswith("v."):
|
|
103
|
+
associated_version_tag = tag
|
|
104
|
+
|
|
105
|
+
if not associated_version_tag:
|
|
106
|
+
raise Exception(
|
|
107
|
+
f"Could not find associated version tag for {source_branch_tag}! Something is wrong."
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
return associated_version_tag
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
from typing_extensions import deprecated
|
|
2
|
+
|
|
3
|
+
import boto3
|
|
4
|
+
from allfly.aws.ssm import AwsSSM
|
|
5
|
+
from allfly.utils import run_shell_command, stdout, exit_with_error
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AwsEcs:
|
|
9
|
+
ssm: AwsSSM
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.ssm = AwsSSM()
|
|
13
|
+
|
|
14
|
+
@deprecated("here are backup in case TF based deployments don't pan out")
|
|
15
|
+
def deploy_image_tag_to_ecs_app(self, app_name: str, tag: str):
|
|
16
|
+
service_id = self.ssm.get_ssm_param_value(f"/infra/services/{app_name}/ecs/cluster_id")
|
|
17
|
+
cluster_id = self.ssm.get_ssm_param_value(f"/infra/services/{app_name}/ecs/service_id")
|
|
18
|
+
stdout(f"Deploying to ecs {cluster_id} {service_id} {tag}")
|
|
19
|
+
run_shell_command(
|
|
20
|
+
f'ecs deploy {cluster_id} {service_id} --tag {tag}'
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
def run_pre_deploy_task(self, app_name: str, task_family: str, new_image_url: str) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Run a one-off ECS Fargate task before the main service deployment.
|
|
26
|
+
|
|
27
|
+
Runs the latest revision of task_family — the targeted terraform apply
|
|
28
|
+
in Phase 1 already registered a new revision with the correct image.
|
|
29
|
+
Clones network configuration from the running service so no extra
|
|
30
|
+
SSM params are needed.
|
|
31
|
+
|
|
32
|
+
Raises a hard exit if the task fails to start or exits non-zero.
|
|
33
|
+
"""
|
|
34
|
+
cluster_id = self.ssm.get_ssm_param_value(f"/infra/services/{app_name}/ecs/cluster_id")
|
|
35
|
+
service_name = self.ssm.get_ssm_param_value(f"/infra/services/{app_name}/ecs/service_id")
|
|
36
|
+
|
|
37
|
+
client = boto3.client("ecs")
|
|
38
|
+
|
|
39
|
+
# Clone network config from the live service — keeps subnets/SGs consistent
|
|
40
|
+
services_response = client.describe_services(cluster=cluster_id, services=[service_name])
|
|
41
|
+
services = services_response.get("services", [])
|
|
42
|
+
if not services:
|
|
43
|
+
exit_with_error(f"Could not find ECS service '{service_name}' in cluster '{cluster_id}'")
|
|
44
|
+
network_config = services[0]["networkConfiguration"]
|
|
45
|
+
|
|
46
|
+
stdout(f"Running pre-deploy task '{task_family}' with image {new_image_url}")
|
|
47
|
+
|
|
48
|
+
run_response = client.run_task(
|
|
49
|
+
cluster=cluster_id,
|
|
50
|
+
taskDefinition=task_family,
|
|
51
|
+
launchType="FARGATE",
|
|
52
|
+
networkConfiguration=network_config,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
failures = run_response.get("failures", [])
|
|
56
|
+
tasks = run_response.get("tasks", [])
|
|
57
|
+
if failures or not tasks:
|
|
58
|
+
exit_with_error(f"Failed to start pre-deploy task '{task_family}': {failures}")
|
|
59
|
+
|
|
60
|
+
task_arn = tasks[0]["taskArn"]
|
|
61
|
+
stdout(f"Pre-deploy task started: {task_arn} — waiting for completion...")
|
|
62
|
+
|
|
63
|
+
waiter = client.get_waiter("tasks_stopped")
|
|
64
|
+
waiter.wait(
|
|
65
|
+
cluster=cluster_id,
|
|
66
|
+
tasks=[task_arn],
|
|
67
|
+
WaiterConfig={"Delay": 10, "MaxAttempts": 60}, # up to 10 minutes
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
describe_response = client.describe_tasks(cluster=cluster_id, tasks=[task_arn])
|
|
71
|
+
container = describe_response["tasks"][0]["containers"][0]
|
|
72
|
+
exit_code = container.get("exitCode")
|
|
73
|
+
|
|
74
|
+
if exit_code != 0:
|
|
75
|
+
exit_with_error(
|
|
76
|
+
f"Pre-deploy task '{task_family}' failed with exit code {exit_code}. "
|
|
77
|
+
f"Halting deployment."
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
stdout(f"Pre-deploy task '{task_family}' completed successfully.")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import boto3
|
|
2
|
+
from botocore.client import BaseClient
|
|
3
|
+
|
|
4
|
+
from allfly.utils import stdout
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AwsLambda:
|
|
8
|
+
client: BaseClient
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.client = boto3.client('lambda')
|
|
12
|
+
|
|
13
|
+
def update_lambda_image_with_image_url(self, app_name: str, image_url: str):
|
|
14
|
+
stdout("Deploying Lambda function...")
|
|
15
|
+
self.client.update_function_code(
|
|
16
|
+
FunctionName=f"{app_name}", ImageUri=image_url, Publish=True
|
|
17
|
+
)
|
|
18
|
+
stdout("Lambda function deployed successfully.")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import boto3
|
|
2
|
+
from botocore.client import BaseClient
|
|
3
|
+
|
|
4
|
+
from allfly.utils import exit_with_error
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AwsSSM:
|
|
8
|
+
client: BaseClient
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
self.client = boto3.client('ssm')
|
|
12
|
+
|
|
13
|
+
def get_ssm_param_value(self, param_name: str, is_encrypted=False) -> str | None:
|
|
14
|
+
|
|
15
|
+
try:
|
|
16
|
+
response = self.client.get_parameter(Name=param_name, WithDecryption=is_encrypted)
|
|
17
|
+
return response['Parameter']['Value']
|
|
18
|
+
except self.client.exceptions.ParameterNotFound:
|
|
19
|
+
exit_with_error(f"Could not find ssm param value {param_name}")
|