diff --git a/config/old-singleton-list-apis.txt b/config/old-singleton-list-apis.txt new file mode 100644 index 000000000..e89ef7bc7 --- /dev/null +++ b/config/old-singleton-list-apis.txt @@ -0,0 +1,210 @@ +google_access_context_manager_access_level +google_access_context_manager_access_level_condition +google_access_context_manager_access_policy_iam_member +google_access_context_manager_service_perimeter +google_alloydb_backup +google_alloydb_cluster +google_alloydb_instance +google_apigee_environment +google_apigee_environment_iam_member +google_apigee_organization +google_app_engine_application +google_app_engine_service_network_settings +google_app_engine_standard_app_version +google_artifact_registry_repository +google_artifact_registry_repository_iam_member +google_beyondcorp_app_connection +google_beyondcorp_app_connector +google_bigquery_analytics_hub_data_exchange_iam_member +google_bigquery_analytics_hub_listing +google_bigquery_connection +google_bigquery_data_transfer_config +google_bigquery_dataset +google_bigquery_dataset_access +google_bigquery_dataset_iam_binding +google_bigquery_dataset_iam_member +google_bigquery_job +google_bigquery_reservation +google_bigquery_routine +google_bigquery_table +google_bigquery_table_iam_binding +google_bigquery_table_iam_member +google_bigtable_app_profile +google_bigtable_gc_policy +google_bigtable_instance +google_bigtable_instance_iam_binding +google_bigtable_instance_iam_member +google_bigtable_table_iam_binding +google_bigtable_table_iam_member +google_binary_authorization_attestor +google_binary_authorization_policy +google_certificate_manager_certificate +google_cloud_run_domain_mapping +google_cloud_run_service +google_cloud_run_service_iam_member +google_cloud_run_v2_job +google_cloud_run_v2_service +google_cloud_scheduler_job +google_cloud_tasks_queue +google_cloudbuild_trigger +google_cloudbuild_worker_pool +google_cloudfunctions2_function +google_cloudfunctions_function +google_cloudfunctions_function_iam_member +google_composer_environment +google_compute_autoscaler +google_compute_backend_bucket +google_compute_backend_service +google_compute_disk +google_compute_disk_iam_member +google_compute_firewall +google_compute_firewall_policy_rule +google_compute_forwarding_rule +google_compute_global_forwarding_rule +google_compute_health_check +google_compute_image +google_compute_image_iam_member +google_compute_instance +google_compute_instance_from_template +google_compute_instance_group_manager +google_compute_instance_iam_member +google_compute_instance_template +google_compute_managed_ssl_certificate +google_compute_node_group +google_compute_node_template +google_compute_packet_mirroring +google_compute_per_instance_config +google_compute_region_autoscaler +google_compute_region_backend_service +google_compute_region_disk +google_compute_region_disk_iam_member +google_compute_region_health_check +google_compute_region_instance_group_manager +google_compute_region_network_endpoint_group +google_compute_region_per_instance_config +google_compute_region_url_map +google_compute_reservation +google_compute_resource_policy +google_compute_router +google_compute_router_nat +google_compute_router_peer +google_compute_security_policy +google_compute_snapshot +google_compute_snapshot_iam_member +google_compute_subnetwork +google_compute_subnetwork_iam_member +google_compute_url_map +google_container_analysis_note +google_container_attached_cluster +google_container_aws_cluster +google_container_aws_node_pool +google_container_azure_cluster +google_container_azure_node_pool +google_container_cluster +google_container_node_pool +google_data_catalog_entry +google_data_catalog_tag_template +google_data_fusion_instance +google_data_loss_prevention_deidentify_template +google_data_loss_prevention_inspect_template +google_data_loss_prevention_job_trigger +google_data_loss_prevention_stored_info_type +google_dataplex_asset +google_dataplex_lake +google_dataplex_zone +google_dataproc_autoscaling_policy +google_dataproc_cluster +google_dataproc_job +google_dataproc_metastore_service +google_dataproc_workflow_template +google_datastream_connection_profile +google_datastream_private_connection +google_dialogflow_cx_agent +google_dialogflow_cx_flow +google_dialogflow_cx_page +google_dialogflow_cx_webhook +google_dns_managed_zone +google_dns_managed_zone_iam_member +google_dns_policy +google_dns_record_set +google_eventarc_trigger +google_filestore_instance +google_firebaserules_ruleset +google_folder_iam_member +google_gke_backup_backup_plan +google_gke_hub_membership +google_gke_hub_membership_iam_member +google_healthcare_dataset_iam_member +google_iam_workload_identity_pool_provider +google_iap_app_engine_service_iam_member +google_iap_app_engine_version_iam_member +google_iap_tunnel_iam_member +google_iap_web_backend_service_iam_member +google_iap_web_iam_member +google_iap_web_type_app_engine_iam_member +google_iap_web_type_compute_iam_member +google_identity_platform_inbound_saml_config +google_identity_platform_project_default_config +google_identity_platform_tenant_inbound_saml_config +google_kms_crypto_key +google_kms_crypto_key_iam_member +google_kms_crypto_key_version +google_kms_key_ring_iam_member +google_logging_folder_bucket_config +google_logging_folder_sink +google_logging_metric +google_logging_project_bucket_config +google_logging_project_sink +google_memcache_instance +google_ml_engine_model +google_monitoring_alert_policy +google_monitoring_custom_service +google_monitoring_metric_descriptor +google_monitoring_notification_channel +google_monitoring_service +google_monitoring_slo +google_monitoring_uptime_check_config +google_network_connectivity_spoke +google_network_management_connectivity_test +google_notebooks_environment +google_notebooks_instance +google_notebooks_instance_iam_member +google_notebooks_runtime +google_notebooks_runtime_iam_member +google_organization_iam_member +google_os_config_os_policy_assignment +google_os_config_patch_deployment +google_privateca_ca_pool +google_privateca_ca_pool_iam_member +google_privateca_certificate +google_privateca_certificate_authority +google_privateca_certificate_template +google_privateca_certificate_template_iam_member +google_project_iam_member +google_pubsub_lite_subscription +google_pubsub_lite_topic +google_pubsub_subscription +google_pubsub_subscription_iam_member +google_pubsub_topic +google_pubsub_topic_iam_member +google_redis_instance +google_secret_manager_secret +google_secret_manager_secret_iam_member +google_service_account_iam_member +google_sourcerepo_repository_iam_member +google_spanner_database +google_spanner_database_iam_member +google_spanner_instance +google_spanner_instance_iam_member +google_sql_database_instance +google_sql_user +google_storage_bucket +google_storage_bucket_iam_member +google_storage_bucket_object +google_storage_transfer_agent_pool +google_tpu_node +google_vertex_ai_dataset +google_vertex_ai_featurestore +google_vertex_ai_featurestore_entitytype +google_vertex_ai_tensorboard +google_vpc_access_connector diff --git a/config/provider.go b/config/provider.go index 1c928c443..f29ac5872 100644 --- a/config/provider.go +++ b/config/provider.go @@ -6,9 +6,12 @@ package config import ( "context" + "strings" + // Note(ezgidemirel): we are importing this to embed provider schema document _ "embed" + "github.com/crossplane/upjet/pkg/config" ujconfig "github.com/crossplane/upjet/pkg/config" "github.com/crossplane/upjet/pkg/config/conversion" "github.com/crossplane/upjet/pkg/registry/reference" @@ -79,6 +82,27 @@ var ( //go:embed provider-metadata.yaml providerMetadata []byte + + // oldSingletonListAPIs is a newline-delimited list of Terraform resource + // names with converted singleton list APIs with at least CRD API version + // containing the old singleton list API. This is to prevent the API + // conversion for the newly added resources whose CRD APIs will already + // use embedded objects instead of the singleton lists and thus, will + // not possess a CRD API version with the singleton list. Thus, for + // the newly added resources (resources added after the singleton lists + // have been converted), we do not need the CRD API conversion + // functions that convert between singleton lists and embedded objects, + // but we need only the Terraform conversion functions. + // This list is immutable and represents the set of resources with the + // already generated CRD API versions with now converted singleton lists. + // Because new resources should never have singleton lists in their + // generated APIs, there should be no need to add them to this list. + // However, bugs might result in exceptions in the future. + // Please see: + // https://github.com/crossplane-contrib/provider-upjet-gcp/pull/508 + // for more context on singleton list to embedded object conversions. + //go:embed old-singleton-list-apis.txt + oldSingletonListAPIs string ) var skipList = []string{ @@ -267,6 +291,12 @@ func resourceList(t map[string]ujconfig.ExternalName) []string { } func bumpVersionsWithEmbeddedLists(pc *ujconfig.Provider) { + l := strings.Split(strings.TrimSpace(oldSingletonListAPIs), "\n") + oldSLAPIs := make(map[string]struct{}, len(l)) + for _, n := range l { + oldSLAPIs[n] = struct{}{} + } + for n, r := range pc.Resources { r := r // nothing to do if no singleton list has been converted to @@ -274,16 +304,29 @@ func bumpVersionsWithEmbeddedLists(pc *ujconfig.Provider) { if len(r.CRDListConversionPaths()) == 0 { continue } - r.Version = "v1beta2" - r.PreviousVersions = []string{VersionV1Beta1} - // we would like to set the storage version to v1beta1 to facilitate - // downgrades. - r.SetCRDStorageVersion("v1beta1") - r.ControllerReconcileVersion = "v1beta1" - r.Conversions = []conversion.Conversion{ - conversion.NewIdentityConversionExpandPaths(conversion.AllVersions, conversion.AllVersions, conversion.DefaultPathPrefixes(), r.CRDListConversionPaths()...), - conversion.NewSingletonListConversion("v1beta1", "v1beta2", conversion.DefaultPathPrefixes(), r.CRDListConversionPaths(), conversion.ToEmbeddedObject), - conversion.NewSingletonListConversion("v1beta2", "v1beta1", conversion.DefaultPathPrefixes(), r.CRDListConversionPaths(), conversion.ToSingletonList)} + + if _, ok := oldSLAPIs[n]; ok { + r.Version = "v1beta2" + r.PreviousVersions = []string{"v1beta1"} + // we would like to set the storage version to v1beta1 to facilitate + // downgrades. + r.SetCRDStorageVersion("v1beta1") + // because the controller reconciles on the API version with the singleton list API, + // no need for a Terraform conversion. + r.ControllerReconcileVersion = "v1beta1" + r.Conversions = []conversion.Conversion{ + conversion.NewIdentityConversionExpandPaths(conversion.AllVersions, conversion.AllVersions, conversion.DefaultPathPrefixes(), r.CRDListConversionPaths()...), + conversion.NewSingletonListConversion("v1beta1", "v1beta2", conversion.DefaultPathPrefixes(), r.CRDListConversionPaths(), conversion.ToEmbeddedObject), + conversion.NewSingletonListConversion("v1beta2", "v1beta1", conversion.DefaultPathPrefixes(), r.CRDListConversionPaths(), conversion.ToSingletonList)} + } else { + // the controller will be reconciling on the CRD API version + // with the converted API (with embedded objects in place of + // singleton lists), so we need the appropriate Terraform + // converter in this case. + r.TerraformConversions = []config.TerraformConversion{ + config.NewTFSingletonConversion(), + } + } pc.Resources[n] = r } }