azure-deploy-cli 1.0.5__py3-none-any.whl → 1.1.0__py3-none-any.whl
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.
- azure_deploy_cli/_version.py +2 -2
- azure_deploy_cli/aca/aca_cli.py +36 -1
- azure_deploy_cli/aca/deploy_aca.py +9 -1
- azure_deploy_cli/aca/model.py +3 -0
- azure_deploy_cli/utils/docker.py +9 -3
- {azure_deploy_cli-1.0.5.dist-info → azure_deploy_cli-1.1.0.dist-info}/METADATA +1 -1
- {azure_deploy_cli-1.0.5.dist-info → azure_deploy_cli-1.1.0.dist-info}/RECORD +11 -11
- {azure_deploy_cli-1.0.5.dist-info → azure_deploy_cli-1.1.0.dist-info}/WHEEL +0 -0
- {azure_deploy_cli-1.0.5.dist-info → azure_deploy_cli-1.1.0.dist-info}/entry_points.txt +0 -0
- {azure_deploy_cli-1.0.5.dist-info → azure_deploy_cli-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {azure_deploy_cli-1.0.5.dist-info → azure_deploy_cli-1.1.0.dist-info}/top_level.txt +0 -0
azure_deploy_cli/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.0
|
|
32
|
-
__version_tuple__ = version_tuple = (1,
|
|
31
|
+
__version__ = version = '1.1.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 1, 0)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
azure_deploy_cli/aca/aca_cli.py
CHANGED
|
@@ -6,6 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
from azure.mgmt.appcontainers import ContainerAppsAPIClient
|
|
9
|
+
from azure.mgmt.appcontainers.models import IpSecurityRestrictionRule
|
|
9
10
|
|
|
10
11
|
from ..identity.managed_identity import create_or_get_user_identity
|
|
11
12
|
from ..identity.role import assign_role_by_files
|
|
@@ -62,7 +63,9 @@ def _label_weight_pair(pair_str: str) -> tuple[str, int]:
|
|
|
62
63
|
return (label, weight)
|
|
63
64
|
|
|
64
65
|
|
|
65
|
-
def _convert_label_traffic_args(
|
|
66
|
+
def _convert_label_traffic_args(
|
|
67
|
+
label_traffic_list: list[tuple[str, int]],
|
|
68
|
+
) -> dict[str, int]:
|
|
66
69
|
"""
|
|
67
70
|
Convert list of (label, weight) tuples to dictionary.
|
|
68
71
|
|
|
@@ -153,6 +156,19 @@ def cli_deploy(args: Any) -> None:
|
|
|
153
156
|
if not env:
|
|
154
157
|
raise ValueError("Cannot create container app env")
|
|
155
158
|
|
|
159
|
+
ip_rules: list[IpSecurityRestrictionRule] = []
|
|
160
|
+
if args.allowed_ips:
|
|
161
|
+
for name, cidr_ranges in args.allowed_ips:
|
|
162
|
+
for idx, cidr_range in enumerate(cidr_ranges):
|
|
163
|
+
rule = IpSecurityRestrictionRule(
|
|
164
|
+
name=f"{name}-{idx + 1}",
|
|
165
|
+
action="Allow",
|
|
166
|
+
ip_address_range=cidr_range,
|
|
167
|
+
description=f"Allowed {name} IP range",
|
|
168
|
+
)
|
|
169
|
+
ip_rules.append(rule)
|
|
170
|
+
logger.critical(f"Configured {len(ip_rules)} Allowed IP restriction rules.")
|
|
171
|
+
|
|
156
172
|
logger.critical("Deploying new revision...")
|
|
157
173
|
result = deploy_revision(
|
|
158
174
|
client=container_apps_api_client,
|
|
@@ -179,6 +195,7 @@ def cli_deploy(args: Any) -> None:
|
|
|
179
195
|
secret_names=args.env_var_secrets or [],
|
|
180
196
|
user_identity=user_identity,
|
|
181
197
|
),
|
|
198
|
+
ip_rules=ip_rules,
|
|
182
199
|
)
|
|
183
200
|
|
|
184
201
|
if args.custom_domains:
|
|
@@ -430,6 +447,24 @@ def add_commands(subparsers: argparse._SubParsersAction) -> None:
|
|
|
430
447
|
"(includes image names, cpu, memory, env_vars, probes, ingress, and scale settings)",
|
|
431
448
|
)
|
|
432
449
|
|
|
450
|
+
def tuple_ip(value: str) -> tuple[str, list[str]]:
|
|
451
|
+
if "=" not in value:
|
|
452
|
+
raise argparse.ArgumentTypeError(
|
|
453
|
+
f"Invalid format: '{value}'. Expected format: Name=IP1,IP2/CIDR"
|
|
454
|
+
)
|
|
455
|
+
name, ranges = value.split("=")
|
|
456
|
+
cidr_ranges = [cidr.strip() for cidr in ranges.split(",") if cidr.strip()]
|
|
457
|
+
return name, cidr_ranges
|
|
458
|
+
|
|
459
|
+
deploy_parser.add_argument(
|
|
460
|
+
"--allowed-ips",
|
|
461
|
+
nargs="*",
|
|
462
|
+
required=True,
|
|
463
|
+
type=tuple_ip,
|
|
464
|
+
help="List of allowed IP addresses or CIDR ranges for IP restriction. "
|
|
465
|
+
+ "e.g., Name=1.3.5.7/32,2.3.4.3/24 Name2=3.4.5.6/43",
|
|
466
|
+
)
|
|
467
|
+
|
|
433
468
|
deploy_parser.set_defaults(func=cli_deploy)
|
|
434
469
|
|
|
435
470
|
# Add update-traffic command
|
|
@@ -20,6 +20,7 @@ from azure.mgmt.appcontainers.models import (
|
|
|
20
20
|
ContainerResources,
|
|
21
21
|
EnvironmentVar,
|
|
22
22
|
Ingress,
|
|
23
|
+
IpSecurityRestrictionRule,
|
|
23
24
|
LogAnalyticsConfiguration,
|
|
24
25
|
ManagedEnvironment,
|
|
25
26
|
ManagedServiceIdentity,
|
|
@@ -221,7 +222,12 @@ def build_container_images(
|
|
|
221
222
|
source_full_image_name = get_aca_docker_image_name(
|
|
222
223
|
registry_server, container_config.image_name, container_config.existing_image_tag
|
|
223
224
|
)
|
|
224
|
-
|
|
225
|
+
_login_to_acr(registry_server)
|
|
226
|
+
docker.pull_retag_and_push_image(
|
|
227
|
+
source_full_image_name,
|
|
228
|
+
target_full_image_name,
|
|
229
|
+
container_config.existing_image_platform,
|
|
230
|
+
)
|
|
225
231
|
logger.success(f"Image retagged successfully to '{image_tag}'")
|
|
226
232
|
elif container_config.dockerfile:
|
|
227
233
|
logger.info(
|
|
@@ -259,6 +265,7 @@ def deploy_revision(
|
|
|
259
265
|
min_replicas: int,
|
|
260
266
|
max_replicas: int,
|
|
261
267
|
secret_key_vault_config: SecretKeyVaultConfig,
|
|
268
|
+
ip_rules: list[IpSecurityRestrictionRule],
|
|
262
269
|
) -> RevisionDeploymentResult:
|
|
263
270
|
"""
|
|
264
271
|
Deploy a new revision with multiple containers without updating traffic weights.
|
|
@@ -348,6 +355,7 @@ def deploy_revision(
|
|
|
348
355
|
transport=ingress_transport,
|
|
349
356
|
traffic=existing_traffic_weights, # Preserve existing traffic
|
|
350
357
|
custom_domains=existing_custom_domains,
|
|
358
|
+
ip_security_restrictions=ip_rules,
|
|
351
359
|
)
|
|
352
360
|
|
|
353
361
|
revision_name = generate_revision_name(container_app_name, revision_suffix, stage)
|
azure_deploy_cli/aca/model.py
CHANGED
|
@@ -52,6 +52,9 @@ class ContainerConfig(BaseModel):
|
|
|
52
52
|
default=None, description="List of probe configurations"
|
|
53
53
|
)
|
|
54
54
|
existing_image_tag: str | None = Field(default=None, description="Optional tag to retag from")
|
|
55
|
+
existing_image_platform: str | None = Field(
|
|
56
|
+
default=None, description="Optional platform for existing image pull"
|
|
57
|
+
)
|
|
55
58
|
dockerfile: str | None = Field(default=None, description="Optional dockerfile path")
|
|
56
59
|
|
|
57
60
|
def post_init(self):
|
azure_deploy_cli/utils/docker.py
CHANGED
|
@@ -61,17 +61,22 @@ def push_image(full_image_name: str) -> None:
|
|
|
61
61
|
raise RuntimeError("Docker push failed")
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
def pull_image(full_image_name: str) -> None:
|
|
64
|
+
def pull_image(full_image_name: str, platform: str | None = None) -> None:
|
|
65
65
|
"""
|
|
66
66
|
Pull a Docker image from the registry.
|
|
67
67
|
|
|
68
68
|
Args:
|
|
69
69
|
full_image_name: Full image name including registry, repository, and tag
|
|
70
|
+
platform: Optional platform specification (e.g., "linux/amd64")
|
|
70
71
|
|
|
71
72
|
Raises:
|
|
72
73
|
RuntimeError: If the docker pull command fails
|
|
73
74
|
"""
|
|
74
|
-
|
|
75
|
+
cmd = ["docker", "pull"]
|
|
76
|
+
if platform:
|
|
77
|
+
cmd.extend(["--platform", platform])
|
|
78
|
+
cmd.append(full_image_name)
|
|
79
|
+
returncode = _run_and_stream(cmd)
|
|
75
80
|
if returncode != 0:
|
|
76
81
|
raise RuntimeError("Docker pull failed")
|
|
77
82
|
|
|
@@ -95,6 +100,7 @@ def tag_image(source_image: str, target_image: str) -> None:
|
|
|
95
100
|
def pull_retag_and_push_image(
|
|
96
101
|
source_full_image_name: str,
|
|
97
102
|
target_full_image_name: str,
|
|
103
|
+
platform: str | None = None,
|
|
98
104
|
) -> None:
|
|
99
105
|
"""
|
|
100
106
|
Pull an existing image, retag it, and push to registry.
|
|
@@ -107,7 +113,7 @@ def pull_retag_and_push_image(
|
|
|
107
113
|
RuntimeError: If the source image doesn't exist or operations fail
|
|
108
114
|
"""
|
|
109
115
|
if not image_exists(source_full_image_name):
|
|
110
|
-
pull_image(source_full_image_name)
|
|
116
|
+
pull_image(source_full_image_name, platform)
|
|
111
117
|
|
|
112
118
|
tag_image(source_full_image_name, target_full_image_name)
|
|
113
119
|
push_image(target_full_image_name)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: azure-deploy-cli
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Python CLI for Azure deployment automation - identity, roles, and container apps management
|
|
5
5
|
Author-email: decewei <celinew1221@gmail.com>
|
|
6
6
|
License: Mozilla Public License Version 2.0
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
azure_deploy_cli/__init__.py,sha256=Xj8ZMqmqKWc2hhR8rtSETkOmkvrFgh020MYVB_yHp4s,1134
|
|
2
|
-
azure_deploy_cli/_version.py,sha256=
|
|
2
|
+
azure_deploy_cli/_version.py,sha256=ePNVzJOkxR8FY5bezqKQ_fgBRbzH1G7QTaRDHvGQRAY,704
|
|
3
3
|
azure_deploy_cli/cli.py,sha256=I1hXskorvbryjNg0XXdqLjdBuQTPKgZeW03tLHlLxzk,1663
|
|
4
4
|
azure_deploy_cli/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
azure_deploy_cli/aca/aca_cli.py,sha256=
|
|
6
|
-
azure_deploy_cli/aca/deploy_aca.py,sha256=
|
|
7
|
-
azure_deploy_cli/aca/model.py,sha256=
|
|
5
|
+
azure_deploy_cli/aca/aca_cli.py,sha256=Ng7faQLMoK9SEOEOrjrKJpoKq-v7RBlu2WSe7nNXTLo,17323
|
|
6
|
+
azure_deploy_cli/aca/deploy_aca.py,sha256=bABLN9q1qxl84kCN8xX6meNrcFMBwouBECsN8l_TYJA,30804
|
|
7
|
+
azure_deploy_cli/aca/model.py,sha256=elz4p02Apl0seUIA2IBz1KydaOHZpBgTVKbmSiVx_3U,2714
|
|
8
8
|
azure_deploy_cli/aca/yaml_loader.py,sha256=awCJLx88j8ErLm-tLIdV8mFtlSQqGezIqugU0v4m9BI,1413
|
|
9
9
|
azure_deploy_cli/aca/bash/aca-cert/create.sh,sha256=FI3Mdp9qv_DqwiAdxWmZnSY98oRxH1Y6gwDQH4OAxCc,6556
|
|
10
10
|
azure_deploy_cli/aca/bash/aca-cert/destroy.sh,sha256=iao35H_c4YnZHLDpKaYeyd3I7RhHKJzSAUbNovUdcFg,1171
|
|
@@ -18,14 +18,14 @@ azure_deploy_cli/identity/role.py,sha256=WlSJmn54Urar58x4HmJUC0adbeuSTPyW-0lGodv
|
|
|
18
18
|
azure_deploy_cli/identity/service_principal.py,sha256=IDBKVVTQP4PBso0Cv0gcApexKEdXUlKEQ3sMr4OjC1U,7958
|
|
19
19
|
azure_deploy_cli/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
20
|
azure_deploy_cli/utils/azure_cli.py,sha256=mQXHedduPShY6NqG4JePijWJnK3alCMxrTjqHCn2MaM,2576
|
|
21
|
-
azure_deploy_cli/utils/docker.py,sha256=
|
|
21
|
+
azure_deploy_cli/utils/docker.py,sha256=Mqm6S-UCGp2I4XV81z_1rJ_WOGomTmXKmAG3sFKnhfQ,4200
|
|
22
22
|
azure_deploy_cli/utils/env.py,sha256=Qoc0mlrEcyCGk6TLl0AJNfuvhdBuok_93EW2g7Clpu8,3451
|
|
23
23
|
azure_deploy_cli/utils/key_vault.py,sha256=9JYE1pmoPhggU7TZXod_qmu8TgeVmdM0OEIVHPYtPvM,354
|
|
24
24
|
azure_deploy_cli/utils/logging.py,sha256=NxrhhNGnS0SWReKbwJ56A8LYLmjRd77ZBVOVQe9bgQE,3813
|
|
25
25
|
azure_deploy_cli/utils/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
26
|
-
azure_deploy_cli-1.0.
|
|
27
|
-
azure_deploy_cli-1.0.
|
|
28
|
-
azure_deploy_cli-1.0.
|
|
29
|
-
azure_deploy_cli-1.0.
|
|
30
|
-
azure_deploy_cli-1.0.
|
|
31
|
-
azure_deploy_cli-1.0.
|
|
26
|
+
azure_deploy_cli-1.1.0.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
|
|
27
|
+
azure_deploy_cli-1.1.0.dist-info/METADATA,sha256=m3YwByyI6FqYJRGgwisxN64nf_Ev2bIR2w2tnLGGb3g,29137
|
|
28
|
+
azure_deploy_cli-1.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
29
|
+
azure_deploy_cli-1.1.0.dist-info/entry_points.txt,sha256=vuN79v5YJtDi5tF3rCd5qVvCGAMEQMImRHq64B-y-KQ,91
|
|
30
|
+
azure_deploy_cli-1.1.0.dist-info/top_level.txt,sha256=luw_MJJWFd2vFwCtx3wbmihlkCdlZxk1NZou1eToBtU,17
|
|
31
|
+
azure_deploy_cli-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|