1use serde::{Deserialize, Deserializer};
4
5pub mod aws;
6pub mod azure;
7pub mod gcp;
8pub mod kubernetes_cluster;
9
10pub use aws::{
11 AwsAiImportData, AwsArtifactRegistryImportData, AwsBuildImportData,
12 AwsComputeClusterImportData, AwsEmailDkimTokenImportData, AwsEmailDomainImportData,
13 AwsEmailImportData, AwsKvImportData, AwsNetworkImportData, AwsOpenSearchImportData,
14 AwsPostgresImportData, AwsQueueImportData, AwsRemoteBindingsImportData,
15 AwsRemoteStackManagementImportData, AwsServiceAccountImportData, AwsStorageImportData,
16 AwsVaultImportData, AwsWorkerImportData,
17};
18pub use azure::{
19 AzureAiImportData, AzureArtifactRegistryImportData, AzureBuildImportData,
20 AzureComputeClusterImportData, AzureContainerAppsEnvironmentImportData,
21 AzureFlexibleServerPostgresImportData, AzureKvImportData, AzureNetworkImportData,
22 AzureQueueImportData, AzureRemoteBindingsImportData, AzureRemoteStackManagementImportData,
23 AzureResourceGroupImportData, AzureServiceAccountImportData, AzureServiceActivationImportData,
24 AzureServiceBusNamespaceImportData, AzureStorageAccountImportData, AzureStorageImportData,
25 AzureVaultImportData, AzureWorkerImportData,
26};
27pub use gcp::{
28 GcpAiImportData, GcpArtifactRegistryImportData, GcpBuildImportData,
29 GcpComputeClusterImportData, GcpKvImportData, GcpNetworkImportData, GcpPostgresImportData,
30 GcpQueueImportData, GcpRemoteBindingsImportData, GcpRemoteStackManagementImportData,
31 GcpServiceAccountImportData, GcpServiceActivationImportData, GcpStorageImportData,
32 GcpVaultImportData, GcpWorkerImportData,
33};
34pub use kubernetes_cluster::{
35 AzureApplicationGatewayForContainersBootstrap, KubernetesClusterImportData,
36};
37
38pub(crate) fn deserialize_bool_from_bool_or_string<'de, D>(
39 deserializer: D,
40) -> Result<bool, D::Error>
41where
42 D: Deserializer<'de>,
43{
44 let value = serde_json::Value::deserialize(deserializer)?;
45 match value {
46 serde_json::Value::Bool(value) => Ok(value),
47 serde_json::Value::String(value) if value.eq_ignore_ascii_case("true") => Ok(true),
48 serde_json::Value::String(value) if value.eq_ignore_ascii_case("false") => Ok(false),
49 other => Err(serde::de::Error::custom(format!(
50 "expected boolean or boolean string, got {other}"
51 ))),
52 }
53}
54
55#[cfg(all(test, feature = "jsonschema"))]
56mod schema_snapshots {
57 use super::*;
58 use indexmap::IndexMap;
59
60 fn schema<T: schemars::JsonSchema>() -> serde_json::Value {
61 serde_json::to_value(schemars::schema_for!(T)).expect("schema should serialize")
62 }
63
64 #[test]
65 fn import_data_schema_snapshot() {
66 let schemas = IndexMap::from([
67 ("aws_ai", schema::<AwsAiImportData>()),
68 (
69 "aws_artifact_registry",
70 schema::<AwsArtifactRegistryImportData>(),
71 ),
72 ("aws_build", schema::<AwsBuildImportData>()),
73 (
74 "aws_compute_cluster",
75 schema::<AwsComputeClusterImportData>(),
76 ),
77 ("aws_email", schema::<AwsEmailImportData>()),
78 ("aws_function", schema::<AwsWorkerImportData>()),
79 ("aws_kv", schema::<AwsKvImportData>()),
80 ("aws_network", schema::<AwsNetworkImportData>()),
81 ("aws_open_search", schema::<AwsOpenSearchImportData>()),
82 ("aws_postgres", schema::<AwsPostgresImportData>()),
83 ("aws_queue", schema::<AwsQueueImportData>()),
84 (
85 "aws_remote_stack_management",
86 schema::<AwsRemoteStackManagementImportData>(),
87 ),
88 (
89 "aws_service_account",
90 schema::<AwsServiceAccountImportData>(),
91 ),
92 ("aws_storage", schema::<AwsStorageImportData>()),
93 ("aws_vault", schema::<AwsVaultImportData>()),
94 ("azure_ai", schema::<AzureAiImportData>()),
95 (
96 "azure_artifact_registry",
97 schema::<AzureArtifactRegistryImportData>(),
98 ),
99 ("azure_build", schema::<AzureBuildImportData>()),
100 (
101 "azure_container_apps_environment",
102 schema::<AzureContainerAppsEnvironmentImportData>(),
103 ),
104 (
105 "azure_compute_cluster",
106 schema::<AzureComputeClusterImportData>(),
107 ),
108 ("azure_function", schema::<AzureWorkerImportData>()),
109 ("azure_kv", schema::<AzureKvImportData>()),
110 ("azure_network", schema::<AzureNetworkImportData>()),
111 (
112 "azure_postgres",
113 schema::<AzureFlexibleServerPostgresImportData>(),
114 ),
115 ("azure_queue", schema::<AzureQueueImportData>()),
116 (
117 "azure_remote_stack_management",
118 schema::<AzureRemoteStackManagementImportData>(),
119 ),
120 (
121 "azure_resource_group",
122 schema::<AzureResourceGroupImportData>(),
123 ),
124 (
125 "azure_service_account",
126 schema::<AzureServiceAccountImportData>(),
127 ),
128 (
129 "azure_service_activation",
130 schema::<AzureServiceActivationImportData>(),
131 ),
132 (
133 "azure_service_bus_namespace",
134 schema::<AzureServiceBusNamespaceImportData>(),
135 ),
136 ("azure_storage", schema::<AzureStorageImportData>()),
137 (
138 "azure_storage_account",
139 schema::<AzureStorageAccountImportData>(),
140 ),
141 ("azure_vault", schema::<AzureVaultImportData>()),
142 ("gcp_ai", schema::<GcpAiImportData>()),
143 (
144 "gcp_artifact_registry",
145 schema::<GcpArtifactRegistryImportData>(),
146 ),
147 ("gcp_build", schema::<GcpBuildImportData>()),
148 (
149 "gcp_compute_cluster",
150 schema::<GcpComputeClusterImportData>(),
151 ),
152 ("gcp_function", schema::<GcpWorkerImportData>()),
153 ("gcp_kv", schema::<GcpKvImportData>()),
154 ("gcp_network", schema::<GcpNetworkImportData>()),
155 ("gcp_postgres", schema::<GcpPostgresImportData>()),
156 ("gcp_queue", schema::<GcpQueueImportData>()),
157 (
158 "gcp_remote_stack_management",
159 schema::<GcpRemoteStackManagementImportData>(),
160 ),
161 (
162 "kubernetes_cluster",
163 schema::<KubernetesClusterImportData>(),
164 ),
165 (
166 "gcp_service_account",
167 schema::<GcpServiceAccountImportData>(),
168 ),
169 (
170 "gcp_service_activation",
171 schema::<GcpServiceActivationImportData>(),
172 ),
173 ("gcp_storage", schema::<GcpStorageImportData>()),
174 ("gcp_vault", schema::<GcpVaultImportData>()),
175 ]);
176
177 insta::assert_json_snapshot!("import_data_schemas", schemas);
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184 use serde_json::json;
185
186 #[test]
187 fn aws_import_data_accepts_cloudformation_string_booleans() {
188 let network: AwsNetworkImportData = serde_json::from_value(json!({
189 "vpcId": "vpc-123",
190 "cidrBlock": null,
191 "internetGatewayId": null,
192 "natGatewayId": null,
193 "eipAllocationId": null,
194 "publicSubnetIds": ["subnet-public"],
195 "privateSubnetIds": ["subnet-private"],
196 "publicRouteTableId": null,
197 "privateRouteTableId": null,
198 "securityGroupId": "sg-123",
199 "availabilityZones": [],
200 "isByoVpc": "true",
201 }))
202 .expect("network import data should parse");
203 assert!(network.is_byo_vpc);
204
205 let remote_stack_management: AwsRemoteStackManagementImportData =
206 serde_json::from_value(json!({
207 "roleName": "alien-manager",
208 "roleArn": "arn:aws:iam::123456789012:role/alien-manager",
209 "managementPermissionsApplied": "true",
210 }))
211 .expect("remote stack management import data should parse");
212 assert!(remote_stack_management.management_permissions_applied);
213
214 let service_account: AwsServiceAccountImportData = serde_json::from_value(json!({
215 "roleName": "alien-worker",
216 "roleArn": "arn:aws:iam::123456789012:role/alien-worker",
217 "stackPermissionsApplied": "false",
218 }))
219 .expect("service account import data should parse");
220 assert!(!service_account.stack_permissions_applied);
221 }
222}