diff --git a/config/old-singleton-list-apis.txt b/config/old-singleton-list-apis.txt new file mode 100644 index 0000000000..e92cdbee3b --- /dev/null +++ b/config/old-singleton-list-apis.txt @@ -0,0 +1,324 @@ +aws_accessanalyzer_analyzer +aws_acm_certificate +aws_acmpca_certificate +aws_acmpca_certificate_authority +aws_amplify_app +aws_api_gateway_documentation_part +aws_api_gateway_domain_name +aws_api_gateway_integration +aws_api_gateway_method_settings +aws_api_gateway_rest_api +aws_api_gateway_stage +aws_api_gateway_usage_plan +aws_apigatewayv2_api +aws_apigatewayv2_authorizer +aws_apigatewayv2_domain_name +aws_apigatewayv2_integration +aws_apigatewayv2_stage +aws_appautoscaling_policy +aws_appautoscaling_scheduled_action +aws_appflow_flow +aws_appintegrations_event_integration +aws_appmesh_gateway_route +aws_appmesh_mesh +aws_appmesh_route +aws_appmesh_virtual_gateway +aws_appmesh_virtual_node +aws_appmesh_virtual_router +aws_appmesh_virtual_service +aws_apprunner_observability_configuration +aws_apprunner_service +aws_appstream_directory_config +aws_appstream_fleet +aws_appstream_image_builder +aws_appstream_stack +aws_appsync_datasource +aws_appsync_function +aws_appsync_graphql_api +aws_appsync_resolver +aws_athena_database +aws_athena_workgroup +aws_autoscaling_group +aws_autoscaling_group_tag +aws_autoscaling_policy +aws_autoscalingplans_scaling_plan +aws_backup_framework +aws_backup_plan +aws_backup_report_plan +aws_batch_job_definition +aws_batch_scheduling_policy +aws_budgets_budget +aws_budgets_budget_action +aws_chime_voice_connector_streaming +aws_cloudformation_stack_set +aws_cloudformation_stack_set_instance +aws_cloudfront_cache_policy +aws_cloudfront_distribution +aws_cloudfront_field_level_encryption_config +aws_cloudfront_field_level_encryption_profile +aws_cloudfront_monitoring_subscription +aws_cloudfront_origin_request_policy +aws_cloudfront_realtime_log_config +aws_cloudfront_response_headers_policy +aws_cloudsearch_domain +aws_cloudwatch_composite_alarm +aws_cloudwatch_event_connection +aws_cloudwatch_event_permission +aws_cloudwatch_event_target +aws_cloudwatch_log_metric_filter +aws_cloudwatch_metric_alarm +aws_codedeploy_deployment_config +aws_codedeploy_deployment_group +aws_codepipeline +aws_codepipeline_custom_action_type +aws_codepipeline_webhook +aws_codestarconnections_host +aws_cognito_risk_configuration +aws_cognito_user_pool +aws_config_config_rule +aws_config_configuration_aggregator +aws_config_configuration_recorder +aws_config_delivery_channel +aws_config_remediation_configuration +aws_connect_bot_association +aws_connect_hours_of_operation +aws_connect_instance_storage_config +aws_connect_queue +aws_connect_quick_connect +aws_connect_user +aws_connect_user_hierarchy_structure +aws_datasync_location_s3 +aws_datasync_task +aws_dax_cluster +aws_db_instance +aws_db_proxy_default_target_group +aws_devicefarm_test_grid_project +aws_directory_service_directory +aws_directory_service_shared_directory +aws_dlm_lifecycle_policy +aws_dms_endpoint +aws_dynamodb_table +aws_ebs_snapshot_import +aws_ec2_traffic_mirror_filter_rule +aws_ecr_replication_configuration +aws_ecr_repository +aws_ecrpublic_repository +aws_ecs_capacity_provider +aws_ecs_cluster +aws_ecs_service +aws_ecs_task_definition +aws_efs_access_point +aws_efs_backup_policy +aws_efs_file_system +aws_efs_replication_configuration +aws_eks_cluster +aws_eks_identity_provider_config +aws_eks_node_group +aws_elastic_beanstalk_application +aws_elasticache_user +aws_elasticsearch_domain +aws_elasticsearch_domain_saml_options +aws_elastictranscoder_pipeline +aws_elastictranscoder_preset +aws_elb +aws_emrserverless_application +aws_evidently_feature +aws_evidently_project +aws_fis_experiment_template +aws_flow_log +aws_fsx_data_repository_association +aws_fsx_lustre_file_system +aws_fsx_ontap_file_system +aws_fsx_ontap_storage_virtual_machine +aws_fsx_windows_file_system +aws_gamelift_alias +aws_gamelift_build +aws_gamelift_fleet +aws_gamelift_script +aws_glacier_vault +aws_globalaccelerator_accelerator +aws_glue_catalog_database +aws_glue_catalog_table +aws_glue_classifier +aws_glue_connection +aws_glue_crawler +aws_glue_data_catalog_encryption_settings +aws_glue_job +aws_glue_security_configuration +aws_glue_trigger +aws_grafana_workspace +aws_guardduty_detector +aws_guardduty_filter +aws_identitystore_user +aws_imagebuilder_container_recipe +aws_imagebuilder_distribution_configuration +aws_imagebuilder_image +aws_imagebuilder_image_pipeline +aws_imagebuilder_image_recipe +aws_imagebuilder_infrastructure_configuration +aws_instance +aws_iot_indexing_configuration +aws_iot_provisioning_template +aws_iot_thing_group +aws_iot_thing_type +aws_iot_topic_rule +aws_iot_topic_rule_destination +aws_ivs_recording_configuration +aws_kendra_data_source +aws_kendra_experience +aws_kendra_index +aws_kendra_query_suggestions_block_list +aws_kendra_thesaurus +aws_keyspaces_table +aws_kinesis_analytics_application +aws_kinesis_firehose_delivery_stream +aws_kinesis_stream +aws_kinesisanalyticsv2_application +aws_lakeformation_permissions +aws_lambda_alias +aws_lambda_code_signing_config +aws_lambda_event_source_mapping +aws_lambda_function +aws_lambda_function_event_invoke_config +aws_lambda_function_url +aws_launch_configuration +aws_launch_template +aws_lb +aws_lb_listener +aws_lb_listener_rule +aws_lb_target_group +aws_lex_bot +aws_lex_bot_alias +aws_lex_intent +aws_lightsail_container_service +aws_lightsail_instance +aws_location_place_index +aws_macie2_classification_job +aws_macie2_findings_filter +aws_media_convert_queue +aws_medialive_channel +aws_medialive_input +aws_medialive_multiplex +aws_memorydb_user +aws_mq_broker +aws_msk_cluster +aws_msk_serverless_cluster +aws_mskconnect_connector +aws_mskconnect_custom_plugin +aws_neptune_cluster +aws_networkfirewall_firewall +aws_networkfirewall_firewall_policy +aws_networkfirewall_logging_configuration +aws_networkfirewall_rule_group +aws_networkmanager_connect_attachment +aws_networkmanager_device +aws_networkmanager_link +aws_networkmanager_site +aws_networkmanager_vpc_attachment +aws_opensearch_domain +aws_opensearch_domain_saml_options +aws_opsworks_custom_layer +aws_opsworks_ecs_cluster_layer +aws_opsworks_ganglia_layer +aws_opsworks_haproxy_layer +aws_opsworks_java_app_layer +aws_opsworks_memcached_layer +aws_opsworks_mysql_layer +aws_opsworks_nodejs_app_layer +aws_opsworks_php_app_layer +aws_opsworks_rails_app_layer +aws_opsworks_stack +aws_opsworks_static_web_layer +aws_pinpoint_app +aws_prometheus_workspace +aws_qldb_stream +aws_rds_cluster +aws_redshift_cluster +aws_redshift_scheduled_action +aws_resourcegroups_group +aws_route53_record +aws_route53recoverycontrolconfig_safety_rule +aws_route53recoveryreadiness_resource_set +aws_rum_app_monitor +aws_s3_access_point +aws_s3_bucket +aws_s3_bucket_acl +aws_s3_bucket_analytics_configuration +aws_s3_bucket_intelligent_tiering_configuration +aws_s3_bucket_inventory +aws_s3_bucket_lifecycle_configuration +aws_s3_bucket_logging +aws_s3_bucket_metric +aws_s3_bucket_object_lock_configuration +aws_s3_bucket_ownership_controls +aws_s3_bucket_replication_configuration +aws_s3_bucket_server_side_encryption_configuration +aws_s3_bucket_versioning +aws_s3_bucket_website_configuration +aws_s3_object +aws_s3control_multi_region_access_point +aws_s3control_multi_region_access_point_policy +aws_s3control_object_lambda_access_point +aws_s3control_storage_lens_configuration +aws_sagemaker_app +aws_sagemaker_app_image_config +aws_sagemaker_code_repository +aws_sagemaker_device +aws_sagemaker_device_fleet +aws_sagemaker_domain +aws_sagemaker_endpoint +aws_sagemaker_endpoint_configuration +aws_sagemaker_feature_group +aws_sagemaker_model +aws_sagemaker_notebook_instance +aws_sagemaker_space +aws_sagemaker_user_profile +aws_sagemaker_workforce +aws_sagemaker_workteam +aws_scheduler_schedule +aws_secretsmanager_secret_rotation +aws_securityhub_insight +aws_service_discovery_service +aws_servicecatalog_product +aws_servicecatalog_service_action +aws_ses_configuration_set +aws_ses_event_destination +aws_sesv2_configuration_set +aws_sesv2_configuration_set_event_destination +aws_sesv2_email_identity +aws_sfn_state_machine +aws_signer_signing_job +aws_signer_signing_profile +aws_spot_fleet_request +aws_spot_instance_request +aws_ssm_association +aws_ssm_maintenance_window_task +aws_ssm_resource_data_sync +aws_ssoadmin_customer_managed_policy_attachment +aws_ssoadmin_permissions_boundary_attachment +aws_timestreamwrite_table +aws_transcribe_language_model +aws_transfer_connector +aws_transfer_server +aws_transfer_user +aws_transfer_workflow +aws_vpc_endpoint +aws_vpc_ipam_pool_cidr +aws_vpc_peering_connection +aws_vpc_peering_connection_accepter +aws_vpc_peering_connection_options +aws_vpn_connection +aws_waf_byte_match_set +aws_waf_regex_match_set +aws_waf_size_constraint_set +aws_waf_sql_injection_match_set +aws_waf_web_acl +aws_waf_xss_match_set +aws_wafregional_byte_match_set +aws_wafregional_regex_match_set +aws_wafregional_size_constraint_set +aws_wafregional_sql_injection_match_set +aws_wafregional_web_acl +aws_wafregional_xss_match_set +aws_workspaces_directory +aws_xray_group diff --git a/config/registry.go b/config/registry.go index ec41e339a8..ead43fe384 100644 --- a/config/registry.go +++ b/config/registry.go @@ -6,11 +6,11 @@ package config import ( "context" - // Note(ezgidemirel): we are importing this to embed provider schema document _ "embed" "fmt" "regexp" "strconv" + "strings" "github.com/crossplane/upjet/pkg/config" "github.com/crossplane/upjet/pkg/config/conversion" @@ -34,6 +34,27 @@ var ( //go:embed field-rename.yaml fieldRename []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-aws/pull/1332 + // for more context on singleton list to embedded object conversions. + //go:embed old-singleton-list-apis.txt + oldSingletonListAPIs string ) var skipList = []string{ @@ -153,6 +174,12 @@ func GetProvider(ctx context.Context, generationProvider bool) (*config.Provider } func bumpVersionsWithEmbeddedLists(pc *config.Provider) error { + l := strings.Split(strings.TrimSpace(oldSingletonListAPIs), "\n") + oldSLAPIs := make(map[string]struct{}, len(l)) + for _, n := range l { + oldSLAPIs[n] = struct{}{} + } + for name, r := range pc.Resources { r := r // nothing to do if no singleton list has been converted to @@ -161,34 +188,52 @@ func bumpVersionsWithEmbeddedLists(pc *config.Provider) error { continue } - bumped, err := bumpAPIVersion(r.Version) - if err != nil { - return errors.Wrapf(err, errFmtCannotBumpSingletonList, r.Name) - } - - if r.PreviousVersions == nil { - prev, err := getPreviousVersions(bumped) - if err != nil { - return errors.Wrapf(err, errFmtCannotFindPrev, r.Name) + if _, ok := oldSLAPIs[name]; ok { + if err := configureSingletonListAPIConverters(r); err != nil { + return errors.Wrap(err, "failed to configure singleton list API converters") + } + } 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(), } - r.PreviousVersions = prev } - - currentVer := r.Version - r.Version = bumped - // we would like to set the storage version to v1beta1 to facilitate - // downgrades. - r.SetCRDStorageVersion(currentVer) - r.ControllerReconcileVersion = currentVer - r.Conversions = []conversion.Conversion{ - conversion.NewIdentityConversionExpandPaths(conversion.AllVersions, conversion.AllVersions, conversion.DefaultPathPrefixes(), r.CRDListConversionPaths()...), - conversion.NewSingletonListConversion(conversion.AllVersions, bumped, conversion.DefaultPathPrefixes(), r.CRDListConversionPaths(), conversion.ToEmbeddedObject), - conversion.NewSingletonListConversion(bumped, conversion.AllVersions, conversion.DefaultPathPrefixes(), r.CRDListConversionPaths(), conversion.ToSingletonList)} pc.Resources[name] = r } return nil } +func configureSingletonListAPIConverters(r *config.Resource) error { + bumped, err := bumpAPIVersion(r.Version) + if err != nil { + return errors.Wrapf(err, errFmtCannotBumpSingletonList, r.Name) + } + + if r.PreviousVersions == nil { + prev, err := getPreviousVersions(bumped) + if err != nil { + return errors.Wrapf(err, errFmtCannotFindPrev, r.Name) + } + r.PreviousVersions = prev + } + currentVer := r.Version + r.Version = bumped + // we would like to set the storage version to v1beta1 to facilitate + // downgrades. + r.SetCRDStorageVersion(currentVer) + // because the controller reconciles on the API version with the singleton list API, + // no need for a Terraform conversion. + r.ControllerReconcileVersion = currentVer + r.Conversions = []conversion.Conversion{ + conversion.NewIdentityConversionExpandPaths(conversion.AllVersions, conversion.AllVersions, conversion.DefaultPathPrefixes(), r.CRDListConversionPaths()...), + conversion.NewSingletonListConversion(conversion.AllVersions, bumped, conversion.DefaultPathPrefixes(), r.CRDListConversionPaths(), conversion.ToEmbeddedObject), + conversion.NewSingletonListConversion(bumped, conversion.AllVersions, conversion.DefaultPathPrefixes(), r.CRDListConversionPaths(), conversion.ToSingletonList)} + return nil +} + // returns a new API version by bumping the last number if the // API version string is a Kubernetes API version string such // as v1alpha1, v1beta1 or v1. Otherwise, returns an error.