qontract-reconcile 0.9.1rc298__py3-none-any.whl → 0.10.1.dev1203__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.1.dev1203.dist-info/METADATA +500 -0
- qontract_reconcile-0.10.1.dev1203.dist-info/RECORD +771 -0
- {qontract_reconcile-0.9.1rc298.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/WHEEL +1 -2
- {qontract_reconcile-0.9.1rc298.dist-info → qontract_reconcile-0.10.1.dev1203.dist-info}/entry_points.txt +4 -2
- reconcile/acs_notifiers.py +126 -0
- reconcile/acs_policies.py +243 -0
- reconcile/acs_rbac.py +596 -0
- reconcile/aus/advanced_upgrade_service.py +621 -8
- reconcile/aus/aus_label_source.py +115 -0
- reconcile/aus/base.py +1053 -353
- reconcile/{utils → aus}/cluster_version_data.py +27 -12
- reconcile/aus/healthchecks.py +77 -0
- reconcile/aus/metrics.py +158 -0
- reconcile/aus/models.py +245 -5
- reconcile/aus/node_pool_spec.py +35 -0
- reconcile/aus/ocm_addons_upgrade_scheduler_org.py +225 -110
- reconcile/aus/ocm_upgrade_scheduler.py +76 -71
- reconcile/aus/ocm_upgrade_scheduler_org.py +81 -23
- reconcile/aus/version_gate_approver.py +204 -0
- reconcile/aus/version_gates/__init__.py +12 -0
- reconcile/aus/version_gates/handler.py +33 -0
- reconcile/aus/version_gates/ingress_gate_handler.py +32 -0
- reconcile/aus/version_gates/ocp_gate_handler.py +26 -0
- reconcile/aus/version_gates/sts_version_gate_handler.py +100 -0
- reconcile/aws_account_manager/README.md +5 -0
- reconcile/aws_account_manager/integration.py +373 -0
- reconcile/aws_account_manager/merge_request_manager.py +114 -0
- reconcile/aws_account_manager/metrics.py +39 -0
- reconcile/aws_account_manager/reconciler.py +403 -0
- reconcile/aws_account_manager/utils.py +41 -0
- reconcile/aws_ami_cleanup/integration.py +273 -0
- reconcile/aws_ami_share.py +18 -14
- reconcile/aws_cloudwatch_log_retention/integration.py +253 -0
- reconcile/aws_iam_keys.py +1 -1
- reconcile/aws_iam_password_reset.py +56 -20
- reconcile/aws_saml_idp/integration.py +204 -0
- reconcile/aws_saml_roles/integration.py +322 -0
- reconcile/aws_support_cases_sos.py +2 -2
- reconcile/aws_version_sync/integration.py +430 -0
- reconcile/aws_version_sync/merge_request_manager/merge_request.py +156 -0
- reconcile/aws_version_sync/merge_request_manager/merge_request_manager.py +160 -0
- reconcile/aws_version_sync/utils.py +64 -0
- reconcile/blackbox_exporter_endpoint_monitoring.py +2 -5
- reconcile/change_owners/README.md +34 -0
- reconcile/change_owners/approver.py +7 -9
- reconcile/change_owners/bundle.py +134 -9
- reconcile/change_owners/change_log_tracking.py +236 -0
- reconcile/change_owners/change_owners.py +204 -194
- reconcile/change_owners/change_types.py +183 -265
- reconcile/change_owners/changes.py +488 -0
- reconcile/change_owners/decision.py +120 -41
- reconcile/change_owners/diff.py +63 -92
- reconcile/change_owners/implicit_ownership.py +19 -16
- reconcile/change_owners/self_service_roles.py +158 -35
- reconcile/change_owners/tester.py +20 -18
- reconcile/checkpoint.py +4 -6
- reconcile/cli.py +1523 -242
- reconcile/closedbox_endpoint_monitoring_base.py +10 -17
- reconcile/cluster_auth_rhidp/integration.py +257 -0
- reconcile/cluster_deployment_mapper.py +2 -5
- reconcile/cna/assets/asset.py +4 -7
- reconcile/cna/assets/null.py +2 -5
- reconcile/cna/integration.py +2 -3
- reconcile/cna/state.py +6 -9
- reconcile/dashdotdb_base.py +31 -10
- reconcile/dashdotdb_cso.py +3 -6
- reconcile/dashdotdb_dora.py +530 -0
- reconcile/dashdotdb_dvo.py +10 -13
- reconcile/dashdotdb_slo.py +75 -19
- reconcile/database_access_manager.py +753 -0
- reconcile/deadmanssnitch.py +207 -0
- reconcile/dynatrace_token_provider/dependencies.py +69 -0
- reconcile/dynatrace_token_provider/integration.py +656 -0
- reconcile/dynatrace_token_provider/metrics.py +62 -0
- reconcile/dynatrace_token_provider/model.py +14 -0
- reconcile/dynatrace_token_provider/ocm.py +140 -0
- reconcile/dynatrace_token_provider/validate.py +48 -0
- reconcile/endpoints_discovery/integration.py +348 -0
- reconcile/endpoints_discovery/merge_request.py +96 -0
- reconcile/endpoints_discovery/merge_request_manager.py +178 -0
- reconcile/external_resources/aws.py +204 -0
- reconcile/external_resources/factories.py +163 -0
- reconcile/external_resources/integration.py +194 -0
- reconcile/external_resources/integration_secrets_sync.py +47 -0
- reconcile/external_resources/manager.py +405 -0
- reconcile/external_resources/meta.py +17 -0
- reconcile/external_resources/metrics.py +95 -0
- reconcile/external_resources/model.py +350 -0
- reconcile/external_resources/reconciler.py +265 -0
- reconcile/external_resources/secrets_sync.py +465 -0
- reconcile/external_resources/state.py +258 -0
- reconcile/gabi_authorized_users.py +19 -11
- reconcile/gcr_mirror.py +43 -34
- reconcile/github_org.py +4 -6
- reconcile/github_owners.py +1 -1
- reconcile/github_repo_invites.py +2 -5
- reconcile/gitlab_fork_compliance.py +14 -13
- reconcile/gitlab_housekeeping.py +185 -91
- reconcile/gitlab_labeler.py +15 -14
- reconcile/gitlab_members.py +126 -120
- reconcile/gitlab_owners.py +53 -66
- reconcile/gitlab_permissions.py +167 -6
- reconcile/glitchtip/README.md +150 -0
- reconcile/glitchtip/integration.py +99 -51
- reconcile/glitchtip/reconciler.py +99 -70
- reconcile/glitchtip_project_alerts/__init__.py +0 -0
- reconcile/glitchtip_project_alerts/integration.py +333 -0
- reconcile/glitchtip_project_dsn/integration.py +43 -43
- reconcile/gql_definitions/acs/__init__.py +0 -0
- reconcile/gql_definitions/acs/acs_instances.py +83 -0
- reconcile/gql_definitions/acs/acs_policies.py +239 -0
- reconcile/gql_definitions/acs/acs_rbac.py +111 -0
- reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +46 -8
- reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +38 -8
- reconcile/gql_definitions/app_interface_metrics_exporter/__init__.py +0 -0
- reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +61 -0
- reconcile/gql_definitions/aws_account_manager/__init__.py +0 -0
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +177 -0
- reconcile/gql_definitions/aws_ami_cleanup/__init__.py +0 -0
- reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +161 -0
- reconcile/gql_definitions/aws_saml_idp/__init__.py +0 -0
- reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +117 -0
- reconcile/gql_definitions/aws_saml_roles/__init__.py +0 -0
- reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +117 -0
- reconcile/gql_definitions/aws_saml_roles/roles.py +97 -0
- reconcile/gql_definitions/aws_version_sync/__init__.py +0 -0
- reconcile/gql_definitions/aws_version_sync/clusters.py +83 -0
- reconcile/gql_definitions/aws_version_sync/namespaces.py +143 -0
- reconcile/gql_definitions/change_owners/queries/change_types.py +16 -29
- reconcile/gql_definitions/change_owners/queries/self_service_roles.py +45 -11
- reconcile/gql_definitions/cluster_auth_rhidp/__init__.py +0 -0
- reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +128 -0
- reconcile/gql_definitions/cna/queries/cna_provisioners.py +6 -8
- reconcile/gql_definitions/cna/queries/cna_resources.py +3 -5
- reconcile/gql_definitions/common/alerting_services_settings.py +2 -2
- reconcile/gql_definitions/common/app_code_component_repos.py +9 -5
- reconcile/gql_definitions/{glitchtip/glitchtip_settings.py → common/app_interface_custom_messages.py} +14 -16
- reconcile/gql_definitions/common/app_interface_dms_settings.py +86 -0
- reconcile/gql_definitions/common/app_interface_repo_settings.py +2 -2
- reconcile/gql_definitions/common/app_interface_state_settings.py +3 -5
- reconcile/gql_definitions/common/app_interface_vault_settings.py +3 -5
- reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +120 -0
- reconcile/gql_definitions/common/apps.py +72 -0
- reconcile/gql_definitions/common/aws_vpc_requests.py +109 -0
- reconcile/gql_definitions/common/aws_vpcs.py +84 -0
- reconcile/gql_definitions/common/clusters.py +120 -254
- reconcile/gql_definitions/common/clusters_minimal.py +11 -35
- reconcile/gql_definitions/common/clusters_with_dms.py +72 -0
- reconcile/gql_definitions/common/clusters_with_peering.py +70 -98
- reconcile/gql_definitions/common/github_orgs.py +2 -2
- reconcile/gql_definitions/common/jira_settings.py +68 -0
- reconcile/gql_definitions/common/jiralert_settings.py +68 -0
- reconcile/gql_definitions/common/namespaces.py +74 -32
- reconcile/gql_definitions/common/namespaces_minimal.py +4 -10
- reconcile/gql_definitions/common/ocm_env_telemeter.py +95 -0
- reconcile/gql_definitions/common/ocm_environments.py +4 -2
- reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
- reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -11
- reconcile/gql_definitions/common/pipeline_providers.py +45 -90
- reconcile/gql_definitions/common/quay_instances.py +64 -0
- reconcile/gql_definitions/common/quay_orgs.py +68 -0
- reconcile/gql_definitions/common/reserved_networks.py +94 -0
- reconcile/gql_definitions/common/saas_files.py +133 -95
- reconcile/gql_definitions/common/saas_target_namespaces.py +41 -26
- reconcile/gql_definitions/common/saasherder_settings.py +2 -2
- reconcile/gql_definitions/common/slack_workspaces.py +62 -0
- reconcile/gql_definitions/common/smtp_client_settings.py +2 -2
- reconcile/gql_definitions/common/state_aws_account.py +77 -0
- reconcile/gql_definitions/common/users.py +3 -2
- reconcile/gql_definitions/cost_report/__init__.py +0 -0
- reconcile/gql_definitions/cost_report/app_names.py +68 -0
- reconcile/gql_definitions/cost_report/cost_namespaces.py +86 -0
- reconcile/gql_definitions/cost_report/settings.py +77 -0
- reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +42 -12
- reconcile/gql_definitions/dynatrace_token_provider/__init__.py +0 -0
- reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +79 -0
- reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +84 -0
- reconcile/gql_definitions/endpoints_discovery/__init__.py +0 -0
- reconcile/gql_definitions/endpoints_discovery/namespaces.py +127 -0
- reconcile/gql_definitions/external_resources/__init__.py +0 -0
- reconcile/gql_definitions/external_resources/aws_accounts.py +73 -0
- reconcile/gql_definitions/external_resources/external_resources_modules.py +78 -0
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +1111 -0
- reconcile/gql_definitions/external_resources/external_resources_settings.py +98 -0
- reconcile/gql_definitions/fragments/aus_organization.py +34 -39
- reconcile/gql_definitions/fragments/aws_account_common.py +62 -0
- reconcile/gql_definitions/fragments/aws_account_managed.py +57 -0
- reconcile/gql_definitions/fragments/aws_account_sso.py +35 -0
- reconcile/gql_definitions/fragments/aws_infra_management_account.py +2 -2
- reconcile/gql_definitions/fragments/aws_vpc.py +47 -0
- reconcile/gql_definitions/fragments/aws_vpc_request.py +65 -0
- reconcile/gql_definitions/fragments/aws_vpc_request_subnet.py +29 -0
- reconcile/gql_definitions/fragments/deplopy_resources.py +7 -7
- reconcile/gql_definitions/fragments/disable.py +28 -0
- reconcile/gql_definitions/fragments/jumphost_common_fields.py +2 -2
- reconcile/gql_definitions/fragments/membership_source.py +47 -0
- reconcile/gql_definitions/fragments/minimal_ocm_organization.py +29 -0
- reconcile/gql_definitions/fragments/oc_connection_cluster.py +4 -9
- reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
- reconcile/gql_definitions/fragments/pipeline_provider_retention.py +30 -0
- reconcile/gql_definitions/fragments/prometheus_instance.py +48 -0
- reconcile/gql_definitions/fragments/resource_limits_requirements.py +29 -0
- reconcile/gql_definitions/fragments/{resource_requirements.py → resource_requests_requirements.py} +3 -3
- reconcile/gql_definitions/fragments/resource_values.py +2 -2
- reconcile/gql_definitions/fragments/saas_target_namespace.py +55 -12
- reconcile/gql_definitions/fragments/serviceaccount_token.py +38 -0
- reconcile/gql_definitions/fragments/terraform_state.py +36 -0
- reconcile/gql_definitions/fragments/upgrade_policy.py +5 -3
- reconcile/gql_definitions/fragments/user.py +3 -2
- reconcile/gql_definitions/fragments/vault_secret.py +2 -2
- reconcile/gql_definitions/gitlab_members/gitlab_instances.py +6 -2
- reconcile/gql_definitions/gitlab_members/permissions.py +3 -5
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +16 -2
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +22 -23
- reconcile/gql_definitions/glitchtip_project_alerts/__init__.py +0 -0
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +173 -0
- reconcile/gql_definitions/integrations/integrations.py +62 -45
- reconcile/gql_definitions/introspection.json +51176 -0
- reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +13 -5
- reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +79 -0
- reconcile/gql_definitions/jira/__init__.py +0 -0
- reconcile/gql_definitions/jira/jira_servers.py +80 -0
- reconcile/gql_definitions/jira_permissions_validator/__init__.py +0 -0
- reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +131 -0
- reconcile/gql_definitions/jumphosts/jumphosts.py +3 -5
- reconcile/gql_definitions/ldap_groups/__init__.py +0 -0
- reconcile/gql_definitions/ldap_groups/roles.py +111 -0
- reconcile/gql_definitions/ldap_groups/settings.py +79 -0
- reconcile/gql_definitions/maintenance/__init__.py +0 -0
- reconcile/gql_definitions/maintenance/maintenances.py +101 -0
- reconcile/gql_definitions/membershipsources/__init__.py +0 -0
- reconcile/gql_definitions/membershipsources/roles.py +112 -0
- reconcile/gql_definitions/ocm_labels/__init__.py +0 -0
- reconcile/gql_definitions/ocm_labels/clusters.py +112 -0
- reconcile/gql_definitions/ocm_labels/organizations.py +78 -0
- reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
- reconcile/gql_definitions/openshift_cluster_bots/__init__.py +0 -0
- reconcile/gql_definitions/openshift_cluster_bots/clusters.py +126 -0
- reconcile/gql_definitions/openshift_groups/managed_groups.py +2 -2
- reconcile/gql_definitions/openshift_groups/managed_roles.py +3 -2
- reconcile/gql_definitions/openshift_serviceaccount_tokens/__init__.py +0 -0
- reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +132 -0
- reconcile/gql_definitions/quay_membership/quay_membership.py +3 -5
- reconcile/gql_definitions/rhidp/__init__.py +0 -0
- reconcile/gql_definitions/rhidp/organizations.py +96 -0
- reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +2 -2
- reconcile/gql_definitions/service_dependencies/service_dependencies.py +9 -31
- reconcile/gql_definitions/sharding/aws_accounts.py +2 -2
- reconcile/gql_definitions/sharding/ocm_organization.py +63 -0
- reconcile/gql_definitions/skupper_network/site_controller_template.py +2 -2
- reconcile/gql_definitions/skupper_network/skupper_networks.py +12 -38
- reconcile/gql_definitions/slack_usergroups/clusters.py +2 -2
- reconcile/gql_definitions/slack_usergroups/permissions.py +8 -15
- reconcile/gql_definitions/slack_usergroups/users.py +3 -2
- reconcile/gql_definitions/slo_documents/__init__.py +0 -0
- reconcile/gql_definitions/slo_documents/slo_documents.py +142 -0
- reconcile/gql_definitions/status_board/__init__.py +0 -0
- reconcile/gql_definitions/status_board/status_board.py +163 -0
- reconcile/gql_definitions/statuspage/statuspages.py +56 -7
- reconcile/gql_definitions/templating/__init__.py +0 -0
- reconcile/gql_definitions/templating/template_collection.py +130 -0
- reconcile/gql_definitions/templating/templates.py +108 -0
- reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +4 -8
- reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +8 -8
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +6 -8
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +45 -56
- reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +4 -8
- reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +4 -8
- reconcile/gql_definitions/terraform_init/__init__.py +0 -0
- reconcile/gql_definitions/terraform_init/aws_accounts.py +93 -0
- reconcile/gql_definitions/terraform_repo/__init__.py +0 -0
- reconcile/gql_definitions/terraform_repo/terraform_repo.py +141 -0
- reconcile/gql_definitions/terraform_resources/database_access_manager.py +158 -0
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +153 -162
- reconcile/gql_definitions/terraform_tgw_attachments/__init__.py +0 -0
- reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +119 -0
- reconcile/gql_definitions/unleash_feature_toggles/__init__.py +0 -0
- reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +113 -0
- reconcile/gql_definitions/vault_instances/vault_instances.py +17 -50
- reconcile/gql_definitions/vault_policies/vault_policies.py +2 -2
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +49 -12
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +7 -2
- reconcile/integrations_manager.py +25 -13
- reconcile/jenkins/types.py +5 -1
- reconcile/jenkins_base.py +36 -0
- reconcile/jenkins_job_builder.py +10 -48
- reconcile/jenkins_job_builds_cleaner.py +40 -25
- reconcile/jenkins_job_cleaner.py +1 -3
- reconcile/jenkins_roles.py +22 -26
- reconcile/jenkins_webhooks.py +9 -6
- reconcile/jenkins_worker_fleets.py +11 -6
- reconcile/jira_permissions_validator.py +340 -0
- reconcile/jira_watcher.py +3 -5
- reconcile/ldap_groups/__init__.py +0 -0
- reconcile/ldap_groups/integration.py +279 -0
- reconcile/ldap_users.py +3 -0
- reconcile/ocm/types.py +39 -59
- reconcile/ocm_additional_routers.py +0 -1
- reconcile/ocm_addons_upgrade_tests_trigger.py +10 -15
- reconcile/ocm_aws_infrastructure_access.py +30 -32
- reconcile/ocm_clusters.py +217 -130
- reconcile/ocm_external_configuration_labels.py +15 -0
- reconcile/ocm_github_idp.py +1 -1
- reconcile/ocm_groups.py +25 -5
- reconcile/ocm_internal_notifications/__init__.py +0 -0
- reconcile/ocm_internal_notifications/integration.py +119 -0
- reconcile/ocm_labels/__init__.py +0 -0
- reconcile/ocm_labels/integration.py +409 -0
- reconcile/ocm_machine_pools.py +517 -108
- reconcile/ocm_upgrade_scheduler_org_updater.py +15 -11
- reconcile/openshift_base.py +609 -207
- reconcile/openshift_cluster_bots.py +344 -0
- reconcile/openshift_clusterrolebindings.py +15 -15
- reconcile/openshift_groups.py +42 -45
- reconcile/openshift_limitranges.py +1 -0
- reconcile/openshift_namespace_labels.py +22 -28
- reconcile/openshift_namespaces.py +22 -22
- reconcile/openshift_network_policies.py +4 -8
- reconcile/openshift_prometheus_rules.py +43 -0
- reconcile/openshift_resourcequotas.py +2 -16
- reconcile/openshift_resources.py +12 -10
- reconcile/openshift_resources_base.py +304 -328
- reconcile/openshift_rolebindings.py +18 -20
- reconcile/openshift_saas_deploy.py +105 -21
- reconcile/openshift_saas_deploy_change_tester.py +30 -35
- reconcile/openshift_saas_deploy_trigger_base.py +39 -36
- reconcile/openshift_saas_deploy_trigger_cleaner.py +41 -27
- reconcile/openshift_saas_deploy_trigger_configs.py +1 -2
- reconcile/openshift_saas_deploy_trigger_images.py +1 -2
- reconcile/openshift_saas_deploy_trigger_moving_commits.py +1 -2
- reconcile/openshift_saas_deploy_trigger_upstream_jobs.py +1 -2
- reconcile/openshift_serviceaccount_tokens.py +138 -74
- reconcile/openshift_tekton_resources.py +89 -24
- reconcile/openshift_upgrade_watcher.py +110 -62
- reconcile/openshift_users.py +16 -15
- reconcile/openshift_vault_secrets.py +11 -6
- reconcile/oum/__init__.py +0 -0
- reconcile/oum/base.py +387 -0
- reconcile/oum/labelset.py +55 -0
- reconcile/oum/metrics.py +71 -0
- reconcile/oum/models.py +69 -0
- reconcile/oum/providers.py +59 -0
- reconcile/oum/standalone.py +196 -0
- reconcile/prometheus_rules_tester/integration.py +31 -23
- reconcile/quay_base.py +4 -1
- reconcile/quay_membership.py +1 -2
- reconcile/quay_mirror.py +111 -61
- reconcile/quay_mirror_org.py +34 -21
- reconcile/quay_permissions.py +7 -3
- reconcile/quay_repos.py +24 -32
- reconcile/queries.py +263 -198
- reconcile/query_validator.py +3 -5
- reconcile/resource_scraper.py +3 -4
- reconcile/{template_tester.py → resource_template_tester.py} +3 -3
- reconcile/rhidp/__init__.py +0 -0
- reconcile/rhidp/common.py +214 -0
- reconcile/rhidp/metrics.py +20 -0
- reconcile/rhidp/ocm_oidc_idp/__init__.py +0 -0
- reconcile/rhidp/ocm_oidc_idp/base.py +221 -0
- reconcile/rhidp/ocm_oidc_idp/integration.py +56 -0
- reconcile/rhidp/ocm_oidc_idp/metrics.py +22 -0
- reconcile/rhidp/sso_client/__init__.py +0 -0
- reconcile/rhidp/sso_client/base.py +266 -0
- reconcile/rhidp/sso_client/integration.py +60 -0
- reconcile/rhidp/sso_client/metrics.py +39 -0
- reconcile/run_integration.py +293 -0
- reconcile/saas_auto_promotions_manager/integration.py +69 -24
- reconcile/saas_auto_promotions_manager/merge_request_manager/batcher.py +208 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/desired_state.py +28 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py +3 -4
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager_v2.py +172 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/metrics.py +42 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/mr_parser.py +226 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/open_merge_requests.py +23 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +108 -32
- reconcile/saas_auto_promotions_manager/meta.py +4 -0
- reconcile/saas_auto_promotions_manager/publisher.py +32 -4
- reconcile/saas_auto_promotions_manager/s3_exporter.py +77 -0
- reconcile/saas_auto_promotions_manager/subscriber.py +110 -23
- reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py +48 -41
- reconcile/saas_file_validator.py +16 -6
- reconcile/sendgrid_teammates.py +27 -12
- reconcile/service_dependencies.py +0 -3
- reconcile/signalfx_endpoint_monitoring.py +2 -5
- reconcile/skupper_network/integration.py +10 -11
- reconcile/skupper_network/models.py +3 -5
- reconcile/skupper_network/reconciler.py +28 -35
- reconcile/skupper_network/site_controller.py +8 -8
- reconcile/slack_base.py +4 -7
- reconcile/slack_usergroups.py +249 -171
- reconcile/sql_query.py +324 -171
- reconcile/status.py +0 -1
- reconcile/status_board.py +275 -0
- reconcile/statuspage/__init__.py +0 -5
- reconcile/statuspage/atlassian.py +219 -80
- reconcile/statuspage/integration.py +9 -97
- reconcile/statuspage/integrations/__init__.py +0 -0
- reconcile/statuspage/integrations/components.py +77 -0
- reconcile/statuspage/integrations/maintenances.py +111 -0
- reconcile/statuspage/page.py +107 -72
- reconcile/statuspage/state.py +6 -11
- reconcile/statuspage/status.py +8 -12
- reconcile/templates/rosa-classic-cluster-creation.sh.j2 +60 -0
- reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +61 -0
- reconcile/templating/__init__.py +0 -0
- reconcile/templating/lib/__init__.py +0 -0
- reconcile/templating/lib/merge_request_manager.py +180 -0
- reconcile/templating/lib/model.py +20 -0
- reconcile/templating/lib/rendering.py +191 -0
- reconcile/templating/renderer.py +410 -0
- reconcile/templating/validator.py +153 -0
- reconcile/terraform_aws_route53.py +13 -10
- reconcile/terraform_cloudflare_dns.py +92 -122
- reconcile/terraform_cloudflare_resources.py +15 -13
- reconcile/terraform_cloudflare_users.py +27 -27
- reconcile/terraform_init/__init__.py +0 -0
- reconcile/terraform_init/integration.py +165 -0
- reconcile/terraform_init/merge_request.py +57 -0
- reconcile/terraform_init/merge_request_manager.py +102 -0
- reconcile/terraform_repo.py +403 -0
- reconcile/terraform_resources.py +266 -168
- reconcile/terraform_tgw_attachments.py +417 -167
- reconcile/terraform_users.py +40 -17
- reconcile/terraform_vpc_peerings.py +310 -142
- reconcile/terraform_vpc_resources/__init__.py +0 -0
- reconcile/terraform_vpc_resources/integration.py +220 -0
- reconcile/terraform_vpc_resources/merge_request.py +57 -0
- reconcile/terraform_vpc_resources/merge_request_manager.py +107 -0
- reconcile/typed_queries/alerting_services_settings.py +1 -2
- reconcile/typed_queries/app_interface_custom_messages.py +24 -0
- reconcile/typed_queries/app_interface_deadmanssnitch_settings.py +17 -0
- reconcile/typed_queries/app_interface_metrics_exporter/__init__.py +0 -0
- reconcile/typed_queries/app_interface_metrics_exporter/onboarding_status.py +13 -0
- reconcile/typed_queries/app_interface_repo_url.py +1 -2
- reconcile/typed_queries/app_interface_state_settings.py +1 -3
- reconcile/typed_queries/app_interface_vault_settings.py +1 -2
- reconcile/typed_queries/app_quay_repos_escalation_policies.py +14 -0
- reconcile/typed_queries/apps.py +11 -0
- reconcile/typed_queries/aws_vpc_requests.py +9 -0
- reconcile/typed_queries/aws_vpcs.py +12 -0
- reconcile/typed_queries/cloudflare.py +10 -0
- reconcile/typed_queries/clusters.py +7 -5
- reconcile/typed_queries/clusters_minimal.py +6 -5
- reconcile/typed_queries/clusters_with_dms.py +16 -0
- reconcile/typed_queries/cost_report/__init__.py +0 -0
- reconcile/typed_queries/cost_report/app_names.py +22 -0
- reconcile/typed_queries/cost_report/cost_namespaces.py +43 -0
- reconcile/typed_queries/cost_report/settings.py +15 -0
- reconcile/typed_queries/dynatrace.py +10 -0
- reconcile/typed_queries/dynatrace_environments.py +14 -0
- reconcile/typed_queries/dynatrace_token_provider_token_specs.py +14 -0
- reconcile/typed_queries/external_resources.py +46 -0
- reconcile/typed_queries/get_state_aws_account.py +20 -0
- reconcile/typed_queries/glitchtip.py +10 -0
- reconcile/typed_queries/jenkins.py +25 -0
- reconcile/typed_queries/jira.py +7 -0
- reconcile/typed_queries/jira_settings.py +16 -0
- reconcile/typed_queries/jiralert_settings.py +22 -0
- reconcile/typed_queries/ocm.py +8 -0
- reconcile/typed_queries/pagerduty_instances.py +2 -7
- reconcile/typed_queries/quay.py +23 -0
- reconcile/typed_queries/repos.py +20 -8
- reconcile/typed_queries/reserved_networks.py +12 -0
- reconcile/typed_queries/saas_files.py +221 -167
- reconcile/typed_queries/slack.py +7 -0
- reconcile/typed_queries/slo_documents.py +12 -0
- reconcile/typed_queries/status_board.py +58 -0
- reconcile/typed_queries/tekton_pipeline_providers.py +1 -2
- reconcile/typed_queries/terraform_namespaces.py +1 -2
- reconcile/typed_queries/terraform_tgw_attachments/__init__.py +0 -0
- reconcile/typed_queries/terraform_tgw_attachments/aws_accounts.py +16 -0
- reconcile/typed_queries/unleash.py +10 -0
- reconcile/typed_queries/users.py +11 -0
- reconcile/typed_queries/vault.py +10 -0
- reconcile/unleash_feature_toggles/__init__.py +0 -0
- reconcile/unleash_feature_toggles/integration.py +287 -0
- reconcile/utils/acs/__init__.py +0 -0
- reconcile/utils/acs/base.py +81 -0
- reconcile/utils/acs/notifiers.py +143 -0
- reconcile/utils/acs/policies.py +163 -0
- reconcile/utils/acs/rbac.py +277 -0
- reconcile/utils/aggregated_list.py +11 -9
- reconcile/utils/amtool.py +6 -4
- reconcile/utils/aws_api.py +279 -66
- reconcile/utils/aws_api_typed/__init__.py +0 -0
- reconcile/utils/aws_api_typed/account.py +23 -0
- reconcile/utils/aws_api_typed/api.py +273 -0
- reconcile/utils/aws_api_typed/dynamodb.py +16 -0
- reconcile/utils/aws_api_typed/iam.py +67 -0
- reconcile/utils/aws_api_typed/organization.py +152 -0
- reconcile/utils/aws_api_typed/s3.py +26 -0
- reconcile/utils/aws_api_typed/service_quotas.py +79 -0
- reconcile/utils/aws_api_typed/sts.py +36 -0
- reconcile/utils/aws_api_typed/support.py +79 -0
- reconcile/utils/aws_helper.py +42 -3
- reconcile/utils/batches.py +11 -0
- reconcile/utils/binary.py +7 -9
- reconcile/utils/cloud_resource_best_practice/__init__.py +0 -0
- reconcile/utils/cloud_resource_best_practice/aws_rds.py +66 -0
- reconcile/utils/clusterhealth/__init__.py +0 -0
- reconcile/utils/clusterhealth/providerbase.py +39 -0
- reconcile/utils/clusterhealth/telemeter.py +39 -0
- reconcile/utils/config.py +3 -4
- reconcile/utils/deadmanssnitch_api.py +86 -0
- reconcile/utils/differ.py +205 -0
- reconcile/utils/disabled_integrations.py +4 -6
- reconcile/utils/dynatrace/__init__.py +0 -0
- reconcile/utils/dynatrace/client.py +93 -0
- reconcile/utils/early_exit_cache.py +289 -0
- reconcile/utils/elasticsearch_exceptions.py +5 -0
- reconcile/utils/environ.py +2 -2
- reconcile/utils/exceptions.py +4 -0
- reconcile/utils/expiration.py +4 -8
- reconcile/utils/extended_early_exit.py +210 -0
- reconcile/utils/external_resource_spec.py +34 -12
- reconcile/utils/external_resources.py +48 -20
- reconcile/utils/filtering.py +16 -0
- reconcile/utils/git.py +49 -16
- reconcile/utils/github_api.py +10 -9
- reconcile/utils/gitlab_api.py +333 -190
- reconcile/utils/glitchtip/client.py +97 -100
- reconcile/utils/glitchtip/models.py +89 -11
- reconcile/utils/gql.py +157 -58
- reconcile/utils/grouping.py +17 -0
- reconcile/utils/helm.py +89 -18
- reconcile/utils/helpers.py +51 -0
- reconcile/utils/imap_client.py +5 -6
- reconcile/utils/internal_groups/__init__.py +0 -0
- reconcile/utils/internal_groups/client.py +160 -0
- reconcile/utils/internal_groups/models.py +71 -0
- reconcile/utils/jenkins_api.py +10 -34
- reconcile/utils/jinja2/__init__.py +0 -0
- reconcile/utils/{jinja2_ext.py → jinja2/extensions.py} +6 -4
- reconcile/utils/jinja2/filters.py +142 -0
- reconcile/utils/jinja2/utils.py +278 -0
- reconcile/utils/jira_client.py +165 -8
- reconcile/utils/jjb_client.py +47 -35
- reconcile/utils/jobcontroller/__init__.py +0 -0
- reconcile/utils/jobcontroller/controller.py +413 -0
- reconcile/utils/jobcontroller/models.py +195 -0
- reconcile/utils/jsonpath.py +4 -5
- reconcile/utils/jump_host.py +13 -12
- reconcile/utils/keycloak.py +106 -0
- reconcile/utils/ldap_client.py +35 -6
- reconcile/utils/lean_terraform_client.py +115 -6
- reconcile/utils/membershipsources/__init__.py +0 -0
- reconcile/utils/membershipsources/app_interface_resolver.py +60 -0
- reconcile/utils/membershipsources/models.py +91 -0
- reconcile/utils/membershipsources/resolver.py +110 -0
- reconcile/utils/merge_request_manager/__init__.py +0 -0
- reconcile/utils/merge_request_manager/merge_request_manager.py +99 -0
- reconcile/utils/merge_request_manager/parser.py +67 -0
- reconcile/utils/metrics.py +511 -1
- reconcile/utils/models.py +123 -0
- reconcile/utils/mr/README.md +198 -0
- reconcile/utils/mr/__init__.py +14 -10
- reconcile/utils/mr/app_interface_reporter.py +2 -2
- reconcile/utils/mr/aws_access.py +4 -4
- reconcile/utils/mr/base.py +51 -31
- reconcile/utils/mr/clusters_updates.py +10 -7
- reconcile/utils/mr/glitchtip_access_reporter.py +2 -4
- reconcile/utils/mr/labels.py +14 -1
- reconcile/utils/mr/notificator.py +1 -3
- reconcile/utils/mr/ocm_update_recommended_version.py +1 -2
- reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +7 -3
- reconcile/utils/mr/promote_qontract.py +203 -0
- reconcile/utils/mr/user_maintenance.py +24 -4
- reconcile/utils/oauth2_backend_application_session.py +132 -0
- reconcile/utils/oc.py +194 -170
- reconcile/utils/oc_connection_parameters.py +40 -51
- reconcile/utils/oc_filters.py +11 -13
- reconcile/utils/oc_map.py +14 -35
- reconcile/utils/ocm/__init__.py +30 -1
- reconcile/utils/ocm/addons.py +228 -0
- reconcile/utils/ocm/base.py +618 -5
- reconcile/utils/ocm/cluster_groups.py +5 -56
- reconcile/utils/ocm/clusters.py +111 -99
- reconcile/utils/ocm/identity_providers.py +66 -0
- reconcile/utils/ocm/label_sources.py +75 -0
- reconcile/utils/ocm/labels.py +139 -54
- reconcile/utils/ocm/manifests.py +39 -0
- reconcile/utils/ocm/ocm.py +182 -928
- reconcile/utils/ocm/products.py +758 -0
- reconcile/utils/ocm/search_filters.py +20 -28
- reconcile/utils/ocm/service_log.py +32 -79
- reconcile/utils/ocm/sre_capability_labels.py +51 -0
- reconcile/utils/ocm/status_board.py +66 -0
- reconcile/utils/ocm/subscriptions.py +49 -59
- reconcile/utils/ocm/syncsets.py +39 -0
- reconcile/utils/ocm/upgrades.py +181 -0
- reconcile/utils/ocm_base_client.py +71 -36
- reconcile/utils/openshift_resource.py +113 -67
- reconcile/utils/output.py +18 -11
- reconcile/utils/pagerduty_api.py +16 -10
- reconcile/utils/parse_dhms_duration.py +13 -1
- reconcile/utils/prometheus.py +123 -0
- reconcile/utils/promotion_state.py +56 -19
- reconcile/utils/promtool.py +5 -8
- reconcile/utils/quay_api.py +13 -25
- reconcile/utils/raw_github_api.py +3 -5
- reconcile/utils/repo_owners.py +2 -8
- reconcile/utils/rest_api_base.py +126 -0
- reconcile/utils/rosa/__init__.py +0 -0
- reconcile/utils/rosa/rosa_cli.py +310 -0
- reconcile/utils/rosa/session.py +201 -0
- reconcile/utils/ruamel.py +16 -0
- reconcile/utils/runtime/__init__.py +0 -1
- reconcile/utils/runtime/desired_state_diff.py +9 -20
- reconcile/utils/runtime/environment.py +33 -8
- reconcile/utils/runtime/integration.py +28 -12
- reconcile/utils/runtime/meta.py +1 -3
- reconcile/utils/runtime/runner.py +8 -11
- reconcile/utils/runtime/sharding.py +93 -36
- reconcile/utils/saasherder/__init__.py +1 -1
- reconcile/utils/saasherder/interfaces.py +143 -138
- reconcile/utils/saasherder/models.py +201 -43
- reconcile/utils/saasherder/saasherder.py +508 -378
- reconcile/utils/secret_reader.py +22 -27
- reconcile/utils/semver_helper.py +15 -1
- reconcile/utils/slack_api.py +124 -36
- reconcile/utils/smtp_client.py +1 -2
- reconcile/utils/sqs_gateway.py +10 -6
- reconcile/utils/state.py +276 -127
- reconcile/utils/terraform/config_client.py +6 -7
- reconcile/utils/terraform_client.py +284 -125
- reconcile/utils/terrascript/cloudflare_client.py +38 -17
- reconcile/utils/terrascript/cloudflare_resources.py +67 -18
- reconcile/utils/terrascript/models.py +2 -3
- reconcile/utils/terrascript/resources.py +1 -2
- reconcile/utils/terrascript_aws_client.py +1292 -540
- reconcile/utils/three_way_diff_strategy.py +157 -0
- reconcile/utils/unleash/__init__.py +11 -0
- reconcile/utils/{unleash.py → unleash/client.py} +35 -29
- reconcile/utils/unleash/server.py +145 -0
- reconcile/utils/vault.py +42 -32
- reconcile/utils/vaultsecretref.py +2 -4
- reconcile/utils/vcs.py +250 -0
- reconcile/vault_replication.py +38 -31
- reconcile/vpc_peerings_validator.py +82 -13
- tools/app_interface_metrics_exporter.py +70 -0
- tools/app_interface_reporter.py +44 -157
- tools/cli_commands/container_images_report.py +154 -0
- tools/cli_commands/cost_report/__init__.py +0 -0
- tools/cli_commands/cost_report/aws.py +137 -0
- tools/cli_commands/cost_report/cost_management_api.py +155 -0
- tools/cli_commands/cost_report/model.py +49 -0
- tools/cli_commands/cost_report/openshift.py +166 -0
- tools/cli_commands/cost_report/openshift_cost_optimization.py +187 -0
- tools/cli_commands/cost_report/response.py +124 -0
- tools/cli_commands/cost_report/util.py +72 -0
- tools/cli_commands/cost_report/view.py +524 -0
- tools/cli_commands/erv2.py +620 -0
- tools/cli_commands/gpg_encrypt.py +5 -8
- tools/cli_commands/systems_and_tools.py +489 -0
- tools/glitchtip_access_revalidation.py +1 -1
- tools/qontract_cli.py +2301 -673
- tools/saas_metrics_exporter/__init__.py +0 -0
- tools/saas_metrics_exporter/commit_distance/__init__.py +0 -0
- tools/saas_metrics_exporter/commit_distance/channel.py +63 -0
- tools/saas_metrics_exporter/commit_distance/commit_distance.py +103 -0
- tools/saas_metrics_exporter/commit_distance/metrics.py +19 -0
- tools/saas_metrics_exporter/main.py +99 -0
- tools/saas_promotion_state/__init__.py +0 -0
- tools/saas_promotion_state/saas_promotion_state.py +105 -0
- tools/sd_app_sre_alert_report.py +145 -0
- tools/template_validation.py +107 -0
- e2e_tests/cli.py +0 -83
- e2e_tests/create_namespace.py +0 -43
- e2e_tests/dedicated_admin_rolebindings.py +0 -44
- e2e_tests/dedicated_admin_test_base.py +0 -39
- e2e_tests/default_network_policies.py +0 -47
- e2e_tests/default_project_labels.py +0 -52
- e2e_tests/network_policy_test_base.py +0 -17
- e2e_tests/test_base.py +0 -56
- qontract_reconcile-0.9.1rc298.dist-info/METADATA +0 -63
- qontract_reconcile-0.9.1rc298.dist-info/RECORD +0 -585
- qontract_reconcile-0.9.1rc298.dist-info/top_level.txt +0 -4
- reconcile/ecr_mirror.py +0 -152
- reconcile/github_scanner.py +0 -74
- reconcile/gitlab_integrations.py +0 -63
- reconcile/gql_definitions/ocm_oidc_idp/clusters.py +0 -195
- reconcile/gql_definitions/ocp_release_mirror/ocp_release_mirror.py +0 -287
- reconcile/integrations_validator.py +0 -18
- reconcile/jenkins_plugins.py +0 -129
- reconcile/kafka_clusters.py +0 -208
- reconcile/ocm_cluster_admin.py +0 -42
- reconcile/ocm_oidc_idp.py +0 -198
- reconcile/ocp_release_mirror.py +0 -373
- reconcile/prometheus_rules_tester_old.py +0 -436
- reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py +0 -279
- reconcile/saas_auto_promotions_manager/utils/vcs.py +0 -141
- reconcile/sentry_config.py +0 -613
- reconcile/sentry_helper.py +0 -69
- reconcile/test/conftest.py +0 -187
- reconcile/test/fixtures.py +0 -24
- reconcile/test/saas_auto_promotions_manager/conftest.py +0 -69
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/conftest.py +0 -110
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/data_keys.py +0 -10
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_housekeeping.py +0 -200
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager/test_merge_request_manager.py +0 -151
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/conftest.py +0 -63
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/data_keys.py +0 -4
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_multiple_namespaces.py +0 -46
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_namespace.py +0 -94
- reconcile/test/saas_auto_promotions_manager/merge_request_manager/renderer/test_content_single_target.py +0 -44
- reconcile/test/saas_auto_promotions_manager/subscriber/conftest.py +0 -74
- reconcile/test/saas_auto_promotions_manager/subscriber/data_keys.py +0 -11
- reconcile/test/saas_auto_promotions_manager/subscriber/test_content_hash.py +0 -155
- reconcile/test/saas_auto_promotions_manager/subscriber/test_diff.py +0 -173
- reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_config_hash.py +0 -226
- reconcile/test/saas_auto_promotions_manager/subscriber/test_multiple_channels_moving_ref.py +0 -224
- reconcile/test/saas_auto_promotions_manager/subscriber/test_single_channel_with_single_publisher.py +0 -350
- reconcile/test/saas_auto_promotions_manager/test_integration_test.py +0 -129
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_multiple_publishers_for_single_channel.py +0 -70
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_use_target_config_hash.py +0 -63
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_with_auto_promote.py +0 -74
- reconcile/test/saas_auto_promotions_manager/utils/saas_files_inventory/test_saas_files_without_auto_promote.py +0 -65
- reconcile/test/test_aggregated_list.py +0 -237
- reconcile/test/test_amtool.py +0 -37
- reconcile/test/test_auto_promoter.py +0 -295
- reconcile/test/test_aws_ami_share.py +0 -68
- reconcile/test/test_aws_iam_keys.py +0 -70
- reconcile/test/test_aws_iam_password_reset.py +0 -35
- reconcile/test/test_aws_support_cases_sos.py +0 -23
- reconcile/test/test_checkpoint.py +0 -178
- reconcile/test/test_cli.py +0 -41
- reconcile/test/test_closedbox_endpoint_monitoring.py +0 -207
- reconcile/test/test_gabi_authorized_users.py +0 -72
- reconcile/test/test_github_org.py +0 -154
- reconcile/test/test_github_repo_invites.py +0 -123
- reconcile/test/test_gitlab_housekeeping.py +0 -88
- reconcile/test/test_gitlab_labeler.py +0 -129
- reconcile/test/test_gitlab_members.py +0 -283
- reconcile/test/test_instrumented_wrappers.py +0 -18
- reconcile/test/test_integrations_manager.py +0 -995
- reconcile/test/test_jenkins_worker_fleets.py +0 -55
- reconcile/test/test_jump_host.py +0 -117
- reconcile/test/test_ldap_users.py +0 -123
- reconcile/test/test_make.py +0 -28
- reconcile/test/test_ocm_additional_routers.py +0 -134
- reconcile/test/test_ocm_addons_upgrade_scheduler_org.py +0 -149
- reconcile/test/test_ocm_clusters.py +0 -598
- reconcile/test/test_ocm_clusters_manifest_updates.py +0 -89
- reconcile/test/test_ocm_oidc_idp.py +0 -315
- reconcile/test/test_ocm_update_recommended_version.py +0 -145
- reconcile/test/test_ocm_upgrade_scheduler.py +0 -614
- reconcile/test/test_ocm_upgrade_scheduler_org_updater.py +0 -129
- reconcile/test/test_openshift_base.py +0 -730
- reconcile/test/test_openshift_namespace_labels.py +0 -345
- reconcile/test/test_openshift_namespaces.py +0 -256
- reconcile/test/test_openshift_resource.py +0 -415
- reconcile/test/test_openshift_resources_base.py +0 -440
- reconcile/test/test_openshift_saas_deploy_change_tester.py +0 -310
- reconcile/test/test_openshift_tekton_resources.py +0 -253
- reconcile/test/test_openshift_upgrade_watcher.py +0 -146
- reconcile/test/test_prometheus_rules_tester.py +0 -151
- reconcile/test/test_prometheus_rules_tester_old.py +0 -77
- reconcile/test/test_quay_membership.py +0 -86
- reconcile/test/test_quay_mirror.py +0 -109
- reconcile/test/test_quay_mirror_org.py +0 -70
- reconcile/test/test_quay_repos.py +0 -59
- reconcile/test/test_queries.py +0 -53
- reconcile/test/test_repo_owners.py +0 -47
- reconcile/test/test_requests_sender.py +0 -139
- reconcile/test/test_saasherder.py +0 -1074
- reconcile/test/test_saasherder_allowed_secret_paths.py +0 -127
- reconcile/test/test_secret_reader.py +0 -153
- reconcile/test/test_slack_base.py +0 -185
- reconcile/test/test_slack_usergroups.py +0 -744
- reconcile/test/test_sql_query.py +0 -19
- reconcile/test/test_terraform_cloudflare_dns.py +0 -117
- reconcile/test/test_terraform_cloudflare_resources.py +0 -106
- reconcile/test/test_terraform_cloudflare_users.py +0 -749
- reconcile/test/test_terraform_resources.py +0 -257
- reconcile/test/test_terraform_tgw_attachments.py +0 -631
- reconcile/test/test_terraform_users.py +0 -57
- reconcile/test/test_terraform_vpc_peerings.py +0 -499
- reconcile/test/test_terraform_vpc_peerings_build_desired_state.py +0 -1061
- reconcile/test/test_unleash.py +0 -138
- reconcile/test/test_utils_aws_api.py +0 -240
- reconcile/test/test_utils_aws_helper.py +0 -80
- reconcile/test/test_utils_cluster_version_data.py +0 -177
- reconcile/test/test_utils_data_structures.py +0 -13
- reconcile/test/test_utils_disabled_integrations.py +0 -86
- reconcile/test/test_utils_expiration.py +0 -109
- reconcile/test/test_utils_external_resource_spec.py +0 -383
- reconcile/test/test_utils_external_resources.py +0 -247
- reconcile/test/test_utils_github_api.py +0 -73
- reconcile/test/test_utils_gitlab_api.py +0 -20
- reconcile/test/test_utils_gpg.py +0 -69
- reconcile/test/test_utils_gql.py +0 -81
- reconcile/test/test_utils_helm.py +0 -306
- reconcile/test/test_utils_helpers.py +0 -55
- reconcile/test/test_utils_imap_client.py +0 -65
- reconcile/test/test_utils_jjb_client.py +0 -52
- reconcile/test/test_utils_jsonpath.py +0 -286
- reconcile/test/test_utils_ldap_client.py +0 -51
- reconcile/test/test_utils_mr.py +0 -226
- reconcile/test/test_utils_mr_clusters_updates.py +0 -77
- reconcile/test/test_utils_oc.py +0 -984
- reconcile/test/test_utils_ocm.py +0 -110
- reconcile/test/test_utils_pagerduty_api.py +0 -251
- reconcile/test/test_utils_parse_dhms_duration.py +0 -34
- reconcile/test/test_utils_password_validator.py +0 -155
- reconcile/test/test_utils_quay_api.py +0 -86
- reconcile/test/test_utils_semver_helper.py +0 -19
- reconcile/test/test_utils_sharding.py +0 -56
- reconcile/test/test_utils_slack_api.py +0 -439
- reconcile/test/test_utils_smtp_client.py +0 -73
- reconcile/test/test_utils_state.py +0 -256
- reconcile/test/test_utils_terraform.py +0 -13
- reconcile/test/test_utils_terraform_client.py +0 -585
- reconcile/test/test_utils_terraform_config_client.py +0 -219
- reconcile/test/test_utils_terrascript_aws_client.py +0 -277
- reconcile/test/test_utils_terrascript_cloudflare_client.py +0 -597
- reconcile/test/test_utils_terrascript_cloudflare_resources.py +0 -26
- reconcile/test/test_vault_replication.py +0 -515
- reconcile/test/test_vault_utils.py +0 -47
- reconcile/test/test_version_bump.py +0 -18
- reconcile/test/test_vpc_peerings_validator.py +0 -103
- reconcile/test/test_wrong_region.py +0 -78
- reconcile/typed_queries/glitchtip_settings.py +0 -18
- reconcile/typed_queries/ocp_release_mirror.py +0 -11
- reconcile/unleash_watcher.py +0 -120
- reconcile/utils/git_secrets.py +0 -63
- reconcile/utils/mr/auto_promoter.py +0 -218
- reconcile/utils/sentry_client.py +0 -383
- release/test_version.py +0 -50
- release/version.py +0 -100
- tools/test/test_qontract_cli.py +0 -60
- tools/test/test_sre_checkpoints.py +0 -79
- /e2e_tests/__init__.py → /reconcile/aus/upgrades.py +0 -0
- /reconcile/{gql_definitions/ocp_release_mirror → aws_account_manager}/__init__.py +0 -0
- /reconcile/{test → aws_ami_cleanup}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager → aws_cloudwatch_log_retention}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/merge_request_manager → aws_saml_idp}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/merge_request_manager → aws_saml_roles}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/merge_request_manager/renderer → aws_version_sync}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/subscriber → aws_version_sync/merge_request_manager}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/utils → cluster_auth_rhidp}/__init__.py +0 -0
- /reconcile/{test/saas_auto_promotions_manager/utils/saas_files_inventory → dynatrace_token_provider}/__init__.py +0 -0
- {release → reconcile/endpoints_discovery}/__init__.py +0 -0
- {tools/test → reconcile/external_resources}/__init__.py +0 -0
@@ -1,6 +1,5 @@
|
|
1
1
|
import base64
|
2
2
|
import enum
|
3
|
-
import imghdr
|
4
3
|
import json
|
5
4
|
import logging
|
6
5
|
import os
|
@@ -8,12 +7,9 @@ import random
|
|
8
7
|
import re
|
9
8
|
import string
|
10
9
|
import tempfile
|
11
|
-
from collections
|
12
|
-
|
13
|
-
|
14
|
-
MutableMapping,
|
15
|
-
)
|
16
|
-
from dataclasses import dataclass
|
10
|
+
from collections import Counter
|
11
|
+
from collections.abc import Iterable, Mapping, MutableMapping
|
12
|
+
from dataclasses import dataclass, field
|
17
13
|
from ipaddress import (
|
18
14
|
ip_address,
|
19
15
|
ip_network,
|
@@ -22,11 +18,11 @@ from json import JSONDecodeError
|
|
22
18
|
from threading import Lock
|
23
19
|
from typing import (
|
24
20
|
Any,
|
25
|
-
Optional,
|
26
21
|
cast,
|
27
22
|
)
|
28
23
|
|
29
24
|
import anymarkup
|
25
|
+
import filetype
|
30
26
|
import requests
|
31
27
|
from botocore.errorfactory import ClientError
|
32
28
|
from github import Github
|
@@ -35,7 +31,9 @@ from sretoolbox.utils import threaded
|
|
35
31
|
# temporary to create aws_ecrpublic_repository
|
36
32
|
from terrascript import (
|
37
33
|
Backend,
|
34
|
+
Block,
|
38
35
|
Data,
|
36
|
+
Module,
|
39
37
|
Output,
|
40
38
|
Provider,
|
41
39
|
Resource,
|
@@ -90,11 +88,11 @@ from terrascript.resource import (
|
|
90
88
|
aws_iam_role,
|
91
89
|
aws_iam_role_policy,
|
92
90
|
aws_iam_role_policy_attachment,
|
91
|
+
aws_iam_saml_provider,
|
93
92
|
aws_iam_service_linked_role,
|
94
93
|
aws_iam_user,
|
95
94
|
aws_iam_user_group_membership,
|
96
95
|
aws_iam_user_login_profile,
|
97
|
-
aws_iam_user_policy,
|
98
96
|
aws_iam_user_policy_attachment,
|
99
97
|
aws_kinesis_stream,
|
100
98
|
aws_kms_alias,
|
@@ -108,6 +106,8 @@ from terrascript.resource import (
|
|
108
106
|
aws_lb_listener_rule,
|
109
107
|
aws_lb_target_group,
|
110
108
|
aws_lb_target_group_attachment,
|
109
|
+
aws_msk_cluster,
|
110
|
+
aws_msk_configuration,
|
111
111
|
aws_ram_principal_association,
|
112
112
|
aws_ram_resource_association,
|
113
113
|
aws_ram_resource_share,
|
@@ -138,17 +138,27 @@ from terrascript.resource import (
|
|
138
138
|
random_id,
|
139
139
|
)
|
140
140
|
|
141
|
-
import reconcile.openshift_resources_base as orb
|
142
141
|
import reconcile.utils.aws_helper as awsh
|
143
142
|
from reconcile import queries
|
143
|
+
from reconcile.cli import TERRAFORM_VERSION
|
144
144
|
from reconcile.github_org import get_default_config
|
145
|
+
from reconcile.gql_definitions.fragments.aws_vpc_request import (
|
146
|
+
VPCRequest,
|
147
|
+
)
|
148
|
+
from reconcile.gql_definitions.terraform_resources.terraform_resources_namespaces import (
|
149
|
+
NamespaceTerraformResourceLifecycleV1,
|
150
|
+
)
|
145
151
|
from reconcile.utils import gql
|
146
152
|
from reconcile.utils.aws_api import (
|
147
153
|
AmiTag,
|
148
154
|
AWSApi,
|
149
155
|
)
|
156
|
+
from reconcile.utils.cloud_resource_best_practice.aws_rds import (
|
157
|
+
verify_rds_best_practices,
|
158
|
+
)
|
150
159
|
from reconcile.utils.disabled_integrations import integration_is_enabled
|
151
160
|
from reconcile.utils.elasticsearch_exceptions import (
|
161
|
+
ElasticSearchResourceColdStorageError,
|
152
162
|
ElasticSearchResourceMissingSubnetIdError,
|
153
163
|
ElasticSearchResourceNameInvalidError,
|
154
164
|
ElasticSearchResourceZoneAwareSubnetInvalidError,
|
@@ -168,12 +178,13 @@ from reconcile.utils.external_resources import (
|
|
168
178
|
from reconcile.utils.git import is_file_in_git_repo
|
169
179
|
from reconcile.utils.gitlab_api import GitLabApi
|
170
180
|
from reconcile.utils.jenkins_api import JenkinsApi
|
181
|
+
from reconcile.utils.jinja2.utils import process_extracurlyjinja2_template
|
171
182
|
from reconcile.utils.ocm import OCMMap
|
172
183
|
from reconcile.utils.password_validator import (
|
173
184
|
PasswordPolicy,
|
174
185
|
PasswordValidator,
|
175
186
|
)
|
176
|
-
from reconcile.utils.secret_reader import SecretReader
|
187
|
+
from reconcile.utils.secret_reader import SecretReader, SecretReaderBase
|
177
188
|
from reconcile.utils.terraform import safe_resource_id
|
178
189
|
|
179
190
|
GH_BASE_URL = os.environ.get("GITHUB_API", "https://api.github.com")
|
@@ -217,7 +228,9 @@ VARIABLE_KEYS = [
|
|
217
228
|
"image",
|
218
229
|
"assume_role",
|
219
230
|
"inline_policy",
|
231
|
+
"role_policy",
|
220
232
|
"assume_condition",
|
233
|
+
"assume_action",
|
221
234
|
"api_proxy_uri",
|
222
235
|
"cognito_callback_bucket_name",
|
223
236
|
"openshift_ingress_load_balancer_arn",
|
@@ -232,6 +245,7 @@ VARIABLE_KEYS = [
|
|
232
245
|
"subscriptions",
|
233
246
|
"records",
|
234
247
|
"extra_tags",
|
248
|
+
"lifecycle",
|
235
249
|
]
|
236
250
|
|
237
251
|
EMAIL_REGEX = re.compile(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
|
@@ -250,6 +264,28 @@ SUPPORTED_ALB_LISTENER_RULE_CONDITION_TYPE_MAPPING = {
|
|
250
264
|
"source-ip": "source_ip",
|
251
265
|
}
|
252
266
|
|
267
|
+
DEFAULT_TAGS = {
|
268
|
+
"tags": {
|
269
|
+
"app": "app-sre-infra",
|
270
|
+
},
|
271
|
+
}
|
272
|
+
|
273
|
+
|
274
|
+
class OutputResourceNameNotUniqueException(Exception):
|
275
|
+
def __init__(self, namespace, duplicates):
|
276
|
+
self.namespace, self.duplicates = namespace, duplicates
|
277
|
+
super().__init__(
|
278
|
+
str.format(
|
279
|
+
"Found duplicate values {} for 'output_resource_name' in namespace {}. Please ensure 'output_resource_name' is unique in a given namespace.",
|
280
|
+
self.duplicates,
|
281
|
+
self.namespace,
|
282
|
+
)
|
283
|
+
)
|
284
|
+
|
285
|
+
|
286
|
+
class RDSParameterGroupValidationError(Exception):
|
287
|
+
pass
|
288
|
+
|
253
289
|
|
254
290
|
class StateInaccessibleException(Exception):
|
255
291
|
pass
|
@@ -264,6 +300,13 @@ class UnapprovedSecretPathError(Exception):
|
|
264
300
|
pass
|
265
301
|
|
266
302
|
|
303
|
+
class Moved(Block):
|
304
|
+
"""Terraform `moved` block, available since Terraform 1.1"""
|
305
|
+
|
306
|
+
def __init__(self, fro: str, to: str):
|
307
|
+
super().__init__(fro=fro, to=to)
|
308
|
+
|
309
|
+
|
267
310
|
class aws_ecrpublic_repository(Resource):
|
268
311
|
pass
|
269
312
|
|
@@ -272,10 +315,18 @@ class aws_s3_bucket_acl(Resource):
|
|
272
315
|
pass
|
273
316
|
|
274
317
|
|
318
|
+
class aws_s3_bucket_logging(Resource):
|
319
|
+
pass
|
320
|
+
|
321
|
+
|
275
322
|
class aws_cloudfront_log_delivery_canonical_user_id(Data):
|
276
323
|
pass
|
277
324
|
|
278
325
|
|
326
|
+
class cloudinit_config(Data):
|
327
|
+
pass
|
328
|
+
|
329
|
+
|
279
330
|
# temporary until we upgrade to a terrascript release
|
280
331
|
# that supports this provider
|
281
332
|
# https://github.com/mjuenema/python-terrascript/pull/166
|
@@ -302,6 +353,18 @@ class aws_api_gateway_rest_api_policy(Resource):
|
|
302
353
|
pass
|
303
354
|
|
304
355
|
|
356
|
+
# temporary until we upgrade to a terrascript release
|
357
|
+
# that supports this resource
|
358
|
+
class aws_msk_scram_secret_association(Resource):
|
359
|
+
pass
|
360
|
+
|
361
|
+
|
362
|
+
# temporary until we upgrade to a terrascript release
|
363
|
+
# that supports this resource
|
364
|
+
class aws_secretsmanager_secret_policy(Resource):
|
365
|
+
pass
|
366
|
+
|
367
|
+
|
305
368
|
class ElasticSearchLogGroupType(enum.Enum):
|
306
369
|
INDEX_SLOW_LOGS = "INDEX_SLOW_LOGS"
|
307
370
|
SEARCH_SLOW_LOGS = "SEARCH_SLOW_LOGS"
|
@@ -316,6 +379,22 @@ class ElasticSearchLogGroupInfo:
|
|
316
379
|
log_group_identifier: str
|
317
380
|
|
318
381
|
|
382
|
+
@dataclass
|
383
|
+
class Exclusion:
|
384
|
+
all: bool = False
|
385
|
+
provisioners: set[str] = field(default_factory=set)
|
386
|
+
|
387
|
+
|
388
|
+
class ProviderExcludedError(Exception):
|
389
|
+
def __init__(self, spec: ExternalResourceSpec) -> None:
|
390
|
+
super().__init__(
|
391
|
+
self,
|
392
|
+
"The provider is not managed by terraform_resources in this provisioner. "
|
393
|
+
"Set the `managed_by_erv2: true` attribute in the external resource spec to fix it."
|
394
|
+
f"Provisioner: {spec.provisioner['name']}, Provider: {spec.provider}, Identifier: {spec.resource['identifier']}",
|
395
|
+
)
|
396
|
+
|
397
|
+
|
319
398
|
class TerrascriptClient: # pylint: disable=too-many-public-methods
|
320
399
|
"""
|
321
400
|
At a high-level, this class is responsible for generating Terraform configuration in
|
@@ -337,17 +416,23 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
337
416
|
integration_prefix: str,
|
338
417
|
thread_pool_size: int,
|
339
418
|
accounts: Iterable[dict[str, Any]],
|
340
|
-
settings:
|
341
|
-
prefetch_resources_by_schemas:
|
419
|
+
settings: Mapping[str, Any] | None = None,
|
420
|
+
prefetch_resources_by_schemas: list[str] | None = None,
|
421
|
+
secret_reader: SecretReaderBase | None = None,
|
342
422
|
) -> None:
|
343
423
|
self.integration = integration
|
344
424
|
self.integration_prefix = integration_prefix
|
345
|
-
self.settings = settings
|
346
425
|
self.thread_pool_size = thread_pool_size
|
347
426
|
filtered_accounts = self.filter_disabled_accounts(accounts)
|
348
|
-
|
427
|
+
if secret_reader:
|
428
|
+
self.secret_reader = secret_reader
|
429
|
+
else:
|
430
|
+
self.secret_reader = SecretReader(settings=settings)
|
431
|
+
self.configs: dict[str, dict] = {}
|
349
432
|
self.populate_configs(filtered_accounts)
|
350
|
-
self.versions
|
433
|
+
self.versions: dict[str, str] = {
|
434
|
+
a["name"]: a["providerVersion"] for a in filtered_accounts
|
435
|
+
}
|
351
436
|
tss = {}
|
352
437
|
locks = {}
|
353
438
|
self.supported_regions = {}
|
@@ -361,32 +446,47 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
361
446
|
ts += provider.aws(
|
362
447
|
access_key=config["aws_access_key_id"],
|
363
448
|
secret_key=config["aws_secret_access_key"],
|
364
|
-
version=self.versions.get(name),
|
365
449
|
region=region,
|
366
450
|
alias=region,
|
451
|
+
skip_region_validation=True,
|
452
|
+
default_tags=DEFAULT_TAGS,
|
367
453
|
)
|
368
454
|
|
369
455
|
# Add default region, which will be in resourcesDefaultRegion
|
370
456
|
ts += provider.aws(
|
371
457
|
access_key=config["aws_access_key_id"],
|
372
458
|
secret_key=config["aws_secret_access_key"],
|
373
|
-
version=self.versions.get(name),
|
374
459
|
region=config["resourcesDefaultRegion"],
|
460
|
+
skip_region_validation=True,
|
461
|
+
default_tags=DEFAULT_TAGS,
|
375
462
|
)
|
376
463
|
|
377
|
-
# the time provider can be removed if all AWS accounts
|
378
|
-
# upgrade to a provider version with this bug fix
|
379
|
-
# https://github.com/hashicorp/terraform-provider-aws/pull/20926
|
380
|
-
ts += time(version="0.9.1")
|
381
|
-
|
382
|
-
ts += provider.random(version="3.4.3")
|
383
|
-
|
384
|
-
ts += provider.template(version="2.2.0")
|
385
|
-
|
386
464
|
ts += Terraform(
|
387
465
|
backend=TerrascriptClient.state_bucket_for_account(
|
388
466
|
self.integration, name, config
|
389
|
-
)
|
467
|
+
),
|
468
|
+
required_providers={
|
469
|
+
"aws": {
|
470
|
+
"source": "hashicorp/aws",
|
471
|
+
"version": self.versions.get(name),
|
472
|
+
},
|
473
|
+
# the time provider can be removed if all AWS accounts
|
474
|
+
# upgrade to a provider version with this bug fix
|
475
|
+
# https://github.com/hashicorp/terraform-provider-aws/pull/20926
|
476
|
+
"time": {
|
477
|
+
"source": "hashicorp/time",
|
478
|
+
"version": "0.9.1",
|
479
|
+
},
|
480
|
+
"random": {
|
481
|
+
"source": "hashicorp/random",
|
482
|
+
"version": "3.4.3",
|
483
|
+
},
|
484
|
+
"cloudinit": {
|
485
|
+
"source": "hashicorp/cloudinit",
|
486
|
+
"version": "2.3.3",
|
487
|
+
},
|
488
|
+
},
|
489
|
+
required_version=TERRAFORM_VERSION[0],
|
390
490
|
)
|
391
491
|
tss[name] = ts
|
392
492
|
locks[name] = Lock()
|
@@ -402,8 +502,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
402
502
|
|
403
503
|
self.accounts = {a["name"]: a for a in filtered_accounts}
|
404
504
|
self.uids = {a["name"]: a["uid"] for a in filtered_accounts}
|
505
|
+
# default_regions info is needed in populate_tf_resource_rds, even in disabled accounts
|
405
506
|
self.default_regions = {
|
406
|
-
a["name"]: a["resourcesDefaultRegion"] for a in
|
507
|
+
a["name"]: a["resourcesDefaultRegion"] for a in accounts
|
407
508
|
}
|
408
509
|
self.partitions = {
|
409
510
|
a["name"]: a.get("partition") or "aws" for a in filtered_accounts
|
@@ -414,9 +515,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
414
515
|
self.rosa_authenticator_pre_signup_zip_lock = Lock()
|
415
516
|
self.lambda_zip: dict[str, str] = {}
|
416
517
|
self.lambda_lock = Lock()
|
417
|
-
self.github:
|
518
|
+
self.github: Github | None = None
|
418
519
|
self.github_lock = Lock()
|
419
|
-
self.gitlab:
|
520
|
+
self.gitlab: GitLabApi | None = None
|
420
521
|
self.gitlab_lock = Lock()
|
421
522
|
self.jenkins_map: dict[str, JenkinsApi] = {}
|
422
523
|
self.jenkins_lock = Lock()
|
@@ -445,7 +546,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
445
546
|
|
446
547
|
# defaults from account
|
447
548
|
bucket_backend_value = config.get("bucket")
|
448
|
-
key_backend_value = config.get("{}_key"
|
549
|
+
key_backend_value = config.get(f"{integration}_key")
|
449
550
|
region_backend_value = config.get("region")
|
450
551
|
terraform_state = config["terraformState"]
|
451
552
|
if terraform_state:
|
@@ -567,7 +668,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
567
668
|
with self.gitlab_lock:
|
568
669
|
if not self.gitlab:
|
569
670
|
instance = queries.get_gitlab_instance()
|
570
|
-
self.gitlab = GitLabApi(instance,
|
671
|
+
self.gitlab = GitLabApi(instance, secret_reader=self.secret_reader)
|
571
672
|
return self.gitlab
|
572
673
|
|
573
674
|
def init_jenkins(self, instance: dict) -> JenkinsApi:
|
@@ -576,10 +677,10 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
576
677
|
with self.jenkins_lock:
|
577
678
|
# this may have already happened, so we check again
|
578
679
|
if not self.jenkins_map.get(instance_name):
|
579
|
-
self.jenkins_map[
|
580
|
-
|
581
|
-
|
582
|
-
|
680
|
+
self.jenkins_map[instance_name] = (
|
681
|
+
JenkinsApi.init_jenkins_from_secret(
|
682
|
+
self.secret_reader, instance["token"]
|
683
|
+
)
|
583
684
|
)
|
584
685
|
return self.jenkins_map[instance_name]
|
585
686
|
|
@@ -600,7 +701,6 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
600
701
|
self.thread_pool_size,
|
601
702
|
secret_reader=self.secret_reader,
|
602
703
|
)
|
603
|
-
self.configs: dict[str, dict] = {}
|
604
704
|
for account_name, config in results:
|
605
705
|
account = awsh.get_account(accounts, account_name)
|
606
706
|
config["supportedDeploymentRegions"] = account["supportedDeploymentRegions"]
|
@@ -635,6 +735,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
635
735
|
group_name = aws_group["name"]
|
636
736
|
group_policies = aws_group["policies"]
|
637
737
|
account = aws_group["account"]
|
738
|
+
if account["sso"] is True:
|
739
|
+
# AWS accounts with SSO enabled do not need IAM groups
|
740
|
+
continue
|
638
741
|
account_name = account["name"]
|
639
742
|
if account_name not in groups:
|
640
743
|
groups[account_name] = {}
|
@@ -691,7 +794,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
691
794
|
self,
|
692
795
|
roles,
|
693
796
|
skip_reencrypt_accounts: list[str],
|
694
|
-
appsre_pgp_key:
|
797
|
+
appsre_pgp_key: str | None,
|
695
798
|
):
|
696
799
|
error = False
|
697
800
|
for role in roles:
|
@@ -705,6 +808,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
705
808
|
for aws_group in aws_groups:
|
706
809
|
group_name = aws_group["name"]
|
707
810
|
account = aws_group["account"]
|
811
|
+
if account["sso"] is True:
|
812
|
+
# AWS accounts with SSO enabled do not need IAM users
|
813
|
+
continue
|
708
814
|
account_name = account["name"]
|
709
815
|
account_console_url = account["consoleUrl"]
|
710
816
|
|
@@ -716,11 +822,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
716
822
|
|
717
823
|
# we want to include the console url in the outputs
|
718
824
|
# to be used later to generate the email invitations
|
719
|
-
|
720
|
-
self.integration_prefix, account_name
|
721
|
-
)
|
825
|
+
output_name = f"{self.integration_prefix}_console-urls__{account_name}"
|
722
826
|
output_value = account_console_url
|
723
|
-
tf_output = Output(
|
827
|
+
tf_output = Output(output_name, value=output_value)
|
724
828
|
self.add_resource(account_name, tf_output)
|
725
829
|
|
726
830
|
for user in users:
|
@@ -777,25 +881,23 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
777
881
|
# we want the outputs to be formed into a mail invitation
|
778
882
|
# for each new user. we form an output of the form
|
779
883
|
# 'qrtf.enc-passwords[user_name] = <encrypted password>
|
780
|
-
|
781
|
-
self.integration_prefix
|
884
|
+
output_name = (
|
885
|
+
f"{self.integration_prefix}_enc-passwords__{user_name}"
|
782
886
|
)
|
783
887
|
output_value = (
|
784
888
|
"${" + tf_iam_user_login_profile.encrypted_password + "}"
|
785
889
|
)
|
786
|
-
tf_output = Output(
|
890
|
+
tf_output = Output(output_name, value=output_value, sensitive=True)
|
787
891
|
self.add_resource(account_name, tf_output)
|
788
892
|
|
789
893
|
for user_policy in user_policies:
|
894
|
+
if user_policy["account"]["sso"] is True:
|
895
|
+
# AWS accounts with SSO enabled do not need user policies
|
896
|
+
continue
|
790
897
|
policy_name = user_policy["name"]
|
791
898
|
account_name = user_policy["account"]["name"]
|
792
|
-
account_uid = user_policy["account"]["uid"]
|
793
899
|
for user in users:
|
794
|
-
# replace known keys with values
|
795
900
|
user_name = self._get_aws_username(user)
|
796
|
-
policy = user_policy["policy"]
|
797
|
-
policy = policy.replace("${aws:username}", user_name)
|
798
|
-
policy = policy.replace("${aws:accountid}", account_uid)
|
799
901
|
|
800
902
|
# Ref: terraform aws_iam_policy
|
801
903
|
tf_iam_user = self.get_tf_iam_user(user_name)
|
@@ -803,7 +905,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
803
905
|
tf_aws_iam_policy = aws_iam_policy(
|
804
906
|
identifier,
|
805
907
|
name=identifier,
|
806
|
-
policy=policy,
|
908
|
+
policy=user_policy["policy"],
|
807
909
|
)
|
808
910
|
self.add_resource(account_name, tf_aws_iam_policy)
|
809
911
|
# Ref: terraform aws_iam_user_policy_attachment
|
@@ -811,9 +913,10 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
811
913
|
identifier,
|
812
914
|
user=user_name,
|
813
915
|
policy_arn=f"${{{tf_aws_iam_policy.arn}}}",
|
814
|
-
depends_on=self.get_dependencies(
|
815
|
-
|
816
|
-
|
916
|
+
depends_on=self.get_dependencies([
|
917
|
+
tf_iam_user,
|
918
|
+
tf_aws_iam_policy,
|
919
|
+
]),
|
817
920
|
)
|
818
921
|
self.add_resource(account_name, tf_iam_user_policy_attachment)
|
819
922
|
|
@@ -823,7 +926,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
823
926
|
self,
|
824
927
|
roles,
|
825
928
|
skip_reencrypt_accounts: list[str],
|
826
|
-
appsre_pgp_key:
|
929
|
+
appsre_pgp_key: str | None = None,
|
827
930
|
):
|
828
931
|
self.populate_iam_groups(roles)
|
829
932
|
err = self.populate_iam_users(
|
@@ -834,27 +937,59 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
834
937
|
return err
|
835
938
|
|
836
939
|
@staticmethod
|
837
|
-
def
|
838
|
-
|
839
|
-
|
940
|
+
def get_provider_alias(account: Mapping[str, str]) -> str:
|
941
|
+
if not account.get("assume_role"):
|
942
|
+
return f"account-{account['name']}-{account['assume_region']}"
|
943
|
+
uid = awsh.get_account_uid_from_arn(account["assume_role"])
|
944
|
+
role_name = awsh.get_id_from_arn(account["assume_role"])
|
945
|
+
return f"account-{uid}-{role_name}"
|
840
946
|
|
841
|
-
|
947
|
+
@staticmethod
|
948
|
+
def get_resource_lifecycle(
|
949
|
+
common_values: dict[str, Any],
|
950
|
+
) -> dict[str, Any] | None:
|
951
|
+
if lifecycle := common_values.get("lifecycle"):
|
952
|
+
lifecycle = NamespaceTerraformResourceLifecycleV1(**lifecycle)
|
953
|
+
if lifecycle.create_before_destroy is None:
|
954
|
+
lifecycle.create_before_destroy = False
|
955
|
+
if lifecycle.prevent_destroy is None:
|
956
|
+
lifecycle.prevent_destroy = False
|
957
|
+
if lifecycle.ignore_changes is None:
|
958
|
+
lifecycle.ignore_changes = []
|
959
|
+
if "all" in lifecycle.ignore_changes:
|
960
|
+
lifecycle.ignore_changes = "all"
|
961
|
+
return lifecycle.dict(by_alias=True)
|
962
|
+
return None
|
963
|
+
|
964
|
+
def populate_additional_providers(self, infra_account_name: str, accounts):
|
842
965
|
for account in accounts:
|
843
966
|
account_name = account["name"]
|
844
|
-
assume_role = account
|
845
|
-
|
846
|
-
|
967
|
+
assume_role = account.get("assume_role")
|
968
|
+
region = account["assume_region"]
|
969
|
+
alias = self.get_provider_alias(account)
|
970
|
+
ts = self.tss[infra_account_name]
|
847
971
|
config = self.configs[account_name]
|
848
972
|
existing_provider_aliases = {p.get("alias") for p in ts["provider"]["aws"]}
|
849
973
|
if alias not in existing_provider_aliases:
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
974
|
+
if assume_role:
|
975
|
+
ts += provider.aws(
|
976
|
+
access_key=config["aws_access_key_id"],
|
977
|
+
secret_key=config["aws_secret_access_key"],
|
978
|
+
region=region,
|
979
|
+
alias=alias,
|
980
|
+
assume_role={"role_arn": assume_role},
|
981
|
+
skip_region_validation=True,
|
982
|
+
default_tags=DEFAULT_TAGS,
|
983
|
+
)
|
984
|
+
else:
|
985
|
+
ts += provider.aws(
|
986
|
+
access_key=config["aws_access_key_id"],
|
987
|
+
secret_key=config["aws_secret_access_key"],
|
988
|
+
region=region,
|
989
|
+
alias=alias,
|
990
|
+
skip_region_validation=True,
|
991
|
+
default_tags=DEFAULT_TAGS,
|
992
|
+
)
|
858
993
|
|
859
994
|
def populate_route53(
|
860
995
|
self, desired_state: Iterable[dict[str, Any]], default_ttl: int = 300
|
@@ -913,7 +1048,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
913
1048
|
record["health_check_id"] = f"${{{healthcheck_resource.id}}}"
|
914
1049
|
|
915
1050
|
# Get value from Vault if _records_from_vault was set
|
916
|
-
records_from_vault:
|
1051
|
+
records_from_vault: Iterable[dict[str, str]] | None = record.pop(
|
917
1052
|
"records_from_vault", None
|
918
1053
|
)
|
919
1054
|
if records_from_vault:
|
@@ -922,19 +1057,17 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
922
1057
|
)
|
923
1058
|
vault_values: list[str] = []
|
924
1059
|
for rec in records_from_vault:
|
925
|
-
if
|
1060
|
+
if rec["path"] not in allowed_vault_secret_paths:
|
926
1061
|
raise UnapprovedSecretPathError(
|
927
1062
|
"'{}' is not in the list of approved Vault secret paths. Add this path to 'allowed_vault_secret_paths'.".format(
|
928
1063
|
rec["path"]
|
929
1064
|
)
|
930
1065
|
)
|
931
|
-
value = self.secret_reader.read(
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
}
|
937
|
-
)
|
1066
|
+
value = self.secret_reader.read({
|
1067
|
+
"path": rec["path"],
|
1068
|
+
"field": rec["field"],
|
1069
|
+
"version": rec["version"],
|
1070
|
+
})
|
938
1071
|
# 'key' is only set when the secret data is in JSON format and a
|
939
1072
|
# specific item from the object needs to be selected, otherwise the
|
940
1073
|
# value is used as-is.
|
@@ -950,7 +1083,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
950
1083
|
except KeyError:
|
951
1084
|
msg = f"Key '{rec['key']}' was not found in the contents of secret '{rec['path']}'"
|
952
1085
|
logging.error(msg)
|
953
|
-
raise KeyError(msg)
|
1086
|
+
raise KeyError(msg) from None
|
954
1087
|
vault_values.append(value)
|
955
1088
|
record["records"] = vault_values
|
956
1089
|
|
@@ -963,14 +1096,19 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
963
1096
|
if item["deleted"]:
|
964
1097
|
continue
|
965
1098
|
|
1099
|
+
infra_account_name = item["infra_account_name"]
|
1100
|
+
|
966
1101
|
connection_provider = item["connection_provider"]
|
967
1102
|
connection_name = item["connection_name"]
|
968
1103
|
requester = item["requester"]
|
969
1104
|
accepter = item["accepter"]
|
970
1105
|
|
971
1106
|
req_account = requester["account"]
|
972
|
-
|
973
|
-
|
1107
|
+
req_alias = self.get_provider_alias(req_account)
|
1108
|
+
|
1109
|
+
acc_account = accepter["account"]
|
1110
|
+
acc_account_name = acc_account["name"]
|
1111
|
+
acc_alias = self.get_provider_alias(acc_account)
|
974
1112
|
|
975
1113
|
# Requester's side of the connection - the cluster's account
|
976
1114
|
identifier = f"{requester['vpc_id']}-{accepter['vpc_id']}"
|
@@ -981,7 +1119,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
981
1119
|
"vpc_id": requester["vpc_id"],
|
982
1120
|
"peer_vpc_id": accepter["vpc_id"],
|
983
1121
|
"peer_region": accepter["region"],
|
984
|
-
"peer_owner_id":
|
1122
|
+
"peer_owner_id": acc_account["uid"],
|
985
1123
|
"auto_accept": False,
|
986
1124
|
"tags": {
|
987
1125
|
"managed_by_integration": self.integration,
|
@@ -993,7 +1131,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
993
1131
|
if req_peer_owner_id:
|
994
1132
|
values["peer_owner_id"] = req_peer_owner_id
|
995
1133
|
tf_resource = aws_vpc_peering_connection(identifier, **values)
|
996
|
-
self.add_resource(
|
1134
|
+
self.add_resource(infra_account_name, tf_resource)
|
997
1135
|
|
998
1136
|
# add routes to existing route tables
|
999
1137
|
route_table_ids = requester.get("route_table_ids")
|
@@ -1009,11 +1147,38 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1009
1147
|
}
|
1010
1148
|
route_identifier = f"{identifier}-{route_table_id}"
|
1011
1149
|
tf_resource = aws_route(route_identifier, **values)
|
1012
|
-
self.add_resource(
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1150
|
+
self.add_resource(infra_account_name, tf_resource)
|
1151
|
+
|
1152
|
+
# add security group rules for private hosted controlplane API VPC endpoint service
|
1153
|
+
if requester.get("api_security_group_id"):
|
1154
|
+
hcp_api_ingress_rule = aws_security_group_rule(
|
1155
|
+
f"requester-api-access-from-peering-{connection_name}",
|
1156
|
+
provider="aws." + req_alias,
|
1157
|
+
type="ingress",
|
1158
|
+
security_group_id=requester.get("api_security_group_id"),
|
1159
|
+
cidr_blocks=[accepter["cidr_block"]],
|
1160
|
+
from_port=443,
|
1161
|
+
to_port=443,
|
1162
|
+
protocol="tcp",
|
1163
|
+
description=f"HCP API access from peering connection {connection_name}",
|
1164
|
+
)
|
1165
|
+
self.add_resource(infra_account_name, hcp_api_ingress_rule)
|
1166
|
+
|
1167
|
+
if accepter.get("api_security_group_id"):
|
1168
|
+
self.add_resource(
|
1169
|
+
infra_account_name,
|
1170
|
+
aws_security_group_rule(
|
1171
|
+
f"accepter-api-access-from-peering-{connection_name}",
|
1172
|
+
provider="aws." + acc_alias,
|
1173
|
+
type="ingress",
|
1174
|
+
security_group_id=accepter.get("api_security_group_id"),
|
1175
|
+
cidr_blocks=[requester["cidr_block"]],
|
1176
|
+
from_port=443,
|
1177
|
+
to_port=443,
|
1178
|
+
protocol="tcp",
|
1179
|
+
description=f"HCP API access from peering connection {connection_name}",
|
1180
|
+
),
|
1181
|
+
)
|
1017
1182
|
|
1018
1183
|
# Accepter's side of the connection.
|
1019
1184
|
values = {
|
@@ -1027,13 +1192,13 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1027
1192
|
"Name": connection_name,
|
1028
1193
|
},
|
1029
1194
|
}
|
1030
|
-
if connection_provider in
|
1195
|
+
if connection_provider in {"account-vpc", "account-vpc-mesh"}:
|
1031
1196
|
if self._multiregion_account(acc_account_name):
|
1032
1197
|
values["provider"] = "aws." + accepter["region"]
|
1033
1198
|
else:
|
1034
1199
|
values["provider"] = "aws." + acc_alias
|
1035
1200
|
tf_resource = aws_vpc_peering_connection_accepter(identifier, **values)
|
1036
|
-
self.add_resource(
|
1201
|
+
self.add_resource(infra_account_name, tf_resource)
|
1037
1202
|
|
1038
1203
|
# add routes to existing route tables
|
1039
1204
|
route_table_ids = accepter.get("route_table_ids")
|
@@ -1046,32 +1211,121 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1046
1211
|
+ identifier
|
1047
1212
|
+ ".id}",
|
1048
1213
|
}
|
1049
|
-
if connection_provider in
|
1214
|
+
if connection_provider in {"account-vpc", "account-vpc-mesh"}:
|
1050
1215
|
if self._multiregion_account(acc_account_name):
|
1051
1216
|
values["provider"] = "aws." + accepter["region"]
|
1052
1217
|
else:
|
1053
1218
|
values["provider"] = "aws." + acc_alias
|
1054
1219
|
route_identifier = f"{identifier}-{route_table_id}"
|
1055
1220
|
tf_resource = aws_route(route_identifier, **values)
|
1056
|
-
self.add_resource(
|
1221
|
+
self.add_resource(infra_account_name, tf_resource)
|
1222
|
+
|
1223
|
+
def populate_vpc_requests(
|
1224
|
+
self, vpc_requests: Iterable[VPCRequest], vpc_module_version: str
|
1225
|
+
) -> None:
|
1226
|
+
for request in vpc_requests:
|
1227
|
+
# skiping deleted requests
|
1228
|
+
if request.delete:
|
1229
|
+
continue
|
1230
|
+
# The default values here come from infra repo's module configuration
|
1231
|
+
vpc_module_values = {
|
1232
|
+
"source": "terraform-aws-modules/vpc/aws",
|
1233
|
+
"version": vpc_module_version,
|
1234
|
+
"name": request.identifier,
|
1235
|
+
"cidr": request.cidr_block.network_address,
|
1236
|
+
"private_subnet_tags": {"kubernetes.io/role/internal-elb": "1"},
|
1237
|
+
"public_subnet_tags": {"kubernetes.io/role/elb": "1"},
|
1238
|
+
"create_database_subnet_group": False,
|
1239
|
+
"enable_dns_hostnames": True,
|
1240
|
+
"tags": {
|
1241
|
+
"managed_by_integration": self.integration,
|
1242
|
+
},
|
1243
|
+
}
|
1244
|
+
|
1245
|
+
if request.subnets and request.subnets.public:
|
1246
|
+
vpc_module_values["public_subnets"] = request.subnets.public
|
1247
|
+
if request.subnets and request.subnets.private:
|
1248
|
+
vpc_module_values["private_subnets"] = request.subnets.private
|
1249
|
+
if request.subnets and request.subnets.availability_zones:
|
1250
|
+
vpc_module_values["azs"] = request.subnets.availability_zones
|
1251
|
+
|
1252
|
+
# We only want to enable nat_gateway if we have public and private subnets
|
1253
|
+
if request.subnets and request.subnets.public and request.subnets.private:
|
1254
|
+
vpc_module_values["enable_nat_gateway"] = True
|
1255
|
+
|
1256
|
+
aws_account = request.account.name
|
1257
|
+
vpc_module = Module(request.identifier, **vpc_module_values)
|
1258
|
+
self.add_resource(aws_account, vpc_module)
|
1259
|
+
|
1260
|
+
# vpc_endpoint
|
1261
|
+
vpc_endpoint_values = {
|
1262
|
+
"source": "terraform-aws-modules/vpc/aws//modules/vpc-endpoints",
|
1263
|
+
"version": vpc_module_version,
|
1264
|
+
"vpc_id": f"${{{vpc_module.vpc_id}}}",
|
1265
|
+
"endpoints": {
|
1266
|
+
"s3": {
|
1267
|
+
"service": "s3",
|
1268
|
+
"serivce_type": "Gateway",
|
1269
|
+
"tags": {
|
1270
|
+
"managed_by_integration": self.integration,
|
1271
|
+
"Name": f"{request.identifier}--vpce-s3",
|
1272
|
+
"route_table_ids": vpc_module.vpc.private_route_table_ids,
|
1273
|
+
},
|
1274
|
+
}
|
1275
|
+
},
|
1276
|
+
}
|
1277
|
+
|
1278
|
+
vpc_endpoint = Module(
|
1279
|
+
f"{request.identifier}-endpoint", **vpc_endpoint_values
|
1280
|
+
)
|
1281
|
+
self.add_resource(aws_account, vpc_endpoint)
|
1282
|
+
|
1283
|
+
# The outputs for module are only working with this sintaxe
|
1284
|
+
vpc_id_output = Output(
|
1285
|
+
f"{request.identifier}-vpc_id", value=f"${{{vpc_module.vpc_id}}}"
|
1286
|
+
)
|
1287
|
+
self.add_resource(aws_account, vpc_id_output)
|
1288
|
+
|
1289
|
+
vpc_cidr_block_output = Output(
|
1290
|
+
f"{request.identifier}-vpc_cidr_block",
|
1291
|
+
value=f"${{{vpc_module.vpc_cidr_block}}}",
|
1292
|
+
)
|
1293
|
+
self.add_resource(aws_account, vpc_cidr_block_output)
|
1294
|
+
|
1295
|
+
if request.subnets and request.subnets.private:
|
1296
|
+
private_subnets_output = Output(
|
1297
|
+
f"{request.identifier}-private_subnets",
|
1298
|
+
value=f"${{module.{request.identifier}.private_subnets}}",
|
1299
|
+
)
|
1300
|
+
self.add_resource(aws_account, private_subnets_output)
|
1301
|
+
|
1302
|
+
if request.subnets and request.subnets.public:
|
1303
|
+
public_subnets_output = Output(
|
1304
|
+
f"{request.identifier}-public_subnets",
|
1305
|
+
value=f"${{module.{request.identifier}.public_subnets}}",
|
1306
|
+
)
|
1307
|
+
self.add_resource(aws_account, public_subnets_output)
|
1057
1308
|
|
1058
1309
|
def populate_tgw_attachments(self, desired_state):
|
1059
1310
|
for item in desired_state:
|
1060
|
-
if item
|
1311
|
+
if item.deleted:
|
1061
1312
|
continue
|
1062
1313
|
|
1063
|
-
|
1064
|
-
|
1065
|
-
|
1314
|
+
infra_account_name = item.infra_acount_name
|
1315
|
+
|
1316
|
+
connection_name = item.connection_name
|
1317
|
+
requester = item.requester
|
1318
|
+
accepter = item.accepter
|
1066
1319
|
|
1067
1320
|
# Requester's side of the connection - the AWS account
|
1068
|
-
req_account = requester
|
1069
|
-
req_account_name = req_account
|
1321
|
+
req_account = requester.account
|
1322
|
+
req_account_name = req_account.name
|
1070
1323
|
# Accepter's side of the connection - the cluster's account
|
1071
|
-
acc_account = accepter
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1324
|
+
acc_account = accepter.account
|
1325
|
+
acc_alias = self.get_provider_alias(acc_account.dict(by_alias=True))
|
1326
|
+
acc_uid = acc_account.uid
|
1327
|
+
if acc_account.assume_role:
|
1328
|
+
acc_uid = awsh.get_account_uid_from_arn(acc_account.assume_role)
|
1075
1329
|
|
1076
1330
|
tags = {"managed_by_integration": self.integration, "Name": connection_name}
|
1077
1331
|
# add resource share
|
@@ -1081,9 +1335,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1081
1335
|
"tags": tags,
|
1082
1336
|
}
|
1083
1337
|
if self._multiregion_account(req_account_name):
|
1084
|
-
values["provider"] = "aws." + requester
|
1338
|
+
values["provider"] = "aws." + requester.region
|
1085
1339
|
tf_resource_share = aws_ram_resource_share(connection_name, **values)
|
1086
|
-
self.add_resource(
|
1340
|
+
self.add_resource(infra_account_name, tf_resource_share)
|
1087
1341
|
|
1088
1342
|
# share with accepter aws account
|
1089
1343
|
values = {
|
@@ -1091,11 +1345,11 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1091
1345
|
"resource_share_arn": "${" + tf_resource_share.arn + "}",
|
1092
1346
|
}
|
1093
1347
|
if self._multiregion_account(req_account_name):
|
1094
|
-
values["provider"] = "aws." + requester
|
1348
|
+
values["provider"] = "aws." + requester.region
|
1095
1349
|
tf_resource_association = aws_ram_principal_association(
|
1096
1350
|
connection_name, **values
|
1097
1351
|
)
|
1098
|
-
self.add_resource(
|
1352
|
+
self.add_resource(infra_account_name, tf_resource_association)
|
1099
1353
|
|
1100
1354
|
# accept resource share from accepter aws account
|
1101
1355
|
values = {
|
@@ -1109,32 +1363,32 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1109
1363
|
tf_resource_share_accepter = aws_ram_resource_share_accepter(
|
1110
1364
|
connection_name, **values
|
1111
1365
|
)
|
1112
|
-
self.add_resource(
|
1366
|
+
self.add_resource(infra_account_name, tf_resource_share_accepter)
|
1113
1367
|
|
1114
1368
|
# until now it was standard sharing
|
1115
1369
|
# from this line onwards we will be adding content
|
1116
1370
|
# specific for the TGW attachments integration
|
1117
1371
|
|
1118
1372
|
# tgw share association
|
1119
|
-
identifier = f"{requester
|
1373
|
+
identifier = f"{requester.tgw_id}-{accepter.vpc_id}"
|
1120
1374
|
values = {
|
1121
|
-
"resource_arn": requester
|
1375
|
+
"resource_arn": requester.tgw_arn,
|
1122
1376
|
"resource_share_arn": "${" + tf_resource_share.arn + "}",
|
1123
1377
|
}
|
1124
1378
|
if self._multiregion_account(req_account_name):
|
1125
|
-
values["provider"] = "aws." + requester
|
1379
|
+
values["provider"] = "aws." + requester.region
|
1126
1380
|
tf_resource_association = aws_ram_resource_association(identifier, **values)
|
1127
|
-
self.add_resource(
|
1381
|
+
self.add_resource(infra_account_name, tf_resource_association)
|
1128
1382
|
|
1129
1383
|
# now that the tgw is shared to the cluster's aws account
|
1130
1384
|
# we can create a vpc attachment to the tgw
|
1131
|
-
subnets_id_az = accepter
|
1385
|
+
subnets_id_az = accepter.subnets_id_az
|
1132
1386
|
subnets = self.get_az_unique_subnet_ids(subnets_id_az)
|
1133
1387
|
values = {
|
1134
1388
|
"provider": "aws." + acc_alias,
|
1135
1389
|
"subnet_ids": subnets,
|
1136
|
-
"transit_gateway_id": requester
|
1137
|
-
"vpc_id": accepter
|
1390
|
+
"transit_gateway_id": requester.tgw_id,
|
1391
|
+
"vpc_id": accepter.vpc_id,
|
1138
1392
|
"depends_on": [
|
1139
1393
|
"aws_ram_principal_association." + connection_name,
|
1140
1394
|
"aws_ram_resource_association." + identifier,
|
@@ -1145,7 +1399,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1145
1399
|
identifier, **values
|
1146
1400
|
)
|
1147
1401
|
# we send the attachment from the cluster's aws account
|
1148
|
-
self.add_resource(
|
1402
|
+
self.add_resource(infra_account_name, tf_resource_attachment)
|
1149
1403
|
|
1150
1404
|
# and accept the attachment in the non cluster's aws account
|
1151
1405
|
values = {
|
@@ -1153,30 +1407,45 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1153
1407
|
"tags": tags,
|
1154
1408
|
}
|
1155
1409
|
if self._multiregion_account(req_account_name):
|
1156
|
-
values["provider"] = "aws." + requester
|
1410
|
+
values["provider"] = "aws." + requester.region
|
1157
1411
|
tf_resource_attachment_accepter = (
|
1158
1412
|
aws_ec2_transit_gateway_vpc_attachment_accepter(identifier, **values)
|
1159
1413
|
)
|
1160
|
-
self.add_resource(
|
1414
|
+
self.add_resource(infra_account_name, tf_resource_attachment_accepter)
|
1161
1415
|
|
1162
1416
|
# add routes to existing route tables
|
1163
|
-
route_table_ids = accepter.
|
1164
|
-
req_cidr_block = requester.
|
1165
|
-
|
1417
|
+
route_table_ids = accepter.route_table_ids
|
1418
|
+
req_cidr_block = requester.cidr_block
|
1419
|
+
req_cidr_blocks = requester.cidr_blocks or []
|
1420
|
+
if req_cidr_block:
|
1421
|
+
req_cidr_blocks.append(req_cidr_block)
|
1422
|
+
if route_table_ids and (req_cidr_block or req_cidr_blocks):
|
1166
1423
|
for route_table_id in route_table_ids:
|
1167
|
-
|
1168
|
-
|
1169
|
-
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1424
|
+
for cidr_block in req_cidr_blocks:
|
1425
|
+
values = {
|
1426
|
+
"provider": "aws." + acc_alias,
|
1427
|
+
"route_table_id": route_table_id,
|
1428
|
+
"destination_cidr_block": cidr_block,
|
1429
|
+
"transit_gateway_id": requester.tgw_id,
|
1430
|
+
}
|
1431
|
+
# use the cidr block in the resource name to allow re-ordering
|
1432
|
+
cidr_id = cidr_block.replace(".", "-").replace("/", "_")
|
1433
|
+
route_identifier = (
|
1434
|
+
f"{identifier}-{route_table_id}-dest-{cidr_id}"
|
1435
|
+
)
|
1436
|
+
tf_resource = aws_route(route_identifier, **values)
|
1437
|
+
self.add_resource(infra_account_name, tf_resource)
|
1438
|
+
if req_cidr_block:
|
1439
|
+
req_cidr_id = req_cidr_block.replace(".", "-").replace("/", "_")
|
1440
|
+
moved = Moved(
|
1441
|
+
fro=f"aws_route.{identifier}-{route_table_id}",
|
1442
|
+
to=f"aws_route.{identifier}-{route_table_id}-dest-{req_cidr_id}",
|
1443
|
+
)
|
1444
|
+
self.add_moved(infra_account_name, moved)
|
1176
1445
|
|
1177
1446
|
# add routes to peered transit gateways in the requester's
|
1178
1447
|
# account to achieve global routing from all regions
|
1179
|
-
requester_routes = requester.
|
1448
|
+
requester_routes = requester.routes
|
1180
1449
|
if requester_routes:
|
1181
1450
|
for route in requester_routes:
|
1182
1451
|
route_region = route["region"]
|
@@ -1197,11 +1466,25 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1197
1466
|
tf_resource = aws_ec2_transit_gateway_route(
|
1198
1467
|
route_identifier, **values
|
1199
1468
|
)
|
1200
|
-
self.add_resource(
|
1469
|
+
self.add_resource(infra_account_name, tf_resource)
|
1470
|
+
|
1471
|
+
if accepter.api_security_group_id:
|
1472
|
+
hcp_api_ingress_rule = aws_security_group_rule(
|
1473
|
+
f"api-access-from-{requester.tgw_id}",
|
1474
|
+
provider="aws." + acc_alias,
|
1475
|
+
type="ingress",
|
1476
|
+
security_group_id=accepter.api_security_group_id,
|
1477
|
+
cidr_blocks=[requester.cidr_block],
|
1478
|
+
from_port=443,
|
1479
|
+
to_port=443,
|
1480
|
+
protocol="tcp",
|
1481
|
+
description=f"HCP API access from TGW attachment {requester.tgw_id}",
|
1482
|
+
)
|
1483
|
+
self.add_resource(infra_account_name, hcp_api_ingress_rule)
|
1201
1484
|
|
1202
1485
|
# add rules to security groups of VPCs which are attached
|
1203
1486
|
# to the transit gateway to allow traffic through the routes
|
1204
|
-
requester_rules = requester.
|
1487
|
+
requester_rules = requester.rules
|
1205
1488
|
if requester_rules:
|
1206
1489
|
for rule in requester_rules:
|
1207
1490
|
rule_region = rule["region"]
|
@@ -1223,25 +1506,25 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1223
1506
|
values["provider"] = "aws." + rule_region
|
1224
1507
|
rule_identifier = f"{identifier}-{rule['vpc_id']}"
|
1225
1508
|
tf_resource = aws_security_group_rule(rule_identifier, **values)
|
1226
|
-
self.add_resource(
|
1509
|
+
self.add_resource(infra_account_name, tf_resource)
|
1227
1510
|
|
1228
|
-
for zone in requester.
|
1511
|
+
for zone in requester.hostedzones or []:
|
1229
1512
|
id = f"{identifier}-{zone}"
|
1230
1513
|
values = {
|
1231
|
-
"vpc_id": accepter
|
1232
|
-
"vpc_region": accepter
|
1514
|
+
"vpc_id": accepter.vpc_id,
|
1515
|
+
"vpc_region": accepter.region,
|
1233
1516
|
"zone_id": zone,
|
1234
1517
|
}
|
1235
1518
|
authorization = aws_route53_vpc_association_authorization(id, **values)
|
1236
|
-
self.add_resource(
|
1519
|
+
self.add_resource(infra_account_name, authorization)
|
1237
1520
|
values = {
|
1238
1521
|
"provider": "aws." + acc_alias,
|
1239
1522
|
"vpc_id": f"${{aws_route53_vpc_association_authorization.{id}.vpc_id}}",
|
1240
|
-
"vpc_region": accepter
|
1523
|
+
"vpc_region": accepter.region,
|
1241
1524
|
"zone_id": f"${{aws_route53_vpc_association_authorization.{id}.zone_id}}",
|
1242
1525
|
}
|
1243
1526
|
association = aws_route53_zone_association(id, **values)
|
1244
|
-
self.add_resource(
|
1527
|
+
self.add_resource(infra_account_name, association)
|
1245
1528
|
|
1246
1529
|
@staticmethod
|
1247
1530
|
def get_az_unique_subnet_ids(subnets_id_az):
|
@@ -1257,7 +1540,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1257
1540
|
|
1258
1541
|
return results
|
1259
1542
|
|
1260
|
-
def populate_resources(self, ocm_map:
|
1543
|
+
def populate_resources(self, ocm_map: OCMMap | None = None) -> None:
|
1261
1544
|
"""
|
1262
1545
|
Populates the terraform configuration from resource specs.
|
1263
1546
|
:param ocm_map:
|
@@ -1266,10 +1549,49 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1266
1549
|
for spec in specs:
|
1267
1550
|
self.populate_tf_resources(spec, ocm_map=ocm_map)
|
1268
1551
|
|
1552
|
+
def _is_provisioner_excluded(
|
1553
|
+
self,
|
1554
|
+
spec: ExternalResourceSpec,
|
1555
|
+
provider_exclusions: Mapping[str, Exclusion],
|
1556
|
+
) -> bool:
|
1557
|
+
e = provider_exclusions.get(spec.provider)
|
1558
|
+
if not e:
|
1559
|
+
return False
|
1560
|
+
return e.all or spec.provisioner_name in e.provisioners
|
1561
|
+
|
1562
|
+
def _filter_specs_managed_by_erv2(
|
1563
|
+
self,
|
1564
|
+
specs: Iterable[ExternalResourceSpec],
|
1565
|
+
provider_exclusions: Mapping[str, Exclusion],
|
1566
|
+
) -> list[ExternalResourceSpec]:
|
1567
|
+
filtered_specs = [
|
1568
|
+
spec for spec in specs if not spec.resource.get("managed_by_erv2")
|
1569
|
+
]
|
1570
|
+
|
1571
|
+
for spec in filtered_specs:
|
1572
|
+
if self._is_provisioner_excluded(spec, provider_exclusions):
|
1573
|
+
raise ProviderExcludedError(spec)
|
1574
|
+
|
1575
|
+
return filtered_specs
|
1576
|
+
|
1577
|
+
def _get_provider_exclusions_query_dict(
|
1578
|
+
self, provider_exclusions: Iterable[Mapping[str, Any]]
|
1579
|
+
) -> dict[str, Exclusion]:
|
1580
|
+
return {
|
1581
|
+
item["provider"]: Exclusion(
|
1582
|
+
all=item.get("excludeAllProvisioners") or False,
|
1583
|
+
provisioners={
|
1584
|
+
p["name"] for p in (item.get("excludeProvisioners") or [])
|
1585
|
+
},
|
1586
|
+
)
|
1587
|
+
for item in provider_exclusions
|
1588
|
+
}
|
1589
|
+
|
1269
1590
|
def init_populate_specs(
|
1270
1591
|
self,
|
1271
1592
|
namespaces: Iterable[Mapping[str, Any]],
|
1272
|
-
account_names:
|
1593
|
+
account_names: Iterable[str] | None,
|
1594
|
+
provider_exclusions: Iterable[Mapping[str, Any]] | None = None,
|
1273
1595
|
) -> None:
|
1274
1596
|
"""
|
1275
1597
|
Initiates resource specs from the definitions in app-interface
|
@@ -1280,16 +1602,37 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1280
1602
|
self.account_resource_specs: dict[str, list[ExternalResourceSpec]] = {}
|
1281
1603
|
self.resource_spec_inventory: ExternalResourceSpecInventory = {}
|
1282
1604
|
|
1605
|
+
# Ensure provider exclusions are fetched
|
1606
|
+
if provider_exclusions is None:
|
1607
|
+
provider_exclusions = (
|
1608
|
+
queries.get_tf_resources_provider_exclusions_by_provisioner() or []
|
1609
|
+
)
|
1610
|
+
|
1611
|
+
provider_exclusions_query_dict = self._get_provider_exclusions_query_dict(
|
1612
|
+
provider_exclusions
|
1613
|
+
)
|
1614
|
+
|
1283
1615
|
for namespace_info in namespaces:
|
1284
|
-
|
1285
|
-
namespace_info,
|
1616
|
+
all_specs = get_external_resource_specs(
|
1617
|
+
namespace_info,
|
1618
|
+
provision_provider=PROVIDER_AWS,
|
1619
|
+
)
|
1620
|
+
specs = self._filter_specs_managed_by_erv2(
|
1621
|
+
all_specs, provider_exclusions_query_dict
|
1286
1622
|
)
|
1623
|
+
name_counter = Counter(spec.output_resource_name for spec in specs)
|
1624
|
+
duplicates = [name for name, count in name_counter.items() if count > 1]
|
1625
|
+
if duplicates:
|
1626
|
+
raise OutputResourceNameNotUniqueException(
|
1627
|
+
namespace_info.get("name"), duplicates
|
1628
|
+
)
|
1287
1629
|
for spec in specs:
|
1288
1630
|
if account_names and spec.provisioner_name not in account_names:
|
1289
1631
|
continue
|
1290
1632
|
self.account_resource_specs.setdefault(
|
1291
1633
|
spec.provisioner_name, []
|
1292
1634
|
).append(spec)
|
1635
|
+
|
1293
1636
|
self.resource_spec_inventory[spec.id_object()] = spec
|
1294
1637
|
|
1295
1638
|
def populate_tf_resources(self, spec, ocm_map=None):
|
@@ -1346,6 +1689,8 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1346
1689
|
self.populate_tf_resource_rosa_authenticator(spec)
|
1347
1690
|
elif provider == "rosa-authenticator-vpce":
|
1348
1691
|
self.populate_tf_resource_rosa_authenticator_vpce(spec)
|
1692
|
+
elif provider == "msk":
|
1693
|
+
self.populate_tf_resource_msk(spec)
|
1349
1694
|
else:
|
1350
1695
|
raise UnknownProviderError(provider)
|
1351
1696
|
|
@@ -1360,12 +1705,13 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1360
1705
|
|
1361
1706
|
# we want to allow an empty name, so we
|
1362
1707
|
# only validate names which are not empty
|
1363
|
-
|
1708
|
+
db_name = self._get_db_name_from_values(values)
|
1709
|
+
if db_name and not self.validate_db_name(db_name):
|
1364
1710
|
raise FetchResourceError(
|
1365
1711
|
f"[{account}] RDS name must contain 1 to 63 letters, "
|
1366
1712
|
+ "numbers, or underscores. RDS name must begin with a "
|
1367
1713
|
+ "letter. Subsequent characters can be letters, "
|
1368
|
-
+ f"underscores, or digits (0-9): {
|
1714
|
+
+ f"underscores, or digits (0-9): {db_name}"
|
1369
1715
|
)
|
1370
1716
|
|
1371
1717
|
if not values.get("apply_immediately"):
|
@@ -1393,6 +1739,16 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1393
1739
|
elif provider != provider_region:
|
1394
1740
|
raise ValueError("region does not match availability zone")
|
1395
1741
|
|
1742
|
+
def validate_parameter_group(parameter_group: aws_db_parameter_group) -> None:
|
1743
|
+
parameter_group_name = parameter_group.get("name")
|
1744
|
+
for parameter in parameter_group.get("parameter", []):
|
1745
|
+
if parameter.get("name") == "rds.logical_replication":
|
1746
|
+
apply_method = parameter.get("apply_method")
|
1747
|
+
if apply_method != "pending-reboot":
|
1748
|
+
raise RDSParameterGroupValidationError(
|
1749
|
+
f"{parameter_group_name=} rds.logical_replication {apply_method=} must be set to 'pending-reboot'"
|
1750
|
+
)
|
1751
|
+
|
1396
1752
|
def populate_parameter_group(name: str) -> aws_db_parameter_group:
|
1397
1753
|
pg_values = self.get_values(name)
|
1398
1754
|
# Parameter group name is not required by terraform.
|
@@ -1406,7 +1762,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1406
1762
|
pg_values["parameter"] = pg_values.pop("parameters")
|
1407
1763
|
if self._multiregion_account(account) and len(provider) > 0:
|
1408
1764
|
pg_values["provider"] = provider
|
1409
|
-
|
1765
|
+
parameter_group = aws_db_parameter_group(pg_identifier, **pg_values)
|
1766
|
+
validate_parameter_group(parameter_group=parameter_group)
|
1767
|
+
return parameter_group
|
1410
1768
|
|
1411
1769
|
# 'deps' should contain a list of terraform resource names
|
1412
1770
|
# (not full objects) that must be created
|
@@ -1507,9 +1865,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1507
1865
|
ca_cert = values.pop("ca_cert", None)
|
1508
1866
|
if ca_cert:
|
1509
1867
|
# db.ca_cert
|
1510
|
-
|
1868
|
+
output_name = output_prefix + "__db_ca_cert"
|
1511
1869
|
output_value = self.secret_reader.read(ca_cert)
|
1512
|
-
tf_resources.append(Output(
|
1870
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
1513
1871
|
|
1514
1872
|
region = self._region_from_availability_zone(az) or self.default_regions.get(
|
1515
1873
|
account
|
@@ -1532,6 +1890,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1532
1890
|
replica_region = self.default_regions.get(account)
|
1533
1891
|
|
1534
1892
|
source_values = self.init_values(source_info)
|
1893
|
+
db_name = self._get_db_name_from_values(source_values)
|
1535
1894
|
if replica_region == region:
|
1536
1895
|
# replica is in the same region as source
|
1537
1896
|
values["replicate_source_db"] = replica_source
|
@@ -1631,7 +1990,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1631
1990
|
if sns_topic_name.startswith("arn:"):
|
1632
1991
|
raise ValueError("destination should not be an arn")
|
1633
1992
|
e_n["sns_topic"] = "${aws_sns_topic" + "." + sns_topic_name + ".arn}"
|
1634
|
-
e_n["source_ids"] = [
|
1993
|
+
e_n["source_ids"] = [identifier]
|
1635
1994
|
source_type = e_n.get("source_type", "all")
|
1636
1995
|
e_n_identifier = (
|
1637
1996
|
f"{sns_topic_name}_{source_type}_aws_db_event_subscription"
|
@@ -1642,33 +2001,34 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1642
2001
|
# rds instance
|
1643
2002
|
# Ref: https://www.terraform.io/docs/providers/aws/r/db_instance.html
|
1644
2003
|
tf_resource = aws_db_instance(identifier, **values)
|
2004
|
+
verify_rds_best_practices(tf_resource, spec.resource["data_classification"])
|
1645
2005
|
tf_resources.append(tf_resource)
|
1646
2006
|
|
1647
2007
|
# rds outputs
|
1648
2008
|
# we want the outputs to be formed into an OpenShift Secret
|
1649
2009
|
# with the following fields
|
1650
2010
|
# db.host
|
1651
|
-
|
2011
|
+
output_name = output_prefix + "__db_host"
|
1652
2012
|
output_value = "${" + tf_resource.address + "}"
|
1653
|
-
tf_resources.append(Output(
|
2013
|
+
tf_resources.append(Output(output_name, value=output_value))
|
1654
2014
|
# db.port
|
1655
|
-
|
2015
|
+
output_name = output_prefix + "__db_port"
|
1656
2016
|
output_value = "${" + str(tf_resource.port) + "}"
|
1657
|
-
tf_resources.append(Output(
|
2017
|
+
tf_resources.append(Output(output_name, value=output_value))
|
1658
2018
|
# db.name
|
1659
|
-
|
1660
|
-
output_value = output_resource_db_name or
|
1661
|
-
tf_resources.append(Output(
|
2019
|
+
output_name = output_prefix + "__db_name"
|
2020
|
+
output_value = output_resource_db_name or db_name
|
2021
|
+
tf_resources.append(Output(output_name, value=output_value))
|
1662
2022
|
# only set db user/password if not a replica or creation from snapshot
|
1663
2023
|
if self._db_needs_auth(values):
|
1664
2024
|
# db.user
|
1665
|
-
|
2025
|
+
output_name = output_prefix + "__db_user"
|
1666
2026
|
output_value = values["username"]
|
1667
|
-
tf_resources.append(Output(
|
2027
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
1668
2028
|
# db.password
|
1669
|
-
|
2029
|
+
output_name = output_prefix + "__db_password"
|
1670
2030
|
output_value = values["password"]
|
1671
|
-
tf_resources.append(Output(
|
2031
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
1672
2032
|
# only add reset_password key to the terraform state
|
1673
2033
|
# if reset_password_current_value is defined.
|
1674
2034
|
# this means that if the reset_password field is removed
|
@@ -1676,9 +2036,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1676
2036
|
# removed from the state and from the output resource,
|
1677
2037
|
# leading to a recycle of the pods using this resource.
|
1678
2038
|
if reset_password_current_value:
|
1679
|
-
|
2039
|
+
output_name = output_prefix + "__reset_password"
|
1680
2040
|
output_value = reset_password_current_value
|
1681
|
-
tf_resources.append(Output(
|
2041
|
+
tf_resources.append(Output(output_name, value=output_value))
|
1682
2042
|
|
1683
2043
|
self.add_resources(account, tf_resources)
|
1684
2044
|
|
@@ -1686,14 +2046,11 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1686
2046
|
if name not in self.configs:
|
1687
2047
|
return False
|
1688
2048
|
|
1689
|
-
|
1690
|
-
return True
|
1691
|
-
|
1692
|
-
return False
|
2049
|
+
return self.configs[name]["supportedDeploymentRegions"] is not None
|
1693
2050
|
|
1694
2051
|
def _find_resource_spec(
|
1695
2052
|
self, account: str, source: str, provider: str
|
1696
|
-
) ->
|
2053
|
+
) -> ExternalResourceSpec | None:
|
1697
2054
|
if account not in self.account_resource_specs:
|
1698
2055
|
return None
|
1699
2056
|
|
@@ -1702,6 +2059,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1702
2059
|
return spec
|
1703
2060
|
return None
|
1704
2061
|
|
2062
|
+
def _get_db_name_from_values(self, values: dict) -> str:
|
2063
|
+
return values.get("name") or values.get("db_name") or ""
|
2064
|
+
|
1705
2065
|
@staticmethod
|
1706
2066
|
def _region_from_availability_zone(az):
|
1707
2067
|
# Find the region by removing the last character from the
|
@@ -1714,12 +2074,10 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1714
2074
|
|
1715
2075
|
@staticmethod
|
1716
2076
|
def _db_needs_auth(config):
|
1717
|
-
|
2077
|
+
return bool(
|
1718
2078
|
"replicate_source_db" not in config
|
1719
2079
|
and config.get("replica_source", None) is None
|
1720
|
-
)
|
1721
|
-
return True
|
1722
|
-
return False
|
2080
|
+
)
|
1723
2081
|
|
1724
2082
|
@staticmethod
|
1725
2083
|
def validate_db_name(name):
|
@@ -1764,9 +2122,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1764
2122
|
common_values.get("server_side_encryption_configuration")
|
1765
2123
|
or DEFAULT_S3_SSE_CONFIGURATION
|
1766
2124
|
)
|
1767
|
-
values[
|
1768
|
-
|
1769
|
-
|
2125
|
+
values["server_side_encryption_configuration"] = (
|
2126
|
+
server_side_encryption_configuration
|
2127
|
+
)
|
1770
2128
|
# Support static website hosting [rosa-authenticator]
|
1771
2129
|
website = common_values.get("website")
|
1772
2130
|
if website:
|
@@ -1819,6 +2177,27 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1819
2177
|
if cors_rules:
|
1820
2178
|
# common_values['cors_rules'] is a list of cors_rules
|
1821
2179
|
values["cors_rule"] = cors_rules
|
2180
|
+
# S3 Bucket Logging
|
2181
|
+
s3_bucket_logging = common_values.get("s3_bucket_logging")
|
2182
|
+
if s3_bucket_logging:
|
2183
|
+
target_bucket_name = s3_bucket_logging.get("target_bucket_name")
|
2184
|
+
logging_identifier = f"{identifier}-logging"
|
2185
|
+
|
2186
|
+
# Logging config will be set out of this resource
|
2187
|
+
# the following `ignore_change` allows to avoid conflicts
|
2188
|
+
values.setdefault("lifecycle", {}).setdefault("ignore_changes", []).append(
|
2189
|
+
"logging"
|
2190
|
+
)
|
2191
|
+
|
2192
|
+
logging_values = {
|
2193
|
+
"bucket": "${aws_s3_bucket." + identifier + ".id}",
|
2194
|
+
"target_bucket": "${aws_s3_bucket." + target_bucket_name + ".id}",
|
2195
|
+
"target_prefix": s3_bucket_logging.get("target_prefix", ""),
|
2196
|
+
}
|
2197
|
+
logging_tf_resource = aws_s3_bucket_logging(
|
2198
|
+
logging_identifier, **logging_values
|
2199
|
+
)
|
2200
|
+
tf_resources.append(logging_tf_resource)
|
1822
2201
|
deps = []
|
1823
2202
|
replication_configs = common_values.get("replication_configurations")
|
1824
2203
|
if replication_configs:
|
@@ -1889,9 +2268,10 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1889
2268
|
# Terraform resource reference:
|
1890
2269
|
# https://www.terraform.io/docs/providers/aws/r/iam_policy_attachment.html
|
1891
2270
|
rc_values.clear()
|
1892
|
-
rc_values["depends_on"] = self.get_dependencies(
|
1893
|
-
|
1894
|
-
|
2271
|
+
rc_values["depends_on"] = self.get_dependencies([
|
2272
|
+
role_resource,
|
2273
|
+
policy_resource,
|
2274
|
+
])
|
1895
2275
|
rc_values["role"] = "${aws_iam_role." + id + ".name}"
|
1896
2276
|
rc_values["policy_arn"] = "${aws_iam_policy." + id + ".arn}"
|
1897
2277
|
tf_resource = aws_iam_role_policy_attachment(id, **rc_values)
|
@@ -1923,14 +2303,14 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1923
2303
|
values["provider"] = "aws." + region
|
1924
2304
|
bucket_tf_resource = aws_s3_bucket(identifier, **values)
|
1925
2305
|
tf_resources.append(bucket_tf_resource)
|
1926
|
-
|
2306
|
+
output_name = output_prefix + "__bucket"
|
1927
2307
|
output_value = bucket_tf_resource.bucket
|
1928
|
-
tf_resources.append(Output(
|
1929
|
-
|
1930
|
-
tf_resources.append(Output(
|
1931
|
-
endpoint = "s3.{}.amazonaws.com"
|
1932
|
-
|
1933
|
-
tf_resources.append(Output(
|
2308
|
+
tf_resources.append(Output(output_name, value=output_value))
|
2309
|
+
output_name = output_prefix + "__aws_region"
|
2310
|
+
tf_resources.append(Output(output_name, value=region))
|
2311
|
+
endpoint = f"s3.{region}.amazonaws.com"
|
2312
|
+
output_name = output_prefix + "__endpoint"
|
2313
|
+
tf_resources.append(Output(output_name, value=endpoint))
|
1934
2314
|
|
1935
2315
|
sqs_identifier = common_values.get("sqs_identifier", None)
|
1936
2316
|
if sqs_identifier is not None:
|
@@ -2043,6 +2423,8 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2043
2423
|
"policy": bucket_policy,
|
2044
2424
|
"depends_on": self.get_dependencies([bucket_tf_resource]),
|
2045
2425
|
}
|
2426
|
+
if self._multiregion_account(account):
|
2427
|
+
values["provider"] = "aws." + region
|
2046
2428
|
bucket_policy_tf_resource = aws_s3_bucket_policy(identifier, **values)
|
2047
2429
|
tf_resources.append(bucket_policy_tf_resource)
|
2048
2430
|
|
@@ -2065,10 +2447,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2065
2447
|
|
2066
2448
|
# iam user policy for bucket
|
2067
2449
|
values = {}
|
2068
|
-
values["user"] = identifier
|
2069
2450
|
values["name"] = identifier
|
2070
2451
|
|
2071
|
-
action = ["s3:*Object"]
|
2452
|
+
action = ["s3:*Object*"]
|
2072
2453
|
if common_values.get("acl", "private") == "public-read":
|
2073
2454
|
action.append("s3:PutObjectAcl")
|
2074
2455
|
allow_object_tagging = common_values.get("allow_object_tagging", False)
|
@@ -2095,12 +2476,6 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2095
2476
|
values["policy"] = json.dumps(policy, sort_keys=True)
|
2096
2477
|
values["depends_on"] = self.get_dependencies([user_tf_resource])
|
2097
2478
|
|
2098
|
-
# This is temporary, we are going to remove this after the
|
2099
|
-
# aws_iam_user_policy_attachment is deployed
|
2100
|
-
tf_aws_iam_user_policy = aws_iam_user_policy(identifier, **values)
|
2101
|
-
tf_resources.append(tf_aws_iam_user_policy)
|
2102
|
-
|
2103
|
-
values.pop("user")
|
2104
2479
|
tf_aws_iam_policy = aws_iam_policy(identifier, **values)
|
2105
2480
|
tf_resources.append(tf_aws_iam_policy)
|
2106
2481
|
|
@@ -2184,23 +2559,23 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2184
2559
|
# we want the outputs to be formed into an OpenShift Secret
|
2185
2560
|
# with the following fields
|
2186
2561
|
# db.endpoint
|
2187
|
-
|
2562
|
+
output_name = output_prefix + "__db_endpoint"
|
2188
2563
|
# https://docs.aws.amazon.com/AmazonElastiCache/
|
2189
2564
|
# latest/red-ug/Endpoints.html
|
2190
2565
|
if pg_cluster_enabled:
|
2191
2566
|
output_value = "${" + tf_resource.configuration_endpoint_address + "}"
|
2192
2567
|
else:
|
2193
2568
|
output_value = "${" + tf_resource.primary_endpoint_address + "}"
|
2194
|
-
tf_resources.append(Output(
|
2569
|
+
tf_resources.append(Output(output_name, value=output_value))
|
2195
2570
|
# db.port
|
2196
|
-
|
2571
|
+
output_name = output_prefix + "__db_port"
|
2197
2572
|
output_value = "${" + str(tf_resource.port) + "}"
|
2198
|
-
tf_resources.append(Output(
|
2573
|
+
tf_resources.append(Output(output_name, value=output_value))
|
2199
2574
|
# db.auth_token
|
2200
2575
|
if values.get("transit_encryption_enabled", False):
|
2201
|
-
|
2576
|
+
output_name = output_prefix + "__db_auth_token"
|
2202
2577
|
output_value = values["auth_token"]
|
2203
|
-
tf_resources.append(Output(
|
2578
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
2204
2579
|
|
2205
2580
|
self.add_resources(account, tf_resources)
|
2206
2581
|
|
@@ -2245,19 +2620,8 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2245
2620
|
for k, v in data.items():
|
2246
2621
|
to_replace = "${" + k + "}"
|
2247
2622
|
user_policy = user_policy.replace(to_replace, v)
|
2248
|
-
|
2249
|
-
tf_resources.append(Output(
|
2250
|
-
|
2251
|
-
# This is temporary, we are going to remove this after the
|
2252
|
-
# aws_iam_user_policy_attachment is deployed
|
2253
|
-
tf_aws_iam_user_policy = aws_iam_user_policy(
|
2254
|
-
identifier,
|
2255
|
-
name=identifier,
|
2256
|
-
user=identifier,
|
2257
|
-
policy=user_policy,
|
2258
|
-
depends_on=self.get_dependencies([user_tf_resource]),
|
2259
|
-
)
|
2260
|
-
tf_resources.append(tf_aws_iam_user_policy)
|
2623
|
+
output_name = output_prefix + f"__{k}"
|
2624
|
+
tf_resources.append(Output(output_name, value=v))
|
2261
2625
|
|
2262
2626
|
tf_aws_iam_policy = aws_iam_policy(
|
2263
2627
|
identifier,
|
@@ -2286,15 +2650,15 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2286
2650
|
# OCM AWS infrastructure access.
|
2287
2651
|
assume_role = aws_infrastructure_access.get("assume_role")
|
2288
2652
|
if assume_role:
|
2289
|
-
|
2290
|
-
tf_resources.append(Output(
|
2653
|
+
output_name = output_prefix + "__role_arn"
|
2654
|
+
tf_resources.append(Output(output_name, value=assume_role))
|
2291
2655
|
elif ocm_map:
|
2292
2656
|
cluster = aws_infrastructure_access["cluster"]["name"]
|
2293
2657
|
ocm = ocm_map.get(cluster)
|
2294
2658
|
role_grants = ocm.get_aws_infrastructure_access_role_grants(cluster)
|
2295
2659
|
for user_arn, _, state, switch_role_link in role_grants:
|
2296
2660
|
# find correct user by identifier
|
2297
|
-
user_id = awsh.
|
2661
|
+
user_id = awsh.get_id_from_arn(user_arn)
|
2298
2662
|
# output will only be added once
|
2299
2663
|
# terraform-resources created the user
|
2300
2664
|
# and ocm-aws-infrastructure-access granted it the role
|
@@ -2302,10 +2666,8 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2302
2666
|
switch_role_arn = awsh.get_role_arn_from_role_link(
|
2303
2667
|
switch_role_link
|
2304
2668
|
)
|
2305
|
-
|
2306
|
-
tf_resources.append(
|
2307
|
-
Output(output_name_0_13, value=switch_role_arn)
|
2308
|
-
)
|
2669
|
+
output_name = output_prefix + "__role_arn"
|
2670
|
+
tf_resources.append(Output(output_name, value=switch_role_arn))
|
2309
2671
|
else:
|
2310
2672
|
raise KeyError(
|
2311
2673
|
f"[{account}/{identifier}] "
|
@@ -2348,9 +2710,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2348
2710
|
)
|
2349
2711
|
)
|
2350
2712
|
|
2351
|
-
|
2713
|
+
output_name = output_prefix + "__secrets_prefix"
|
2352
2714
|
output_value = secrets_prefix
|
2353
|
-
tf_resources.append(Output(
|
2715
|
+
tf_resources.append(Output(output_name, value=output_value))
|
2354
2716
|
|
2355
2717
|
self.add_resources(account, tf_resources)
|
2356
2718
|
|
@@ -2365,12 +2727,13 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2365
2727
|
|
2366
2728
|
assume_role = common_values["assume_role"]
|
2367
2729
|
assume_role = {k: v for k, v in assume_role.items() if v is not None}
|
2730
|
+
assume_action = common_values.get("assume_action") or "AssumeRole"
|
2368
2731
|
# assume role policy
|
2369
2732
|
assume_role_policy = {
|
2370
2733
|
"Version": "2012-10-17",
|
2371
2734
|
"Statement": [
|
2372
2735
|
{
|
2373
|
-
"Action": "sts:
|
2736
|
+
"Action": f"sts:{assume_action}",
|
2374
2737
|
"Effect": "Allow",
|
2375
2738
|
"Principal": assume_role,
|
2376
2739
|
}
|
@@ -2391,16 +2754,96 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2391
2754
|
if inline_policy:
|
2392
2755
|
values["inline_policy"] = {"name": identifier, "policy": inline_policy}
|
2393
2756
|
|
2757
|
+
if lifecycle := self.get_resource_lifecycle(common_values):
|
2758
|
+
values["lifecycle"] = lifecycle
|
2759
|
+
|
2394
2760
|
role_tf_resource = aws_iam_role(identifier, **values)
|
2395
2761
|
tf_resources.append(role_tf_resource)
|
2396
2762
|
|
2763
|
+
if role_policy := common_values.get("role_policy"):
|
2764
|
+
tf_aws_iam_policy = aws_iam_policy(
|
2765
|
+
identifier,
|
2766
|
+
name=identifier,
|
2767
|
+
policy=role_policy,
|
2768
|
+
depends_on=self.get_dependencies([role_tf_resource]),
|
2769
|
+
tags=common_values["tags"],
|
2770
|
+
)
|
2771
|
+
tf_resources.append(tf_aws_iam_policy)
|
2772
|
+
|
2773
|
+
tf_aws_iam_policy_attachment = aws_iam_role_policy_attachment(
|
2774
|
+
identifier,
|
2775
|
+
role=role_tf_resource.name,
|
2776
|
+
policy_arn=f"${{{tf_aws_iam_policy.arn}}}",
|
2777
|
+
depends_on=self.get_dependencies([role_tf_resource, tf_aws_iam_policy]),
|
2778
|
+
)
|
2779
|
+
tf_resources.append(tf_aws_iam_policy_attachment)
|
2780
|
+
|
2781
|
+
for policy in common_values.get("policies") or []:
|
2782
|
+
tf_iam_role_policy_attachment = aws_iam_role_policy_attachment(
|
2783
|
+
identifier + "-" + policy,
|
2784
|
+
role=role_tf_resource.name,
|
2785
|
+
policy_arn=f"arn:{self._get_partition(account)}:iam::aws:policy/{policy}",
|
2786
|
+
depends_on=self.get_dependencies([role_tf_resource]),
|
2787
|
+
)
|
2788
|
+
tf_resources.append(tf_iam_role_policy_attachment)
|
2789
|
+
|
2397
2790
|
# output role arn
|
2398
|
-
|
2791
|
+
output_name = output_prefix + "__role_arn"
|
2399
2792
|
output_value = "${" + role_tf_resource.arn + "}"
|
2400
|
-
tf_resources.append(Output(
|
2793
|
+
tf_resources.append(Output(output_name, value=output_value))
|
2401
2794
|
|
2402
2795
|
self.add_resources(account, tf_resources)
|
2403
2796
|
|
2797
|
+
def populate_iam_policy(self, account: str, name: str, policy: dict[str, Any]):
|
2798
|
+
tf_aws_iam_policy = aws_iam_policy(
|
2799
|
+
f"{account}-{name}", name=name, policy=json.dumps(policy)
|
2800
|
+
)
|
2801
|
+
self.add_resource(account, tf_aws_iam_policy)
|
2802
|
+
|
2803
|
+
def populate_saml_iam_role(
|
2804
|
+
self,
|
2805
|
+
account: str,
|
2806
|
+
name: str,
|
2807
|
+
saml_provider_name: str,
|
2808
|
+
aws_managed_policies: list[str],
|
2809
|
+
customer_managed_policies: list[str] | None = None,
|
2810
|
+
max_session_duration_hours: int = 1,
|
2811
|
+
) -> None:
|
2812
|
+
"""Manage the an IAM role needed for SAML authentication."""
|
2813
|
+
managed_policy_arns = [
|
2814
|
+
f"arn:{self._get_partition(account)}:iam::aws:policy/{policy}"
|
2815
|
+
for policy in aws_managed_policies
|
2816
|
+
]
|
2817
|
+
managed_policy_arns += [
|
2818
|
+
f"arn:{self._get_partition(account)}:iam::{self.uids[account]}:policy/{policy}"
|
2819
|
+
for policy in customer_managed_policies or []
|
2820
|
+
]
|
2821
|
+
assume_role_policy = {
|
2822
|
+
"Version": "2012-10-17",
|
2823
|
+
"Statement": [
|
2824
|
+
{
|
2825
|
+
"Effect": "Allow",
|
2826
|
+
"Principal": {
|
2827
|
+
"Federated": f"arn:{self._get_partition(account)}:iam::{self.uids[account]}:saml-provider/{saml_provider_name}"
|
2828
|
+
},
|
2829
|
+
"Action": "sts:AssumeRoleWithSAML",
|
2830
|
+
"Condition": {
|
2831
|
+
"StringEquals": {
|
2832
|
+
"SAML:aud": "https://signin.aws.amazon.com/saml"
|
2833
|
+
}
|
2834
|
+
},
|
2835
|
+
}
|
2836
|
+
],
|
2837
|
+
}
|
2838
|
+
role_tf_resource = aws_iam_role(
|
2839
|
+
f"{account}-{name}",
|
2840
|
+
name=name,
|
2841
|
+
assume_role_policy=json.dumps(assume_role_policy),
|
2842
|
+
managed_policy_arns=managed_policy_arns,
|
2843
|
+
max_session_duration=max_session_duration_hours * 3600,
|
2844
|
+
)
|
2845
|
+
self.add_resource(account, role_tf_resource)
|
2846
|
+
|
2404
2847
|
def populate_tf_resource_sqs(self, spec):
|
2405
2848
|
account = spec.provisioner_name
|
2406
2849
|
identifier = spec.identifier
|
@@ -2414,9 +2857,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2414
2857
|
specs = common_values.get("specs")
|
2415
2858
|
all_queues_per_spec = []
|
2416
2859
|
kms_keys = set()
|
2417
|
-
for
|
2418
|
-
defaults = self.get_values(
|
2419
|
-
queues =
|
2860
|
+
for _spec in specs:
|
2861
|
+
defaults = self.get_values(_spec["defaults"])
|
2862
|
+
queues = _spec.pop("queues", [])
|
2420
2863
|
all_queues = []
|
2421
2864
|
for queue_kv in queues:
|
2422
2865
|
queue_key = queue_kv["key"]
|
@@ -2473,13 +2916,11 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2473
2916
|
kms_keys.add(values["kms_master_key_id"])
|
2474
2917
|
queue_tf_resource = aws_sqs_queue(queue, **values)
|
2475
2918
|
tf_resources.append(queue_tf_resource)
|
2476
|
-
|
2477
|
-
tf_resources.append(Output(
|
2478
|
-
|
2479
|
-
output_value = "https://sqs.{}.amazonaws.com/{}/{}"
|
2480
|
-
|
2481
|
-
)
|
2482
|
-
tf_resources.append(Output(output_name_0_13, value=output_value))
|
2919
|
+
output_name = output_prefix + "__aws_region"
|
2920
|
+
tf_resources.append(Output(output_name, value=region))
|
2921
|
+
output_name = f"{output_prefix}__{queue_key}"
|
2922
|
+
output_value = f"https://sqs.{region}.amazonaws.com/{uid}/{queue_name}"
|
2923
|
+
tf_resources.append(Output(output_name, value=output_value))
|
2483
2924
|
all_queues_per_spec.append(all_queues)
|
2484
2925
|
|
2485
2926
|
# iam resources
|
@@ -2499,10 +2940,8 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2499
2940
|
)
|
2500
2941
|
|
2501
2942
|
# iam policy for queue
|
2502
|
-
policy_index
|
2503
|
-
for all_queues in all_queues_per_spec:
|
2943
|
+
for policy_index, all_queues in enumerate(all_queues_per_spec):
|
2504
2944
|
policy_identifier = f"{identifier}-{policy_index}"
|
2505
|
-
policy_index += 1
|
2506
2945
|
if len(all_queues_per_spec) == 1:
|
2507
2946
|
policy_identifier = identifier
|
2508
2947
|
values = {}
|
@@ -2536,9 +2975,10 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2536
2975
|
values = {}
|
2537
2976
|
values["user"] = identifier
|
2538
2977
|
values["policy_arn"] = "${" + policy_tf_resource.arn + "}"
|
2539
|
-
values["depends_on"] = self.get_dependencies(
|
2540
|
-
|
2541
|
-
|
2978
|
+
values["depends_on"] = self.get_dependencies([
|
2979
|
+
user_tf_resource,
|
2980
|
+
policy_tf_resource,
|
2981
|
+
])
|
2542
2982
|
tf_resource = aws_iam_user_policy_attachment(policy_identifier, **values)
|
2543
2983
|
tf_resources.append(tf_resource)
|
2544
2984
|
|
@@ -2554,10 +2994,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2554
2994
|
|
2555
2995
|
values = {}
|
2556
2996
|
fifo_topic = common_values.get("fifo_topic", False)
|
2557
|
-
if fifo_topic
|
2558
|
-
topic_name = identifier + (".fifo")
|
2559
|
-
else:
|
2560
|
-
topic_name = identifier
|
2997
|
+
topic_name = identifier + ".fifo" if fifo_topic else identifier
|
2561
2998
|
|
2562
2999
|
values["name"] = topic_name
|
2563
3000
|
values["policy"] = policy
|
@@ -2568,9 +3005,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2568
3005
|
tf_resource = aws_sns_topic(identifier, **values)
|
2569
3006
|
tf_resources.append(tf_resource)
|
2570
3007
|
|
2571
|
-
if "subscriptions" in common_values
|
3008
|
+
if "subscriptions" in common_values:
|
2572
3009
|
subscriptions = common_values.get("subscriptions")
|
2573
|
-
for sub in subscriptions:
|
3010
|
+
for index, sub in enumerate(subscriptions):
|
2574
3011
|
sub_values = {}
|
2575
3012
|
sub_values["topic_arn"] = "${aws_sns_topic" + "." + identifier + ".arn}"
|
2576
3013
|
protocol = sub["protocol"]
|
@@ -2580,17 +3017,21 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2580
3017
|
raise ValueError(msg)
|
2581
3018
|
sub_values["protocol"] = protocol
|
2582
3019
|
sub_values["endpoint"] = endpoint
|
2583
|
-
|
3020
|
+
# append suffix only in case there are multiple subscriptions
|
3021
|
+
suffix = f"_{index + 1}" if len(subscriptions) > 1 else ""
|
3022
|
+
sub_identifier = (
|
3023
|
+
f"{identifier}_{protocol}_aws_sns_topic_subscription{suffix}"
|
3024
|
+
)
|
2584
3025
|
sub_tf_resource = aws_sns_topic_subscription(
|
2585
3026
|
sub_identifier, **sub_values
|
2586
3027
|
)
|
2587
3028
|
tf_resources.append(sub_tf_resource)
|
2588
3029
|
|
2589
|
-
|
2590
|
-
tf_resources.append(Output(
|
2591
|
-
|
3030
|
+
output_name = output_prefix + "__aws_region"
|
3031
|
+
tf_resources.append(Output(output_name, value=region))
|
3032
|
+
output_name = output_prefix + "__endpoint"
|
2592
3033
|
output_value = f"https://sns.{region}.amazonaws.com"
|
2593
|
-
tf_resources.append(Output(
|
3034
|
+
tf_resources.append(Output(output_name, value=output_value))
|
2594
3035
|
self.add_resources(account, tf_resources)
|
2595
3036
|
|
2596
3037
|
def populate_tf_resource_dynamodb(self, spec):
|
@@ -2605,10 +3046,10 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2605
3046
|
region = common_values.get("region") or self.default_regions.get(account)
|
2606
3047
|
specs = common_values.get("specs")
|
2607
3048
|
all_tables = []
|
2608
|
-
for
|
2609
|
-
defaults = self.get_values(
|
3049
|
+
for _spec in specs:
|
3050
|
+
defaults = self.get_values(_spec["defaults"])
|
2610
3051
|
attributes = defaults.pop("attributes")
|
2611
|
-
tables =
|
3052
|
+
tables = _spec["tables"]
|
2612
3053
|
for table_kv in tables:
|
2613
3054
|
table_key = table_kv["key"]
|
2614
3055
|
table = table_kv["value"]
|
@@ -2626,14 +3067,14 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2626
3067
|
values["provider"] = "aws." + region
|
2627
3068
|
table_tf_resource = aws_dynamodb_table(table, **values)
|
2628
3069
|
tf_resources.append(table_tf_resource)
|
2629
|
-
|
2630
|
-
tf_resources.append(Output(
|
3070
|
+
output_name = f"{output_prefix}__{table_key}"
|
3071
|
+
tf_resources.append(Output(output_name, value=table))
|
2631
3072
|
|
2632
|
-
|
2633
|
-
tf_resources.append(Output(
|
2634
|
-
|
3073
|
+
output_name = output_prefix + "__aws_region"
|
3074
|
+
tf_resources.append(Output(output_name, value=region))
|
3075
|
+
output_name = output_prefix + "__endpoint"
|
2635
3076
|
output_value = f"https://dynamodb.{region}.amazonaws.com"
|
2636
|
-
tf_resources.append(Output(
|
3077
|
+
tf_resources.append(Output(output_name, value=output_value))
|
2637
3078
|
|
2638
3079
|
# iam resources
|
2639
3080
|
# Terraform resource reference:
|
@@ -2653,7 +3094,6 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2653
3094
|
|
2654
3095
|
# iam user policy for queue
|
2655
3096
|
values = {}
|
2656
|
-
values["user"] = identifier
|
2657
3097
|
values["name"] = identifier
|
2658
3098
|
policy = {
|
2659
3099
|
"Version": "2012-10-17",
|
@@ -2662,8 +3102,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2662
3102
|
"Effect": "Allow",
|
2663
3103
|
"Action": ["dynamodb:*"],
|
2664
3104
|
"Resource": [
|
2665
|
-
"arn:aws:dynamodb:{}:{}:table/{}"
|
2666
|
-
for t in all_tables
|
3105
|
+
f"arn:aws:dynamodb:{region}:{uid}:table/{t}" for t in all_tables
|
2667
3106
|
],
|
2668
3107
|
}
|
2669
3108
|
],
|
@@ -2671,12 +3110,6 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2671
3110
|
values["policy"] = json.dumps(policy, sort_keys=True)
|
2672
3111
|
values["depends_on"] = self.get_dependencies([user_tf_resource])
|
2673
3112
|
|
2674
|
-
# This is temporary, we are going to remove this after the
|
2675
|
-
# aws_iam_user_policy_attachment is deployed
|
2676
|
-
tf_aws_iam_user_policy = aws_iam_user_policy(identifier, **values)
|
2677
|
-
tf_resources.append(tf_aws_iam_user_policy)
|
2678
|
-
|
2679
|
-
values.pop("user")
|
2680
3113
|
tf_aws_iam_policy = aws_iam_policy(identifier, **values)
|
2681
3114
|
tf_resources.append(tf_aws_iam_policy)
|
2682
3115
|
|
@@ -2719,13 +3152,13 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2719
3152
|
values["repository_name"] = values.pop("name")
|
2720
3153
|
ecr_tf_resource = aws_ecrpublic_repository(identifier, **values)
|
2721
3154
|
tf_resources.append(ecr_tf_resource)
|
2722
|
-
|
3155
|
+
output_name = output_prefix + "__url"
|
2723
3156
|
output_value = "${" + ecr_tf_resource.repository_url + "}"
|
2724
3157
|
if public:
|
2725
3158
|
output_value = "${" + ecr_tf_resource.repository_uri + "}"
|
2726
|
-
tf_resources.append(Output(
|
2727
|
-
|
2728
|
-
tf_resources.append(Output(
|
3159
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3160
|
+
output_name = output_prefix + "__aws_region"
|
3161
|
+
tf_resources.append(Output(output_name, value=region))
|
2729
3162
|
|
2730
3163
|
# iam resources
|
2731
3164
|
# Terraform resource reference:
|
@@ -2746,7 +3179,6 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2746
3179
|
|
2747
3180
|
# iam user policy for bucket
|
2748
3181
|
values = {}
|
2749
|
-
values["user"] = identifier
|
2750
3182
|
values["name"] = identifier
|
2751
3183
|
policy = {
|
2752
3184
|
"Version": "2012-10-17",
|
@@ -2787,12 +3219,6 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2787
3219
|
values["policy"] = json.dumps(policy, sort_keys=True)
|
2788
3220
|
values["depends_on"] = self.get_dependencies([user_tf_resource])
|
2789
3221
|
|
2790
|
-
# This is temporary, we are going to remove this after the
|
2791
|
-
# aws_iam_user_policy_attachment is deployed
|
2792
|
-
tf_aws_iam_user_policy = aws_iam_user_policy(identifier, **values)
|
2793
|
-
tf_resources.append(tf_aws_iam_user_policy)
|
2794
|
-
|
2795
|
-
values.pop("user")
|
2796
3222
|
tf_aws_iam_policy = aws_iam_policy(identifier, **values)
|
2797
3223
|
tf_resources.append(tf_aws_iam_policy)
|
2798
3224
|
|
@@ -2850,49 +3276,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2850
3276
|
bucket_policy_tf_resource = aws_s3_bucket_policy(identifier, **values)
|
2851
3277
|
tf_resources.append(bucket_policy_tf_resource)
|
2852
3278
|
|
2853
|
-
# cloud front distribution
|
2854
3279
|
values = common_values.get("distribution_config", {})
|
2855
|
-
values["tags"] = common_values["tags"]
|
2856
|
-
values.setdefault("default_cache_behavior", {}).setdefault(
|
2857
|
-
"target_origin_id", "default"
|
2858
|
-
)
|
2859
|
-
origin = {
|
2860
|
-
"domain_name": "${" + bucket_tf_resource.bucket_domain_name + "}",
|
2861
|
-
"origin_id": values["default_cache_behavior"]["target_origin_id"],
|
2862
|
-
"s3_origin_config": {
|
2863
|
-
"origin_access_identity": "origin-access-identity/cloudfront/"
|
2864
|
-
+ "${"
|
2865
|
-
+ cf_oai_tf_resource.id
|
2866
|
-
+ "}"
|
2867
|
-
},
|
2868
|
-
}
|
2869
|
-
values["origin"] = [origin]
|
2870
|
-
cf_distribution_tf_resource = aws_cloudfront_distribution(identifier, **values)
|
2871
|
-
tf_resources.append(cf_distribution_tf_resource)
|
2872
|
-
|
2873
|
-
# outputs
|
2874
|
-
# cloud_front_origin_access_identity_id
|
2875
|
-
output_name_0_13 = output_prefix + "__cloud_front_origin_access_identity_id"
|
2876
|
-
output_value = "${" + cf_oai_tf_resource.id + "}"
|
2877
|
-
tf_resources.append(Output(output_name_0_13, value=output_value))
|
2878
|
-
# s3_canonical_user_id
|
2879
|
-
output_name_0_13 = output_prefix + "__s3_canonical_user_id"
|
2880
|
-
output_value = "${" + cf_oai_tf_resource.s3_canonical_user_id + "}"
|
2881
|
-
tf_resources.append(Output(output_name_0_13, value=output_value))
|
2882
|
-
# distribution_domain
|
2883
|
-
output_name_0_13 = output_prefix + "__distribution_domain"
|
2884
|
-
output_value = "${" + cf_distribution_tf_resource.domain_name + "}"
|
2885
|
-
tf_resources.append(Output(output_name_0_13, value=output_value))
|
2886
|
-
# origin_access_identity
|
2887
|
-
output_name_0_13 = output_prefix + "__origin_access_identity"
|
2888
|
-
output_value = (
|
2889
|
-
"origin-access-identity/cloudfront/" + "${" + cf_oai_tf_resource.id + "}"
|
2890
|
-
)
|
2891
|
-
tf_resources.append(Output(output_name_0_13, value=output_value))
|
2892
|
-
|
2893
3280
|
# aws_s3_bucket_acl
|
2894
|
-
|
2895
|
-
if "logging_config" in values.keys():
|
3281
|
+
if "logging_config" in values:
|
2896
3282
|
# we could set this at a global level with a standard name like "cloudfront"
|
2897
3283
|
# but we need all aws accounts upgraded to aws provider >3.60 first
|
2898
3284
|
tf_resources.append(
|
@@ -2900,7 +3286,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2900
3286
|
)
|
2901
3287
|
|
2902
3288
|
logging_config_bucket = values["logging_config"]
|
2903
|
-
|
3289
|
+
acl_values = {}
|
2904
3290
|
access_control_policy = {
|
2905
3291
|
"owner": {
|
2906
3292
|
"id": "${data.aws_canonical_user_id.current.id}",
|
@@ -2923,12 +3309,61 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
2923
3309
|
},
|
2924
3310
|
],
|
2925
3311
|
}
|
2926
|
-
|
2927
|
-
|
3312
|
+
external_account_id = logging_config_bucket.pop("external_account_id", None)
|
3313
|
+
if external_account_id:
|
3314
|
+
external_account_policy = {
|
3315
|
+
"grantee": {
|
3316
|
+
"id": external_account_id,
|
3317
|
+
"type": "CanonicalUser",
|
3318
|
+
},
|
3319
|
+
"permission": "FULL_CONTROL",
|
3320
|
+
}
|
3321
|
+
access_control_policy["grant"].append(external_account_policy)
|
3322
|
+
acl_values["access_control_policy"] = access_control_policy
|
3323
|
+
acl_values["bucket"] = logging_config_bucket.get("bucket").split(".")[0]
|
2928
3324
|
|
2929
|
-
aws_s3_bucket_acl_resource = aws_s3_bucket_acl(identifier, **
|
3325
|
+
aws_s3_bucket_acl_resource = aws_s3_bucket_acl(identifier, **acl_values)
|
2930
3326
|
tf_resources.append(aws_s3_bucket_acl_resource)
|
2931
3327
|
|
3328
|
+
# cloud front distribution
|
3329
|
+
values["tags"] = common_values["tags"]
|
3330
|
+
values.setdefault("default_cache_behavior", {}).setdefault(
|
3331
|
+
"target_origin_id", "default"
|
3332
|
+
)
|
3333
|
+
origin = {
|
3334
|
+
"domain_name": "${" + bucket_tf_resource.bucket_domain_name + "}",
|
3335
|
+
"origin_id": values["default_cache_behavior"]["target_origin_id"],
|
3336
|
+
"s3_origin_config": {
|
3337
|
+
"origin_access_identity": "origin-access-identity/cloudfront/"
|
3338
|
+
+ "${"
|
3339
|
+
+ cf_oai_tf_resource.id
|
3340
|
+
+ "}"
|
3341
|
+
},
|
3342
|
+
}
|
3343
|
+
values["origin"] = [origin]
|
3344
|
+
cf_distribution_tf_resource = aws_cloudfront_distribution(identifier, **values)
|
3345
|
+
tf_resources.append(cf_distribution_tf_resource)
|
3346
|
+
|
3347
|
+
# outputs
|
3348
|
+
# cloud_front_origin_access_identity_id
|
3349
|
+
output_name = output_prefix + "__cloud_front_origin_access_identity_id"
|
3350
|
+
output_value = "${" + cf_oai_tf_resource.id + "}"
|
3351
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3352
|
+
# s3_canonical_user_id
|
3353
|
+
output_name = output_prefix + "__s3_canonical_user_id"
|
3354
|
+
output_value = "${" + cf_oai_tf_resource.s3_canonical_user_id + "}"
|
3355
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3356
|
+
# distribution_domain
|
3357
|
+
output_name = output_prefix + "__distribution_domain"
|
3358
|
+
output_value = "${" + cf_distribution_tf_resource.domain_name + "}"
|
3359
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3360
|
+
# origin_access_identity
|
3361
|
+
output_name = output_prefix + "__origin_access_identity"
|
3362
|
+
output_value = (
|
3363
|
+
"origin-access-identity/cloudfront/" + "${" + cf_oai_tf_resource.id + "}"
|
3364
|
+
)
|
3365
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3366
|
+
|
2932
3367
|
self.add_resources(account, tf_resources)
|
2933
3368
|
|
2934
3369
|
def populate_tf_resource_s3_sqs(self, spec):
|
@@ -3076,13 +3511,13 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3076
3511
|
tf_resources.append(access_key_tf_resource)
|
3077
3512
|
# outputs
|
3078
3513
|
# sqs_aws_access_key_id
|
3079
|
-
|
3514
|
+
output_name = output_prefix + "__sqs_aws_access_key_id"
|
3080
3515
|
output_value = "${" + access_key_tf_resource.id + "}"
|
3081
|
-
tf_resources.append(Output(
|
3516
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
3082
3517
|
# sqs_aws_secret_access_key
|
3083
|
-
|
3518
|
+
output_name = output_prefix + "__sqs_aws_secret_access_key"
|
3084
3519
|
output_value = "${" + access_key_tf_resource.secret + "}"
|
3085
|
-
tf_resources.append(Output(
|
3520
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
3086
3521
|
|
3087
3522
|
# iam policy for queue
|
3088
3523
|
values = {}
|
@@ -3116,20 +3551,19 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3116
3551
|
values = {}
|
3117
3552
|
values["user"] = sqs_identifier
|
3118
3553
|
values["policy_arn"] = "${" + policy_tf_resource.arn + "}"
|
3119
|
-
values["depends_on"] = self.get_dependencies(
|
3120
|
-
|
3121
|
-
|
3554
|
+
values["depends_on"] = self.get_dependencies([
|
3555
|
+
user_tf_resource,
|
3556
|
+
policy_tf_resource,
|
3557
|
+
])
|
3122
3558
|
user_policy_attachment_tf_resource = aws_iam_user_policy_attachment(
|
3123
3559
|
sqs_identifier, **values
|
3124
3560
|
)
|
3125
3561
|
tf_resources.append(user_policy_attachment_tf_resource)
|
3126
3562
|
|
3127
3563
|
# outputs
|
3128
|
-
|
3129
|
-
output_value = "https://sqs.{}.amazonaws.com/{}/{}"
|
3130
|
-
|
3131
|
-
)
|
3132
|
-
tf_resources.append(Output(output_name_0_13, value=output_value))
|
3564
|
+
output_name = f"{output_prefix}__{sqs_identifier}"
|
3565
|
+
output_value = f"https://sqs.{region}.amazonaws.com/{uid}/{sqs_identifier}"
|
3566
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3133
3567
|
|
3134
3568
|
self.add_resources(account, tf_resources)
|
3135
3569
|
|
@@ -3294,11 +3728,11 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3294
3728
|
)
|
3295
3729
|
tf_resources.append(subscription_tf_resource)
|
3296
3730
|
|
3297
|
-
|
3731
|
+
output_name = output_prefix + "__log_group_name"
|
3298
3732
|
output_value = log_group_tf_resource.name
|
3299
|
-
tf_resources.append(Output(
|
3300
|
-
|
3301
|
-
tf_resources.append(Output(
|
3733
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3734
|
+
output_name = output_prefix + "__aws_region"
|
3735
|
+
tf_resources.append(Output(output_name, value=region))
|
3302
3736
|
|
3303
3737
|
# iam resources
|
3304
3738
|
# Terraform resource reference:
|
@@ -3340,18 +3774,11 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3340
3774
|
],
|
3341
3775
|
}
|
3342
3776
|
values = {
|
3343
|
-
"user": identifier,
|
3344
3777
|
"name": identifier,
|
3345
3778
|
"policy": json.dumps(policy, sort_keys=True),
|
3346
3779
|
"depends_on": self.get_dependencies([user_tf_resource]),
|
3347
3780
|
}
|
3348
3781
|
|
3349
|
-
# This is temporary, we are going to remove this after the
|
3350
|
-
# aws_iam_user_policy_attachment is deployed
|
3351
|
-
tf_aws_iam_user_policy = aws_iam_user_policy(identifier, **values)
|
3352
|
-
tf_resources.append(tf_aws_iam_user_policy)
|
3353
|
-
|
3354
|
-
values.pop("user")
|
3355
3782
|
tf_aws_iam_policy = aws_iam_policy(identifier, **values)
|
3356
3783
|
tf_resources.append(tf_aws_iam_policy)
|
3357
3784
|
|
@@ -3395,9 +3822,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3395
3822
|
tf_resources.append(tf_resource)
|
3396
3823
|
|
3397
3824
|
# key_id
|
3398
|
-
|
3825
|
+
output_name = output_prefix + "__key_id"
|
3399
3826
|
output_value = "${" + tf_resource.key_id + "}"
|
3400
|
-
tf_resources.append(Output(
|
3827
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3401
3828
|
|
3402
3829
|
alias_values = {}
|
3403
3830
|
alias_values["name"] = "alias/" + identifier
|
@@ -3510,11 +3937,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3510
3937
|
attachment_values = {
|
3511
3938
|
"role": role_tf_resource.name,
|
3512
3939
|
"policy_arn": "${" + policy_tf_resource.arn + "}",
|
3513
|
-
"depends_on": self.get_dependencies(
|
3514
|
-
|
3515
|
-
|
3516
|
-
]
|
3517
|
-
),
|
3940
|
+
"depends_on": self.get_dependencies([
|
3941
|
+
role_tf_resource,
|
3942
|
+
]),
|
3518
3943
|
}
|
3519
3944
|
attachment_tf_resource = aws_iam_role_policy_attachment(
|
3520
3945
|
policy_identifier, **attachment_values
|
@@ -3598,9 +4023,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3598
4023
|
"starting_position_timestamp", None
|
3599
4024
|
)
|
3600
4025
|
if not starting_position_timestamp:
|
3601
|
-
source_vaules[
|
3602
|
-
|
3603
|
-
|
4026
|
+
source_vaules["starting_position_timestamp"] = (
|
4027
|
+
starting_position_timestamp
|
4028
|
+
)
|
3604
4029
|
|
3605
4030
|
batch_size = common_values.get("batch_size", 100)
|
3606
4031
|
source_vaules["batch_size"] = batch_size
|
@@ -3617,11 +4042,11 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3617
4042
|
|
3618
4043
|
# outputs
|
3619
4044
|
# stream_name
|
3620
|
-
|
3621
|
-
tf_resources.append(Output(
|
4045
|
+
output_name = output_prefix + "__stream_name"
|
4046
|
+
tf_resources.append(Output(output_name, value=identifier))
|
3622
4047
|
# aws_region
|
3623
|
-
|
3624
|
-
tf_resources.append(Output(
|
4048
|
+
output_name = output_prefix + "__aws_region"
|
4049
|
+
tf_resources.append(Output(output_name, value=region))
|
3625
4050
|
|
3626
4051
|
# iam resources
|
3627
4052
|
policy = {
|
@@ -3713,17 +4138,10 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3713
4138
|
|
3714
4139
|
# iam user policy
|
3715
4140
|
values = {}
|
3716
|
-
values["user"] = identifier
|
3717
4141
|
values["name"] = identifier
|
3718
4142
|
values["policy"] = json.dumps(policy, sort_keys=True)
|
3719
4143
|
values["depends_on"] = self.get_dependencies([user_tf_resource])
|
3720
4144
|
|
3721
|
-
# This is temporary, we are going to remove this after the
|
3722
|
-
# aws_iam_user_policy_attachment is deployed
|
3723
|
-
tf_aws_iam_user_policy = aws_iam_user_policy(identifier, **values)
|
3724
|
-
tf_resources.append(tf_aws_iam_user_policy)
|
3725
|
-
|
3726
|
-
values.pop("user")
|
3727
4145
|
tf_aws_iam_policy = aws_iam_policy(identifier, **values)
|
3728
4146
|
tf_resources.append(tf_aws_iam_policy)
|
3729
4147
|
|
@@ -3746,13 +4164,13 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3746
4164
|
tf_resources.append(tf_resource)
|
3747
4165
|
# outputs
|
3748
4166
|
# aws_access_key_id
|
3749
|
-
|
4167
|
+
output_name = output_prefix + "__aws_access_key_id"
|
3750
4168
|
output_value = "${" + tf_resource.id + "}"
|
3751
|
-
tf_resources.append(Output(
|
4169
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
3752
4170
|
# aws_secret_access_key
|
3753
|
-
|
4171
|
+
output_name = output_prefix + "__aws_secret_access_key"
|
3754
4172
|
output_value = "${" + tf_resource.secret + "}"
|
3755
|
-
tf_resources.append(Output(
|
4173
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
3756
4174
|
|
3757
4175
|
return tf_resources
|
3758
4176
|
|
@@ -3763,17 +4181,30 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3763
4181
|
def add_resource(self, account, tf_resource):
|
3764
4182
|
if account not in self.locks:
|
3765
4183
|
logging.debug(
|
3766
|
-
"integration {} is disabled for account {}. "
|
3767
|
-
"can not add resource"
|
4184
|
+
f"integration {self.integration} is disabled for account {account}. "
|
4185
|
+
"can not add resource"
|
3768
4186
|
)
|
3769
4187
|
return
|
3770
4188
|
with self.locks[account]:
|
3771
4189
|
self.tss[account].add(tf_resource)
|
3772
4190
|
|
4191
|
+
def add_moved(self, account: str, moved: Moved):
|
4192
|
+
if account not in self.locks:
|
4193
|
+
logging.debug(
|
4194
|
+
f"integration {self.integration} is disabled for account {account}. "
|
4195
|
+
"can not add resource"
|
4196
|
+
)
|
4197
|
+
return
|
4198
|
+
with self.locks[account]:
|
4199
|
+
self.tss[account].setdefault("moved", []).append({
|
4200
|
+
"from": moved.fro,
|
4201
|
+
"to": moved.to,
|
4202
|
+
})
|
4203
|
+
|
3773
4204
|
def dump(
|
3774
4205
|
self,
|
3775
|
-
print_to_file:
|
3776
|
-
existing_dirs:
|
4206
|
+
print_to_file: str | None = None,
|
4207
|
+
existing_dirs: dict[str, str] | None = None,
|
3777
4208
|
) -> dict[str, str]:
|
3778
4209
|
"""
|
3779
4210
|
Dump the Terraform configurations (in JSON format) to the working directories.
|
@@ -3796,21 +4227,36 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3796
4227
|
os.remove(print_to_file)
|
3797
4228
|
|
3798
4229
|
for name, ts in self.tss.items():
|
4230
|
+
content = str(ts)
|
3799
4231
|
if print_to_file:
|
3800
|
-
with open(print_to_file, "a") as f:
|
4232
|
+
with open(print_to_file, "a", encoding="locale") as f:
|
3801
4233
|
f.write(f"##### {name} #####\n")
|
3802
|
-
f.write(
|
4234
|
+
f.write(content)
|
3803
4235
|
f.write("\n")
|
3804
4236
|
if existing_dirs is None:
|
3805
4237
|
wd = tempfile.mkdtemp(prefix=TMP_DIR_PREFIX)
|
3806
4238
|
else:
|
3807
4239
|
wd = working_dirs[name]
|
3808
|
-
with open(wd + "/config.tf.json", "w") as f:
|
3809
|
-
f.write(
|
4240
|
+
with open(wd + "/config.tf.json", "w", encoding="locale") as f:
|
4241
|
+
f.write(content)
|
3810
4242
|
working_dirs[name] = wd
|
3811
4243
|
|
3812
4244
|
return working_dirs
|
3813
4245
|
|
4246
|
+
def terraform_configurations(self) -> dict[str, str]:
|
4247
|
+
"""
|
4248
|
+
Return the Terraform configurations (in JSON format) for each AWS account.
|
4249
|
+
Terraform config content keys are sorted for consistent hash check.
|
4250
|
+
The result is not used for final file dump.
|
4251
|
+
Doc: https://python-terrascript.readthedocs.io/en/stable/quickstart.html
|
4252
|
+
|
4253
|
+
:return: key is AWS account name and value is terraform configuration
|
4254
|
+
"""
|
4255
|
+
return {
|
4256
|
+
name: json.dumps(ts, indent=2, sort_keys=True)
|
4257
|
+
for name, ts in self.tss.items()
|
4258
|
+
}
|
4259
|
+
|
3814
4260
|
def init_values(self, spec: ExternalResourceSpec, init_tags: bool = True) -> dict:
|
3815
4261
|
"""
|
3816
4262
|
Initialize the values of the terraform resource and merge the defaults and
|
@@ -3834,6 +4280,33 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3834
4280
|
if val is not None:
|
3835
4281
|
values[key] = val
|
3836
4282
|
|
4283
|
+
if self.versions and not self.versions.get(
|
4284
|
+
spec.provisioner_name, ""
|
4285
|
+
).startswith("3"):
|
4286
|
+
if spec.provider == "rds":
|
4287
|
+
if db_name := values.pop("name", None):
|
4288
|
+
values["db_name"] = db_name
|
4289
|
+
if values.get("replica_source"):
|
4290
|
+
values.pop("db_name", None)
|
4291
|
+
elif spec.provider == "elasticache":
|
4292
|
+
if description := values.pop("replication_group_description", None):
|
4293
|
+
values["description"] = description
|
4294
|
+
if num_cache_clusters := values.pop("number_cache_clusters", None):
|
4295
|
+
values["num_cache_clusters"] = num_cache_clusters
|
4296
|
+
if cluster_mode := values.pop("cluster_mode", {}):
|
4297
|
+
for k, v in cluster_mode.items():
|
4298
|
+
values[k] = v
|
4299
|
+
values.pop("availability_zones", None)
|
4300
|
+
elif spec.provider == "msk":
|
4301
|
+
if ebs_volume_size := values.get("broker_node_group_info", {}).pop(
|
4302
|
+
"ebs_volume_size", None
|
4303
|
+
):
|
4304
|
+
values["broker_node_group_info"].setdefault(
|
4305
|
+
"storage_info", {}
|
4306
|
+
).setdefault("ebs_storage_info", {})[
|
4307
|
+
"volume_size"
|
4308
|
+
] = ebs_volume_size
|
4309
|
+
|
3837
4310
|
return values
|
3838
4311
|
|
3839
4312
|
@staticmethod
|
@@ -3863,39 +4336,39 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3863
4336
|
tf_resources: list[Resource],
|
3864
4337
|
spec: ExternalResourceSpec,
|
3865
4338
|
):
|
3866
|
-
|
4339
|
+
output_format = "{}__{}_{}"
|
3867
4340
|
# cluster
|
3868
|
-
|
4341
|
+
output_name = output_format.format(
|
3869
4342
|
spec.output_prefix, self.integration_prefix, "cluster"
|
3870
4343
|
)
|
3871
4344
|
output_value = spec.cluster_name
|
3872
|
-
tf_resources.append(Output(
|
4345
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3873
4346
|
# namespace
|
3874
|
-
|
4347
|
+
output_name = output_format.format(
|
3875
4348
|
spec.output_prefix, self.integration_prefix, "namespace"
|
3876
4349
|
)
|
3877
4350
|
output_value = spec.namespace_name
|
3878
|
-
tf_resources.append(Output(
|
4351
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3879
4352
|
# resource
|
3880
|
-
|
4353
|
+
output_name = output_format.format(
|
3881
4354
|
spec.output_prefix, self.integration_prefix, "resource"
|
3882
4355
|
)
|
3883
4356
|
output_value = "Secret"
|
3884
|
-
tf_resources.append(Output(
|
4357
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3885
4358
|
# output_resource_name
|
3886
|
-
|
4359
|
+
output_name = output_format.format(
|
3887
4360
|
spec.output_prefix, self.integration_prefix, "output_resource_name"
|
3888
4361
|
)
|
3889
4362
|
output_value = spec.output_resource_name
|
3890
|
-
tf_resources.append(Output(
|
4363
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3891
4364
|
# annotations
|
3892
4365
|
if spec.annotations():
|
3893
|
-
|
4366
|
+
output_name = output_format.format(
|
3894
4367
|
spec.output_prefix, self.integration_prefix, "annotations"
|
3895
4368
|
)
|
3896
4369
|
anno_json = json.dumps(spec.annotations()).encode("utf-8")
|
3897
4370
|
output_value = base64.b64encode(anno_json).decode()
|
3898
|
-
tf_resources.append(Output(
|
4371
|
+
tf_resources.append(Output(output_name, value=output_value))
|
3899
4372
|
|
3900
4373
|
def prefetch_resources(self, schema) -> dict[str, dict[str, str]]:
|
3901
4374
|
gqlapi = gql.get_api()
|
@@ -3909,7 +4382,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3909
4382
|
try:
|
3910
4383
|
raw_values = gqlapi.get_resource(path)
|
3911
4384
|
except gql.GqlGetResourceError as e:
|
3912
|
-
raise FetchResourceError(str(e))
|
4385
|
+
raise FetchResourceError(str(e)) from e
|
3913
4386
|
return raw_values
|
3914
4387
|
|
3915
4388
|
def get_values(self, path: str) -> dict[str, Any]:
|
@@ -3919,7 +4392,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3919
4392
|
values.pop("$schema", None)
|
3920
4393
|
except anymarkup.AnyMarkupError:
|
3921
4394
|
e_msg = "Could not parse data. Skipping resource: {}"
|
3922
|
-
raise FetchResourceError(e_msg.format(path))
|
4395
|
+
raise FetchResourceError(e_msg.format(path)) from None
|
3923
4396
|
return values
|
3924
4397
|
|
3925
4398
|
@staticmethod
|
@@ -3990,7 +4463,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
3990
4463
|
|
3991
4464
|
def _get_elasticsearch_account_wide_resource_policy(
|
3992
4465
|
self, account: str
|
3993
|
-
) ->
|
4466
|
+
) -> aws_cloudwatch_log_resource_policy | None:
|
3994
4467
|
"""
|
3995
4468
|
https://docs.aws.amazon.com/opensearch-service/latest/developerguide/createdomain-configure-slow-logs.html
|
3996
4469
|
CloudWatch Logs supports 10 resource policies per Region.
|
@@ -4065,13 +4538,11 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4065
4538
|
for t in ElasticSearchLogGroupType:
|
4066
4539
|
log_type = t.value
|
4067
4540
|
if log_type not in publish_log_types:
|
4068
|
-
publishing_options.append(
|
4069
|
-
|
4070
|
-
|
4071
|
-
|
4072
|
-
|
4073
|
-
}
|
4074
|
-
)
|
4541
|
+
publishing_options.append({
|
4542
|
+
"log_type": log_type,
|
4543
|
+
"enabled": False,
|
4544
|
+
"cloudwatch_log_group_arn": "",
|
4545
|
+
})
|
4075
4546
|
continue
|
4076
4547
|
|
4077
4548
|
log_type_identifier = TerrascriptClient.elasticsearch_log_group_identifier(
|
@@ -4093,25 +4564,23 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4093
4564
|
arn = f"${{{log_group_tf_resource.arn}}}"
|
4094
4565
|
|
4095
4566
|
# add arn to output
|
4096
|
-
|
4567
|
+
output_name = (
|
4097
4568
|
f"{output_prefix}__cloudwatch_log_group_" f"{log_type.lower()}_arn"
|
4098
4569
|
)
|
4099
4570
|
output_value = arn
|
4100
|
-
tf_resources.append(Output(
|
4571
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4101
4572
|
|
4102
4573
|
# add name to output
|
4103
|
-
|
4574
|
+
output_name = (
|
4104
4575
|
f"{output_prefix}__cloudwatch_log_group_" f"{log_type.lower()}_name"
|
4105
4576
|
)
|
4106
4577
|
output_value = log_type_identifier
|
4107
|
-
tf_resources.append(Output(
|
4108
|
-
publishing_options.append(
|
4109
|
-
|
4110
|
-
|
4111
|
-
|
4112
|
-
|
4113
|
-
}
|
4114
|
-
)
|
4578
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4579
|
+
publishing_options.append({
|
4580
|
+
"log_type": log_type,
|
4581
|
+
"enabled": True,
|
4582
|
+
"cloudwatch_log_group_arn": arn,
|
4583
|
+
})
|
4115
4584
|
|
4116
4585
|
return tf_resources, publishing_options
|
4117
4586
|
|
@@ -4281,6 +4750,24 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4281
4750
|
)
|
4282
4751
|
cluster_vaules["warm_count"] = cluster_config.get("warm_count", 2)
|
4283
4752
|
|
4753
|
+
cold_storage_options = cluster_config.get("cold_storage_options", {})
|
4754
|
+
if cold_storage_options.get("enabled", False):
|
4755
|
+
if not dedicated_master_enabled:
|
4756
|
+
raise ElasticSearchResourceColdStorageError(
|
4757
|
+
f"[{account}] Cold storage can only be enabled when "
|
4758
|
+
+ "dedicated_master_enabled is set to true for resource"
|
4759
|
+
f" {values['identifier']}"
|
4760
|
+
)
|
4761
|
+
if not warm_enabled:
|
4762
|
+
raise ElasticSearchResourceColdStorageError(
|
4763
|
+
f"[{account}] Cold storage can only be enabled when "
|
4764
|
+
+ "warm_enabled is set to true for resource"
|
4765
|
+
f" {values['identifier']}"
|
4766
|
+
)
|
4767
|
+
cluster_vaules["cold_storage_options"] = {
|
4768
|
+
"enabled": True,
|
4769
|
+
}
|
4770
|
+
|
4284
4771
|
es_values["cluster_config"] = cluster_vaules
|
4285
4772
|
|
4286
4773
|
snapshot_options = values.get("snapshot_options", {})
|
@@ -4358,19 +4845,19 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4358
4845
|
auth_options = values.get("auth", {})
|
4359
4846
|
# TODO: @fishi0x01 make mandatory after migration APPSRE-3409
|
4360
4847
|
if auth_options:
|
4361
|
-
es_values[
|
4362
|
-
|
4363
|
-
|
4848
|
+
es_values["advanced_security_options"] = (
|
4849
|
+
self._build_es_advanced_security_options(auth_options)
|
4850
|
+
)
|
4364
4851
|
|
4365
4852
|
# TODO: @fishi0x01 remove after migration APPSRE-3409
|
4366
4853
|
# ++++++++ START: REMOVE +++++++++
|
4367
4854
|
else:
|
4368
4855
|
advanced_security_options = values.get("advanced_security_options", {})
|
4369
4856
|
if advanced_security_options:
|
4370
|
-
es_values[
|
4371
|
-
|
4372
|
-
|
4373
|
-
|
4857
|
+
es_values["advanced_security_options"] = (
|
4858
|
+
self._build_es_advanced_security_options_deprecated(
|
4859
|
+
advanced_security_options
|
4860
|
+
)
|
4374
4861
|
)
|
4375
4862
|
# ++++++++ END: REMOVE ++++++++++
|
4376
4863
|
|
@@ -4379,33 +4866,33 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4379
4866
|
|
4380
4867
|
# Setup outputs
|
4381
4868
|
# arn
|
4382
|
-
|
4869
|
+
output_name = output_prefix + "__arn"
|
4383
4870
|
output_value = "${" + es_tf_resource.arn + "}"
|
4384
|
-
tf_resources.append(Output(
|
4871
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4385
4872
|
# domain_id
|
4386
|
-
|
4873
|
+
output_name = output_prefix + "__domain_id"
|
4387
4874
|
output_value = "${" + es_tf_resource.domain_id + "}"
|
4388
|
-
tf_resources.append(Output(
|
4875
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4389
4876
|
# domain_name
|
4390
|
-
|
4877
|
+
output_name = output_prefix + "__domain_name"
|
4391
4878
|
output_value = es_tf_resource.domain_name
|
4392
|
-
tf_resources.append(Output(
|
4879
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4393
4880
|
# endpoint
|
4394
|
-
|
4881
|
+
output_name = output_prefix + "__endpoint"
|
4395
4882
|
output_value = "https://" + "${" + es_tf_resource.endpoint + "}"
|
4396
|
-
tf_resources.append(Output(
|
4883
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4397
4884
|
# kibana_endpoint
|
4398
|
-
|
4885
|
+
output_name = output_prefix + "__kibana_endpoint"
|
4399
4886
|
output_value = "https://" + "${" + es_tf_resource.kibana_endpoint + "}"
|
4400
|
-
tf_resources.append(Output(
|
4887
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4401
4888
|
# vpc_id
|
4402
|
-
|
4889
|
+
output_name = output_prefix + "__vpc_id"
|
4403
4890
|
output_value = (
|
4404
4891
|
"${aws_elasticsearch_domain." + identifier + ".vpc_options.0.vpc_id}"
|
4405
4892
|
)
|
4406
|
-
tf_resources.append(Output(
|
4893
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4407
4894
|
# add master user creds to output and secretsmanager if internal_user_database_enabled
|
4408
|
-
security_options = es_values.get("advanced_security_options"
|
4895
|
+
security_options = es_values.get("advanced_security_options")
|
4409
4896
|
if security_options and security_options.get(
|
4410
4897
|
"internal_user_database_enabled", False
|
4411
4898
|
):
|
@@ -4454,20 +4941,20 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4454
4941
|
)
|
4455
4942
|
tf_resources.append(iam_policy_resource)
|
4456
4943
|
|
4457
|
-
|
4944
|
+
output_name = output_prefix + "__secret_name"
|
4458
4945
|
output_value = secret_name
|
4459
|
-
tf_resources.append(Output(
|
4460
|
-
|
4946
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4947
|
+
output_name = output_prefix + "__secret_policy_arn"
|
4461
4948
|
output_value = "${" + iam_policy_resource.arn + "}"
|
4462
|
-
tf_resources.append(Output(
|
4949
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4463
4950
|
# master_user_name
|
4464
|
-
|
4951
|
+
output_name = output_prefix + "__master_user_name"
|
4465
4952
|
output_value = master_user["master_user_name"]
|
4466
|
-
tf_resources.append(Output(
|
4953
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
4467
4954
|
# master_user_password
|
4468
|
-
|
4955
|
+
output_name = output_prefix + "__master_user_password"
|
4469
4956
|
output_value = master_user["master_user_password"]
|
4470
|
-
tf_resources.append(Output(
|
4957
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
4471
4958
|
|
4472
4959
|
self.add_resources(account, tf_resources)
|
4473
4960
|
|
@@ -4545,34 +5032,36 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4545
5032
|
|
4546
5033
|
# outputs
|
4547
5034
|
# arn
|
4548
|
-
|
5035
|
+
output_name = output_prefix + "__arn"
|
4549
5036
|
output_value = "${" + acm_tf_resource.arn + "}"
|
4550
|
-
tf_resources.append(Output(
|
5037
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4551
5038
|
# domain name
|
4552
|
-
#
|
5039
|
+
# output_name = output_prefix + '__domain_name'
|
4553
5040
|
# output_value = '${' + acm_tf_resource.domain_name + '}'
|
4554
|
-
# tf_resources.append(Output(
|
5041
|
+
# tf_resources.append(Output(output_name, value=output_value))
|
4555
5042
|
# status
|
4556
|
-
|
5043
|
+
output_name = output_prefix + "__status"
|
4557
5044
|
output_value = "${" + acm_tf_resource.status + "}"
|
4558
|
-
tf_resources.append(Output(
|
5045
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4559
5046
|
# domain_validation_options
|
4560
|
-
|
5047
|
+
output_name = output_prefix + "__domain_validation_options"
|
4561
5048
|
output_value = "${" + acm_tf_resource.domain_validation_options + "}"
|
4562
|
-
tf_resources.append(Output(
|
5049
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4563
5050
|
if secret is not None:
|
4564
5051
|
# key
|
4565
|
-
|
5052
|
+
output_name = output_prefix + "__key"
|
4566
5053
|
output_value = key
|
4567
|
-
tf_resources.append(Output(
|
5054
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4568
5055
|
# certificate
|
4569
|
-
|
5056
|
+
output_name = output_prefix + "__certificate"
|
4570
5057
|
output_value = certificate
|
4571
|
-
tf_resources.append(Output(
|
5058
|
+
tf_resources.append(Output(output_name, value=output_value, sensitive=True))
|
4572
5059
|
if caCertificate is not None:
|
4573
|
-
|
5060
|
+
output_name = output_prefix + "__caCertificate"
|
4574
5061
|
output_value = caCertificate
|
4575
|
-
tf_resources.append(
|
5062
|
+
tf_resources.append(
|
5063
|
+
Output(output_name, value=output_value, sensitive=True)
|
5064
|
+
)
|
4576
5065
|
|
4577
5066
|
self.add_resources(account, tf_resources)
|
4578
5067
|
|
@@ -4609,17 +5098,17 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4609
5098
|
|
4610
5099
|
# outputs
|
4611
5100
|
# etag
|
4612
|
-
|
5101
|
+
output_name = output_prefix + "_etag"
|
4613
5102
|
output_value = "${" + pk_tf_resource.etag + "}"
|
4614
|
-
tf_resources.append(Output(
|
5103
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4615
5104
|
# id
|
4616
|
-
|
5105
|
+
output_name = output_prefix + "__id"
|
4617
5106
|
output_value = "${" + pk_tf_resource.id + "}"
|
4618
|
-
tf_resources.append(Output(
|
5107
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4619
5108
|
# key
|
4620
|
-
|
5109
|
+
output_name = output_prefix + "__key"
|
4621
5110
|
output_value = key
|
4622
|
-
tf_resources.append(Output(
|
5111
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4623
5112
|
|
4624
5113
|
self.add_resources(account, tf_resources)
|
4625
5114
|
|
@@ -4629,16 +5118,18 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4629
5118
|
account = self.accounts[account_name]
|
4630
5119
|
cluster = namespace_info["cluster"]
|
4631
5120
|
ocm = ocm_map.get(cluster["name"])
|
4632
|
-
account[
|
4633
|
-
|
4634
|
-
|
4635
|
-
|
4636
|
-
|
4637
|
-
|
5121
|
+
account["assume_role"] = (
|
5122
|
+
ocm.get_aws_infrastructure_access_terraform_assume_role(
|
5123
|
+
cluster["name"],
|
5124
|
+
account["uid"],
|
5125
|
+
account["terraformUsername"],
|
5126
|
+
)
|
4638
5127
|
)
|
4639
5128
|
account["assume_region"] = cluster["spec"]["region"]
|
4640
5129
|
service_name = f"{namespace_info['name']}/{openshift_service}"
|
4641
|
-
with AWSApi(
|
5130
|
+
with AWSApi(
|
5131
|
+
1, [account], secret_reader=self.secret_reader, init_users=False
|
5132
|
+
) as awsapi:
|
4642
5133
|
ips = awsapi.get_alb_network_interface_ips(account, service_name)
|
4643
5134
|
if not ips:
|
4644
5135
|
raise ValueError(
|
@@ -4652,7 +5143,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4652
5143
|
def _get_alb_rule_condition_value(condition):
|
4653
5144
|
condition_type = condition["type"]
|
4654
5145
|
condition_type_key = SUPPORTED_ALB_LISTENER_RULE_CONDITION_TYPE_MAPPING.get(
|
4655
|
-
condition_type
|
5146
|
+
condition_type
|
4656
5147
|
)
|
4657
5148
|
if condition_type_key is None:
|
4658
5149
|
raise KeyError(f"unknown alb rule condition type {condition_type}")
|
@@ -4739,7 +5230,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4739
5230
|
tf_resources.append(sg_tf_resource)
|
4740
5231
|
|
4741
5232
|
# https://www.terraform.io/docs/providers/aws/r/lb.html
|
4742
|
-
|
5233
|
+
lb_values = {
|
4743
5234
|
"provider": provider,
|
4744
5235
|
"name": identifier,
|
4745
5236
|
"internal": False,
|
@@ -4753,13 +5244,33 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4753
5244
|
|
4754
5245
|
idle_timeout = resource.get("idle_timeout")
|
4755
5246
|
if idle_timeout:
|
4756
|
-
|
5247
|
+
lb_values["idle_timeout"] = idle_timeout
|
4757
5248
|
|
4758
5249
|
enable_http2 = resource.get("enable_http2")
|
4759
5250
|
if enable_http2 is False:
|
4760
|
-
|
5251
|
+
lb_values["enable_http2"] = False
|
5252
|
+
|
5253
|
+
if resource.get("access_logs"):
|
5254
|
+
# https://www.terraform.io/docs/providers/aws/r/lb.html#access_logs
|
5255
|
+
bucket_identifier = f"{identifier}-lb-access-logs"
|
5256
|
+
lb_access_logs_s3_bucket_values = {
|
5257
|
+
"provider": provider,
|
5258
|
+
"bucket": bucket_identifier,
|
5259
|
+
}
|
5260
|
+
lb_access_logs_s3_bucket_tf_resource = aws_s3_bucket(
|
5261
|
+
bucket_identifier, **lb_access_logs_s3_bucket_values
|
5262
|
+
)
|
5263
|
+
tf_resources.append(lb_access_logs_s3_bucket_tf_resource)
|
4761
5264
|
|
4762
|
-
|
5265
|
+
lb_values["access_logs"] = {
|
5266
|
+
"enabled": True,
|
5267
|
+
"bucket": f"${{{lb_access_logs_s3_bucket_tf_resource.id}}}",
|
5268
|
+
}
|
5269
|
+
lb_values["depends_on"].extend(
|
5270
|
+
self.get_dependencies([lb_access_logs_s3_bucket_tf_resource])
|
5271
|
+
)
|
5272
|
+
|
5273
|
+
lb_tf_resource = aws_lb(identifier, **lb_values)
|
4763
5274
|
tf_resources.append(lb_tf_resource)
|
4764
5275
|
|
4765
5276
|
default_target = None
|
@@ -4768,6 +5279,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4768
5279
|
target_name = t["name"]
|
4769
5280
|
t_openshift_service = t.get("openshift_service")
|
4770
5281
|
t_ips = t.get("ips")
|
5282
|
+
t_protocol = t.get("protocol") or "HTTPS"
|
5283
|
+
t_protocol_version = t.get("protocol_version") or "HTTP1"
|
5284
|
+
|
4771
5285
|
if t_openshift_service:
|
4772
5286
|
target_ips = self._get_alb_target_ips_by_openshift_service(
|
4773
5287
|
identifier, t_openshift_service, account, namespace_info, ocm_map
|
@@ -4798,8 +5312,8 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4798
5312
|
"provider": provider,
|
4799
5313
|
"name": f"{target_name}-${{{lbt_random_id.hex}}}",
|
4800
5314
|
"port": 443,
|
4801
|
-
"protocol":
|
4802
|
-
"protocol_version":
|
5315
|
+
"protocol": t_protocol,
|
5316
|
+
"protocol_version": t_protocol_version,
|
4803
5317
|
"target_type": "ip",
|
4804
5318
|
"vpc_id": vpc_id,
|
4805
5319
|
"health_check": {
|
@@ -4832,7 +5346,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4832
5346
|
"port": 443,
|
4833
5347
|
"depends_on": self.get_dependencies([lbt_tf_resource]),
|
4834
5348
|
}
|
4835
|
-
if
|
5349
|
+
if ip_address(ip) not in ip_network(vpc_cidr_block):
|
4836
5350
|
values["availability_zone"] = "all"
|
4837
5351
|
ip_slug = ip.replace(".", "_")
|
4838
5352
|
lbta_identifier = f"{lbt_identifier}-{ip_slug}"
|
@@ -4864,12 +5378,13 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4864
5378
|
# forward
|
4865
5379
|
if not default_target:
|
4866
5380
|
raise KeyError("expected a single default target")
|
5381
|
+
ssl_policy = resource.get("ssl_policy") or "ELBSecurityPolicy-TLS13-1-0-2021-06"
|
4867
5382
|
values = {
|
4868
5383
|
"provider": provider,
|
4869
5384
|
"load_balancer_arn": f"${{{lb_tf_resource.arn}}}",
|
4870
5385
|
"port": 443,
|
4871
5386
|
"protocol": "HTTPS",
|
4872
|
-
"ssl_policy":
|
5387
|
+
"ssl_policy": ssl_policy,
|
4873
5388
|
"certificate_arn": resource["certificate_arn"],
|
4874
5389
|
"default_action": {
|
4875
5390
|
"type": "forward",
|
@@ -4907,9 +5422,10 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4907
5422
|
|
4908
5423
|
target_resource = valid_targets[target_name]
|
4909
5424
|
|
4910
|
-
action_values["forward"]["target_group"].append(
|
4911
|
-
|
4912
|
-
|
5425
|
+
action_values["forward"]["target_group"].append({
|
5426
|
+
"arn": f"${{{target_resource.arn}}}",
|
5427
|
+
"weight": a["weight"],
|
5428
|
+
})
|
4913
5429
|
weight_sum += a["weight"]
|
4914
5430
|
if weight_sum != 100:
|
4915
5431
|
raise ValueError(
|
@@ -4926,6 +5442,19 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4926
5442
|
"status_code": fr_data.get("status_code"),
|
4927
5443
|
},
|
4928
5444
|
}
|
5445
|
+
elif action_type == "redirect":
|
5446
|
+
redirect_data = action.get("redirect", {})
|
5447
|
+
action_values = {
|
5448
|
+
"type": "redirect",
|
5449
|
+
"redirect": {
|
5450
|
+
"host": redirect_data.get("host"),
|
5451
|
+
"path": redirect_data.get("path"),
|
5452
|
+
"port": redirect_data.get("port"),
|
5453
|
+
"protocol": redirect_data.get("protocol"),
|
5454
|
+
"query": redirect_data.get("query"),
|
5455
|
+
"status_code": redirect_data.get("status_code"),
|
5456
|
+
},
|
5457
|
+
}
|
4929
5458
|
else:
|
4930
5459
|
raise KeyError(f"unknown alb rule action type {action_type}")
|
4931
5460
|
|
@@ -4941,20 +5470,20 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4941
5470
|
"depends_on": self.get_dependencies([forward_lbl_tf_resource]),
|
4942
5471
|
}
|
4943
5472
|
|
4944
|
-
lblr_identifier = f"{identifier}-rule-{rule_num+1:02d}"
|
5473
|
+
lblr_identifier = f"{identifier}-rule-{rule_num + 1:02d}"
|
4945
5474
|
lblr_tf_resource = aws_lb_listener_rule(lblr_identifier, **values)
|
4946
5475
|
|
4947
5476
|
tf_resources.append(lblr_tf_resource)
|
4948
5477
|
|
4949
5478
|
# outputs
|
4950
5479
|
# dns name
|
4951
|
-
|
5480
|
+
output_name = output_prefix + "__dns_name"
|
4952
5481
|
output_value = f"${{{lb_tf_resource.dns_name}}}"
|
4953
|
-
tf_resources.append(Output(
|
5482
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4954
5483
|
# vpc cidr block
|
4955
|
-
|
5484
|
+
output_name = output_prefix + "__vpc_cidr_block"
|
4956
5485
|
output_value = vpc_cidr_block
|
4957
|
-
tf_resources.append(Output(
|
5486
|
+
tf_resources.append(Output(output_name, value=output_value))
|
4958
5487
|
|
4959
5488
|
self.add_resources(account, tf_resources)
|
4960
5489
|
|
@@ -4993,12 +5522,12 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4993
5522
|
tf_resources.append(aws_version_resource)
|
4994
5523
|
|
4995
5524
|
# outputs
|
4996
|
-
|
5525
|
+
output_name = output_prefix + "__arn"
|
4997
5526
|
output_value = "${" + aws_version_resource.arn + "}"
|
4998
|
-
tf_resources.append(Output(
|
4999
|
-
|
5527
|
+
tf_resources.append(Output(output_name, value=output_value))
|
5528
|
+
output_name = output_prefix + "__version_id"
|
5000
5529
|
output_value = "${" + aws_version_resource.version_id + "}"
|
5001
|
-
tf_resources.append(Output(
|
5530
|
+
tf_resources.append(Output(output_name, value=output_value))
|
5002
5531
|
|
5003
5532
|
self.add_resources(account, tf_resources)
|
5004
5533
|
|
@@ -5021,14 +5550,14 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5021
5550
|
if "gitlab" in url:
|
5022
5551
|
gitlab = self.init_gitlab()
|
5023
5552
|
project = gitlab.get_project(url)
|
5024
|
-
commits = project.commits.list(ref_name=ref)
|
5553
|
+
commits = project.commits.list(ref_name=ref, per_page=1, page=1)
|
5025
5554
|
return commits[0].id
|
5026
5555
|
|
5027
5556
|
return ""
|
5028
5557
|
|
5029
5558
|
def get_asg_image_id(
|
5030
5559
|
self, filters: Iterable[Mapping[str, Any]], account: str, region: str
|
5031
|
-
) ->
|
5560
|
+
) -> str | None:
|
5032
5561
|
"""
|
5033
5562
|
AMI ID comes form AWS Api filter result.
|
5034
5563
|
AMI needs to be shared by integration aws-ami-share.
|
@@ -5045,7 +5574,9 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5045
5574
|
|
5046
5575
|
# Get the most recent AMI id
|
5047
5576
|
aws_account = self.accounts[account]
|
5048
|
-
with AWSApi(
|
5577
|
+
with AWSApi(
|
5578
|
+
1, [aws_account], secret_reader=self.secret_reader, init_users=False
|
5579
|
+
) as aws:
|
5049
5580
|
return aws.get_image_id(account, region, tags)
|
5050
5581
|
|
5051
5582
|
def _use_previous_image_id(self, filters: Iterable[Mapping[str, Any]]) -> bool:
|
@@ -5127,23 +5658,19 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5127
5658
|
part = []
|
5128
5659
|
for c in cloudinit_configs:
|
5129
5660
|
raw = self.get_raw_values(c["content"])
|
5130
|
-
content =
|
5131
|
-
body=raw["content"], vars=vars,
|
5661
|
+
content = process_extracurlyjinja2_template(
|
5662
|
+
body=raw["content"], vars=vars, secret_reader=self.secret_reader
|
5132
5663
|
)
|
5133
5664
|
# https://www.terraform.io/docs/language/expressions/strings.html#escape-sequences
|
5134
5665
|
content = content.replace("${", "$${")
|
5135
5666
|
content = content.replace("%{", "%%{")
|
5136
|
-
part.append(
|
5137
|
-
|
5138
|
-
|
5139
|
-
|
5140
|
-
|
5141
|
-
}
|
5142
|
-
)
|
5667
|
+
part.append({
|
5668
|
+
"filename": c.get("filename"),
|
5669
|
+
"content_type": c.get("content_type"),
|
5670
|
+
"content": content,
|
5671
|
+
})
|
5143
5672
|
cloudinit_value = {"gzip": True, "base64_encode": True, "part": part}
|
5144
|
-
cloudinit_data =
|
5145
|
-
identifier, **cloudinit_value
|
5146
|
-
)
|
5673
|
+
cloudinit_data = cloudinit_config(identifier, **cloudinit_value)
|
5147
5674
|
tf_resources.append(cloudinit_data)
|
5148
5675
|
template_values["user_data"] = "${" + cloudinit_data.rendered + "}"
|
5149
5676
|
template_resource = aws_launch_template(identifier, **template_values)
|
@@ -5172,25 +5699,36 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5172
5699
|
"preferences": common_values.get("instance_refresh_preferences"),
|
5173
5700
|
},
|
5174
5701
|
}
|
5702
|
+
|
5703
|
+
override = []
|
5175
5704
|
instance_types = common_values.get("instance_types")
|
5176
5705
|
if instance_types:
|
5177
|
-
override
|
5178
|
-
|
5179
|
-
|
5180
|
-
|
5181
|
-
|
5706
|
+
override += [{"instance_type": i} for i in instance_types]
|
5707
|
+
instance_requirements = common_values.get("instance_requirements")
|
5708
|
+
if instance_requirements:
|
5709
|
+
override += [{"instance_requirements": instance_requirements}]
|
5710
|
+
if override:
|
5711
|
+
asg_value["mixed_instances_policy"]["launch_template"]["override"] = (
|
5712
|
+
override
|
5713
|
+
)
|
5714
|
+
|
5715
|
+
tags = [
|
5182
5716
|
{"key": k, "value": v, "propagate_at_launch": True} for k, v in tags.items()
|
5183
5717
|
]
|
5718
|
+
if self.versions.get(account, "").startswith("3"):
|
5719
|
+
asg_value["tags"] = tags
|
5720
|
+
else:
|
5721
|
+
asg_value["tag"] = tags
|
5184
5722
|
asg_resource = aws_autoscaling_group(identifier, **asg_value)
|
5185
5723
|
tf_resources.append(asg_resource)
|
5186
5724
|
|
5187
5725
|
# outputs
|
5188
|
-
|
5726
|
+
output_name = output_prefix + "__template_latest_version"
|
5189
5727
|
output_value = "${" + template_resource.latest_version + "}"
|
5190
|
-
tf_resources.append(Output(
|
5191
|
-
|
5728
|
+
tf_resources.append(Output(output_name, value=output_value))
|
5729
|
+
output_name = output_prefix + "__image_id"
|
5192
5730
|
output_value = image_id
|
5193
|
-
tf_resources.append(Output(
|
5731
|
+
tf_resources.append(Output(output_name, value=output_value))
|
5194
5732
|
|
5195
5733
|
self.add_resources(account, tf_resources)
|
5196
5734
|
|
@@ -5257,7 +5795,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5257
5795
|
lambda_managed_policy_arn = (
|
5258
5796
|
"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
5259
5797
|
)
|
5260
|
-
if region in
|
5798
|
+
if region in {"us-gov-west-1", "us-gov-east-1"}:
|
5261
5799
|
lambda_managed_policy_arn = "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
|
5262
5800
|
vpc_id = common_values.get("vpc_id")
|
5263
5801
|
subnet_ids = common_values.get("subnet_ids")
|
@@ -5333,8 +5871,8 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5333
5871
|
s3_client.head_bucket(Bucket=bucket_name)
|
5334
5872
|
except ClientError as details:
|
5335
5873
|
raise StateInaccessibleException(
|
5336
|
-
f"Bucket {bucket_name} is not accessible - {
|
5337
|
-
)
|
5874
|
+
f"Bucket {bucket_name} is not accessible - {details!s}"
|
5875
|
+
) from None
|
5338
5876
|
|
5339
5877
|
# todo: probably remove 'RedHat' from the object/variable/filepath
|
5340
5878
|
# names to keep the code RedHat-agnostic?
|
@@ -5352,8 +5890,8 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5352
5890
|
f"from s3 bucket {bucket_name} to local filepath {redhat_logo_png_filepath},"
|
5353
5891
|
f" but no file exists locally at this path!"
|
5354
5892
|
)
|
5355
|
-
file_type =
|
5356
|
-
if file_type != "png":
|
5893
|
+
file_type = filetype.guess(redhat_logo_png_filepath)
|
5894
|
+
if file_type.extension != "png":
|
5357
5895
|
raise Exception(
|
5358
5896
|
f"Attempted to download object {redhat_logo_png_obj_name} "
|
5359
5897
|
f"from s3 bucket {bucket_name} to local filepath {redhat_logo_png_filepath}."
|
@@ -5650,7 +6188,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5650
6188
|
api_gateway_vpc_link_resource = aws_api_gateway_vpc_link(
|
5651
6189
|
"vpc_link",
|
5652
6190
|
name=f"{identifier}-vpc-link",
|
5653
|
-
target_arns=[openshift_ingress_load_balancer_arn]
|
6191
|
+
target_arns=[openshift_ingress_load_balancer_arn],
|
5654
6192
|
# future: use data source to get vpc arn by annotation
|
5655
6193
|
)
|
5656
6194
|
tf_resources.append(api_gateway_vpc_link_resource)
|
@@ -5877,26 +6415,24 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5877
6415
|
)
|
5878
6416
|
tf_resources.append(api_gateway_stage_resource)
|
5879
6417
|
|
5880
|
-
rest_api_policy = json.dumps(
|
5881
|
-
|
5882
|
-
|
5883
|
-
|
5884
|
-
|
5885
|
-
|
5886
|
-
|
5887
|
-
|
5888
|
-
|
5889
|
-
|
5890
|
-
|
5891
|
-
|
5892
|
-
|
5893
|
-
|
5894
|
-
|
5895
|
-
|
5896
|
-
|
5897
|
-
|
5898
|
-
}
|
5899
|
-
)
|
6418
|
+
rest_api_policy = json.dumps({
|
6419
|
+
"Version": "2012-10-17",
|
6420
|
+
"Statement": [
|
6421
|
+
{
|
6422
|
+
"Effect": "Allow",
|
6423
|
+
"Principal": "*",
|
6424
|
+
"Action": "execute-api:Invoke",
|
6425
|
+
"Resource": "${aws_api_gateway_rest_api.gw_api.execution_arn}/*",
|
6426
|
+
},
|
6427
|
+
{
|
6428
|
+
"Effect": "Deny",
|
6429
|
+
"Principal": "*",
|
6430
|
+
"Action": "execute-api:Invoke",
|
6431
|
+
"Resource": "${aws_api_gateway_rest_api.gw_api.execution_arn}/*",
|
6432
|
+
"Condition": {"StringNotEquals": {"aws:SourceVpce": vpce_id}},
|
6433
|
+
},
|
6434
|
+
],
|
6435
|
+
})
|
5900
6436
|
|
5901
6437
|
# REST API POLICY
|
5902
6438
|
api_gateway_rest_api_policy_resource = aws_api_gateway_rest_api_policy(
|
@@ -5965,6 +6501,7 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
5965
6501
|
"${aws_cloudwatch_log_group.waf_log_group.arn}"
|
5966
6502
|
],
|
5967
6503
|
resource_arn="${aws_wafv2_web_acl.api_waf.arn}",
|
6504
|
+
redacted_fields={"single_header": {"name": "authorization"}},
|
5968
6505
|
)
|
5969
6506
|
)
|
5970
6507
|
|
@@ -6120,3 +6657,218 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
6120
6657
|
tf_resources.append(aws_vpc_endpoint_subnet_association_resource)
|
6121
6658
|
|
6122
6659
|
self.add_resources(account, tf_resources)
|
6660
|
+
|
6661
|
+
def populate_tf_resource_msk(self, spec):
|
6662
|
+
account = spec.provisioner_name
|
6663
|
+
values = self.init_values(spec)
|
6664
|
+
output_prefix = spec.output_prefix
|
6665
|
+
tf_resources = []
|
6666
|
+
resource_id = spec.identifier
|
6667
|
+
|
6668
|
+
del values["identifier"]
|
6669
|
+
values.setdefault("cluster_name", spec.identifier)
|
6670
|
+
|
6671
|
+
# common
|
6672
|
+
self.init_common_outputs(tf_resources, spec)
|
6673
|
+
|
6674
|
+
# validations
|
6675
|
+
if (
|
6676
|
+
values["number_of_broker_nodes"]
|
6677
|
+
% len(values["broker_node_group_info"]["client_subnets"])
|
6678
|
+
!= 0
|
6679
|
+
):
|
6680
|
+
raise ValueError(
|
6681
|
+
"number_of_broker_nodes must be a multiple of the number of specified client subnets."
|
6682
|
+
)
|
6683
|
+
|
6684
|
+
scram_enabled = (
|
6685
|
+
values.get("client_authentication", {}).get("sasl", {}).get("scram", False)
|
6686
|
+
)
|
6687
|
+
scram_users = {}
|
6688
|
+
if scram_enabled:
|
6689
|
+
if not spec.resource.get("users", []):
|
6690
|
+
raise ValueError(
|
6691
|
+
"users attribute must be given when client_authentication.sasl.scram is enabled."
|
6692
|
+
)
|
6693
|
+
scram_users = {
|
6694
|
+
user["name"]: self.secret_reader.read_all(user["secret"])
|
6695
|
+
for user in spec.resource["users"]
|
6696
|
+
}
|
6697
|
+
# validate user objects
|
6698
|
+
for user, secret in scram_users.items():
|
6699
|
+
if secret.keys() != {"password", "username"}:
|
6700
|
+
raise ValueError(
|
6701
|
+
f"MSK user '{user}' secret must contain only 'username' and 'password' keys!"
|
6702
|
+
)
|
6703
|
+
|
6704
|
+
# resource - msk config
|
6705
|
+
# unique msk config resource name enables "create_before_destroy" lifecycle
|
6706
|
+
# which is required when changing version which requires a resource replacement
|
6707
|
+
msk_version_str = values["kafka_version"].replace(".", "-")
|
6708
|
+
msk_config_name = f"{resource_id}-{msk_version_str}"
|
6709
|
+
msk_config = aws_msk_configuration(
|
6710
|
+
msk_config_name,
|
6711
|
+
name=msk_config_name,
|
6712
|
+
kafka_versions=[values["kafka_version"]],
|
6713
|
+
server_properties=values["server_properties"],
|
6714
|
+
# lifecycle create_before_destroy is required to ensure that the config is created
|
6715
|
+
# before it is assigned to the cluster
|
6716
|
+
lifecycle={
|
6717
|
+
"create_before_destroy": True,
|
6718
|
+
},
|
6719
|
+
)
|
6720
|
+
tf_resources.append(msk_config)
|
6721
|
+
values.pop("server_properties", None)
|
6722
|
+
|
6723
|
+
# resource - cluster
|
6724
|
+
values["configuration_info"] = {
|
6725
|
+
"arn": "${" + msk_config.arn + "}",
|
6726
|
+
"revision": "${" + msk_config.latest_revision + "}",
|
6727
|
+
}
|
6728
|
+
msk_cluster = aws_msk_cluster(resource_id, **values)
|
6729
|
+
tf_resources.append(msk_cluster)
|
6730
|
+
|
6731
|
+
# resource - cloudwatch
|
6732
|
+
if (
|
6733
|
+
values.get("logging_info", {})
|
6734
|
+
.get("broker_logs", {})
|
6735
|
+
.get("cloudwatch_logs", {})
|
6736
|
+
.get("enabled", False)
|
6737
|
+
):
|
6738
|
+
log_group_values = {
|
6739
|
+
"name": f"{resource_id}-msk-broker-logs",
|
6740
|
+
"tags": values["tags"],
|
6741
|
+
"retention_in_days": values["logging_info"]["broker_logs"][
|
6742
|
+
"cloudwatch_logs"
|
6743
|
+
]["retention_in_days"],
|
6744
|
+
}
|
6745
|
+
log_group_tf_resource = aws_cloudwatch_log_group(
|
6746
|
+
resource_id, **log_group_values
|
6747
|
+
)
|
6748
|
+
tf_resources.append(log_group_tf_resource)
|
6749
|
+
del values["logging_info"]["broker_logs"]["cloudwatch_logs"][
|
6750
|
+
"retention_in_days"
|
6751
|
+
]
|
6752
|
+
values["logging_info"]["broker_logs"]["cloudwatch_logs"]["log_group"] = (
|
6753
|
+
log_group_tf_resource.name
|
6754
|
+
)
|
6755
|
+
|
6756
|
+
# resource - secret manager for SCRAM client credentials
|
6757
|
+
if scram_enabled and scram_users:
|
6758
|
+
scram_secrets: list[
|
6759
|
+
tuple[aws_secretsmanager_secret, aws_secretsmanager_secret_version]
|
6760
|
+
] = []
|
6761
|
+
|
6762
|
+
# kms
|
6763
|
+
kms_values = {
|
6764
|
+
"description": "KMS key for MSK SCRAM credentials",
|
6765
|
+
"tags": values["tags"],
|
6766
|
+
}
|
6767
|
+
kms_key = aws_kms_key(resource_id, **kms_values)
|
6768
|
+
tf_resources.append(kms_key)
|
6769
|
+
|
6770
|
+
kms_key_alias = aws_kms_alias(
|
6771
|
+
resource_id,
|
6772
|
+
name=f"alias/{resource_id}-msk-scram",
|
6773
|
+
target_key_id="${" + kms_key.arn + "}",
|
6774
|
+
)
|
6775
|
+
tf_resources.append(kms_key_alias)
|
6776
|
+
|
6777
|
+
for user, secret in scram_users.items():
|
6778
|
+
secret_identifier = f"AmazonMSK_{resource_id}-{user}"
|
6779
|
+
|
6780
|
+
secret_values = {
|
6781
|
+
"name": secret_identifier,
|
6782
|
+
"tags": values["tags"],
|
6783
|
+
"kms_key_id": "${" + kms_key.arn + "}",
|
6784
|
+
}
|
6785
|
+
secret_resource = aws_secretsmanager_secret(
|
6786
|
+
secret_identifier, **secret_values
|
6787
|
+
)
|
6788
|
+
tf_resources.append(secret_resource)
|
6789
|
+
|
6790
|
+
version_values = {
|
6791
|
+
"secret_id": "${" + secret_resource.arn + "}",
|
6792
|
+
"secret_string": json.dumps(secret, sort_keys=True),
|
6793
|
+
}
|
6794
|
+
version_resource = aws_secretsmanager_secret_version(
|
6795
|
+
secret_identifier, **version_values
|
6796
|
+
)
|
6797
|
+
tf_resources.append(version_resource)
|
6798
|
+
|
6799
|
+
secret_policy_values = {
|
6800
|
+
"secret_arn": "${" + secret_resource.arn + "}",
|
6801
|
+
"policy": json.dumps({
|
6802
|
+
"Version": "2012-10-17",
|
6803
|
+
"Statement": [
|
6804
|
+
{
|
6805
|
+
"Sid": "AWSKafkaResourcePolicy",
|
6806
|
+
"Effect": "Allow",
|
6807
|
+
"Principal": {"Service": "kafka.amazonaws.com"},
|
6808
|
+
"Action": "secretsmanager:getSecretValue",
|
6809
|
+
"Resource": "${" + secret_resource.arn + "}",
|
6810
|
+
}
|
6811
|
+
],
|
6812
|
+
}),
|
6813
|
+
}
|
6814
|
+
secret_policy = aws_secretsmanager_secret_policy(
|
6815
|
+
secret_identifier, **secret_policy_values
|
6816
|
+
)
|
6817
|
+
tf_resources.append(secret_policy)
|
6818
|
+
scram_secrets.append((secret_resource, version_resource))
|
6819
|
+
|
6820
|
+
# create ONE scram secret association for each secret created above
|
6821
|
+
scram_secret_association_values = {
|
6822
|
+
"cluster_arn": "${" + msk_cluster.arn + "}",
|
6823
|
+
"secret_arn_list": ["${" + s.arn + "}" for s, _ in scram_secrets],
|
6824
|
+
"depends_on": self.get_dependencies([v for _, v in scram_secrets]),
|
6825
|
+
}
|
6826
|
+
scram_secret_association = aws_msk_scram_secret_association(
|
6827
|
+
resource_id, **scram_secret_association_values
|
6828
|
+
)
|
6829
|
+
tf_resources.append(scram_secret_association)
|
6830
|
+
|
6831
|
+
# outputs
|
6832
|
+
tf_resources.append(
|
6833
|
+
Output(
|
6834
|
+
output_prefix + "__zookeeper_connect_string",
|
6835
|
+
value="${" + msk_cluster.zookeeper_connect_string + "}",
|
6836
|
+
)
|
6837
|
+
)
|
6838
|
+
tf_resources.append(
|
6839
|
+
Output(
|
6840
|
+
output_prefix + "__zookeeper_connect_string_tls",
|
6841
|
+
value="${" + msk_cluster.zookeeper_connect_string_tls + "}",
|
6842
|
+
)
|
6843
|
+
)
|
6844
|
+
tf_resources.append(
|
6845
|
+
Output(
|
6846
|
+
output_prefix + "__bootstrap_brokers",
|
6847
|
+
value="${" + msk_cluster.bootstrap_brokers + "}",
|
6848
|
+
)
|
6849
|
+
)
|
6850
|
+
tf_resources.append(
|
6851
|
+
Output(
|
6852
|
+
output_prefix + "__bootstrap_brokers_tls",
|
6853
|
+
value="${" + msk_cluster.bootstrap_brokers_tls + "}",
|
6854
|
+
)
|
6855
|
+
)
|
6856
|
+
tf_resources.append(
|
6857
|
+
Output(
|
6858
|
+
output_prefix + "__bootstrap_brokers_sasl_iam",
|
6859
|
+
value="${" + msk_cluster.bootstrap_brokers_sasl_iam + "}",
|
6860
|
+
)
|
6861
|
+
)
|
6862
|
+
tf_resources.append(
|
6863
|
+
Output(
|
6864
|
+
output_prefix + "__bootstrap_brokers_sasl_scram",
|
6865
|
+
value="${" + msk_cluster.bootstrap_brokers_sasl_scram + "}",
|
6866
|
+
)
|
6867
|
+
)
|
6868
|
+
self.add_resources(account, tf_resources)
|
6869
|
+
|
6870
|
+
def populate_saml_idp(self, account_name: str, name: str, metadata: str) -> None:
|
6871
|
+
saml_idp = aws_iam_saml_provider(
|
6872
|
+
f"{account_name}-{name}", name=name, saml_metadata_document=metadata
|
6873
|
+
)
|
6874
|
+
self.add_resource(account_name, saml_idp)
|