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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qontract-reconcile
3
- Version: 0.10.2.dev247
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
@@ -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=mewdtUiv_j2OYNnjIMsc4BTbgDk6WTIotsyD-E4LwT4,112803
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=Hxx6sFFyPTNi6zY-qlAco9OqPvdx6Kbgce0DunDUsNQ,15838
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=qDD7x4uhnr7WJenc5mN9XSttu4NhI8FDEUIc33nWKpM,33211
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.dev247.dist-info/METADATA,sha256=cWYfGDu3xHx3tih9Mz3sdUUtbrXc1Qks-MmS9n0J7Ps,24049
802
- qontract_reconcile-0.10.2.dev247.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
803
- qontract_reconcile-0.10.2.dev247.dist-info/entry_points.txt,sha256=5i9l54La3vQrDLAdwDKQWC0iG4sV9RRfOb1BpvzOWLc,698
804
- qontract_reconcile-0.10.2.dev247.dist-info/RECORD,,
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 typing import (
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: Optional["Product"]
123
+ product: Product
126
124
  services: list["Service"] | None
127
125
 
128
126
  def create(self, ocm: OCMBaseClient) -> None:
129
- if self.product and self.product.id:
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 if self.product and self.product.id else ""
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
- # `application` here is used to create a flat map to easily compare state.
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 and self.application.id:
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 and self.application.id:
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) for a in get_product_applications(ocm_api, p.id)
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) for s in get_application_services(ocm_api, a.id)
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]], slodocs: list[SLODocumentV1]
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 product, apps in desired_product_apps.items():
308
- desired_abstract_status_board_map[product] = Product(
309
- name=product, fullname=product, applications=[], metadata={}
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"{product}/{a}"
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=desired_abstract_status_board_map[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 product in products:
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
- product not in desired_product_apps
334
- or app not in desired_product_apps.get(product, set())
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"{product}/{app}/{slo.name}"
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"{product}/{app}"
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)
@@ -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
 
@@ -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)