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
@@ -0,0 +1,222 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from enum import Enum, StrEnum
|
4
|
+
from typing import TypeAlias
|
5
|
+
|
6
|
+
from pydantic import BaseModel, ConfigDict, Field
|
7
|
+
|
8
|
+
from atlas_init.humps import pascalize
|
9
|
+
|
10
|
+
|
11
|
+
def lowercase_no_snake(name: str) -> str:
|
12
|
+
return name.lower().replace("_", "")
|
13
|
+
|
14
|
+
|
15
|
+
def default_config_dict() -> ConfigDict:
|
16
|
+
return ConfigDict(populate_by_name=True, alias_generator=lowercase_no_snake)
|
17
|
+
|
18
|
+
|
19
|
+
class BaseModelLocal(BaseModel):
|
20
|
+
model_config = default_config_dict()
|
21
|
+
|
22
|
+
|
23
|
+
class ElemType(int, Enum):
|
24
|
+
BOOL = 0
|
25
|
+
FLOAT64 = 1
|
26
|
+
INT64 = 2
|
27
|
+
NUMBER = 3
|
28
|
+
STRING = 4
|
29
|
+
UNKNOWN = 5
|
30
|
+
|
31
|
+
|
32
|
+
class CustomDefault(BaseModelLocal):
|
33
|
+
definition: str
|
34
|
+
imports: list[str]
|
35
|
+
|
36
|
+
|
37
|
+
SnakeCaseString = str
|
38
|
+
|
39
|
+
|
40
|
+
class ComputedOptionalRequired(StrEnum):
|
41
|
+
computed = "computed"
|
42
|
+
computed_optional = "computed_optional"
|
43
|
+
optional = "optional"
|
44
|
+
required = "required"
|
45
|
+
unset = ""
|
46
|
+
|
47
|
+
|
48
|
+
class BoolAttribute(BaseModelLocal):
|
49
|
+
default: bool | None = None
|
50
|
+
|
51
|
+
|
52
|
+
class Float64Attribute(BaseModelLocal):
|
53
|
+
default: float | None = None
|
54
|
+
|
55
|
+
|
56
|
+
class Int64Attribute(BaseModelLocal):
|
57
|
+
default: int | None = None
|
58
|
+
|
59
|
+
|
60
|
+
class MapAttribute(BaseModelLocal):
|
61
|
+
default: CustomDefault | None = None
|
62
|
+
element_type: ElemType
|
63
|
+
|
64
|
+
|
65
|
+
class NestedAttributeObject(BaseModelLocal):
|
66
|
+
attributes: list[Attribute]
|
67
|
+
|
68
|
+
|
69
|
+
class MapNestedAttribute(BaseModelLocal):
|
70
|
+
default: CustomDefault | None = None
|
71
|
+
nested_object: NestedAttributeObject
|
72
|
+
|
73
|
+
|
74
|
+
class NumberAttribute(BaseModelLocal):
|
75
|
+
default: CustomDefault | None = None
|
76
|
+
|
77
|
+
|
78
|
+
class SetAttribute(BaseModelLocal):
|
79
|
+
default: CustomDefault | None = None
|
80
|
+
element_type: ElemType
|
81
|
+
|
82
|
+
|
83
|
+
class SetNestedAttribute(BaseModelLocal):
|
84
|
+
default: CustomDefault | None = None
|
85
|
+
nested_object: NestedAttributeObject
|
86
|
+
|
87
|
+
|
88
|
+
class SingleNestedAttribute(BaseModelLocal):
|
89
|
+
default: CustomDefault | None = None
|
90
|
+
nested_object: NestedAttributeObject
|
91
|
+
|
92
|
+
|
93
|
+
class StringAttribute(BaseModelLocal):
|
94
|
+
default: str | None = None
|
95
|
+
|
96
|
+
|
97
|
+
class ListAttribute(BaseModelLocal):
|
98
|
+
default: CustomDefault | None = None
|
99
|
+
element_type: ElemType
|
100
|
+
|
101
|
+
|
102
|
+
class ListNestedAttribute(BaseModelLocal):
|
103
|
+
default: CustomDefault | None = None
|
104
|
+
nested_object: NestedAttributeObject
|
105
|
+
|
106
|
+
|
107
|
+
class Operation(int, Enum):
|
108
|
+
CREATE = 0
|
109
|
+
UPDATE = 1
|
110
|
+
READ = 2
|
111
|
+
DELETE = 3
|
112
|
+
|
113
|
+
|
114
|
+
class TimeoutsAttribute(BaseModelLocal):
|
115
|
+
configurable_timeouts: list[Operation] = Field(default_factory=list, alias="configurabletimeouts")
|
116
|
+
|
117
|
+
|
118
|
+
NestedModelT: TypeAlias = SetNestedAttribute | ListNestedAttribute | MapNestedAttribute | SingleNestedAttribute
|
119
|
+
|
120
|
+
|
121
|
+
class Attribute(BaseModelLocal):
|
122
|
+
list: ListAttribute | None = None
|
123
|
+
float64: Float64Attribute | None = None
|
124
|
+
string: StringAttribute | None = None
|
125
|
+
bool: BoolAttribute | None = None
|
126
|
+
map: MapAttribute | None = None
|
127
|
+
number: NumberAttribute | None = None
|
128
|
+
set: SetAttribute | None = None
|
129
|
+
int64: Int64Attribute | None = None
|
130
|
+
|
131
|
+
set_nested: SetNestedAttribute | None = None
|
132
|
+
list_nested: ListNestedAttribute | None = None
|
133
|
+
map_nested: MapNestedAttribute | None = None
|
134
|
+
single_nested: SingleNestedAttribute | None = None
|
135
|
+
|
136
|
+
timeouts: TimeoutsAttribute | None = None
|
137
|
+
description: str | None = None
|
138
|
+
name: SnakeCaseString
|
139
|
+
deprecation_message: str | None = None
|
140
|
+
sensitive: bool = False
|
141
|
+
|
142
|
+
computed_optional_required: ComputedOptionalRequired | None = Field(default=None, alias="computedoptionalrequired")
|
143
|
+
|
144
|
+
@property
|
145
|
+
def name_pascal(self):
|
146
|
+
return pascalize(self.name)
|
147
|
+
|
148
|
+
@property
|
149
|
+
def is_nested(self) -> bool:
|
150
|
+
return any([self.single_nested, self.list_nested, self.map_nested, self.set_nested])
|
151
|
+
|
152
|
+
@property
|
153
|
+
def nested_model(self) -> NestedModelT:
|
154
|
+
assert self.is_nested
|
155
|
+
return self.single_nested or self.list_nested or self.map_nested or self.set_nested # type: ignore
|
156
|
+
|
157
|
+
@property
|
158
|
+
def is_attribute(self) -> bool:
|
159
|
+
return self.computed_optional_required != ComputedOptionalRequired.unset
|
160
|
+
|
161
|
+
@property
|
162
|
+
def nested_attributes(self) -> list[Attribute]:
|
163
|
+
return self.nested_model.nested_object.attributes
|
164
|
+
|
165
|
+
@property
|
166
|
+
def is_optional(self) -> bool:
|
167
|
+
return self.computed_optional_required in {
|
168
|
+
ComputedOptionalRequired.optional,
|
169
|
+
ComputedOptionalRequired.computed_optional,
|
170
|
+
ComputedOptionalRequired.computed,
|
171
|
+
}
|
172
|
+
|
173
|
+
@property
|
174
|
+
def is_required(self) -> bool:
|
175
|
+
return self.computed_optional_required == ComputedOptionalRequired.required
|
176
|
+
|
177
|
+
@property
|
178
|
+
def go_type(self) -> str:
|
179
|
+
assert not self.is_nested
|
180
|
+
if self.bool:
|
181
|
+
return "bool"
|
182
|
+
if self.float64:
|
183
|
+
return "float64"
|
184
|
+
if self.int64:
|
185
|
+
return "int64"
|
186
|
+
if self.number:
|
187
|
+
return "number"
|
188
|
+
if self.string:
|
189
|
+
return "string"
|
190
|
+
if self.list:
|
191
|
+
raise NotImplementedError(f"list {self.name}")
|
192
|
+
if self.map:
|
193
|
+
if self.map.element_type == ElemType.STRING:
|
194
|
+
return "map[string]string"
|
195
|
+
raise NotImplementedError(f"map {self.name}")
|
196
|
+
if self.set:
|
197
|
+
raise NotImplementedError(f"set {self.name}")
|
198
|
+
raise NotImplementedError(f"unknown type: {self.name}")
|
199
|
+
|
200
|
+
@property
|
201
|
+
def go_type_optional(self) -> str:
|
202
|
+
assert not self.is_nested, "should find go_type_optional for a nested attribute"
|
203
|
+
return f"*{self.go_type}" if self.is_optional else self.go_type
|
204
|
+
|
205
|
+
|
206
|
+
class Schema(BaseModelLocal):
|
207
|
+
description: str | None = None
|
208
|
+
deprecation_message: str | None = None
|
209
|
+
attributes: list[Attribute]
|
210
|
+
|
211
|
+
|
212
|
+
class Resource(BaseModelLocal):
|
213
|
+
schema: Schema
|
214
|
+
name: SnakeCaseString
|
215
|
+
|
216
|
+
@property
|
217
|
+
def use_timeout(self) -> bool:
|
218
|
+
return any(a.timeouts for a in self.schema.attributes)
|
219
|
+
|
220
|
+
|
221
|
+
ResourceSchemaV3 = Resource
|
222
|
+
TF_MODEL_NAME = "TFModel"
|
@@ -0,0 +1,279 @@
|
|
1
|
+
import logging
|
2
|
+
from functools import singledispatch
|
3
|
+
from queue import Queue
|
4
|
+
|
5
|
+
from atlas_init.cli_tf.schema_v2 import (
|
6
|
+
extend_import_urls,
|
7
|
+
go_fmt,
|
8
|
+
import_lines,
|
9
|
+
package_name,
|
10
|
+
)
|
11
|
+
from atlas_init.cli_tf.schema_v2_sdk import GoVarName, SDKAttribute, SDKModel
|
12
|
+
from atlas_init.cli_tf.schema_v3 import (
|
13
|
+
TF_MODEL_NAME,
|
14
|
+
Attribute,
|
15
|
+
ListNestedAttribute,
|
16
|
+
Resource,
|
17
|
+
SingleNestedAttribute,
|
18
|
+
)
|
19
|
+
from atlas_init.cli_tf.schema_v3_sdk_base import (
|
20
|
+
AllowedMissingAttributeError,
|
21
|
+
SDKAndSchemaAttribute,
|
22
|
+
find_attribute,
|
23
|
+
name_schema_struct,
|
24
|
+
name_struct_attribute,
|
25
|
+
schema_attributes,
|
26
|
+
)
|
27
|
+
from atlas_init.humps import camelize, pascalize
|
28
|
+
|
29
|
+
logger = logging.getLogger(__name__)
|
30
|
+
|
31
|
+
|
32
|
+
def generate_model_go(resource: Resource, sdk_model: SDKModel) -> str:
|
33
|
+
func_lines = sdk_to_tf_func(resource, sdk_model)
|
34
|
+
import_urls = set()
|
35
|
+
extend_import_urls(import_urls, func_lines)
|
36
|
+
unformatted = "\n".join(
|
37
|
+
[
|
38
|
+
f"package {package_name(resource.name)}",
|
39
|
+
"",
|
40
|
+
*import_lines(import_urls),
|
41
|
+
"",
|
42
|
+
*func_lines,
|
43
|
+
]
|
44
|
+
)
|
45
|
+
return go_fmt(resource.name, unformatted)
|
46
|
+
|
47
|
+
|
48
|
+
def sdk_to_tf_func(resource: Resource, sdk_model: SDKModel) -> list[str]:
|
49
|
+
lines = []
|
50
|
+
timeouts_signature = ", timeout timeouts.Value" if resource.use_timeout else ""
|
51
|
+
lines.append(
|
52
|
+
f"func New{TF_MODEL_NAME}(ctx context.Context, {GoVarName.INPUT} *admin.{sdk_model.name}{timeouts_signature}) (*{TF_MODEL_NAME}, diag.Diagnostics) {{"
|
53
|
+
)
|
54
|
+
nested_attributes, call_lines = call_nested_functions(resource, sdk_model.list_nested_attributes())
|
55
|
+
lines.extend(call_lines)
|
56
|
+
timeouts_set = [" Timeouts: timeout,"] if resource.use_timeout else []
|
57
|
+
lines.extend(
|
58
|
+
[
|
59
|
+
f" return &{TF_MODEL_NAME}{{",
|
60
|
+
*tf_struct_create(resource, sdk_model),
|
61
|
+
*timeouts_set,
|
62
|
+
" }, nil", # close return
|
63
|
+
"}\n", # close function
|
64
|
+
]
|
65
|
+
)
|
66
|
+
lines.extend(process_nested_attributes(nested_attributes))
|
67
|
+
return lines
|
68
|
+
|
69
|
+
|
70
|
+
def as_var_name(attr: SDKAttribute) -> str:
|
71
|
+
return camelize(attr.json_name)
|
72
|
+
|
73
|
+
|
74
|
+
def call_nested_functions(
|
75
|
+
root: Resource | Attribute,
|
76
|
+
nested_attributes: list[SDKAttribute],
|
77
|
+
*,
|
78
|
+
return_on_error: bool = True,
|
79
|
+
sdk_var_name: GoVarName = GoVarName.INPUT,
|
80
|
+
) -> tuple[list[SDKAndSchemaAttribute], list[str]]:
|
81
|
+
lines = []
|
82
|
+
schema_nested_attributes = schema_attributes(root)
|
83
|
+
nested_generations = []
|
84
|
+
for sdk_attribute in nested_attributes:
|
85
|
+
try:
|
86
|
+
schema_attribute = find_attribute(schema_nested_attributes, sdk_attribute.tf_name, root.name)
|
87
|
+
except AllowedMissingAttributeError as e:
|
88
|
+
logger.info(f"skipping {e!r}")
|
89
|
+
continue
|
90
|
+
var_name = as_var_name(sdk_attribute)
|
91
|
+
lines.append(
|
92
|
+
f"{var_name} := New{_name_custom_object_type(schema_attribute.name)}(ctx, {sdk_var_name}.{sdk_attribute.struct_name}, {GoVarName.DIAGS})"
|
93
|
+
)
|
94
|
+
nested_generations.append(SDKAndSchemaAttribute(sdk_attribute, schema_attribute))
|
95
|
+
if lines and return_on_error:
|
96
|
+
lines.insert(0, "diags := &diag.Diagnostics{}")
|
97
|
+
lines.extend(
|
98
|
+
[
|
99
|
+
" if diags.HasError() {",
|
100
|
+
" return nil, *diags",
|
101
|
+
" }",
|
102
|
+
]
|
103
|
+
)
|
104
|
+
|
105
|
+
return nested_generations, lines
|
106
|
+
|
107
|
+
|
108
|
+
_sdk_to_tf_funcs = {
|
109
|
+
("*string", "string"): lambda sdk_ref: f"types.StringPointerValue({sdk_ref})",
|
110
|
+
("string", "string"): lambda sdk_ref: f"types.StringValue({sdk_ref})",
|
111
|
+
("*int64", "int64"): lambda sdk_ref: f"types.Int64PointerValue({sdk_ref})",
|
112
|
+
("int64", "int64"): lambda sdk_ref: f"types.Int64Value({sdk_ref})",
|
113
|
+
(
|
114
|
+
"*int",
|
115
|
+
"int64",
|
116
|
+
): lambda sdk_ref: f"types.Int64PointerValue(conversion.IntPtrToInt64Ptr({sdk_ref}))",
|
117
|
+
("*float64", "float64"): lambda sdk_ref: f"types.Float64PointerValue({sdk_ref})",
|
118
|
+
("float64", "float64"): lambda sdk_ref: f"types.Float64Value({sdk_ref})",
|
119
|
+
("*bool", "bool"): lambda sdk_ref: f"types.BoolPointerValue({sdk_ref})",
|
120
|
+
("bool", "bool"): lambda sdk_ref: f"types.BoolValue({sdk_ref})",
|
121
|
+
(
|
122
|
+
"*map[string]string",
|
123
|
+
"map[string]string",
|
124
|
+
): lambda sdk_ref: f"conversion.ToTFMapOfString({GoVarName.CTX}, {GoVarName.DIAGS}, {sdk_ref})",
|
125
|
+
(
|
126
|
+
"map[string]string",
|
127
|
+
"map[string]string",
|
128
|
+
): lambda sdk_ref: f"conversion.ToTFMapOfString({GoVarName.CTX}, {GoVarName.DIAGS}, &{sdk_ref})",
|
129
|
+
(
|
130
|
+
"*time.Time",
|
131
|
+
"string",
|
132
|
+
): lambda sdk_ref: f"types.StringPointerValue(conversion.TimePtrToStringPtr({sdk_ref}))",
|
133
|
+
(
|
134
|
+
"time.Time",
|
135
|
+
"string",
|
136
|
+
): lambda sdk_ref: f"types.StringValue(conversion.TimeToString({sdk_ref}))",
|
137
|
+
}
|
138
|
+
|
139
|
+
|
140
|
+
def sdk_to_tf_attribute_value(
|
141
|
+
schema_attribute: Attribute,
|
142
|
+
sdk_attribute: SDKAttribute,
|
143
|
+
variable_name: GoVarName = GoVarName.INPUT,
|
144
|
+
) -> str:
|
145
|
+
key = (sdk_attribute.go_type, schema_attribute.go_type)
|
146
|
+
if key in _sdk_to_tf_funcs:
|
147
|
+
return _sdk_to_tf_funcs[key](f"{variable_name}.{sdk_attribute.struct_name}")
|
148
|
+
raise ValueError(f"Could not find conversion function for {key}")
|
149
|
+
|
150
|
+
|
151
|
+
# sdk_to_tf_attribute_value(schema_attribute, sdk_attribute, sdk_var_name)
|
152
|
+
def tf_struct_create(
|
153
|
+
root: Resource | Attribute,
|
154
|
+
sdk_model: SDKModel,
|
155
|
+
sdk_var_name: GoVarName = GoVarName.INPUT,
|
156
|
+
) -> list[str]:
|
157
|
+
lines = []
|
158
|
+
for attr in schema_attributes(root):
|
159
|
+
if attr.is_nested:
|
160
|
+
local_var = sdk_model.lookup_tf_name(attr.name)
|
161
|
+
lines.append(f"{name_struct_attribute(attr.name)}: {as_var_name(local_var)},")
|
162
|
+
elif attr.is_attribute:
|
163
|
+
local_var = sdk_model.lookup_tf_name(attr.name)
|
164
|
+
lines.append(
|
165
|
+
f"{name_struct_attribute(attr.name)}: {sdk_to_tf_attribute_value(attr, local_var, sdk_var_name)},"
|
166
|
+
)
|
167
|
+
return lines
|
168
|
+
|
169
|
+
|
170
|
+
def process_nested_attributes(
|
171
|
+
nested_attributes: list[SDKAndSchemaAttribute],
|
172
|
+
) -> list[str]:
|
173
|
+
lines = []
|
174
|
+
queue = Queue()
|
175
|
+
|
176
|
+
def add_nested_to_queue(attributes: list[SDKAndSchemaAttribute]):
|
177
|
+
for nested in attributes:
|
178
|
+
logger.info(f"found nested attribute: {nested.schema_attribute.name}")
|
179
|
+
queue.put(nested)
|
180
|
+
|
181
|
+
add_nested_to_queue(nested_attributes)
|
182
|
+
while not queue.empty():
|
183
|
+
sdk_attribute, schema_attribute = queue.get()
|
184
|
+
more_nested_attributes, nested_lines = convert_nested_attribute(
|
185
|
+
schema_attribute.nested_model, schema_attribute, sdk_attribute
|
186
|
+
)
|
187
|
+
lines.extend(nested_lines)
|
188
|
+
add_nested_to_queue(more_nested_attributes)
|
189
|
+
return lines
|
190
|
+
|
191
|
+
|
192
|
+
def _name_custom_object_type(name: str) -> str:
|
193
|
+
return f"{pascalize(name)}ObjType"
|
194
|
+
|
195
|
+
|
196
|
+
@singledispatch
|
197
|
+
def convert_nested_attribute(
|
198
|
+
nested_model: object, schema_attribute: Attribute, _: SDKAttribute
|
199
|
+
) -> tuple[list[SDKAndSchemaAttribute], list[str]]:
|
200
|
+
raise NotImplementedError(f"unsupported nested attribute: {schema_attribute.name} of type {type(nested_model)}")
|
201
|
+
|
202
|
+
|
203
|
+
@convert_nested_attribute.register
|
204
|
+
def _convert_single_nested_attribute(
|
205
|
+
_: SingleNestedAttribute,
|
206
|
+
schema_attribute: Attribute,
|
207
|
+
sdk_attribute: SDKAttribute,
|
208
|
+
) -> tuple[list[SDKAndSchemaAttribute], list[str]]:
|
209
|
+
object_type_name = _name_custom_object_type(schema_attribute.name)
|
210
|
+
lines: list[str] = [
|
211
|
+
f"func New{object_type_name}(ctx context.Context, {GoVarName.INPUT} *admin.{sdk_attribute.struct_type_name}, diags *diag.Diagnostics) types.Object {{",
|
212
|
+
f" if {GoVarName.INPUT} == nil {{",
|
213
|
+
f" return types.ObjectNull({object_type_name}.AttrTypes)",
|
214
|
+
" }",
|
215
|
+
]
|
216
|
+
|
217
|
+
nested_attributes, call_lines = call_nested_functions(
|
218
|
+
schema_attribute, sdk_attribute.list_nested_attributes(), return_on_error=False
|
219
|
+
)
|
220
|
+
lines.extend(call_lines)
|
221
|
+
struct_name = name_schema_struct(schema_attribute.name)
|
222
|
+
lines.extend(
|
223
|
+
[
|
224
|
+
f" tfModel := {struct_name}{{",
|
225
|
+
*tf_struct_create(schema_attribute, sdk_attribute.as_sdk_model()),
|
226
|
+
" }",
|
227
|
+
f" objType, diagsLocal := types.ObjectValueFrom(ctx, {object_type_name}.AttrTypes, tfModel)",
|
228
|
+
f" {GoVarName.DIAGS}.Append(diagsLocal...)",
|
229
|
+
" return objType",
|
230
|
+
"}\n",
|
231
|
+
]
|
232
|
+
)
|
233
|
+
return nested_attributes, lines
|
234
|
+
|
235
|
+
|
236
|
+
@convert_nested_attribute.register
|
237
|
+
def _convert_list_nested_attriute(
|
238
|
+
_: ListNestedAttribute,
|
239
|
+
schema_attribute: Attribute,
|
240
|
+
sdk_attribute: SDKAttribute,
|
241
|
+
) -> tuple[list[SDKAndSchemaAttribute], list[str]]:
|
242
|
+
object_type_name = _name_custom_object_type(schema_attribute.name)
|
243
|
+
lines: list[str] = [
|
244
|
+
f"func New{object_type_name}(ctx context.Context, {GoVarName.INPUT} *[]admin.{sdk_attribute.struct_type_name}, diags *diag.Diagnostics) types.List {{",
|
245
|
+
f" if {GoVarName.INPUT} == nil {{",
|
246
|
+
f" return types.ListNull({object_type_name})",
|
247
|
+
" }",
|
248
|
+
]
|
249
|
+
struct_name = name_schema_struct(schema_attribute.name)
|
250
|
+
lines.extend(
|
251
|
+
[
|
252
|
+
f" tfModels := make([]{struct_name}, len(*{GoVarName.INPUT}))",
|
253
|
+
f" for i, item := range *{GoVarName.INPUT} {{",
|
254
|
+
]
|
255
|
+
)
|
256
|
+
nested_attributes, call_lines = call_nested_functions(
|
257
|
+
schema_attribute,
|
258
|
+
sdk_attribute.list_nested_attributes(),
|
259
|
+
return_on_error=False,
|
260
|
+
sdk_var_name=GoVarName.ITEM,
|
261
|
+
)
|
262
|
+
lines.extend([f" {line}" for line in call_lines])
|
263
|
+
lines.extend(
|
264
|
+
[
|
265
|
+
f" tfModels[i] = {struct_name}{{",
|
266
|
+
*tf_struct_create(
|
267
|
+
schema_attribute,
|
268
|
+
sdk_attribute.as_sdk_model(),
|
269
|
+
sdk_var_name=GoVarName.ITEM,
|
270
|
+
),
|
271
|
+
" }",
|
272
|
+
" }",
|
273
|
+
f" listType, diagsLocal := types.ListValueFrom(ctx, {object_type_name}, tfModels)",
|
274
|
+
f" {GoVarName.DIAGS}.Append(diagsLocal...)",
|
275
|
+
" return listType",
|
276
|
+
"}\n",
|
277
|
+
]
|
278
|
+
)
|
279
|
+
return nested_attributes, lines
|
@@ -0,0 +1,68 @@
|
|
1
|
+
from functools import singledispatch
|
2
|
+
from typing import NamedTuple
|
3
|
+
|
4
|
+
from atlas_init.cli_tf.schema_v2_sdk import SDKAttribute
|
5
|
+
from atlas_init.cli_tf.schema_v3 import Attribute, Resource
|
6
|
+
from atlas_init.humps import pascalize
|
7
|
+
|
8
|
+
|
9
|
+
class SDKAndSchemaAttribute(NamedTuple):
|
10
|
+
sdk_attribute: SDKAttribute
|
11
|
+
schema_attribute: Attribute
|
12
|
+
|
13
|
+
|
14
|
+
_allowed_missing_attributes: set[str] = set()
|
15
|
+
|
16
|
+
|
17
|
+
def set_allowed_missing_attributes(allowed: set[str]):
|
18
|
+
global _allowed_missing_attributes # noqa: PLW0603 `Using the global statement to update `_allowed_missing_attributes` is discouraged`
|
19
|
+
_allowed_missing_attributes = allowed
|
20
|
+
|
21
|
+
|
22
|
+
class AllowedMissingAttributeError(Exception):
|
23
|
+
def __init__(self, name: str, *args: object) -> None:
|
24
|
+
self.name = name
|
25
|
+
super().__init__(*args)
|
26
|
+
|
27
|
+
|
28
|
+
def find_attribute(attributes: list[Attribute], name: str, root_name: str) -> Attribute:
|
29
|
+
for schema_attribute in attributes:
|
30
|
+
if name == schema_attribute.name:
|
31
|
+
return schema_attribute
|
32
|
+
if name in _allowed_missing_attributes:
|
33
|
+
raise AllowedMissingAttributeError(name)
|
34
|
+
raise ValueError(f"could not find schema attribute for {name} on resource: {root_name}")
|
35
|
+
|
36
|
+
|
37
|
+
@singledispatch
|
38
|
+
def schema_attributes(root: object) -> list[Attribute]:
|
39
|
+
raise NotImplementedError(f"unsupported root type: {type(root)} to find schema attributes")
|
40
|
+
|
41
|
+
|
42
|
+
@schema_attributes.register
|
43
|
+
def _resource_attributes(root: Resource) -> list[Attribute]:
|
44
|
+
return root.schema.attributes
|
45
|
+
|
46
|
+
|
47
|
+
@schema_attributes.register
|
48
|
+
def _attribute_nested(root: Attribute) -> list[Attribute]:
|
49
|
+
return root.nested_attributes
|
50
|
+
|
51
|
+
|
52
|
+
def name_schema_struct(name: str) -> str:
|
53
|
+
return f"TF{pascalize(name)}Model"
|
54
|
+
|
55
|
+
|
56
|
+
def name_struct_attribute(name: str) -> str:
|
57
|
+
default = pascalize(name)
|
58
|
+
if override := _name_attribute_overrides.get(default):
|
59
|
+
return override
|
60
|
+
return default
|
61
|
+
|
62
|
+
|
63
|
+
_name_attribute_overrides = {}
|
64
|
+
|
65
|
+
|
66
|
+
def set_name_attribute_overrides(overrides: dict[str, str]):
|
67
|
+
global _name_attribute_overrides # noqa: PLW0603 `Using the global statement to update `_name_attribute_overrides` is discouraged`
|
68
|
+
_name_attribute_overrides = overrides
|