qontract-reconcile 0.10.2.dev299__py3-none-any.whl → 0.10.2.dev430__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/METADATA +13 -12
- {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/RECORD +399 -394
- reconcile/acs_rbac.py +2 -2
- reconcile/aus/advanced_upgrade_service.py +18 -12
- reconcile/aus/base.py +134 -32
- reconcile/aus/cluster_version_data.py +15 -5
- reconcile/aus/models.py +3 -1
- reconcile/aus/ocm_addons_upgrade_scheduler_org.py +1 -0
- reconcile/aus/ocm_upgrade_scheduler.py +8 -1
- reconcile/aus/ocm_upgrade_scheduler_org.py +20 -5
- reconcile/aus/version_gates/sts_version_gate_handler.py +54 -1
- reconcile/automated_actions/config/integration.py +16 -4
- reconcile/aws_account_manager/integration.py +8 -8
- reconcile/aws_account_manager/reconciler.py +3 -3
- reconcile/aws_ami_cleanup/integration.py +8 -12
- reconcile/aws_ami_share.py +69 -62
- reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
- reconcile/aws_ecr_image_pull_secrets.py +4 -4
- reconcile/aws_iam_keys.py +1 -0
- reconcile/aws_saml_idp/integration.py +12 -4
- reconcile/aws_saml_roles/integration.py +32 -25
- reconcile/aws_version_sync/integration.py +125 -84
- reconcile/change_owners/bundle.py +3 -3
- reconcile/change_owners/change_log_tracking.py +3 -2
- reconcile/change_owners/change_owners.py +1 -1
- reconcile/change_owners/diff.py +2 -4
- reconcile/checkpoint.py +12 -4
- reconcile/cli.py +111 -18
- reconcile/cluster_deployment_mapper.py +2 -3
- reconcile/dashdotdb_dora.py +5 -12
- reconcile/dashdotdb_slo.py +1 -1
- reconcile/database_access_manager.py +125 -121
- reconcile/deadmanssnitch.py +1 -5
- reconcile/dynatrace_token_provider/integration.py +1 -1
- reconcile/endpoints_discovery/integration.py +4 -1
- reconcile/endpoints_discovery/merge_request.py +1 -1
- reconcile/endpoints_discovery/merge_request_manager.py +9 -11
- reconcile/external_resources/factories.py +5 -12
- reconcile/external_resources/integration.py +1 -1
- reconcile/external_resources/manager.py +8 -5
- reconcile/external_resources/meta.py +0 -1
- reconcile/external_resources/metrics.py +1 -1
- reconcile/external_resources/model.py +20 -20
- reconcile/external_resources/reconciler.py +7 -4
- reconcile/external_resources/secrets_sync.py +8 -11
- reconcile/external_resources/state.py +26 -16
- reconcile/fleet_labeler/integration.py +1 -1
- reconcile/gabi_authorized_users.py +8 -5
- reconcile/gcp_image_mirror.py +2 -2
- reconcile/github_org.py +1 -1
- reconcile/github_owners.py +4 -0
- reconcile/gitlab_housekeeping.py +13 -15
- reconcile/gitlab_members.py +6 -12
- reconcile/gitlab_mr_sqs_consumer.py +2 -2
- reconcile/gitlab_owners.py +15 -11
- reconcile/gitlab_permissions.py +8 -12
- reconcile/glitchtip_project_alerts/integration.py +3 -1
- reconcile/gql_definitions/acs/acs_instances.py +10 -10
- reconcile/gql_definitions/acs/acs_policies.py +5 -5
- reconcile/gql_definitions/acs/acs_rbac.py +6 -6
- reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +32 -32
- reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +26 -26
- reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +6 -7
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
- reconcile/gql_definitions/automated_actions/instance.py +51 -12
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +11 -11
- reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +20 -10
- reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +28 -68
- reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +20 -10
- reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +20 -10
- reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
- reconcile/gql_definitions/aws_version_sync/clusters.py +10 -10
- reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
- reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
- reconcile/gql_definitions/change_owners/queries/self_service_roles.py +9 -9
- reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +18 -18
- reconcile/gql_definitions/common/alerting_services_settings.py +9 -9
- reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
- reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
- reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_roles.py +120 -0
- reconcile/gql_definitions/common/app_interface_state_settings.py +10 -10
- reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
- reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
- reconcile/gql_definitions/common/apps.py +5 -5
- reconcile/gql_definitions/common/aws_vpc_requests.py +23 -10
- reconcile/gql_definitions/common/aws_vpcs.py +11 -11
- reconcile/gql_definitions/common/clusters.py +37 -35
- reconcile/gql_definitions/common/clusters_minimal.py +14 -14
- reconcile/gql_definitions/common/clusters_with_dms.py +6 -6
- reconcile/gql_definitions/common/clusters_with_peering.py +29 -30
- reconcile/gql_definitions/common/github_orgs.py +10 -10
- reconcile/gql_definitions/common/jira_settings.py +10 -10
- reconcile/gql_definitions/common/jiralert_settings.py +5 -5
- reconcile/gql_definitions/common/ldap_settings.py +5 -5
- reconcile/gql_definitions/common/namespaces.py +42 -44
- reconcile/gql_definitions/common/namespaces_minimal.py +15 -13
- reconcile/gql_definitions/common/ocm_env_telemeter.py +12 -12
- reconcile/gql_definitions/common/ocm_environments.py +19 -19
- reconcile/gql_definitions/common/pagerduty_instances.py +9 -9
- reconcile/gql_definitions/common/pgp_reencryption_settings.py +6 -6
- reconcile/gql_definitions/common/pipeline_providers.py +29 -29
- reconcile/gql_definitions/common/quay_instances.py +5 -5
- reconcile/gql_definitions/common/quay_orgs.py +5 -5
- reconcile/gql_definitions/common/reserved_networks.py +5 -5
- reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
- reconcile/gql_definitions/common/saas_files.py +44 -44
- reconcile/gql_definitions/common/saas_target_namespaces.py +10 -10
- reconcile/gql_definitions/common/saasherder_settings.py +5 -5
- reconcile/gql_definitions/common/slack_workspaces.py +5 -5
- reconcile/gql_definitions/common/smtp_client_settings.py +19 -19
- reconcile/gql_definitions/common/state_aws_account.py +7 -8
- reconcile/gql_definitions/common/users.py +5 -5
- reconcile/gql_definitions/common/users_with_paths.py +5 -5
- reconcile/gql_definitions/cost_report/app_names.py +5 -5
- reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
- reconcile/gql_definitions/cost_report/settings.py +9 -9
- reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +43 -43
- reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +10 -10
- reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
- reconcile/gql_definitions/email_sender/apps.py +5 -5
- reconcile/gql_definitions/email_sender/emails.py +8 -8
- reconcile/gql_definitions/email_sender/users.py +6 -6
- reconcile/gql_definitions/endpoints_discovery/apps.py +10 -10
- reconcile/gql_definitions/external_resources/aws_accounts.py +9 -9
- reconcile/gql_definitions/external_resources/external_resources_modules.py +23 -23
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +492 -410
- reconcile/gql_definitions/external_resources/external_resources_settings.py +28 -26
- reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
- reconcile/gql_definitions/fleet_labeler/fleet_labels.py +40 -40
- reconcile/gql_definitions/fragments/aus_organization.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
- reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
- reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
- reconcile/gql_definitions/fragments/{aws_vpc_request_subnet.py → aws_organization.py} +12 -8
- reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
- reconcile/gql_definitions/fragments/aws_vpc_request.py +10 -5
- reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
- reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
- reconcile/gql_definitions/fragments/disable.py +5 -5
- reconcile/gql_definitions/fragments/email_service.py +5 -5
- reconcile/gql_definitions/fragments/email_user.py +5 -5
- reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
- reconcile/gql_definitions/fragments/membership_source.py +5 -5
- reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
- reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
- reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
- reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
- reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
- reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_values.py +5 -5
- reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
- reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
- reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
- reconcile/gql_definitions/fragments/terraform_state.py +5 -5
- reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
- reconcile/gql_definitions/fragments/user.py +5 -5
- reconcile/gql_definitions/fragments/vault_secret.py +5 -5
- reconcile/gql_definitions/gcp/gcp_docker_repos.py +9 -9
- reconcile/gql_definitions/gcp/gcp_projects.py +9 -9
- reconcile/gql_definitions/gitlab_members/gitlab_instances.py +9 -9
- reconcile/gql_definitions/gitlab_members/permissions.py +9 -9
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +9 -9
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +11 -11
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +9 -9
- reconcile/gql_definitions/integrations/integrations.py +48 -51
- reconcile/gql_definitions/introspection.json +3050 -1393
- reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +11 -11
- reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +10 -10
- reconcile/gql_definitions/jira/jira_servers.py +5 -5
- reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +14 -10
- reconcile/gql_definitions/jumphosts/jumphosts.py +13 -13
- reconcile/gql_definitions/ldap_groups/roles.py +5 -5
- reconcile/gql_definitions/ldap_groups/settings.py +9 -9
- reconcile/gql_definitions/maintenance/maintenances.py +5 -5
- reconcile/gql_definitions/membershipsources/roles.py +5 -5
- reconcile/gql_definitions/ocm_labels/clusters.py +18 -19
- reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
- reconcile/gql_definitions/openshift_cluster_bots/clusters.py +22 -22
- reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_roles.py +6 -6
- reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +10 -10
- reconcile/gql_definitions/quay_membership/quay_membership.py +6 -6
- reconcile/gql_definitions/rhcs/certs.py +33 -87
- reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
- reconcile/gql_definitions/rhidp/organizations.py +18 -18
- reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
- reconcile/gql_definitions/service_dependencies/service_dependencies.py +8 -8
- reconcile/gql_definitions/sharding/aws_accounts.py +10 -10
- reconcile/gql_definitions/sharding/ocm_organization.py +8 -8
- reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
- reconcile/gql_definitions/skupper_network/skupper_networks.py +10 -10
- reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
- reconcile/gql_definitions/slack_usergroups/permissions.py +9 -9
- reconcile/gql_definitions/slack_usergroups/users.py +5 -5
- reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
- reconcile/gql_definitions/status_board/status_board.py +6 -7
- reconcile/gql_definitions/statuspage/statuspages.py +9 -9
- reconcile/gql_definitions/templating/template_collection.py +5 -5
- reconcile/gql_definitions/templating/templates.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +6 -6
- reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +11 -11
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +11 -11
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +20 -25
- reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +6 -6
- reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +12 -12
- reconcile/gql_definitions/terraform_init/aws_accounts.py +23 -9
- reconcile/gql_definitions/terraform_repo/terraform_repo.py +9 -9
- reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +448 -402
- reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +23 -17
- reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +9 -9
- reconcile/gql_definitions/vault_instances/vault_instances.py +61 -61
- reconcile/gql_definitions/vault_policies/vault_policies.py +11 -11
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +8 -8
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
- reconcile/integrations_manager.py +3 -3
- reconcile/jenkins_job_builder.py +1 -1
- reconcile/jenkins_worker_fleets.py +80 -11
- reconcile/jira_permissions_validator.py +237 -122
- reconcile/ldap_groups/integration.py +1 -1
- reconcile/ocm/types.py +35 -56
- reconcile/ocm_aws_infrastructure_access.py +1 -1
- reconcile/ocm_clusters.py +4 -4
- reconcile/ocm_labels/integration.py +3 -2
- reconcile/ocm_machine_pools.py +33 -27
- reconcile/openshift_base.py +122 -10
- reconcile/openshift_cluster_bots.py +5 -5
- reconcile/openshift_groups.py +5 -0
- reconcile/openshift_limitranges.py +1 -1
- reconcile/openshift_namespace_labels.py +1 -1
- reconcile/openshift_namespaces.py +97 -101
- reconcile/openshift_resources_base.py +10 -5
- reconcile/openshift_rhcs_certs.py +77 -40
- reconcile/openshift_rolebindings.py +230 -130
- reconcile/openshift_saas_deploy.py +6 -7
- reconcile/openshift_saas_deploy_change_tester.py +9 -7
- reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
- reconcile/openshift_serviceaccount_tokens.py +8 -7
- reconcile/openshift_tekton_resources.py +1 -1
- reconcile/openshift_upgrade_watcher.py +4 -4
- reconcile/openshift_users.py +5 -3
- reconcile/oum/labelset.py +5 -3
- reconcile/oum/models.py +1 -4
- reconcile/oum/providers.py +1 -1
- reconcile/prometheus_rules_tester/integration.py +4 -4
- reconcile/quay_mirror.py +1 -1
- reconcile/queries.py +131 -0
- reconcile/requests_sender.py +8 -3
- reconcile/resource_scraper.py +1 -5
- reconcile/rhidp/common.py +5 -5
- reconcile/rhidp/sso_client/base.py +19 -10
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
- reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
- reconcile/sendgrid_teammates.py +20 -9
- reconcile/skupper_network/integration.py +2 -2
- reconcile/slack_usergroups.py +35 -14
- reconcile/sql_query.py +1 -0
- reconcile/status.py +2 -2
- reconcile/status_board.py +6 -6
- reconcile/statuspage/atlassian.py +7 -7
- reconcile/statuspage/integrations/maintenances.py +4 -3
- reconcile/statuspage/page.py +4 -9
- reconcile/statuspage/status.py +5 -8
- reconcile/templates/rosa-classic-cluster-creation.sh.j2 +4 -0
- reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +3 -0
- reconcile/templating/lib/merge_request_manager.py +2 -2
- reconcile/templating/lib/rendering.py +3 -3
- reconcile/templating/renderer.py +12 -13
- reconcile/terraform_aws_route53.py +18 -8
- reconcile/terraform_cloudflare_dns.py +3 -3
- reconcile/terraform_cloudflare_resources.py +12 -13
- reconcile/terraform_cloudflare_users.py +3 -2
- reconcile/terraform_init/integration.py +187 -23
- reconcile/terraform_repo.py +16 -12
- reconcile/terraform_resources.py +18 -10
- reconcile/terraform_tgw_attachments.py +27 -19
- reconcile/terraform_users.py +29 -21
- reconcile/terraform_vpc_peerings.py +16 -4
- reconcile/terraform_vpc_resources/integration.py +32 -2
- reconcile/typed_queries/app_interface_roles.py +10 -0
- reconcile/typed_queries/aws_account_tags.py +41 -0
- reconcile/typed_queries/cost_report/app_names.py +1 -1
- reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
- reconcile/typed_queries/saas_files.py +13 -13
- reconcile/typed_queries/status_board.py +2 -2
- reconcile/unleash_feature_toggles/integration.py +4 -2
- reconcile/utils/acs/base.py +6 -3
- reconcile/utils/acs/policies.py +2 -2
- reconcile/utils/aggregated_list.py +4 -3
- reconcile/utils/aws_api.py +51 -20
- reconcile/utils/aws_api_typed/api.py +38 -9
- reconcile/utils/aws_api_typed/cloudformation.py +149 -0
- reconcile/utils/aws_api_typed/logs.py +73 -0
- reconcile/utils/aws_api_typed/organization.py +4 -2
- reconcile/utils/binary.py +7 -12
- reconcile/utils/datetime_util.py +67 -0
- reconcile/utils/deadmanssnitch_api.py +1 -1
- reconcile/utils/differ.py +2 -3
- reconcile/utils/early_exit_cache.py +11 -12
- reconcile/utils/expiration.py +7 -3
- reconcile/utils/external_resource_spec.py +24 -1
- reconcile/utils/filtering.py +1 -1
- reconcile/utils/gitlab_api.py +7 -5
- reconcile/utils/glitchtip/client.py +6 -2
- reconcile/utils/glitchtip/models.py +25 -28
- reconcile/utils/gpg.py +5 -3
- reconcile/utils/gql.py +4 -7
- reconcile/utils/helm.py +2 -1
- reconcile/utils/helpers.py +1 -1
- reconcile/utils/imap_client.py +1 -1
- reconcile/utils/instrumented_wrappers.py +1 -1
- reconcile/utils/internal_groups/client.py +2 -2
- reconcile/utils/internal_groups/models.py +8 -17
- reconcile/utils/jenkins_api.py +24 -1
- reconcile/utils/jinja2/utils.py +6 -8
- reconcile/utils/jira_client.py +82 -63
- reconcile/utils/jjb_client.py +59 -43
- reconcile/utils/jobcontroller/controller.py +2 -2
- reconcile/utils/jobcontroller/models.py +17 -1
- reconcile/utils/json.py +74 -0
- reconcile/utils/ldap_client.py +4 -3
- reconcile/utils/lean_terraform_client.py +3 -1
- reconcile/utils/membershipsources/app_interface_resolver.py +4 -2
- reconcile/utils/membershipsources/models.py +16 -23
- reconcile/utils/membershipsources/resolver.py +4 -2
- reconcile/utils/merge_request_manager/merge_request_manager.py +4 -4
- reconcile/utils/merge_request_manager/parser.py +6 -6
- reconcile/utils/metrics.py +5 -5
- reconcile/utils/models.py +304 -82
- reconcile/utils/mr/__init__.py +3 -1
- reconcile/utils/mr/app_interface_reporter.py +6 -3
- reconcile/utils/mr/aws_access.py +1 -1
- reconcile/utils/mr/base.py +7 -13
- reconcile/utils/mr/clusters_updates.py +4 -2
- reconcile/utils/mr/notificator.py +3 -3
- reconcile/utils/mr/ocm_upgrade_scheduler_org_updates.py +4 -1
- reconcile/utils/mr/promote_qontract.py +28 -12
- reconcile/utils/mr/update_access_report_base.py +3 -4
- reconcile/utils/mr/user_maintenance.py +7 -6
- reconcile/utils/oc.py +445 -336
- reconcile/utils/oc_filters.py +3 -3
- reconcile/utils/ocm/addons.py +0 -1
- reconcile/utils/ocm/base.py +27 -20
- reconcile/utils/ocm/cluster_groups.py +1 -1
- reconcile/utils/ocm/identity_providers.py +2 -2
- reconcile/utils/ocm/labels.py +1 -1
- reconcile/utils/ocm/ocm.py +81 -71
- reconcile/utils/ocm/products.py +9 -3
- reconcile/utils/ocm/search_filters.py +3 -6
- reconcile/utils/ocm/service_log.py +4 -6
- reconcile/utils/ocm/sre_capability_labels.py +20 -13
- reconcile/utils/ocm_base_client.py +4 -4
- reconcile/utils/openshift_resource.py +83 -52
- reconcile/utils/openssl.py +2 -2
- reconcile/utils/output.py +3 -2
- reconcile/utils/pagerduty_api.py +10 -7
- reconcile/utils/promotion_state.py +6 -11
- reconcile/utils/raw_github_api.py +11 -8
- reconcile/utils/repo_owners.py +21 -29
- reconcile/utils/rhcsv2_certs.py +138 -35
- reconcile/utils/rosa/session.py +16 -0
- reconcile/utils/runtime/integration.py +2 -3
- reconcile/utils/runtime/meta.py +2 -1
- reconcile/utils/runtime/runner.py +2 -2
- reconcile/utils/saasherder/interfaces.py +13 -20
- reconcile/utils/saasherder/models.py +25 -21
- reconcile/utils/saasherder/saasherder.py +60 -32
- reconcile/utils/secret_reader.py +6 -6
- reconcile/utils/sharding.py +1 -1
- reconcile/utils/slack_api.py +26 -4
- reconcile/utils/sloth.py +224 -0
- reconcile/utils/sqs_gateway.py +16 -11
- reconcile/utils/state.py +2 -1
- reconcile/utils/structs.py +4 -4
- reconcile/utils/terraform_client.py +32 -29
- reconcile/utils/terrascript_aws_client.py +658 -480
- reconcile/utils/three_way_diff_strategy.py +1 -1
- reconcile/utils/throughput.py +1 -1
- reconcile/utils/unleash/server.py +2 -8
- reconcile/utils/vault.py +44 -41
- reconcile/utils/vcs.py +8 -8
- reconcile/vault_replication.py +119 -58
- reconcile/vpc_peerings_validator.py +2 -2
- tools/app_interface_reporter.py +4 -4
- tools/cli_commands/cost_report/cost_management_api.py +3 -3
- tools/cli_commands/cost_report/view.py +7 -6
- tools/cli_commands/erv2.py +1 -1
- tools/cli_commands/gpg_encrypt.py +4 -1
- tools/cli_commands/systems_and_tools.py +5 -1
- tools/qontract_cli.py +36 -21
- tools/sre_checkpoints/util.py +5 -3
- tools/template_validation.py +3 -1
- reconcile/gql_definitions/ocm_oidc_idp/__init__.py +0 -0
- reconcile/gql_definitions/ocm_subscription_labels/__init__.py +0 -0
- reconcile/jenkins/__init__.py +0 -0
- reconcile/jenkins/types.py +0 -77
- {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev299.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/entry_points.txt +0 -0
reconcile/terraform_users.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import sys
|
|
2
|
+
from collections.abc import Iterable, Mapping
|
|
2
3
|
from textwrap import indent
|
|
3
4
|
from typing import (
|
|
4
5
|
Any,
|
|
5
|
-
cast,
|
|
6
6
|
)
|
|
7
7
|
|
|
8
8
|
from reconcile import (
|
|
@@ -11,6 +11,7 @@ from reconcile import (
|
|
|
11
11
|
)
|
|
12
12
|
from reconcile.change_owners.diff import IDENTIFIER_FIELD_NAME
|
|
13
13
|
from reconcile.gql_definitions.common.pgp_reencryption_settings import query
|
|
14
|
+
from reconcile.typed_queries.external_resources import get_settings
|
|
14
15
|
from reconcile.utils import (
|
|
15
16
|
expiration,
|
|
16
17
|
gql,
|
|
@@ -30,7 +31,6 @@ from reconcile.utils.terraform_client import TerraformClient as Terraform
|
|
|
30
31
|
from reconcile.utils.terrascript_aws_client import TerrascriptClient as Terrascript
|
|
31
32
|
from reconcile.utils.vault import (
|
|
32
33
|
VaultClient,
|
|
33
|
-
_VaultClient,
|
|
34
34
|
)
|
|
35
35
|
|
|
36
36
|
TF_POLICY = """
|
|
@@ -81,8 +81,10 @@ QONTRACT_INTEGRATION = "terraform_users"
|
|
|
81
81
|
QONTRACT_INTEGRATION_VERSION = make_semver(0, 4, 2)
|
|
82
82
|
QONTRACT_TF_PREFIX = "qrtf"
|
|
83
83
|
|
|
84
|
+
Role = dict[str, Any]
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
|
|
87
|
+
def get_tf_roles() -> list[Role]:
|
|
86
88
|
gqlapi = gql.get_api()
|
|
87
89
|
roles: list[dict] = expiration.filter(gqlapi.query(TF_QUERY)["roles"])
|
|
88
90
|
return [
|
|
@@ -93,9 +95,9 @@ def get_tf_roles() -> list[dict[str, Any]]:
|
|
|
93
95
|
|
|
94
96
|
|
|
95
97
|
def _filter_participating_aws_accounts(
|
|
96
|
-
accounts:
|
|
97
|
-
roles:
|
|
98
|
-
) -> list:
|
|
98
|
+
accounts: Iterable[dict[str, Any]],
|
|
99
|
+
roles: Iterable[Mapping[str, Any]],
|
|
100
|
+
) -> list[dict[str, Any]]:
|
|
99
101
|
participating_aws_account_names: set[str] = set()
|
|
100
102
|
for role in roles:
|
|
101
103
|
participating_aws_account_names.update(
|
|
@@ -109,7 +111,7 @@ def _filter_participating_aws_accounts(
|
|
|
109
111
|
|
|
110
112
|
|
|
111
113
|
def setup(
|
|
112
|
-
print_to_file,
|
|
114
|
+
print_to_file: str | None,
|
|
113
115
|
thread_pool_size: int,
|
|
114
116
|
skip_reencrypt_accounts: list[str],
|
|
115
117
|
appsre_pgp_key: str | None = None,
|
|
@@ -125,12 +127,18 @@ def setup(
|
|
|
125
127
|
participating_aws_accounts = _filter_participating_aws_accounts(accounts, roles)
|
|
126
128
|
|
|
127
129
|
settings = queries.get_app_interface_settings()
|
|
130
|
+
try:
|
|
131
|
+
default_tags = get_settings().default_tags
|
|
132
|
+
except ValueError:
|
|
133
|
+
# no external resources settings found
|
|
134
|
+
default_tags = None
|
|
128
135
|
ts = Terrascript(
|
|
129
136
|
QONTRACT_INTEGRATION,
|
|
130
137
|
QONTRACT_TF_PREFIX,
|
|
131
138
|
thread_pool_size,
|
|
132
139
|
participating_aws_accounts,
|
|
133
140
|
settings=settings,
|
|
141
|
+
default_tags=default_tags,
|
|
134
142
|
)
|
|
135
143
|
err = ts.populate_users(
|
|
136
144
|
roles,
|
|
@@ -144,10 +152,10 @@ def setup(
|
|
|
144
152
|
|
|
145
153
|
|
|
146
154
|
def send_email_invites(
|
|
147
|
-
new_users,
|
|
155
|
+
new_users: Iterable[tuple[str, str, str, str]],
|
|
148
156
|
smtp_client: SmtpClient,
|
|
149
|
-
skip_reencrypt_accounts:
|
|
150
|
-
):
|
|
157
|
+
skip_reencrypt_accounts: Iterable[str],
|
|
158
|
+
) -> None:
|
|
151
159
|
msg_template = """
|
|
152
160
|
You have been invited to join the {} AWS account!
|
|
153
161
|
Below you will find credentials for the first sign in.
|
|
@@ -185,11 +193,11 @@ Encrypted password: {}
|
|
|
185
193
|
|
|
186
194
|
|
|
187
195
|
def write_user_to_vault(
|
|
188
|
-
vault_client:
|
|
196
|
+
vault_client: VaultClient,
|
|
189
197
|
vault_path: str,
|
|
190
|
-
new_users:
|
|
191
|
-
skip_reencrypt_accounts:
|
|
192
|
-
):
|
|
198
|
+
new_users: Iterable[tuple[str, str, str, str]],
|
|
199
|
+
skip_reencrypt_accounts: Iterable[str],
|
|
200
|
+
) -> None:
|
|
193
201
|
for account, console_url, user_name, enc_password in new_users:
|
|
194
202
|
if account in skip_reencrypt_accounts:
|
|
195
203
|
continue
|
|
@@ -206,13 +214,13 @@ def write_user_to_vault(
|
|
|
206
214
|
vault_client.write(desired_secret, decode_base64=False)
|
|
207
215
|
|
|
208
216
|
|
|
209
|
-
def cleanup_and_exit(tf=None, status=False):
|
|
217
|
+
def cleanup_and_exit(tf: Terraform | None = None, status: bool = False) -> None:
|
|
210
218
|
if tf is not None:
|
|
211
219
|
tf.cleanup()
|
|
212
220
|
sys.exit(status)
|
|
213
221
|
|
|
214
222
|
|
|
215
|
-
def get_reencrypt_settings():
|
|
223
|
+
def get_reencrypt_settings() -> tuple[list[str], str | None, Any]:
|
|
216
224
|
all_reencrypt_settings = query(
|
|
217
225
|
query_func=gql.get_api().query
|
|
218
226
|
).pgp_reencryption_settings
|
|
@@ -241,7 +249,7 @@ def run(
|
|
|
241
249
|
thread_pool_size: int = DEFAULT_THREAD_POOL_SIZE,
|
|
242
250
|
send_mails: bool = True,
|
|
243
251
|
account_name: str | None = None,
|
|
244
|
-
):
|
|
252
|
+
) -> None:
|
|
245
253
|
skip_accounts, appsre_pgp_key, reencrypt_settings = get_reencrypt_settings()
|
|
246
254
|
|
|
247
255
|
# setup errors should skip resources that will lead
|
|
@@ -295,7 +303,7 @@ def run(
|
|
|
295
303
|
new_users = tf.get_new_users()
|
|
296
304
|
|
|
297
305
|
if reencrypt_settings:
|
|
298
|
-
vc =
|
|
306
|
+
vc = VaultClient.get_instance()
|
|
299
307
|
write_user_to_vault(
|
|
300
308
|
vc, reencrypt_settings.reencrypt_vault_path, new_users, skip_accounts
|
|
301
309
|
)
|
|
@@ -317,7 +325,7 @@ def run(
|
|
|
317
325
|
cleanup_and_exit(tf, setup_err)
|
|
318
326
|
|
|
319
327
|
|
|
320
|
-
def early_exit_desired_state(*args, **kwargs) -> dict[str, Any]:
|
|
328
|
+
def early_exit_desired_state(*args: Any, **kwargs: Any) -> dict[str, Any]:
|
|
321
329
|
"""
|
|
322
330
|
Finding diffs in deeply nested structures is time/resource consuming.
|
|
323
331
|
Having a unique known property to identify objects makes it easier to match
|
|
@@ -328,11 +336,11 @@ def early_exit_desired_state(*args, **kwargs) -> dict[str, Any]:
|
|
|
328
336
|
for the DeepDiff library used in qontract-reconcile.
|
|
329
337
|
"""
|
|
330
338
|
|
|
331
|
-
def add_account_identity(acc):
|
|
339
|
+
def add_account_identity(acc: dict[str, Any]) -> dict[str, Any]:
|
|
332
340
|
acc[IDENTIFIER_FIELD_NAME] = acc["path"]
|
|
333
341
|
return acc
|
|
334
342
|
|
|
335
|
-
def add_role_identity(role):
|
|
343
|
+
def add_role_identity(role: dict[str, Any]) -> dict[str, Any]:
|
|
336
344
|
role[IDENTIFIER_FIELD_NAME] = role["name"]
|
|
337
345
|
return role
|
|
338
346
|
|
|
@@ -7,6 +7,7 @@ from typing import Any, TypedDict
|
|
|
7
7
|
import reconcile.utils.terraform_client as terraform
|
|
8
8
|
import reconcile.utils.terrascript_aws_client as terrascript
|
|
9
9
|
from reconcile import queries
|
|
10
|
+
from reconcile.typed_queries import external_resources
|
|
10
11
|
from reconcile.utils import (
|
|
11
12
|
aws_api,
|
|
12
13
|
ocm,
|
|
@@ -73,6 +74,7 @@ def _build_infrastructure_assume_role(
|
|
|
73
74
|
ocm: OCM | None,
|
|
74
75
|
provided_assume_role: str | None,
|
|
75
76
|
) -> dict[str, Any] | None:
|
|
77
|
+
assume_role: str | None = None
|
|
76
78
|
if provided_assume_role:
|
|
77
79
|
assume_role = provided_assume_role
|
|
78
80
|
elif cluster["spec"].get("account"):
|
|
@@ -565,7 +567,7 @@ def build_desired_state_vpc(
|
|
|
565
567
|
@defer
|
|
566
568
|
def run(
|
|
567
569
|
dry_run: bool,
|
|
568
|
-
print_to_file:
|
|
570
|
+
print_to_file: str | None = None,
|
|
569
571
|
enable_deletion: bool = False,
|
|
570
572
|
thread_pool_size: int = DEFAULT_THREAD_POOL_SIZE,
|
|
571
573
|
account_name: str | None = None,
|
|
@@ -653,8 +655,18 @@ def run(
|
|
|
653
655
|
])
|
|
654
656
|
|
|
655
657
|
account_by_name = {a["name"]: a for a in accounts}
|
|
658
|
+
try:
|
|
659
|
+
default_tags = external_resources.get_settings().default_tags
|
|
660
|
+
except ValueError:
|
|
661
|
+
# no external resources settings found
|
|
662
|
+
default_tags = None
|
|
656
663
|
with terrascript.TerrascriptClient(
|
|
657
|
-
QONTRACT_INTEGRATION,
|
|
664
|
+
QONTRACT_INTEGRATION,
|
|
665
|
+
"",
|
|
666
|
+
thread_pool_size,
|
|
667
|
+
infra_accounts,
|
|
668
|
+
settings=settings,
|
|
669
|
+
default_tags=default_tags,
|
|
658
670
|
) as ts:
|
|
659
671
|
rosa_cluster_accounts = [
|
|
660
672
|
account_by_name[c["spec"]["account"]["name"]]
|
|
@@ -663,8 +675,8 @@ def run(
|
|
|
663
675
|
]
|
|
664
676
|
ts.populate_configs(rosa_cluster_accounts)
|
|
665
677
|
|
|
666
|
-
for infra_account_name,
|
|
667
|
-
ts.populate_additional_providers(infra_account_name,
|
|
678
|
+
for infra_account_name, accounts in participating_accounts.items():
|
|
679
|
+
ts.populate_additional_providers(infra_account_name, accounts)
|
|
668
680
|
ts.populate_vpc_peerings(desired_state)
|
|
669
681
|
working_dirs = ts.dump(print_to_file=print_to_file)
|
|
670
682
|
terraform_configurations = ts.terraform_configurations()
|
|
@@ -20,6 +20,7 @@ from reconcile.typed_queries.app_interface_vault_settings import (
|
|
|
20
20
|
get_app_interface_vault_settings,
|
|
21
21
|
)
|
|
22
22
|
from reconcile.typed_queries.aws_vpc_requests import get_aws_vpc_requests
|
|
23
|
+
from reconcile.typed_queries.external_resources import get_settings
|
|
23
24
|
from reconcile.typed_queries.github_orgs import get_github_orgs
|
|
24
25
|
from reconcile.typed_queries.gitlab_instances import get_gitlab_instances
|
|
25
26
|
from reconcile.utils import gql
|
|
@@ -31,7 +32,11 @@ from reconcile.utils.runtime.integration import (
|
|
|
31
32
|
from reconcile.utils.secret_reader import create_secret_reader
|
|
32
33
|
from reconcile.utils.semver_helper import make_semver
|
|
33
34
|
from reconcile.utils.terraform_client import TerraformClient
|
|
34
|
-
from reconcile.utils.terrascript_aws_client import
|
|
35
|
+
from reconcile.utils.terrascript_aws_client import (
|
|
36
|
+
VPC_REQUEST_DEFAULT_PRIVATE_SUBNET_TAGS,
|
|
37
|
+
VPC_REQUEST_DEFAULT_PUBLIC_SUBNET_TAGS,
|
|
38
|
+
TerrascriptClient,
|
|
39
|
+
)
|
|
35
40
|
from reconcile.utils.vcs import VCS
|
|
36
41
|
|
|
37
42
|
QONTRACT_INTEGRATION = "terraform_vpc_resources"
|
|
@@ -89,15 +94,32 @@ class TerraformVpcResources(QontractReconcileIntegration[TerraformVpcResourcesPa
|
|
|
89
94
|
public_subnets = outputs_per_account.get(
|
|
90
95
|
f"{request.identifier}-public_subnets", {}
|
|
91
96
|
).get("value", [])
|
|
97
|
+
availability_zones: list[str] = []
|
|
98
|
+
|
|
99
|
+
if request.subnets:
|
|
100
|
+
private_subnet_tags = VPC_REQUEST_DEFAULT_PRIVATE_SUBNET_TAGS | (
|
|
101
|
+
request.subnets.private_subnet_tags or {}
|
|
102
|
+
)
|
|
103
|
+
public_subnet_tags = VPC_REQUEST_DEFAULT_PUBLIC_SUBNET_TAGS | (
|
|
104
|
+
request.subnets.public_subnet_tags or {}
|
|
105
|
+
)
|
|
106
|
+
availability_zones = request.subnets.availability_zones or []
|
|
107
|
+
else:
|
|
108
|
+
private_subnet_tags = VPC_REQUEST_DEFAULT_PRIVATE_SUBNET_TAGS
|
|
109
|
+
public_subnet_tags = VPC_REQUEST_DEFAULT_PUBLIC_SUBNET_TAGS
|
|
92
110
|
|
|
93
111
|
values = {
|
|
94
112
|
"static": {
|
|
95
113
|
"vpc_id": outputs_per_account.get(
|
|
96
114
|
f"{request.identifier}-vpc_id", {}
|
|
97
115
|
).get("value"),
|
|
116
|
+
"vpc_tags": request.vpc_tags or {},
|
|
98
117
|
"subnets": {
|
|
99
118
|
"private": private_subnets,
|
|
100
119
|
"public": public_subnets,
|
|
120
|
+
"private_subnet_tags": private_subnet_tags,
|
|
121
|
+
"public_subnet_tags": public_subnet_tags,
|
|
122
|
+
"availability_zones": availability_zones,
|
|
101
123
|
},
|
|
102
124
|
"account_name": request.account.name,
|
|
103
125
|
"region": request.region,
|
|
@@ -140,13 +162,21 @@ class TerraformVpcResources(QontractReconcileIntegration[TerraformVpcResourcesPa
|
|
|
140
162
|
logging.debug("No VPC requests found, nothing to do.")
|
|
141
163
|
sys.exit(ExitCodes.SUCCESS)
|
|
142
164
|
|
|
143
|
-
accounts_untyped: list[dict] = [
|
|
165
|
+
accounts_untyped: list[dict] = [
|
|
166
|
+
acc.model_dump(by_alias=True) for acc in accounts
|
|
167
|
+
]
|
|
168
|
+
try:
|
|
169
|
+
default_tags = get_settings().default_tags
|
|
170
|
+
except ValueError:
|
|
171
|
+
# no external resources settings found
|
|
172
|
+
default_tags = None
|
|
144
173
|
with TerrascriptClient(
|
|
145
174
|
integration=QONTRACT_INTEGRATION,
|
|
146
175
|
integration_prefix=QONTRACT_TF_PREFIX,
|
|
147
176
|
thread_pool_size=thread_pool_size,
|
|
148
177
|
accounts=accounts_untyped,
|
|
149
178
|
secret_reader=secret_reader,
|
|
179
|
+
default_tags=default_tags,
|
|
150
180
|
) as ts_client:
|
|
151
181
|
ts_client.populate_vpc_requests(data, AWS_PROVIDER_VERSION)
|
|
152
182
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from collections.abc import Mapping
|
|
3
|
+
|
|
4
|
+
from reconcile.gql_definitions.fragments.aws_organization import (
|
|
5
|
+
AWSOrganization,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_aws_account_tags(
|
|
10
|
+
organization: AWSOrganization | Mapping | None,
|
|
11
|
+
) -> dict[str, str]:
|
|
12
|
+
"""
|
|
13
|
+
Get AWS account tags by merging payer account tags
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
organization: AWSOrganization | Mapping | None - The organization object from which to extract tags.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
dict[str, str]: A dictionary containing the merged tags from the payer account and the account itself.
|
|
20
|
+
"""
|
|
21
|
+
if organization is None:
|
|
22
|
+
return {}
|
|
23
|
+
|
|
24
|
+
match organization:
|
|
25
|
+
case AWSOrganization():
|
|
26
|
+
payer_account_tags = (
|
|
27
|
+
organization.payer_account.organization_account_tags or {}
|
|
28
|
+
)
|
|
29
|
+
account_tags = organization.tags or {}
|
|
30
|
+
case Mapping():
|
|
31
|
+
payer_account_tags = organization.get("payerAccount", {}).get(
|
|
32
|
+
"organizationAccountTags", {}
|
|
33
|
+
)
|
|
34
|
+
if isinstance(payer_account_tags, str):
|
|
35
|
+
payer_account_tags = json.loads(payer_account_tags)
|
|
36
|
+
|
|
37
|
+
account_tags = organization.get("tags", {})
|
|
38
|
+
if isinstance(account_tags, str):
|
|
39
|
+
account_tags = json.loads(account_tags)
|
|
40
|
+
|
|
41
|
+
return payer_account_tags | account_tags
|
|
@@ -13,7 +13,7 @@ class CostNamespace(BaseModel, frozen=True):
|
|
|
13
13
|
labels: CostNamespaceLabels
|
|
14
14
|
app_name: str
|
|
15
15
|
cluster_name: str
|
|
16
|
-
cluster_external_id: str | None
|
|
16
|
+
cluster_external_id: str | None = None
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def get_cost_namespaces(
|
|
@@ -32,7 +32,7 @@ def get_cost_namespaces(
|
|
|
32
32
|
return [
|
|
33
33
|
CostNamespace(
|
|
34
34
|
name=namespace.name,
|
|
35
|
-
labels=CostNamespaceLabels.
|
|
35
|
+
labels=CostNamespaceLabels.model_validate(namespace.labels or {}),
|
|
36
36
|
app_name=namespace.app.name,
|
|
37
37
|
cluster_name=namespace.cluster.name,
|
|
38
38
|
cluster_external_id=namespace.cluster.spec.external_id
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import hashlib
|
|
2
|
-
import json
|
|
3
2
|
from collections.abc import Callable
|
|
4
3
|
from threading import Lock
|
|
5
4
|
from typing import Any
|
|
@@ -7,7 +6,6 @@ from typing import Any
|
|
|
7
6
|
from jsonpath_ng.exceptions import JsonPathParserError
|
|
8
7
|
from pydantic import (
|
|
9
8
|
BaseModel,
|
|
10
|
-
Extra,
|
|
11
9
|
Field,
|
|
12
10
|
Json,
|
|
13
11
|
)
|
|
@@ -48,10 +46,16 @@ from reconcile.utils.exceptions import (
|
|
|
48
46
|
AppInterfaceSettingsError,
|
|
49
47
|
ParameterError,
|
|
50
48
|
)
|
|
49
|
+
from reconcile.utils.json import json_dumps
|
|
51
50
|
from reconcile.utils.jsonpath import parse_jsonpath
|
|
52
51
|
|
|
53
52
|
|
|
54
|
-
class SaasResourceTemplateTarget(
|
|
53
|
+
class SaasResourceTemplateTarget(
|
|
54
|
+
ConfiguredBaseModel,
|
|
55
|
+
validate_by_alias=True,
|
|
56
|
+
# ignore `namespaceSelector` and 'provider' fields from the GQL schema
|
|
57
|
+
extra="ignore",
|
|
58
|
+
):
|
|
55
59
|
path: str | None = Field(..., alias="path")
|
|
56
60
|
name: str | None = Field(..., alias="name")
|
|
57
61
|
# the namespace must be required to fulfill the saas file schema (utils.saasherder.interface.SaasFile)
|
|
@@ -79,12 +83,8 @@ class SaasResourceTemplateTarget(ConfiguredBaseModel):
|
|
|
79
83
|
digest_size=20,
|
|
80
84
|
).hexdigest()
|
|
81
85
|
|
|
82
|
-
class Config:
|
|
83
|
-
# ignore `namespaceSelector` and 'provider' fields from the GQL schema
|
|
84
|
-
extra = Extra.ignore
|
|
85
|
-
|
|
86
86
|
|
|
87
|
-
class SaasResourceTemplate(ConfiguredBaseModel):
|
|
87
|
+
class SaasResourceTemplate(ConfiguredBaseModel, validate_by_alias=True):
|
|
88
88
|
name: str = Field(..., alias="name")
|
|
89
89
|
url: str = Field(..., alias="url")
|
|
90
90
|
path: str = Field(..., alias="path")
|
|
@@ -97,7 +97,7 @@ class SaasResourceTemplate(ConfiguredBaseModel):
|
|
|
97
97
|
targets: list[SaasResourceTemplateTarget] = Field(..., alias="targets")
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
class SaasFile(ConfiguredBaseModel):
|
|
100
|
+
class SaasFile(ConfiguredBaseModel, validate_by_alias=True):
|
|
101
101
|
path: str = Field(..., alias="path")
|
|
102
102
|
name: str = Field(..., alias="name")
|
|
103
103
|
labels: Json | None = Field(..., alias="labels")
|
|
@@ -221,7 +221,7 @@ class SaasFileList:
|
|
|
221
221
|
with self._namespaces_as_dict_lock:
|
|
222
222
|
self._namespaces_as_dict_cache = {
|
|
223
223
|
"namespace": [
|
|
224
|
-
ns.
|
|
224
|
+
ns.model_dump(by_alias=True, exclude_none=True)
|
|
225
225
|
for ns in self.namespaces
|
|
226
226
|
]
|
|
227
227
|
}
|
|
@@ -283,7 +283,7 @@ class SaasFileList:
|
|
|
283
283
|
if app_name and saas_file.app.name != app_name:
|
|
284
284
|
continue
|
|
285
285
|
|
|
286
|
-
sf = saas_file.
|
|
286
|
+
sf = saas_file.model_copy(deep=True)
|
|
287
287
|
if env_name:
|
|
288
288
|
for rt in sf.resource_templates[:]:
|
|
289
289
|
for target in rt.targets[:]:
|
|
@@ -302,7 +302,7 @@ def convert_parameters_to_json_string(root: dict[str, Any]) -> dict[str, Any]:
|
|
|
302
302
|
"""Find all parameter occurrences and convert them to a json string."""
|
|
303
303
|
for key, value in root.items():
|
|
304
304
|
if key in {"parameters", "labels"}:
|
|
305
|
-
root[key] =
|
|
305
|
+
root[key] = json_dumps(value) if value is not None else None
|
|
306
306
|
elif isinstance(value, dict):
|
|
307
307
|
root[key] = convert_parameters_to_json_string(value)
|
|
308
308
|
elif isinstance(value, list):
|
|
@@ -314,7 +314,7 @@ def convert_parameters_to_json_string(root: dict[str, Any]) -> dict[str, Any]:
|
|
|
314
314
|
|
|
315
315
|
|
|
316
316
|
def export_model(model: BaseModel) -> dict[str, Any]:
|
|
317
|
-
return convert_parameters_to_json_string(model.
|
|
317
|
+
return convert_parameters_to_json_string(model.model_dump(by_alias=True))
|
|
318
318
|
|
|
319
319
|
|
|
320
320
|
def get_saas_files(
|
|
@@ -32,7 +32,7 @@ def get_selected_app_names(
|
|
|
32
32
|
prefix = f"{namespace.app.parent_app.name}-"
|
|
33
33
|
name = f"{prefix}{namespace.app.name}"
|
|
34
34
|
selected_app_names.add(name)
|
|
35
|
-
app = namespace.app.
|
|
35
|
+
app = namespace.app.model_dump(by_alias=True)
|
|
36
36
|
app["name"] = name
|
|
37
37
|
apps["apps"].append(app)
|
|
38
38
|
|
|
@@ -40,7 +40,7 @@ def get_selected_app_names(
|
|
|
40
40
|
name = f"{namespace.app.name}-{child.name}"
|
|
41
41
|
if name not in selected_app_names:
|
|
42
42
|
selected_app_names.add(f"{namespace.app.name}-{child.name}")
|
|
43
|
-
child_dict = child.
|
|
43
|
+
child_dict = child.model_dump(by_alias=True)
|
|
44
44
|
child_dict["name"] = name
|
|
45
45
|
apps["apps"].append(child_dict)
|
|
46
46
|
|
|
@@ -31,7 +31,7 @@ QONTRACT_INTEGRATION_VERSION = make_semver(1, 0, 0)
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
class UnleashTogglesIntegrationParams(PydanticRunParams):
|
|
34
|
-
instance: str | None
|
|
34
|
+
instance: str | None = None
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def feature_toggle_equal(c: FeatureToggle, d: FeatureToggleUnleashV1) -> bool:
|
|
@@ -68,7 +68,9 @@ class UnleashTogglesIntegration(
|
|
|
68
68
|
if not query_func:
|
|
69
69
|
query_func = gql.get_api().query
|
|
70
70
|
return {
|
|
71
|
-
"toggles": [
|
|
71
|
+
"toggles": [
|
|
72
|
+
ft.model_dump() for ft in self.get_unleash_instances(query_func)
|
|
73
|
+
],
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
def get_unleash_instances(
|
reconcile/utils/acs/base.py
CHANGED
|
@@ -6,7 +6,7 @@ from typing import (
|
|
|
6
6
|
)
|
|
7
7
|
|
|
8
8
|
import requests
|
|
9
|
-
from pydantic import BaseModel
|
|
9
|
+
from pydantic import BaseModel, ConfigDict
|
|
10
10
|
|
|
11
11
|
from reconcile.gql_definitions.acs.acs_instances import AcsInstanceV1
|
|
12
12
|
from reconcile.gql_definitions.acs.acs_instances import query as acs_instances_query
|
|
@@ -19,8 +19,11 @@ class AcsBaseApi(BaseModel):
|
|
|
19
19
|
timeout: int = 30
|
|
20
20
|
session: requests.Session = requests.Session()
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
model_config = ConfigDict(
|
|
23
|
+
validate_by_name=True,
|
|
24
|
+
validate_by_alias=True,
|
|
25
|
+
arbitrary_types_allowed=True,
|
|
26
|
+
)
|
|
24
27
|
|
|
25
28
|
def __enter__(self) -> Self:
|
|
26
29
|
return self
|
reconcile/utils/acs/policies.py
CHANGED
|
@@ -11,7 +11,7 @@ class Scope(BaseModel):
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
cluster: str
|
|
14
|
-
namespace: str | None
|
|
14
|
+
namespace: str | None = None
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class PolicyCondition(BaseModel):
|
|
@@ -23,7 +23,7 @@ class PolicyCondition(BaseModel):
|
|
|
23
23
|
"""
|
|
24
24
|
|
|
25
25
|
field_name: str
|
|
26
|
-
negate: bool | None
|
|
26
|
+
negate: bool | None = None
|
|
27
27
|
values: list[str]
|
|
28
28
|
|
|
29
29
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import json
|
|
2
1
|
import logging
|
|
3
2
|
from collections.abc import Callable, KeysView
|
|
4
3
|
from typing import Any, TypedDict
|
|
5
4
|
|
|
5
|
+
from reconcile.utils.json import json_dumps
|
|
6
|
+
|
|
6
7
|
Action = Callable[[Any, list[Any]], bool]
|
|
7
8
|
Cond = Callable[[Any], bool]
|
|
8
9
|
|
|
@@ -89,11 +90,11 @@ class AggregatedList:
|
|
|
89
90
|
return list(self._dict.values())
|
|
90
91
|
|
|
91
92
|
def to_json(self) -> str:
|
|
92
|
-
return
|
|
93
|
+
return json_dumps(self.dump(), indent=4)
|
|
93
94
|
|
|
94
95
|
@staticmethod
|
|
95
96
|
def hash_params(params: Any) -> int:
|
|
96
|
-
return hash(
|
|
97
|
+
return hash(json_dumps(params))
|
|
97
98
|
|
|
98
99
|
|
|
99
100
|
class AggregatedDiffRunner:
|
reconcile/utils/aws_api.py
CHANGED
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
import operator
|
|
5
5
|
import os
|
|
6
|
-
import re
|
|
7
6
|
from functools import lru_cache
|
|
8
7
|
from threading import Lock
|
|
9
8
|
from typing import (
|
|
@@ -25,6 +24,7 @@ import reconcile.utils.lean_terraform_client as terraform
|
|
|
25
24
|
from reconcile.utils.secret_reader import SecretReader, SecretReaderBase
|
|
26
25
|
|
|
27
26
|
if TYPE_CHECKING:
|
|
27
|
+
import re
|
|
28
28
|
from collections.abc import (
|
|
29
29
|
Iterable,
|
|
30
30
|
Iterator,
|
|
@@ -1074,28 +1074,40 @@ class AWSApi:
|
|
|
1074
1074
|
return [rt["RouteTableId"] for rt in vpc_route_tables]
|
|
1075
1075
|
|
|
1076
1076
|
@staticmethod
|
|
1077
|
-
def
|
|
1078
|
-
|
|
1079
|
-
) -> list[dict[str, Any]]:
|
|
1080
|
-
results = []
|
|
1081
|
-
pattern = re.compile(regex)
|
|
1082
|
-
for i in images:
|
|
1083
|
-
if not re.search(pattern, i["Name"]):
|
|
1084
|
-
continue
|
|
1085
|
-
if i["State"] != "available":
|
|
1086
|
-
continue
|
|
1087
|
-
item = {"image_id": i["ImageId"], "tags": i.get("Tags", [])}
|
|
1088
|
-
results.append(item)
|
|
1077
|
+
def normalize_tags(tags: Iterable[TagTypeDef]) -> dict[str, str]:
|
|
1078
|
+
return {tag["Key"]: tag["Value"] for tag in tags}
|
|
1089
1079
|
|
|
1090
|
-
|
|
1080
|
+
@staticmethod
|
|
1081
|
+
def _filter_amis(
|
|
1082
|
+
images: Iterable[ImageTypeDef],
|
|
1083
|
+
regex: re.Pattern,
|
|
1084
|
+
) -> dict[str, dict[str, str]]:
|
|
1085
|
+
return {
|
|
1086
|
+
image["ImageId"]: AWSApi.normalize_tags(image.get("Tags", []))
|
|
1087
|
+
for image in images
|
|
1088
|
+
if regex.search(image["Name"]) and image["State"] == "available"
|
|
1089
|
+
}
|
|
1091
1090
|
|
|
1092
1091
|
def get_amis_details(
|
|
1093
1092
|
self,
|
|
1094
1093
|
account: Mapping[str, Any],
|
|
1095
1094
|
owner_account: Mapping[str, Any],
|
|
1096
|
-
regex:
|
|
1095
|
+
regex: re.Pattern,
|
|
1097
1096
|
region: str | None = None,
|
|
1098
|
-
) ->
|
|
1097
|
+
) -> dict[str, dict[str, str]]:
|
|
1098
|
+
"""
|
|
1099
|
+
Get AMI details for an account, find AMI name matches regex and state is available.
|
|
1100
|
+
Return ImageId and normalized tags.
|
|
1101
|
+
|
|
1102
|
+
Args:
|
|
1103
|
+
account: AWS account
|
|
1104
|
+
owner_account: AMI owner AWS account uid
|
|
1105
|
+
regex: regex to filter AMI name
|
|
1106
|
+
region: AWS account region
|
|
1107
|
+
|
|
1108
|
+
Returns:
|
|
1109
|
+
dict[str, dict[str, str]]: Key is AMI ImageId, value is AMI normalized tags.
|
|
1110
|
+
"""
|
|
1099
1111
|
ec2 = self._account_ec2_client(account["name"], region_name=region)
|
|
1100
1112
|
images = self.get_account_amis(ec2, owner=owner_account["uid"])
|
|
1101
1113
|
return self._filter_amis(images, regex)
|
|
@@ -1175,12 +1187,31 @@ class AWSApi:
|
|
|
1175
1187
|
client = self._account_cloudwatch_client(account_name, region_name=region_name)
|
|
1176
1188
|
client.delete_log_group(logGroupName=group_name)
|
|
1177
1189
|
|
|
1178
|
-
def
|
|
1179
|
-
self,
|
|
1190
|
+
def create_tags(
|
|
1191
|
+
self,
|
|
1192
|
+
account: Mapping[str, Any],
|
|
1193
|
+
resource_id: str,
|
|
1194
|
+
tags: Mapping[str, str],
|
|
1180
1195
|
) -> None:
|
|
1196
|
+
"""
|
|
1197
|
+
Create tags on EC2 resources (AMI)
|
|
1198
|
+
|
|
1199
|
+
Args:
|
|
1200
|
+
account: AWS account
|
|
1201
|
+
resource_id: AWS resource id
|
|
1202
|
+
tags: tags to update
|
|
1203
|
+
|
|
1204
|
+
Returns:
|
|
1205
|
+
None
|
|
1206
|
+
"""
|
|
1181
1207
|
ec2 = self._account_ec2_client(account["name"])
|
|
1182
|
-
|
|
1183
|
-
|
|
1208
|
+
formatted_tags: list[TagTypeDef] = [
|
|
1209
|
+
{"Key": k, "Value": v} for k, v in tags.items()
|
|
1210
|
+
]
|
|
1211
|
+
ec2.create_tags(
|
|
1212
|
+
Resources=[resource_id],
|
|
1213
|
+
Tags=formatted_tags,
|
|
1214
|
+
)
|
|
1184
1215
|
|
|
1185
1216
|
def get_alb_network_interface_ips(
|
|
1186
1217
|
self, account: awsh.Account, service_name: str
|