diff --git a/README.md b/README.md index 5d9230b..a1f024a 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,10 @@ Flags: ``` +## Note + +Import management of terraform resources is provider specific, which means that this tool does not have 100% coverage. If you attempt to use this tool and notice that it generates faulty imports, consider extending the support for your resources and contributing a PR. + ## Contributing PRs are always welcome!. Refer [CONTRIBUTING.md](./CONTRIBUTING.md) for more information diff --git a/pkg/convertor.go b/pkg/convertor.go index 838e3c6..f5abb58 100644 --- a/pkg/convertor.go +++ b/pkg/convertor.go @@ -16,6 +16,17 @@ func computeTerraformImportForResource(resource parser.TerraformResource) Terraf "aws_iam_policy_attachment", "aws_acm_certificate_validation", "aws_ami_copy", + "google_storage_default_object", + "google_storage_default_object_acl", + "google_storage_bucket_acl", + "google_project_service_identity", + "google_project_default_service_accounts", + "google_compute_instance_from_template", + "google_pubsub_subscription_iam_member", + "google_pubsub_subscription_iam_binding", + "google_compute_instance_template", + "google_iap_tunnel_instance_iam_binding", + "local_file", } if slices.Contains(resourcesWhichDoNotSupportImport, resource.Type) { return TerraformImport{ @@ -35,7 +46,9 @@ func computeResourceID(resource parser.TerraformResource) string { v := func(name string) string { return fmt.Sprint(resource.AttributeValues[name]) } + switch resource.Type { + // aws resources case "aws_iam_role_policy_attachment": return fmt.Sprintf("%s/%s", v("role"), v("policy_arn")) case "aws_cloudwatch_event_target": @@ -78,6 +91,77 @@ func computeResourceID(resource parser.TerraformResource) string { return fmt.Sprintf("%s/%s/%s/%s", v("service_namespace"), v("resource_id"), v("scalable_dimension"), v("name")) case "aws_ecs_service": return fmt.Sprintf("%s/%s", getEcsClusterNameFromARN(v("cluster")), v("name")) + + // gcp resources + case "google_bigquery_dataset_iam_member": + return fmt.Sprintf("projects/%s/datasets/%s %s %s", v("project"), v("dataset_id"), v("role"), v("member")) + case "google_bigquery_table_iam_member": + return fmt.Sprintf("%s %s %s", v("table_id"), v("role"), v("member")) + case "google_service_account_iam_member": + return fmt.Sprintf("%s %s %s", v("service_account_id"), v("role"), v("member")) + case "google_service_account_iam_binding": + return fmt.Sprintf("%s %s", v("service_account_id"), v("role")) + case "google_privateca_ca_pool_iam_member": + conditions, ok := resource.AttributeValues["condition"].([]any) + if ok && len(conditions) > 0 { + condition := conditions[0].(map[string]any) + return fmt.Sprintf("%s %s %s %s", v("ca_pool"), v("role"), v("member"), condition["title"]) + } + return fmt.Sprintf("%s %s %s", v("ca_pool"), v("role"), v("member")) + case "google_privateca_certificate_template_iam_member": + return fmt.Sprintf("%s %s %s", v("certificate_template"), v("role"), v("member")) + case "google_cloud_run_service_iam_binding": + return fmt.Sprintf("%s %s", v("service"), v("role")) + case "google_kms_crypto_key_iam_binding": + return fmt.Sprintf("%s %s", v("crypto_key_id"), v("role")) + case "google_kms_crypto_key_iam_member": + return fmt.Sprintf("%s %s %s", v("crypto_key_id"), v("role"), v("member")) + case "google_organization_iam_member": + return fmt.Sprintf("%s %s %s", v("org_id"), v("role"), v("member")) + case "google_project_iam_member": + conditions, ok := resource.AttributeValues["condition"].([]any) + if ok && len(conditions) > 0 { + condition := conditions[0].(map[string]any) + return fmt.Sprintf("%s %s %s %s", v("project"), v("role"), v("member"), condition["title"]) + } + return fmt.Sprintf("%s %s %s", v("project"), v("role"), v("member")) + case "google_project_iam_binding": + return fmt.Sprintf("%s %s", v("project"), v("role")) + case "google_project_iam_custom_role": + return fmt.Sprintf("%s %s", v("project"), v("id")) + case "google_sql_database_instance": + return fmt.Sprintf("projects/%s/instances/%s", v("project"), v("name")) + case "google_sql_user": + return fmt.Sprintf("%s/%s/%s", v("project"), v("instance"), v("name")) + case "google_iap_tunnel_instance_iam_binding": + return fmt.Sprintf("%s %s", v("instance"), v("role")) + case "google_secret_manager_secret_iam_binding": + return fmt.Sprintf("%s %s", v("secret_id"), v("role")) + case "google_secret_manager_secret_iam_member": + return fmt.Sprintf("%s %s %s", v("secret_id"), v("role"), v("member")) + case "google_storage_bucket_iam_member": + return fmt.Sprintf("%s %s %s", v("bucket"), v("role"), v("member")) + case "google_storage_bucket_iam_binding": + return fmt.Sprintf("%s %s", v("bucket"), v("role")) + case "google_compute_subnetwork_iam_binding": + return fmt.Sprintf("%s %s", v("subnetwork"), v("role")) + case "google_pubsub_topic_iam_binding": + return fmt.Sprintf("%s %s", v("topic"), v("role")) + case "google_pubsub_topic_iam_member": + conditions, ok := resource.AttributeValues["condition"].([]any) + if ok && len(conditions) > 0 { + condition := conditions[0].(map[string]any) + return fmt.Sprintf("%s %s %s %s", v("topic"), v("role"), v("member"), condition["title"]) + } + return fmt.Sprintf("%s %s %s", v("topic"), v("role"), v("member")) + case "google_resource_manager_lien": + return fmt.Sprintf("%s/%s", strings.ReplaceAll(v("parent"), "projects/", ""), v("name")) + case "google_monitoring_uptime_check_config": + return fmt.Sprintf("%s %s", v("project"), v("id")) + case "google_monitoring_alert_policy": + return fmt.Sprintf("%s %s", v("project"), v("name")) + case "google_monitoring_notification_channel": + return v("name") default: return v("id") } diff --git a/pkg/convertor_test.go b/pkg/convertor_test.go index eba1d39..54360bd 100644 --- a/pkg/convertor_test.go +++ b/pkg/convertor_test.go @@ -429,6 +429,530 @@ func Test_ComputeTerraformImportForResource(t *testing.T) { SupportsImport: true, }, }, + { + name: "For google_monitoring_alert_policy", + terraformResource: parser.TerraformResource{ + Address: "google_monitoring_alert_policy.test", + Type: "google_monitoring_alert_policy", + AttributeValues: map[string]any{ + "name": "projects/project/alertPolicies/123456789", + "project": "project", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_monitoring_alert_policy.test", + ResourceID: "project projects/project/alertPolicies/123456789", + SupportsImport: true, + }, + }, + { + name: "For google_monitoring_notification_channel", + terraformResource: parser.TerraformResource{ + Address: "google_monitoring_notification_channel.test", + Type: "google_monitoring_notification_channel", + AttributeValues: map[string]any{ + "display_name": "Team Email Group", + "id": "project projects/project/notificationChannels/12345678901234567", + "name": "projects/project/notificationChannels/12345678901234567", + "project": "project", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_monitoring_notification_channel.test", + ResourceID: "projects/project/notificationChannels/12345678901234567", + SupportsImport: true, + }, + }, + { + name: "For google_service_account_iam_binding", + terraformResource: parser.TerraformResource{ + Address: "google_service_account_iam_binding.test", + Type: "google_service_account_iam_binding", + AttributeValues: map[string]any{ + "id": "projects/project/serviceAccounts/service@project.iam.gserviceaccount.com/roles/iam.serviceAccountUser", + "role": "roles/iam.serviceAccountUser", + "service_account_id": "projects/project/serviceAccounts/service@project.iam.gserviceaccount.com", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_service_account_iam_binding.test", + ResourceID: "projects/project/serviceAccounts/service@project.iam.gserviceaccount.com roles/iam.serviceAccountUser", + SupportsImport: true, + }, + }, + { + name: "For google_service_account_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_service_account_iam_member.test", + Type: "google_service_account_iam_member", + AttributeValues: map[string]any{ + "id": "projects/project/serviceAccounts/service@project.iam.gserviceaccount.com/roles/iam.serviceAccountUser/user:user.name@email.com", + "member": "user:user.name@email.com", + "role": "roles/iam.serviceAccountUser", + "service_account_id": "projects/project/serviceAccounts/service@project.iam.gserviceaccount.com", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_service_account_iam_member.test", + ResourceID: "projects/project/serviceAccounts/service@project.iam.gserviceaccount.com roles/iam.serviceAccountUser user:user.name@email.com", + SupportsImport: true, + }, + }, + { + name: "For google_privateca_ca_pool_iam_member.pool", + terraformResource: parser.TerraformResource{ + Address: "google_privateca_ca_pool_iam_member.pool", + Type: "google_privateca_ca_pool_iam_member", + AttributeValues: map[string]any{ + "ca_pool": "projects/project/locations/us-north1/caPools/service", + "id": "projects/project/locations/us-north1/caPools/service/roles/privateca.poolReader/user:user.name@email.com", + "member": "user:user.name@email.com", + "location": "us-north1", + "project": "project", + "role": "roles/privateca.poolReader", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_privateca_ca_pool_iam_member.pool", + ResourceID: "projects/project/locations/us-north1/caPools/service roles/privateca.poolReader user:user.name@email.com", + SupportsImport: true, + }, + }, + { + name: "For google_privateca_certificate_template_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_privateca_certificate_template_iam_member.test", + Type: "google_privateca_certificate_template_iam_member", + AttributeValues: map[string]any{ + "certificate_template": "projects/project/locations/us-north1/certificateTemplates/test", + "id": "projects/project/locations/us-north1/certificateTemplates/test/roles/privateca.templateUser/user:user.name@email.com", + "location": "us-north1", + "member": "user:user.name@email.com", + "project": "project", + "role": "roles/privateca.templateUser", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_privateca_certificate_template_iam_member.test", + ResourceID: "projects/project/locations/us-north1/certificateTemplates/test roles/privateca.templateUser user:user.name@email.com", + SupportsImport: true, + }, + }, + { + name: "For google_project_iam_binding", + terraformResource: parser.TerraformResource{ + Address: "google_project_iam_binding.test", + Type: "google_project_iam_binding", + AttributeValues: map[string]any{ + "id": "project/projects/project/roles/testuser", + "members": []string{ + "serviceAccount:service@project.iam.gserviceaccount.com", + "serviceAccount:test@project.iam.gserviceaccount.com", + }, + "project": "project", + "role": "projects/project/roles/testuser", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_project_iam_binding.test", + ResourceID: "project projects/project/roles/testuser", + SupportsImport: true, + }, + }, + { + name: "For google_project_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_project_iam_member.test", + Type: "google_project_iam_member", + AttributeValues: map[string]any{ + "id": "project/projects/project/roles/test/serviceAccount:service_account@company.iam.gserviceaccount.com", + "member": "serviceAccount:service_account@company.iam.gserviceaccount.com", + "project": "project", + "role": "projects/project/roles/test", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_project_iam_member.test", + ResourceID: "project projects/project/roles/test serviceAccount:service_account@company.iam.gserviceaccount.com", + SupportsImport: true, + }, + }, + { + name: "For google_sql_database_instance", + terraformResource: parser.TerraformResource{ + Address: "google_sql_database_instance.test", + Type: "google_sql_database_instance", + AttributeValues: map[string]any{ + "id": "test-ydfs787sd8f", + "name": "test-ydfs787sd8f", + "project": "project", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_sql_database_instance.test", + ResourceID: "projects/project/instances/test-ydfs787sd8f", + SupportsImport: true, + }, + }, + { + name: "For google_sql_user", + terraformResource: parser.TerraformResource{ + Address: "google_sql_user.test", + Type: "google_sql_user", + AttributeValues: map[string]any{ + "id": "service@project.iam//instance-test-45l3n534jh5n", + "instance": "instance-test-45l3n534jh5n", + "name": "service@project.iam", + "project": "project", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_sql_user.test", + ResourceID: "project/instance-test-45l3n534jh5n/service@project.iam", + SupportsImport: true, + }, + }, + { + name: "For google_iap_tunnel_instance_iam_binding", + terraformResource: parser.TerraformResource{ + Address: "google_iap_tunnel_instance_iam_binding.test", + Type: "google_iap_tunnel_instance_iam_binding", + AttributeValues: map[string]any{ + "id": "projects/project/iap_tunnel/zones/us-north1-c/instances/test/roles/iap.tunnelResourceAccessor", + "instance": "projects/project/iap_tunnel/zones/us-north1-c/instances/test", + "members": []string{ + "group:team@company.com", + "user:user.name@email.com", + }, + "project": "project", + "role": "roles/iap.tunnelResourceAccessor", + "zone": "us-north1-c", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_iap_tunnel_instance_iam_binding.test", + ResourceID: "projects/project/iap_tunnel/zones/us-north1-c/instances/test roles/iap.tunnelResourceAccessor", + SupportsImport: false, + }, + }, + { + name: "For google_bigquery_dataset_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_bigquery_dataset_iam_member.test", + Type: "google_bigquery_dataset_iam_member", + AttributeValues: map[string]any{ + "dataset_id": "test_123456", + "etag": "", + "id": "projects/project/datasets/test_123456/roles/bigquery.dataEditor/user:user.name@email.com", + "member": "user:user.name@email.com", + "project": "project", + "role": "roles/bigquery.dataEditor", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_bigquery_dataset_iam_member.test", + ResourceID: "projects/project/datasets/test_123456 roles/bigquery.dataEditor user:user.name@email.com", + SupportsImport: true, + }, + }, + { + name: "For google_bigquery_table_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_bigquery_table_iam_member.test", + Type: "google_bigquery_table_iam_member", + AttributeValues: map[string]any{ + "dataset_id": "test_123456", + "id": "projects/project/datasets/test_123456/tables/_retracted_file/roles/bigquery.dataEditor/group:group.name@email.com", + "member": "group:group.name@email.com", + "project": "project", + "role": "roles/bigquery.dataEditor", + "table_id": "projects/project/datasets/test_123456/tables/_retracted_file", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_bigquery_table_iam_member.test", + ResourceID: "projects/project/datasets/test_123456/tables/_retracted_file roles/bigquery.dataEditor group:group.name@email.com", + SupportsImport: true, + }, + }, + { + name: "For google_kms_crypto_key_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_kms_crypto_key_iam_member.test", + Type: "google_kms_crypto_key_iam_member", + AttributeValues: map[string]any{ + "crypto_key_id": "projects/project/locations/europe/keyRings/test-data/cryptoKeys/data-converter", + "id": "projects/project/locations/europe/keyRings/test-data/cryptoKeys/data-converter/roles/cloudkms.cryptoKeyEncrypterDecrypter/serviceAccount:service@project.iam.gserviceaccount.com", + "member": "serviceAccount:service@project.iam.gserviceaccount.com", + "role": "roles/cloudkms.cryptoKeyEncrypterDecrypter", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_kms_crypto_key_iam_member.test", + ResourceID: "projects/project/locations/europe/keyRings/test-data/cryptoKeys/data-converter roles/cloudkms.cryptoKeyEncrypterDecrypter serviceAccount:service@project.iam.gserviceaccount.com", + SupportsImport: true, + }, + }, + { + name: "For google_kms_crypto_key_iam_binding", + terraformResource: parser.TerraformResource{ + Address: "google_kms_crypto_key_iam_binding.test", + Type: "google_kms_crypto_key_iam_binding", + AttributeValues: map[string]any{ + "crypto_key_id": "projects/project/locations/us-north1/keyRings/gke-backup/cryptoKeys/backup", + "id": "projects/project/locations/us-north1/keyRings/gke-backup/cryptoKeys/backup/roles/cloudkms.cryptoKeyDecrypter", + "members": []string{ + "serviceAccount:service@container-engine-robot.iam.gserviceaccount.com", + "serviceAccount:service@gcp-sa-gkebackup.iam.gserviceaccount.com", + }, + "role": "roles/cloudkms.cryptoKeyDecrypter", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_kms_crypto_key_iam_binding.test", + ResourceID: "projects/project/locations/us-north1/keyRings/gke-backup/cryptoKeys/backup roles/cloudkms.cryptoKeyDecrypter", + SupportsImport: true, + }, + }, + { + name: "For google_cloud_run_service_iam_binding", + terraformResource: parser.TerraformResource{ + Address: "google_cloud_run_service_iam_binding.test", + Type: "google_cloud_run_service_iam_binding", + AttributeValues: map[string]any{ + "id": "v1/projects/project/locations/us-north1/services/service/roles/run.invoker", + "location": "us-north1", + "members": []string{ + "serviceAccount:service@project.iam.gserviceaccount.com", + }, + "project": "project", + "role": "roles/run.invoker", + "service": "v1/projects/project/locations/us-north1/services/service", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_cloud_run_service_iam_binding.test", + ResourceID: "v1/projects/project/locations/us-north1/services/service roles/run.invoker", + SupportsImport: true, + }, + }, + { + name: "For google_secret_manager_secret_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_secret_manager_secret_iam_member.test", + Type: "google_secret_manager_secret_iam_member", + AttributeValues: map[string]any{ + "id": "projects/project/secrets/test-developer-client-key/roles/secretmanager.secretAccessor/user:user.name@email.com", + "member": "user:user.name@email.com", + "project": "project", + "role": "roles/secretmanager.secretAccessor", + "secret_id": "projects/project/secrets/test-developer-client-key", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_secret_manager_secret_iam_member.test", + ResourceID: "projects/project/secrets/test-developer-client-key roles/secretmanager.secretAccessor user:user.name@email.com", + SupportsImport: true, + }, + }, + { + name: "For google_secret_manager_secret_iam_binding", + terraformResource: parser.TerraformResource{ + Address: "google_secret_manager_secret_iam_binding.test", + Type: "google_secret_manager_secret_iam_binding", + AttributeValues: map[string]any{ + "id": "projects/project/secrets/service-import/roles/secretmanager.secretAccessor", + "members": []string{ + "serviceAccount:service@project.iam.gserviceaccount.com", + "serviceAccount:test@project.iam.gserviceaccount.com", + }, + "project": "project", + "role": "roles/secretmanager.secretAccessor", + "secret_id": "projects/project/secrets/service-import", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_secret_manager_secret_iam_binding.test", + ResourceID: "projects/project/secrets/service-import roles/secretmanager.secretAccessor", + SupportsImport: true, + }, + }, + { + name: "For google_storage_bucket_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_storage_bucket_iam_member.test", + Type: "google_storage_bucket_iam_member", + AttributeValues: map[string]any{ + "bucket": "b/test-cache", + "id": "b/test-cache/roles/storage.objectCreator/user:user.name@email.com", + "member": "user:user.name@email.com", + "role": "roles/storage.objectCreator", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_storage_bucket_iam_member.test", + ResourceID: "b/test-cache roles/storage.objectCreator user:user.name@email.com", + SupportsImport: true, + }, + }, + { + name: "For google_storage_bucket_iam_binding", + terraformResource: parser.TerraformResource{ + Address: "google_storage_bucket_iam_binding.test", + Type: "google_storage_bucket_iam_binding", + AttributeValues: map[string]any{ + "bucket": "b/test-company-com", + "id": "b/test-company-com/roles/storage.legacyObjectReader", + "role": "roles/storage.legacyObjectReader", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_storage_bucket_iam_binding.test", + ResourceID: "b/test-company-com roles/storage.legacyObjectReader", + SupportsImport: true, + }, + }, + { + name: "For google_compute_subnetwork_iam_binding", + terraformResource: parser.TerraformResource{ + Address: "google_compute_subnetwork_iam_binding.test", + Type: "google_compute_subnetwork_iam_binding", + AttributeValues: map[string]any{ + "id": "projects/project/regions/us-north1/subnetworks/test/roles/compute.networkUser", + "role": "roles/compute.networkUser", + "subnetwork": "projects/project/regions/us-north1/subnetworks/test", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_compute_subnetwork_iam_binding.test", + ResourceID: "projects/project/regions/us-north1/subnetworks/test roles/compute.networkUser", + SupportsImport: true, + }, + }, + { + name: "For google_organization_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_organization_iam_member.test", + Type: "google_organization_iam_member", + AttributeValues: map[string]any{ + "id": "123456789/roles/viewer/serviceAccount:test@prod-eu4.iam.gserviceaccount.com", + "member": "serviceAccount:test@prod-eu4.iam.gserviceaccount.com", + "org_id": "123456789", + "role": "roles/viewer", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_organization_iam_member.test", + ResourceID: "123456789 roles/viewer serviceAccount:test@prod-eu4.iam.gserviceaccount.com", + SupportsImport: true, + }, + }, + { + name: "For google_project_iam_custom_role", + terraformResource: parser.TerraformResource{ + Address: "google_project_iam_custom_role.test", + Type: "google_project_iam_custom_role", + AttributeValues: map[string]any{ + "id": "projects/project/roles/osLoginProjectGet_23i4po", + "project": "project", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_project_iam_custom_role.test", + ResourceID: "project projects/project/roles/osLoginProjectGet_23i4po", + SupportsImport: true, + }, + }, + { + name: "For google_pubsub_topic_iam_binding", + terraformResource: parser.TerraformResource{ + Address: "google_pubsub_topic_iam_binding.test", + Type: "google_pubsub_topic_iam_binding", + AttributeValues: map[string]any{ + "id": "projects/project/topics/subscription-test/roles/pubsub.publisher", + "project": "project", + "role": "roles/pubsub.publisher", + "topic": "projects/project/topics/subscription-test", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_pubsub_topic_iam_binding.test", + ResourceID: "projects/project/topics/subscription-test roles/pubsub.publisher", + SupportsImport: true, + }, + }, + { + name: "For google_pubsub_topic_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_pubsub_topic_iam_member.test", + Type: "google_pubsub_topic_iam_member", + AttributeValues: map[string]any{ + "id": "projects/project/topics/service-data-logs-export/roles/pubsub.publisher/serviceAccount:service@gcp-sa-logging.iam.gserviceaccount.com", + "member": "serviceAccount:service@gcp-sa-logging.iam.gserviceaccount.com", + "project": "project", + "role": "roles/pubsub.publisher", + "topic": "projects/project/topics/service-data-logs-export", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_pubsub_topic_iam_member.test", + ResourceID: "projects/project/topics/service-data-logs-export roles/pubsub.publisher serviceAccount:service@gcp-sa-logging.iam.gserviceaccount.com", + SupportsImport: true, + }, + }, + { + name: "For google_pubsub_subscription_iam_member", + terraformResource: parser.TerraformResource{ + Address: "google_pubsub_subscription_iam_member.test", + Type: "google_pubsub_subscription_iam_member", + AttributeValues: map[string]any{ + "id": "projects/project/subscriptions/subscription-test/roles/pubsub.subscriber/serviceAccount:service@gcp-sa-pubsub.iam.gserviceaccount.com", + "member": "serviceAccount:service@gcp-sa-pubsub.iam.gserviceaccount.com", + "project": "project", + "role": "roles/pubsub.subscriber", + "subscription": "subscription-test", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_pubsub_subscription_iam_member.test", + ResourceID: "projects/project/subscriptions/subscription-test/roles/pubsub.subscriber/serviceAccount:service@gcp-sa-pubsub.iam.gserviceaccount.com", + SupportsImport: false, + }, + }, + { + name: "For google_resource_manager_lien", + terraformResource: parser.TerraformResource{ + Address: "google_resource_manager_lien.lien", + Type: "google_resource_manager_lien", + AttributeValues: map[string]any{ + "name": "p1234567890-apa12345-ab12-2727-bc34-d1234567890", + "origin": "project-factory", + "parent": "projects/123456890", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_resource_manager_lien.lien", + ResourceID: "123456890/p1234567890-apa12345-ab12-2727-bc34-d1234567890", + SupportsImport: true, + }, + }, + { + name: "For google_monitoring_uptime_check_config", + terraformResource: parser.TerraformResource{ + Address: "google_monitoring_uptime_check_config.test", + Type: "google_monitoring_uptime_check_config", + AttributeValues: map[string]any{ + "id": "projects/project/uptimeCheckConfigs/uptimecheckconfigtest", + "name": "projects/project/uptimeCheckConfigs/uptimecheckconfigtest", + "project": "project", + }, + }, + expected: TerraformImport{ + ResourceAddress: "google_monitoring_uptime_check_config.test", + ResourceID: "project projects/project/uptimeCheckConfigs/uptimecheckconfigtest", + SupportsImport: true, + }, + }, { name: "For everything else", terraformResource: parser.TerraformResource{ diff --git a/pkg/testdata/google.json b/pkg/testdata/google.json new file mode 100644 index 0000000..389bedf --- /dev/null +++ b/pkg/testdata/google.json @@ -0,0 +1,72 @@ +{ + "format_version": "0.1", + "terraform_version": "0.12.31", + "values": { + "root_module": { + "resources": [ + { + "address": "google_project_iam_member.service_sa_bindings", + "mode": "managed", + "type": "google_project_iam_member", + "name": "service_sa_bindings", + "provider_name": "registry.opentofu.org/hashicorp/google", + "schema_version": 0, + "values": { + "condition": [ + { + "description": "Exclude test secret", + "expression": "!(resource.name.startsWith(\"projects/123456789/secrets/test\"))", + "title": "Test title 1 is here." + } + ], + "id": "project/projects/project/roles/service/serviceAccount:service@project.iam.gserviceaccount.com/exclude test secret/Exclude test secret/!(resource.name.startsWith(\"projects/123456789/secrets/test\"))", + "member": "serviceAccount:service@project.iam.gserviceaccount.com", + "project": "project", + "role": "projects/project/roles/service" + }, + "sensitive_values": { + "condition": [{}] + }, + "depends_on": [ + "data.google_project.current_project", + "google_project_iam_custom_role.service", + "google_service_account.service" + ] + }, + { + "address": "google_privateca_ca_pool_iam_member.client[\"user.name@email.com\"]", + "mode": "managed", + "type": "google_privateca_ca_pool_iam_member", + "name": "client", + "index": "user.name@email.com", + "provider_name": "registry.opentofu.org/hashicorp/google", + "schema_version": 0, + "values": { + "ca_pool": "projects/project/locations/us-north1/caPools/service", + "condition": [ + { + "description": "", + "expression": "", + "title": "Test title 2 is here." + } + ], + "id": "projects/project/locations/us-north1/caPools/service/roles/privateca.certificateRequester/user:user.name@email.com/Test title is here.//api.getAttribute(\"privateca.googleapis.com/template\", \"\") == \"project/-/service-client\"\n&& api.getAttribute(\"privateca.googleapis.com/subject\", {})[\"common_name\"] == \"user.name@email.com\"\n", + "location": "us-north1", + "member": "user:user.name@email.com", + "project": "project", + "role": "roles/privateca.certificateRequester" + }, + "sensitive_values": { + "condition": [{}] + }, + "depends_on": [ + "data.google_project.shared_project", + "data.google_projects.shared_projects", + "ca.google_privateca_ca_pool.pool", + "ca.google_privateca_certificate_template.client" + ] + } + ] + } + } +} diff --git a/pkg/tfimportgen_test.go b/pkg/tfimportgen_test.go index 79495b0..9a4f1e1 100644 --- a/pkg/tfimportgen_test.go +++ b/pkg/tfimportgen_test.go @@ -64,6 +64,22 @@ func Test_GenerateImports_ShouldGenerateImportsForAllResourcesWhenNoFiltersAreGi }, }, }, + { + name: "google", + filePath: "testdata/google.json", + expected: tfimportgen.TerraformImports{ + { + ResourceAddress: "google_project_iam_member.service_sa_bindings", + ResourceID: "project projects/project/roles/service serviceAccount:service@project.iam.gserviceaccount.com Test title 1 is here.", + SupportsImport: true, + }, + { + ResourceAddress: "google_privateca_ca_pool_iam_member.client[\"user.name@email.com\"]", + ResourceID: "projects/project/locations/us-north1/caPools/service roles/privateca.certificateRequester user:user.name@email.com Test title 2 is here.", + SupportsImport: true, + }, + }, + }, } for _, tt := range tests {