qontract-reconcile 0.10.1rc1061__py3-none-any.whl → 0.10.1rc1063__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.1rc1061.dist-info → qontract_reconcile-0.10.1rc1063.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc1061.dist-info → qontract_reconcile-0.10.1rc1063.dist-info}/RECORD +16 -15
- 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
- reconcile/gql_definitions/common/clusters_with_peering.py +2 -0
- reconcile/terraform_tgw_attachments.py +14 -10
- reconcile/test/test_terraform_tgw_attachments.py +4 -0
- reconcile/utils/terraform_client.py +17 -1
- reconcile/utils/terrascript_aws_client.py +46 -10
- tools/qontract_cli.py +36 -0
- {qontract_reconcile-0.10.1rc1061.dist-info → qontract_reconcile-0.10.1rc1063.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc1061.dist-info → qontract_reconcile-0.10.1rc1063.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc1061.dist-info → qontract_reconcile-0.10.1rc1063.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc1061.dist-info → qontract_reconcile-0.10.1rc1063.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.1rc1063
|
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.1rc1061.dist-info → qontract_reconcile-0.10.1rc1063.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
|
@@ -114,7 +114,7 @@ reconcile/terraform_cloudflare_resources.py,sha256=41Mj1WkuS75slCDpmhG2GGf1nh3Bw
|
|
114
114
|
reconcile/terraform_cloudflare_users.py,sha256=iyTG5sj20Jg4J4qWJ144KVptfIHGOSfH8wQKxu0imq0,13942
|
115
115
|
reconcile/terraform_repo.py,sha256=TKqlodhQGoAtQ6nDm04TNlpx4wpgJ_n4atoUK5Rfd7o,16444
|
116
116
|
reconcile/terraform_resources.py,sha256=-sgMMHDtNvnQyNR05-MKebI_pSiyxSWAg8LmeA2_Ntk,19326
|
117
|
-
reconcile/terraform_tgw_attachments.py,sha256=
|
117
|
+
reconcile/terraform_tgw_attachments.py,sha256=09svJG9pAiwWp4aY0xRoQRV90T4ZNwHG3r8flI-ZS_s,18810
|
118
118
|
reconcile/terraform_users.py,sha256=HqSm3ev3b8dZ9J6F_phDZB-FQsnlsdeKp9RPoY1cU94,10188
|
119
119
|
reconcile/terraform_vpc_peerings.py,sha256=VLSfuO7FvHN5McopRiKoKJDHCmIhYtlJEHv_hxV5kcM,27669
|
120
120
|
reconcile/vault_replication.py,sha256=isfmNaqxl4AC90n8sVJffUt685sPBfhNSvjks6DoQXg,17339
|
@@ -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
|
@@ -255,7 +256,7 @@ reconcile/gql_definitions/common/aws_vpcs.py,sha256=Dss9dQ3xagnz3Ltg1e9mtG2PAmQG
|
|
255
256
|
reconcile/gql_definitions/common/clusters.py,sha256=Dr5AsSsTuqjAxkI9fU0fdiaP6u5qkmRpkkCcYDnU584,21868
|
256
257
|
reconcile/gql_definitions/common/clusters_minimal.py,sha256=JYrJV_aStmryiiGKyiXhj47qpF_8KilCqy-d9CofBCo,4635
|
257
258
|
reconcile/gql_definitions/common/clusters_with_dms.py,sha256=GJ53P8tgMLh1NfVkaV9_AmaqF9pNUqJZcDkcKzKzUy0,2242
|
258
|
-
reconcile/gql_definitions/common/clusters_with_peering.py,sha256=
|
259
|
+
reconcile/gql_definitions/common/clusters_with_peering.py,sha256=B1Hi3u6rZZsl4bDDPMLIcSRI5lNFuh29lPVVTOrRRpQ,11929
|
259
260
|
reconcile/gql_definitions/common/github_orgs.py,sha256=rZ0pDAA2_9hF9N-ykRZIxPtEmczTSjuA_k3nkp0k1W0,2039
|
260
261
|
reconcile/gql_definitions/common/jira_settings.py,sha256=Fmjxhlhr69kc4jkG_0k17fuYlQVucbNex0jXYu83wbY,1990
|
261
262
|
reconcile/gql_definitions/common/jiralert_settings.py,sha256=H96nMg_r2YcOvioj3aIkwqtFrALGSLt7uhbx9jGSUTo,1984
|
@@ -566,7 +567,7 @@ reconcile/test/test_terraform_cloudflare_resources.py,sha256=1mdSZS-38mtTSg7teJg
|
|
566
567
|
reconcile/test/test_terraform_cloudflare_users.py,sha256=2VGBtMUhckLPtUnQlHIzpGsCnyVJZPNLFf-ABELkxbQ,27456
|
567
568
|
reconcile/test/test_terraform_repo.py,sha256=INfl-VlUtpV87J0neQt4wliptnX7PKvxLPF-ZgweTFA,12960
|
568
569
|
reconcile/test/test_terraform_resources.py,sha256=8C97yXIEihaQ3DZrtjxLNt4y4G12IOhD01ydm7JjliY,15359
|
569
|
-
reconcile/test/test_terraform_tgw_attachments.py,sha256=
|
570
|
+
reconcile/test/test_terraform_tgw_attachments.py,sha256=pJFmQzUwAn-wKpF6oSkImpdF7WXvcky8iaJiXbjGGgU,41104
|
570
571
|
reconcile/test/test_terraform_users.py,sha256=XOAfGvITCJPI1LTlISmHbA4ONMQMkxYUMTsny7pQCFw,4319
|
571
572
|
reconcile/test/test_terraform_vpc_peerings.py,sha256=bpjCjhmic07cw3XKSHf-2JvmLuWlyQG8laXlC-H7qtI,20796
|
572
573
|
reconcile/test/test_terraform_vpc_peerings_build_desired_state.py,sha256=cHmr1_yhRgfdqlFX6TMw-aiKXebaRv0szl16M9YRJic,49988
|
@@ -724,8 +725,8 @@ reconcile/utils/sqs_gateway.py,sha256=XNIf3PY4UCPNufP2Ul0UJj3fKlt5larBba-VTT-41F
|
|
724
725
|
reconcile/utils/state.py,sha256=W0_awkLAPX18hNOF_60o73tkPxDUylqbzYNHfl_sDsk,16386
|
725
726
|
reconcile/utils/structs.py,sha256=LcbLEg8WxfRqM6nW7NhcWN0YeqF7SQzxOgntmLs1SgY,352
|
726
727
|
reconcile/utils/template.py,sha256=wTvRU4AnAV_o042tD4Mwls2dwWMuk7MKnde3MaCjaYg,331
|
727
|
-
reconcile/utils/terraform_client.py,sha256=
|
728
|
-
reconcile/utils/terrascript_aws_client.py,sha256=
|
728
|
+
reconcile/utils/terraform_client.py,sha256=LjX2U2E0Dglt2S_KA5jWQ_dVC8sPn4FEAh0xW_d6JTk,35953
|
729
|
+
reconcile/utils/terrascript_aws_client.py,sha256=SMsJaOmpn_9QQHhKIN_5ps1zOa9zEcBSsxGOyvF8voU,280492
|
729
730
|
reconcile/utils/three_way_diff_strategy.py,sha256=oQcHXd9LVhirJfoaOBoHUYuZVGfyL2voKr6KVI34zZE,4833
|
730
731
|
reconcile/utils/throughput.py,sha256=iP4UWAe2LVhDo69mPPmgo9nQ7RxHD6_GS8MZe-aSiuM,344
|
731
732
|
reconcile/utils/vault.py,sha256=9GSNHku8tw5KM2LKpZ1myWYDLtLGUJgpSnD0DxbzeO0,14956
|
@@ -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.1rc1063.dist-info/METADATA,sha256=7-a0ZUIlQEjsDHPbo9WkNXXBEumFIE91sWi6HVm8Umw,2213
|
872
|
+
qontract_reconcile-0.10.1rc1063.dist-info/WHEEL,sha256=eOLhNAGa2EW3wWl_TU484h7q1UNgy0JXjjoqKoxAAQc,92
|
873
|
+
qontract_reconcile-0.10.1rc1063.dist-info/entry_points.txt,sha256=GKQqCl2j2X1BJQ69een6rHcR26PmnxnONLNOQB-nRjY,491
|
874
|
+
qontract_reconcile-0.10.1rc1063.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
875
|
+
qontract_reconcile-0.10.1rc1063.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")
|
@@ -147,6 +147,7 @@ query ClustersWithPeering {
|
|
147
147
|
}
|
148
148
|
tags
|
149
149
|
cidrBlock
|
150
|
+
cidrBlocks
|
150
151
|
manageSecurityGroups
|
151
152
|
manageRoute53Associations
|
152
153
|
allowPrivateHcpApiAccess
|
@@ -268,6 +269,7 @@ class ClusterPeeringConnectionAccountTGWV1(ClusterPeeringConnectionV1):
|
|
268
269
|
account: ClusterPeeringConnectionAccountTGWV1_AWSAccountV1 = Field(..., alias="account")
|
269
270
|
tags: Optional[Json] = Field(..., alias="tags")
|
270
271
|
cidr_block: Optional[str] = Field(..., alias="cidrBlock")
|
272
|
+
cidr_blocks: Optional[list[str]] = Field(..., alias="cidrBlocks")
|
271
273
|
manage_security_groups: Optional[bool] = Field(..., alias="manageSecurityGroups")
|
272
274
|
manage_route53_associations: Optional[bool] = Field(..., alias="manageRoute53Associations")
|
273
275
|
allow_private_hcp_api_access: Optional[bool] = Field(..., alias="allowPrivateHcpApiAccess")
|
@@ -64,11 +64,14 @@ class ValidationError(Exception):
|
|
64
64
|
pass
|
65
65
|
|
66
66
|
|
67
|
-
class
|
67
|
+
class TGWAccountProviderInfo(BaseModel):
|
68
68
|
name: str
|
69
69
|
uid: str
|
70
70
|
assume_role: str | None
|
71
71
|
assume_region: str
|
72
|
+
|
73
|
+
|
74
|
+
class ClusterAccountProviderInfo(TGWAccountProviderInfo):
|
72
75
|
assume_cidr: str
|
73
76
|
|
74
77
|
|
@@ -79,8 +82,9 @@ class Requester(BaseModel):
|
|
79
82
|
routes: list[dict] | None
|
80
83
|
rules: list[dict] | None
|
81
84
|
hostedzones: list[str] | None
|
82
|
-
cidr_block: str
|
83
|
-
|
85
|
+
cidr_block: str | None
|
86
|
+
cidr_blocks: list[str]
|
87
|
+
account: TGWAccountProviderInfo
|
84
88
|
|
85
89
|
|
86
90
|
class Accepter(BaseModel):
|
@@ -89,7 +93,7 @@ class Accepter(BaseModel):
|
|
89
93
|
vpc_id: str | None
|
90
94
|
route_table_ids: list[str] | None
|
91
95
|
subnets_id_az: list[dict] | None
|
92
|
-
account:
|
96
|
+
account: ClusterAccountProviderInfo
|
93
97
|
api_security_group_id: str | None
|
94
98
|
|
95
99
|
|
@@ -225,7 +229,7 @@ def _build_account_with_assume_role(
|
|
225
229
|
region: str,
|
226
230
|
cidr_block: str,
|
227
231
|
ocm: OCM | None,
|
228
|
-
) ->
|
232
|
+
) -> ClusterAccountProviderInfo:
|
229
233
|
account = peer_connection.account
|
230
234
|
# assume_role is the role to assume to provision the
|
231
235
|
# peering connection request, through the accepter AWS account.
|
@@ -235,7 +239,7 @@ def _build_account_with_assume_role(
|
|
235
239
|
# there is no OCM at all.
|
236
240
|
if not assume_role:
|
237
241
|
if isinstance(cluster.spec, ClusterSpecROSAV1) and cluster.spec.account:
|
238
|
-
return
|
242
|
+
return ClusterAccountProviderInfo(
|
239
243
|
name=cluster.spec.account.name,
|
240
244
|
uid=cluster.spec.account.uid,
|
241
245
|
assume_role=assume_role,
|
@@ -247,7 +251,7 @@ def _build_account_with_assume_role(
|
|
247
251
|
assume_role = ocm.get_aws_infrastructure_access_terraform_assume_role(
|
248
252
|
cluster.name, account.uid, account.terraform_username
|
249
253
|
)
|
250
|
-
return
|
254
|
+
return ClusterAccountProviderInfo(
|
251
255
|
name=account.name,
|
252
256
|
uid=account.uid,
|
253
257
|
assume_role=assume_role,
|
@@ -258,7 +262,7 @@ def _build_account_with_assume_role(
|
|
258
262
|
|
259
263
|
def _build_accepter(
|
260
264
|
peer_connection: ClusterPeeringConnectionAccountTGWV1,
|
261
|
-
account:
|
265
|
+
account: ClusterAccountProviderInfo,
|
262
266
|
region: str,
|
263
267
|
cidr_block: str,
|
264
268
|
awsapi: AWSApi,
|
@@ -290,11 +294,10 @@ def _build_requester(
|
|
290
294
|
peer_connection: ClusterPeeringConnectionAccountTGWV1,
|
291
295
|
tgw: Mapping,
|
292
296
|
) -> Requester:
|
293
|
-
tgw_account =
|
297
|
+
tgw_account = TGWAccountProviderInfo(
|
294
298
|
name=peer_connection.account.name,
|
295
299
|
uid=peer_connection.account.uid,
|
296
300
|
assume_region=tgw["region"],
|
297
|
-
assume_cidr=peer_connection.cidr_block,
|
298
301
|
)
|
299
302
|
return Requester(
|
300
303
|
tgw_id=tgw["tgw_id"],
|
@@ -304,6 +307,7 @@ def _build_requester(
|
|
304
307
|
rules=tgw.get("rules"),
|
305
308
|
hostedzones=tgw.get("hostedzones"),
|
306
309
|
cidr_block=peer_connection.cidr_block,
|
310
|
+
cidr_blocks=peer_connection.cidr_blocks or [],
|
307
311
|
account=tgw_account,
|
308
312
|
)
|
309
313
|
|
@@ -161,6 +161,7 @@ def peering_connection_builder(
|
|
161
161
|
account: ClusterPeeringConnectionAccountTGWV1_AWSAccountV1 | None = None,
|
162
162
|
assume_role: str | None = None,
|
163
163
|
cidr_block: str | None = None,
|
164
|
+
cidr_blocks: list[str] | None = None,
|
164
165
|
delete: bool | None = None,
|
165
166
|
) -> ClusterPeeringConnectionAccountTGWV1:
|
166
167
|
return gql_class_factory(
|
@@ -172,6 +173,7 @@ def peering_connection_builder(
|
|
172
173
|
"account": account.dict(by_alias=True) if account is not None else None,
|
173
174
|
"assumeRole": assume_role,
|
174
175
|
"cidrBlock": cidr_block,
|
176
|
+
"cidrBlocks": cidr_blocks,
|
175
177
|
"delete": delete,
|
176
178
|
},
|
177
179
|
)
|
@@ -191,6 +193,7 @@ def account_tgw_connection(
|
|
191
193
|
account=tgw_connection_account,
|
192
194
|
assume_role=None,
|
193
195
|
cidr_block="172.16.0.0/16",
|
196
|
+
cidr_blocks=["10.240.0.0/12"],
|
194
197
|
delete=False,
|
195
198
|
)
|
196
199
|
|
@@ -481,6 +484,7 @@ def build_expected_desired_state_item(
|
|
481
484
|
rules=tgw["rules"],
|
482
485
|
hostedzones=tgw["hostedzones"],
|
483
486
|
cidr_block=connection.cidr_block,
|
487
|
+
cidr_blocks=connection.cidr_blocks or [],
|
484
488
|
account=expected_tgw_account,
|
485
489
|
),
|
486
490
|
accepter=Accepter(
|
@@ -331,12 +331,28 @@ class TerraformClient: # pylint: disable=too-many-public-methods
|
|
331
331
|
for resource_change in resource_changes:
|
332
332
|
resource_type = resource_change["type"]
|
333
333
|
resource_name = resource_change["name"]
|
334
|
+
resource_address = resource_change["address"]
|
335
|
+
resource_previous_address = resource_change.get("previous_address")
|
334
336
|
resource_change = resource_change["change"]
|
335
337
|
actions = resource_change["actions"]
|
336
338
|
for action in actions:
|
339
|
+
if resource_previous_address:
|
340
|
+
# the resource is being moved/renamed in the TF state
|
341
|
+
with self._log_lock:
|
342
|
+
logging.info([
|
343
|
+
"move/rename",
|
344
|
+
name,
|
345
|
+
resource_previous_address,
|
346
|
+
resource_address,
|
347
|
+
])
|
348
|
+
|
337
349
|
if action == "no-op":
|
338
350
|
logging.debug([action, name, resource_type, resource_name])
|
339
|
-
|
351
|
+
if resource_previous_address:
|
352
|
+
# apply resource renaming with no-op
|
353
|
+
self.increment_apply_count()
|
354
|
+
else:
|
355
|
+
continue
|
340
356
|
if action == "update" and resource_type == "aws_db_instance":
|
341
357
|
self.validate_db_upgrade(name, resource_name, resource_change)
|
342
358
|
# Ignore RDS modifications that are going to occur during the next
|
@@ -35,6 +35,7 @@ from sretoolbox.utils import threaded
|
|
35
35
|
# temporary to create aws_ecrpublic_repository
|
36
36
|
from terrascript import (
|
37
37
|
Backend,
|
38
|
+
Block,
|
38
39
|
Data,
|
39
40
|
Module,
|
40
41
|
Output,
|
@@ -299,6 +300,13 @@ class UnapprovedSecretPathError(Exception):
|
|
299
300
|
pass
|
300
301
|
|
301
302
|
|
303
|
+
class Moved(Block):
|
304
|
+
"""Terraform `moved` block, available since Terraform 1.1"""
|
305
|
+
|
306
|
+
def __init__(self, fro: str, to: str):
|
307
|
+
super().__init__(fro=fro, to=to)
|
308
|
+
|
309
|
+
|
302
310
|
class aws_ecrpublic_repository(Resource):
|
303
311
|
pass
|
304
312
|
|
@@ -1392,17 +1400,32 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
1392
1400
|
# add routes to existing route tables
|
1393
1401
|
route_table_ids = accepter.route_table_ids
|
1394
1402
|
req_cidr_block = requester.cidr_block
|
1395
|
-
|
1403
|
+
req_cidr_blocks = requester.cidr_blocks or []
|
1404
|
+
if req_cidr_block:
|
1405
|
+
req_cidr_blocks.append(req_cidr_block)
|
1406
|
+
if route_table_ids and (req_cidr_block or req_cidr_blocks):
|
1396
1407
|
for route_table_id in route_table_ids:
|
1397
|
-
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
1408
|
+
for cidr_block in req_cidr_blocks:
|
1409
|
+
values = {
|
1410
|
+
"provider": "aws." + acc_alias,
|
1411
|
+
"route_table_id": route_table_id,
|
1412
|
+
"destination_cidr_block": cidr_block,
|
1413
|
+
"transit_gateway_id": requester.tgw_id,
|
1414
|
+
}
|
1415
|
+
# use the cidr block in the resource name to allow re-ordering
|
1416
|
+
cidr_id = cidr_block.replace(".", "-").replace("/", "_")
|
1417
|
+
route_identifier = (
|
1418
|
+
f"{identifier}-{route_table_id}-dest-{cidr_id}"
|
1419
|
+
)
|
1420
|
+
tf_resource = aws_route(route_identifier, **values)
|
1421
|
+
self.add_resource(infra_account_name, tf_resource)
|
1422
|
+
if req_cidr_block:
|
1423
|
+
req_cidr_id = req_cidr_block.replace(".", "-").replace("/", "_")
|
1424
|
+
moved = Moved(
|
1425
|
+
fro=f"aws_route.{identifier}-{route_table_id}",
|
1426
|
+
to=f"aws_route.{identifier}-{route_table_id}-dest-{req_cidr_id}",
|
1427
|
+
)
|
1428
|
+
self.add_moved(infra_account_name, moved)
|
1406
1429
|
|
1407
1430
|
# add routes to peered transit gateways in the requester's
|
1408
1431
|
# account to achieve global routing from all regions
|
@@ -4084,6 +4107,19 @@ class TerrascriptClient: # pylint: disable=too-many-public-methods
|
|
4084
4107
|
with self.locks[account]:
|
4085
4108
|
self.tss[account].add(tf_resource)
|
4086
4109
|
|
4110
|
+
def add_moved(self, account: str, moved: Moved):
|
4111
|
+
if account not in self.locks:
|
4112
|
+
logging.debug(
|
4113
|
+
f"integration {self.integration} is disabled for account {account}. "
|
4114
|
+
"can not add resource"
|
4115
|
+
)
|
4116
|
+
return
|
4117
|
+
with self.locks[account]:
|
4118
|
+
self.tss[account].setdefault("moved", []).append({
|
4119
|
+
"from": moved.fro,
|
4120
|
+
"to": moved.to,
|
4121
|
+
})
|
4122
|
+
|
4087
4123
|
def dump(
|
4088
4124
|
self,
|
4089
4125
|
print_to_file: str | None = None,
|
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.1rc1061.dist-info → qontract_reconcile-0.10.1rc1063.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|
File without changes
|