qontract-reconcile 0.10.2.dev207__py3-none-any.whl → 0.10.2.dev209__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qontract-reconcile
3
- Version: 0.10.2.dev207
3
+ Version: 0.10.2.dev209
4
4
  Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
5
5
  Project-URL: homepage, https://github.com/app-sre/qontract-reconcile
6
6
  Project-URL: repository, https://github.com/app-sre/qontract-reconcile
@@ -141,7 +141,7 @@ reconcile/aus/version_gates/ocp_gate_handler.py,sha256=RW1ppDaCZXVegV9AzzqYXxDUu
141
141
  reconcile/aus/version_gates/sts_version_gate_handler.py,sha256=swwwz0YyvrEBf_InqrRRBCt2QzHYNvvq8jz9aYwElh4,3663
142
142
  reconcile/automated_actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
143
  reconcile/automated_actions/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
144
- reconcile/automated_actions/config/integration.py,sha256=gDNUKxs8m_4GWH0GnW9QXubtsBF6idc0kHxo05hdj0U,11633
144
+ reconcile/automated_actions/config/integration.py,sha256=y4Ce_sgCx50lZQNvfkcnuyrDP4VPC1Dvq5-eBU8uibM,12248
145
145
  reconcile/aws_account_manager/README.md,sha256=_XFM3GZNHUzv--e_navqJuaUWpjC6QrHfulreHynFf0,262
146
146
  reconcile/aws_account_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
147
147
  reconcile/aws_account_manager/integration.py,sha256=XTamC824imAezzVoQhhwdMOawNcPCOghR_y7i_8bpJI,15343
@@ -227,7 +227,7 @@ reconcile/glitchtip_project_alerts/integration.py,sha256=d3PMy-mQSbSZdIGAVaZCA2U
227
227
  reconcile/glitchtip_project_dsn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
228
228
  reconcile/glitchtip_project_dsn/integration.py,sha256=2iugub-kHYkHNK33n0v9_TeWonuxCPah_VkoTPvaajE,8077
229
229
  reconcile/gql_definitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
230
- reconcile/gql_definitions/introspection.json,sha256=Oo__Q1ENvfRSNRcJbojqqWyICHq5mSE_ebhJGqtKCsw,2335890
230
+ reconcile/gql_definitions/introspection.json,sha256=98cLVDNRRqTIu5ONbfa0WqIptS3J7g-s4M2Dhq3oSo4,2345500
231
231
  reconcile/gql_definitions/acs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
232
232
  reconcile/gql_definitions/acs/acs_instances.py,sha256=L91WW9LbhJbBSrECqShQpFtjoBOsmNIYLRpMbx1io5o,2181
233
233
  reconcile/gql_definitions/acs/acs_policies.py,sha256=Ygpfl2-VkYLSlJvHgp_dJBfb66K_Rwfdfpsa18w1v1s,4338
@@ -241,7 +241,7 @@ reconcile/gql_definitions/app_sre_tekton_access_revalidation/__init__.py,sha256=
241
241
  reconcile/gql_definitions/app_sre_tekton_access_revalidation/roles.py,sha256=8Y4NsS5T7tumDWxY5MuoV50MK2i-DsLYSpCRjb7KaLE,2353
242
242
  reconcile/gql_definitions/app_sre_tekton_access_revalidation/users.py,sha256=XdVxBxiyTR6Cy939EHNw__0k7iWrZWlhrgS5DakST0I,2504
243
243
  reconcile/gql_definitions/automated_actions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
244
- reconcile/gql_definitions/automated_actions/instance.py,sha256=73vRFDvrD9t2cY1Y8jmjfVPNJ_osPrI8fHTAQz0CGv4,6105
244
+ reconcile/gql_definitions/automated_actions/instance.py,sha256=A2cTd13049HVSU7-AOOFpbpIoDkawEjCaHUsE3CoQGs,7478
245
245
  reconcile/gql_definitions/aws_account_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
246
246
  reconcile/gql_definitions/aws_account_manager/aws_accounts.py,sha256=vF51KrY2gwX0J9vESiaRMPQqdAMEtz9f_tBq52bInp0,5148
247
247
  reconcile/gql_definitions/aws_ami_cleanup/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -767,9 +767,9 @@ reconcile/utils/runtime/meta.py,sha256=dWdKS9eHVuowFkTK4lgXJ723vS1y9giOMzePUKnHn
767
767
  reconcile/utils/runtime/runner.py,sha256=I30KRrX1UQbHc_Ir1cIZX3OfNSdoHKdnDSPAEB69Ilk,7944
768
768
  reconcile/utils/runtime/sharding.py,sha256=r0ieUtNed7NvknSw6qQrCkKpVXE1shuHGnfFcnpA_k4,16142
769
769
  reconcile/utils/saasherder/__init__.py,sha256=3U8plqMAPRE1kjwZ5YnIsYsggTf4_gS7flRUEuXVBAs,343
770
- reconcile/utils/saasherder/interfaces.py,sha256=NEYQspYfyWQhBeJyNCqSFbixi1A4wRVGB7FeNM5BDCk,9141
771
- reconcile/utils/saasherder/models.py,sha256=JaOz_DEtudJZhiDe90kaBlJkppFufn81V92oK9PHYx0,10208
772
- reconcile/utils/saasherder/saasherder.py,sha256=uQovEpcnZXpJlG_tBUY0X1v5obYMH55vc5cSvi3eZjU,86862
770
+ reconcile/utils/saasherder/interfaces.py,sha256=nbGVLiIXJvOtd5ZfKsP3bfrFbMpdQ02D0cTTM9rrED0,9286
771
+ reconcile/utils/saasherder/models.py,sha256=MSKaC65_bXSxKvhCibRH5K1DNppLPbw5w7_6VrjCCFU,11018
772
+ reconcile/utils/saasherder/saasherder.py,sha256=W9nmQyULr4Jx9VAMwFyhULbKo5WRP9nSieOnpO5UxKQ,90224
773
773
  reconcile/utils/terraform/__init__.py,sha256=zNbiyTWo35AT1sFTElL2j_AA0jJ_yWE_bfFn-nD2xik,250
774
774
  reconcile/utils/terraform/config.py,sha256=5UVrd563TMcvi4ooa5JvWVDW1I3bIWg484u79evfV_8,164
775
775
  reconcile/utils/terraform/config_client.py,sha256=gRL1rQ0AqvShei_rcGqC3HDYGskOFKE1nPrJyJE9yno,4676
@@ -815,7 +815,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
815
815
  tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
816
816
  tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
817
817
  tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
818
- qontract_reconcile-0.10.2.dev207.dist-info/METADATA,sha256=UdoDHkjPDfwtakZqafNuWU01FUq_fUTiiWiCAbpI5P0,24555
819
- qontract_reconcile-0.10.2.dev207.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
820
- qontract_reconcile-0.10.2.dev207.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
821
- qontract_reconcile-0.10.2.dev207.dist-info/RECORD,,
818
+ qontract_reconcile-0.10.2.dev209.dist-info/METADATA,sha256=QKUofEI-f485b9dZemKXq6v2vV1nQPGJDX3BaZL1_g4,24555
819
+ qontract_reconcile-0.10.2.dev209.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
820
+ qontract_reconcile-0.10.2.dev209.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
821
+ qontract_reconcile-0.10.2.dev209.dist-info/RECORD,,
@@ -17,10 +17,12 @@ from pydantic import BaseModel
17
17
  import reconcile.openshift_base as ob
18
18
  from reconcile.gql_definitions.automated_actions.instance import (
19
19
  AutomatedActionActionListV1,
20
+ AutomatedActionExternalResourceRdsRebootV1,
20
21
  AutomatedActionOpenshiftWorkloadRestartArgumentV1,
21
22
  AutomatedActionOpenshiftWorkloadRestartV1,
22
23
  AutomatedActionsInstanceV1,
23
24
  AutomatedActionV1,
25
+ AWSAccountV1,
24
26
  )
25
27
  from reconcile.gql_definitions.automated_actions.instance import query as instance_query
26
28
  from reconcile.utils import expiration, gql
@@ -165,6 +167,15 @@ class AutomatedActionsConfigIntegration(
165
167
  arg.dict(exclude_none=True, exclude_defaults=True)
166
168
  for arg in action.action_list_arguments or []
167
169
  )
170
+ case AutomatedActionExternalResourceRdsRebootV1():
171
+ for arg in action.external_resource_rds_reboot_arguments:
172
+ for er in arg.namespace.external_resources or []:
173
+ if not isinstance(er.provisioner, AWSAccountV1):
174
+ continue
175
+ parameters.append({
176
+ "account": f"^{er.provisioner.name}$",
177
+ "identifier": arg.identifier,
178
+ })
168
179
  case AutomatedActionOpenshiftWorkloadRestartV1():
169
180
  parameters.extend(
170
181
  {
@@ -84,6 +84,26 @@ query AutomatedActionsInstances {
84
84
  }
85
85
  }
86
86
  maxOps
87
+ ... on AutomatedActionActionList_v1 {
88
+ action_list_arguments: arguments {
89
+ action_user
90
+ max_age_minutes
91
+ }
92
+ }
93
+ ... on AutomatedActionExternalResourceRdsReboot_v1 {
94
+ external_resource_rds_reboot_arguments: arguments {
95
+ namespace {
96
+ externalResources {
97
+ provisioner {
98
+ ... on AWSAccount_v1 {
99
+ name
100
+ }
101
+ }
102
+ }
103
+ }
104
+ identifier
105
+ }
106
+ }
87
107
  ... on AutomatedActionOpenshiftWorkloadRestart_v1 {
88
108
  openshift_workload_restart_arguments: arguments {
89
109
  namespace {
@@ -100,12 +120,6 @@ query AutomatedActionsInstances {
100
120
  name
101
121
  }
102
122
  }
103
- ... on AutomatedActionActionList_v1 {
104
- action_list_arguments: arguments {
105
- action_user
106
- max_age_minutes
107
- }
108
- }
109
123
  }
110
124
  }
111
125
  }
@@ -150,6 +164,40 @@ class AutomatedActionV1(ConfiguredBaseModel):
150
164
  max_ops: int = Field(..., alias="maxOps")
151
165
 
152
166
 
167
+ class AutomatedActionActionListArgumentV1(ConfiguredBaseModel):
168
+ action_user: Optional[str] = Field(..., alias="action_user")
169
+ max_age_minutes: Optional[int] = Field(..., alias="max_age_minutes")
170
+
171
+
172
+ class AutomatedActionActionListV1(AutomatedActionV1):
173
+ action_list_arguments: Optional[list[AutomatedActionActionListArgumentV1]] = Field(..., alias="action_list_arguments")
174
+
175
+
176
+ class ExternalResourcesProvisionerV1(ConfiguredBaseModel):
177
+ ...
178
+
179
+
180
+ class AWSAccountV1(ExternalResourcesProvisionerV1):
181
+ name: str = Field(..., alias="name")
182
+
183
+
184
+ class NamespaceExternalResourceV1(ConfiguredBaseModel):
185
+ provisioner: Union[AWSAccountV1, ExternalResourcesProvisionerV1] = Field(..., alias="provisioner")
186
+
187
+
188
+ class AutomatedActionExternalResourceArgumentV1_NamespaceV1(ConfiguredBaseModel):
189
+ external_resources: Optional[list[NamespaceExternalResourceV1]] = Field(..., alias="externalResources")
190
+
191
+
192
+ class AutomatedActionExternalResourceArgumentV1(ConfiguredBaseModel):
193
+ namespace: AutomatedActionExternalResourceArgumentV1_NamespaceV1 = Field(..., alias="namespace")
194
+ identifier: str = Field(..., alias="identifier")
195
+
196
+
197
+ class AutomatedActionExternalResourceRdsRebootV1(AutomatedActionV1):
198
+ external_resource_rds_reboot_arguments: list[AutomatedActionExternalResourceArgumentV1] = Field(..., alias="external_resource_rds_reboot_arguments")
199
+
200
+
153
201
  class DisableClusterAutomationsV1(ConfiguredBaseModel):
154
202
  integrations: Optional[list[str]] = Field(..., alias="integrations")
155
203
 
@@ -175,19 +223,10 @@ class AutomatedActionOpenshiftWorkloadRestartV1(AutomatedActionV1):
175
223
  openshift_workload_restart_arguments: list[AutomatedActionOpenshiftWorkloadRestartArgumentV1] = Field(..., alias="openshift_workload_restart_arguments")
176
224
 
177
225
 
178
- class AutomatedActionActionListArgumentV1(ConfiguredBaseModel):
179
- action_user: Optional[str] = Field(..., alias="action_user")
180
- max_age_minutes: Optional[int] = Field(..., alias="max_age_minutes")
181
-
182
-
183
- class AutomatedActionActionListV1(AutomatedActionV1):
184
- action_list_arguments: Optional[list[AutomatedActionActionListArgumentV1]] = Field(..., alias="action_list_arguments")
185
-
186
-
187
226
  class AutomatedActionsInstanceV1(ConfiguredBaseModel):
188
227
  name: str = Field(..., alias="name")
189
228
  deployment: NamespaceV1 = Field(..., alias="deployment")
190
- actions: Optional[list[Union[AutomatedActionOpenshiftWorkloadRestartV1, AutomatedActionActionListV1, AutomatedActionV1]]] = Field(..., alias="actions")
229
+ actions: Optional[list[Union[AutomatedActionActionListV1, AutomatedActionExternalResourceRdsRebootV1, AutomatedActionOpenshiftWorkloadRestartV1, AutomatedActionV1]]] = Field(..., alias="actions")
191
230
 
192
231
 
193
232
  class AutomatedActionsInstancesQueryData(ConfiguredBaseModel):
@@ -5737,6 +5737,11 @@
5737
5737
  "name": "AutomatedActionCreateToken_v1",
5738
5738
  "ofType": null
5739
5739
  },
5740
+ {
5741
+ "kind": "OBJECT",
5742
+ "name": "AutomatedActionExternalResourceRdsReboot_v1",
5743
+ "ofType": null
5744
+ },
5740
5745
  {
5741
5746
  "kind": "OBJECT",
5742
5747
  "name": "AutomatedActionNoOp_v1",
@@ -27339,6 +27344,11 @@
27339
27344
  "name": "AutomatedActionCreateToken_v1",
27340
27345
  "ofType": null
27341
27346
  },
27347
+ {
27348
+ "kind": "OBJECT",
27349
+ "name": "AutomatedActionExternalResourceRdsReboot_v1",
27350
+ "ofType": null
27351
+ },
27342
27352
  {
27343
27353
  "kind": "OBJECT",
27344
27354
  "name": "AutomatedActionNoOp_v1",
@@ -53500,6 +53510,215 @@
53500
53510
  "enumValues": null,
53501
53511
  "possibleTypes": null
53502
53512
  },
53513
+ {
53514
+ "kind": "OBJECT",
53515
+ "name": "AutomatedActionExternalResourceRdsReboot_v1",
53516
+ "description": null,
53517
+ "fields": [
53518
+ {
53519
+ "name": "schema",
53520
+ "description": null,
53521
+ "args": [],
53522
+ "type": {
53523
+ "kind": "NON_NULL",
53524
+ "name": null,
53525
+ "ofType": {
53526
+ "kind": "SCALAR",
53527
+ "name": "String",
53528
+ "ofType": null
53529
+ }
53530
+ },
53531
+ "isDeprecated": false,
53532
+ "deprecationReason": null
53533
+ },
53534
+ {
53535
+ "name": "path",
53536
+ "description": null,
53537
+ "args": [],
53538
+ "type": {
53539
+ "kind": "NON_NULL",
53540
+ "name": null,
53541
+ "ofType": {
53542
+ "kind": "SCALAR",
53543
+ "name": "String",
53544
+ "ofType": null
53545
+ }
53546
+ },
53547
+ "isDeprecated": false,
53548
+ "deprecationReason": null
53549
+ },
53550
+ {
53551
+ "name": "type",
53552
+ "description": null,
53553
+ "args": [],
53554
+ "type": {
53555
+ "kind": "NON_NULL",
53556
+ "name": null,
53557
+ "ofType": {
53558
+ "kind": "SCALAR",
53559
+ "name": "String",
53560
+ "ofType": null
53561
+ }
53562
+ },
53563
+ "isDeprecated": false,
53564
+ "deprecationReason": null
53565
+ },
53566
+ {
53567
+ "name": "description",
53568
+ "description": null,
53569
+ "args": [],
53570
+ "type": {
53571
+ "kind": "SCALAR",
53572
+ "name": "String",
53573
+ "ofType": null
53574
+ },
53575
+ "isDeprecated": false,
53576
+ "deprecationReason": null
53577
+ },
53578
+ {
53579
+ "name": "maxOps",
53580
+ "description": null,
53581
+ "args": [],
53582
+ "type": {
53583
+ "kind": "NON_NULL",
53584
+ "name": null,
53585
+ "ofType": {
53586
+ "kind": "SCALAR",
53587
+ "name": "Int",
53588
+ "ofType": null
53589
+ }
53590
+ },
53591
+ "isDeprecated": false,
53592
+ "deprecationReason": null
53593
+ },
53594
+ {
53595
+ "name": "instances",
53596
+ "description": null,
53597
+ "args": [],
53598
+ "type": {
53599
+ "kind": "NON_NULL",
53600
+ "name": null,
53601
+ "ofType": {
53602
+ "kind": "LIST",
53603
+ "name": null,
53604
+ "ofType": {
53605
+ "kind": "NON_NULL",
53606
+ "name": null,
53607
+ "ofType": {
53608
+ "kind": "OBJECT",
53609
+ "name": "AutomatedActionsInstance_v1",
53610
+ "ofType": null
53611
+ }
53612
+ }
53613
+ }
53614
+ },
53615
+ "isDeprecated": false,
53616
+ "deprecationReason": null
53617
+ },
53618
+ {
53619
+ "name": "permissions",
53620
+ "description": null,
53621
+ "args": [],
53622
+ "type": {
53623
+ "kind": "LIST",
53624
+ "name": null,
53625
+ "ofType": {
53626
+ "kind": "NON_NULL",
53627
+ "name": null,
53628
+ "ofType": {
53629
+ "kind": "OBJECT",
53630
+ "name": "PermissionAutomatedActions_v1",
53631
+ "ofType": null
53632
+ }
53633
+ }
53634
+ },
53635
+ "isDeprecated": false,
53636
+ "deprecationReason": null
53637
+ },
53638
+ {
53639
+ "name": "arguments",
53640
+ "description": null,
53641
+ "args": [],
53642
+ "type": {
53643
+ "kind": "NON_NULL",
53644
+ "name": null,
53645
+ "ofType": {
53646
+ "kind": "LIST",
53647
+ "name": null,
53648
+ "ofType": {
53649
+ "kind": "NON_NULL",
53650
+ "name": null,
53651
+ "ofType": {
53652
+ "kind": "OBJECT",
53653
+ "name": "AutomatedActionExternalResourceArgument_v1",
53654
+ "ofType": null
53655
+ }
53656
+ }
53657
+ }
53658
+ },
53659
+ "isDeprecated": false,
53660
+ "deprecationReason": null
53661
+ }
53662
+ ],
53663
+ "inputFields": null,
53664
+ "interfaces": [
53665
+ {
53666
+ "kind": "INTERFACE",
53667
+ "name": "AutomatedAction_v1",
53668
+ "ofType": null
53669
+ },
53670
+ {
53671
+ "kind": "INTERFACE",
53672
+ "name": "DatafileObject_v1",
53673
+ "ofType": null
53674
+ }
53675
+ ],
53676
+ "enumValues": null,
53677
+ "possibleTypes": null
53678
+ },
53679
+ {
53680
+ "kind": "OBJECT",
53681
+ "name": "AutomatedActionExternalResourceArgument_v1",
53682
+ "description": null,
53683
+ "fields": [
53684
+ {
53685
+ "name": "namespace",
53686
+ "description": null,
53687
+ "args": [],
53688
+ "type": {
53689
+ "kind": "NON_NULL",
53690
+ "name": null,
53691
+ "ofType": {
53692
+ "kind": "OBJECT",
53693
+ "name": "Namespace_v1",
53694
+ "ofType": null
53695
+ }
53696
+ },
53697
+ "isDeprecated": false,
53698
+ "deprecationReason": null
53699
+ },
53700
+ {
53701
+ "name": "identifier",
53702
+ "description": null,
53703
+ "args": [],
53704
+ "type": {
53705
+ "kind": "NON_NULL",
53706
+ "name": null,
53707
+ "ofType": {
53708
+ "kind": "SCALAR",
53709
+ "name": "String",
53710
+ "ofType": null
53711
+ }
53712
+ },
53713
+ "isDeprecated": false,
53714
+ "deprecationReason": null
53715
+ }
53716
+ ],
53717
+ "inputFields": null,
53718
+ "interfaces": [],
53719
+ "enumValues": null,
53720
+ "possibleTypes": null
53721
+ },
53503
53722
  {
53504
53723
  "kind": "OBJECT",
53505
53724
  "name": "AutomatedActionNoOp_v1",
@@ -7,6 +7,7 @@ from typing import (
7
7
  runtime_checkable,
8
8
  )
9
9
 
10
+ from reconcile.gql_definitions.fragments.saas_slo_document import SLODocument
10
11
  from reconcile.utils import oc_connection_parameters
11
12
  from reconcile.utils.secret_reader import HasSecret
12
13
 
@@ -326,6 +327,9 @@ class SaasResourceTemplateTarget(HasParameters, HasSecretParameters, Protocol):
326
327
  @property
327
328
  def images(self) -> Sequence[SaasResourceTemplateTargetImage] | None: ...
328
329
 
330
+ @property
331
+ def slos(self) -> list[SLODocument] | None: ...
332
+
329
333
  def uid(
330
334
  self, parent_saas_file_name: str, parent_resource_template_name: str
331
335
  ) -> str: ...
@@ -12,6 +12,9 @@ from pydantic import (
12
12
  Field,
13
13
  )
14
14
 
15
+ from reconcile.gql_definitions.fragments.saas_slo_document import (
16
+ SLODocument,
17
+ )
15
18
  from reconcile.utils.oc_connection_parameters import Cluster
16
19
  from reconcile.utils.saasherder.interfaces import (
17
20
  HasParameters,
@@ -66,8 +69,18 @@ class TriggerSpecBase:
66
69
  raise NotImplementedError("implement this function in inheriting classes")
67
70
 
68
71
 
72
+ @dataclass(frozen=True)
73
+ class SLOKey:
74
+ slo_document_name: str
75
+ namespace_name: str
76
+ cluster_name: str
77
+
78
+
69
79
  @dataclass
70
80
  class TriggerSpecConfig(TriggerSpecBase):
81
+ resource_template_url: str
82
+ target_ref: str
83
+ slos: list[SLODocument] | None = None
71
84
  target_name: str | None = None
72
85
  reason: str | None = None
73
86
 
@@ -81,6 +94,19 @@ class TriggerSpecConfig(TriggerSpecBase):
81
94
  key += f"/{self.target_name}"
82
95
  return key
83
96
 
97
+ def extract_slo_keys(self) -> list[SLOKey]:
98
+ return [
99
+ SLOKey(
100
+ slo_document_name=slo_document.name,
101
+ namespace_name=namespace.namespace.name,
102
+ cluster_name=namespace.namespace.cluster.name,
103
+ )
104
+ for slo_document in self.slos or []
105
+ for namespace in slo_document.namespaces
106
+ if namespace.namespace.name == self.namespace_name
107
+ and namespace.namespace.cluster.name == self.cluster_name
108
+ ]
109
+
84
110
 
85
111
  @dataclass
86
112
  class TriggerSpecMovingCommit(TriggerSpecBase):
@@ -71,6 +71,7 @@ from reconcile.utils.saasherder.models import (
71
71
  ImageAuth,
72
72
  Namespace,
73
73
  Promotion,
74
+ SLOKey,
74
75
  TargetSpec,
75
76
  TriggerSpecConfig,
76
77
  TriggerSpecContainerImage,
@@ -81,6 +82,7 @@ from reconcile.utils.saasherder.models import (
81
82
  UpstreamJob,
82
83
  )
83
84
  from reconcile.utils.secret_reader import SecretReaderBase
85
+ from reconcile.utils.slo_document_manager import SLODetails, SLODocumentManager
84
86
  from reconcile.utils.state import State
85
87
  from reconcile.utils.vcs import VCS
86
88
 
@@ -1040,19 +1042,19 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1040
1042
  return channel_map
1041
1043
 
1042
1044
  def _collect_blocked_versions(self) -> dict[str, set[str]]:
1043
- blocked_versions: dict[str, set[str]] = {}
1045
+ blocked_versions: dict[str, set[str]] = defaultdict(set[str])
1044
1046
  for saas_file in self.saas_files:
1045
1047
  for cc in saas_file.app.code_components or []:
1046
1048
  for v in cc.blocked_versions or []:
1047
- blocked_versions.setdefault(cc.url, set()).add(v)
1049
+ blocked_versions[cc.url].add(v)
1048
1050
  return blocked_versions
1049
1051
 
1050
1052
  def _collect_hotfix_versions(self) -> dict[str, set[str]]:
1051
- hotfix_versions: dict[str, set[str]] = {}
1053
+ hotfix_versions: dict[str, set[str]] = defaultdict(set[str])
1052
1054
  for saas_file in self.saas_files:
1053
1055
  for cc in saas_file.app.code_components or []:
1054
1056
  for v in cc.hotfix_versions or []:
1055
- hotfix_versions.setdefault(cc.url, set()).add(v)
1057
+ hotfix_versions[cc.url].add(v)
1056
1058
  return hotfix_versions
1057
1059
 
1058
1060
  @staticmethod
@@ -1273,6 +1275,8 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1273
1275
  cluster_name=target.namespace.cluster.name,
1274
1276
  namespace_name=target.namespace.name,
1275
1277
  target_name=target.name,
1278
+ resource_template_url=rt.url,
1279
+ target_ref=target.ref,
1276
1280
  state_content=None,
1277
1281
  ).state_key
1278
1282
  digest = SaasHerder.get_target_config_hash(
@@ -1691,7 +1695,82 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1691
1695
  results = threaded.run(
1692
1696
  self.get_configs_diff_saas_file, self.saas_files, self.thread_pool_size
1693
1697
  )
1694
- return list(itertools.chain.from_iterable(results))
1698
+ trigger_config_spec_list = list(itertools.chain.from_iterable(results))
1699
+ return self.filter_slo_breached_triggers(trigger_config_spec_list)
1700
+
1701
+ def filter_slo_breached_triggers(
1702
+ self, trigger_config_spec_list: list[TriggerSpecConfig]
1703
+ ) -> list[TriggerSpecConfig]:
1704
+ trigger_config_specs_to_validate: list[TriggerSpecConfig] = [
1705
+ trigger_config_spec
1706
+ for trigger_config_spec in trigger_config_spec_list
1707
+ if trigger_config_spec.slos
1708
+ and trigger_config_spec.target_ref
1709
+ not in self.hotfix_versions[trigger_config_spec.resource_template_url]
1710
+ ]
1711
+ if not trigger_config_specs_to_validate:
1712
+ return trigger_config_spec_list
1713
+
1714
+ slo_documents = [
1715
+ slo
1716
+ for trigger_spec in trigger_config_specs_to_validate
1717
+ for slo in trigger_spec.slos or []
1718
+ ]
1719
+ slo_document_manager = SLODocumentManager(
1720
+ slo_documents=slo_documents,
1721
+ thread_pool_size=self.thread_pool_size,
1722
+ secret_reader=self.secret_reader,
1723
+ )
1724
+ breached_slos = slo_document_manager.get_breached_slos()
1725
+ if not breached_slos:
1726
+ return trigger_config_spec_list
1727
+
1728
+ breached_slos_map = self.make_breached_slos_map(breached_slos)
1729
+ valid_trigger_config_specs = [
1730
+ trigger_config_spec
1731
+ for trigger_config_spec in trigger_config_spec_list
1732
+ if not self.has_breached_slos(trigger_config_spec, breached_slos_map)
1733
+ ]
1734
+ return valid_trigger_config_specs
1735
+
1736
+ @staticmethod
1737
+ def make_breached_slos_map(
1738
+ breached_slos: list[SLODetails],
1739
+ ) -> dict[SLOKey, list[SLODetails]]:
1740
+ breached_slos_map: dict[SLOKey, list[SLODetails]] = defaultdict(
1741
+ list[SLODetails]
1742
+ )
1743
+ for breached_slo in breached_slos:
1744
+ breached_slos_map[
1745
+ SLOKey(
1746
+ slo_document_name=breached_slo.slo_document_name,
1747
+ namespace_name=breached_slo.namespace_name,
1748
+ cluster_name=breached_slo.cluster_name,
1749
+ )
1750
+ ].append(breached_slo)
1751
+ return breached_slos_map
1752
+
1753
+ @staticmethod
1754
+ def has_breached_slos(
1755
+ trigger_spec: TriggerSpecConfig,
1756
+ breached_slo_map: dict[SLOKey, list[SLODetails]],
1757
+ ) -> bool:
1758
+ matching_slo_keys = [
1759
+ slo_key
1760
+ for slo_key in trigger_spec.extract_slo_keys()
1761
+ if slo_key in breached_slo_map
1762
+ ]
1763
+ if not matching_slo_keys:
1764
+ return False
1765
+ logging.info(
1766
+ f"Skipping target from saas file {trigger_spec.saas_file_name} due to following breached SLOs."
1767
+ )
1768
+ for matching_key in matching_slo_keys:
1769
+ for breached_slo in breached_slo_map[matching_key]:
1770
+ logging.info(
1771
+ f"SLO: {breached_slo.slo.name} of document {breached_slo.slo_document_name} is breached. Current value: {breached_slo.current_slo_value} Expected: {breached_slo.slo.slo_target}"
1772
+ )
1773
+ return True
1695
1774
 
1696
1775
  @staticmethod
1697
1776
  def remove_none_values(d: dict[Any, Any] | None) -> dict[Any, Any]:
@@ -1725,7 +1804,6 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1725
1804
  dtc = SaasHerder.remove_none_values(trigger_spec.state_content)
1726
1805
  if ctc == dtc:
1727
1806
  continue
1728
-
1729
1807
  if self.include_trigger_trace:
1730
1808
  trigger_spec.reason = f"{self.repo_url}/commit/{RunningState().commit}"
1731
1809
  # For now we count every saas config change as an auto-promotion
@@ -1820,6 +1898,9 @@ class SaasHerder: # pylint: disable=too-many-public-methods
1820
1898
  namespace_name=target.namespace.name,
1821
1899
  target_name=target.name,
1822
1900
  state_content=serializable_target_config,
1901
+ resource_template_url=rt.url,
1902
+ target_ref=target.ref,
1903
+ slos=target.slos or None,
1823
1904
  )
1824
1905
  configs[trigger_spec.state_key] = trigger_spec
1825
1906