qontract-reconcile 0.10.2.dev128__py3-none-any.whl → 0.10.2.dev130__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qontract_reconcile-0.10.2.dev128.dist-info → qontract_reconcile-0.10.2.dev130.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.2.dev128.dist-info → qontract_reconcile-0.10.2.dev130.dist-info}/RECORD +13 -13
- reconcile/external_resources/aws.py +0 -3
- reconcile/glitchtip/integration.py +0 -7
- reconcile/gql_definitions/glitchtip/glitchtip_project.py +23 -2
- reconcile/gql_definitions/introspection.json +7 -3
- reconcile/utils/glitchtip/client.py +37 -0
- reconcile/utils/glitchtip/models.py +11 -0
- reconcile/utils/rest_api_base.py +4 -2
- tools/glitchtip_access_revalidation.py +1 -1
- tools/qontract_cli.py +145 -1
- {qontract_reconcile-0.10.2.dev128.dist-info → qontract_reconcile-0.10.2.dev130.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev128.dist-info → qontract_reconcile-0.10.2.dev130.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev128.dist-info → qontract_reconcile-0.10.2.dev130.dist-info}/METADATA
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: qontract-reconcile
|
3
|
-
Version: 0.10.2.
|
3
|
+
Version: 0.10.2.dev130
|
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
|
{qontract_reconcile-0.10.2.dev128.dist-info → qontract_reconcile-0.10.2.dev130.dist-info}/RECORD
RENAMED
@@ -198,7 +198,7 @@ reconcile/endpoints_discovery/integration.py,sha256=ecjIZK_h6JO2wUhUmJlZ9pjOh60n
|
|
198
198
|
reconcile/endpoints_discovery/merge_request.py,sha256=_yLb4tnvoZMCko8rta2C_CvOInJa9pa3HzSmHNtjgGU,2978
|
199
199
|
reconcile/endpoints_discovery/merge_request_manager.py,sha256=a8zTIQIpRrUwXexZClwpQnnkEoS6XNZLJziI9x7ly0s,6389
|
200
200
|
reconcile/external_resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
201
|
-
reconcile/external_resources/aws.py,sha256=
|
201
|
+
reconcile/external_resources/aws.py,sha256=nvghzolcM_xR5ElNNt_PCZsCPzxTehsrzhzC6Y9NtKw,11983
|
202
202
|
reconcile/external_resources/factories.py,sha256=C0QHT0soEv6z99-ELAAE19S5MaMHhV0t1fSiQn0Coc4,5970
|
203
203
|
reconcile/external_resources/integration.py,sha256=WF6O4rT0oUHbNaWEemjLLzCqdNSQIUaymUuj08VsIl8,7034
|
204
204
|
reconcile/external_resources/integration_secrets_sync.py,sha256=CImwt_tyS3MMGpkjI_0gZqYt4XgqIw4BtdJiDH2xrCk,1700
|
@@ -220,14 +220,14 @@ reconcile/fleet_labeler/validate.py,sha256=Ch4fe7jXQZKl4pnvl5IxWS-dKSIuuiwdH2B7m
|
|
220
220
|
reconcile/fleet_labeler/vcs.py,sha256=6UHUQ08AGAHXF7629I6X-T_E1pvx96LxjS66EeOzve4,1108
|
221
221
|
reconcile/glitchtip/README.md,sha256=rfXT6jNP9khJW65jL7I2PgoxvxgcGGuJF8NpbzufEQ4,4335
|
222
222
|
reconcile/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
223
|
-
reconcile/glitchtip/integration.py,sha256=
|
223
|
+
reconcile/glitchtip/integration.py,sha256=HWc0cz3vNpZg8T5nVMPyD5QnlgsUHwLpJsGRbr_hvIM,7937
|
224
224
|
reconcile/glitchtip/reconciler.py,sha256=nUvDv7qG1ly0cA16MmlL6NV71yl1mJYLT2mui7lmi0Y,12402
|
225
225
|
reconcile/glitchtip_project_alerts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
226
226
|
reconcile/glitchtip_project_alerts/integration.py,sha256=BgMx-NyV9mTuv7Sotb2OioCO-iwVrN9-HCViVLU771c,13755
|
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=
|
230
|
+
reconcile/gql_definitions/introspection.json,sha256=0begChFQIAwAkSL-tmYKbh3fJmtvgxoyHm0FRP3HPGY,2283286
|
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=bN5i4mks10Z23KJSj7jqp966Osq2dps4d-sPH9gjxEA,7008
|
@@ -352,7 +352,7 @@ reconcile/gql_definitions/gitlab_members/gitlab_instances.py,sha256=oYPvfiOsPTGH
|
|
352
352
|
reconcile/gql_definitions/gitlab_members/permissions.py,sha256=Qzj3Fpv7xj8v9eygeP312nHRNg8er8XMRBveynPIyQM,3302
|
353
353
|
reconcile/gql_definitions/glitchtip/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
354
354
|
reconcile/gql_definitions/glitchtip/glitchtip_instance.py,sha256=QUfLhRkdE_-SorWgLBB8LHFD6kihbFwEoVByCLax3yM,2781
|
355
|
-
reconcile/gql_definitions/glitchtip/glitchtip_project.py,sha256=
|
355
|
+
reconcile/gql_definitions/glitchtip/glitchtip_project.py,sha256=3hS6ZbWr-KMWeVHYbP3HAK7uHd2e6KsXOr87gba7Uqc,6578
|
356
356
|
reconcile/gql_definitions/glitchtip_project_alerts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
357
357
|
reconcile/gql_definitions/glitchtip_project_alerts/glitchtip_project.py,sha256=Pv6RcuIzpNmGc43eEq64nnKG0Dr7H0wjy5Xg1_oRltM,5197
|
358
358
|
reconcile/gql_definitions/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -639,7 +639,7 @@ reconcile/utils/promtool.py,sha256=xmPBWEApkk0L2qZBAvTxakNXxfTz-tVLPFxGnpsxXnM,2
|
|
639
639
|
reconcile/utils/quay_api.py,sha256=uE_jxcdy3ViHtYFAfwDQuFDaO7Pr6AAPoVnmORbyHio,7822
|
640
640
|
reconcile/utils/raw_github_api.py,sha256=2WKtE8ABYYB9UGOAh9N_kLkksBWL3320Z2_scteZddI,2805
|
641
641
|
reconcile/utils/repo_owners.py,sha256=BHrAXxKyvn4qWJwFPWYGTtfgnLmYnWtYFEJGFeD__FE,6573
|
642
|
-
reconcile/utils/rest_api_base.py,sha256=
|
642
|
+
reconcile/utils/rest_api_base.py,sha256=MT7tp6CQO2S5aKfVOzw_hipWg7wAGoOqkm4qurI1hEU,4342
|
643
643
|
reconcile/utils/ruamel.py,sha256=FzL4_L0FnMOUZmgThrZSMJs5MTdXwiy-E9MZWfk8bh8,397
|
644
644
|
reconcile/utils/secret_reader.py,sha256=MaP56KZaAE35EyYbgAitdm6fUSxdzWeGFSOym9qiZkw,10206
|
645
645
|
reconcile/utils/semver_helper.py,sha256=-WfPOMSA2v1h7hT3PwVf-Htg7wOsoKlQC1JdmDX2Ars,1268
|
@@ -680,8 +680,8 @@ reconcile/utils/clusterhealth/telemeter.py,sha256=PllSLsJXvGNatmTF4mxCNPVbDrpr_M
|
|
680
680
|
reconcile/utils/dynatrace/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
681
681
|
reconcile/utils/dynatrace/client.py,sha256=RUk6KH-3CJyfJ1jolrdGQR4Hhz-tIWWJo9dsZ1IgJVw,3736
|
682
682
|
reconcile/utils/glitchtip/__init__.py,sha256=FT6iBhGqoe7KExFdbgL8AYUb64iW_4snF5__Dcl7yt0,258
|
683
|
-
reconcile/utils/glitchtip/client.py,sha256=
|
684
|
-
reconcile/utils/glitchtip/models.py,sha256=
|
683
|
+
reconcile/utils/glitchtip/client.py,sha256=F_x18QMHfeNoS3vS_VvjVm1IKnwGOsXvopjR9iwj4aY,8948
|
684
|
+
reconcile/utils/glitchtip/models.py,sha256=FyNt9EA9IS6tlsvqz-j7SkL9MoT_zIUTun0EiC9No6U,6684
|
685
685
|
reconcile/utils/internal_groups/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
686
686
|
reconcile/utils/internal_groups/client.py,sha256=DVWSEOsdP0trHANM-xw9WJjKSywrA9x_SFSCgUjvEV8,4665
|
687
687
|
reconcile/utils/internal_groups/models.py,sha256=y_IqBVqfGqNXiu0VudvBWFrm_-uafVm5KgLG-ca8XAs,2281
|
@@ -763,8 +763,8 @@ tools/app_interface_reporter.py,sha256=0_oq1-mL0UOh1x5G8CoKaEVJqK-XTKE7PX7IbRTov
|
|
763
763
|
tools/app_sre_tekton_access_reporter.py,sha256=o9prLUgQpwO3msRWc2as1xT1y9OB3znkpgvLr0Ys8_M,3146
|
764
764
|
tools/app_sre_tekton_access_revalidation.py,sha256=66nHEaY-bIqxIhpcmwN8AvQZu6ZXenfkg4Fut0pVZRM,2726
|
765
765
|
tools/glitchtip_access_reporter.py,sha256=o01A6b88t3Wie6tj_tJWWVo2J01LxQ_a9giGm4UzEaU,2901
|
766
|
-
tools/glitchtip_access_revalidation.py,sha256=
|
767
|
-
tools/qontract_cli.py,sha256=
|
766
|
+
tools/glitchtip_access_revalidation.py,sha256=PXN5wxl6OX8sxddPaakDF3X79nFLvpm-lz0mWLVelw0,2806
|
767
|
+
tools/qontract_cli.py,sha256=S_DGw0RXy0UZYBhuTqV8lJis1ARukmqT6SNr6Gl-tS4,157625
|
768
768
|
tools/sd_app_sre_alert_report.py,sha256=jQpJdXVID68bSNtJNOGDh0-ei1CfEUS4Itr4MAaBNFA,5062
|
769
769
|
tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
|
770
770
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -791,7 +791,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
791
791
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
|
792
792
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
793
793
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
794
|
-
qontract_reconcile-0.10.2.
|
795
|
-
qontract_reconcile-0.10.2.
|
796
|
-
qontract_reconcile-0.10.2.
|
797
|
-
qontract_reconcile-0.10.2.
|
794
|
+
qontract_reconcile-0.10.2.dev130.dist-info/METADATA,sha256=2CCwcz__a7QKk0BgiDB2-tPBCrscTGVp8QHheIuF5Fo,24566
|
795
|
+
qontract_reconcile-0.10.2.dev130.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
796
|
+
qontract_reconcile-0.10.2.dev130.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
797
|
+
qontract_reconcile-0.10.2.dev130.dist-info/RECORD,,
|
@@ -163,9 +163,6 @@ class AWSRdsFactory(AWSDefaultResourceFactory):
|
|
163
163
|
if "parameter_group" in data:
|
164
164
|
pg_data = rvr._get_values(data["parameter_group"])
|
165
165
|
data["parameter_group"] = pg_data
|
166
|
-
if "old_parameter_group" in data:
|
167
|
-
old_pg_data = rvr._get_values(data["old_parameter_group"])
|
168
|
-
data["old_parameter_group"] = old_pg_data
|
169
166
|
if (
|
170
167
|
(blue_green_deployment := data.get("blue_green_deployment"))
|
171
168
|
and (target := blue_green_deployment.get("target"))
|
@@ -144,13 +144,6 @@ def get_glitchtip_projects(query_func: Callable) -> list[GlitchtipProjectV1]:
|
|
144
144
|
glitchtip_projects = (
|
145
145
|
glitchtip_project_query(query_func=query_func).glitchtip_projects or []
|
146
146
|
)
|
147
|
-
for project in glitchtip_projects:
|
148
|
-
# either org.owners or project.app must be set
|
149
|
-
if not project.organization.owners and not project.app:
|
150
|
-
raise ValueError(
|
151
|
-
f"Either owners in organization {project.organization.name} or app must be set for project {project.name}"
|
152
|
-
)
|
153
|
-
|
154
147
|
return glitchtip_projects
|
155
148
|
|
156
149
|
|
@@ -98,9 +98,17 @@ query Projects {
|
|
98
98
|
}
|
99
99
|
}
|
100
100
|
}
|
101
|
-
# for glitchtip access revalidation
|
102
101
|
app {
|
102
|
+
# for glitchtip access revalidation
|
103
103
|
path
|
104
|
+
# for the qontract-cli glitchtip subcommands
|
105
|
+
escalationPolicy {
|
106
|
+
channels {
|
107
|
+
jiraBoard {
|
108
|
+
name
|
109
|
+
}
|
110
|
+
}
|
111
|
+
}
|
104
112
|
}
|
105
113
|
}
|
106
114
|
}
|
@@ -176,8 +184,21 @@ class NamespaceV1(ConfiguredBaseModel):
|
|
176
184
|
cluster: ClusterV1 = Field(..., alias="cluster")
|
177
185
|
|
178
186
|
|
187
|
+
class JiraBoardV1(ConfiguredBaseModel):
|
188
|
+
name: str = Field(..., alias="name")
|
189
|
+
|
190
|
+
|
191
|
+
class AppEscalationPolicyChannelsV1(ConfiguredBaseModel):
|
192
|
+
jira_board: list[JiraBoardV1] = Field(..., alias="jiraBoard")
|
193
|
+
|
194
|
+
|
195
|
+
class AppEscalationPolicyV1(ConfiguredBaseModel):
|
196
|
+
channels: AppEscalationPolicyChannelsV1 = Field(..., alias="channels")
|
197
|
+
|
198
|
+
|
179
199
|
class AppV1(ConfiguredBaseModel):
|
180
200
|
path: str = Field(..., alias="path")
|
201
|
+
escalation_policy: AppEscalationPolicyV1 = Field(..., alias="escalationPolicy")
|
181
202
|
|
182
203
|
|
183
204
|
class GlitchtipProjectV1(ConfiguredBaseModel):
|
@@ -188,7 +209,7 @@ class GlitchtipProjectV1(ConfiguredBaseModel):
|
|
188
209
|
teams: list[GlitchtipTeamV1] = Field(..., alias="teams")
|
189
210
|
organization: GlitchtipProjectV1_GlitchtipOrganizationV1 = Field(..., alias="organization")
|
190
211
|
namespaces: list[NamespaceV1] = Field(..., alias="namespaces")
|
191
|
-
app:
|
212
|
+
app: AppV1 = Field(..., alias="app")
|
192
213
|
|
193
214
|
|
194
215
|
class ProjectsQueryData(ConfiguredBaseModel):
|
@@ -23719,9 +23719,13 @@
|
|
23719
23719
|
"description": null,
|
23720
23720
|
"args": [],
|
23721
23721
|
"type": {
|
23722
|
-
"kind": "
|
23723
|
-
"name":
|
23724
|
-
"ofType":
|
23722
|
+
"kind": "NON_NULL",
|
23723
|
+
"name": null,
|
23724
|
+
"ofType": {
|
23725
|
+
"kind": "OBJECT",
|
23726
|
+
"name": "App_v1",
|
23727
|
+
"ofType": null
|
23728
|
+
}
|
23725
23729
|
},
|
23726
23730
|
"isDeprecated": false,
|
23727
23731
|
"deprecationReason": null
|
@@ -1,8 +1,11 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
|
1
3
|
from reconcile.utils.glitchtip.models import (
|
2
4
|
Organization,
|
3
5
|
Project,
|
4
6
|
ProjectAlert,
|
5
7
|
ProjectKey,
|
8
|
+
ProjectStatistics,
|
6
9
|
Team,
|
7
10
|
User,
|
8
11
|
)
|
@@ -57,6 +60,40 @@ class GlitchtipClient(ApiBase):
|
|
57
60
|
)
|
58
61
|
]
|
59
62
|
|
63
|
+
def all_projects(self) -> list[Project]:
|
64
|
+
"""List all projects."""
|
65
|
+
return [
|
66
|
+
Project(**r) for r in self._list("/api/0/projects/", params={"limit": 100})
|
67
|
+
]
|
68
|
+
|
69
|
+
def project_statistics(
|
70
|
+
self,
|
71
|
+
organization_slug: str,
|
72
|
+
project_pk: int,
|
73
|
+
start: datetime,
|
74
|
+
end: datetime,
|
75
|
+
) -> ProjectStatistics:
|
76
|
+
"""Get project statistics."""
|
77
|
+
field = "sum(quantity)"
|
78
|
+
timeseries = self._get(
|
79
|
+
f"/api/0/organizations/{organization_slug}/stats_v2/",
|
80
|
+
params={
|
81
|
+
"category": "error",
|
82
|
+
"interval": "1h",
|
83
|
+
"field": field,
|
84
|
+
"start": start.isoformat(),
|
85
|
+
"end": end.isoformat(),
|
86
|
+
"project": [project_pk],
|
87
|
+
},
|
88
|
+
)
|
89
|
+
return ProjectStatistics(
|
90
|
+
start=start,
|
91
|
+
end=end,
|
92
|
+
events=sum(
|
93
|
+
i for i in timeseries["groups"][0]["series"][field] if i is not None
|
94
|
+
),
|
95
|
+
)
|
96
|
+
|
60
97
|
def create_project(
|
61
98
|
self, organization_slug: str, team_slug: str, name: str, platform: str | None
|
62
99
|
) -> Project:
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
import re
|
4
4
|
from collections.abc import MutableMapping
|
5
|
+
from datetime import datetime
|
5
6
|
from enum import Enum
|
6
7
|
from typing import Any
|
7
8
|
|
@@ -152,6 +153,7 @@ class Project(BaseModel):
|
|
152
153
|
teams: list[Team] = []
|
153
154
|
alerts: list[ProjectAlert] = []
|
154
155
|
event_throttle_rate: int = Field(0, alias="eventThrottleRate")
|
156
|
+
organization: Organization | None = None
|
155
157
|
|
156
158
|
class Config:
|
157
159
|
allow_population_by_field_name = True
|
@@ -185,6 +187,12 @@ class Project(BaseModel):
|
|
185
187
|
return hash(self.slug)
|
186
188
|
|
187
189
|
|
190
|
+
class ProjectStatistics(BaseModel):
|
191
|
+
start: datetime
|
192
|
+
end: datetime
|
193
|
+
events: int = 0
|
194
|
+
|
195
|
+
|
188
196
|
class Organization(BaseModel):
|
189
197
|
pk: int | None = Field(None, alias="id")
|
190
198
|
name: str
|
@@ -210,3 +218,6 @@ class Organization(BaseModel):
|
|
210
218
|
|
211
219
|
def __hash__(self) -> int:
|
212
220
|
return hash(self.name)
|
221
|
+
|
222
|
+
|
223
|
+
Project.update_forward_refs()
|
reconcile/utils/rest_api_base.py
CHANGED
@@ -74,8 +74,10 @@ class ApiBase:
|
|
74
74
|
def cleanup(self) -> None:
|
75
75
|
self.session.close()
|
76
76
|
|
77
|
-
def _get(self, url: str) -> dict[str, Any]:
|
78
|
-
response = self.session.get(
|
77
|
+
def _get(self, url: str, params: dict | None = None) -> dict[str, Any]:
|
78
|
+
response = self.session.get(
|
79
|
+
urljoin(self.host, url), params=params, timeout=self.read_timeout
|
80
|
+
)
|
79
81
|
response.raise_for_status()
|
80
82
|
try:
|
81
83
|
return response.json()
|
@@ -64,7 +64,7 @@ def main(
|
|
64
64
|
glitchtip_project_query(query_func=gql.get_api().query).glitchtip_projects or []
|
65
65
|
)
|
66
66
|
|
67
|
-
apps = {project.app.path for project in glitchtip_projects
|
67
|
+
apps = {project.app.path for project in glitchtip_projects}
|
68
68
|
|
69
69
|
notification = Notification(
|
70
70
|
notification_type="Action Required",
|
tools/qontract_cli.py
CHANGED
@@ -10,7 +10,7 @@ import sys
|
|
10
10
|
import tempfile
|
11
11
|
import textwrap
|
12
12
|
from collections import defaultdict
|
13
|
-
from collections.abc import Callable, Mapping
|
13
|
+
from collections.abc import Callable, Iterable, Mapping
|
14
14
|
from datetime import (
|
15
15
|
UTC,
|
16
16
|
datetime,
|
@@ -83,6 +83,12 @@ from reconcile.gql_definitions.common.app_interface_vault_settings import (
|
|
83
83
|
)
|
84
84
|
from reconcile.gql_definitions.common.clusters import ClusterSpecROSAV1
|
85
85
|
from reconcile.gql_definitions.fragments.aus_organization import AUSOCMOrganization
|
86
|
+
from reconcile.gql_definitions.glitchtip.glitchtip_instance import (
|
87
|
+
query as glitchtip_instance_query,
|
88
|
+
)
|
89
|
+
from reconcile.gql_definitions.glitchtip.glitchtip_project import (
|
90
|
+
query as glitchtip_project_query,
|
91
|
+
)
|
86
92
|
from reconcile.gql_definitions.integrations import integrations as integrations_gql
|
87
93
|
from reconcile.gql_definitions.maintenance import maintenances as maintenances_gql
|
88
94
|
from reconcile.jenkins_job_builder import init_jjb
|
@@ -133,6 +139,8 @@ from reconcile.utils.gitlab_api import (
|
|
133
139
|
MRState,
|
134
140
|
MRStatus,
|
135
141
|
)
|
142
|
+
from reconcile.utils.glitchtip.client import GlitchtipClient
|
143
|
+
from reconcile.utils.glitchtip.models import Project, ProjectStatistics
|
136
144
|
from reconcile.utils.gql import GqlApiSingleton
|
137
145
|
from reconcile.utils.jjb_client import JJB
|
138
146
|
from reconcile.utils.keycloak import (
|
@@ -156,6 +164,7 @@ from reconcile.utils.ocm import OCM_PRODUCT_ROSA, OCMMap
|
|
156
164
|
from reconcile.utils.ocm.upgrades import get_upgrade_policies
|
157
165
|
from reconcile.utils.ocm_base_client import init_ocm_base_client
|
158
166
|
from reconcile.utils.output import print_output
|
167
|
+
from reconcile.utils.rest_api_base import BearerTokenAuth
|
159
168
|
from reconcile.utils.saasherder.models import TargetSpec
|
160
169
|
from reconcile.utils.saasherder.saasherder import SaasHerder
|
161
170
|
from reconcile.utils.secret_reader import (
|
@@ -4635,5 +4644,140 @@ def log_group_usage(ctx: click.Context, aws_account: str) -> None:
|
|
4635
4644
|
print_output(ctx.obj["options"], results, columns)
|
4636
4645
|
|
4637
4646
|
|
4647
|
+
@root.group()
|
4648
|
+
@click.option(
|
4649
|
+
"--instance",
|
4650
|
+
required=True,
|
4651
|
+
help="Glitchtip Instance Name",
|
4652
|
+
default="glitchtip-production",
|
4653
|
+
)
|
4654
|
+
@click.pass_context
|
4655
|
+
def glitchtip(ctx: click.Context, instance: str) -> None:
|
4656
|
+
"""Glitchtip commands"""
|
4657
|
+
|
4658
|
+
gqlapi = gql.get_api()
|
4659
|
+
vault_settings = get_app_interface_vault_settings()
|
4660
|
+
secret_reader = create_secret_reader(use_vault=vault_settings.vault)
|
4661
|
+
for glitchtip_instance in (
|
4662
|
+
glitchtip_instance_query(query_func=gqlapi.query).instances or []
|
4663
|
+
):
|
4664
|
+
if glitchtip_instance.name.lower() == instance.lower():
|
4665
|
+
ctx.obj["client"] = GlitchtipClient(
|
4666
|
+
host=glitchtip_instance.console_url,
|
4667
|
+
auth=BearerTokenAuth(
|
4668
|
+
secret_reader.read_secret(glitchtip_instance.automation_token)
|
4669
|
+
),
|
4670
|
+
read_timeout=glitchtip_instance.read_timeout,
|
4671
|
+
max_retries=glitchtip_instance.max_retries,
|
4672
|
+
)
|
4673
|
+
if "client" not in ctx.obj:
|
4674
|
+
print(f"Glitchtip instance {instance} not found")
|
4675
|
+
sys.exit(1)
|
4676
|
+
|
4677
|
+
|
4678
|
+
@glitchtip.command()
|
4679
|
+
@click.option(
|
4680
|
+
"--id",
|
4681
|
+
"ids",
|
4682
|
+
type=int,
|
4683
|
+
help="Glitchtip Project ID. Can be specified multiple times.",
|
4684
|
+
multiple=True,
|
4685
|
+
)
|
4686
|
+
@click.option(
|
4687
|
+
"--name",
|
4688
|
+
"names",
|
4689
|
+
help="Glitchtip Project Name. Can be specified multiple times.",
|
4690
|
+
multiple=True,
|
4691
|
+
)
|
4692
|
+
@click.pass_context
|
4693
|
+
def projects(ctx: click.Context, ids: Iterable[int], names: Iterable[str]) -> None:
|
4694
|
+
"""Display Glitchtip project information
|
4695
|
+
|
4696
|
+
This command will display the project metadata for the specified project IDs or names.
|
4697
|
+
If no IDs or names are provided, all projects will be displayed.
|
4698
|
+
"""
|
4699
|
+
console = Console()
|
4700
|
+
table = Table("ID", "Organization", "Name", "Throttle Rate")
|
4701
|
+
glitchtip_client: GlitchtipClient = ctx.obj["client"]
|
4702
|
+
with glitchtip_client as client:
|
4703
|
+
for project in client.all_projects():
|
4704
|
+
if (
|
4705
|
+
(ids or names)
|
4706
|
+
and (project.pk and project.pk not in ids)
|
4707
|
+
and (project.name not in names)
|
4708
|
+
):
|
4709
|
+
continue
|
4710
|
+
|
4711
|
+
assert project.organization # make mypy happy
|
4712
|
+
|
4713
|
+
table.add_row(
|
4714
|
+
str(project.pk),
|
4715
|
+
project.organization.name,
|
4716
|
+
project.name,
|
4717
|
+
str(project.event_throttle_rate),
|
4718
|
+
)
|
4719
|
+
console.print(table)
|
4720
|
+
|
4721
|
+
|
4722
|
+
@glitchtip.command()
|
4723
|
+
@click.option(
|
4724
|
+
"--top",
|
4725
|
+
type=int,
|
4726
|
+
help="Display the top N projects with the most events in the last 24 hours",
|
4727
|
+
default=10,
|
4728
|
+
)
|
4729
|
+
@click.pass_context
|
4730
|
+
def top_talkers(ctx: click.Context, top: int) -> None:
|
4731
|
+
"""Get the projects with the most events in the last 24 hours."""
|
4732
|
+
console = Console()
|
4733
|
+
table = Table("ID", "Organization", "Name", "Jira Board", "# Events in last 24h")
|
4734
|
+
|
4735
|
+
glitchtip_client: GlitchtipClient = ctx.obj["client"]
|
4736
|
+
stats: list[tuple[Project, ProjectStatistics]] = []
|
4737
|
+
app_interface_glitchtip_projects = {
|
4738
|
+
p.name: p
|
4739
|
+
for p in glitchtip_project_query(
|
4740
|
+
query_func=gql.get_api().query
|
4741
|
+
).glitchtip_projects
|
4742
|
+
or []
|
4743
|
+
}
|
4744
|
+
|
4745
|
+
with glitchtip_client as client:
|
4746
|
+
for project in client.all_projects():
|
4747
|
+
assert project.organization # make mypy happy
|
4748
|
+
assert project.pk # make mypy happy
|
4749
|
+
|
4750
|
+
stat = client.project_statistics(
|
4751
|
+
organization_slug=project.organization.slug,
|
4752
|
+
project_pk=project.pk,
|
4753
|
+
start=datetime.now(tz=UTC) - timedelta(hours=24),
|
4754
|
+
end=datetime.now(tz=UTC),
|
4755
|
+
)
|
4756
|
+
stats.append((project, stat))
|
4757
|
+
|
4758
|
+
# sort by event count
|
4759
|
+
stats.sort(key=lambda x: x[1].events, reverse=True)
|
4760
|
+
|
4761
|
+
for project, stat in stats[:top]:
|
4762
|
+
assert project.organization # make mypy happy
|
4763
|
+
assert project.pk # make mypy happy
|
4764
|
+
|
4765
|
+
jira_boards = [
|
4766
|
+
board.name
|
4767
|
+
for board in app_interface_glitchtip_projects[
|
4768
|
+
project.name
|
4769
|
+
].app.escalation_policy.channels.jira_board
|
4770
|
+
]
|
4771
|
+
|
4772
|
+
table.add_row(
|
4773
|
+
str(project.pk),
|
4774
|
+
project.organization.name,
|
4775
|
+
project.name,
|
4776
|
+
", ".join(jira_boards),
|
4777
|
+
str(stat.events),
|
4778
|
+
)
|
4779
|
+
console.print(table)
|
4780
|
+
|
4781
|
+
|
4638
4782
|
if __name__ == "__main__":
|
4639
4783
|
root() # pylint: disable=no-value-for-parameter
|
{qontract_reconcile-0.10.2.dev128.dist-info → qontract_reconcile-0.10.2.dev130.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|