qontract-reconcile 0.10.2.dev349__py3-none-any.whl → 0.10.2.dev414__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.
- {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/METADATA +12 -11
- {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/RECORD +356 -350
- reconcile/acs_rbac.py +2 -2
- reconcile/aus/advanced_upgrade_service.py +15 -12
- reconcile/aus/base.py +26 -27
- reconcile/aus/cluster_version_data.py +15 -5
- reconcile/aus/models.py +1 -1
- reconcile/automated_actions/config/integration.py +15 -3
- reconcile/aws_account_manager/integration.py +8 -8
- reconcile/aws_account_manager/reconciler.py +3 -3
- reconcile/aws_ami_cleanup/integration.py +8 -12
- reconcile/aws_ami_share.py +69 -62
- reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
- reconcile/aws_ecr_image_pull_secrets.py +2 -2
- reconcile/aws_iam_keys.py +7 -41
- reconcile/aws_saml_idp/integration.py +12 -4
- reconcile/aws_saml_roles/integration.py +32 -25
- reconcile/aws_version_sync/integration.py +6 -12
- reconcile/change_owners/bundle.py +3 -3
- reconcile/change_owners/change_log_tracking.py +3 -2
- reconcile/change_owners/change_owners.py +1 -1
- reconcile/change_owners/diff.py +2 -4
- reconcile/checkpoint.py +11 -3
- reconcile/cli.py +33 -8
- reconcile/dashdotdb_dora.py +5 -12
- reconcile/dashdotdb_slo.py +1 -1
- reconcile/database_access_manager.py +123 -117
- reconcile/dynatrace_token_provider/integration.py +1 -1
- reconcile/endpoints_discovery/integration.py +4 -1
- reconcile/endpoints_discovery/merge_request.py +1 -1
- reconcile/endpoints_discovery/merge_request_manager.py +9 -11
- reconcile/external_resources/factories.py +5 -12
- reconcile/external_resources/integration.py +1 -1
- reconcile/external_resources/manager.py +24 -10
- reconcile/external_resources/meta.py +0 -1
- reconcile/external_resources/metrics.py +1 -1
- reconcile/external_resources/model.py +13 -13
- reconcile/external_resources/reconciler.py +7 -4
- reconcile/external_resources/secrets_sync.py +6 -8
- reconcile/external_resources/state.py +60 -17
- reconcile/fleet_labeler/integration.py +1 -1
- reconcile/gabi_authorized_users.py +8 -5
- reconcile/gcp_image_mirror.py +2 -2
- reconcile/github_org.py +1 -1
- reconcile/github_owners.py +4 -0
- reconcile/gitlab_housekeeping.py +13 -15
- reconcile/gitlab_members.py +6 -12
- reconcile/gitlab_mr_sqs_consumer.py +2 -2
- reconcile/gitlab_owners.py +15 -11
- reconcile/gitlab_permissions.py +8 -12
- reconcile/glitchtip_project_alerts/integration.py +3 -1
- reconcile/gql_definitions/acs/acs_instances.py +5 -5
- reconcile/gql_definitions/acs/acs_policies.py +5 -5
- reconcile/gql_definitions/acs/acs_rbac.py +5 -5
- reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
- reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
- reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
- reconcile/gql_definitions/automated_actions/instance.py +46 -7
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +5 -5
- reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +15 -5
- reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +27 -66
- reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +15 -5
- reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +15 -5
- reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
- reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
- reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
- reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
- reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
- reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
- reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
- reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
- reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
- reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_roles.py +5 -5
- reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
- reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
- reconcile/gql_definitions/common/apps.py +5 -5
- reconcile/gql_definitions/common/aws_vpc_requests.py +15 -5
- reconcile/gql_definitions/common/aws_vpcs.py +5 -5
- reconcile/gql_definitions/common/clusters.py +7 -5
- reconcile/gql_definitions/common/clusters_minimal.py +5 -5
- reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
- reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
- reconcile/gql_definitions/common/github_orgs.py +5 -5
- reconcile/gql_definitions/common/jira_settings.py +5 -5
- reconcile/gql_definitions/common/jiralert_settings.py +5 -5
- reconcile/gql_definitions/common/ldap_settings.py +5 -5
- reconcile/gql_definitions/common/namespaces.py +5 -5
- reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
- reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
- reconcile/gql_definitions/common/ocm_environments.py +5 -5
- reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
- reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
- reconcile/gql_definitions/common/pipeline_providers.py +5 -5
- reconcile/gql_definitions/common/quay_instances.py +5 -5
- reconcile/gql_definitions/common/quay_orgs.py +5 -5
- reconcile/gql_definitions/common/reserved_networks.py +5 -5
- reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
- reconcile/gql_definitions/common/saas_files.py +5 -5
- reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
- reconcile/gql_definitions/common/saasherder_settings.py +5 -5
- reconcile/gql_definitions/common/slack_workspaces.py +5 -5
- reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
- reconcile/gql_definitions/common/state_aws_account.py +5 -5
- reconcile/gql_definitions/common/users.py +5 -5
- reconcile/gql_definitions/common/users_with_paths.py +5 -5
- reconcile/gql_definitions/cost_report/app_names.py +5 -5
- reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
- reconcile/gql_definitions/cost_report/settings.py +5 -5
- reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
- reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
- reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
- reconcile/gql_definitions/email_sender/apps.py +5 -5
- reconcile/gql_definitions/email_sender/emails.py +5 -5
- reconcile/gql_definitions/email_sender/users.py +5 -5
- reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
- reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
- reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +89 -6
- reconcile/gql_definitions/external_resources/external_resources_settings.py +7 -5
- reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
- reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
- reconcile/gql_definitions/fragments/aus_organization.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
- reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
- reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
- reconcile/gql_definitions/fragments/aws_organization.py +33 -0
- reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
- reconcile/gql_definitions/fragments/aws_vpc_request.py +7 -5
- reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
- reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
- reconcile/gql_definitions/fragments/disable.py +5 -5
- reconcile/gql_definitions/fragments/email_service.py +5 -5
- reconcile/gql_definitions/fragments/email_user.py +5 -5
- reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
- reconcile/gql_definitions/fragments/membership_source.py +5 -5
- reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
- reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
- reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
- reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
- reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
- reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_values.py +5 -5
- reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
- reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
- reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
- reconcile/gql_definitions/fragments/terraform_state.py +5 -5
- reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
- reconcile/gql_definitions/fragments/user.py +5 -5
- reconcile/gql_definitions/fragments/vault_secret.py +5 -5
- reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
- reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
- reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
- reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
- reconcile/gql_definitions/integrations/integrations.py +5 -5
- reconcile/gql_definitions/introspection.json +2137 -1053
- reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
- reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
- reconcile/gql_definitions/jira/jira_servers.py +5 -5
- reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +9 -5
- reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
- reconcile/gql_definitions/ldap_groups/roles.py +5 -5
- reconcile/gql_definitions/ldap_groups/settings.py +5 -5
- reconcile/gql_definitions/maintenance/maintenances.py +5 -5
- reconcile/gql_definitions/membershipsources/roles.py +5 -5
- reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
- reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
- reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
- reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
- reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
- reconcile/gql_definitions/rhcs/certs.py +5 -5
- reconcile/gql_definitions/rhidp/organizations.py +5 -5
- reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
- reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
- reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
- reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
- reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
- reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
- reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
- reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
- reconcile/gql_definitions/slack_usergroups/users.py +5 -5
- reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
- reconcile/gql_definitions/status_board/status_board.py +5 -5
- reconcile/gql_definitions/statuspage/statuspages.py +5 -5
- reconcile/gql_definitions/templating/template_collection.py +5 -5
- reconcile/gql_definitions/templating/templates.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
- reconcile/gql_definitions/terraform_init/aws_accounts.py +19 -5
- reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
- reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +38 -6
- reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +15 -5
- reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
- reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
- reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +5 -5
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
- reconcile/integrations_manager.py +3 -3
- reconcile/jenkins_worker_fleets.py +10 -8
- reconcile/jira_permissions_validator.py +237 -122
- reconcile/ldap_groups/integration.py +1 -1
- reconcile/ocm/types.py +35 -56
- reconcile/ocm_aws_infrastructure_access.py +1 -1
- reconcile/ocm_clusters.py +4 -4
- reconcile/ocm_labels/integration.py +3 -2
- reconcile/ocm_machine_pools.py +23 -23
- reconcile/openshift_base.py +53 -2
- reconcile/openshift_cluster_bots.py +3 -2
- reconcile/openshift_namespace_labels.py +1 -1
- reconcile/openshift_namespaces.py +97 -101
- reconcile/openshift_resources_base.py +6 -2
- reconcile/openshift_rhcs_certs.py +5 -5
- reconcile/openshift_rolebindings.py +7 -11
- reconcile/openshift_saas_deploy.py +6 -7
- reconcile/openshift_saas_deploy_change_tester.py +9 -7
- reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
- reconcile/openshift_serviceaccount_tokens.py +2 -2
- reconcile/openshift_upgrade_watcher.py +4 -4
- reconcile/oum/labelset.py +5 -3
- reconcile/oum/models.py +1 -4
- reconcile/prometheus_rules_tester/integration.py +3 -3
- reconcile/quay_mirror.py +1 -1
- reconcile/queries.py +131 -1
- reconcile/rhidp/common.py +3 -5
- reconcile/rhidp/sso_client/base.py +1 -1
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
- reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
- reconcile/skupper_network/integration.py +2 -2
- reconcile/slack_usergroups.py +35 -14
- reconcile/sql_query.py +1 -0
- reconcile/status_board.py +6 -6
- reconcile/statuspage/atlassian.py +7 -7
- reconcile/statuspage/integrations/maintenances.py +4 -3
- reconcile/statuspage/page.py +4 -9
- reconcile/statuspage/status.py +5 -8
- reconcile/templates/rosa-classic-cluster-creation.sh.j2 +4 -0
- reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +3 -0
- reconcile/templating/lib/rendering.py +3 -3
- reconcile/templating/renderer.py +4 -3
- reconcile/terraform_aws_route53.py +7 -1
- reconcile/terraform_cloudflare_dns.py +3 -3
- reconcile/terraform_cloudflare_resources.py +5 -5
- reconcile/terraform_cloudflare_users.py +3 -2
- reconcile/terraform_init/integration.py +187 -23
- reconcile/terraform_repo.py +16 -12
- reconcile/terraform_resources.py +17 -7
- reconcile/terraform_tgw_attachments.py +27 -19
- reconcile/terraform_users.py +7 -0
- reconcile/terraform_vpc_peerings.py +14 -3
- reconcile/terraform_vpc_resources/integration.py +10 -1
- reconcile/typed_queries/aws_account_tags.py +41 -0
- reconcile/typed_queries/cost_report/app_names.py +1 -1
- reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
- reconcile/typed_queries/saas_files.py +13 -13
- reconcile/typed_queries/status_board.py +2 -2
- reconcile/unleash_feature_toggles/integration.py +4 -2
- reconcile/utils/acs/base.py +6 -3
- reconcile/utils/acs/policies.py +2 -2
- reconcile/utils/aggregated_list.py +4 -3
- reconcile/utils/aws_api.py +51 -54
- reconcile/utils/aws_api_typed/api.py +38 -9
- reconcile/utils/aws_api_typed/cloudformation.py +149 -0
- reconcile/utils/aws_api_typed/logs.py +73 -0
- reconcile/utils/aws_api_typed/organization.py +4 -2
- reconcile/utils/datetime_util.py +67 -0
- reconcile/utils/deadmanssnitch_api.py +1 -1
- reconcile/utils/differ.py +2 -3
- reconcile/utils/early_exit_cache.py +11 -12
- reconcile/utils/expiration.py +7 -3
- reconcile/utils/external_resource_spec.py +24 -1
- reconcile/utils/filtering.py +1 -1
- reconcile/utils/gitlab_api.py +7 -5
- reconcile/utils/glitchtip/client.py +6 -2
- reconcile/utils/glitchtip/models.py +25 -28
- reconcile/utils/gql.py +4 -7
- reconcile/utils/helm.py +2 -1
- reconcile/utils/helpers.py +1 -1
- reconcile/utils/instrumented_wrappers.py +1 -1
- reconcile/utils/internal_groups/client.py +2 -2
- reconcile/utils/internal_groups/models.py +8 -17
- reconcile/utils/jinja2/utils.py +6 -101
- reconcile/utils/jira_client.py +82 -63
- reconcile/utils/jjb_client.py +9 -12
- reconcile/utils/jobcontroller/controller.py +1 -1
- reconcile/utils/jobcontroller/models.py +17 -1
- reconcile/utils/json.py +70 -0
- reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
- reconcile/utils/membershipsources/models.py +16 -23
- reconcile/utils/membershipsources/resolver.py +4 -2
- reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
- reconcile/utils/merge_request_manager/parser.py +6 -6
- reconcile/utils/metrics.py +5 -5
- reconcile/utils/models.py +304 -82
- reconcile/utils/mr/app_interface_reporter.py +2 -2
- reconcile/utils/mr/base.py +2 -2
- reconcile/utils/mr/notificator.py +3 -3
- reconcile/utils/mr/update_access_report_base.py +3 -4
- reconcile/utils/mr/user_maintenance.py +3 -2
- reconcile/utils/oc.py +118 -97
- reconcile/utils/oc_filters.py +3 -3
- reconcile/utils/ocm/addons.py +0 -1
- reconcile/utils/ocm/base.py +17 -20
- reconcile/utils/ocm/cluster_groups.py +1 -1
- reconcile/utils/ocm/identity_providers.py +2 -2
- reconcile/utils/ocm/labels.py +1 -1
- reconcile/utils/ocm/products.py +9 -3
- reconcile/utils/ocm/search_filters.py +3 -6
- reconcile/utils/ocm/service_log.py +4 -6
- reconcile/utils/ocm/sre_capability_labels.py +20 -13
- reconcile/utils/openshift_resource.py +10 -5
- reconcile/utils/output.py +3 -2
- reconcile/utils/pagerduty_api.py +10 -7
- reconcile/utils/promotion_state.py +6 -11
- reconcile/utils/raw_github_api.py +1 -1
- reconcile/utils/rhcsv2_certs.py +1 -4
- reconcile/utils/runtime/integration.py +2 -3
- reconcile/utils/runtime/runner.py +2 -2
- reconcile/utils/saasherder/interfaces.py +13 -20
- reconcile/utils/saasherder/models.py +25 -21
- reconcile/utils/saasherder/saasherder.py +35 -24
- reconcile/utils/slack_api.py +26 -4
- reconcile/utils/sloth.py +171 -2
- reconcile/utils/sqs_gateway.py +2 -1
- reconcile/utils/state.py +2 -1
- reconcile/utils/structs.py +1 -1
- reconcile/utils/terraform_client.py +5 -4
- reconcile/utils/terrascript_aws_client.py +171 -114
- reconcile/utils/unleash/server.py +2 -8
- reconcile/utils/vault.py +5 -12
- reconcile/utils/vcs.py +8 -8
- reconcile/vault_replication.py +107 -42
- tools/app_interface_reporter.py +4 -4
- tools/cli_commands/cost_report/cost_management_api.py +3 -3
- tools/cli_commands/cost_report/view.py +7 -6
- tools/cli_commands/erv2.py +3 -1
- tools/cli_commands/systems_and_tools.py +5 -1
- tools/qontract_cli.py +31 -18
- tools/template_validation.py +3 -1
- {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev349.dist-info → qontract_reconcile-0.10.2.dev414.dist-info}/entry_points.txt +0 -0
|
@@ -22,7 +22,6 @@ from typing import (
|
|
|
22
22
|
TYPE_CHECKING,
|
|
23
23
|
Any,
|
|
24
24
|
Self,
|
|
25
|
-
TypeAlias,
|
|
26
25
|
cast,
|
|
27
26
|
)
|
|
28
27
|
|
|
@@ -152,6 +151,7 @@ from reconcile.github_org import get_default_config
|
|
|
152
151
|
from reconcile.gql_definitions.terraform_resources.terraform_resources_namespaces import (
|
|
153
152
|
NamespaceTerraformResourceLifecycleV1,
|
|
154
153
|
)
|
|
154
|
+
from reconcile.typed_queries.aws_account_tags import get_aws_account_tags
|
|
155
155
|
from reconcile.utils import gql
|
|
156
156
|
from reconcile.utils.aws_api import (
|
|
157
157
|
AmiTag,
|
|
@@ -178,7 +178,11 @@ from reconcile.utils.external_resources import (
|
|
|
178
178
|
from reconcile.utils.git import is_file_in_git_repo
|
|
179
179
|
from reconcile.utils.gitlab_api import GitLabApi
|
|
180
180
|
from reconcile.utils.jenkins_api import JenkinsApi
|
|
181
|
-
from reconcile.utils.jinja2.utils import
|
|
181
|
+
from reconcile.utils.jinja2.utils import (
|
|
182
|
+
process_extracurlyjinja2_template,
|
|
183
|
+
process_jinja2_template,
|
|
184
|
+
)
|
|
185
|
+
from reconcile.utils.json import json_dumps
|
|
182
186
|
from reconcile.utils.password_validator import (
|
|
183
187
|
PasswordPolicy,
|
|
184
188
|
PasswordValidator,
|
|
@@ -202,7 +206,7 @@ if TYPE_CHECKING:
|
|
|
202
206
|
from reconcile.utils.ocm import OCMMap
|
|
203
207
|
|
|
204
208
|
|
|
205
|
-
TFResource
|
|
209
|
+
type TFResource = type[
|
|
206
210
|
Resource | Data | Module | Provider | Variable | Output | Locals | Terraform
|
|
207
211
|
]
|
|
208
212
|
|
|
@@ -267,6 +271,7 @@ VARIABLE_KEYS = [
|
|
|
267
271
|
"extra_tags",
|
|
268
272
|
"lifecycle",
|
|
269
273
|
"max_session_duration",
|
|
274
|
+
"secret_format",
|
|
270
275
|
]
|
|
271
276
|
|
|
272
277
|
EMAIL_REGEX = re.compile(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
|
|
@@ -286,12 +291,6 @@ SUPPORTED_ALB_LISTENER_RULE_CONDITION_TYPE_MAPPING = {
|
|
|
286
291
|
"source-ip": "source_ip",
|
|
287
292
|
}
|
|
288
293
|
|
|
289
|
-
DEFAULT_TAGS = {
|
|
290
|
-
"tags": {
|
|
291
|
-
"app": "app-sre-infra",
|
|
292
|
-
},
|
|
293
|
-
}
|
|
294
|
-
|
|
295
294
|
AWS_ELB_ACCOUNT_IDS = {
|
|
296
295
|
"us-east-1": "127311923021",
|
|
297
296
|
"us-east-2": "033677994240",
|
|
@@ -475,6 +474,7 @@ class TerrascriptClient:
|
|
|
475
474
|
integration_prefix: str,
|
|
476
475
|
thread_pool_size: int,
|
|
477
476
|
accounts: Iterable[MutableMapping[str, Any]],
|
|
477
|
+
default_tags: Mapping[str, str] | None,
|
|
478
478
|
settings: Mapping[str, Any] | None = None,
|
|
479
479
|
prefetch_resources_by_schemas: Iterable[str] | None = None,
|
|
480
480
|
secret_reader: SecretReaderBase | None = None,
|
|
@@ -488,6 +488,7 @@ class TerrascriptClient:
|
|
|
488
488
|
else:
|
|
489
489
|
self.secret_reader = SecretReader(settings=settings)
|
|
490
490
|
self.configs: dict[str, dict] = {}
|
|
491
|
+
self.default_tags = default_tags or {"app": "app-sre-infra"}
|
|
491
492
|
self.populate_configs(filtered_accounts)
|
|
492
493
|
self.versions: dict[str, str] = {
|
|
493
494
|
a["name"]: a["providerVersion"] for a in filtered_accounts
|
|
@@ -508,7 +509,7 @@ class TerrascriptClient:
|
|
|
508
509
|
region=region,
|
|
509
510
|
alias=region,
|
|
510
511
|
skip_region_validation=True,
|
|
511
|
-
default_tags=
|
|
512
|
+
default_tags={"tags": config["tags"]},
|
|
512
513
|
)
|
|
513
514
|
|
|
514
515
|
# Add default region, which will be in resourcesDefaultRegion
|
|
@@ -517,7 +518,7 @@ class TerrascriptClient:
|
|
|
517
518
|
secret_key=config["aws_secret_access_key"],
|
|
518
519
|
region=config["resourcesDefaultRegion"],
|
|
519
520
|
skip_region_validation=True,
|
|
520
|
-
default_tags=
|
|
521
|
+
default_tags={"tags": config["tags"]},
|
|
521
522
|
)
|
|
522
523
|
|
|
523
524
|
ts += Terraform(
|
|
@@ -800,6 +801,9 @@ class TerrascriptClient:
|
|
|
800
801
|
config["supportedDeploymentRegions"] = account["supportedDeploymentRegions"]
|
|
801
802
|
config["resourcesDefaultRegion"] = account["resourcesDefaultRegion"]
|
|
802
803
|
config["terraformState"] = account["terraformState"]
|
|
804
|
+
config["tags"] = dict(self.default_tags) | get_aws_account_tags(
|
|
805
|
+
account.get("organization", None)
|
|
806
|
+
)
|
|
803
807
|
self.configs[account_name] = config
|
|
804
808
|
|
|
805
809
|
def _get_partition(self, account: str) -> str:
|
|
@@ -1054,7 +1058,9 @@ class TerrascriptClient:
|
|
|
1054
1058
|
ignore_changes = (
|
|
1055
1059
|
"all" if "all" in lifecycle.ignore_changes else lifecycle.ignore_changes
|
|
1056
1060
|
)
|
|
1057
|
-
return lifecycle.
|
|
1061
|
+
return lifecycle.model_dump(by_alias=True) | {
|
|
1062
|
+
"ignore_changes": ignore_changes
|
|
1063
|
+
}
|
|
1058
1064
|
return None
|
|
1059
1065
|
|
|
1060
1066
|
def populate_additional_providers(
|
|
@@ -1069,25 +1075,15 @@ class TerrascriptClient:
|
|
|
1069
1075
|
config = self.configs[account_name]
|
|
1070
1076
|
existing_provider_aliases = {p.get("alias") for p in ts["provider"]["aws"]}
|
|
1071
1077
|
if alias not in existing_provider_aliases:
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
)
|
|
1082
|
-
else:
|
|
1083
|
-
ts += provider.aws(
|
|
1084
|
-
access_key=config["aws_access_key_id"],
|
|
1085
|
-
secret_key=config["aws_secret_access_key"],
|
|
1086
|
-
region=region,
|
|
1087
|
-
alias=alias,
|
|
1088
|
-
skip_region_validation=True,
|
|
1089
|
-
default_tags=DEFAULT_TAGS,
|
|
1090
|
-
)
|
|
1078
|
+
ts += provider.aws(
|
|
1079
|
+
access_key=config["aws_access_key_id"],
|
|
1080
|
+
secret_key=config["aws_secret_access_key"],
|
|
1081
|
+
region=region,
|
|
1082
|
+
alias=alias,
|
|
1083
|
+
skip_region_validation=True,
|
|
1084
|
+
default_tags={"tags": config["tags"]},
|
|
1085
|
+
**{"assume_role": {"role_arn": assume_role}} if assume_role else {},
|
|
1086
|
+
)
|
|
1091
1087
|
|
|
1092
1088
|
def populate_route53(
|
|
1093
1089
|
self, desired_state: Iterable[Mapping[str, Any]], default_ttl: int = 300
|
|
@@ -1430,7 +1426,7 @@ class TerrascriptClient:
|
|
|
1430
1426
|
req_account_name = req_account.name
|
|
1431
1427
|
# Accepter's side of the connection - the cluster's account
|
|
1432
1428
|
acc_account = accepter.account
|
|
1433
|
-
acc_alias = self.get_provider_alias(acc_account.
|
|
1429
|
+
acc_alias = self.get_provider_alias(acc_account.model_dump(by_alias=True))
|
|
1434
1430
|
acc_uid = acc_account.uid
|
|
1435
1431
|
if acc_account.assume_role:
|
|
1436
1432
|
acc_uid = awsh.get_account_uid_from_arn(acc_account.assume_role)
|
|
@@ -1947,7 +1943,7 @@ class TerrascriptClient:
|
|
|
1947
1943
|
em_identifier = f"{identifier}-enhanced-monitoring"
|
|
1948
1944
|
em_values = {
|
|
1949
1945
|
"name": em_identifier,
|
|
1950
|
-
"assume_role_policy":
|
|
1946
|
+
"assume_role_policy": json_dumps(assume_role_policy),
|
|
1951
1947
|
}
|
|
1952
1948
|
role_tf_resource = aws_iam_role(em_identifier, **em_values)
|
|
1953
1949
|
tf_resources.append(role_tf_resource)
|
|
@@ -2216,6 +2212,43 @@ class TerrascriptClient:
|
|
|
2216
2212
|
letters_and_digits = string.ascii_letters + string.digits
|
|
2217
2213
|
return "".join(random.choice(letters_and_digits) for i in range(string_length))
|
|
2218
2214
|
|
|
2215
|
+
@staticmethod
|
|
2216
|
+
def _build_tf_resource_s3_lifecycle_rules(
|
|
2217
|
+
versioning: bool,
|
|
2218
|
+
common_values: Mapping[str, Any],
|
|
2219
|
+
) -> list[dict]:
|
|
2220
|
+
lifecycle_rules = common_values.get("lifecycle_rules") or []
|
|
2221
|
+
if versioning and not any(
|
|
2222
|
+
"noncurrent_version_expiration" in lr for lr in lifecycle_rules
|
|
2223
|
+
):
|
|
2224
|
+
# Add a default noncurrent object expiration rule
|
|
2225
|
+
# if one isn't already set
|
|
2226
|
+
rule = {
|
|
2227
|
+
"id": "expire_noncurrent_versions",
|
|
2228
|
+
"enabled": True,
|
|
2229
|
+
"noncurrent_version_expiration": {"days": 30},
|
|
2230
|
+
"expiration": {"expired_object_delete_marker": True},
|
|
2231
|
+
"abort_incomplete_multipart_upload_days": 3,
|
|
2232
|
+
}
|
|
2233
|
+
lifecycle_rules.append(rule)
|
|
2234
|
+
|
|
2235
|
+
if storage_class := common_values.get("storage_class"):
|
|
2236
|
+
sc = storage_class.upper()
|
|
2237
|
+
days = "1"
|
|
2238
|
+
if sc.endswith("_IA"):
|
|
2239
|
+
# Infrequent Access storage class has minimum 30 days
|
|
2240
|
+
# before transition
|
|
2241
|
+
days = "30"
|
|
2242
|
+
rule = {
|
|
2243
|
+
"id": sc + "_storage_class",
|
|
2244
|
+
"enabled": True,
|
|
2245
|
+
"transition": {"days": days, "storage_class": sc},
|
|
2246
|
+
"noncurrent_version_transition": {"days": days, "storage_class": sc},
|
|
2247
|
+
}
|
|
2248
|
+
lifecycle_rules.append(rule)
|
|
2249
|
+
|
|
2250
|
+
return lifecycle_rules
|
|
2251
|
+
|
|
2219
2252
|
def populate_tf_resource_s3(self, spec: ExternalResourceSpec) -> aws_s3_bucket:
|
|
2220
2253
|
account = spec.provisioner_name
|
|
2221
2254
|
identifier = spec.identifier
|
|
@@ -2255,47 +2288,11 @@ class TerrascriptClient:
|
|
|
2255
2288
|
request_payer = common_values.get("request_payer")
|
|
2256
2289
|
if request_payer:
|
|
2257
2290
|
values["request_payer"] = request_payer
|
|
2258
|
-
lifecycle_rules
|
|
2259
|
-
|
|
2260
|
-
|
|
2291
|
+
if lifecycle_rules := self._build_tf_resource_s3_lifecycle_rules(
|
|
2292
|
+
versioning=versioning,
|
|
2293
|
+
common_values=common_values,
|
|
2294
|
+
):
|
|
2261
2295
|
values["lifecycle_rule"] = lifecycle_rules
|
|
2262
|
-
if versioning:
|
|
2263
|
-
lrs = values.get("lifecycle_rule", [])
|
|
2264
|
-
expiration_rule = False
|
|
2265
|
-
for lr in lrs:
|
|
2266
|
-
if "noncurrent_version_expiration" in lr:
|
|
2267
|
-
expiration_rule = True
|
|
2268
|
-
break
|
|
2269
|
-
if not expiration_rule:
|
|
2270
|
-
# Add a default noncurrent object expiration rule if
|
|
2271
|
-
# if one isn't already set
|
|
2272
|
-
rule = {
|
|
2273
|
-
"id": "expire_noncurrent_versions",
|
|
2274
|
-
"enabled": "true",
|
|
2275
|
-
"noncurrent_version_expiration": {"days": 30},
|
|
2276
|
-
}
|
|
2277
|
-
if len(lrs) > 0:
|
|
2278
|
-
lrs.append(rule)
|
|
2279
|
-
else:
|
|
2280
|
-
lrs = rule
|
|
2281
|
-
sc = common_values.get("storage_class")
|
|
2282
|
-
if sc:
|
|
2283
|
-
sc = sc.upper()
|
|
2284
|
-
days = "1"
|
|
2285
|
-
if sc.endswith("_IA"):
|
|
2286
|
-
# Infrequent Access storage class has minimum 30 days
|
|
2287
|
-
# before transition
|
|
2288
|
-
days = "30"
|
|
2289
|
-
rule = {
|
|
2290
|
-
"id": sc + "_storage_class",
|
|
2291
|
-
"enabled": "true",
|
|
2292
|
-
"transition": {"days": days, "storage_class": sc},
|
|
2293
|
-
"noncurrent_version_transition": {"days": days, "storage_class": sc},
|
|
2294
|
-
}
|
|
2295
|
-
if values.get("lifecycle_rule"):
|
|
2296
|
-
values["lifecycle_rule"].append(rule)
|
|
2297
|
-
else:
|
|
2298
|
-
values["lifecycle_rule"] = rule
|
|
2299
2296
|
cors_rules = common_values.get("cors_rules")
|
|
2300
2297
|
if cors_rules:
|
|
2301
2298
|
# common_values['cors_rules'] is a list of cors_rules
|
|
@@ -2345,7 +2342,7 @@ class TerrascriptClient:
|
|
|
2345
2342
|
}
|
|
2346
2343
|
],
|
|
2347
2344
|
}
|
|
2348
|
-
rc_values["assume_role_policy"] =
|
|
2345
|
+
rc_values["assume_role_policy"] = json_dumps(role)
|
|
2349
2346
|
role_resource = aws_iam_role(id, **rc_values)
|
|
2350
2347
|
tf_resources.append(role_resource)
|
|
2351
2348
|
|
|
@@ -2383,7 +2380,7 @@ class TerrascriptClient:
|
|
|
2383
2380
|
},
|
|
2384
2381
|
],
|
|
2385
2382
|
}
|
|
2386
|
-
rc_values["policy"] =
|
|
2383
|
+
rc_values["policy"] = json_dumps(policy)
|
|
2387
2384
|
policy_resource = aws_iam_policy(id, **rc_values)
|
|
2388
2385
|
tf_resources.append(policy_resource)
|
|
2389
2386
|
|
|
@@ -2598,7 +2595,7 @@ class TerrascriptClient:
|
|
|
2598
2595
|
},
|
|
2599
2596
|
],
|
|
2600
2597
|
}
|
|
2601
|
-
values["policy"] =
|
|
2598
|
+
values["policy"] = json_dumps(policy)
|
|
2602
2599
|
values["depends_on"] = self.get_dependencies([user_tf_resource])
|
|
2603
2600
|
|
|
2604
2601
|
tf_aws_iam_policy = aws_iam_policy(identifier, **values)
|
|
@@ -2877,7 +2874,7 @@ class TerrascriptClient:
|
|
|
2877
2874
|
values: dict[str, Any] = {
|
|
2878
2875
|
"name": identifier,
|
|
2879
2876
|
"tags": common_values["tags"],
|
|
2880
|
-
"assume_role_policy":
|
|
2877
|
+
"assume_role_policy": json_dumps(assume_role_policy),
|
|
2881
2878
|
}
|
|
2882
2879
|
|
|
2883
2880
|
inline_policy = common_values.get("inline_policy")
|
|
@@ -2931,7 +2928,7 @@ class TerrascriptClient:
|
|
|
2931
2928
|
self, account: str, name: str, policy: Mapping[str, Any]
|
|
2932
2929
|
) -> None:
|
|
2933
2930
|
tf_aws_iam_policy = aws_iam_policy(
|
|
2934
|
-
f"{account}-{name}", name=name, policy=
|
|
2931
|
+
f"{account}-{name}", name=name, policy=json_dumps(policy)
|
|
2935
2932
|
)
|
|
2936
2933
|
self.add_resource(account, tf_aws_iam_policy)
|
|
2937
2934
|
|
|
@@ -2973,7 +2970,7 @@ class TerrascriptClient:
|
|
|
2973
2970
|
role_tf_resource = aws_iam_role(
|
|
2974
2971
|
f"{account}-{name}",
|
|
2975
2972
|
name=name,
|
|
2976
|
-
assume_role_policy=
|
|
2973
|
+
assume_role_policy=json_dumps(assume_role_policy),
|
|
2977
2974
|
managed_policy_arns=managed_policy_arns,
|
|
2978
2975
|
max_session_duration=max_session_duration_hours * 3600,
|
|
2979
2976
|
)
|
|
@@ -3017,7 +3014,7 @@ class TerrascriptClient:
|
|
|
3017
3014
|
all_queues.append(queue_name)
|
|
3018
3015
|
sqs_policy = values.pop("sqs_policy", None)
|
|
3019
3016
|
if sqs_policy is not None:
|
|
3020
|
-
values["policy"] =
|
|
3017
|
+
values["policy"] = json_dumps(sqs_policy)
|
|
3021
3018
|
dl_queue = values.pop("dl_queue", None)
|
|
3022
3019
|
if dl_queue is not None:
|
|
3023
3020
|
max_receive_count = int(values.pop("max_receive_count", 10))
|
|
@@ -3031,9 +3028,7 @@ class TerrascriptClient:
|
|
|
3031
3028
|
"deadLetterTargetArn": "${" + dl_data.arn + "}",
|
|
3032
3029
|
"maxReceiveCount": max_receive_count,
|
|
3033
3030
|
}
|
|
3034
|
-
values["redrive_policy"] =
|
|
3035
|
-
redrive_policy, sort_keys=True
|
|
3036
|
-
)
|
|
3031
|
+
values["redrive_policy"] = json_dumps(redrive_policy)
|
|
3037
3032
|
kms_master_key_id = values.pop("kms_master_key_id", None)
|
|
3038
3033
|
if kms_master_key_id is not None:
|
|
3039
3034
|
if kms_master_key_id.startswith("arn:"):
|
|
@@ -3106,7 +3101,7 @@ class TerrascriptClient:
|
|
|
3106
3101
|
"Resource": list(kms_keys),
|
|
3107
3102
|
}
|
|
3108
3103
|
policy["Statement"].append(kms_statement)
|
|
3109
|
-
values["policy"] =
|
|
3104
|
+
values["policy"] = json_dumps(policy)
|
|
3110
3105
|
policy_tf_resource = aws_iam_policy(policy_identifier, **values)
|
|
3111
3106
|
tf_resources.append(policy_tf_resource)
|
|
3112
3107
|
|
|
@@ -3256,7 +3251,7 @@ class TerrascriptClient:
|
|
|
3256
3251
|
}
|
|
3257
3252
|
],
|
|
3258
3253
|
}
|
|
3259
|
-
values["policy"] =
|
|
3254
|
+
values["policy"] = json_dumps(policy)
|
|
3260
3255
|
values["depends_on"] = self.get_dependencies([user_tf_resource])
|
|
3261
3256
|
|
|
3262
3257
|
tf_aws_iam_policy = aws_iam_policy(identifier, **values)
|
|
@@ -3366,7 +3361,7 @@ class TerrascriptClient:
|
|
|
3366
3361
|
},
|
|
3367
3362
|
],
|
|
3368
3363
|
}
|
|
3369
|
-
values_policy["policy"] =
|
|
3364
|
+
values_policy["policy"] = json_dumps(policy)
|
|
3370
3365
|
values_policy["depends_on"] = self.get_dependencies([user_tf_resource])
|
|
3371
3366
|
|
|
3372
3367
|
tf_aws_iam_policy = aws_iam_policy(identifier, **values_policy)
|
|
@@ -3416,7 +3411,7 @@ class TerrascriptClient:
|
|
|
3416
3411
|
}
|
|
3417
3412
|
],
|
|
3418
3413
|
}
|
|
3419
|
-
values_policy["policy"] =
|
|
3414
|
+
values_policy["policy"] = json_dumps(policy)
|
|
3420
3415
|
values_policy["depends_on"] = self.get_dependencies([bucket_tf_resource])
|
|
3421
3416
|
region = common_values.get("region") or self.default_regions.get(account)
|
|
3422
3417
|
assert region # make mypy happy
|
|
@@ -3562,7 +3557,7 @@ class TerrascriptClient:
|
|
|
3562
3557
|
}
|
|
3563
3558
|
],
|
|
3564
3559
|
}
|
|
3565
|
-
sqs_values["policy"] =
|
|
3560
|
+
sqs_values["policy"] = json_dumps(sqs_policy)
|
|
3566
3561
|
|
|
3567
3562
|
kms_encryption = common_values.get("kms_encryption", False)
|
|
3568
3563
|
if kms_encryption:
|
|
@@ -3598,7 +3593,7 @@ class TerrascriptClient:
|
|
|
3598
3593
|
},
|
|
3599
3594
|
],
|
|
3600
3595
|
}
|
|
3601
|
-
kms_values["policy"] =
|
|
3596
|
+
kms_values["policy"] = json_dumps(kms_policy)
|
|
3602
3597
|
if provider:
|
|
3603
3598
|
kms_values["provider"] = provider
|
|
3604
3599
|
|
|
@@ -3696,7 +3691,7 @@ class TerrascriptClient:
|
|
|
3696
3691
|
"Resource": [sqs_values["kms_master_key_id"]],
|
|
3697
3692
|
}
|
|
3698
3693
|
policy["Statement"].append(kms_statement)
|
|
3699
|
-
values_policy["policy"] =
|
|
3694
|
+
values_policy["policy"] = json_dumps(policy)
|
|
3700
3695
|
policy_tf_resource = aws_iam_policy(sqs_identifier, **values_policy)
|
|
3701
3696
|
tf_resources.append(policy_tf_resource)
|
|
3702
3697
|
|
|
@@ -3767,7 +3762,7 @@ class TerrascriptClient:
|
|
|
3767
3762
|
role_identifier = f"{identifier}-lambda-execution-role"
|
|
3768
3763
|
role_values = {
|
|
3769
3764
|
"name": role_identifier,
|
|
3770
|
-
"assume_role_policy":
|
|
3765
|
+
"assume_role_policy": json_dumps(assume_role_policy),
|
|
3771
3766
|
}
|
|
3772
3767
|
|
|
3773
3768
|
role_tf_resource = aws_iam_role(role_identifier, **role_values)
|
|
@@ -3799,7 +3794,7 @@ class TerrascriptClient:
|
|
|
3799
3794
|
|
|
3800
3795
|
policy_values = {
|
|
3801
3796
|
"role": "${" + role_tf_resource.id + "}",
|
|
3802
|
-
"policy":
|
|
3797
|
+
"policy": json_dumps(policy),
|
|
3803
3798
|
}
|
|
3804
3799
|
policy_tf_resource = aws_iam_role_policy(policy_identifier, **policy_values)
|
|
3805
3800
|
tf_resources.append(policy_tf_resource)
|
|
@@ -3927,7 +3922,7 @@ class TerrascriptClient:
|
|
|
3927
3922
|
}
|
|
3928
3923
|
values = {
|
|
3929
3924
|
"name": identifier,
|
|
3930
|
-
"policy":
|
|
3925
|
+
"policy": json_dumps(policy),
|
|
3931
3926
|
"depends_on": self.get_dependencies([user_tf_resource]),
|
|
3932
3927
|
}
|
|
3933
3928
|
|
|
@@ -4048,7 +4043,7 @@ class TerrascriptClient:
|
|
|
4048
4043
|
role_identifier = f"{identifier}-lambda-execution-role"
|
|
4049
4044
|
role_values = {
|
|
4050
4045
|
"name": role_identifier,
|
|
4051
|
-
"assume_role_policy":
|
|
4046
|
+
"assume_role_policy": json_dumps(assume_role_policy),
|
|
4052
4047
|
"tags": tags,
|
|
4053
4048
|
}
|
|
4054
4049
|
|
|
@@ -4085,7 +4080,7 @@ class TerrascriptClient:
|
|
|
4085
4080
|
policy_tf_resource = aws_iam_policy(
|
|
4086
4081
|
policy_identifier,
|
|
4087
4082
|
name=policy_identifier,
|
|
4088
|
-
policy=
|
|
4083
|
+
policy=json_dumps(policy),
|
|
4089
4084
|
tags=tags,
|
|
4090
4085
|
)
|
|
4091
4086
|
tf_resources.append(policy_tf_resource)
|
|
@@ -4300,7 +4295,7 @@ class TerrascriptClient:
|
|
|
4300
4295
|
# iam user policy
|
|
4301
4296
|
values_policy: dict[str, Any] = {
|
|
4302
4297
|
"name": identifier,
|
|
4303
|
-
"policy":
|
|
4298
|
+
"policy": json_dumps(policy),
|
|
4304
4299
|
"depends_on": self.get_dependencies([user_tf_resource]),
|
|
4305
4300
|
}
|
|
4306
4301
|
|
|
@@ -4418,10 +4413,7 @@ class TerrascriptClient:
|
|
|
4418
4413
|
|
|
4419
4414
|
:return: key is AWS account name and value is terraform configuration
|
|
4420
4415
|
"""
|
|
4421
|
-
return {
|
|
4422
|
-
name: json.dumps(ts, indent=2, sort_keys=True)
|
|
4423
|
-
for name, ts in self.tss.items()
|
|
4424
|
-
}
|
|
4416
|
+
return {name: json_dumps(ts, indent=2) for name, ts in self.tss.items()}
|
|
4425
4417
|
|
|
4426
4418
|
def init_values(
|
|
4427
4419
|
self, spec: ExternalResourceSpec, init_tags: bool = True
|
|
@@ -4533,7 +4525,7 @@ class TerrascriptClient:
|
|
|
4533
4525
|
output_name = output_format.format(
|
|
4534
4526
|
spec.output_prefix, self.integration_prefix, "annotations"
|
|
4535
4527
|
)
|
|
4536
|
-
anno_json =
|
|
4528
|
+
anno_json = json_dumps(spec.annotations()).encode("utf-8")
|
|
4537
4529
|
output_value = base64.b64encode(anno_json).decode()
|
|
4538
4530
|
tf_resources.append(Output(output_name, value=output_value))
|
|
4539
4531
|
|
|
@@ -4673,7 +4665,7 @@ class TerrascriptClient:
|
|
|
4673
4665
|
}
|
|
4674
4666
|
log_groups_policy_values = {
|
|
4675
4667
|
"policy_name": "es-log-publishing-permissions",
|
|
4676
|
-
"policy_document":
|
|
4668
|
+
"policy_document": json_dumps(log_groups_policy),
|
|
4677
4669
|
}
|
|
4678
4670
|
resource_policy = aws_cloudwatch_log_resource_policy(
|
|
4679
4671
|
"es_log_publishing_resource_policy",
|
|
@@ -5005,7 +4997,7 @@ class TerrascriptClient:
|
|
|
5005
4997
|
}
|
|
5006
4998
|
],
|
|
5007
4999
|
}
|
|
5008
|
-
es_values["access_policies"] =
|
|
5000
|
+
es_values["access_policies"] = json_dumps(access_policies)
|
|
5009
5001
|
|
|
5010
5002
|
region = values.get("region") or self.default_regions.get(account)
|
|
5011
5003
|
assert region # make mypy happy
|
|
@@ -5061,7 +5053,7 @@ class TerrascriptClient:
|
|
|
5061
5053
|
|
|
5062
5054
|
version_values = {
|
|
5063
5055
|
"secret_id": "${" + aws_secret_resource.id + "}",
|
|
5064
|
-
"secret_string":
|
|
5056
|
+
"secret_string": json_dumps(master_user),
|
|
5065
5057
|
}
|
|
5066
5058
|
if provider:
|
|
5067
5059
|
version_values["provider"] = provider
|
|
@@ -5088,7 +5080,7 @@ class TerrascriptClient:
|
|
|
5088
5080
|
iam_policy_resource = aws_iam_policy(
|
|
5089
5081
|
secret_identifier,
|
|
5090
5082
|
name=f"{identifier}-secretsmanager-policy",
|
|
5091
|
-
policy=
|
|
5083
|
+
policy=json_dumps(policy),
|
|
5092
5084
|
tags=tags,
|
|
5093
5085
|
)
|
|
5094
5086
|
tf_resources.append(iam_policy_resource)
|
|
@@ -5500,7 +5492,7 @@ class TerrascriptClient:
|
|
|
5500
5492
|
lb_access_logs_s3_bucket_policy_values = {
|
|
5501
5493
|
"provider": provider,
|
|
5502
5494
|
"bucket": f"${{{lb_access_logs_s3_bucket_tf_resource.id}}}",
|
|
5503
|
-
"policy":
|
|
5495
|
+
"policy": json_dumps(policy),
|
|
5504
5496
|
}
|
|
5505
5497
|
lb_access_logs_s3_bucket_policy_tf_resource = aws_s3_bucket_policy(
|
|
5506
5498
|
policy_identifier, **lb_access_logs_s3_bucket_policy_values
|
|
@@ -5813,9 +5805,13 @@ class TerrascriptClient:
|
|
|
5813
5805
|
assert secret # make mypy happy
|
|
5814
5806
|
secret_data = self.secret_reader.read_all(secret)
|
|
5815
5807
|
|
|
5808
|
+
secret_format = common_values.get("secret_format")
|
|
5809
|
+
if secret_format is not None:
|
|
5810
|
+
secret_data = self._apply_secret_format(str(secret_format), secret_data)
|
|
5811
|
+
|
|
5816
5812
|
version_values: dict[str, Any] = {
|
|
5817
5813
|
"secret_id": "${" + aws_secret_resource.id + "}",
|
|
5818
|
-
"secret_string":
|
|
5814
|
+
"secret_string": json_dumps(secret_data),
|
|
5819
5815
|
}
|
|
5820
5816
|
|
|
5821
5817
|
if self._multiregion_account(account):
|
|
@@ -5836,6 +5832,66 @@ class TerrascriptClient:
|
|
|
5836
5832
|
|
|
5837
5833
|
self.add_resources(account, tf_resources)
|
|
5838
5834
|
|
|
5835
|
+
@staticmethod
|
|
5836
|
+
def _unflatten_dotted_keys_dict(flat_dict: dict[str, str]) -> dict[str, Any]:
|
|
5837
|
+
"""Convert a flat dictionary with dotted keys to a nested dictionary.
|
|
5838
|
+
|
|
5839
|
+
Example:
|
|
5840
|
+
{"db.host": "localhost", "db.port": "5432"} ->
|
|
5841
|
+
{"db": {"host": "localhost", "port": "5432"}}
|
|
5842
|
+
|
|
5843
|
+
Raises:
|
|
5844
|
+
ValueError: If there are conflicting keys (e.g., "a.b" and "a.b.c")
|
|
5845
|
+
"""
|
|
5846
|
+
result: dict[str, Any] = {}
|
|
5847
|
+
for key, value in flat_dict.items():
|
|
5848
|
+
parts = key.split(".")
|
|
5849
|
+
current = result
|
|
5850
|
+
for i, part in enumerate(parts[:-1]):
|
|
5851
|
+
if part not in current:
|
|
5852
|
+
current[part] = {}
|
|
5853
|
+
elif not isinstance(current[part], dict):
|
|
5854
|
+
# Conflict: trying to traverse through a non-dict value
|
|
5855
|
+
conflicting_path = ".".join(parts[: i + 1])
|
|
5856
|
+
raise ValueError(
|
|
5857
|
+
f"Conflicting keys detected: '{conflicting_path}' is both a "
|
|
5858
|
+
f"value and a nested path in key '{key}'"
|
|
5859
|
+
)
|
|
5860
|
+
current = current[part]
|
|
5861
|
+
|
|
5862
|
+
# Check if we're trying to set a value where a dict already exists
|
|
5863
|
+
if parts[-1] in current and isinstance(current[parts[-1]], dict):
|
|
5864
|
+
raise ValueError(
|
|
5865
|
+
f"Conflicting keys detected: '{key}' conflicts with nested keys"
|
|
5866
|
+
)
|
|
5867
|
+
|
|
5868
|
+
current[parts[-1]] = value
|
|
5869
|
+
|
|
5870
|
+
return result
|
|
5871
|
+
|
|
5872
|
+
@staticmethod
|
|
5873
|
+
def _apply_secret_format(
|
|
5874
|
+
secret_format: str, secret_data: dict[str, str]
|
|
5875
|
+
) -> dict[str, str]:
|
|
5876
|
+
# Convert flat dict with dotted keys to nested dict for Jinja2
|
|
5877
|
+
nested_secret_data = TerrascriptClient._unflatten_dotted_keys_dict(secret_data)
|
|
5878
|
+
rendered_data = process_jinja2_template(secret_format, nested_secret_data)
|
|
5879
|
+
|
|
5880
|
+
parsed_data = json.loads(rendered_data)
|
|
5881
|
+
|
|
5882
|
+
if not isinstance(parsed_data, dict):
|
|
5883
|
+
raise ValueError("secret_format must be a dictionary")
|
|
5884
|
+
|
|
5885
|
+
# validate secret is a dict[str, str]
|
|
5886
|
+
for k, v in parsed_data.items():
|
|
5887
|
+
if not isinstance(k, str):
|
|
5888
|
+
raise ValueError(f"key '{k}' is not a string")
|
|
5889
|
+
|
|
5890
|
+
if not isinstance(v, str):
|
|
5891
|
+
raise ValueError(f"dictionary value '{v}' under '{k}' is not a string")
|
|
5892
|
+
|
|
5893
|
+
return parsed_data
|
|
5894
|
+
|
|
5839
5895
|
def get_commit_sha(self, repo_info: Mapping) -> str:
|
|
5840
5896
|
url = repo_info["url"]
|
|
5841
5897
|
ref = repo_info["ref"]
|
|
@@ -5854,7 +5910,8 @@ class TerrascriptClient:
|
|
|
5854
5910
|
return commit.sha
|
|
5855
5911
|
case "gitlab":
|
|
5856
5912
|
gitlab = self.init_gitlab()
|
|
5857
|
-
project
|
|
5913
|
+
if not (project := gitlab.get_project(url)):
|
|
5914
|
+
raise ValueError(f"could not find gitlab project for url {url}")
|
|
5858
5915
|
commits = project.commits.list(ref_name=ref, per_page=1, page=1)
|
|
5859
5916
|
return commits[0].id
|
|
5860
5917
|
case _:
|
|
@@ -6135,7 +6192,7 @@ class TerrascriptClient:
|
|
|
6135
6192
|
lambda_iam_role_resource = aws_iam_role(
|
|
6136
6193
|
"lambda_role",
|
|
6137
6194
|
name=f"ocm-{identifier}-cognito-lambda-role",
|
|
6138
|
-
assume_role_policy=
|
|
6195
|
+
assume_role_policy=json_dumps(lambda_role_policy),
|
|
6139
6196
|
managed_policy_arns=[lambda_managed_policy_arn],
|
|
6140
6197
|
force_detach_policies=False,
|
|
6141
6198
|
max_session_duration=3600,
|
|
@@ -6810,7 +6867,7 @@ class TerrascriptClient:
|
|
|
6810
6867
|
)
|
|
6811
6868
|
tf_resources.append(api_gateway_stage_resource)
|
|
6812
6869
|
|
|
6813
|
-
rest_api_policy =
|
|
6870
|
+
rest_api_policy = json_dumps({
|
|
6814
6871
|
"Version": "2012-10-17",
|
|
6815
6872
|
"Statement": [
|
|
6816
6873
|
{
|
|
@@ -6914,7 +6971,7 @@ class TerrascriptClient:
|
|
|
6914
6971
|
},
|
|
6915
6972
|
],
|
|
6916
6973
|
}
|
|
6917
|
-
cloudwatch_assume_role_policy =
|
|
6974
|
+
cloudwatch_assume_role_policy = json_dumps(policy)
|
|
6918
6975
|
|
|
6919
6976
|
cloudwatch_iam_role_resource = aws_iam_role(
|
|
6920
6977
|
"cloudwatch_assume_role",
|
|
@@ -6942,7 +6999,7 @@ class TerrascriptClient:
|
|
|
6942
6999
|
],
|
|
6943
7000
|
}
|
|
6944
7001
|
|
|
6945
|
-
cloudwatch_iam_policy_document =
|
|
7002
|
+
cloudwatch_iam_policy_document = json_dumps(policy)
|
|
6946
7003
|
|
|
6947
7004
|
cloudwatch_iam_policy_resource = aws_iam_policy(
|
|
6948
7005
|
"cloudwatch",
|
|
@@ -7187,7 +7244,7 @@ class TerrascriptClient:
|
|
|
7187
7244
|
|
|
7188
7245
|
version_values = {
|
|
7189
7246
|
"secret_id": "${" + secret_resource.arn + "}",
|
|
7190
|
-
"secret_string":
|
|
7247
|
+
"secret_string": json_dumps(secret),
|
|
7191
7248
|
}
|
|
7192
7249
|
version_resource = aws_secretsmanager_secret_version(
|
|
7193
7250
|
secret_identifier, **version_values
|
|
@@ -7196,7 +7253,7 @@ class TerrascriptClient:
|
|
|
7196
7253
|
|
|
7197
7254
|
secret_policy_values = {
|
|
7198
7255
|
"secret_arn": "${" + secret_resource.arn + "}",
|
|
7199
|
-
"policy":
|
|
7256
|
+
"policy": json_dumps({
|
|
7200
7257
|
"Version": "2012-10-17",
|
|
7201
7258
|
"Statement": [
|
|
7202
7259
|
{
|
|
@@ -24,30 +24,24 @@ class Environment(BaseModel):
|
|
|
24
24
|
return self.name == other
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class FeatureToggle(BaseModel):
|
|
27
|
+
class FeatureToggle(BaseModel, validate_by_name=True, validate_by_alias=True):
|
|
28
28
|
name: str
|
|
29
29
|
type: FeatureToggleType = FeatureToggleType.release
|
|
30
30
|
description: str | None = None
|
|
31
31
|
impression_data: bool = Field(False, alias="impressionData")
|
|
32
32
|
environments: list[Environment]
|
|
33
33
|
|
|
34
|
-
class Config:
|
|
35
|
-
allow_population_by_field_name = True
|
|
36
|
-
|
|
37
34
|
def __eq__(self, other: object) -> bool:
|
|
38
35
|
if isinstance(other, FeatureToggle):
|
|
39
36
|
return self.name == other.name
|
|
40
37
|
return self.name == other
|
|
41
38
|
|
|
42
39
|
|
|
43
|
-
class Project(BaseModel):
|
|
40
|
+
class Project(BaseModel, validate_by_name=True, validate_by_alias=True):
|
|
44
41
|
pk: str = Field(alias="id")
|
|
45
42
|
name: str
|
|
46
43
|
feature_toggles: list[FeatureToggle] = []
|
|
47
44
|
|
|
48
|
-
class Config:
|
|
49
|
-
allow_population_by_field_name = True
|
|
50
|
-
|
|
51
45
|
|
|
52
46
|
class TokenAuth(BearerTokenAuth):
|
|
53
47
|
def __call__(self, r: requests.PreparedRequest) -> requests.PreparedRequest:
|