qontract-reconcile 0.10.2.dev345__py3-none-any.whl → 0.10.2.dev408__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.
Files changed (126) hide show
  1. {qontract_reconcile-0.10.2.dev345.dist-info → qontract_reconcile-0.10.2.dev408.dist-info}/METADATA +11 -10
  2. {qontract_reconcile-0.10.2.dev345.dist-info → qontract_reconcile-0.10.2.dev408.dist-info}/RECORD +126 -120
  3. reconcile/aus/base.py +17 -14
  4. reconcile/automated_actions/config/integration.py +12 -0
  5. reconcile/aws_account_manager/integration.py +2 -2
  6. reconcile/aws_ami_cleanup/integration.py +6 -7
  7. reconcile/aws_ami_share.py +69 -62
  8. reconcile/aws_cloudwatch_log_retention/integration.py +155 -126
  9. reconcile/aws_ecr_image_pull_secrets.py +2 -2
  10. reconcile/aws_iam_keys.py +1 -0
  11. reconcile/aws_saml_idp/integration.py +7 -1
  12. reconcile/aws_saml_roles/integration.py +9 -3
  13. reconcile/change_owners/change_owners.py +1 -1
  14. reconcile/change_owners/diff.py +2 -4
  15. reconcile/checkpoint.py +11 -3
  16. reconcile/cli.py +33 -8
  17. reconcile/dashdotdb_dora.py +4 -11
  18. reconcile/database_access_manager.py +118 -111
  19. reconcile/endpoints_discovery/integration.py +4 -1
  20. reconcile/endpoints_discovery/merge_request_manager.py +9 -11
  21. reconcile/external_resources/factories.py +5 -12
  22. reconcile/external_resources/integration.py +1 -1
  23. reconcile/external_resources/manager.py +5 -3
  24. reconcile/external_resources/meta.py +0 -1
  25. reconcile/external_resources/model.py +10 -10
  26. reconcile/external_resources/reconciler.py +5 -2
  27. reconcile/external_resources/secrets_sync.py +4 -6
  28. reconcile/external_resources/state.py +5 -4
  29. reconcile/gabi_authorized_users.py +8 -5
  30. reconcile/gitlab_housekeeping.py +13 -15
  31. reconcile/gitlab_mr_sqs_consumer.py +2 -2
  32. reconcile/gitlab_owners.py +15 -11
  33. reconcile/gql_definitions/automated_actions/instance.py +41 -2
  34. reconcile/gql_definitions/aws_ami_cleanup/aws_accounts.py +10 -0
  35. reconcile/gql_definitions/aws_cloudwatch_log_retention/aws_accounts.py +22 -61
  36. reconcile/gql_definitions/aws_saml_idp/aws_accounts.py +10 -0
  37. reconcile/gql_definitions/aws_saml_roles/aws_accounts.py +10 -0
  38. reconcile/gql_definitions/common/aws_vpc_requests.py +10 -0
  39. reconcile/gql_definitions/common/clusters.py +2 -0
  40. reconcile/gql_definitions/external_resources/external_resources_namespaces.py +84 -1
  41. reconcile/gql_definitions/external_resources/external_resources_settings.py +2 -0
  42. reconcile/gql_definitions/fragments/aws_account_common.py +2 -0
  43. reconcile/gql_definitions/fragments/aws_organization.py +33 -0
  44. reconcile/gql_definitions/fragments/aws_vpc_request.py +2 -0
  45. reconcile/gql_definitions/introspection.json +3474 -1986
  46. reconcile/gql_definitions/jira_permissions_validator/jira_boards_for_permissions_validator.py +4 -0
  47. reconcile/gql_definitions/terraform_init/aws_accounts.py +14 -0
  48. reconcile/gql_definitions/terraform_resources/terraform_resources_namespaces.py +33 -1
  49. reconcile/gql_definitions/terraform_tgw_attachments/aws_accounts.py +10 -0
  50. reconcile/jenkins_worker_fleets.py +1 -0
  51. reconcile/jira_permissions_validator.py +236 -121
  52. reconcile/ocm/types.py +6 -0
  53. reconcile/openshift_base.py +47 -1
  54. reconcile/openshift_cluster_bots.py +2 -1
  55. reconcile/openshift_resources_base.py +6 -2
  56. reconcile/openshift_saas_deploy.py +2 -2
  57. reconcile/openshift_saas_deploy_trigger_cleaner.py +3 -5
  58. reconcile/openshift_upgrade_watcher.py +3 -3
  59. reconcile/queries.py +131 -0
  60. reconcile/saas_auto_promotions_manager/subscriber.py +4 -3
  61. reconcile/slack_usergroups.py +4 -3
  62. reconcile/sql_query.py +1 -0
  63. reconcile/statuspage/integrations/maintenances.py +4 -3
  64. reconcile/statuspage/status.py +5 -8
  65. reconcile/templates/rosa-classic-cluster-creation.sh.j2 +4 -0
  66. reconcile/templates/rosa-hcp-cluster-creation.sh.j2 +3 -0
  67. reconcile/templating/renderer.py +2 -1
  68. reconcile/terraform_aws_route53.py +7 -1
  69. reconcile/terraform_init/integration.py +185 -21
  70. reconcile/terraform_resources.py +11 -1
  71. reconcile/terraform_tgw_attachments.py +7 -1
  72. reconcile/terraform_users.py +7 -0
  73. reconcile/terraform_vpc_peerings.py +14 -3
  74. reconcile/terraform_vpc_resources/integration.py +7 -0
  75. reconcile/typed_queries/aws_account_tags.py +41 -0
  76. reconcile/typed_queries/saas_files.py +2 -2
  77. reconcile/utils/aggregated_list.py +4 -3
  78. reconcile/utils/aws_api.py +51 -20
  79. reconcile/utils/aws_api_typed/api.py +38 -9
  80. reconcile/utils/aws_api_typed/cloudformation.py +149 -0
  81. reconcile/utils/aws_api_typed/logs.py +73 -0
  82. reconcile/utils/datetime_util.py +67 -0
  83. reconcile/utils/differ.py +2 -3
  84. reconcile/utils/early_exit_cache.py +3 -2
  85. reconcile/utils/expiration.py +7 -3
  86. reconcile/utils/external_resource_spec.py +24 -1
  87. reconcile/utils/filtering.py +1 -1
  88. reconcile/utils/helm.py +2 -1
  89. reconcile/utils/helpers.py +1 -1
  90. reconcile/utils/jinja2/utils.py +4 -96
  91. reconcile/utils/jira_client.py +82 -63
  92. reconcile/utils/jjb_client.py +9 -12
  93. reconcile/utils/jobcontroller/controller.py +1 -1
  94. reconcile/utils/jobcontroller/models.py +17 -1
  95. reconcile/utils/json.py +32 -0
  96. reconcile/utils/merge_request_manager/merge_request_manager.py +3 -3
  97. reconcile/utils/merge_request_manager/parser.py +2 -2
  98. reconcile/utils/mr/app_interface_reporter.py +2 -2
  99. reconcile/utils/mr/base.py +2 -2
  100. reconcile/utils/mr/notificator.py +2 -2
  101. reconcile/utils/mr/update_access_report_base.py +3 -4
  102. reconcile/utils/oc.py +113 -95
  103. reconcile/utils/oc_filters.py +3 -3
  104. reconcile/utils/ocm/products.py +6 -0
  105. reconcile/utils/ocm/search_filters.py +3 -6
  106. reconcile/utils/ocm/service_log.py +3 -5
  107. reconcile/utils/openshift_resource.py +10 -5
  108. reconcile/utils/output.py +3 -2
  109. reconcile/utils/pagerduty_api.py +5 -5
  110. reconcile/utils/runtime/integration.py +1 -2
  111. reconcile/utils/runtime/runner.py +2 -2
  112. reconcile/utils/saasherder/models.py +2 -1
  113. reconcile/utils/saasherder/saasherder.py +9 -7
  114. reconcile/utils/slack_api.py +24 -2
  115. reconcile/utils/sloth.py +171 -2
  116. reconcile/utils/sqs_gateway.py +2 -1
  117. reconcile/utils/state.py +2 -1
  118. reconcile/utils/terraform_client.py +4 -3
  119. reconcile/utils/terrascript_aws_client.py +165 -111
  120. reconcile/utils/vault.py +1 -1
  121. reconcile/vault_replication.py +107 -42
  122. tools/app_interface_reporter.py +4 -4
  123. tools/cli_commands/systems_and_tools.py +5 -1
  124. tools/qontract_cli.py +25 -13
  125. {qontract_reconcile-0.10.2.dev345.dist-info → qontract_reconcile-0.10.2.dev408.dist-info}/WHEEL +0 -0
  126. {qontract_reconcile-0.10.2.dev345.dist-info → qontract_reconcile-0.10.2.dev408.dist-info}/entry_points.txt +0 -0
@@ -30,9 +30,11 @@ from reconcile.utils import (
30
30
  )
31
31
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
32
32
  from reconcile.utils.oc import (
33
+ AmbiguousResourceTypeError,
33
34
  DeploymentFieldIsImmutableError,
34
35
  FieldIsImmutableError,
35
36
  InvalidValueApplyError,
37
+ KindNotFoundError,
36
38
  MayNotChangeOnceSetError,
37
39
  MetaDataAnnotationsTooLongApplyError,
38
40
  OC_Map,
@@ -128,6 +130,29 @@ class ClusterMap(Protocol):
128
130
  ) -> list[str]: ...
129
131
 
130
132
 
133
+ def validate_managed_resource_types(
134
+ oc: OCCli,
135
+ managed_resource_types: Iterable[str],
136
+ managed_resource_names: Iterable[Mapping[str, Any]],
137
+ cluster_scope_resource_validation: bool,
138
+ ) -> None:
139
+ """Validate the managed resource types."""
140
+ managed_resources = [
141
+ managed_resource_name["resource"]
142
+ for managed_resource_name in managed_resource_names
143
+ ]
144
+ for managed_resource_type in managed_resource_types:
145
+ # The k8s kind must be supported by the cluster
146
+ resource = oc.get_api_resource(managed_resource_type)
147
+
148
+ if cluster_scope_resource_validation and not resource.namespaced:
149
+ # cluster-scoped resources must be use managedResourceNames!
150
+ if managed_resource_type not in managed_resources:
151
+ raise ValidationError(
152
+ f"Cluster-scoped resource {managed_resource_type} must be managed by name only. Please use 'managedResourceNames' field to specify the names of the resources to manage."
153
+ )
154
+
155
+
131
156
  def init_specs_to_fetch(
132
157
  ri: ResourceInventory,
133
158
  oc_map: ClusterMap,
@@ -136,6 +161,7 @@ def init_specs_to_fetch(
136
161
  override_managed_types: Iterable[str] | None = None,
137
162
  managed_types_key: str = "managedResourceTypes",
138
163
  cluster_admin: bool = False,
164
+ cluster_scope_resource_validation: bool = False,
139
165
  ) -> list[StateSpec]:
140
166
  state_specs: list[StateSpec] = []
141
167
 
@@ -163,9 +189,27 @@ def init_specs_to_fetch(
163
189
  logging.log(level=ex.log_level, msg=ex.message)
164
190
  continue
165
191
 
192
+ managed_resource_names = namespace_info.get("managedResourceNames") or []
193
+ try:
194
+ validate_managed_resource_types(
195
+ oc,
196
+ managed_types,
197
+ managed_resource_names,
198
+ cluster_scope_resource_validation=cluster_scope_resource_validation,
199
+ )
200
+ except KindNotFoundError:
201
+ # We must allow kinds that are not supported by the cluster because:
202
+ # 1. We install CRD with an operator in the same MR
203
+ # 2. SAAS files initialize the namespace objects with managedResourceTypes from the SAAS file
204
+ # and we can't expect that all of those are valid for all clusters
205
+ pass
206
+ except (AmbiguousResourceTypeError, ValidationError) as e:
207
+ ri.register_error()
208
+ logging.error(f"[{cluster}/{namespace_info['name']}] {e}")
209
+ continue
210
+
166
211
  namespace = namespace_info["name"]
167
212
  # These may exit but have a value of None
168
- managed_resource_names = namespace_info.get("managedResourceNames") or []
169
213
  managed_resource_type_overrides = (
170
214
  namespace_info.get("managedResourceTypeOverrides") or []
171
215
  )
@@ -340,6 +384,7 @@ def fetch_current_state(
340
384
  cluster_admin: bool = False,
341
385
  caller: str | None = None,
342
386
  init_projects: bool = False,
387
+ cluster_scope_resource_validation: bool = False,
343
388
  ) -> tuple[ResourceInventory, OC_Map]:
344
389
  ri = ResourceInventory()
345
390
  settings = queries.get_app_interface_settings()
@@ -362,6 +407,7 @@ def fetch_current_state(
362
407
  clusters=clusters,
363
408
  override_managed_types=override_managed_types,
364
409
  cluster_admin=cluster_admin,
410
+ cluster_scope_resource_validation=cluster_scope_resource_validation,
365
411
  )
366
412
  threaded.run(
367
413
  populate_current_state,
@@ -16,6 +16,7 @@ from reconcile.gql_definitions.openshift_cluster_bots.clusters import ClusterV1
16
16
  from reconcile.status import ExitCodes
17
17
  from reconcile.utils import gql
18
18
  from reconcile.utils.disabled_integrations import integration_is_enabled
19
+ from reconcile.utils.json import json_dumps
19
20
  from reconcile.utils.mr import clusters_updates
20
21
  from reconcile.utils.ocm import OCM, OCMMap
21
22
  from reconcile.utils.openshift_resource import (
@@ -102,7 +103,7 @@ def oc(
102
103
 
103
104
  def oc_apply(kubeconfig: str, namespace: str, items: list[dict]) -> None:
104
105
  for item in items:
105
- stdin = json.dumps(item).encode()
106
+ stdin = json_dumps(item).encode()
106
107
  oc(kubeconfig, namespace, ["apply", "-f", "-"], stdin)
107
108
 
108
109
 
@@ -806,7 +806,11 @@ def fetch_data(
806
806
  init_api_resources=init_api_resources,
807
807
  )
808
808
  state_specs = ob.init_specs_to_fetch(
809
- ri, oc_map, namespaces=namespaces, override_managed_types=overrides
809
+ ri,
810
+ oc_map,
811
+ namespaces=namespaces,
812
+ override_managed_types=overrides,
813
+ cluster_scope_resource_validation=True,
810
814
  )
811
815
  threaded.run(fetch_states, state_specs, thread_pool_size, ri=ri, settings=settings)
812
816
 
@@ -861,7 +865,7 @@ def canonicalize_namespaces(
861
865
  elif providers[0] == "route":
862
866
  override = ["Route"]
863
867
  elif providers[0] == "prometheus-rule":
864
- override = ["PrometheusRule"]
868
+ override = ["PrometheusRule.monitoring.coreos.com"]
865
869
 
866
870
  namespace_info["openshiftResources"] = ors
867
871
  canonicalized_namespaces.append(namespace_info)
@@ -1,4 +1,3 @@
1
- import json
2
1
  import logging
3
2
  import os
4
3
  import sys
@@ -28,6 +27,7 @@ from reconcile.typed_queries.saas_files import (
28
27
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
29
28
  from reconcile.utils.defer import defer
30
29
  from reconcile.utils.gitlab_api import GitLabApi
30
+ from reconcile.utils.json import json_dumps
31
31
  from reconcile.utils.openshift_resource import ResourceInventory
32
32
  from reconcile.utils.saasherder import SaasHerder
33
33
  from reconcile.utils.secret_reader import create_secret_reader
@@ -346,4 +346,4 @@ def run(
346
346
  if image_auth.auth_server:
347
347
  json_file = os.path.join(io_dir, "dockerconfigjson")
348
348
  with open(json_file, "w", encoding="locale") as f:
349
- f.write(json.dumps(image_auth.get_docker_config_json(), indent=2))
349
+ f.write(json_dumps(image_auth.get_docker_config_json(), indent=2))
@@ -1,14 +1,11 @@
1
1
  import logging
2
2
  from collections.abc import Callable
3
3
  from datetime import (
4
- UTC,
5
4
  datetime,
6
5
  timedelta,
7
6
  )
8
7
  from typing import Any
9
8
 
10
- from dateutil import parser
11
-
12
9
  from reconcile.gql_definitions.fragments.pipeline_provider_retention import (
13
10
  PipelineProviderRetention,
14
11
  )
@@ -19,6 +16,7 @@ from reconcile.typed_queries.tekton_pipeline_providers import (
19
16
  get_tekton_pipeline_providers,
20
17
  )
21
18
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
19
+ from reconcile.utils.datetime_util import from_utc_iso_format, utc_now
22
20
  from reconcile.utils.defer import defer
23
21
  from reconcile.utils.oc_map import (
24
22
  OCLogMsg,
@@ -35,7 +33,7 @@ def within_retention_days(
35
33
  resource: dict[str, Any], days: int, now_date: datetime
36
34
  ) -> bool:
37
35
  metadata = resource["metadata"]
38
- creation_date = parser.parse(metadata["creationTimestamp"])
36
+ creation_date = from_utc_iso_format(metadata["creationTimestamp"])
39
37
  interval = now_date.timestamp() - creation_date.timestamp()
40
38
 
41
39
  return interval < timedelta(days=days).total_seconds()
@@ -69,7 +67,7 @@ def run(
69
67
  use_jump_host: bool = True,
70
68
  defer: Callable | None = None,
71
69
  ) -> None:
72
- now_date = datetime.now(UTC)
70
+ now_date = utc_now()
73
71
  vault_settings = get_app_interface_vault_settings()
74
72
  secret_reader = create_secret_reader(use_vault=vault_settings.vault)
75
73
  pipeline_providers = get_tekton_pipeline_providers()
@@ -3,7 +3,6 @@ from collections.abc import (
3
3
  Callable,
4
4
  Iterable,
5
5
  )
6
- from datetime import datetime
7
6
 
8
7
  from reconcile import queries
9
8
  from reconcile.gql_definitions.common.clusters import ClusterV1
@@ -13,6 +12,7 @@ from reconcile.typed_queries.app_interface_vault_settings import (
13
12
  )
14
13
  from reconcile.typed_queries.clusters import get_clusters
15
14
  from reconcile.utils.constants import DEFAULT_THREAD_POOL_SIZE
15
+ from reconcile.utils.datetime_util import from_utc_iso_format, utc_now
16
16
  from reconcile.utils.defer import defer
17
17
  from reconcile.utils.oc_map import (
18
18
  OCLogMsg,
@@ -101,7 +101,7 @@ def notify_upgrades_start(
101
101
  state: State,
102
102
  slack: SlackApi | None,
103
103
  ) -> None:
104
- now = datetime.utcnow()
104
+ now = utc_now()
105
105
  for cluster in clusters:
106
106
  if cluster.spec and not cluster.spec.hypershift:
107
107
  upgrade_at, version = _get_start_osd(oc_map, cluster.name)
@@ -113,7 +113,7 @@ def notify_upgrades_start(
113
113
  continue
114
114
 
115
115
  if upgrade_at and version:
116
- upgrade_at_obj = datetime.strptime(upgrade_at, "%Y-%m-%dT%H:%M:%SZ")
116
+ upgrade_at_obj = from_utc_iso_format(upgrade_at)
117
117
  state_key = f"{cluster.name}-{upgrade_at}1"
118
118
  # if this is the first iteration in which 'now' had passed
119
119
  # the upgrade at date time, we send a notification
reconcile/queries.py CHANGED
@@ -477,6 +477,12 @@ AWS_ACCOUNTS_QUERY = """
477
477
  integrations
478
478
  }
479
479
  deleteKeys
480
+ organization {
481
+ payerAccount {
482
+ organizationAccountTags
483
+ }
484
+ tags
485
+ }
480
486
  {% if reset_passwords %}
481
487
  resetPasswords {
482
488
  user {
@@ -499,6 +505,12 @@ AWS_ACCOUNTS_QUERY = """
499
505
  name
500
506
  uid
501
507
  supportedDeploymentRegions
508
+ organization {
509
+ payerAccount {
510
+ organizationAccountTags
511
+ }
512
+ tags
513
+ }
502
514
  }
503
515
  ... on AWSAccountSharingOptionAMI_v1 {
504
516
  regex
@@ -606,6 +618,12 @@ awsInfrastructureManagementAccounts {
606
618
  version
607
619
  format
608
620
  }
621
+ organization {
622
+ payerAccount {
623
+ organizationAccountTags
624
+ }
625
+ tags
626
+ }
609
627
  }
610
628
  accessLevel
611
629
  default
@@ -636,6 +654,12 @@ awsInfrastructureAccess {
636
654
  version
637
655
  format
638
656
  }
657
+ organization {
658
+ payerAccount {
659
+ organizationAccountTags
660
+ }
661
+ tags
662
+ }
639
663
  }
640
664
  roles {
641
665
  users {
@@ -745,6 +769,12 @@ CLUSTERS_QUERY = """
745
769
  version
746
770
  format
747
771
  }
772
+ organization {
773
+ payerAccount {
774
+ organizationAccountTags
775
+ }
776
+ tags
777
+ }
748
778
  rosa {
749
779
  ocm_environments {
750
780
  ocm {
@@ -773,6 +803,7 @@ CLUSTERS_QUERY = """
773
803
  private
774
804
  provision_shard_id
775
805
  disable_user_workload_monitoring
806
+ fips
776
807
  }
777
808
  externalConfiguration {
778
809
  labels
@@ -829,6 +860,12 @@ CLUSTERS_QUERY = """
829
860
  version
830
861
  format
831
862
  }
863
+ organization {
864
+ payerAccount {
865
+ organizationAccountTags
866
+ }
867
+ tags
868
+ }
832
869
  }
833
870
  vpc_id
834
871
  cidr_block
@@ -847,6 +884,12 @@ CLUSTERS_QUERY = """
847
884
  version
848
885
  format
849
886
  }
887
+ organization {
888
+ payerAccount {
889
+ organizationAccountTags
890
+ }
891
+ tags
892
+ }
850
893
  }
851
894
  tags
852
895
  }
@@ -861,6 +904,12 @@ CLUSTERS_QUERY = """
861
904
  version
862
905
  format
863
906
  }
907
+ organization {
908
+ payerAccount {
909
+ organizationAccountTags
910
+ }
911
+ tags
912
+ }
864
913
  }
865
914
  tags
866
915
  cidrBlock
@@ -889,6 +938,12 @@ CLUSTERS_QUERY = """
889
938
  version
890
939
  format
891
940
  }
941
+ organization {
942
+ payerAccount {
943
+ organizationAccountTags
944
+ }
945
+ tags
946
+ }
892
947
  }
893
948
  }
894
949
  accessLevel
@@ -914,6 +969,12 @@ CLUSTERS_QUERY = """
914
969
  version
915
970
  format
916
971
  }
972
+ organization {
973
+ payerAccount {
974
+ organizationAccountTags
975
+ }
976
+ tags
977
+ }
917
978
  }
918
979
  }
919
980
  }
@@ -1067,6 +1128,12 @@ CLUSTER_PEERING_QUERY = """
1067
1128
  version
1068
1129
  format
1069
1130
  }
1131
+ organization {
1132
+ payerAccount {
1133
+ organizationAccountTags
1134
+ }
1135
+ tags
1136
+ }
1070
1137
  }
1071
1138
  accessLevel
1072
1139
  default
@@ -1088,6 +1155,12 @@ CLUSTER_PEERING_QUERY = """
1088
1155
  version
1089
1156
  format
1090
1157
  }
1158
+ organization {
1159
+ payerAccount {
1160
+ organizationAccountTags
1161
+ }
1162
+ tags
1163
+ }
1091
1164
  }
1092
1165
  }
1093
1166
  }
@@ -1112,6 +1185,12 @@ CLUSTER_PEERING_QUERY = """
1112
1185
  version
1113
1186
  format
1114
1187
  }
1188
+ organization {
1189
+ payerAccount {
1190
+ organizationAccountTags
1191
+ }
1192
+ tags
1193
+ }
1115
1194
  }
1116
1195
  vpc_id
1117
1196
  cidr_block
@@ -1131,6 +1210,12 @@ CLUSTER_PEERING_QUERY = """
1131
1210
  version
1132
1211
  format
1133
1212
  }
1213
+ organization {
1214
+ payerAccount {
1215
+ organizationAccountTags
1216
+ }
1217
+ tags
1218
+ }
1134
1219
  }
1135
1220
  tags
1136
1221
  assumeRole
@@ -1146,6 +1231,12 @@ CLUSTER_PEERING_QUERY = """
1146
1231
  version
1147
1232
  format
1148
1233
  }
1234
+ organization {
1235
+ payerAccount {
1236
+ organizationAccountTags
1237
+ }
1238
+ tags
1239
+ }
1149
1240
  }
1150
1241
  tags
1151
1242
  cidrBlock
@@ -1175,6 +1266,12 @@ CLUSTER_PEERING_QUERY = """
1175
1266
  version
1176
1267
  format
1177
1268
  }
1269
+ organization {
1270
+ payerAccount {
1271
+ organizationAccountTags
1272
+ }
1273
+ tags
1274
+ }
1178
1275
  }
1179
1276
  }
1180
1277
  }
@@ -1190,6 +1287,12 @@ CLUSTER_PEERING_QUERY = """
1190
1287
  version
1191
1288
  format
1192
1289
  }
1290
+ organization {
1291
+ payerAccount {
1292
+ organizationAccountTags
1293
+ }
1294
+ tags
1295
+ }
1193
1296
  }
1194
1297
  accessLevel
1195
1298
  default
@@ -1216,6 +1319,12 @@ CLUSTER_PEERING_QUERY = """
1216
1319
  version
1217
1320
  format
1218
1321
  }
1322
+ organization {
1323
+ payerAccount {
1324
+ organizationAccountTags
1325
+ }
1326
+ tags
1327
+ }
1219
1328
  }
1220
1329
  }
1221
1330
  }
@@ -1231,6 +1340,12 @@ CLUSTER_PEERING_QUERY = """
1231
1340
  version
1232
1341
  format
1233
1342
  }
1343
+ organization {
1344
+ payerAccount {
1345
+ organizationAccountTags
1346
+ }
1347
+ tags
1348
+ }
1234
1349
  }
1235
1350
  }
1236
1351
  }
@@ -2230,6 +2345,12 @@ JIRA_BOARDS_QUICK_QUERY = """
2230
2345
  version
2231
2346
  format
2232
2347
  }
2348
+ email {
2349
+ path
2350
+ field
2351
+ version
2352
+ format
2353
+ }
2233
2354
  }
2234
2355
  }
2235
2356
  }
@@ -2336,6 +2457,12 @@ DNS_ZONES_QUERY = """
2336
2457
  version
2337
2458
  format
2338
2459
  }
2460
+ organization {
2461
+ payerAccount {
2462
+ organizationAccountTags
2463
+ }
2464
+ tags
2465
+ }
2339
2466
  }
2340
2467
  vpc {
2341
2468
  vpc_id
@@ -2697,6 +2824,10 @@ APP_METADATA = """
2697
2824
  path
2698
2825
  field
2699
2826
  }
2827
+ email {
2828
+ path
2829
+ field
2830
+ }
2700
2831
  }
2701
2832
  }
2702
2833
  slackUserGroup {
@@ -2,7 +2,7 @@ import hashlib
2
2
  import logging
3
3
  from collections.abc import Iterable
4
4
  from dataclasses import dataclass
5
- from datetime import UTC, datetime, timedelta
5
+ from datetime import timedelta
6
6
 
7
7
  from croniter import croniter
8
8
 
@@ -13,6 +13,7 @@ from reconcile.saas_auto_promotions_manager.publisher import (
13
13
  DeploymentInfo,
14
14
  Publisher,
15
15
  )
16
+ from reconcile.utils.datetime_util import utc_now
16
17
  from reconcile.utils.slo_document_manager import SLODocumentManager
17
18
 
18
19
  CONTENT_HASH_LENGTH = 32
@@ -113,7 +114,7 @@ class Subscriber:
113
114
  We accumulate the time a ref is running on all publishers for this subscriber.
114
115
  We compare that accumulated time with the soak_days setting of the subscriber.
115
116
  """
116
- now = datetime.now(UTC)
117
+ now = utc_now()
117
118
  delta = timedelta(days=0)
118
119
  for channel in self.channels:
119
120
  for publisher in channel.publishers:
@@ -136,7 +137,7 @@ class Subscriber:
136
137
  self.schedule,
137
138
  )
138
139
  return False
139
- return croniter.match(self.schedule, datetime.now(UTC), day_or=False)
140
+ return croniter.match(self.schedule, utc_now(), day_or=False)
140
141
 
141
142
  def _compute_desired_ref(self) -> None:
142
143
  """
@@ -40,6 +40,7 @@ from reconcile.typed_queries.app_interface_vault_settings import (
40
40
  )
41
41
  from reconcile.typed_queries.pagerduty_instances import get_pagerduty_instances
42
42
  from reconcile.utils import gql
43
+ from reconcile.utils.datetime_util import ensure_utc, utc_now
43
44
  from reconcile.utils.disabled_integrations import integration_is_enabled
44
45
  from reconcile.utils.exceptions import (
45
46
  AppInterfaceSettingsError,
@@ -357,11 +358,11 @@ def get_slack_usernames_from_owners(
357
358
 
358
359
  def get_slack_usernames_from_schedule(schedule: Iterable[ScheduleEntryV1]) -> list[str]:
359
360
  """Return list of usernames from all schedules."""
360
- now = datetime.utcnow()
361
+ now = utc_now()
361
362
  all_slack_usernames: list[str] = []
362
363
  for entry in schedule:
363
- start = datetime.strptime(entry.start, DATE_FORMAT)
364
- end = datetime.strptime(entry.end, DATE_FORMAT)
364
+ start = ensure_utc(datetime.strptime(entry.start, DATE_FORMAT)) # noqa: DTZ007
365
+ end = ensure_utc(datetime.strptime(entry.end, DATE_FORMAT)) # noqa: DTZ007
365
366
  if start <= now <= end:
366
367
  all_slack_usernames.extend(get_slack_username(u) for u in entry.users)
367
368
  return all_slack_usernames
reconcile/sql_query.py CHANGED
@@ -229,6 +229,7 @@ def collect_queries(
229
229
  accounts=[],
230
230
  prefetch_resources_by_schemas=["/aws/rds-defaults-1.yml"],
231
231
  secret_reader=secret_reader,
232
+ default_tags=None,
232
233
  )
233
234
 
234
235
  for sql_query in sql_queries:
@@ -1,12 +1,13 @@
1
1
  import logging
2
2
  import sys
3
- from datetime import UTC, datetime, timedelta
3
+ from datetime import datetime, timedelta
4
4
 
5
5
  from reconcile.slack_base import slackapi_from_queries
6
6
  from reconcile.statuspage.atlassian import AtlassianStatusPageProvider
7
7
  from reconcile.statuspage.integration import get_binding_state, get_status_pages
8
8
  from reconcile.statuspage.page import StatusMaintenance
9
9
  from reconcile.statuspage.state import S3ComponentBindingState
10
+ from reconcile.utils.datetime_util import utc_now
10
11
  from reconcile.utils.differ import diff_iterables
11
12
  from reconcile.utils.runtime.integration import (
12
13
  NoParams,
@@ -52,7 +53,7 @@ class StatusPageMaintenancesIntegration(QontractReconcileIntegration[NoParams]):
52
53
  desired_state: list[StatusMaintenance],
53
54
  binding_state: S3ComponentBindingState,
54
55
  ) -> None:
55
- now = datetime.now(UTC)
56
+ now = utc_now()
56
57
  slack = slackapi_from_queries(QONTRACT_INTEGRATION, init_usergroups=False)
57
58
  for m in desired_state:
58
59
  scheduled_start = m.schedule_start
@@ -68,7 +69,7 @@ class StatusPageMaintenancesIntegration(QontractReconcileIntegration[NoParams]):
68
69
  def run(self, dry_run: bool = False) -> None:
69
70
  binding_state = get_binding_state(self.name, self.secret_reader)
70
71
  pages = get_status_pages()
71
- now = datetime.now(UTC)
72
+ now = utc_now()
72
73
 
73
74
  error = False
74
75
  for p in pages:
@@ -2,18 +2,15 @@ from abc import (
2
2
  ABC,
3
3
  abstractmethod,
4
4
  )
5
- from datetime import (
6
- UTC,
7
- datetime,
8
- )
5
+ from datetime import datetime
9
6
 
10
- from dateutil.parser import isoparse
11
7
  from pydantic import BaseModel
12
8
 
13
9
  from reconcile.gql_definitions.statuspage.statuspages import (
14
10
  ManualStatusProviderV1,
15
11
  StatusProviderV1,
16
12
  )
13
+ from reconcile.utils.datetime_util import from_utc_iso_format, utc_now
17
14
 
18
15
  # This module defines the interface for status providers for components on status
19
16
  # pages. A status provider is responsible for determining the status of a component.
@@ -70,7 +67,7 @@ class ManualStatusProvider(StatusProvider, BaseModel):
70
67
  raise ValueError(
71
68
  "manual component status time window is invalid: end before start"
72
69
  )
73
- now = datetime.now(UTC)
70
+ now = utc_now()
74
71
  if self.start and now < self.start:
75
72
  return False
76
73
  return not (self.end and self.end < now)
@@ -84,8 +81,8 @@ def build_status_provider_config(
84
81
  provider specific implementation that provides the status resolution logic.
85
82
  """
86
83
  if isinstance(cfg, ManualStatusProviderV1):
87
- start = isoparse(cfg.manual.q_from) if cfg.manual.q_from else None
88
- end = isoparse(cfg.manual.until) if cfg.manual.until else None
84
+ start = from_utc_iso_format(cfg.manual.q_from) if cfg.manual.q_from else None
85
+ end = from_utc_iso_format(cfg.manual.until) if cfg.manual.until else None
89
86
  return ManualStatusProvider(
90
87
  component_status=cfg.manual.component_status,
91
88
  start=start,
@@ -55,4 +55,8 @@ rosa create cluster -y --cluster-name={{ cluster_name }} \
55
55
  {% if cluster.spec.provision_shard_id -%}
56
56
  --properties provision_shard_id:{{ cluster.spec.provision_shard_id }} \
57
57
  {% endif -%}
58
+ {% if cluster.spec.fips -%}
59
+ --fips \
60
+ {% endif -%}
58
61
  --channel-group {{ cluster.spec.channel }}
62
+
@@ -59,4 +59,7 @@ rosa create cluster --cluster-name={{ cluster_name }} \
59
59
  {% if cluster.spec.provision_shard_id -%}
60
60
  --properties provision_shard_id:{{ cluster.spec.provision_shard_id }} \
61
61
  {% endif -%}
62
+ {% if cluster.spec.fips -%}
63
+ --fips \
64
+ {% endif -%}
62
65
  --channel-group {{ cluster.spec.channel }}
@@ -33,6 +33,7 @@ from reconcile.utils import gql
33
33
  from reconcile.utils.git import checkout, clone
34
34
  from reconcile.utils.gql import GqlApi
35
35
  from reconcile.utils.jinja2.utils import TemplateRenderOptions, process_jinja2_template
36
+ from reconcile.utils.json import json_dumps
36
37
  from reconcile.utils.ruamel import create_ruamel_instance
37
38
  from reconcile.utils.runtime.integration import (
38
39
  PydanticRunParams,
@@ -215,7 +216,7 @@ def unpack_static_variables(
215
216
  each: dict[str, Any],
216
217
  ) -> dict:
217
218
  return {
218
- k: json.loads(process_jinja2_template(body=json.dumps(v), vars={"each": each}))
219
+ k: json.loads(process_jinja2_template(body=json_dumps(v), vars={"each": each}))
219
220
  for k, v in (collection_variables.static or {}).items()
220
221
  }
221
222