qontract-reconcile 0.10.2.dev247__py3-none-any.whl → 0.10.2.dev249__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.dev247.dist-info → qontract_reconcile-0.10.2.dev249.dist-info}/METADATA +1 -2
- {qontract_reconcile-0.10.2.dev247.dist-info → qontract_reconcile-0.10.2.dev249.dist-info}/RECORD +7 -8
- reconcile/cli.py +0 -9
- reconcile/status_board.py +31 -39
- reconcile/utils/ocm/ocm.py +0 -56
- reconcile/ocm_github_idp.py +0 -117
- {qontract_reconcile-0.10.2.dev247.dist-info → qontract_reconcile-0.10.2.dev249.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.2.dev247.dist-info → qontract_reconcile-0.10.2.dev249.dist-info}/entry_points.txt +0 -0
{qontract_reconcile-0.10.2.dev247.dist-info → qontract_reconcile-0.10.2.dev249.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.dev249
|
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
|
@@ -205,7 +205,6 @@ OpenShift templates can be found [here](/openshift/qontract-reconcile.yaml). In
|
|
205
205
|
ocm-clusters Manages clusters via OCM.
|
206
206
|
ocm-external-configuration-labels
|
207
207
|
Manage External Configuration labels in OCM.
|
208
|
-
ocm-github-idp Manage GitHub Identity Providers in OCM.
|
209
208
|
ocm-groups Manage membership in OpenShift groups via
|
210
209
|
OCM.
|
211
210
|
ocm-internal-notifications Notifications to internal Red Hat users
|
{qontract_reconcile-0.10.2.dev247.dist-info → qontract_reconcile-0.10.2.dev249.dist-info}/RECORD
RENAMED
@@ -8,7 +8,7 @@ reconcile/aws_iam_password_reset.py,sha256=O0JX2N5kNRKs3u2xzu4NNrI6p0ag5JWy3MTsv
|
|
8
8
|
reconcile/aws_support_cases_sos.py,sha256=PDhilxQ4TBxVnxUPIUdTbKEaNUI0wzPiEsB91oHT2fY,3384
|
9
9
|
reconcile/blackbox_exporter_endpoint_monitoring.py,sha256=O1wFp52EyF538c6txaWBs8eMtUIy19gyHZ6VzJ6QXS8,3512
|
10
10
|
reconcile/checkpoint.py,sha256=gjtS8g6KIyKFYlHMSZjAqDUOlVh83nh4go-9yNrhWZU,5016
|
11
|
-
reconcile/cli.py,sha256=
|
11
|
+
reconcile/cli.py,sha256=BETiU1ewxtown2t7x-h9xlEwSOWL60nFnoV-1Zg_rm4,112510
|
12
12
|
reconcile/closedbox_endpoint_monitoring_base.py,sha256=al7m8EgnnYx90rY1REryW3byN_ItfJfAzEeLtjbCfi0,4921
|
13
13
|
reconcile/cluster_deployment_mapper.py,sha256=5gumAaRCcFXsabUJ1dnuUy9WrP_FEEM5JnOnE8ch9sE,2326
|
14
14
|
reconcile/dashdotdb_base.py,sha256=83ZWIf5JJk3P_D69y2TmXRcQr6ELJGlv10OM0h7fJVs,4767
|
@@ -51,7 +51,6 @@ reconcile/ocm_addons_upgrade_tests_trigger.py,sha256=A9zXeYG-_52DsS1dz47yDSnHz62
|
|
51
51
|
reconcile/ocm_aws_infrastructure_access.py,sha256=rrlcQxvRTmKyYOUR1C-Nlxj_o_iCDSxc7PNoELUDiew,6892
|
52
52
|
reconcile/ocm_clusters.py,sha256=he-BkbEb-ozHuZNqRr2nIWUjBHhLF-2Jvcctx4K3eK4,17021
|
53
53
|
reconcile/ocm_external_configuration_labels.py,sha256=imEpDv1RBpCSj8tHDv0R76hmNCFtcUzVNgS1yOVl8vs,3870
|
54
|
-
reconcile/ocm_github_idp.py,sha256=glwXMsIBcl38-OmDDQCpe0YoLLXfoRgVQmqwXMEXjds,3946
|
55
54
|
reconcile/ocm_groups.py,sha256=nz6n4a0ZVDClpm1HbPfcwJ8fw3AYg7o4DCH-SBItVbs,3389
|
56
55
|
reconcile/ocm_machine_pools.py,sha256=iiqReJMdzmvl9Ae0X1nT48WyROAoLS4pcI4Wk9NdWE0,16637
|
57
56
|
reconcile/ocm_update_recommended_version.py,sha256=Vi3Y2sX-OQxx1mv_xiPQXnmrpsZzGIE38No0yBcTaD4,4204
|
@@ -104,7 +103,7 @@ reconcile/slack_base.py,sha256=I-msunWxfgu5bSwXYulGbtLjxUB_tRmTCAUCU-3nabI,3484
|
|
104
103
|
reconcile/slack_usergroups.py,sha256=xFkVe67RXSUj8JvpfSFEiRdQzB0TnJJEHW_b5PEwLng,30213
|
105
104
|
reconcile/sql_query.py,sha256=auZCWe6dytsDp83Imfo4zqkpMCLRXU007IUlPeUE3j4,26376
|
106
105
|
reconcile/status.py,sha256=cY4IJFXemhxptRJqR4qaaOWqei9e4jgLXuVSGajMsjg,544
|
107
|
-
reconcile/status_board.py,sha256=
|
106
|
+
reconcile/status_board.py,sha256=wDto8vVFXHLIGwh4MfvsXTogVQ08JhqyDmhOyjjTJyk,15288
|
108
107
|
reconcile/terraform_aws_route53.py,sha256=dQzzT46YhwRA902_H6pi-f7WlX4EaH187wXSdmJAUkQ,9958
|
109
108
|
reconcile/terraform_cloudflare_dns.py,sha256=-aLEe2QnH5cJPu7HWqs-R9NmQ1NlFbcVUm0v7alVL3I,13431
|
110
109
|
reconcile/terraform_cloudflare_resources.py,sha256=pq8Ieo5NmB-dYQ9X2F0s6iEoINMzhiqGw2yQK4ovok4,14980
|
@@ -730,7 +729,7 @@ reconcile/utils/ocm/identity_providers.py,sha256=dKed09N8iWmn39tI_MpwgVe47x23eLs
|
|
730
729
|
reconcile/utils/ocm/label_sources.py,sha256=ES_5VP4X6gsRxMFZ95WgbwE_HqqIUo_JRjHjdGYw6Ss,1846
|
731
730
|
reconcile/utils/ocm/labels.py,sha256=CmAgaOEPiaUb4gLtKab9vNkSDJceuREPd4ApgGcIA1U,6240
|
732
731
|
reconcile/utils/ocm/manifests.py,sha256=Q6kgOeiAwLbJY_vO_BEW2oePvbLDZcMZk20YpJJGpOA,1195
|
733
|
-
reconcile/utils/ocm/ocm.py,sha256=
|
732
|
+
reconcile/utils/ocm/ocm.py,sha256=4wXsptVwBRlJX19WLgZxZHjx6OJjuWSUyNOxac1EBGM,31454
|
734
733
|
reconcile/utils/ocm/products.py,sha256=Ki9o0VV4z_FsXQaJtSFzlUnxLvpk1H-RamvJpUwwbuQ,26006
|
735
734
|
reconcile/utils/ocm/search_filters.py,sha256=uUCJ-XOEp4D5uxPW7lDqNe6s-mQWLOCqMu9_xvO6PXU,14798
|
736
735
|
reconcile/utils/ocm/service_log.py,sha256=RG1f0MMn6joKaRCAm2xveSJCavdOPP1BVo9FXecDxaI,2018
|
@@ -798,7 +797,7 @@ tools/saas_promotion_state/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
798
797
|
tools/saas_promotion_state/saas_promotion_state.py,sha256=UfwwRLS5Ya4_Nh1w5n1dvoYtchQvYE9yj1VANt2IKqI,3925
|
799
798
|
tools/sre_checkpoints/__init__.py,sha256=CDaDaywJnmRCLyl_NCcvxi-Zc0hTi_3OdwKiFOyS39I,145
|
800
799
|
tools/sre_checkpoints/util.py,sha256=zEDbGr18ZeHNQwW8pUsr2JRjuXIPz--WAGJxZo9sv_Y,894
|
801
|
-
qontract_reconcile-0.10.2.
|
802
|
-
qontract_reconcile-0.10.2.
|
803
|
-
qontract_reconcile-0.10.2.
|
804
|
-
qontract_reconcile-0.10.2.
|
800
|
+
qontract_reconcile-0.10.2.dev249.dist-info/METADATA,sha256=gwjkeR4GBIHNQvWj-GxTlvIelNg9lny81cU3jDwHC8c,23974
|
801
|
+
qontract_reconcile-0.10.2.dev249.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
802
|
+
qontract_reconcile-0.10.2.dev249.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
|
803
|
+
qontract_reconcile-0.10.2.dev249.dist-info/RECORD,,
|
reconcile/cli.py
CHANGED
@@ -2958,15 +2958,6 @@ def ocm_aws_infrastructure_access(ctx: click.Context) -> None:
|
|
2958
2958
|
run_integration(reconcile.ocm_aws_infrastructure_access, ctx)
|
2959
2959
|
|
2960
2960
|
|
2961
|
-
@integration.command(short_help="Manage GitHub Identity Providers in OCM.")
|
2962
|
-
@vault_input_path
|
2963
|
-
@click.pass_context
|
2964
|
-
def ocm_github_idp(ctx: click.Context, vault_input_path: str) -> None:
|
2965
|
-
import reconcile.ocm_github_idp
|
2966
|
-
|
2967
|
-
run_integration(reconcile.ocm_github_idp, ctx, vault_input_path)
|
2968
|
-
|
2969
|
-
|
2970
2961
|
@integration.command(
|
2971
2962
|
short_help="Manage OIDC cluster configuration in OCM organizations based on OCM labels. Part of RHIDP."
|
2972
2963
|
)
|
reconcile/status_board.py
CHANGED
@@ -5,9 +5,7 @@ from abc import (
|
|
5
5
|
)
|
6
6
|
from collections.abc import Iterable, Mapping
|
7
7
|
from enum import Enum
|
8
|
-
from
|
9
|
-
Optional,
|
10
|
-
)
|
8
|
+
from itertools import chain
|
11
9
|
|
12
10
|
from pydantic import BaseModel
|
13
11
|
|
@@ -122,11 +120,11 @@ class Product(AbstractStatusBoard):
|
|
122
120
|
|
123
121
|
|
124
122
|
class Application(AbstractStatusBoard):
|
125
|
-
product:
|
123
|
+
product: Product
|
126
124
|
services: list["Service"] | None
|
127
125
|
|
128
126
|
def create(self, ocm: OCMBaseClient) -> None:
|
129
|
-
if self.product
|
127
|
+
if self.product.id:
|
130
128
|
spec = self.to_ocm_spec()
|
131
129
|
self.id = create_application(ocm, spec)
|
132
130
|
else:
|
@@ -147,7 +145,7 @@ class Application(AbstractStatusBoard):
|
|
147
145
|
return f'Application: "{self.name}" "{self.fullname}"'
|
148
146
|
|
149
147
|
def to_ocm_spec(self) -> ApplicationOCMSpec:
|
150
|
-
product_id = self.product.id
|
148
|
+
product_id = self.product.id or ""
|
151
149
|
return {
|
152
150
|
"name": self.name,
|
153
151
|
"fullname": self.fullname,
|
@@ -160,18 +158,12 @@ class Application(AbstractStatusBoard):
|
|
160
158
|
|
161
159
|
|
162
160
|
class Service(AbstractStatusBoard):
|
163
|
-
|
164
|
-
# This field is optional so we can create the Service object without the
|
165
|
-
# need to create an Application object first.
|
166
|
-
# This filed is needed when we are creating a Service on teh OCM API.
|
167
|
-
# This field is not used when we are mapping the services that belongs to an
|
168
|
-
# application in that case we use the `services` field in Application class.
|
169
|
-
application: Optional["Application"]
|
161
|
+
application: Application
|
170
162
|
metadata: ServiceMetadataSpec
|
171
163
|
|
172
164
|
def create(self, ocm: OCMBaseClient) -> None:
|
173
165
|
spec = self.to_ocm_spec()
|
174
|
-
if self.application
|
166
|
+
if self.application.id:
|
175
167
|
self.id = create_service(ocm, spec)
|
176
168
|
else:
|
177
169
|
logging.warning("Missing application id for service")
|
@@ -187,7 +179,7 @@ class Service(AbstractStatusBoard):
|
|
187
179
|
logging.error(f'Trying to update Service "{self.name}" without id')
|
188
180
|
return
|
189
181
|
spec = self.to_ocm_spec()
|
190
|
-
if self.application
|
182
|
+
if self.application.id:
|
191
183
|
update_service(ocm, self.id, spec)
|
192
184
|
else:
|
193
185
|
logging.warning("Missing application id for service")
|
@@ -196,9 +188,7 @@ class Service(AbstractStatusBoard):
|
|
196
188
|
return f'Service: "{self.name}" "{self.fullname}"'
|
197
189
|
|
198
190
|
def to_ocm_spec(self) -> ServiceOCMSpec:
|
199
|
-
application_id =
|
200
|
-
self.application.id if self.application and self.application.id else ""
|
201
|
-
)
|
191
|
+
application_id = self.application.id or ""
|
202
192
|
|
203
193
|
return {
|
204
194
|
"name": self.name,
|
@@ -281,21 +271,24 @@ class StatusBoardExporterIntegration(QontractReconcileIntegration):
|
|
281
271
|
logging.error(f'Product "{p.name}" has no id')
|
282
272
|
continue
|
283
273
|
p.applications = [
|
284
|
-
Application(**a
|
274
|
+
Application(**a, product=p)
|
275
|
+
for a in get_product_applications(ocm_api, p.id)
|
285
276
|
]
|
286
277
|
for a in p.applications:
|
287
278
|
if not a.id:
|
288
279
|
logging.error(f'Application "{a.name}" has no id')
|
289
280
|
continue
|
290
281
|
a.services = [
|
291
|
-
Service(**s
|
282
|
+
Service(**s, application=a)
|
283
|
+
for s in get_application_services(ocm_api, a.id)
|
292
284
|
]
|
293
285
|
|
294
286
|
return products
|
295
287
|
|
296
288
|
@staticmethod
|
297
289
|
def desired_abstract_status_board_map(
|
298
|
-
desired_product_apps: Mapping[str, set[str]],
|
290
|
+
desired_product_apps: Mapping[str, set[str]],
|
291
|
+
slodocs: list[SLODocumentV1],
|
299
292
|
) -> dict[str, AbstractStatusBoard]:
|
300
293
|
"""
|
301
294
|
Returns a Mapping of all the AbstractStatusBoard data objects as dictionaries.
|
@@ -304,25 +297,26 @@ class StatusBoardExporterIntegration(QontractReconcileIntegration):
|
|
304
297
|
on Status Board OCM API.
|
305
298
|
"""
|
306
299
|
desired_abstract_status_board_map: dict[str, AbstractStatusBoard] = {}
|
307
|
-
for
|
308
|
-
|
309
|
-
name=
|
300
|
+
for product_name, apps in desired_product_apps.items():
|
301
|
+
product = Product(
|
302
|
+
id=None, name=product_name, fullname=product_name, applications=[]
|
310
303
|
)
|
304
|
+
desired_abstract_status_board_map[product_name] = product
|
311
305
|
for a in apps:
|
312
|
-
key = f"{
|
306
|
+
key = f"{product_name}/{a}"
|
313
307
|
desired_abstract_status_board_map[key] = Application(
|
308
|
+
id=None,
|
314
309
|
name=a,
|
315
310
|
fullname=key,
|
316
311
|
services=[],
|
317
|
-
product=
|
318
|
-
metadata={},
|
312
|
+
product=product,
|
319
313
|
)
|
320
314
|
for slodoc in slodocs:
|
321
315
|
products = [
|
322
316
|
ns.namespace.environment.product.name for ns in slodoc.namespaces
|
323
317
|
]
|
324
318
|
for slo in slodoc.slos or []:
|
325
|
-
for
|
319
|
+
for product_name in products:
|
326
320
|
if slodoc.app.parent_app:
|
327
321
|
app = f"{slodoc.app.parent_app.name}-{slodoc.app.name}"
|
328
322
|
else:
|
@@ -330,8 +324,8 @@ class StatusBoardExporterIntegration(QontractReconcileIntegration):
|
|
330
324
|
|
331
325
|
# Check if the product or app is excluded from the desired list
|
332
326
|
product_or_app_excluded = (
|
333
|
-
|
334
|
-
or app not in desired_product_apps.get(
|
327
|
+
product_name not in desired_product_apps
|
328
|
+
or app not in desired_product_apps.get(product_name, set())
|
335
329
|
)
|
336
330
|
|
337
331
|
# Check if statusBoard label exists and is explicitly disabled
|
@@ -344,8 +338,8 @@ class StatusBoardExporterIntegration(QontractReconcileIntegration):
|
|
344
338
|
if product_or_app_excluded or not status_board_enabled:
|
345
339
|
continue
|
346
340
|
|
347
|
-
key = f"{
|
348
|
-
metadata = {
|
341
|
+
key = f"{product_name}/{app}/{slo.name}"
|
342
|
+
metadata: ServiceMetadataSpec = {
|
349
343
|
"sli_type": slo.sli_type,
|
350
344
|
"sli_specification": slo.sli_specification,
|
351
345
|
"slo_details": slo.slo_details,
|
@@ -354,11 +348,12 @@ class StatusBoardExporterIntegration(QontractReconcileIntegration):
|
|
354
348
|
"window": slo.slo_parameters.window,
|
355
349
|
}
|
356
350
|
desired_abstract_status_board_map[key] = Service(
|
351
|
+
id=None,
|
357
352
|
name=slo.name,
|
358
353
|
fullname=key,
|
359
354
|
metadata=metadata,
|
360
355
|
application=desired_abstract_status_board_map[
|
361
|
-
f"{
|
356
|
+
f"{product_name}/{app}"
|
362
357
|
],
|
363
358
|
)
|
364
359
|
|
@@ -382,7 +377,6 @@ class StatusBoardExporterIntegration(QontractReconcileIntegration):
|
|
382
377
|
def get_diff(
|
383
378
|
desired_abstract_status_board_map: Mapping[str, AbstractStatusBoard],
|
384
379
|
current_abstract_status_board_map: Mapping[str, AbstractStatusBoard],
|
385
|
-
current_products: Mapping[str, Product],
|
386
380
|
) -> list[StatusBoardHandler]:
|
387
381
|
return_list: list[StatusBoardHandler] = []
|
388
382
|
|
@@ -391,6 +385,9 @@ class StatusBoardExporterIntegration(QontractReconcileIntegration):
|
|
391
385
|
desired_abstract_status_board_map,
|
392
386
|
)
|
393
387
|
|
388
|
+
for pair in chain(diff_result.identical.values(), diff_result.change.values()):
|
389
|
+
pair.desired.id = pair.current.id
|
390
|
+
|
394
391
|
return_list.extend(
|
395
392
|
StatusBoardHandler(action=Action.create, status_board_object=o)
|
396
393
|
for o in diff_result.add.values()
|
@@ -460,14 +457,9 @@ class StatusBoardExporterIntegration(QontractReconcileIntegration):
|
|
460
457
|
current_abstract_status_board_map = self.current_abstract_status_board_map(
|
461
458
|
current_products_applications_services
|
462
459
|
)
|
463
|
-
|
464
|
-
current_products = {
|
465
|
-
p.name: p for p in current_products_applications_services
|
466
|
-
}
|
467
460
|
diff = self.get_diff(
|
468
461
|
desired_abstract_status_board_map,
|
469
462
|
current_abstract_status_board_map,
|
470
|
-
current_products,
|
471
463
|
)
|
472
464
|
|
473
465
|
self.apply_diff(dry_run, ocm_api, diff)
|
reconcile/utils/ocm/ocm.py
CHANGED
@@ -337,62 +337,6 @@ class OCM: # pylint: disable=too-many-public-methods
|
|
337
337
|
aws_infrastructure_access_role_grant_id = rg["id"]
|
338
338
|
self._delete(f"{api}/{aws_infrastructure_access_role_grant_id}")
|
339
339
|
|
340
|
-
def get_github_idp_teams(self, cluster):
|
341
|
-
"""Returns a list of details of GitHub IDP providers
|
342
|
-
|
343
|
-
:param cluster: cluster name
|
344
|
-
|
345
|
-
:type cluster: string
|
346
|
-
"""
|
347
|
-
result_idps = []
|
348
|
-
cluster_id = self.cluster_ids.get(cluster)
|
349
|
-
if not cluster_id:
|
350
|
-
return result_idps
|
351
|
-
api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/identity_providers"
|
352
|
-
idps = self._get_json(api).get("items")
|
353
|
-
if not idps:
|
354
|
-
return result_idps
|
355
|
-
|
356
|
-
for idp in idps:
|
357
|
-
if idp["type"] != "GithubIdentityProvider":
|
358
|
-
continue
|
359
|
-
idp_name = idp["name"]
|
360
|
-
idp_github = idp["github"]
|
361
|
-
|
362
|
-
item = {
|
363
|
-
"id": idp["id"],
|
364
|
-
"cluster": cluster,
|
365
|
-
"name": idp_name,
|
366
|
-
"client_id": idp_github["client_id"],
|
367
|
-
"teams": idp_github.get("teams"),
|
368
|
-
}
|
369
|
-
result_idps.append(item)
|
370
|
-
return result_idps
|
371
|
-
|
372
|
-
def create_github_idp_teams(self, spec):
|
373
|
-
"""Creates a new GitHub IDP
|
374
|
-
|
375
|
-
:param cluster: cluster name
|
376
|
-
:param spec: required information for idp creation
|
377
|
-
|
378
|
-
:type cluster: string
|
379
|
-
:type spec: dictionary
|
380
|
-
"""
|
381
|
-
cluster = spec["cluster"]
|
382
|
-
cluster_id = self.cluster_ids[cluster]
|
383
|
-
api = f"{CS_API_BASE}/v1/clusters/{cluster_id}/identity_providers"
|
384
|
-
payload = {
|
385
|
-
"type": "GithubIdentityProvider",
|
386
|
-
"mapping_method": "add",
|
387
|
-
"name": spec["name"],
|
388
|
-
"github": {
|
389
|
-
"client_id": spec["client_id"],
|
390
|
-
"client_secret": spec["client_secret"],
|
391
|
-
"teams": spec["teams"],
|
392
|
-
},
|
393
|
-
}
|
394
|
-
self._post(api, payload)
|
395
|
-
|
396
340
|
def get_kubeconfig(self, cluster: str) -> str | None:
|
397
341
|
"""Returns the cluster credentials (kubeconfig)
|
398
342
|
|
reconcile/ocm_github_idp.py
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
import sys
|
3
|
-
from collections.abc import Mapping
|
4
|
-
from typing import Any
|
5
|
-
|
6
|
-
from reconcile import queries
|
7
|
-
from reconcile.status import ExitCodes
|
8
|
-
from reconcile.utils.disabled_integrations import integration_is_enabled
|
9
|
-
from reconcile.utils.ocm import OCMMap
|
10
|
-
from reconcile.utils.secret_reader import SecretReader
|
11
|
-
|
12
|
-
QONTRACT_INTEGRATION = "ocm-github-idp"
|
13
|
-
|
14
|
-
|
15
|
-
def fetch_current_state(clusters, settings):
|
16
|
-
current_state = []
|
17
|
-
ocm_map = OCMMap(
|
18
|
-
clusters=clusters, integration=QONTRACT_INTEGRATION, settings=settings
|
19
|
-
)
|
20
|
-
|
21
|
-
for cluster_info in clusters:
|
22
|
-
cluster = cluster_info["name"]
|
23
|
-
ocm = ocm_map.get(cluster)
|
24
|
-
idps = ocm.get_github_idp_teams(cluster)
|
25
|
-
current_state.extend(idps)
|
26
|
-
|
27
|
-
return ocm_map, current_state
|
28
|
-
|
29
|
-
|
30
|
-
def fetch_desired_state(clusters, vault_input_path, settings):
|
31
|
-
desired_state = []
|
32
|
-
error = False
|
33
|
-
secret_reader = SecretReader(settings=settings)
|
34
|
-
for cluster_info in clusters:
|
35
|
-
cluster = cluster_info["name"]
|
36
|
-
for auth in cluster_info["auth"]:
|
37
|
-
if auth["service"] != "github-org-team":
|
38
|
-
continue
|
39
|
-
|
40
|
-
org = auth["org"]
|
41
|
-
team = auth["team"]
|
42
|
-
secret = {
|
43
|
-
"path": f"{vault_input_path}/{QONTRACT_INTEGRATION}/{auth['service']}/{org}/{team}"
|
44
|
-
}
|
45
|
-
try:
|
46
|
-
oauth_data = secret_reader.read_all(secret)
|
47
|
-
client_id = oauth_data["client-id"]
|
48
|
-
client_secret = oauth_data["client-secret"]
|
49
|
-
except Exception:
|
50
|
-
logging.error(f"unable to read secret in path {secret['path']}")
|
51
|
-
error = True
|
52
|
-
continue
|
53
|
-
item = {
|
54
|
-
"cluster": cluster,
|
55
|
-
"name": f"github-{org}",
|
56
|
-
"client_id": client_id,
|
57
|
-
"client_secret": client_secret,
|
58
|
-
"teams": [f"{org}/{team}"],
|
59
|
-
}
|
60
|
-
desired_state.append(item)
|
61
|
-
|
62
|
-
return desired_state, error
|
63
|
-
|
64
|
-
|
65
|
-
def sanitize(state):
|
66
|
-
return {k: v for k, v in state.items() if k not in {"client_secret", "id"}}
|
67
|
-
|
68
|
-
|
69
|
-
def act(dry_run, ocm_map, current_state, desired_state):
|
70
|
-
sanitized_current_state = [sanitize(d) for d in current_state]
|
71
|
-
sanitized_desired_state = [sanitize(d) for d in desired_state]
|
72
|
-
to_add = [d for d in desired_state if sanitize(d) not in sanitized_current_state]
|
73
|
-
for item in to_add:
|
74
|
-
cluster = item["cluster"]
|
75
|
-
idp_name = item["name"]
|
76
|
-
team = item["teams"][0]
|
77
|
-
logging.info(["create_github_idp", cluster, idp_name, team])
|
78
|
-
|
79
|
-
if not dry_run:
|
80
|
-
ocm = ocm_map.get(cluster)
|
81
|
-
ocm.create_github_idp_teams(item)
|
82
|
-
|
83
|
-
to_remove = [d for d in current_state if sanitize(d) not in sanitized_desired_state]
|
84
|
-
for item in to_remove:
|
85
|
-
cluster = item["cluster"]
|
86
|
-
idp_name = item["name"]
|
87
|
-
team = item["teams"][0]
|
88
|
-
logging.info(["remove_github_idp", cluster, idp_name, team])
|
89
|
-
|
90
|
-
if not dry_run:
|
91
|
-
ocm = ocm_map.get(cluster)
|
92
|
-
ocm.delete_idp(cluster, item["id"])
|
93
|
-
|
94
|
-
|
95
|
-
def _cluster_is_compatible(cluster: Mapping[str, Any]) -> bool:
|
96
|
-
return cluster.get("ocm") is not None and cluster.get("auth") is not None
|
97
|
-
|
98
|
-
|
99
|
-
def run(dry_run, vault_input_path=""):
|
100
|
-
if not vault_input_path:
|
101
|
-
logging.error("must supply vault input path")
|
102
|
-
sys.exit(1)
|
103
|
-
settings = queries.get_app_interface_settings()
|
104
|
-
clusters = [
|
105
|
-
c
|
106
|
-
for c in queries.get_clusters()
|
107
|
-
if integration_is_enabled(QONTRACT_INTEGRATION, c) and _cluster_is_compatible(c)
|
108
|
-
]
|
109
|
-
if not clusters:
|
110
|
-
logging.debug("No github-idp definitions found in app-interface")
|
111
|
-
sys.exit(ExitCodes.SUCCESS)
|
112
|
-
|
113
|
-
ocm_map, current_state = fetch_current_state(clusters, settings)
|
114
|
-
desired_state, error = fetch_desired_state(clusters, vault_input_path, settings)
|
115
|
-
if error:
|
116
|
-
sys.exit(1)
|
117
|
-
act(dry_run, ocm_map, current_state, desired_state)
|
{qontract_reconcile-0.10.2.dev247.dist-info → qontract_reconcile-0.10.2.dev249.dist-info}/WHEEL
RENAMED
File without changes
|
File without changes
|