qontract-reconcile 0.10.1rc397__py3-none-any.whl → 0.10.1rc399__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.1
2
2
  Name: qontract-reconcile
3
- Version: 0.10.1rc397
3
+ Version: 0.10.1rc399
4
4
  Summary: Collection of tools to reconcile services with their desired state as defined in the app-interface DB.
5
5
  Home-page: https://github.com/app-sre/qontract-reconcile
6
6
  Author: Red Hat App-SRE Team
@@ -148,12 +148,12 @@ reconcile/cna/assets/asset.py,sha256=1v51uYSaD1NOc9cI_YxG7h0NOcR1ng-mkmD2UzQ8PXE
148
148
  reconcile/cna/assets/asset_factory.py,sha256=7T7X_J6xIsoGETqBRI45_EyIKEdQcnRPt_GAuVuLQcc,785
149
149
  reconcile/cna/assets/null.py,sha256=Fby1Fbn7oNRIGNasdyhRDvXJ0ktpxv-pUAPN0lZWSzk,1684
150
150
  reconcile/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
- reconcile/glitchtip/integration.py,sha256=kkag8hcVbUSFDrLVEvpJjqXz3O1HkKtzF8HOZ5jKVTU,8191
151
+ reconcile/glitchtip/integration.py,sha256=FB1dmwrDs8z6MHfO5Za83fcPkxsVvcaw6sFymIx4C_Q,8116
152
152
  reconcile/glitchtip/reconciler.py,sha256=_Lsu5_LRqSfjYe3Tn0eGE-u8WmTJt3c2TgCRvURoEM0,12306
153
153
  reconcile/glitchtip_project_alerts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
154
- reconcile/glitchtip_project_alerts/integration.py,sha256=u_HPhzID-oNh1J08X88Q7RRmZNObGlYVCzgrnJGgcoc,9176
154
+ reconcile/glitchtip_project_alerts/integration.py,sha256=ocKiowpcNCyJXaTbdl2CYg283dZ8lvwA85-_yllTtbg,11073
155
155
  reconcile/glitchtip_project_dsn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
156
- reconcile/glitchtip_project_dsn/integration.py,sha256=dQPb_izAXSlHBwksEpiTGgeybIsUsPZ1wJfMZ5voBHY,8046
156
+ reconcile/glitchtip_project_dsn/integration.py,sha256=NSHW3qVwkeSMv7Anl6fb-UFKRLUh_dh7JfvPQVvg1cA,7946
157
157
  reconcile/gql_definitions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
158
158
  reconcile/gql_definitions/advanced_upgrade_service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
159
159
  reconcile/gql_definitions/advanced_upgrade_service/aus_clusters.py,sha256=RSgN-BpYC1XG_4yaLdanUGsjBwh0RGLiEFX9T_Z_cvM,4091
@@ -218,11 +218,10 @@ reconcile/gql_definitions/gitlab_members/__init__.py,sha256=47DEQpj8HBSa-_TImW-5
218
218
  reconcile/gql_definitions/gitlab_members/gitlab_instances.py,sha256=2pLJMX5VngtQ93wDG0G96N3GhpWKlnPt3tsAot6W-Jg,2089
219
219
  reconcile/gql_definitions/gitlab_members/permissions.py,sha256=eQ1A22jnPMs2aCioS_u2Fw9wkMy9wsU_RuunPt4uu6I,3320
220
220
  reconcile/gql_definitions/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
221
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py,sha256=Dyqs6tFaixcxUJR8TA3PZJ0GXtQL1tegiGFv2aAHXj0,2181
221
+ reconcile/gql_definitions/glitchtip/glitchtip_instance.py,sha256=m0rAcytpzgbUbBNJTx892azExGTDmF8pLwUQDPWFeaI,2742
222
222
  reconcile/gql_definitions/glitchtip/glitchtip_project.py,sha256=TTfg3TDkAnEOwidgq_BsvnFLwwfl9kZvnl4Hp_fVeqU,5990
223
- reconcile/gql_definitions/glitchtip/glitchtip_settings.py,sha256=triKpfVwYxXWyZaZ6r7B37brzbqncjb2vhlBO_33phY,2058
224
223
  reconcile/gql_definitions/glitchtip_project_alerts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
225
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py,sha256=NYffd2Y8Q_fAwLeEvWvBDwHHMp49vQp2udu-uX4de50,3816
224
+ reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py,sha256=xFpu0OycGQlxdrT5TsNACk9IwOyrPuHh2Wn8-wO4m00,4206
226
225
  reconcile/gql_definitions/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
227
226
  reconcile/gql_definitions/integrations/integrations.py,sha256=BVQi1KouOszucg250nYq5gQYVBwWtSgR17-Zt7sWKc0,11710
228
227
  reconcile/gql_definitions/jenkins_configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -322,7 +321,7 @@ reconcile/saas_auto_promotions_manager/subscriber.py,sha256=cLhPlkT71J2LIice3SLm
322
321
  reconcile/saas_auto_promotions_manager/merge_request_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
323
322
  reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request.py,sha256=PNu7sE-tDUY61E03z5w0b93fdowZ8auCl0S4_vhYOKQ,1333
324
323
  reconcile/saas_auto_promotions_manager/merge_request_manager/merge_request_manager.py,sha256=SNJ9WLlaFnf_tblwC0xDBfrXi4SVadeFgV3llhTqbGM,10959
325
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py,sha256=cQYT0qCQQdsG4H16zpXBnHvnF_aZy4T87SxruyxRgNc,8565
324
+ reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py,sha256=t4Zi1BSDBEhrEl0hFIC7bPA41IGwh3kTWlo7qCtDTLE,7176
326
325
  reconcile/saas_auto_promotions_manager/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
327
326
  reconcile/saas_auto_promotions_manager/utils/saas_files_inventory.py,sha256=mihuWynroB1Cea1Lsvf6V8Nb8PGiBdcLC0uhCX_52Y0,6966
328
327
  reconcile/saas_auto_promotions_manager/utils/vcs.py,sha256=WXzr6I0Q9NzTU8s2Dk_wdWxKN8zUwPFiXbx31CnuY0w,5237
@@ -457,7 +456,6 @@ reconcile/typed_queries/clusters_minimal.py,sha256=flvs4oXVR4b971h-zMTK3C2GL3bjM
457
456
  reconcile/typed_queries/clusters_with_peering.py,sha256=lIai7SJJD0bqIJbe7virgrbYRqjLouSL2OpJD0itpAY,330
458
457
  reconcile/typed_queries/github_orgs.py,sha256=UZhoPl8qvA_tcO7CZlN8GuMKckt3ywd47Suu61rgHsc,258
459
458
  reconcile/typed_queries/gitlab_instances.py,sha256=ZVQHy2W9xIp53f5qYkjKLHLHgOVtQpxTfcmM1C2046g,291
460
- reconcile/typed_queries/glitchtip_settings.py,sha256=Hwq8H73PTK-ZIysGEqWcPEqYyRjETS91h9odp-T5ce0,721
461
459
  reconcile/typed_queries/jira_settings.py,sha256=i0ddx5xxHrM1v-9mtL_6OB-jBFLw7-HS6xenpIDjrkw,570
462
460
  reconcile/typed_queries/namespaces.py,sha256=vItPrn7sfcHOix-VvkzQkf54_ljzI_ymyxh5esdBJ5Y,262
463
461
  reconcile/typed_queries/namespaces_minimal.py,sha256=rUtqNQ0ORXXUTQfnpsMURymAJ4gYtE77V-Lb3LiJFEY,278
@@ -548,7 +546,7 @@ reconcile/utils/vaultsecretref.py,sha256=3Ed2uBy36TzSvL0B-l4FoWQqB2SbBKDKEuUPIO6
548
546
  reconcile/utils/cloud_resource_best_practice/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
549
547
  reconcile/utils/cloud_resource_best_practice/aws_rds.py,sha256=ZMQ7jT1HQbPIw0yJ7dXlDc6IETKUsLX3azWOvf5QLe0,2246
550
548
  reconcile/utils/glitchtip/__init__.py,sha256=FT6iBhGqoe7KExFdbgL8AYUb64iW_4snF5__Dcl7yt0,258
551
- reconcile/utils/glitchtip/client.py,sha256=lusu2b8PdnJanvQl4lK-mMqRZ6lXETXx0RJAGQRwfRE,10316
549
+ reconcile/utils/glitchtip/client.py,sha256=LpWiTg6ddmJPcB8LPEARai2nP9NrN4O8Gmtd8VZ9Iz0,10438
552
550
  reconcile/utils/glitchtip/models.py,sha256=Ic-RimRgMFskdbyYL6fQuOLwC2dGrt4y70-p-OqbQ-c,6197
553
551
  reconcile/utils/internal_groups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
554
552
  reconcile/utils/internal_groups/client.py,sha256=abREA8RwXKybXFjCK8CAcCr-iUp2r0tAbIEJ-c-PXws,4538
@@ -615,8 +613,8 @@ tools/test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
615
613
  tools/test/test_qontract_cli.py,sha256=awwTHEc2DWlykuqGIYM0WOBoSL0KRnOraCLk3C7izis,1401
616
614
  tools/test/test_sd_app_sre_alert_report.py,sha256=JeLhgzpKCPgLvptwg_4ZvJHLVWKNG1T5845HXTkMBxA,1826
617
615
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
618
- qontract_reconcile-0.10.1rc397.dist-info/METADATA,sha256=z4kimdW8MbXFkm5-MnD5gGyw6YL6FEZYPVGzeFVKywE,2347
619
- qontract_reconcile-0.10.1rc397.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
620
- qontract_reconcile-0.10.1rc397.dist-info/entry_points.txt,sha256=ErVY2Jp-0Rtuq5KOtMlW5yvna4nIEuc_1YbEdEdcy9o,301
621
- qontract_reconcile-0.10.1rc397.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
622
- qontract_reconcile-0.10.1rc397.dist-info/RECORD,,
616
+ qontract_reconcile-0.10.1rc399.dist-info/METADATA,sha256=8Rhg2IJPlLsVXNXBbLK1INKk5ke86eV9Z67fDjHGShA,2347
617
+ qontract_reconcile-0.10.1rc399.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
618
+ qontract_reconcile-0.10.1rc399.dist-info/entry_points.txt,sha256=ErVY2Jp-0Rtuq5KOtMlW5yvna4nIEuc_1YbEdEdcy9o,301
619
+ qontract_reconcile-0.10.1rc399.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
620
+ qontract_reconcile-0.10.1rc399.dist-info/RECORD,,
@@ -29,7 +29,6 @@ from reconcile.ldap_groups.integration import LdapGroupsIntegration
29
29
  from reconcile.typed_queries.app_interface_vault_settings import (
30
30
  get_app_interface_vault_settings,
31
31
  )
32
- from reconcile.typed_queries.glitchtip_settings import get_glitchtip_settings
33
32
  from reconcile.utils import gql
34
33
  from reconcile.utils.defer import defer
35
34
  from reconcile.utils.glitchtip import (
@@ -176,7 +175,6 @@ def run(
176
175
  gqlapi = gql.get_api()
177
176
  vault_settings = get_app_interface_vault_settings()
178
177
  secret_reader = create_secret_reader(use_vault=vault_settings.vault)
179
- read_timeout, max_retries, mail_domain = get_glitchtip_settings()
180
178
  internal_groups_client = get_internal_groups_client(gqlapi.query, secret_reader)
181
179
  if defer:
182
180
  defer(internal_groups_client.close)
@@ -191,8 +189,8 @@ def run(
191
189
  glitchtip_client = GlitchtipClient(
192
190
  host=glitchtip_instance.console_url,
193
191
  token=secret_reader.read_secret(glitchtip_instance.automation_token),
194
- read_timeout=read_timeout,
195
- max_retries=max_retries,
192
+ read_timeout=glitchtip_instance.read_timeout,
193
+ max_retries=glitchtip_instance.max_retries,
196
194
  )
197
195
  current_state = fetch_current_state(
198
196
  glitchtip_client=glitchtip_client,
@@ -207,7 +205,7 @@ def run(
207
205
  for p in glitchtip_projects
208
206
  if p.organization.instance.name == glitchtip_instance.name
209
207
  ],
210
- mail_domain=mail_domain,
208
+ mail_domain=glitchtip_instance.mail_domain or "redhat.com",
211
209
  internal_groups_client=internal_groups_client,
212
210
  )
213
211
 
@@ -8,6 +8,7 @@ from typing import (
8
8
  Any,
9
9
  Optional,
10
10
  )
11
+ from urllib.parse import quote
11
12
 
12
13
  from reconcile.gql_definitions.glitchtip.glitchtip_instance import (
13
14
  query as glitchtip_instance_query,
@@ -21,7 +22,6 @@ from reconcile.gql_definitions.glitchtip_project_alerts.glitchtip_project import
21
22
  from reconcile.gql_definitions.glitchtip_project_alerts.glitchtip_project import (
22
23
  query as glitchtip_project_query,
23
24
  )
24
- from reconcile.typed_queries.glitchtip_settings import get_glitchtip_settings
25
25
  from reconcile.utils import gql
26
26
  from reconcile.utils.differ import diff_iterables
27
27
  from reconcile.utils.glitchtip.client import GlitchtipClient
@@ -38,7 +38,7 @@ from reconcile.utils.runtime.integration import (
38
38
  )
39
39
 
40
40
  QONTRACT_INTEGRATION = "glitchtip-project-alerts"
41
-
41
+ GJB_ALERT_NAME = "Glitchtip-Jira-Bridge-Integration"
42
42
  ProjectStates = dict[str, Project]
43
43
 
44
44
 
@@ -79,7 +79,10 @@ class GlitchtipProjectAlertsIntegration(
79
79
  raise TypeError("Unsupported type")
80
80
 
81
81
  def fetch_desired_state(
82
- self, glitchtip_projects: Iterable[GlitchtipProjectsV1]
82
+ self,
83
+ glitchtip_projects: Iterable[GlitchtipProjectsV1],
84
+ gjb_alert_url: str | None,
85
+ gjb_token: str | None,
83
86
  ) -> list[Organization]:
84
87
  organizations: dict[str, Organization] = {}
85
88
  for glitchtip_project in glitchtip_projects:
@@ -87,13 +90,13 @@ class GlitchtipProjectAlertsIntegration(
87
90
  glitchtip_project.organization.name,
88
91
  Organization(name=glitchtip_project.organization.name),
89
92
  )
90
- project = Project(
91
- name=glitchtip_project.name,
92
- platform=None,
93
- slug=glitchtip_project.project_id
94
- if glitchtip_project.project_id
95
- else "",
96
- alerts=[
93
+ alerts = []
94
+ for alert in glitchtip_project.alerts or []:
95
+ if alert.name == GJB_ALERT_NAME:
96
+ raise ValueError(
97
+ f"'{GJB_ALERT_NAME}' alert name is reserved. Please use another name."
98
+ )
99
+ alerts.append(
97
100
  ProjectAlert(
98
101
  name=alert.name,
99
102
  timespan_minutes=alert.timespan_minutes,
@@ -103,8 +106,42 @@ class GlitchtipProjectAlertsIntegration(
103
106
  for recp in alert.recipients
104
107
  ],
105
108
  )
106
- for alert in glitchtip_project.alerts or []
107
- ],
109
+ )
110
+ if glitchtip_project.jira and gjb_alert_url:
111
+ if not (jira_project_key := glitchtip_project.jira.project):
112
+ if glitchtip_project.jira.board:
113
+ jira_project_key = glitchtip_project.jira.board.name
114
+
115
+ # this shouldn't happen, because our schemas enforce it
116
+ if not jira_project_key:
117
+ raise ValueError(
118
+ "Either jira.project or jira.board must be set for Jira integration"
119
+ )
120
+
121
+ url = f"{gjb_alert_url}/{jira_project_key}"
122
+ if gjb_token:
123
+ url += f"?token={quote(gjb_token)}"
124
+
125
+ alerts.append(
126
+ ProjectAlert(
127
+ name=GJB_ALERT_NAME,
128
+ timespan_minutes=1,
129
+ quantity=1,
130
+ recipients=[
131
+ ProjectAlertRecipient(
132
+ recipient_type=RecipientType.WEBHOOK,
133
+ url=url,
134
+ )
135
+ ],
136
+ )
137
+ )
138
+ project = Project(
139
+ name=glitchtip_project.name,
140
+ platform=None,
141
+ slug=glitchtip_project.project_id
142
+ if glitchtip_project.project_id
143
+ else "",
144
+ alerts=alerts,
108
145
  )
109
146
 
110
147
  organization.projects.append(project)
@@ -199,7 +236,6 @@ class GlitchtipProjectAlertsIntegration(
199
236
 
200
237
  def run(self, dry_run: bool) -> None:
201
238
  gqlapi = gql.get_api()
202
- read_timeout, max_retries, _ = get_glitchtip_settings()
203
239
  # data
204
240
  glitchtip_instances = glitchtip_instance_query(
205
241
  query_func=gqlapi.query
@@ -215,20 +251,29 @@ class GlitchtipProjectAlertsIntegration(
215
251
  for glitchtip_instance in glitchtip_instances:
216
252
  if self.params.instance and glitchtip_instance.name != self.params.instance:
217
253
  continue
254
+ glitchtip_jira_bridge_token = (
255
+ self.secret_reader.read_secret(
256
+ glitchtip_instance.glitchtip_jira_bridge_token
257
+ )
258
+ if glitchtip_instance.glitchtip_jira_bridge_token
259
+ else None
260
+ )
218
261
 
219
262
  glitchtip_client = GlitchtipClient(
220
263
  host=glitchtip_instance.console_url,
221
264
  token=self.secret_reader.read_secret(
222
265
  glitchtip_instance.automation_token
223
266
  ),
224
- read_timeout=read_timeout,
225
- max_retries=max_retries,
267
+ read_timeout=glitchtip_instance.read_timeout,
268
+ max_retries=glitchtip_instance.max_retries,
226
269
  )
227
270
  current_state = self.fetch_current_state(glitchtip_client=glitchtip_client)
228
271
  desired_state = self.fetch_desired_state(
229
272
  glitchtip_projects=glitchtip_projects_by_instance[
230
273
  glitchtip_instance.name
231
- ]
274
+ ],
275
+ gjb_alert_url=glitchtip_instance.glitchtip_jira_bridge_alert_url,
276
+ gjb_token=glitchtip_jira_bridge_token,
232
277
  )
233
278
  self.reconcile(
234
279
  glitchtip_client=glitchtip_client,
@@ -27,7 +27,6 @@ from reconcile.gql_definitions.glitchtip.glitchtip_project import (
27
27
  from reconcile.typed_queries.app_interface_vault_settings import (
28
28
  get_app_interface_vault_settings,
29
29
  )
30
- from reconcile.typed_queries.glitchtip_settings import get_glitchtip_settings
31
30
  from reconcile.utils import gql
32
31
  from reconcile.utils.defer import defer
33
32
  from reconcile.utils.disabled_integrations import integration_is_enabled
@@ -175,7 +174,6 @@ def run(
175
174
  ) -> None:
176
175
  # settings
177
176
  vault_settings = get_app_interface_vault_settings()
178
- read_timeout, max_retries, _ = get_glitchtip_settings()
179
177
 
180
178
  # data
181
179
  gqlapi = gql.get_api()
@@ -208,8 +206,8 @@ def run(
208
206
  glitchtip_client = GlitchtipClient(
209
207
  host=glitchtip_instance.console_url,
210
208
  token=secret_reader.read_secret(glitchtip_instance.automation_token),
211
- read_timeout=read_timeout,
212
- max_retries=max_retries,
209
+ read_timeout=glitchtip_instance.read_timeout,
210
+ max_retries=glitchtip_instance.max_retries,
213
211
  )
214
212
  threaded.run(
215
213
  fetch_current_state,
@@ -38,6 +38,13 @@ query GlitchtipInstance {
38
38
  automationToken {
39
39
  ...VaultSecret
40
40
  }
41
+ readTimeout
42
+ maxRetries
43
+ mailDomain
44
+ glitchtipJiraBridgeAlertUrl
45
+ glitchtipJiraBridgeToken {
46
+ ...VaultSecret
47
+ }
41
48
  }
42
49
  }
43
50
  """
@@ -54,6 +61,15 @@ class GlitchtipInstanceV1(ConfiguredBaseModel):
54
61
  console_url: str = Field(..., alias="consoleUrl")
55
62
  automation_user_email: VaultSecret = Field(..., alias="automationUserEmail")
56
63
  automation_token: VaultSecret = Field(..., alias="automationToken")
64
+ read_timeout: Optional[int] = Field(..., alias="readTimeout")
65
+ max_retries: Optional[int] = Field(..., alias="maxRetries")
66
+ mail_domain: Optional[str] = Field(..., alias="mailDomain")
67
+ glitchtip_jira_bridge_alert_url: Optional[str] = Field(
68
+ ..., alias="glitchtipJiraBridgeAlertUrl"
69
+ )
70
+ glitchtip_jira_bridge_token: Optional[VaultSecret] = Field(
71
+ ..., alias="glitchtipJiraBridgeToken"
72
+ )
57
73
 
58
74
 
59
75
  class GlitchtipInstanceQueryData(ConfiguredBaseModel):
@@ -56,6 +56,12 @@ query GlitchtipProjectsWithAlerts {
56
56
  }
57
57
  }
58
58
  }
59
+ jira {
60
+ project
61
+ board {
62
+ name
63
+ }
64
+ }
59
65
  }
60
66
  }
61
67
  """
@@ -103,11 +109,21 @@ class GlitchtipProjectAlertV1(ConfiguredBaseModel):
103
109
  ] = Field(..., alias="recipients")
104
110
 
105
111
 
112
+ class JiraBoardV1(ConfiguredBaseModel):
113
+ name: str = Field(..., alias="name")
114
+
115
+
116
+ class GlitchtipProjectJiraV1(ConfiguredBaseModel):
117
+ project: Optional[str] = Field(..., alias="project")
118
+ board: Optional[JiraBoardV1] = Field(..., alias="board")
119
+
120
+
106
121
  class GlitchtipProjectsV1(ConfiguredBaseModel):
107
122
  name: str = Field(..., alias="name")
108
123
  project_id: Optional[str] = Field(..., alias="projectId")
109
124
  organization: GlitchtipOrganizationV1 = Field(..., alias="organization")
110
125
  alerts: Optional[list[GlitchtipProjectAlertV1]] = Field(..., alias="alerts")
126
+ jira: Optional[GlitchtipProjectJiraV1] = Field(..., alias="jira")
111
127
 
112
128
 
113
129
  class GlitchtipProjectsWithAlertsQueryData(ConfiguredBaseModel):
@@ -56,14 +56,9 @@ class Renderer:
56
56
  **namespace_selector
57
57
  )
58
58
  # Check if the target namespace is addressed by the selector
59
- return (
60
- len(
61
- get_namespaces_by_selector(
62
- namespaces=[subscriber.target_namespace],
63
- namespace_selector=selector,
64
- )
65
- )
66
- == 1
59
+ return is_namespace_addressed_by_selector(
60
+ namespace=subscriber.target_namespace,
61
+ namespace_selector=selector,
67
62
  )
68
63
  return target["namespace"]["$ref"] == subscriber.target_namespace.path
69
64
 
@@ -158,56 +153,33 @@ class Renderer:
158
153
  return f"[auto-promotion] event for channel(s) {channels}"
159
154
 
160
155
 
161
- def get_namespaces_by_selector(
162
- namespaces: list[SaasTargetNamespace],
163
- namespace_selector: SaasResourceTemplateTargetNamespaceSelectorV1,
164
- ) -> list[SaasTargetNamespace]:
165
- """
166
- # TODO: for whatever reason tox fails to import this from saas_files.
167
- Interestingly it works outside of tox, but to get going we simply
168
- copy the function here - very bad style but works for now
156
+ def _parse_expression(expression: str) -> Any:
157
+ try:
158
+ return parser.parse(expression)
159
+ except JsonPathParserError as e:
160
+ raise RuntimeError(
161
+ f"Invalid jsonpath expression in namespaceSelector '{expression}' :{e}"
162
+ )
169
163
 
170
- Copy of reconcile.typed_queries.saas_files.get_namespaces_by_selector
171
- """
172
164
 
173
- # json representation of all the namespaces to filter on
165
+ def is_namespace_addressed_by_selector(
166
+ namespace: SaasTargetNamespace,
167
+ namespace_selector: SaasResourceTemplateTargetNamespaceSelectorV1,
168
+ ) -> bool:
169
+ # json representation of namespace to filter on
174
170
  # remove all the None values to simplify the jsonpath expressions
175
- namespaces_as_dict = {
176
- "namespace": [ns.dict(by_alias=True, exclude_none=True) for ns in namespaces]
171
+ namespace_as_dict = {
172
+ "namespace": [namespace.dict(by_alias=True, exclude_none=True)]
177
173
  }
178
174
 
179
- def _get_namespace_by_cluster_and_name(
180
- cluster_name: str, name: str
181
- ) -> SaasTargetNamespace:
182
- for ns in namespaces:
183
- if ns.cluster.name == cluster_name and ns.name == name:
184
- return ns
185
- # this should never ever happen - just make mypy happy
186
- raise RuntimeError(f"namespace '{name}' not found in cluster '{cluster_name}'")
175
+ do_include = any(
176
+ _parse_expression(include).find(namespace_as_dict)
177
+ for include in namespace_selector.json_path_selectors.include or []
178
+ )
187
179
 
188
- filtered_namespaces: dict[str, Any] = {}
180
+ do_exclude = any(
181
+ _parse_expression(exclude).find(namespace_as_dict)
182
+ for exclude in namespace_selector.json_path_selectors.exclude or []
183
+ )
189
184
 
190
- try:
191
- for include in namespace_selector.json_path_selectors.include:
192
- for match in parser.parse(include).find(namespaces_as_dict):
193
- cluster_name = match.value["cluster"]["name"]
194
- ns_name = match.value["name"]
195
- filtered_namespaces[
196
- f"{cluster_name}-{ns_name}"
197
- ] = _get_namespace_by_cluster_and_name(cluster_name, ns_name)
198
- except JsonPathParserError as e:
199
- raise RuntimeError(
200
- f"Invalid jsonpath expression in namespaceSelector '{include}' :{e}"
201
- )
202
-
203
- try:
204
- for exclude in namespace_selector.json_path_selectors.exclude or []:
205
- for match in parser.parse(exclude).find(namespaces_as_dict):
206
- cluster_name = match.value["cluster"]["name"]
207
- ns_name = match.value["name"]
208
- filtered_namespaces.pop(f"{cluster_name}-{ns_name}", None)
209
- except JsonPathParserError as e:
210
- raise RuntimeError(
211
- f"Invalid jsonpath expression in namespaceSelector '{exclude}' :{e}"
212
- )
213
- return list(filtered_namespaces.values())
185
+ return do_include and not do_exclude
@@ -31,12 +31,16 @@ def get_next_url(links: dict[str, dict[str, str]]) -> Optional[str]:
31
31
 
32
32
  class GlitchtipClient: # pylint: disable=too-many-public-methods
33
33
  def __init__(
34
- self, host: str, token: str, max_retries: int = 3, read_timeout: float = 30
34
+ self,
35
+ host: str,
36
+ token: str,
37
+ max_retries: int | None = None,
38
+ read_timeout: float | None = None,
35
39
  ) -> None:
36
40
  self.host = host
37
41
  self.token = token
38
- self.max_retries = max_retries
39
- self.read_timeout = read_timeout
42
+ self.max_retries = max_retries if max_retries is not None else 3
43
+ self.read_timeout = read_timeout if read_timeout is not None else 30
40
44
  self._thread_local = threading.local()
41
45
 
42
46
  @property
@@ -1,70 +0,0 @@
1
- """
2
- Generated by qenerate plugin=pydantic_v1. DO NOT MODIFY MANUALLY!
3
- """
4
- from collections.abc import Callable # noqa: F401 # pylint: disable=W0611
5
- from datetime import datetime # noqa: F401 # pylint: disable=W0611
6
- from enum import Enum # noqa: F401 # pylint: disable=W0611
7
- from typing import ( # noqa: F401 # pylint: disable=W0611
8
- Any,
9
- Optional,
10
- Union,
11
- )
12
-
13
- from pydantic import ( # noqa: F401 # pylint: disable=W0611
14
- BaseModel,
15
- Extra,
16
- Field,
17
- Json,
18
- )
19
-
20
-
21
- DEFINITION = """
22
- query GlitchtipSettings {
23
- settings: app_interface_settings_v1 {
24
- glitchtip {
25
- readTimeout
26
- maxRetries
27
- mailDomain
28
- }
29
- }
30
- }
31
- """
32
-
33
-
34
- class ConfiguredBaseModel(BaseModel):
35
- class Config:
36
- smart_union = True
37
- extra = Extra.forbid
38
-
39
-
40
- class GlitchtipSettingsV1(ConfiguredBaseModel):
41
- read_timeout: Optional[int] = Field(..., alias="readTimeout")
42
- max_retries: Optional[int] = Field(..., alias="maxRetries")
43
- mail_domain: Optional[str] = Field(..., alias="mailDomain")
44
-
45
-
46
- class AppInterfaceSettingsV1(ConfiguredBaseModel):
47
- glitchtip: Optional[GlitchtipSettingsV1] = Field(..., alias="glitchtip")
48
-
49
-
50
- class GlitchtipSettingsQueryData(ConfiguredBaseModel):
51
- settings: Optional[list[AppInterfaceSettingsV1]] = Field(..., alias="settings")
52
-
53
-
54
- def query(query_func: Callable, **kwargs: Any) -> GlitchtipSettingsQueryData:
55
- """
56
- This is a convenience function which queries and parses the data into
57
- concrete types. It should be compatible with most GQL clients.
58
- You do not have to use it to consume the generated data classes.
59
- Alternatively, you can also mime and alternate the behavior
60
- of this function in the caller.
61
-
62
- Parameters:
63
- query_func (Callable): Function which queries your GQL Server
64
- kwargs: optional arguments that will be passed to the query function
65
-
66
- Returns:
67
- GlitchtipSettingsQueryData: queried data parsed into generated classes
68
- """
69
- raw_data: dict[Any, Any] = query_func(DEFINITION, **kwargs)
70
- return GlitchtipSettingsQueryData(**raw_data)
@@ -1,18 +0,0 @@
1
- from reconcile.gql_definitions.glitchtip.glitchtip_settings import query
2
- from reconcile.utils import gql
3
-
4
-
5
- def get_glitchtip_settings(
6
- read_timeout: int = 30, max_retries: int = 3, mail_domain: str = "redhat.com"
7
- ) -> tuple[int, int, str]:
8
- """Returns Glitchtip Settings."""
9
- gqlapi = gql.get_api()
10
- if _s := query(query_func=gqlapi.query).settings:
11
- if _gs := _s[0].glitchtip:
12
- if _gs.read_timeout is not None:
13
- read_timeout = _gs.read_timeout
14
- if _gs.max_retries is not None:
15
- max_retries = _gs.max_retries
16
- if _gs.mail_domain is not None:
17
- mail_domain = _gs.mail_domain
18
- return read_timeout, max_retries, mail_domain