qontract-reconcile 0.10.1rc711__py3-none-any.whl → 0.10.1rc712__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qontract-reconcile
3
- Version: 0.10.1rc711
3
+ Version: 0.10.1rc712
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
@@ -18,7 +18,7 @@ reconcile/dashdotdb_dora.py,sha256=n9EJXhxCoMYuldj4Fa5s0TqfiiolSrqDEOCaLBV3uag,1
18
18
  reconcile/dashdotdb_dvo.py,sha256=YXqpI6fBQAql-ybGI0grj9gWMzmKiAvPE__pNju6obk,8996
19
19
  reconcile/dashdotdb_slo.py,sha256=bf1WSh5JP9obHVQsMy0OO71_VTYZgwAopElFZM6DmRo,6714
20
20
  reconcile/database_access_manager.py,sha256=42dBJyihdwx4WjEBjwi3lUiDzQ1t_2ZFViJri2c4_aE,25716
21
- reconcile/deadmanssnitch.py,sha256=ET4gUX1WvmWsILI10GgcPDOuJL2f3bDwwvKORWvyFhc,7339
21
+ reconcile/deadmanssnitch.py,sha256=n-5W-djUgwzpmdDM4eQIZpkkDmHY0vndt-42LJXI4Y8,7491
22
22
  reconcile/dynatrace_token_provider.py,sha256=P5jvMavremWp64LVknz1kCZI4aagwLrDDfXkmJ9diwY,17212
23
23
  reconcile/email_sender.py,sha256=-5L-Ag_jaEYSzYRoMr52KQBRXz1E8yx9GqLbg2X4XFU,3533
24
24
  reconcile/gabi_authorized_users.py,sha256=9kpSJGyMe_qYVHIgTFHhYf8E3lKSLO0Ia1WwK9ADNIE,4502
@@ -440,7 +440,7 @@ reconcile/test/test_cli.py,sha256=qx_iBwh4Z-YkK3sbjK1wEziPTgn060EN-baf9DNvR3k,10
440
440
  reconcile/test/test_closedbox_endpoint_monitoring.py,sha256=isMHYwRWMFARU2nbJgbl69kD6H0eA86noCM4MPVI1fo,7151
441
441
  reconcile/test/test_dashdotdb_dora.py,sha256=MfHGAsX2eSQSvBVt9_1Sah3aQKNJBXA9Iu86X0NWD6c,7705
442
442
  reconcile/test/test_database_access_manager.py,sha256=-9fYo8wMNhbJUTK_bd7g_fS5zYsAlqQ0rBDDYBMZvZQ,19595
443
- reconcile/test/test_deadmanssnitch.py,sha256=3AiarCKkSPU1cEkVwooglwU3sQgDifMAiXuJb1P9_vI,9220
443
+ reconcile/test/test_deadmanssnitch.py,sha256=qtn1zwWgIQYw5JULLPvDLaj0GWiecYnvky0HcuETjdo,9843
444
444
  reconcile/test/test_gabi_authorized_users.py,sha256=6XnV5Q9inxP81ktGMVKyWucjBTUj8Imy2L0HG3YHyUE,2496
445
445
  reconcile/test/test_gcr_mirror.py,sha256=A0y8auKZzr62-mGoxSQ__JnN0-ijZUltzjwR5miBgso,490
446
446
  reconcile/test/test_github_org.py,sha256=j3KeB4OnSln1gm2hidce49xdMru-j75NS3cM-AEgzZc,4511
@@ -764,8 +764,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
764
764
  tools/test/test_qontract_cli.py,sha256=UEwAW7PA_GIrbqzaLxpkCxbuVjEFLNvnVG-6VyoCGIc,4147
765
765
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
766
766
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
767
- qontract_reconcile-0.10.1rc711.dist-info/METADATA,sha256=C66Bft6HzT9sQVAcNyckeGBHPW2gAhwMv7dGVxGcF_Y,2382
768
- qontract_reconcile-0.10.1rc711.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
769
- qontract_reconcile-0.10.1rc711.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
770
- qontract_reconcile-0.10.1rc711.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
771
- qontract_reconcile-0.10.1rc711.dist-info/RECORD,,
767
+ qontract_reconcile-0.10.1rc712.dist-info/METADATA,sha256=MeTu0tcuNA_jlvS3yM5lz9s0oR5AQtaXj5SbIG8_qjk,2382
768
+ qontract_reconcile-0.10.1rc712.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
769
+ qontract_reconcile-0.10.1rc712.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
770
+ qontract_reconcile-0.10.1rc712.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
771
+ qontract_reconcile-0.10.1rc712.dist-info/RECORD,,
@@ -1,6 +1,5 @@
1
1
  import logging
2
2
  from typing import (
3
- Optional,
4
3
  cast,
5
4
  )
6
5
 
@@ -20,12 +19,8 @@ from reconcile.utils.runtime.integration import (
20
19
  NoParams,
21
20
  QontractReconcileIntegration,
22
21
  )
23
- from reconcile.utils.secret_reader import (
24
- SecretNotFound,
25
- )
26
22
  from reconcile.utils.semver_helper import make_semver
27
23
  from reconcile.utils.vault import (
28
- SecretFieldNotFound,
29
24
  VaultClient,
30
25
  _VaultClient,
31
26
  )
@@ -62,37 +57,24 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
62
57
  def get_snitch_name(cluster: ClusterV1) -> str:
63
58
  return cluster.prometheus_url.replace("https://", "")
64
59
 
65
- def write_snitch_to_vault(
66
- self, cluster_name: str, snitch_url: Optional[str]
67
- ) -> None:
68
- if snitch_url:
69
- self.vault_client.write(
70
- {
71
- "path": self.settings.snitches_path,
72
- "data": {f"deadmanssnitch-{cluster_name}-url": snitch_url},
73
- },
74
- decode_base64=False,
75
- )
60
+ @staticmethod
61
+ def get_vault_key(cluster_name: str) -> str:
62
+ return f"deadmanssnitch-{cluster_name}-url"
76
63
 
77
64
  def add_vault_data(
78
- self, cluster_name: str, snitch: Snitch, snitch_secret_path: str
65
+ self, cluster_name: str, snitch: Snitch, vault_snitch_map: dict[str, str]
79
66
  ) -> Snitch:
80
- try:
81
- full_secret_path = {
82
- "path": snitch_secret_path,
83
- "field": f"deadmanssnitch-{cluster_name}-url",
84
- }
85
- snitch.vault_data = self.secret_reader.read(full_secret_path).strip()
86
- except (SecretNotFound, SecretFieldNotFound):
67
+ if snitch_url := vault_snitch_map.get(self.get_vault_key(cluster_name)):
68
+ snitch.vault_data = snitch_url
69
+ else:
87
70
  snitch.vault_data = SECRET_NOT_FOUND
88
71
  return snitch
89
72
 
90
73
  def create_snitch(
91
74
  self,
92
- cluster_name: str,
93
75
  snitch_spec: SnitchSpec,
94
76
  deadmanssnitch_api: DeadMansSnitchApi,
95
- ) -> None:
77
+ ) -> Snitch:
96
78
  payload = {
97
79
  "name": snitch_spec.name,
98
80
  "alert_type": snitch_spec.alert_type,
@@ -102,9 +84,7 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
102
84
  "notes": snitch_spec.notes,
103
85
  }
104
86
  snitch_data = deadmanssnitch_api.create_snitch(payload=payload)
105
- self.write_snitch_to_vault(
106
- cluster_name=cluster_name, snitch_url=snitch_data.check_in_url
107
- )
87
+ return snitch_data
108
88
 
109
89
  def reconcile(
110
90
  self,
@@ -112,6 +92,7 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
112
92
  current_state: dict[str, Snitch],
113
93
  desired_state: dict[str, SnitchSpec],
114
94
  deadmanssnitch_api: DeadMansSnitchApi,
95
+ vault_snitch_map: dict[str, str],
115
96
  ) -> None:
116
97
  diffs = diff_mappings(
117
98
  current=current_state,
@@ -119,11 +100,15 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
119
100
  equal=lambda current, desired: current.name == desired.name,
120
101
  )
121
102
  errors = []
103
+ vault_snitch_map_copy = vault_snitch_map.copy()
122
104
  for cluster_name, snitch in diffs.add.items():
123
105
  logging.info("[cluster_name:%s] [Action:create_snitch]", cluster_name)
124
106
  if not dry_run:
125
107
  try:
126
- self.create_snitch(cluster_name, snitch, deadmanssnitch_api)
108
+ snitch_data = self.create_snitch(snitch, deadmanssnitch_api)
109
+ vault_snitch_map_copy[self.get_vault_key(cluster_name)] = (
110
+ snitch_data.check_in_url
111
+ )
127
112
  except Exception as e:
128
113
  errors.append(e)
129
114
  for cluster_name, snitch_value in diffs.delete.items():
@@ -136,14 +121,23 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
136
121
  for cluster_name, diff_pair in diffs.identical.items():
137
122
  if diff_pair.current.needs_vault_update():
138
123
  logging.info("[cluster_name:%s] [Action:update_vault]", cluster_name)
139
- if not dry_run:
140
- try:
141
- self.write_snitch_to_vault(
142
- cluster_name=cluster_name,
143
- snitch_url=diff_pair.current.check_in_url,
144
- )
145
- except Exception as e:
146
- errors.append(e)
124
+ vault_snitch_map_copy[self.get_vault_key(cluster_name)] = (
125
+ diff_pair.current.check_in_url
126
+ )
127
+
128
+ # write to vault in case there is change in secret i.e in case of creation/update
129
+ if vault_snitch_map != vault_snitch_map_copy and not dry_run:
130
+ try:
131
+ self.vault_client.write(
132
+ {
133
+ "path": self.settings.snitches_path,
134
+ "data": vault_snitch_map_copy,
135
+ },
136
+ decode_base64=False,
137
+ )
138
+ except Exception as e:
139
+ errors.append(e)
140
+
147
141
  if errors:
148
142
  raise ExceptionGroup("Errors occurred while reconcile", errors)
149
143
 
@@ -151,6 +145,7 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
151
145
  self,
152
146
  deadmanssnitch_api: DeadMansSnitchApi,
153
147
  clusters: list[ClusterV1],
148
+ vault_snitch_map: dict[str, str],
154
149
  ) -> dict[str, Snitch]:
155
150
  snitch_name_to_cluster_name_mapping = {
156
151
  self.get_snitch_name(cluster): cluster.name for cluster in clusters
@@ -159,9 +154,7 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
159
154
  snitches = deadmanssnitch_api.get_snitches(tags=self.settings.tags)
160
155
  # create snitch_map only for the desired clusters
161
156
  current_state = {
162
- cluster_name: self.add_vault_data(
163
- cluster_name, snitch, self.settings.snitches_path
164
- )
157
+ cluster_name: self.add_vault_data(cluster_name, snitch, vault_snitch_map)
165
158
  for snitch in snitches
166
159
  if (cluster_name := snitch_name_to_cluster_name_mapping.get(snitch.name))
167
160
  }
@@ -191,6 +184,10 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
191
184
  "path": self.settings.token_creds.path,
192
185
  "field": self.settings.token_creds.field,
193
186
  })
187
+ # get all snitch secrets from vault
188
+ vault_snitch_map = self.secret_reader.read_all({
189
+ "path": self.settings.snitches_path
190
+ })
194
191
  with DeadMansSnitchApi(token=token) as deadmanssnitch_api:
195
192
  # desired state - get the clusters having enableDeadMansSnitch field
196
193
  clusters = get_clusters_with_dms()
@@ -199,10 +196,12 @@ class DeadMansSnitchIntegration(QontractReconcileIntegration[NoParams]):
199
196
  current_state = self.get_current_state(
200
197
  deadmanssnitch_api,
201
198
  clusters,
199
+ vault_snitch_map,
202
200
  )
203
201
  self.reconcile(
204
202
  dry_run,
205
203
  current_state=current_state,
206
204
  desired_state=desired_state,
207
205
  deadmanssnitch_api=deadmanssnitch_api,
206
+ vault_snitch_map=vault_snitch_map,
208
207
  )
@@ -102,6 +102,7 @@ def test_get_current_state(
102
102
  current_state = dms_integration.get_current_state(
103
103
  deadmanssnitch_api=deadmanssnitch_api,
104
104
  clusters=clusters,
105
+ vault_snitch_map={"deadmanssnitch-test_cluster_1-url": "secret"},
105
106
  )
106
107
  assert current_state["test_cluster_1"].vault_data == "secret"
107
108
 
@@ -116,6 +117,7 @@ def test_integration_for_create(
116
117
  "reconcile.deadmanssnitch.DeadMansSnitchIntegration.__init__"
117
118
  ).return_value = None
118
119
  dms_integration = DeadMansSnitchIntegration()
120
+ secret_reader.read_all.return_value = {}
119
121
  dms_integration._secret_reader = secret_reader
120
122
  dms_integration.settings = deadmanssnitch_settings
121
123
  dms_integration.vault_client = vault_mock
@@ -136,7 +138,18 @@ def test_integration_for_create(
136
138
  mock_create_snitch = mocker.patch(
137
139
  "reconcile.deadmanssnitch.DeadMansSnitchIntegration.create_snitch"
138
140
  )
139
- mock_create_snitch.return_value = None
141
+ mock_create_snitch.return_value = Snitch(
142
+ name="prometheus.create_cluster.devshift.net",
143
+ token="test",
144
+ href="testc",
145
+ status="healthy",
146
+ alert_type="basic",
147
+ alert_email=["test_mail"],
148
+ interval="15_minute",
149
+ check_in_url="test_url",
150
+ tags=["app-sre"],
151
+ notes="test_notes",
152
+ )
140
153
  dms_integration.run(dry_run=False)
141
154
  mock_create_snitch.assert_called_once()
142
155
 
@@ -151,6 +164,7 @@ def test_integration_for_delete(
151
164
  "reconcile.deadmanssnitch.DeadMansSnitchIntegration.__init__"
152
165
  ).return_value = None
153
166
  dms_integration = DeadMansSnitchIntegration()
167
+ secret_reader.read_all.return_value = {"deadmanssnitch-create_cluster-url": "test"}
154
168
  dms_integration._secret_reader = secret_reader
155
169
  dms_integration.settings = deadmanssnitch_settings
156
170
  dms_integration.vault_client = vault_mock
@@ -199,6 +213,7 @@ def test_integration_for_update_vault(
199
213
  "reconcile.deadmanssnitch.DeadMansSnitchIntegration.__init__"
200
214
  ).return_value = None
201
215
  dms_integration = DeadMansSnitchIntegration()
216
+ secret_reader.read_all.return_value = {"deadmanssnitch-test_cluster-url": "test"}
202
217
  dms_integration._secret_reader = secret_reader
203
218
  dms_integration.settings = deadmanssnitch_settings
204
219
  dms_integration.vault_client = vault_mock
@@ -230,10 +245,11 @@ def test_integration_for_update_vault(
230
245
  )
231
246
  ]
232
247
  dms_integration.run(dry_run=False)
248
+ data = {"deadmanssnitch-test_cluster-url": "test_url"}
233
249
  vault_mock.write.assert_called_once_with(
234
250
  {
235
251
  "path": deadmanssnitch_settings.snitches_path,
236
- "data": {"deadmanssnitch-test_cluster-url": "test_url"},
252
+ "data": data,
237
253
  },
238
254
  decode_base64=False,
239
255
  )