atlas-init 0.1.0__py3-none-any.whl → 0.1.4__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.
- atlas_init/__init__.py +3 -3
- atlas_init/atlas_init.yaml +51 -34
- atlas_init/cli.py +76 -72
- atlas_init/cli_cfn/app.py +40 -117
- atlas_init/cli_cfn/{cfn.py → aws.py} +129 -14
- atlas_init/cli_cfn/cfn_parameter_finder.py +89 -6
- atlas_init/cli_cfn/example.py +203 -0
- atlas_init/cli_cfn/files.py +63 -0
- atlas_init/cli_helper/go.py +6 -3
- atlas_init/cli_helper/run.py +18 -2
- atlas_init/cli_helper/tf_runner.py +12 -21
- atlas_init/cli_root/__init__.py +0 -0
- atlas_init/cli_root/trigger.py +153 -0
- atlas_init/cli_tf/app.py +211 -4
- atlas_init/cli_tf/changelog.py +103 -0
- atlas_init/cli_tf/debug_logs.py +221 -0
- atlas_init/cli_tf/debug_logs_test_data.py +253 -0
- atlas_init/cli_tf/github_logs.py +229 -0
- atlas_init/cli_tf/go_test_run.py +194 -0
- atlas_init/cli_tf/go_test_run_format.py +31 -0
- atlas_init/cli_tf/go_test_summary.py +144 -0
- atlas_init/cli_tf/hcl/__init__.py +0 -0
- atlas_init/cli_tf/hcl/cli.py +161 -0
- atlas_init/cli_tf/hcl/cluster_mig.py +348 -0
- atlas_init/cli_tf/hcl/parser.py +140 -0
- atlas_init/cli_tf/schema.py +222 -18
- atlas_init/cli_tf/schema_go_parser.py +236 -0
- atlas_init/cli_tf/schema_table.py +150 -0
- atlas_init/cli_tf/schema_table_models.py +155 -0
- atlas_init/cli_tf/schema_v2.py +599 -0
- atlas_init/cli_tf/schema_v2_api_parsing.py +298 -0
- atlas_init/cli_tf/schema_v2_sdk.py +361 -0
- atlas_init/cli_tf/schema_v3.py +222 -0
- atlas_init/cli_tf/schema_v3_sdk.py +279 -0
- atlas_init/cli_tf/schema_v3_sdk_base.py +68 -0
- atlas_init/cli_tf/schema_v3_sdk_create.py +216 -0
- atlas_init/humps.py +253 -0
- atlas_init/repos/cfn.py +6 -1
- atlas_init/repos/path.py +3 -3
- atlas_init/settings/config.py +30 -11
- atlas_init/settings/env_vars.py +29 -3
- atlas_init/settings/path.py +12 -1
- atlas_init/settings/rich_utils.py +39 -2
- atlas_init/terraform.yaml +77 -1
- atlas_init/tf/.terraform.lock.hcl +125 -0
- atlas_init/tf/always.tf +11 -2
- atlas_init/tf/main.tf +3 -0
- atlas_init/tf/modules/aws_s3/provider.tf +1 -1
- atlas_init/tf/modules/aws_vars/aws_vars.tf +2 -0
- atlas_init/tf/modules/aws_vpc/provider.tf +4 -1
- atlas_init/tf/modules/cfn/cfn.tf +47 -33
- atlas_init/tf/modules/cfn/kms.tf +54 -0
- atlas_init/tf/modules/cfn/resource_actions.yaml +1 -0
- atlas_init/tf/modules/cfn/variables.tf +31 -0
- atlas_init/tf/modules/cloud_provider/cloud_provider.tf +1 -0
- atlas_init/tf/modules/cloud_provider/provider.tf +1 -1
- atlas_init/tf/modules/cluster/cluster.tf +34 -24
- atlas_init/tf/modules/cluster/provider.tf +1 -1
- atlas_init/tf/modules/federated_vars/federated_vars.tf +3 -0
- atlas_init/tf/modules/federated_vars/provider.tf +1 -1
- atlas_init/tf/modules/project_extra/project_extra.tf +15 -1
- atlas_init/tf/modules/stream_instance/stream_instance.tf +1 -1
- atlas_init/tf/modules/vpc_peering/vpc_peering.tf +1 -1
- atlas_init/tf/modules/vpc_privatelink/versions.tf +1 -1
- atlas_init/tf/outputs.tf +11 -3
- atlas_init/tf/providers.tf +2 -1
- atlas_init/tf/variables.tf +17 -0
- atlas_init/typer_app.py +76 -0
- {atlas_init-0.1.0.dist-info → atlas_init-0.1.4.dist-info}/METADATA +58 -21
- atlas_init-0.1.4.dist-info/RECORD +91 -0
- {atlas_init-0.1.0.dist-info → atlas_init-0.1.4.dist-info}/WHEEL +1 -1
- atlas_init-0.1.0.dist-info/RECORD +0 -61
- /atlas_init/tf/modules/aws_vpc/{aws-vpc.tf → aws_vpc.tf} +0 -0
- {atlas_init-0.1.0.dist-info → atlas_init-0.1.4.dist-info}/entry_points.txt +0 -0
atlas_init/__init__.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from pathlib import Path
|
2
2
|
|
3
|
-
VERSION = "0.1.
|
3
|
+
VERSION = "0.1.4"
|
4
4
|
|
5
5
|
|
6
6
|
def running_in_repo() -> bool:
|
@@ -8,5 +8,5 @@ def running_in_repo() -> bool:
|
|
8
8
|
if py_directory.name != "py":
|
9
9
|
return False
|
10
10
|
git_directory = py_directory.parent / ".git"
|
11
|
-
|
12
|
-
return git_directory.exists() and
|
11
|
+
git_config = git_directory / "config"
|
12
|
+
return git_directory.exists() and git_config.exists() and "atlas-init" in git_config.read_text()
|
atlas_init/atlas_init.yaml
CHANGED
@@ -1,69 +1,86 @@
|
|
1
1
|
repo_aliases:
|
2
|
-
|
3
|
-
|
2
|
+
mongodb/terraform-provider-mongodbatlas: tf
|
3
|
+
mongodb/mongodbatlas-cloudformation-resources: cfn
|
4
4
|
test_suites:
|
5
5
|
- name: cluster
|
6
6
|
repo_go_packages:
|
7
7
|
cfn:
|
8
|
-
|
8
|
+
- cfn-resources/cluster
|
9
|
+
- name: clusterm10
|
10
|
+
vars:
|
11
|
+
cluster_info_m10: true
|
9
12
|
- name: federated
|
10
13
|
repo_go_packages:
|
11
14
|
tf:
|
12
|
-
|
15
|
+
- internal/service/federatedsettingsorgrolemapping
|
13
16
|
vars:
|
14
17
|
use_federated_vars: true
|
15
|
-
- name:
|
16
|
-
vars:
|
17
|
-
use_project_extra: true
|
18
|
-
repo_go_packages:
|
19
|
-
cfn:
|
20
|
-
- 'cfn-resources/project'
|
21
|
-
- name: network_peering
|
22
|
-
vars:
|
23
|
-
use_aws_vpc: true
|
24
|
-
use_aws_vars: true
|
25
|
-
use_vpc_peering: true
|
18
|
+
- name: network
|
26
19
|
repo_go_packages:
|
27
20
|
tf:
|
28
|
-
-
|
29
|
-
|
30
|
-
vars:
|
21
|
+
- internal/service/privatelinkendpointservicedatafederationonlinearchive
|
22
|
+
vars:
|
31
23
|
use_private_link: true
|
24
|
+
- name: network_peering
|
32
25
|
repo_go_packages:
|
33
26
|
tf:
|
34
|
-
-
|
35
|
-
- name: privatelink
|
27
|
+
- internal/service/networkpeering
|
36
28
|
vars:
|
37
|
-
|
29
|
+
use_vpc_peering: true
|
38
30
|
use_aws_vars: true
|
31
|
+
use_aws_vpc: true
|
32
|
+
- name: private_endpoint_regional_mode
|
39
33
|
repo_go_packages:
|
40
34
|
tf:
|
41
|
-
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
35
|
+
- internal/service/privateendpointregionalmode
|
36
|
+
vars:
|
37
|
+
use_aws_vars: true
|
38
|
+
- name: privatelink
|
39
|
+
repo_go_packages:
|
46
40
|
cfn:
|
47
|
-
-
|
41
|
+
- cfn-resources/cfn-private-endpoint-aws
|
42
|
+
tf:
|
43
|
+
- internal/service/privatelinkendpointservice
|
48
44
|
vars:
|
49
|
-
|
50
|
-
|
51
|
-
- name:
|
45
|
+
use_aws_vars: true
|
46
|
+
use_aws_vpc: true
|
47
|
+
- name: project
|
52
48
|
repo_go_packages:
|
49
|
+
cfn:
|
50
|
+
- cfn-resources/project
|
53
51
|
tf:
|
54
|
-
-
|
52
|
+
- internal/service/project
|
55
53
|
vars:
|
56
|
-
|
54
|
+
use_project_extra: true
|
55
|
+
- name: resource_policy
|
56
|
+
repo_go_packages:
|
57
|
+
cfn:
|
58
|
+
- cfn-resources/resource-policy
|
57
59
|
- name: s3
|
58
60
|
repo_go_packages:
|
59
61
|
tf:
|
60
|
-
-
|
62
|
+
- internal/service/cloudbackupsnapshotexportbucket
|
61
63
|
vars:
|
62
64
|
use_aws_s3: true
|
63
65
|
- name: s3_with_cluster
|
64
66
|
repo_go_packages:
|
65
67
|
tf:
|
66
|
-
-
|
68
|
+
- internal/service/cloudbackupsnapshotexportjob
|
67
69
|
vars:
|
70
|
+
cluster_info_m10: true
|
68
71
|
use_aws_s3: true
|
72
|
+
- name: search_index
|
73
|
+
repo_go_packages:
|
74
|
+
tf:
|
75
|
+
- internal/service/searchindex
|
76
|
+
vars:
|
77
|
+
cluster_info: true
|
78
|
+
- name: stream_connection
|
79
|
+
repo_go_packages:
|
80
|
+
tf:
|
81
|
+
- internal/service/streamconnection
|
82
|
+
cfn:
|
83
|
+
- cfn-resources/stream-connection
|
84
|
+
vars:
|
69
85
|
cluster_info_m10: true
|
86
|
+
stream_instance: true
|
atlas_init/cli.py
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
import logging
|
2
|
-
import sys
|
3
2
|
from collections.abc import Callable
|
4
|
-
from
|
3
|
+
from pathlib import Path
|
5
4
|
from pydoc import locate
|
5
|
+
from typing import Literal
|
6
6
|
|
7
7
|
import typer
|
8
|
+
from model_lib import dump, parse_payload
|
8
9
|
from zero_3rdparty.file_utils import iter_paths
|
9
10
|
|
10
|
-
from atlas_init import running_in_repo
|
11
|
-
from atlas_init.cli_cfn.app import app as app_cfn
|
12
11
|
from atlas_init.cli_helper import sdk_auto_changes
|
12
|
+
from atlas_init.cli_helper.go import run_go_tests
|
13
13
|
from atlas_init.cli_helper.run import (
|
14
14
|
run_binary_command_is_ok,
|
15
15
|
run_command_exit_on_failure,
|
16
|
+
run_command_receive_result,
|
16
17
|
)
|
17
18
|
from atlas_init.cli_helper.sdk import (
|
18
19
|
SDK_VERSION_HELP,
|
@@ -31,7 +32,6 @@ from atlas_init.cli_helper.tf_runner import (
|
|
31
32
|
get_tf_vars,
|
32
33
|
run_terraform,
|
33
34
|
)
|
34
|
-
from atlas_init.cli_tf.app import app as app_tf
|
35
35
|
from atlas_init.repos.go_sdk import go_sdk_breaking_changes
|
36
36
|
from atlas_init.repos.path import (
|
37
37
|
Repo,
|
@@ -43,11 +43,7 @@ from atlas_init.repos.path import (
|
|
43
43
|
)
|
44
44
|
from atlas_init.settings.config import RepoAliasNotFoundError
|
45
45
|
from atlas_init.settings.env_vars import (
|
46
|
-
DEFAULT_PROFILE,
|
47
|
-
AtlasInitSettings,
|
48
46
|
active_suites,
|
49
|
-
as_env_var_name,
|
50
|
-
env_var_names,
|
51
47
|
init_settings,
|
52
48
|
)
|
53
49
|
from atlas_init.settings.path import (
|
@@ -55,57 +51,9 @@ from atlas_init.settings.path import (
|
|
55
51
|
dump_vscode_dotenv,
|
56
52
|
repo_path_rel_path,
|
57
53
|
)
|
58
|
-
from atlas_init.
|
54
|
+
from atlas_init.typer_app import app, app_command, extra_root_commands
|
59
55
|
|
60
56
|
logger = logging.getLogger(__name__)
|
61
|
-
app = typer.Typer(name="atlas_init", invoke_without_command=True, no_args_is_help=True)
|
62
|
-
app.add_typer(app_cfn, name="cfn")
|
63
|
-
app.add_typer(app_tf, name="tf")
|
64
|
-
|
65
|
-
app_command = partial(
|
66
|
-
app.command,
|
67
|
-
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
68
|
-
)
|
69
|
-
|
70
|
-
|
71
|
-
@app.callback(invoke_without_command=True)
|
72
|
-
def main(
|
73
|
-
ctx: typer.Context,
|
74
|
-
log_level: str = typer.Option("INFO", help="use one of [INFO, WARNING, ERROR, CRITICAL]"),
|
75
|
-
profile: str = typer.Option(
|
76
|
-
DEFAULT_PROFILE,
|
77
|
-
"-p",
|
78
|
-
"--profile",
|
79
|
-
envvar=env_var_names("profile"),
|
80
|
-
help="used to load .env_manual, store terraform state and variables, and dump .env files.",
|
81
|
-
),
|
82
|
-
project_name: str = typer.Option(
|
83
|
-
"",
|
84
|
-
"--project",
|
85
|
-
envvar=env_var_names("project_name"),
|
86
|
-
help="atlas project name to create",
|
87
|
-
),
|
88
|
-
):
|
89
|
-
explicit_env_vars: dict[str, str] = {}
|
90
|
-
if project_name != "":
|
91
|
-
explicit_env_vars[as_env_var_name("project_name")] = project_name
|
92
|
-
configure_logging(log_level)
|
93
|
-
logger.info(f"running in repo: {running_in_repo()} python location:{sys.executable}")
|
94
|
-
missing_env_vars, ambiguous_env_vars = AtlasInitSettings.check_env_vars(
|
95
|
-
profile,
|
96
|
-
required_extra_fields=["project_name"],
|
97
|
-
explicit_env_vars=explicit_env_vars,
|
98
|
-
)
|
99
|
-
if missing_env_vars:
|
100
|
-
typer.echo(f"missing env_vars: {missing_env_vars}")
|
101
|
-
if ambiguous_env_vars:
|
102
|
-
typer.echo(
|
103
|
-
f"amiguous env_vars: {missing_env_vars} (specified both in cli & in .env-manual file with different values)"
|
104
|
-
)
|
105
|
-
if missing_env_vars or ambiguous_env_vars:
|
106
|
-
raise typer.Exit(1)
|
107
|
-
command = ctx.invoked_subcommand
|
108
|
-
logger.info(f"in the app callback, log-level: {log_level}, command: {command}")
|
109
57
|
|
110
58
|
|
111
59
|
@app_command()
|
@@ -116,12 +64,19 @@ def init(context: typer.Context):
|
|
116
64
|
run_terraform(settings, "init", extra_args)
|
117
65
|
|
118
66
|
|
67
|
+
@app_command()
|
68
|
+
def plan(context: typer.Context, *, skip_outputs: bool = False):
|
69
|
+
_plan_or_apply(context.args, "plan", skip_outputs=skip_outputs)
|
70
|
+
|
71
|
+
|
119
72
|
@app_command()
|
120
73
|
def apply(context: typer.Context, *, skip_outputs: bool = False):
|
74
|
+
_plan_or_apply(context.args, "apply", skip_outputs=skip_outputs)
|
75
|
+
|
76
|
+
|
77
|
+
def _plan_or_apply(extra_args: list[str], command: Literal["plan", "apply"], *, skip_outputs: bool):
|
121
78
|
settings = init_settings()
|
122
|
-
|
123
|
-
logger.info(f"apply extra args: {extra_args}")
|
124
|
-
logger.info("in the apply command")
|
79
|
+
logger.info(f"using the '{command}' command, extra args: {extra_args}")
|
125
80
|
try:
|
126
81
|
suites = active_suites(settings)
|
127
82
|
except (CwdIsNoRepoPathError, RepoAliasNotFoundError) as e:
|
@@ -132,10 +87,10 @@ def apply(context: typer.Context, *, skip_outputs: bool = False):
|
|
132
87
|
dump_tf_vars(settings, tf_vars)
|
133
88
|
|
134
89
|
try:
|
135
|
-
run_terraform(settings,
|
90
|
+
run_terraform(settings, command, extra_args)
|
136
91
|
except TerraformRunError as e:
|
137
92
|
logger.error(repr(e)) # noqa: TRY400
|
138
|
-
|
93
|
+
raise typer.Exit(1) from e
|
139
94
|
|
140
95
|
if not skip_outputs:
|
141
96
|
export_outputs(settings)
|
@@ -149,6 +104,9 @@ def apply(context: typer.Context, *, skip_outputs: bool = False):
|
|
149
104
|
def destroy(context: typer.Context):
|
150
105
|
extra_args = context.args
|
151
106
|
settings = init_settings()
|
107
|
+
if not settings.tf_state_path.exists():
|
108
|
+
logger.warning(f"no terraform state found {settings.tf_state_path}, exiting")
|
109
|
+
return
|
152
110
|
tf_vars = get_tf_vars(settings, [])
|
153
111
|
dump_tf_vars(settings, tf_vars)
|
154
112
|
try:
|
@@ -164,9 +122,15 @@ def test_go():
|
|
164
122
|
suites = active_suites(settings)
|
165
123
|
sorted_suites = sorted(suite.name for suite in suites)
|
166
124
|
logger.info(f"running go tests for {len(suites)} test-suites: {sorted_suites}")
|
167
|
-
|
168
|
-
|
169
|
-
|
125
|
+
match repo_alias := current_repo():
|
126
|
+
case Repo.CFN:
|
127
|
+
raise NotImplementedError
|
128
|
+
case Repo.TF:
|
129
|
+
repo_path = current_repo_path()
|
130
|
+
package_prefix = settings.config.go_package_prefix(repo_alias)
|
131
|
+
run_go_tests(repo_path, repo_alias, package_prefix, settings, suites)
|
132
|
+
case _:
|
133
|
+
raise NotImplementedError
|
170
134
|
|
171
135
|
|
172
136
|
@app_command()
|
@@ -186,8 +150,10 @@ def sdk_upgrade(
|
|
186
150
|
|
187
151
|
sdk_breaking_changes_path = go_sdk_breaking_changes(repo_path)
|
188
152
|
all_breaking_changes = parse_breaking_changes(sdk_breaking_changes_path, old, new)
|
189
|
-
|
190
|
-
|
153
|
+
replacements = {
|
154
|
+
f"go.mongodb.org/atlas-sdk/{old}/mockadmin": f"go.mongodb.org/atlas-sdk/{new}/mockadmin",
|
155
|
+
f"go.mongodb.org/atlas-sdk/{old}/admin": f"go.mongodb.org/atlas-sdk/{new}/admin",
|
156
|
+
}
|
191
157
|
auto_modifier: Callable[[str, str], str] | None = None
|
192
158
|
if auto_change_name:
|
193
159
|
func_path = f"{sdk_auto_changes.__name__}.{auto_change_name}"
|
@@ -198,7 +164,7 @@ def sdk_upgrade(
|
|
198
164
|
resources_breaking_changes: set[str] = set()
|
199
165
|
for path in iter_paths(repo_path, "*.go", ".mockery.yaml"):
|
200
166
|
text_old = path.read_text()
|
201
|
-
if replace_in not in text_old:
|
167
|
+
if all(replace_in not in text_old for replace_in in replacements):
|
202
168
|
continue
|
203
169
|
r_name = resource_name(repo_path, path)
|
204
170
|
if resource and resource != r_name:
|
@@ -210,7 +176,9 @@ def sdk_upgrade(
|
|
210
176
|
logger.warning(f"found breaking changes: {changes_formatted}")
|
211
177
|
if is_removed(breaking_changes):
|
212
178
|
resources_breaking_changes.add(r_name)
|
213
|
-
text_new = text_old
|
179
|
+
text_new = text_old
|
180
|
+
for replace_in, replace_out in replacements.items():
|
181
|
+
text_new = text_new.replace(replace_in, replace_out)
|
214
182
|
if not dry_run:
|
215
183
|
if auto_modifier:
|
216
184
|
text_new = auto_modifier(text_new, old)
|
@@ -237,18 +205,22 @@ def sdk_upgrade(
|
|
237
205
|
def pre_commit(
|
238
206
|
skip_build: bool = typer.Option(default=False),
|
239
207
|
skip_lint: bool = typer.Option(default=False),
|
208
|
+
max_issues: int = typer.Option(1000, "-m", "--max"),
|
240
209
|
):
|
210
|
+
golang_ci_lint_args = f"--max-same-issues {max_issues} --max-issues-per-linter {max_issues}"
|
241
211
|
match current_repo():
|
242
212
|
case Repo.CFN:
|
243
213
|
repo_path, resource_path, r_name = find_paths()
|
244
214
|
build_cmd = f"cd {resource_path} && make build"
|
245
215
|
# TODO: understand why piping to grep doesn't work
|
246
216
|
# f"golangci-lint run --path-prefix=./cfn-resources | grep {r_name}"
|
247
|
-
format_cmd_str =
|
217
|
+
format_cmd_str = (
|
218
|
+
f"cd cfn-resources && golangci-lint run --path-prefix=./cfn-resources {golang_ci_lint_args}"
|
219
|
+
)
|
248
220
|
case Repo.TF:
|
249
221
|
repo_path = current_repo_path()
|
250
222
|
build_cmd = "make build"
|
251
|
-
format_cmd_str = "golangci-lint run"
|
223
|
+
format_cmd_str = f"golangci-lint run {golang_ci_lint_args}"
|
252
224
|
case _:
|
253
225
|
raise NotImplementedError
|
254
226
|
if skip_build:
|
@@ -261,7 +233,39 @@ def pre_commit(
|
|
261
233
|
run_command_exit_on_failure(format_cmd_str, cwd=repo_path, logger=logger)
|
262
234
|
|
263
235
|
|
236
|
+
@app_command()
|
237
|
+
def repo_dump():
|
238
|
+
code_root = Path.home() / "code"
|
239
|
+
path_urls = {}
|
240
|
+
for repo_git_path in iter_paths(code_root, ".git", exclude_folder_names=[".terraform"]):
|
241
|
+
repo_path = repo_git_path.parent
|
242
|
+
logger.info(f"repo: {repo_path}")
|
243
|
+
url = run_command_receive_result("git remote get-url origin", cwd=repo_path, logger=logger, can_fail=True)
|
244
|
+
if url.startswith("FAIL:"):
|
245
|
+
continue
|
246
|
+
path_urls[str(repo_path)] = url
|
247
|
+
out_path = code_root / "repos.json"
|
248
|
+
repos_json = dump(path_urls, "pretty_json")
|
249
|
+
out_path.write_text(repos_json)
|
250
|
+
|
251
|
+
|
252
|
+
@app_command()
|
253
|
+
def repo_clone():
|
254
|
+
repos_file = Path.home() / "code" / "repos.json"
|
255
|
+
repo_path_json: dict[str, str] = parse_payload(repos_file) # type: ignore
|
256
|
+
for repo_path_str, url in repo_path_json.items():
|
257
|
+
logger.info(f"cloning {url} @ {repo_path_str}")
|
258
|
+
repo_path = Path(repo_path_str)
|
259
|
+
parent_dir = repo_path.parent
|
260
|
+
parent_dir.mkdir(parents=True, exist_ok=True)
|
261
|
+
if repo_path.exists():
|
262
|
+
logger.warning(f"skipping {repo_path}, already exists")
|
263
|
+
continue
|
264
|
+
run_command_exit_on_failure(f"git clone {url} {repo_path.name}", cwd=parent_dir, logger=logger)
|
265
|
+
|
266
|
+
|
264
267
|
def typer_main():
|
268
|
+
extra_root_commands()
|
265
269
|
app()
|
266
270
|
|
267
271
|
|
atlas_init/cli_cfn/app.py
CHANGED
@@ -1,42 +1,35 @@
|
|
1
1
|
import logging
|
2
2
|
import os
|
3
|
-
from pathlib import Path
|
4
3
|
|
5
4
|
import typer
|
6
|
-
from model_lib import
|
7
|
-
from rich import prompt
|
5
|
+
from model_lib import parse_payload
|
8
6
|
from zero_3rdparty.file_utils import clean_dir
|
9
7
|
|
10
|
-
from atlas_init.
|
11
|
-
from atlas_init.cli_cfn.cfn import (
|
8
|
+
from atlas_init.cli_cfn.aws import (
|
12
9
|
activate_resource_type,
|
13
|
-
create_stack,
|
14
10
|
deactivate_third_party_type,
|
15
|
-
delete_stack,
|
16
11
|
deregister_cfn_resource_type,
|
17
12
|
get_last_cfn_type,
|
18
|
-
|
13
|
+
wait_on_stack_ok,
|
14
|
+
)
|
15
|
+
from atlas_init.cli_cfn.aws import (
|
16
|
+
delete_stack as delete_stack_aws,
|
19
17
|
)
|
20
18
|
from atlas_init.cli_cfn.cfn_parameter_finder import (
|
21
|
-
check_execution_role,
|
22
|
-
decode_parameters,
|
23
|
-
infer_template_path,
|
24
19
|
read_execution_role,
|
25
20
|
)
|
21
|
+
from atlas_init.cli_cfn.example import example_cmd
|
22
|
+
from atlas_init.cli_cfn.files import create_sample_file, has_md_link, iterate_schemas
|
26
23
|
from atlas_init.cli_helper.run import run_command_is_ok
|
27
24
|
from atlas_init.cloud.aws import run_in_regions
|
28
25
|
from atlas_init.repos.cfn import (
|
29
|
-
CfnOperation,
|
30
|
-
CfnType,
|
31
|
-
Operation,
|
32
|
-
infer_cfn_type_name,
|
33
26
|
validate_type_name_regions,
|
34
27
|
)
|
35
|
-
from atlas_init.repos.path import Repo, current_dir, find_paths
|
28
|
+
from atlas_init.repos.path import Repo, current_dir, find_paths, resource_root
|
36
29
|
from atlas_init.settings.env_vars import active_suites, init_settings
|
37
|
-
from atlas_init.settings.interactive import confirm
|
38
30
|
|
39
31
|
app = typer.Typer(no_args_is_help=True)
|
32
|
+
app.command(name="example")(example_cmd)
|
40
33
|
logger = logging.getLogger(__name__)
|
41
34
|
|
42
35
|
|
@@ -92,104 +85,6 @@ def dereg(
|
|
92
85
|
run_in_regions(deactivate, regions)
|
93
86
|
|
94
87
|
|
95
|
-
@app.command()
|
96
|
-
def example(
|
97
|
-
type_name: str = typer.Argument(default_factory=infer_cfn_type_name),
|
98
|
-
region: str = typer.Argument(...),
|
99
|
-
stack_name: str = typer.Argument(...),
|
100
|
-
operation: str = typer.Argument(...),
|
101
|
-
params: list[str] = typer.Option(..., "-p", default_factory=list),
|
102
|
-
resource_params: list[str] = typer.Option(..., "-r", default_factory=list),
|
103
|
-
stack_timeout_s: int = typer.Option(300, "-t", "--stack-timeout-s"),
|
104
|
-
):
|
105
|
-
params_parsed: dict[str, str] = {}
|
106
|
-
if params:
|
107
|
-
params_parsed = parse_key_values(params)
|
108
|
-
resource_params_parsed = {}
|
109
|
-
if resource_params:
|
110
|
-
resource_params_parsed = parse_key_values_any(resource_params)
|
111
|
-
if resource_params_parsed:
|
112
|
-
logger.info(f"using resource params: {resource_params_parsed}")
|
113
|
-
logger.info(f"about to update stack {stack_name} for {type_name} in {region} with {operation}, params: {params}")
|
114
|
-
settings = init_settings()
|
115
|
-
type_name, region = CfnType.validate_type_region(type_name, region) # type: ignore
|
116
|
-
CfnOperation(operaton=operation) # type: ignore
|
117
|
-
repo_path, resource_path, _ = find_paths(Repo.CFN)
|
118
|
-
env_vars_generated = settings.load_env_vars_generated()
|
119
|
-
cfn_execution_role = check_execution_role(repo_path, env_vars_generated)
|
120
|
-
|
121
|
-
cfn_type_details = get_last_cfn_type(type_name, region, is_third_party=False)
|
122
|
-
logger.info(f"found cfn_type_details {cfn_type_details} for {type_name}")
|
123
|
-
submit_cmd = f"cfn submit --verbose --set-default --region {region} --role-arn {cfn_execution_role}"
|
124
|
-
if cfn_type_details is None and confirm(
|
125
|
-
f"No existing {type_name} found, ok to run:\n{submit_cmd}\nsubmit?",
|
126
|
-
is_interactive=settings.is_interactive,
|
127
|
-
default=True,
|
128
|
-
):
|
129
|
-
assert run_command_is_ok(cmd=submit_cmd.split(), env=None, cwd=resource_path, logger=logger)
|
130
|
-
cfn_type_details = get_last_cfn_type(type_name, region, is_third_party=False)
|
131
|
-
assert cfn_type_details, f"no cfn_type_details found for {type_name}"
|
132
|
-
|
133
|
-
if operation == Operation.DELETE:
|
134
|
-
delete_stack(region, stack_name)
|
135
|
-
return
|
136
|
-
template_path = infer_template_path(repo_path, type_name, stack_name)
|
137
|
-
template_path, parameters, not_found = decode_parameters(
|
138
|
-
exported_env_vars=env_vars_generated,
|
139
|
-
template_path=template_path,
|
140
|
-
stack_name=stack_name,
|
141
|
-
force_params=params_parsed,
|
142
|
-
resource_params=resource_params_parsed,
|
143
|
-
type_name=type_name,
|
144
|
-
)
|
145
|
-
logger.info(f"parameters: {parameters}")
|
146
|
-
if not_found:
|
147
|
-
# TODO: support specifying these extra
|
148
|
-
logger.critical(f"need to fill out parameters manually: {not_found} for {type_name}")
|
149
|
-
raise typer.Exit(1)
|
150
|
-
if not prompt.Confirm("parameters 👆looks good?")():
|
151
|
-
raise typer.Exit(1)
|
152
|
-
if operation == Operation.CREATE:
|
153
|
-
create_stack(
|
154
|
-
stack_name,
|
155
|
-
template_str=template_path.read_text(),
|
156
|
-
region_name=region,
|
157
|
-
role_arn=cfn_execution_role,
|
158
|
-
parameters=parameters,
|
159
|
-
timeout_seconds=stack_timeout_s,
|
160
|
-
)
|
161
|
-
elif operation == Operation.UPDATE:
|
162
|
-
update_stack(
|
163
|
-
stack_name,
|
164
|
-
template_str=template_path.read_text(),
|
165
|
-
region_name=region,
|
166
|
-
parameters=parameters,
|
167
|
-
role_arn=cfn_execution_role,
|
168
|
-
timeout_seconds=stack_timeout_s,
|
169
|
-
)
|
170
|
-
else:
|
171
|
-
raise NotImplementedError
|
172
|
-
|
173
|
-
|
174
|
-
def _create_sample_file(
|
175
|
-
samples_file: Path,
|
176
|
-
log_group_name: str,
|
177
|
-
resource_state: dict,
|
178
|
-
prev_resource_state: dict | None = None,
|
179
|
-
):
|
180
|
-
logger.info(f"adding sample @ {samples_file}")
|
181
|
-
assert isinstance(resource_state, dict)
|
182
|
-
new_json = dump(
|
183
|
-
{
|
184
|
-
"providerLogGroupName": log_group_name,
|
185
|
-
"previousResourceState": prev_resource_state or {},
|
186
|
-
"desiredResourceState": resource_state,
|
187
|
-
},
|
188
|
-
"json",
|
189
|
-
)
|
190
|
-
samples_file.write_text(new_json)
|
191
|
-
|
192
|
-
|
193
88
|
@app.command()
|
194
89
|
def inputs(
|
195
90
|
context: typer.Context,
|
@@ -240,11 +135,11 @@ def inputs(
|
|
240
135
|
assert isinstance(resource_state, dict), f"input file with not a dict {resource_state}"
|
241
136
|
samples_file = samples_dir / file.name
|
242
137
|
if file.name.endswith("_create.json"):
|
243
|
-
|
138
|
+
create_sample_file(samples_file, log_group_name, resource_state)
|
244
139
|
if file.name.endswith("_update.json"):
|
245
140
|
prev_state_path = file.parent / file.name.replace("_update.json", "_create.json")
|
246
141
|
prev_state: dict = parse_payload(prev_state_path) # type: ignore
|
247
|
-
|
142
|
+
create_sample_file(
|
248
143
|
samples_file,
|
249
144
|
log_group_name,
|
250
145
|
resource_state,
|
@@ -256,3 +151,31 @@ def inputs(
|
|
256
151
|
new_filename = inputs_dir / new_name
|
257
152
|
file.rename(new_filename)
|
258
153
|
logger.info(f"renamed from {file} -> {new_filename}")
|
154
|
+
|
155
|
+
|
156
|
+
@app.command()
|
157
|
+
def gen_docs():
|
158
|
+
repo_path, *_ = find_paths(Repo.CFN)
|
159
|
+
root = resource_root(repo_path)
|
160
|
+
for path, schema in iterate_schemas(root):
|
161
|
+
if has_md_link(schema.description):
|
162
|
+
logger.warning(f"found md link in {schema.type_name} in {path}")
|
163
|
+
|
164
|
+
|
165
|
+
@app.command()
|
166
|
+
def wait_on_stack(
|
167
|
+
stack_name: str = typer.Argument(...),
|
168
|
+
region: str = typer.Argument(...),
|
169
|
+
timeout_s: int = typer.Option(300, "-t", "--timeout-seconds"),
|
170
|
+
):
|
171
|
+
wait_on_stack_ok(stack_name, region, timeout_seconds=timeout_s)
|
172
|
+
logger.info(f"stack {stack_name} in {region} is ready ✅")
|
173
|
+
|
174
|
+
|
175
|
+
@app.command()
|
176
|
+
def delete_stack(
|
177
|
+
stack_name: str = typer.Argument(...),
|
178
|
+
region: str = typer.Argument(...),
|
179
|
+
):
|
180
|
+
delete_stack_aws(region, stack_name)
|
181
|
+
logger.info(f"stack {stack_name} in {region} is deleted ✅")
|