qontract-reconcile 0.10.1rc1062__py3-none-any.whl → 0.10.1rc1064__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.1rc1062.dist-info → qontract_reconcile-0.10.1rc1064.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc1062.dist-info → qontract_reconcile-0.10.1rc1064.dist-info}/RECORD +11 -10
- reconcile/change_owners/change_log_tracking.py +119 -0
- reconcile/change_owners/change_types.py +3 -0
- reconcile/change_owners/changes.py +4 -2
- reconcile/cli.py +23 -0
- reconcile/gql_definitions/change_owners/queries/change_types.py +2 -0
- tools/qontract_cli.py +36 -0
- {qontract_reconcile-0.10.1rc1062.dist-info → qontract_reconcile-0.10.1rc1064.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc1062.dist-info → qontract_reconcile-0.10.1rc1064.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc1062.dist-info → qontract_reconcile-0.10.1rc1064.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc1062.dist-info → qontract_reconcile-0.10.1rc1064.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.1rc1064
|
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.1rc1062.dist-info → qontract_reconcile-0.10.1rc1064.dist-info}/RECORD
RENAMED
@@ -10,7 +10,7 @@ reconcile/aws_iam_password_reset.py,sha256=q96mwr2KeEQ5bpNniGlgIMZTxiuLSodcYfX-t
|
|
10
10
|
reconcile/aws_support_cases_sos.py,sha256=hl_9L53yQYRQxKs3IWrd69Cc60XK067g_bJRM9B0udo,2975
|
11
11
|
reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=O1wFp52EyF538c6txaWBs8eMtUIy19gyHZ6VzJ6QXS8,3512
|
12
12
|
reconcile/checkpoint.py,sha256=_JhMxrye5BgkRMxWYuf7Upli6XayPINKSsuo3ynHTRc,5010
|
13
|
-
reconcile/cli.py,sha256=
|
13
|
+
reconcile/cli.py,sha256=PHoUlP86m-TdTpB3hyoHbOEDWR0_ZO-GSBQEGTmbTmc,107514
|
14
14
|
reconcile/closedbox_endpoint_monitoring_base.py,sha256=rLh16BOlBOxTmJ8Si3wWyyEpmMlhh4Znx1Gc36qsmOc,4865
|
15
15
|
reconcile/cluster_deployment_mapper.py,sha256=5gumAaRCcFXsabUJ1dnuUy9WrP_FEEM5JnOnE8ch9sE,2326
|
16
16
|
reconcile/dashdotdb_base.py,sha256=l34QDu1G96_Ctnh7ZXdxXgSeCE93GQMdLAkWxmN6vDA,4775
|
@@ -161,9 +161,10 @@ reconcile/aws_version_sync/merge_request_manager/merge_request_manager.py,sha256
|
|
161
161
|
reconcile/change_owners/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
162
162
|
reconcile/change_owners/approver.py,sha256=Z3_11vnK2WNOxjEEXVDh0224-_-qbt9d6mBeVE-7fsc,2259
|
163
163
|
reconcile/change_owners/bundle.py,sha256=ZIlXRo6Z2raeWSCUqYsexBdol-q-r9kWJs5O_YPaEYk,5273
|
164
|
+
reconcile/change_owners/change_log_tracking.py,sha256=zFpean5UB3-u5VQLJHzik8GmhBwYoNorR-l90-D1Pis,4160
|
164
165
|
reconcile/change_owners/change_owners.py,sha256=0HRJhDm0oW3uYJFgzynqA1gA0lbhalhSkmWOiQmr-NM,17062
|
165
|
-
reconcile/change_owners/change_types.py,sha256=
|
166
|
-
reconcile/change_owners/changes.py,sha256=
|
166
|
+
reconcile/change_owners/change_types.py,sha256=TjVtvmkU0s8w2NA6qvWQccB6PwlCrChFySlsHLYZjpE,32027
|
167
|
+
reconcile/change_owners/changes.py,sha256=pa3cNAL-Xawh700ARJJQjY0p09NA1J2329RcE0F0MHM,17224
|
167
168
|
reconcile/change_owners/decision.py,sha256=iUJcIc_N_RqXIAY8D10RZqPMC2OinsHTMcqI6f6uylE,7606
|
168
169
|
reconcile/change_owners/diff.py,sha256=0vyu29xCL24ZhUa7hqBni0NaxoCYRXLwvA-h8V23YQ4,9009
|
169
170
|
reconcile/change_owners/implicit_ownership.py,sha256=6BehZvx4IjrphmOt_LLLk9_02Fl5BY5jd00Wuz_PBZk,4234
|
@@ -233,7 +234,7 @@ reconcile/gql_definitions/aws_version_sync/clusters.py,sha256=2TOJOFxpTkZ2HKuqAG
|
|
233
234
|
reconcile/gql_definitions/aws_version_sync/namespaces.py,sha256=eBLyXlSjWdmEE-jY9M2Ocgk7JGi2OsWisTkjHLfgU_A,4311
|
234
235
|
reconcile/gql_definitions/change_owners/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
235
236
|
reconcile/gql_definitions/change_owners/queries/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
236
|
-
reconcile/gql_definitions/change_owners/queries/change_types.py,sha256=
|
237
|
+
reconcile/gql_definitions/change_owners/queries/change_types.py,sha256=SjpKbLWmLh8iwPwfulbjHpH-M1hqBG1TOu_pZazox0Q,5084
|
237
238
|
reconcile/gql_definitions/change_owners/queries/self_service_roles.py,sha256=BcTQvnefPiShG90ajU_l2V6HUYSEXgdAzgiwY89vQew,4790
|
238
239
|
reconcile/gql_definitions/cluster_auth_rhidp/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
239
240
|
reconcile/gql_definitions/cluster_auth_rhidp/clusters.py,sha256=Pp9P3Q30Be3szcVqOEOtPfYUNiGTq1xc5Juz-ApMMw0,3283
|
@@ -836,7 +837,7 @@ tools/app_interface_metrics_exporter.py,sha256=zkwkxdAUAxjdc-pzx2_oJXG25fo0Fnyd5
|
|
836
837
|
tools/app_interface_reporter.py,sha256=oZPib4HPq0aZ2Zui1QGJGk6qQdfpeihujGDBnSdKyGE,17627
|
837
838
|
tools/glitchtip_access_reporter.py,sha256=oPBnk_YoDuljU3v0FaChzOwwnk4vap1xEE67QEjzdqs,2948
|
838
839
|
tools/glitchtip_access_revalidation.py,sha256=8kbBJk04mkq28kWoRDDkfCGIF3GRg3pJrFAh1sW0dbk,2821
|
839
|
-
tools/qontract_cli.py,sha256=
|
840
|
+
tools/qontract_cli.py,sha256=5RQemctfItbH3S4TPjX2AmqmS1vCoI5j9zqhxFRJB44,129495
|
840
841
|
tools/sd_app_sre_alert_report.py,sha256=e9vAdyenUz2f5c8-z-5WY0wv-SJ9aePKDH2r4IwB6pc,5063
|
841
842
|
tools/template_validation.py,sha256=qpKYaTgk0GOPGa2Ct5_5sKdwIHtCAKIBGzsMPuJU5fw,3371
|
842
843
|
tools/cli_commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -867,8 +868,8 @@ tools/test/test_qontract_cli.py,sha256=_D61RFGAN5x44CY1tYbouhlGXXABwYfxKSWSQx3Jr
|
|
867
868
|
tools/test/test_saas_promotion_state.py,sha256=dy4kkSSAQ7bC0Xp2CociETGN-2aABEfL6FU5D9Jl00Y,6056
|
868
869
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
869
870
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
870
|
-
qontract_reconcile-0.10.
|
871
|
-
qontract_reconcile-0.10.
|
872
|
-
qontract_reconcile-0.10.
|
873
|
-
qontract_reconcile-0.10.
|
874
|
-
qontract_reconcile-0.10.
|
871
|
+
qontract_reconcile-0.10.1rc1064.dist-info/METADATA,sha256=zhmq1Fv6WMFLlItqLsy0MfDZKKWBqgzndiykQ9TT4ic,2213
|
872
|
+
qontract_reconcile-0.10.1rc1064.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
873
|
+
qontract_reconcile-0.10.1rc1064.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
874
|
+
qontract_reconcile-0.10.1rc1064.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
875
|
+
qontract_reconcile-0.10.1rc1064.dist-info/RECORD,,
|
@@ -0,0 +1,119 @@
|
|
1
|
+
import logging
|
2
|
+
from collections.abc import Callable
|
3
|
+
from dataclasses import asdict, dataclass, field
|
4
|
+
|
5
|
+
from reconcile.change_owners.bundle import (
|
6
|
+
NoOpFileDiffResolver,
|
7
|
+
QontractServerDiff,
|
8
|
+
)
|
9
|
+
from reconcile.change_owners.change_owners import fetch_change_type_processors
|
10
|
+
from reconcile.change_owners.change_types import ChangeTypeContext
|
11
|
+
from reconcile.change_owners.changes import aggregate_file_moves, parse_bundle_changes
|
12
|
+
from reconcile.utils import gql
|
13
|
+
from reconcile.utils.defer import defer
|
14
|
+
from reconcile.utils.runtime.integration import (
|
15
|
+
PydanticRunParams,
|
16
|
+
QontractReconcileIntegration,
|
17
|
+
)
|
18
|
+
from reconcile.utils.state import init_state
|
19
|
+
|
20
|
+
QONTRACT_INTEGRATION = "change-log-tracking"
|
21
|
+
BUNDLE_DIFFS_OBJ = "bundle-diffs.json"
|
22
|
+
|
23
|
+
|
24
|
+
@dataclass
|
25
|
+
class ChangeLogItem:
|
26
|
+
commit: str
|
27
|
+
change_types: list[str] = field(default_factory=list)
|
28
|
+
error: bool = False
|
29
|
+
|
30
|
+
|
31
|
+
@dataclass
|
32
|
+
class ChangeLog:
|
33
|
+
items: list[ChangeLogItem] = field(default_factory=list)
|
34
|
+
|
35
|
+
|
36
|
+
class ChangeLogIntegrationParams(PydanticRunParams):
|
37
|
+
process_existing: bool = False
|
38
|
+
|
39
|
+
|
40
|
+
class ChangeLogIntegration(QontractReconcileIntegration[ChangeLogIntegrationParams]):
|
41
|
+
@property
|
42
|
+
def name(self) -> str:
|
43
|
+
return QONTRACT_INTEGRATION
|
44
|
+
|
45
|
+
@defer
|
46
|
+
def run(
|
47
|
+
self,
|
48
|
+
dry_run: bool,
|
49
|
+
defer: Callable | None = None,
|
50
|
+
) -> None:
|
51
|
+
change_type_processors = [
|
52
|
+
ctp
|
53
|
+
for ctp in fetch_change_type_processors(
|
54
|
+
gql.get_api(), NoOpFileDiffResolver()
|
55
|
+
)
|
56
|
+
if ctp.labels and "change_log_tracking" in ctp.labels
|
57
|
+
]
|
58
|
+
|
59
|
+
integration_state = init_state(
|
60
|
+
integration=self.name,
|
61
|
+
)
|
62
|
+
if defer:
|
63
|
+
defer(integration_state.cleanup)
|
64
|
+
diff_state = init_state(
|
65
|
+
integration=self.name,
|
66
|
+
)
|
67
|
+
if defer:
|
68
|
+
defer(diff_state.cleanup)
|
69
|
+
diff_state.state_path = "bundle-archive/diff"
|
70
|
+
|
71
|
+
if not self.params.process_existing:
|
72
|
+
existing_change_log = ChangeLog(**integration_state.get(BUNDLE_DIFFS_OBJ))
|
73
|
+
existing_change_log_items = [
|
74
|
+
ChangeLogItem(**i) # type: ignore[arg-type]
|
75
|
+
for i in existing_change_log.items
|
76
|
+
]
|
77
|
+
change_log = ChangeLog()
|
78
|
+
for item in diff_state.ls():
|
79
|
+
key = item.lstrip("/")
|
80
|
+
commit = key.rstrip(".json")
|
81
|
+
if not self.params.process_existing:
|
82
|
+
existing_change_log_item = next(
|
83
|
+
(i for i in existing_change_log_items if i.commit == commit), None
|
84
|
+
)
|
85
|
+
if existing_change_log_item:
|
86
|
+
logging.debug(f"Found existing commit {commit}")
|
87
|
+
change_log.items.append(existing_change_log_item)
|
88
|
+
continue
|
89
|
+
|
90
|
+
logging.info(f"Processing commit {commit}")
|
91
|
+
change_log_item = ChangeLogItem(
|
92
|
+
commit=commit,
|
93
|
+
)
|
94
|
+
change_log.items.append(change_log_item)
|
95
|
+
obj = diff_state.get(key, None)
|
96
|
+
if not obj:
|
97
|
+
logging.error(f"Error processing commit {commit}")
|
98
|
+
change_log_item.error = True
|
99
|
+
continue
|
100
|
+
diff = QontractServerDiff(**obj)
|
101
|
+
changes = aggregate_file_moves(parse_bundle_changes(diff))
|
102
|
+
for change in changes:
|
103
|
+
logging.debug(f"Processing change {change}")
|
104
|
+
for ctp in change_type_processors:
|
105
|
+
logging.info(f"Processing change type {ctp.name}")
|
106
|
+
ctx = ChangeTypeContext(
|
107
|
+
change_type_processor=ctp,
|
108
|
+
context="",
|
109
|
+
origin="",
|
110
|
+
context_file=change.fileref,
|
111
|
+
approvers=[],
|
112
|
+
)
|
113
|
+
covered_diffs = change.cover_changes(ctx)
|
114
|
+
if covered_diffs:
|
115
|
+
if ctp.name not in change_log_item.change_types:
|
116
|
+
change_log_item.change_types.append(ctp.name)
|
117
|
+
|
118
|
+
if not dry_run:
|
119
|
+
integration_state.add(BUNDLE_DIFFS_OBJ, asdict(change_log), force=True)
|
@@ -22,6 +22,7 @@ import jinja2
|
|
22
22
|
import jinja2.meta
|
23
23
|
import jsonpath_ng
|
24
24
|
import networkx
|
25
|
+
from pydantic import Json
|
25
26
|
|
26
27
|
from reconcile.change_owners.approver import (
|
27
28
|
Approver,
|
@@ -474,6 +475,7 @@ class ChangeTypeProcessor:
|
|
474
475
|
"""
|
475
476
|
|
476
477
|
name: str
|
478
|
+
labels: Json | None
|
477
479
|
description: str
|
478
480
|
priority: ChangeTypePriority
|
479
481
|
context_type: BundleFileType
|
@@ -715,6 +717,7 @@ def init_change_type_processors(
|
|
715
717
|
# build raw change-type-processor
|
716
718
|
processors[change_type.name] = ChangeTypeProcessor(
|
717
719
|
name=change_type.name,
|
720
|
+
labels=change_type.labels,
|
718
721
|
description=change_type.description,
|
719
722
|
priority=ChangeTypePriority(change_type.priority),
|
720
723
|
context_type=BundleFileType[change_type.context_type.upper()],
|
@@ -102,7 +102,7 @@ class BundleFileChange:
|
|
102
102
|
def is_file_creation(self) -> bool:
|
103
103
|
return self.old is None and self.new is not None
|
104
104
|
|
105
|
-
def cover_changes(self, change_type_context: ChangeTypeContext) ->
|
105
|
+
def cover_changes(self, change_type_context: ChangeTypeContext) -> dict[str, Diff]:
|
106
106
|
"""
|
107
107
|
Figure out if a ChangeTypeV1 covers detected changes within the BundleFile.
|
108
108
|
Base idea:
|
@@ -121,7 +121,7 @@ class BundleFileChange:
|
|
121
121
|
# as a source of approvers
|
122
122
|
if self.metadata_only_change and not self.diffs:
|
123
123
|
self._metadata_only_diff_coverage().coverage.append(change_type_context)
|
124
|
-
return
|
124
|
+
return {}
|
125
125
|
|
126
126
|
covered_diffs = {}
|
127
127
|
# observe the new state for added fields or list items or entire object sutrees
|
@@ -139,6 +139,8 @@ class BundleFileChange:
|
|
139
139
|
)
|
140
140
|
)
|
141
141
|
|
142
|
+
return covered_diffs
|
143
|
+
|
142
144
|
def _cover_changes_for_diffs(
|
143
145
|
self,
|
144
146
|
diffs: list[DiffCoverage],
|
reconcile/cli.py
CHANGED
@@ -3557,6 +3557,29 @@ def change_owners(
|
|
3557
3557
|
)
|
3558
3558
|
|
3559
3559
|
|
3560
|
+
@integration.command(short_help="Analyze bundle diffs by change types.")
|
3561
|
+
@click.option(
|
3562
|
+
"--process-existing/--no-process-existing",
|
3563
|
+
default=False,
|
3564
|
+
help="wait for pending/running pipelines before acting.",
|
3565
|
+
)
|
3566
|
+
@click.pass_context
|
3567
|
+
def change_log_tracking(ctx, process_existing):
|
3568
|
+
from reconcile.change_owners.change_log_tracking import (
|
3569
|
+
ChangeLogIntegration,
|
3570
|
+
ChangeLogIntegrationParams,
|
3571
|
+
)
|
3572
|
+
|
3573
|
+
run_class_integration(
|
3574
|
+
ChangeLogIntegration(
|
3575
|
+
ChangeLogIntegrationParams(
|
3576
|
+
process_existing=process_existing,
|
3577
|
+
)
|
3578
|
+
),
|
3579
|
+
ctx=ctx.obj,
|
3580
|
+
)
|
3581
|
+
|
3582
|
+
|
3560
3583
|
@integration.command(
|
3561
3584
|
short_help="Configure and enforce glitchtip instance configuration."
|
3562
3585
|
)
|
@@ -22,6 +22,7 @@ DEFINITION = """
|
|
22
22
|
query ChangeTypes($name: String) {
|
23
23
|
change_types: change_types_v1(name: $name) {
|
24
24
|
name
|
25
|
+
labels
|
25
26
|
description
|
26
27
|
priority
|
27
28
|
contextType
|
@@ -117,6 +118,7 @@ class ChangeTypeV1_ChangeTypeV1(ConfiguredBaseModel):
|
|
117
118
|
|
118
119
|
class ChangeTypeV1(ConfiguredBaseModel):
|
119
120
|
name: str = Field(..., alias="name")
|
121
|
+
labels: Optional[Json] = Field(..., alias="labels")
|
120
122
|
description: str = Field(..., alias="description")
|
121
123
|
priority: str = Field(..., alias="priority")
|
122
124
|
context_type: str = Field(..., alias="contextType")
|
tools/qontract_cli.py
CHANGED
@@ -47,6 +47,12 @@ from reconcile.aus.base import (
|
|
47
47
|
)
|
48
48
|
from reconcile.aus.models import OrganizationUpgradeSpec
|
49
49
|
from reconcile.change_owners.bundle import NoOpFileDiffResolver
|
50
|
+
from reconcile.change_owners.change_log_tracking import (
|
51
|
+
ChangeLog,
|
52
|
+
ChangeLogIntegration,
|
53
|
+
ChangeLogIntegrationParams,
|
54
|
+
ChangeLogItem,
|
55
|
+
)
|
50
56
|
from reconcile.change_owners.change_owners import (
|
51
57
|
fetch_change_type_processors,
|
52
58
|
fetch_self_service_roles,
|
@@ -85,6 +91,7 @@ from reconcile.jenkins_job_builder import init_jjb
|
|
85
91
|
from reconcile.slack_base import slackapi_from_queries
|
86
92
|
from reconcile.status_board import StatusBoardExporterIntegration
|
87
93
|
from reconcile.typed_queries.alerting_services_settings import get_alerting_services
|
94
|
+
from reconcile.typed_queries.app_interface_repo_url import get_app_interface_repo_url
|
88
95
|
from reconcile.typed_queries.app_interface_vault_settings import (
|
89
96
|
get_app_interface_vault_settings,
|
90
97
|
)
|
@@ -2857,6 +2864,35 @@ def container_image_details(ctx):
|
|
2857
2864
|
print_output(ctx.obj["options"], data, columns)
|
2858
2865
|
|
2859
2866
|
|
2867
|
+
@get.command
|
2868
|
+
@click.pass_context
|
2869
|
+
def change_log_tracking(ctx):
|
2870
|
+
repo_url = get_app_interface_repo_url()
|
2871
|
+
change_types = fetch_change_type_processors(gql.get_api(), NoOpFileDiffResolver())
|
2872
|
+
state = init_state(
|
2873
|
+
integration=ChangeLogIntegration(ChangeLogIntegrationParams()).name
|
2874
|
+
)
|
2875
|
+
change_log = ChangeLog(**state.get("bundle-diffs.json"))
|
2876
|
+
data: list[dict[str, str]] = []
|
2877
|
+
for item in change_log.items:
|
2878
|
+
change_log_item = ChangeLogItem(**item)
|
2879
|
+
commit = change_log_item.commit
|
2880
|
+
covered_change_types_descriptions = [
|
2881
|
+
ct.description
|
2882
|
+
for ct in change_types
|
2883
|
+
if ct.name in change_log_item.change_types
|
2884
|
+
]
|
2885
|
+
item = {
|
2886
|
+
"commit": f"[{commit}]({repo_url}/commit/{commit})",
|
2887
|
+
"changes": ", ".join(covered_change_types_descriptions),
|
2888
|
+
"error": change_log_item.error,
|
2889
|
+
}
|
2890
|
+
data.append(item)
|
2891
|
+
|
2892
|
+
columns = ["commit", "changes", "error"]
|
2893
|
+
print_output(ctx.obj["options"], data, columns)
|
2894
|
+
|
2895
|
+
|
2860
2896
|
@root.group(name="set")
|
2861
2897
|
@output
|
2862
2898
|
@click.pass_context
|
{qontract_reconcile-0.10.1rc1062.dist-info → qontract_reconcile-0.10.1rc1064.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|