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.
- {qontract_reconcile-0.10.1rc397.dist-info → qontract_reconcile-0.10.1rc399.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc397.dist-info → qontract_reconcile-0.10.1rc399.dist-info}/RECORD +12 -14
- reconcile/glitchtip/integration.py +3 -5
- reconcile/glitchtip_project_alerts/integration.py +61 -16
- reconcile/glitchtip_project_dsn/integration.py +2 -4
- reconcile/gql_definitions/glitchtip/glitchtip_instance.py +16 -0
- reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py +16 -0
- reconcile/saas_auto_promotions_manager/merge_request_manager/renderer.py +26 -54
- reconcile/utils/glitchtip/client.py +7 -3
- reconcile/gql_definitions/glitchtip/glitchtip_settings.py +0 -70
- reconcile/typed_queries/glitchtip_settings.py +0 -18
- {qontract_reconcile-0.10.1rc397.dist-info → qontract_reconcile-0.10.1rc399.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc397.dist-info → qontract_reconcile-0.10.1rc399.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc397.dist-info → qontract_reconcile-0.10.1rc399.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc397.dist-info → qontract_reconcile-0.10.1rc399.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.
|
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
|
{qontract_reconcile-0.10.1rc397.dist-info → qontract_reconcile-0.10.1rc399.dist-info}/RECORD
RENAMED
@@ -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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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.
|
619
|
-
qontract_reconcile-0.10.
|
620
|
-
qontract_reconcile-0.10.
|
621
|
-
qontract_reconcile-0.10.
|
622
|
-
qontract_reconcile-0.10.
|
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,
|
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
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
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
|
-
|
61
|
-
|
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
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
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
|
-
|
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
|
-
|
176
|
-
"namespace": [
|
171
|
+
namespace_as_dict = {
|
172
|
+
"namespace": [namespace.dict(by_alias=True, exclude_none=True)]
|
177
173
|
}
|
178
174
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
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
|
-
|
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
|
-
|
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,
|
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
|
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc397.dist-info → qontract_reconcile-0.10.1rc399.dist-info}/top_level.txt
RENAMED
File without changes
|