qontract-reconcile 0.10.2.dev361__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.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/METADATA +13 -12
- {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/RECORD +351 -345
- 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_iam_keys.py +1 -0
- reconcile/aws_saml_idp/integration.py +12 -4
- reconcile/aws_saml_roles/integration.py +30 -23
- reconcile/aws_version_sync/integration.py +6 -12
- reconcile/change_owners/bundle.py +3 -3
- reconcile/change_owners/change_log_tracking.py +3 -2
- reconcile/change_owners/change_owners.py +1 -1
- reconcile/change_owners/diff.py +0 -2
- reconcile/checkpoint.py +11 -3
- reconcile/cli.py +93 -10
- reconcile/dashdotdb_dora.py +5 -12
- reconcile/dashdotdb_slo.py +1 -1
- reconcile/database_access_manager.py +123 -117
- reconcile/dynatrace_token_provider/integration.py +1 -1
- reconcile/endpoints_discovery/integration.py +4 -1
- reconcile/endpoints_discovery/merge_request.py +1 -1
- reconcile/endpoints_discovery/merge_request_manager.py +8 -8
- reconcile/external_resources/factories.py +4 -6
- reconcile/external_resources/integration.py +1 -1
- reconcile/external_resources/manager.py +8 -6
- reconcile/external_resources/meta.py +0 -1
- reconcile/external_resources/metrics.py +1 -1
- reconcile/external_resources/model.py +19 -15
- reconcile/external_resources/reconciler.py +7 -4
- reconcile/external_resources/secrets_sync.py +4 -7
- reconcile/external_resources/state.py +26 -16
- reconcile/fleet_labeler/integration.py +1 -1
- reconcile/gabi_authorized_users.py +5 -2
- 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_owners.py +15 -11
- reconcile/gitlab_permissions.py +8 -12
- reconcile/glitchtip_project_alerts/integration.py +3 -1
- reconcile/gql_definitions/acs/acs_instances.py +5 -5
- reconcile/gql_definitions/acs/acs_policies.py +5 -5
- reconcile/gql_definitions/acs/acs_rbac.py +5 -5
- reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py +5 -5
- reconcile/gql_definitions/advanced_upgrade_service/aus_organization.py +5 -5
- reconcile/gql_definitions/app_interface_metrics_exporter/onboarding_status.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py +5 -5
- reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py +5 -5
- reconcile/gql_definitions/automated_actions/instance.py +46 -7
- reconcile/gql_definitions/aws_account_manager/aws_accounts.py +5 -5
- reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +15 -5
- reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +27 -66
- reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +15 -5
- reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +15 -5
- reconcile/gql_definitions/aws_saml_roles/roles.py +5 -5
- reconcile/gql_definitions/aws_version_sync/clusters.py +5 -5
- reconcile/gql_definitions/aws_version_sync/namespaces.py +5 -5
- reconcile/gql_definitions/change_owners/queries/change_types.py +5 -5
- reconcile/gql_definitions/change_owners/queries/self_service_roles.py +5 -5
- reconcile/gql_definitions/cluster_auth_rhidp/clusters.py +5 -5
- reconcile/gql_definitions/common/alerting_services_settings.py +5 -5
- reconcile/gql_definitions/common/app_code_component_repos.py +5 -5
- reconcile/gql_definitions/common/app_interface_custom_messages.py +5 -5
- reconcile/gql_definitions/common/app_interface_dms_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_repo_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_roles.py +5 -5
- reconcile/gql_definitions/common/app_interface_state_settings.py +5 -5
- reconcile/gql_definitions/common/app_interface_vault_settings.py +5 -5
- reconcile/gql_definitions/common/app_quay_repos_escalation_policies.py +5 -5
- reconcile/gql_definitions/common/apps.py +5 -5
- reconcile/gql_definitions/common/aws_vpc_requests.py +15 -5
- reconcile/gql_definitions/common/aws_vpcs.py +5 -5
- reconcile/gql_definitions/common/clusters.py +5 -5
- reconcile/gql_definitions/common/clusters_minimal.py +5 -5
- reconcile/gql_definitions/common/clusters_with_dms.py +5 -5
- reconcile/gql_definitions/common/clusters_with_peering.py +5 -5
- reconcile/gql_definitions/common/github_orgs.py +5 -5
- reconcile/gql_definitions/common/jira_settings.py +5 -5
- reconcile/gql_definitions/common/jiralert_settings.py +5 -5
- reconcile/gql_definitions/common/ldap_settings.py +5 -5
- reconcile/gql_definitions/common/namespaces.py +5 -5
- reconcile/gql_definitions/common/namespaces_minimal.py +7 -5
- reconcile/gql_definitions/common/ocm_env_telemeter.py +5 -5
- reconcile/gql_definitions/common/ocm_environments.py +5 -5
- reconcile/gql_definitions/common/pagerduty_instances.py +5 -5
- reconcile/gql_definitions/common/pgp_reencryption_settings.py +5 -5
- reconcile/gql_definitions/common/pipeline_providers.py +5 -5
- reconcile/gql_definitions/common/quay_instances.py +5 -5
- reconcile/gql_definitions/common/quay_orgs.py +5 -5
- reconcile/gql_definitions/common/reserved_networks.py +5 -5
- reconcile/gql_definitions/common/rhcs_provider_settings.py +5 -5
- reconcile/gql_definitions/common/saas_files.py +5 -5
- reconcile/gql_definitions/common/saas_target_namespaces.py +5 -5
- reconcile/gql_definitions/common/saasherder_settings.py +5 -5
- reconcile/gql_definitions/common/slack_workspaces.py +5 -5
- reconcile/gql_definitions/common/smtp_client_settings.py +5 -5
- reconcile/gql_definitions/common/state_aws_account.py +5 -5
- reconcile/gql_definitions/common/users.py +5 -5
- reconcile/gql_definitions/common/users_with_paths.py +5 -5
- reconcile/gql_definitions/cost_report/app_names.py +5 -5
- reconcile/gql_definitions/cost_report/cost_namespaces.py +5 -5
- reconcile/gql_definitions/cost_report/settings.py +5 -5
- reconcile/gql_definitions/dashdotdb_slo/slo_documents_query.py +5 -5
- reconcile/gql_definitions/dynatrace_token_provider/dynatrace_bootstrap_tokens.py +5 -5
- reconcile/gql_definitions/dynatrace_token_provider/token_specs.py +5 -5
- reconcile/gql_definitions/email_sender/apps.py +5 -5
- reconcile/gql_definitions/email_sender/emails.py +5 -5
- reconcile/gql_definitions/email_sender/users.py +5 -5
- reconcile/gql_definitions/endpoints_discovery/apps.py +5 -5
- reconcile/gql_definitions/external_resources/aws_accounts.py +5 -5
- reconcile/gql_definitions/external_resources/external_resources_modules.py +5 -5
- reconcile/gql_definitions/external_resources/external_resources_namespaces.py +33 -6
- reconcile/gql_definitions/external_resources/external_resources_settings.py +5 -5
- reconcile/gql_definitions/external_resources/fragments/external_resources_module_overrides.py +5 -5
- reconcile/gql_definitions/fleet_labeler/fleet_labels.py +5 -5
- reconcile/gql_definitions/fragments/aus_organization.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_common.py +7 -5
- reconcile/gql_definitions/fragments/aws_account_managed.py +5 -5
- reconcile/gql_definitions/fragments/aws_account_sso.py +5 -5
- reconcile/gql_definitions/fragments/aws_infra_management_account.py +5 -5
- reconcile/gql_definitions/fragments/aws_organization.py +33 -0
- reconcile/gql_definitions/fragments/aws_vpc.py +5 -5
- reconcile/gql_definitions/fragments/aws_vpc_request.py +7 -5
- reconcile/gql_definitions/fragments/container_image_mirror.py +5 -5
- reconcile/gql_definitions/fragments/deploy_resources.py +5 -5
- reconcile/gql_definitions/fragments/disable.py +5 -5
- reconcile/gql_definitions/fragments/email_service.py +5 -5
- reconcile/gql_definitions/fragments/email_user.py +5 -5
- reconcile/gql_definitions/fragments/jumphost_common_fields.py +5 -5
- reconcile/gql_definitions/fragments/membership_source.py +5 -5
- reconcile/gql_definitions/fragments/minimal_ocm_organization.py +5 -5
- reconcile/gql_definitions/fragments/oc_connection_cluster.py +5 -5
- reconcile/gql_definitions/fragments/ocm_environment.py +5 -5
- reconcile/gql_definitions/fragments/pipeline_provider_retention.py +5 -5
- reconcile/gql_definitions/fragments/prometheus_instance.py +5 -5
- reconcile/gql_definitions/fragments/resource_limits_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_requests_requirements.py +5 -5
- reconcile/gql_definitions/fragments/resource_values.py +5 -5
- reconcile/gql_definitions/fragments/saas_slo_document.py +5 -5
- reconcile/gql_definitions/fragments/saas_target_namespace.py +5 -5
- reconcile/gql_definitions/fragments/serviceaccount_token.py +5 -5
- reconcile/gql_definitions/fragments/terraform_state.py +5 -5
- reconcile/gql_definitions/fragments/upgrade_policy.py +5 -5
- reconcile/gql_definitions/fragments/user.py +5 -5
- reconcile/gql_definitions/fragments/vault_secret.py +5 -5
- reconcile/gql_definitions/gcp/gcp_docker_repos.py +5 -5
- reconcile/gql_definitions/gcp/gcp_projects.py +5 -5
- reconcile/gql_definitions/gitlab_members/gitlab_instances.py +5 -5
- reconcile/gql_definitions/gitlab_members/permissions.py +5 -5
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +5 -5
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +5 -5
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +5 -5
- reconcile/gql_definitions/integrations/integrations.py +5 -5
- reconcile/gql_definitions/introspection.json +724 -129
- reconcile/gql_definitions/jenkins_configs/jenkins_configs.py +5 -5
- reconcile/gql_definitions/jenkins_configs/jenkins_instances.py +5 -5
- reconcile/gql_definitions/jira/jira_servers.py +5 -5
- reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +9 -5
- reconcile/gql_definitions/jumphosts/jumphosts.py +5 -5
- reconcile/gql_definitions/ldap_groups/roles.py +5 -5
- reconcile/gql_definitions/ldap_groups/settings.py +5 -5
- reconcile/gql_definitions/maintenance/maintenances.py +5 -5
- reconcile/gql_definitions/membershipsources/roles.py +5 -5
- reconcile/gql_definitions/ocm_labels/clusters.py +5 -5
- reconcile/gql_definitions/ocm_labels/organizations.py +5 -5
- reconcile/gql_definitions/openshift_cluster_bots/clusters.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_groups.py +5 -5
- reconcile/gql_definitions/openshift_groups/managed_roles.py +5 -5
- reconcile/gql_definitions/openshift_serviceaccount_tokens/tokens.py +5 -5
- reconcile/gql_definitions/quay_membership/quay_membership.py +5 -5
- reconcile/gql_definitions/rhcs/certs.py +25 -79
- reconcile/gql_definitions/rhcs/openshift_resource_rhcs_cert.py +43 -0
- reconcile/gql_definitions/rhidp/organizations.py +5 -5
- reconcile/gql_definitions/service_dependencies/jenkins_instance_fragment.py +5 -5
- reconcile/gql_definitions/service_dependencies/service_dependencies.py +5 -5
- reconcile/gql_definitions/sharding/aws_accounts.py +5 -5
- reconcile/gql_definitions/sharding/ocm_organization.py +5 -5
- reconcile/gql_definitions/skupper_network/site_controller_template.py +5 -5
- reconcile/gql_definitions/skupper_network/skupper_networks.py +5 -5
- reconcile/gql_definitions/slack_usergroups/clusters.py +5 -5
- reconcile/gql_definitions/slack_usergroups/permissions.py +5 -5
- reconcile/gql_definitions/slack_usergroups/users.py +5 -5
- reconcile/gql_definitions/slo_documents/slo_documents.py +5 -5
- reconcile/gql_definitions/status_board/status_board.py +5 -5
- reconcile/gql_definitions/statuspage/statuspages.py +5 -5
- reconcile/gql_definitions/templating/template_collection.py +5 -5
- reconcile/gql_definitions/templating/templates.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/app_interface_cloudflare_dns_settings.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_dns/terraform_cloudflare_zones.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_accounts.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_resources/terraform_cloudflare_resources.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_users/app_interface_setting_cloudflare_and_vault.py +5 -5
- reconcile/gql_definitions/terraform_cloudflare_users/terraform_cloudflare_roles.py +5 -5
- reconcile/gql_definitions/terraform_init/aws_accounts.py +19 -5
- reconcile/gql_definitions/terraform_repo/terraform_repo.py +5 -5
- reconcile/gql_definitions/terraform_resources/database_access_manager.py +5 -5
- reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +30 -6
- reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +15 -5
- reconcile/gql_definitions/unleash_feature_toggles/feature_toggles.py +5 -5
- reconcile/gql_definitions/vault_instances/vault_instances.py +5 -5
- reconcile/gql_definitions/vault_policies/vault_policies.py +5 -5
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator.py +5 -5
- reconcile/gql_definitions/vpc_peerings_validator/vpc_peerings_validator_peered_cluster_fragment.py +5 -5
- reconcile/integrations_manager.py +3 -3
- reconcile/jenkins_worker_fleets.py +10 -8
- reconcile/jira_permissions_validator.py +237 -122
- reconcile/ldap_groups/integration.py +1 -1
- reconcile/ocm/types.py +35 -57
- 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 +113 -4
- reconcile/openshift_cluster_bots.py +1 -1
- reconcile/openshift_namespace_labels.py +1 -1
- reconcile/openshift_namespaces.py +97 -101
- reconcile/openshift_resources_base.py +6 -2
- reconcile/openshift_rhcs_certs.py +74 -37
- reconcile/openshift_rolebindings.py +7 -11
- reconcile/openshift_saas_deploy.py +4 -5
- reconcile/openshift_saas_deploy_change_tester.py +9 -7
- reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
- reconcile/openshift_serviceaccount_tokens.py +2 -2
- reconcile/openshift_upgrade_watcher.py +4 -4
- reconcile/oum/labelset.py +5 -3
- reconcile/oum/models.py +1 -4
- reconcile/prometheus_rules_tester/integration.py +3 -3
- reconcile/quay_mirror.py +1 -1
- reconcile/queries.py +131 -0
- reconcile/rhidp/common.py +3 -5
- reconcile/rhidp/sso_client/base.py +16 -5
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +1 -1
- reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
- reconcile/skupper_network/integration.py +2 -2
- reconcile/slack_usergroups.py +35 -14
- reconcile/sql_query.py +1 -0
- reconcile/status_board.py +6 -6
- reconcile/statuspage/atlassian.py +7 -7
- reconcile/statuspage/integrations/maintenances.py +4 -3
- reconcile/statuspage/page.py +4 -9
- reconcile/statuspage/status.py +5 -8
- reconcile/templating/lib/rendering.py +3 -3
- reconcile/templating/renderer.py +2 -2
- reconcile/terraform_aws_route53.py +7 -1
- reconcile/terraform_cloudflare_dns.py +3 -3
- reconcile/terraform_cloudflare_resources.py +5 -5
- reconcile/terraform_cloudflare_users.py +3 -2
- reconcile/terraform_init/integration.py +187 -23
- reconcile/terraform_repo.py +16 -12
- reconcile/terraform_resources.py +6 -6
- reconcile/terraform_tgw_attachments.py +27 -19
- reconcile/terraform_users.py +7 -0
- reconcile/terraform_vpc_peerings.py +14 -3
- reconcile/terraform_vpc_resources/integration.py +10 -1
- reconcile/typed_queries/aws_account_tags.py +41 -0
- reconcile/typed_queries/cost_report/app_names.py +1 -1
- reconcile/typed_queries/cost_report/cost_namespaces.py +2 -2
- reconcile/typed_queries/saas_files.py +11 -11
- 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/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/filtering.py +1 -1
- reconcile/utils/gitlab_api.py +7 -5
- reconcile/utils/glitchtip/client.py +6 -2
- reconcile/utils/glitchtip/models.py +25 -28
- reconcile/utils/gql.py +4 -7
- reconcile/utils/helpers.py +1 -1
- reconcile/utils/instrumented_wrappers.py +1 -1
- reconcile/utils/internal_groups/client.py +2 -2
- reconcile/utils/internal_groups/models.py +8 -17
- reconcile/utils/jinja2/utils.py +6 -101
- reconcile/utils/jira_client.py +82 -63
- reconcile/utils/jjb_client.py +7 -10
- reconcile/utils/jobcontroller/controller.py +2 -2
- reconcile/utils/jobcontroller/models.py +17 -1
- reconcile/utils/json.py +43 -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/app_interface_reporter.py +2 -2
- reconcile/utils/mr/notificator.py +3 -3
- reconcile/utils/mr/update_access_report_base.py +3 -4
- reconcile/utils/mr/user_maintenance.py +3 -2
- reconcile/utils/oc.py +246 -201
- reconcile/utils/oc_filters.py +3 -3
- reconcile/utils/ocm/addons.py +0 -1
- reconcile/utils/ocm/base.py +17 -20
- reconcile/utils/ocm/cluster_groups.py +1 -1
- reconcile/utils/ocm/identity_providers.py +2 -2
- reconcile/utils/ocm/labels.py +1 -1
- reconcile/utils/ocm/products.py +8 -8
- reconcile/utils/ocm/search_filters.py +3 -6
- reconcile/utils/ocm/service_log.py +4 -6
- reconcile/utils/ocm/sre_capability_labels.py +20 -13
- reconcile/utils/openshift_resource.py +8 -3
- reconcile/utils/pagerduty_api.py +10 -7
- reconcile/utils/promotion_state.py +6 -11
- reconcile/utils/raw_github_api.py +1 -1
- reconcile/utils/rhcsv2_certs.py +86 -23
- reconcile/utils/rosa/session.py +16 -0
- reconcile/utils/runtime/integration.py +2 -3
- reconcile/utils/runtime/runner.py +2 -2
- reconcile/utils/saasherder/interfaces.py +13 -20
- reconcile/utils/saasherder/models.py +23 -20
- reconcile/utils/saasherder/saasherder.py +50 -27
- reconcile/utils/slack_api.py +2 -2
- reconcile/utils/sloth.py +171 -2
- reconcile/utils/structs.py +1 -1
- reconcile/utils/terraform_client.py +5 -4
- reconcile/utils/terrascript_aws_client.py +134 -74
- reconcile/utils/unleash/server.py +2 -8
- reconcile/utils/vault.py +5 -12
- reconcile/utils/vcs.py +8 -8
- reconcile/vault_replication.py +107 -42
- tools/app_interface_reporter.py +4 -4
- tools/cli_commands/cost_report/cost_management_api.py +3 -3
- tools/cli_commands/cost_report/view.py +7 -6
- tools/cli_commands/erv2.py +1 -1
- tools/qontract_cli.py +28 -17
- tools/template_validation.py +3 -1
- {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev361.dist-info → qontract_reconcile-0.10.2.dev430.dist-info}/entry_points.txt +0 -0
reconcile/utils/ocm/base.py
CHANGED
|
@@ -141,16 +141,16 @@ class OCMClusterAWSOperatorRole(BaseModel):
|
|
|
141
141
|
|
|
142
142
|
|
|
143
143
|
class OCMAWSSTS(OCMClusterFlag):
|
|
144
|
-
role_arn: str | None
|
|
145
|
-
support_role_arn: str | None
|
|
146
|
-
oidc_endpoint_url: str | None
|
|
147
|
-
operator_iam_roles: list[OCMClusterAWSOperatorRole] | None
|
|
148
|
-
instance_iam_roles: dict[str, str] | None
|
|
149
|
-
operator_role_prefix: str | None
|
|
144
|
+
role_arn: str | None = None
|
|
145
|
+
support_role_arn: str | None = None
|
|
146
|
+
oidc_endpoint_url: str | None = None
|
|
147
|
+
operator_iam_roles: list[OCMClusterAWSOperatorRole] | None = None
|
|
148
|
+
instance_iam_roles: dict[str, str] | None = None
|
|
149
|
+
operator_role_prefix: str | None = None
|
|
150
150
|
|
|
151
151
|
|
|
152
152
|
class OCMClusterAWSSettings(BaseModel):
|
|
153
|
-
sts: OCMAWSSTS | None
|
|
153
|
+
sts: OCMAWSSTS | None = None
|
|
154
154
|
|
|
155
155
|
@property
|
|
156
156
|
def sts_enabled(self) -> bool:
|
|
@@ -264,21 +264,21 @@ class OCMCluster(BaseModel):
|
|
|
264
264
|
product: OCMModelLink
|
|
265
265
|
identity_providers: OCMCollectionLink
|
|
266
266
|
|
|
267
|
-
aws: OCMClusterAWSSettings | None
|
|
267
|
+
aws: OCMClusterAWSSettings | None = None
|
|
268
268
|
|
|
269
269
|
version: OCMClusterVersion
|
|
270
270
|
|
|
271
271
|
hypershift: OCMClusterFlag
|
|
272
272
|
|
|
273
|
-
console: OCMClusterConsole | None
|
|
273
|
+
console: OCMClusterConsole | None = None
|
|
274
274
|
|
|
275
|
-
api: OCMClusterAPI | None
|
|
275
|
+
api: OCMClusterAPI | None = None
|
|
276
276
|
|
|
277
|
-
dns: OCMClusterDns | None
|
|
277
|
+
dns: OCMClusterDns | None = None
|
|
278
278
|
|
|
279
|
-
external_configuration: OCMExternalConfiguration | None
|
|
279
|
+
external_configuration: OCMExternalConfiguration | None = None
|
|
280
280
|
|
|
281
|
-
external_auth_config: OCMExternalAuthConfig | None
|
|
281
|
+
external_auth_config: OCMExternalAuthConfig | None = None
|
|
282
282
|
|
|
283
283
|
def minor_version(self) -> str:
|
|
284
284
|
version_info = parse_semver(self.version.raw_id)
|
|
@@ -570,15 +570,12 @@ class OCMOIdentityProviderGithub(OCMOIdentityProvider):
|
|
|
570
570
|
)
|
|
571
571
|
|
|
572
572
|
|
|
573
|
-
class OCMOIdentityProviderOidcOpenIdClaims(BaseModel):
|
|
573
|
+
class OCMOIdentityProviderOidcOpenIdClaims(BaseModel, frozen=True):
|
|
574
574
|
email: list[str]
|
|
575
575
|
name: list[str] = []
|
|
576
576
|
preferred_username: list[str]
|
|
577
577
|
groups: list[str] = []
|
|
578
578
|
|
|
579
|
-
class Config:
|
|
580
|
-
frozen = True
|
|
581
|
-
|
|
582
579
|
|
|
583
580
|
class OCMOIdentityProviderOidcOpenId(BaseModel):
|
|
584
581
|
client_id: str
|
|
@@ -618,11 +615,11 @@ class OCMAddonUpgradePolicy(BaseModel):
|
|
|
618
615
|
id: str
|
|
619
616
|
addon_id: str
|
|
620
617
|
cluster_id: str
|
|
621
|
-
next_run: str | None
|
|
622
|
-
schedule: str | None
|
|
618
|
+
next_run: str | None = None
|
|
619
|
+
schedule: str | None = None
|
|
623
620
|
schedule_type: str
|
|
624
621
|
version: str
|
|
625
|
-
state: str | None
|
|
622
|
+
state: str | None = None
|
|
626
623
|
|
|
627
624
|
|
|
628
625
|
def build_label_container(
|
|
@@ -42,7 +42,7 @@ def add_identity_provider(
|
|
|
42
42
|
)
|
|
43
43
|
ocm_api.post(
|
|
44
44
|
api_path=ocm_cluster.identity_providers.href,
|
|
45
|
-
data=idp.
|
|
45
|
+
data=idp.model_dump(by_alias=True, exclude_none=True),
|
|
46
46
|
)
|
|
47
47
|
|
|
48
48
|
|
|
@@ -55,7 +55,7 @@ def update_identity_provider(
|
|
|
55
55
|
raise ValueError(f"IDP {idp.name} does not have a href!")
|
|
56
56
|
ocm_api.patch(
|
|
57
57
|
api_path=idp.href,
|
|
58
|
-
data=idp.
|
|
58
|
+
data=idp.model_dump(by_alias=True, exclude_none=True, exclude={"name"}),
|
|
59
59
|
)
|
|
60
60
|
|
|
61
61
|
|
reconcile/utils/ocm/labels.py
CHANGED
|
@@ -159,7 +159,7 @@ def build_container_for_prefix(
|
|
|
159
159
|
|
|
160
160
|
return LabelContainer(
|
|
161
161
|
labels={
|
|
162
|
-
strip_prefix_if_needed(label.key): label.
|
|
162
|
+
strip_prefix_if_needed(label.key): label.model_copy(
|
|
163
163
|
update={"key": strip_prefix_if_needed(label.key)}
|
|
164
164
|
)
|
|
165
165
|
for label in container.labels.values()
|
reconcile/utils/ocm/products.py
CHANGED
|
@@ -178,11 +178,11 @@ class OCMProductOsd(OCMProduct):
|
|
|
178
178
|
],
|
|
179
179
|
provision_shard_id=provision_shard_id,
|
|
180
180
|
hypershift=cluster["hypershift"]["enabled"],
|
|
181
|
-
fips=cluster.get("fips"),
|
|
181
|
+
fips=cluster.get("fips") or False,
|
|
182
182
|
)
|
|
183
183
|
|
|
184
184
|
if not cluster["ccs"]["enabled"]:
|
|
185
|
-
cluster_spec_data = spec.
|
|
185
|
+
cluster_spec_data = spec.model_dump()
|
|
186
186
|
cluster_spec_data["storage"] = (
|
|
187
187
|
cluster["storage_quota"]["value"] // BYTES_IN_GIGABYTE
|
|
188
188
|
)
|
|
@@ -229,7 +229,7 @@ class OCMProductOsd(OCMProduct):
|
|
|
229
229
|
"compute_machine_type": {"id": default_machine_pool.instance_type},
|
|
230
230
|
}
|
|
231
231
|
if default_machine_pool.autoscale is not None:
|
|
232
|
-
spec["autoscale_compute"] = default_machine_pool.autoscale.
|
|
232
|
+
spec["autoscale_compute"] = default_machine_pool.autoscale.model_dump()
|
|
233
233
|
else:
|
|
234
234
|
spec["compute"] = default_machine_pool.replicas
|
|
235
235
|
return spec
|
|
@@ -259,7 +259,7 @@ class OCMProductOsd(OCMProduct):
|
|
|
259
259
|
if (duwm := cluster.spec.disable_user_workload_monitoring) is not None
|
|
260
260
|
else True
|
|
261
261
|
),
|
|
262
|
-
"fips":
|
|
262
|
+
"fips": cluster.spec.fips,
|
|
263
263
|
}
|
|
264
264
|
|
|
265
265
|
# Workaround to enable type checks.
|
|
@@ -429,7 +429,7 @@ class OCMProductRosa(OCMProduct):
|
|
|
429
429
|
subnet_ids=cluster["aws"].get("subnet_ids"),
|
|
430
430
|
availability_zones=cluster["nodes"].get("availability_zones"),
|
|
431
431
|
oidc_endpoint_url=oidc_endpoint_url,
|
|
432
|
-
fips=cluster.get("fips"),
|
|
432
|
+
fips=cluster.get("fips") or False,
|
|
433
433
|
)
|
|
434
434
|
|
|
435
435
|
machine_pools = [
|
|
@@ -474,7 +474,7 @@ class OCMProductRosa(OCMProduct):
|
|
|
474
474
|
"compute_machine_type": {"id": default_machine_pool.instance_type},
|
|
475
475
|
}
|
|
476
476
|
if default_machine_pool.autoscale is not None:
|
|
477
|
-
spec["autoscale_compute"] = default_machine_pool.autoscale.
|
|
477
|
+
spec["autoscale_compute"] = default_machine_pool.autoscale.model_dump()
|
|
478
478
|
else:
|
|
479
479
|
spec["compute"] = default_machine_pool.replicas
|
|
480
480
|
return spec
|
|
@@ -517,7 +517,7 @@ class OCMProductRosa(OCMProduct):
|
|
|
517
517
|
if (duwm := cluster.spec.disable_user_workload_monitoring) is not None
|
|
518
518
|
else True
|
|
519
519
|
),
|
|
520
|
-
"fips":
|
|
520
|
+
"fips": cluster.spec.fips,
|
|
521
521
|
}
|
|
522
522
|
|
|
523
523
|
provision_shard_id = cluster.spec.provision_shard_id
|
|
@@ -706,7 +706,7 @@ class OCMProductHypershift(OCMProduct):
|
|
|
706
706
|
availability_zones=cluster["nodes"].get("availability_zones"),
|
|
707
707
|
hypershift=cluster["hypershift"]["enabled"],
|
|
708
708
|
oidc_endpoint_url=oidc_endpoint_url,
|
|
709
|
-
fips=cluster.get("fips"),
|
|
709
|
+
fips=cluster.get("fips") or False,
|
|
710
710
|
)
|
|
711
711
|
|
|
712
712
|
network = OCMClusterNetwork(
|
|
@@ -5,7 +5,6 @@ from abc import (
|
|
|
5
5
|
from collections.abc import Iterable
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from datetime import (
|
|
8
|
-
UTC,
|
|
9
8
|
datetime,
|
|
10
9
|
)
|
|
11
10
|
from enum import Enum
|
|
@@ -16,6 +15,8 @@ from typing import (
|
|
|
16
15
|
|
|
17
16
|
import dateparser
|
|
18
17
|
|
|
18
|
+
from reconcile.utils.datetime_util import utc_now
|
|
19
|
+
|
|
19
20
|
|
|
20
21
|
@dataclass
|
|
21
22
|
class FilterCondition:
|
|
@@ -166,17 +167,13 @@ class DateRangeCondition(FilterCondition):
|
|
|
166
167
|
return date
|
|
167
168
|
parsed = dateparser.parse(
|
|
168
169
|
date,
|
|
169
|
-
settings={"RELATIVE_BASE":
|
|
170
|
+
settings={"RELATIVE_BASE": utc_now()},
|
|
170
171
|
)
|
|
171
172
|
if parsed is None:
|
|
172
173
|
raise InvalidFilterError(f"Invalid relative date: {date}")
|
|
173
174
|
|
|
174
175
|
return parsed
|
|
175
176
|
|
|
176
|
-
@staticmethod
|
|
177
|
-
def now() -> datetime:
|
|
178
|
-
return datetime.now(tz=UTC)
|
|
179
|
-
|
|
180
177
|
|
|
181
178
|
class InvalidFilterError(Exception):
|
|
182
179
|
pass
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
from collections.abc import Generator
|
|
2
|
-
from datetime import
|
|
3
|
-
datetime,
|
|
4
|
-
timedelta,
|
|
5
|
-
)
|
|
2
|
+
from datetime import timedelta
|
|
6
3
|
|
|
4
|
+
from reconcile.utils.datetime_util import utc_now
|
|
7
5
|
from reconcile.utils.ocm.base import (
|
|
8
6
|
OCMClusterServiceLog,
|
|
9
7
|
OCMClusterServiceLogCreateModel,
|
|
@@ -47,7 +45,7 @@ def create_service_log(
|
|
|
47
45
|
.eq("severity", service_log.severity.value)
|
|
48
46
|
.eq("summary", service_log.summary)
|
|
49
47
|
.eq("description", service_log.description)
|
|
50
|
-
.after("created_at",
|
|
48
|
+
.after("created_at", utc_now() - dedup_interval),
|
|
51
49
|
),
|
|
52
50
|
None,
|
|
53
51
|
)
|
|
@@ -57,6 +55,6 @@ def create_service_log(
|
|
|
57
55
|
return OCMClusterServiceLog(
|
|
58
56
|
**ocm_api.post(
|
|
59
57
|
api_path=CLUSTER_SERVICE_LOGS_CREATE_ENDPOINT,
|
|
60
|
-
data=service_log.
|
|
58
|
+
data=service_log.model_dump(by_alias=True),
|
|
61
59
|
)
|
|
62
60
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
-
from pydantic import
|
|
4
|
-
from pydantic.fields import
|
|
3
|
+
from pydantic import WithJsonSchema
|
|
4
|
+
from pydantic.fields import FieldInfo
|
|
5
5
|
|
|
6
6
|
from reconcile.utils.ocm.base import (
|
|
7
7
|
LabelContainer,
|
|
@@ -22,11 +22,11 @@ def sre_capability_label_key(
|
|
|
22
22
|
return f"sre-capabilities.{sre_capability}.{config_atom}"
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
def labelset_groupfield(group_prefix: str) ->
|
|
25
|
+
def labelset_groupfield(group_prefix: str) -> WithJsonSchema:
|
|
26
26
|
"""
|
|
27
27
|
Helper function to build the FieldMeta for a labelset field that groups labels.
|
|
28
28
|
"""
|
|
29
|
-
return
|
|
29
|
+
return WithJsonSchema({"group_by_prefix": group_prefix})
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
def build_labelset(
|
|
@@ -36,16 +36,23 @@ def build_labelset(
|
|
|
36
36
|
Instantiates a dataclass from a set of labels.
|
|
37
37
|
"""
|
|
38
38
|
raw_data = {
|
|
39
|
-
field.alias: _labelset_field_value(labels, field)
|
|
40
|
-
for field in dataclass.
|
|
39
|
+
field.alias or name: _labelset_field_value(labels, name, field)
|
|
40
|
+
for name, field in dataclass.model_fields.items()
|
|
41
41
|
}
|
|
42
42
|
return dataclass(**raw_data)
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
def _labelset_field_value(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
def _labelset_field_value(
|
|
46
|
+
labels: LabelContainer, name: str, field: FieldInfo
|
|
47
|
+
) -> Any | None:
|
|
48
|
+
schema = next((m for m in field.metadata if isinstance(m, WithJsonSchema)), None)
|
|
49
|
+
if (
|
|
50
|
+
schema is None
|
|
51
|
+
or not schema.json_schema
|
|
52
|
+
or "group_by_prefix" not in schema.json_schema
|
|
53
|
+
):
|
|
54
|
+
return labels.get_label_value(field.alias or name)
|
|
55
|
+
|
|
56
|
+
return build_container_for_prefix(
|
|
57
|
+
labels, schema.json_schema["group_by_prefix"], strip_key_prefix=True
|
|
58
|
+
).get_values_dict()
|
|
@@ -4,8 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
import base64
|
|
5
5
|
import contextlib
|
|
6
6
|
import copy
|
|
7
|
-
import datetime
|
|
8
7
|
import hashlib
|
|
8
|
+
import logging
|
|
9
9
|
import re
|
|
10
10
|
from threading import Lock
|
|
11
11
|
from typing import TYPE_CHECKING, Any
|
|
@@ -14,6 +14,7 @@ import semver
|
|
|
14
14
|
from pydantic import BaseModel
|
|
15
15
|
|
|
16
16
|
from reconcile.external_resources.meta import SECRET_UPDATED_AT
|
|
17
|
+
from reconcile.utils.datetime_util import to_utc_seconds_iso_format, utc_now
|
|
17
18
|
from reconcile.utils.json import json_dumps
|
|
18
19
|
from reconcile.utils.metrics import GaugeMetric
|
|
19
20
|
|
|
@@ -368,8 +369,8 @@ class OpenshiftResource:
|
|
|
368
369
|
annotations[QONTRACT_ANNOTATION_INTEGRATION] = self.integration
|
|
369
370
|
annotations[QONTRACT_ANNOTATION_INTEGRATION_VERSION] = self.integration_version
|
|
370
371
|
annotations[QONTRACT_ANNOTATION_SHA256SUM] = sha256sum
|
|
371
|
-
now =
|
|
372
|
-
annotations[QONTRACT_ANNOTATION_UPDATE] = now
|
|
372
|
+
now = utc_now()
|
|
373
|
+
annotations[QONTRACT_ANNOTATION_UPDATE] = to_utc_seconds_iso_format(now)
|
|
373
374
|
if self.caller_name:
|
|
374
375
|
annotations[QONTRACT_ANNOTATION_CALLER_NAME] = self.caller_name
|
|
375
376
|
|
|
@@ -601,6 +602,10 @@ class ResourceInventory:
|
|
|
601
602
|
resource: OpenshiftResource,
|
|
602
603
|
privileged: bool = False,
|
|
603
604
|
) -> None:
|
|
605
|
+
if cluster not in self._clusters:
|
|
606
|
+
logging.error(f"Cluster {cluster} not initialized in ResourceInventory")
|
|
607
|
+
return
|
|
608
|
+
|
|
604
609
|
if resource.kind_and_group in self._clusters[cluster][namespace]:
|
|
605
610
|
kind = resource.kind_and_group
|
|
606
611
|
else:
|
reconcile/utils/pagerduty_api.py
CHANGED
|
@@ -3,8 +3,7 @@ from collections.abc import (
|
|
|
3
3
|
Callable,
|
|
4
4
|
Iterable,
|
|
5
5
|
)
|
|
6
|
-
from datetime import datetime
|
|
7
|
-
from datetime import timedelta
|
|
6
|
+
from datetime import datetime, timedelta
|
|
8
7
|
from typing import (
|
|
9
8
|
Protocol,
|
|
10
9
|
)
|
|
@@ -14,6 +13,7 @@ import requests
|
|
|
14
13
|
from pydantic import BaseModel
|
|
15
14
|
from sretoolbox.utils import retry
|
|
16
15
|
|
|
16
|
+
from reconcile.utils.datetime_util import utc_now
|
|
17
17
|
from reconcile.utils.secret_reader import (
|
|
18
18
|
HasSecret,
|
|
19
19
|
SecretReader,
|
|
@@ -52,10 +52,13 @@ class PagerDutyTarget(Protocol):
|
|
|
52
52
|
which must be implemented by a class to be compatible."""
|
|
53
53
|
|
|
54
54
|
name: str
|
|
55
|
-
instance: PagerDutyInstance
|
|
56
55
|
escalation_policy_id: str | None
|
|
57
56
|
schedule_id: str | None
|
|
58
57
|
|
|
58
|
+
@property
|
|
59
|
+
def instance(self) -> PagerDutyInstance:
|
|
60
|
+
pass
|
|
61
|
+
|
|
59
62
|
|
|
60
63
|
class PagerDutyConfig(BaseModel):
|
|
61
64
|
"""PagerDuty Config."""
|
|
@@ -80,7 +83,7 @@ class PagerDutyApi:
|
|
|
80
83
|
def get_pagerduty_users(
|
|
81
84
|
self, resource_type: str, resource_id: str
|
|
82
85
|
) -> list[pypd.User]:
|
|
83
|
-
now =
|
|
86
|
+
now = utc_now()
|
|
84
87
|
|
|
85
88
|
try:
|
|
86
89
|
if resource_type == "schedule":
|
|
@@ -103,7 +106,7 @@ class PagerDutyApi:
|
|
|
103
106
|
self.users.append(user)
|
|
104
107
|
return user.email.split("@")[0]
|
|
105
108
|
|
|
106
|
-
def get_schedule_users(self, schedule_id: str, now:
|
|
109
|
+
def get_schedule_users(self, schedule_id: str, now: datetime) -> list[pypd.User]:
|
|
107
110
|
until = now + timedelta(seconds=60)
|
|
108
111
|
s = pypd.Schedule.fetch(id=schedule_id, since=now, until=until, time_zone="UTC")
|
|
109
112
|
entries = s["final_schedule"]["rendered_schedule_entries"]
|
|
@@ -115,7 +118,7 @@ class PagerDutyApi:
|
|
|
115
118
|
]
|
|
116
119
|
|
|
117
120
|
def get_escalation_policy_users(
|
|
118
|
-
self, escalation_policy_id: str, now:
|
|
121
|
+
self, escalation_policy_id: str, now: datetime
|
|
119
122
|
) -> list[pypd.User]:
|
|
120
123
|
ep = pypd.EscalationPolicy.fetch(
|
|
121
124
|
id=escalation_policy_id, since=now, until=now, time_zone="UTC"
|
|
@@ -189,7 +192,7 @@ def get_pagerduty_name(user: PagerDutyUser) -> str:
|
|
|
189
192
|
return user.pagerduty_username or user.org_username
|
|
190
193
|
|
|
191
194
|
|
|
192
|
-
@retry(no_retry_exceptions=PagerDutyTargetError)
|
|
195
|
+
@retry(no_retry_exceptions=(PagerDutyTargetError,))
|
|
193
196
|
def get_usernames_from_pagerduty(
|
|
194
197
|
pagerduties: Iterable[PagerDutyTarget],
|
|
195
198
|
users: Iterable[PagerDutyUser],
|
|
@@ -3,13 +3,12 @@ from collections import defaultdict
|
|
|
3
3
|
|
|
4
4
|
from pydantic import (
|
|
5
5
|
BaseModel,
|
|
6
|
-
Extra,
|
|
7
6
|
)
|
|
8
7
|
|
|
9
8
|
from reconcile.utils.state import State
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
class PromotionData(BaseModel):
|
|
11
|
+
class PromotionData(BaseModel, extra="forbid"):
|
|
13
12
|
"""
|
|
14
13
|
A class that strictly corresponds to the json stored in S3.
|
|
15
14
|
|
|
@@ -20,17 +19,13 @@ class PromotionData(BaseModel):
|
|
|
20
19
|
|
|
21
20
|
# The success is primarily used for SAPM auto-promotions
|
|
22
21
|
success: bool
|
|
23
|
-
target_config_hash: str | None
|
|
24
|
-
saas_file: str | None
|
|
25
|
-
check_in: str | None
|
|
22
|
+
target_config_hash: str | None = None
|
|
23
|
+
saas_file: str | None = None
|
|
24
|
+
check_in: str | None = None
|
|
26
25
|
# Whether this promotion has ever succeeded
|
|
27
26
|
# Note, this shouldnt be overridden on subsequent promotions of same ref
|
|
28
27
|
# This attribute is primarily used by saasherder validations
|
|
29
|
-
has_succeeded_once: bool | None
|
|
30
|
-
|
|
31
|
-
class Config:
|
|
32
|
-
smart_union = True
|
|
33
|
-
extra = Extra.forbid
|
|
28
|
+
has_succeeded_once: bool | None = None
|
|
34
29
|
|
|
35
30
|
|
|
36
31
|
class PromotionState:
|
|
@@ -107,5 +102,5 @@ class PromotionState:
|
|
|
107
102
|
self, sha: str, channel: str, target_uid: str, data: PromotionData
|
|
108
103
|
) -> None:
|
|
109
104
|
state_key_v2 = f"promotions_v2/{channel}/{target_uid}/{sha}"
|
|
110
|
-
self._state.add(state_key_v2, data.
|
|
105
|
+
self._state.add(state_key_v2, data.model_dump(), force=True)
|
|
111
106
|
logging.info("Uploaded %s to %s", data, state_key_v2)
|
|
@@ -76,7 +76,7 @@ class RawGithubApi:
|
|
|
76
76
|
if login is not None
|
|
77
77
|
]
|
|
78
78
|
|
|
79
|
-
def team_invitations(self, org_id: str, team_id: str) -> list[str]:
|
|
79
|
+
def team_invitations(self, org_id: str | int, team_id: str | int) -> list[str]:
|
|
80
80
|
invitations = self.query(f"/organizations/{org_id}/team/{team_id}/invitations")
|
|
81
81
|
|
|
82
82
|
return [
|
reconcile/utils/rhcsv2_certs.py
CHANGED
|
@@ -1,22 +1,33 @@
|
|
|
1
|
+
import base64
|
|
1
2
|
import re
|
|
2
3
|
from datetime import UTC
|
|
4
|
+
from enum import StrEnum
|
|
3
5
|
|
|
4
6
|
import requests
|
|
5
7
|
from cryptography import x509
|
|
6
8
|
from cryptography.hazmat.primitives import hashes, serialization
|
|
7
9
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
10
|
+
from cryptography.hazmat.primitives.serialization import pkcs12
|
|
8
11
|
from cryptography.x509.oid import NameOID
|
|
9
12
|
from pydantic import BaseModel, Field
|
|
10
13
|
|
|
11
14
|
|
|
12
|
-
class
|
|
15
|
+
class CertificateFormat(StrEnum):
|
|
16
|
+
PEM = "PEM"
|
|
17
|
+
PKCS12 = "PKCS12"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RhcsV2CertPem(BaseModel, validate_by_name=True, validate_by_alias=True):
|
|
13
21
|
certificate: str = Field(alias="tls.crt")
|
|
14
22
|
private_key: str = Field(alias="tls.key")
|
|
15
23
|
ca_cert: str = Field(alias="ca.crt")
|
|
16
24
|
expiration_timestamp: int
|
|
17
25
|
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
|
|
27
|
+
class RhcsV2CertPkcs12(BaseModel, validate_by_name=True, validate_by_alias=True):
|
|
28
|
+
pkcs12_keystore: str = Field(alias="keystore.pkcs12.b64")
|
|
29
|
+
pkcs12_truststore: str = Field(alias="truststore.pkcs12.b64")
|
|
30
|
+
expiration_timestamp: int
|
|
20
31
|
|
|
21
32
|
|
|
22
33
|
def extract_cert(text: str) -> re.Match:
|
|
@@ -70,7 +81,66 @@ def get_cert_expiry_timestamp(js_escaped_pem: str) -> int:
|
|
|
70
81
|
return int(dt_expiry.timestamp())
|
|
71
82
|
|
|
72
83
|
|
|
73
|
-
def
|
|
84
|
+
def _format_pem(
|
|
85
|
+
private_key: rsa.RSAPrivateKey,
|
|
86
|
+
cert_pem: str,
|
|
87
|
+
ca_pem: str,
|
|
88
|
+
cert_expiry_timestamp: int,
|
|
89
|
+
) -> RhcsV2CertPem:
|
|
90
|
+
"""Generate RhcsV2Cert with PEM components."""
|
|
91
|
+
private_key_pem = private_key.private_bytes(
|
|
92
|
+
encoding=serialization.Encoding.PEM,
|
|
93
|
+
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
|
94
|
+
encryption_algorithm=serialization.NoEncryption(),
|
|
95
|
+
).decode()
|
|
96
|
+
return RhcsV2CertPem(
|
|
97
|
+
private_key=private_key_pem,
|
|
98
|
+
certificate=cert_pem.encode().decode("unicode_escape").replace("\\/", "/"),
|
|
99
|
+
ca_cert=ca_pem,
|
|
100
|
+
expiration_timestamp=cert_expiry_timestamp,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _format_pkcs12(
|
|
105
|
+
private_key: rsa.RSAPrivateKey,
|
|
106
|
+
cert_pem: str,
|
|
107
|
+
ca_pem: str,
|
|
108
|
+
uid: str,
|
|
109
|
+
pwd: str,
|
|
110
|
+
cert_expiry_timestamp: int,
|
|
111
|
+
) -> RhcsV2CertPkcs12:
|
|
112
|
+
"""Generate PKCS#12 keystore and truststore components, returns base64-encoded strings."""
|
|
113
|
+
clean_cert_pem = cert_pem.encode().decode("unicode_escape").replace("\\/", "/")
|
|
114
|
+
cert_obj = x509.load_pem_x509_certificate(clean_cert_pem.encode())
|
|
115
|
+
ca_obj = x509.load_pem_x509_certificate(ca_pem.encode())
|
|
116
|
+
keystore_p12 = pkcs12.serialize_key_and_certificates(
|
|
117
|
+
name=uid.encode("utf-8"),
|
|
118
|
+
key=private_key,
|
|
119
|
+
cert=cert_obj,
|
|
120
|
+
cas=[ca_obj],
|
|
121
|
+
encryption_algorithm=serialization.BestAvailableEncryption(pwd.encode("utf-8")),
|
|
122
|
+
)
|
|
123
|
+
truststore_p12 = pkcs12.serialize_key_and_certificates(
|
|
124
|
+
name=b"ca-trust",
|
|
125
|
+
key=None,
|
|
126
|
+
cert=None,
|
|
127
|
+
cas=[ca_obj],
|
|
128
|
+
encryption_algorithm=serialization.NoEncryption(),
|
|
129
|
+
)
|
|
130
|
+
return RhcsV2CertPkcs12(
|
|
131
|
+
pkcs12_keystore=base64.b64encode(keystore_p12).decode("utf-8"),
|
|
132
|
+
pkcs12_truststore=base64.b64encode(truststore_p12).decode("utf-8"),
|
|
133
|
+
expiration_timestamp=cert_expiry_timestamp,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def generate_cert(
|
|
138
|
+
issuer_url: str,
|
|
139
|
+
uid: str,
|
|
140
|
+
pwd: str,
|
|
141
|
+
ca_url: str,
|
|
142
|
+
cert_format: CertificateFormat = CertificateFormat.PEM,
|
|
143
|
+
) -> RhcsV2CertPem | RhcsV2CertPkcs12:
|
|
74
144
|
private_key = rsa.generate_private_key(65537, 4096)
|
|
75
145
|
csr = (
|
|
76
146
|
x509.CertificateSigningRequestBuilder()
|
|
@@ -81,6 +151,7 @@ def generate_cert(issuer_url: str, uid: str, pwd: str, ca_url: str) -> RhcsV2Cer
|
|
|
81
151
|
)
|
|
82
152
|
.sign(private_key, hashes.SHA256())
|
|
83
153
|
)
|
|
154
|
+
|
|
84
155
|
data = {
|
|
85
156
|
"uid": uid,
|
|
86
157
|
"pwd": pwd,
|
|
@@ -90,27 +161,19 @@ def generate_cert(issuer_url: str, uid: str, pwd: str, ca_url: str) -> RhcsV2Cer
|
|
|
90
161
|
"renewal": "false",
|
|
91
162
|
"xmlOutput": "false",
|
|
92
163
|
}
|
|
93
|
-
response = requests.post(issuer_url, data=data)
|
|
164
|
+
response = requests.post(issuer_url, data=data, timeout=30)
|
|
94
165
|
response.raise_for_status()
|
|
166
|
+
cert_pem = extract_cert(response.text).group(1)
|
|
167
|
+
cert_expiry_timestamp = get_cert_expiry_timestamp(cert_pem)
|
|
95
168
|
|
|
96
|
-
|
|
97
|
-
cert_expiry_timestamp = get_cert_expiry_timestamp(cert_pem.group(1))
|
|
98
|
-
private_key_pem = private_key.private_bytes(
|
|
99
|
-
encoding=serialization.Encoding.PEM,
|
|
100
|
-
format=serialization.PrivateFormat.TraditionalOpenSSL,
|
|
101
|
-
encryption_algorithm=serialization.NoEncryption(),
|
|
102
|
-
).decode()
|
|
103
|
-
|
|
104
|
-
response = requests.get(ca_url)
|
|
169
|
+
response = requests.get(ca_url, timeout=30)
|
|
105
170
|
response.raise_for_status()
|
|
106
171
|
ca_pem = response.text
|
|
107
172
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
.
|
|
114
|
-
|
|
115
|
-
expiration_timestamp=cert_expiry_timestamp,
|
|
116
|
-
)
|
|
173
|
+
match cert_format:
|
|
174
|
+
case CertificateFormat.PKCS12:
|
|
175
|
+
return _format_pkcs12(
|
|
176
|
+
private_key, cert_pem, ca_pem, uid, pwd, cert_expiry_timestamp
|
|
177
|
+
)
|
|
178
|
+
case CertificateFormat.PEM:
|
|
179
|
+
return _format_pem(private_key, cert_pem, ca_pem, cert_expiry_timestamp)
|
reconcile/utils/rosa/session.py
CHANGED
|
@@ -178,6 +178,22 @@ class RosaSession:
|
|
|
178
178
|
)
|
|
179
179
|
result.write_logs_to_logger(logging.info)
|
|
180
180
|
|
|
181
|
+
def upgrade_rosa_roles(
|
|
182
|
+
self,
|
|
183
|
+
cluster_name: str,
|
|
184
|
+
upgrade_version: str,
|
|
185
|
+
policy_version: str,
|
|
186
|
+
dry_run: bool,
|
|
187
|
+
) -> None:
|
|
188
|
+
logging.info(
|
|
189
|
+
f"Upgrade roles in AWS account {self.aws_account_id} to {upgrade_version}"
|
|
190
|
+
)
|
|
191
|
+
if not dry_run:
|
|
192
|
+
result = self.cli_execute(
|
|
193
|
+
f"rosa upgrade roles -c {cluster_name} --cluster-version {upgrade_version} --policy-version {policy_version} -y -m=auto"
|
|
194
|
+
)
|
|
195
|
+
result.write_logs_to_logger(logging.info)
|
|
196
|
+
|
|
181
197
|
|
|
182
198
|
def generate_rosa_creation_script(
|
|
183
199
|
cluster_name: str, cluster: OCMSpec, dry_run: bool
|
|
@@ -7,7 +7,6 @@ from dataclasses import dataclass
|
|
|
7
7
|
from types import ModuleType
|
|
8
8
|
from typing import (
|
|
9
9
|
Any,
|
|
10
|
-
Generic,
|
|
11
10
|
Optional,
|
|
12
11
|
TypeVar,
|
|
13
12
|
)
|
|
@@ -120,7 +119,7 @@ class PydanticRunParams(RunParams, BaseModel):
|
|
|
120
119
|
def copy_and_update(
|
|
121
120
|
self: PydanticRunParamsSelfTypeVar, update: dict[str, Any]
|
|
122
121
|
) -> PydanticRunParamsSelfTypeVar:
|
|
123
|
-
return self.
|
|
122
|
+
return self.model_copy(update=update)
|
|
124
123
|
|
|
125
124
|
def get(self, field: str) -> Any:
|
|
126
125
|
return getattr(self, field)
|
|
@@ -144,7 +143,7 @@ IntegrationClassTypeVar = TypeVar(
|
|
|
144
143
|
)
|
|
145
144
|
|
|
146
145
|
|
|
147
|
-
class QontractReconcileIntegration
|
|
146
|
+
class QontractReconcileIntegration[RunParamsTypeVar: RunParams](ABC):
|
|
148
147
|
"""
|
|
149
148
|
The base class for all integrations. It defines the basic interface to interact
|
|
150
149
|
with an integration and offers hook methods that allow the integration to opt
|