qontract-reconcile 0.10.1rc427__py3-none-any.whl → 0.10.1rc429__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.1rc427
3
+ Version: 0.10.1rc429
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
@@ -16,7 +16,7 @@ reconcile/dashdotdb_cso.py,sha256=FoXrWGpOwXG5jf0eklN84tjJVUAYzKat7rtq_28JMlQ,36
16
16
  reconcile/dashdotdb_dora.py,sha256=FINH-8dU3_r8EgUOMiF_fbxD9fKs6LFDxe6rufQ9XcM,17214
17
17
  reconcile/dashdotdb_dvo.py,sha256=YXqpI6fBQAql-ybGI0grj9gWMzmKiAvPE__pNju6obk,8996
18
18
  reconcile/dashdotdb_slo.py,sha256=bf1WSh5JP9obHVQsMy0OO71_VTYZgwAopElFZM6DmRo,6714
19
- reconcile/database_access_manager.py,sha256=ASeqZ4Img7X5OTVkekC6envsiJUQt7M7W5prZg-N7n8,20929
19
+ reconcile/database_access_manager.py,sha256=pbf3n-8f2sxitMbj9Y2g0G_U7yfHiJaNX4lverxPnX8,21758
20
20
  reconcile/dynatrace_token_provider.py,sha256=HWItJ_LavPcUJlpYz5fmfnfOpP2-0Qjkar0EAzBJ5Cw,16602
21
21
  reconcile/email_sender.py,sha256=-5L-Ag_jaEYSzYRoMr52KQBRXz1E8yx9GqLbg2X4XFU,3533
22
22
  reconcile/gabi_authorized_users.py,sha256=rCosZv8Iu9jhWG88YiwK-gftX475aJ1R-PYIJYp_svY,4342
@@ -368,7 +368,7 @@ reconcile/test/test_checkpoint.py,sha256=sbDtqTbfw5yMZ_mCltMXxkyyGueVLGUjTDtcWhP
368
368
  reconcile/test/test_cli.py,sha256=qx_iBwh4Z-YkK3sbjK1wEziPTgn060EN-baf9DNvR3k,1096
369
369
  reconcile/test/test_closedbox_endpoint_monitoring.py,sha256=isMHYwRWMFARU2nbJgbl69kD6H0eA86noCM4MPVI1fo,7151
370
370
  reconcile/test/test_dashdotdb_dora.py,sha256=XDMdnLDvup8sSqQEynxdPhXQZAafYbd2IUo9flSRJ8I,7917
371
- reconcile/test/test_database_access_manager.py,sha256=9P-IKPlqirpHu_vyRedZ69zR63AvJZdLDuM30qtg4F4,11384
371
+ reconcile/test/test_database_access_manager.py,sha256=gevaMDgOrpnrzYy7JrcJsYf1ZnyvBA2RB5G96JxJYn4,13278
372
372
  reconcile/test/test_gabi_authorized_users.py,sha256=6XnV5Q9inxP81ktGMVKyWucjBTUj8Imy2L0HG3YHyUE,2496
373
373
  reconcile/test/test_github_org.py,sha256=j3KeB4OnSln1gm2hidce49xdMru-j75NS3cM-AEgzZc,4511
374
374
  reconcile/test/test_github_repo_invites.py,sha256=QJ0VFk5B59rx4XtHoT6XOGWw9xRIZMen_cgtviN_Vi8,3419
@@ -637,8 +637,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=dmEcNwZltP1rd_4DbxIYakO
637
637
  tools/test/test_qontract_cli.py,sha256=awwTHEc2DWlykuqGIYM0WOBoSL0KRnOraCLk3C7izis,1401
638
638
  tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
639
639
  tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
640
- qontract_reconcile-0.10.1rc427.dist-info/METADATA,sha256=eXljszdUlU4LYiY6wkpsBcSsB6rxStjbhsWZ5h5hX10,2347
641
- qontract_reconcile-0.10.1rc427.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
642
- qontract_reconcile-0.10.1rc427.dist-info/entry_points.txt,sha256=rTjAv28I_CHLM8ID3OPqMI_suoQ9s7tFbim4aYjn9kk,376
643
- qontract_reconcile-0.10.1rc427.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
644
- qontract_reconcile-0.10.1rc427.dist-info/RECORD,,
640
+ qontract_reconcile-0.10.1rc429.dist-info/METADATA,sha256=IlUDMzAOQmNRBNLh7JrCttTiTIiQiuy-cCb8gLp4gNk,2347
641
+ qontract_reconcile-0.10.1rc429.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
642
+ qontract_reconcile-0.10.1rc429.dist-info/entry_points.txt,sha256=rTjAv28I_CHLM8ID3OPqMI_suoQ9s7tFbim4aYjn9kk,376
643
+ qontract_reconcile-0.10.1rc429.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
644
+ qontract_reconcile-0.10.1rc429.dist-info/RECORD,,
@@ -9,6 +9,7 @@ from typing import (
9
9
  Any,
10
10
  Callable,
11
11
  Optional,
12
+ TypedDict,
12
13
  )
13
14
 
14
15
  from pydantic import BaseModel
@@ -67,6 +68,7 @@ class DatabaseConnectionParameters(BaseModel):
67
68
  class PSQLScriptGenerator(BaseModel):
68
69
  db_access: DatabaseAccessV1
69
70
  connection_parameter: DatabaseConnectionParameters
71
+ admin_connection_parameter: DatabaseConnectionParameters
70
72
  engine: str
71
73
 
72
74
  def _get_db(self) -> str:
@@ -92,7 +94,7 @@ select 'CREATE ROLE "{self._get_user()}" WITH LOGIN PASSWORD ''{self.connection
92
94
  WHERE NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '{self._get_db()}');\\gexec
93
95
 
94
96
  -- rds specific, grant role to admin or create schema fails
95
- grant "{self._get_user()}" to postgres;
97
+ GRANT "{self._get_user()}" to "{self.admin_connection_parameter.user}";
96
98
  CREATE SCHEMA IF NOT EXISTS "{self._get_user()}" AUTHORIZATION "{self._get_user()}";"""
97
99
 
98
100
  def _generate_db_access(self) -> str:
@@ -357,7 +359,8 @@ def _populate_resources(
357
359
  admin_secret_name: str,
358
360
  resource_prefix: str,
359
361
  settings: dict[Any, Any],
360
- database_connection: DatabaseConnectionParameters,
362
+ user_connection: DatabaseConnectionParameters,
363
+ admin_connection: DatabaseConnectionParameters,
361
364
  ) -> list[DBAMResource]:
362
365
  managed_resources: list[DBAMResource] = []
363
366
  # create service account
@@ -371,7 +374,8 @@ def _populate_resources(
371
374
  # create script secret
372
375
  generator = PSQLScriptGenerator(
373
376
  db_access=db_access,
374
- connection_parameter=database_connection,
377
+ connection_parameter=user_connection,
378
+ admin_connection_parameter=admin_connection,
375
379
  engine=engine,
376
380
  )
377
381
  script_secret_name = f"{resource_prefix}-script"
@@ -387,7 +391,7 @@ def _populate_resources(
387
391
  # create user secret
388
392
  managed_resources.append(
389
393
  DBAMResource(
390
- resource=generate_user_secret_spec(resource_prefix, database_connection),
394
+ resource=generate_user_secret_spec(resource_prefix, user_connection),
391
395
  clean_up=False,
392
396
  )
393
397
  )
@@ -433,13 +437,18 @@ def _generate_password() -> str:
433
437
  return "".join(choices(ascii_letters + digits, k=32))
434
438
 
435
439
 
440
+ class _DBDonnections(TypedDict):
441
+ user: DatabaseConnectionParameters
442
+ admin: DatabaseConnectionParameters
443
+
444
+
436
445
  def _create_database_connection_parameter(
437
446
  db_access: DatabaseAccessV1,
438
447
  namespace_name: str,
439
448
  oc: OCClient,
440
449
  admin_secret_name: str,
441
450
  user_secret_name: str,
442
- ) -> DatabaseConnectionParameters:
451
+ ) -> _DBDonnections:
443
452
  def _decode_secret_value(value: str) -> str:
444
453
  return base64.b64decode(value).decode("utf-8")
445
454
 
@@ -449,6 +458,13 @@ def _create_database_connection_parameter(
449
458
  user_secret_name,
450
459
  allow_not_found=True,
451
460
  )
461
+ admin_secret = oc.get(
462
+ namespace_name,
463
+ "Secret",
464
+ admin_secret_name,
465
+ allow_not_found=False,
466
+ )
467
+
452
468
  if user_secret:
453
469
  password = _decode_secret_value(user_secret["data"]["db.password"])
454
470
  host = _decode_secret_value(user_secret["data"]["db.host"])
@@ -456,25 +472,27 @@ def _create_database_connection_parameter(
456
472
  port = _decode_secret_value(user_secret["data"]["db.port"])
457
473
  database = _decode_secret_value(user_secret["data"]["db.name"])
458
474
  else:
459
- admin_secret = oc.get(
460
- namespace_name,
461
- "Secret",
462
- admin_secret_name,
463
- allow_not_found=False,
464
- )
465
475
  host = _decode_secret_value(admin_secret["data"]["db.host"])
466
476
  port = _decode_secret_value(admin_secret["data"]["db.port"])
467
477
  user = db_access.username
468
478
  password = _generate_password()
469
479
  database = db_access.database
470
- database_connection = DatabaseConnectionParameters(
471
- host=host,
472
- port=port,
473
- user=user,
474
- password=password,
475
- database=database,
480
+ return _DBDonnections(
481
+ user=DatabaseConnectionParameters(
482
+ host=host,
483
+ port=port,
484
+ user=user,
485
+ password=password,
486
+ database=database,
487
+ ),
488
+ admin=DatabaseConnectionParameters(
489
+ host=_decode_secret_value(admin_secret["data"]["db.host"]),
490
+ port=_decode_secret_value(admin_secret["data"]["db.port"]),
491
+ user=_decode_secret_value(admin_secret["data"]["db.user"]),
492
+ password=_decode_secret_value(admin_secret["data"]["db.password"]),
493
+ database=_decode_secret_value(admin_secret["data"]["db.name"]),
494
+ ),
476
495
  )
477
- return database_connection
478
496
 
479
497
 
480
498
  class JobFailedError(Exception):
@@ -485,9 +503,7 @@ def _process_db_access(
485
503
  dry_run: bool,
486
504
  state: State,
487
505
  db_access: DatabaseAccessV1,
488
- oc_map: OC_Map,
489
- cluster_name: str,
490
- namespace_name: str,
506
+ namespace: NamespaceV1,
491
507
  admin_secret_name: str,
492
508
  engine: str,
493
509
  settings: dict[Any, Any],
@@ -497,75 +513,90 @@ def _process_db_access(
497
513
  if current_state == db_access.dict(by_alias=True):
498
514
  return
499
515
 
516
+ cluster_name = namespace.cluster.name
517
+ namespace_name = namespace.name
518
+
500
519
  resource_prefix = f"dbam-{db_access.name}"
501
- oc = oc_map.get_cluster(cluster_name, False)
520
+ with OC_Map(
521
+ clusters=[namespace.cluster.dict(by_alias=True)],
522
+ integration=QONTRACT_INTEGRATION,
523
+ settings=settings,
524
+ ) as oc_map:
525
+ oc = oc_map.get_cluster(cluster_name, False)
502
526
 
503
- database_connection = _create_database_connection_parameter(
504
- db_access,
505
- namespace_name,
506
- oc,
507
- admin_secret_name,
508
- resource_prefix,
509
- )
527
+ connections = _create_database_connection_parameter(
528
+ db_access,
529
+ namespace_name,
530
+ oc,
531
+ admin_secret_name,
532
+ resource_prefix,
533
+ )
510
534
 
511
- managed_resources = _populate_resources(
512
- db_access,
513
- engine,
514
- settings["imageRepository"],
515
- settings["pullSecret"],
516
- admin_secret_name,
517
- resource_prefix,
518
- settings,
519
- database_connection,
520
- )
535
+ sql_query_settings = settings.get("sqlQuery")
536
+ if not sql_query_settings:
537
+ raise KeyError("sqlQuery settings are required")
521
538
 
522
- # create job, delete old, failed job first
523
- job = oc.get(
524
- namespace_name,
525
- "Job",
526
- f"dbam-{db_access.name}",
527
- allow_not_found=True,
528
- )
529
- if not job:
530
- for r in managed_resources:
531
- openshift_base.apply(
532
- dry_run=dry_run,
533
- oc_map=oc_map,
534
- cluster=cluster_name,
535
- namespace=namespace_name,
536
- resource_type=r.resource.kind,
537
- resource=r.resource,
538
- wait_for_namespace=False,
539
- )
540
- return
541
- job_status = JobStatus(
542
- conditions=[
543
- JobStatusCondition(type=c["type"])
544
- for c in job["status"].get("conditions", [])
545
- ]
546
- )
547
- if job_status.is_complete():
548
- if job_status.has_errors():
549
- raise JobFailedError(f"Job dbam-{db_access.name} failed, please check logs")
550
- logging.debug("job completed, cleaning up")
551
- for r in managed_resources:
552
- if r.clean_up:
553
- openshift_base.delete(
539
+ managed_resources = _populate_resources(
540
+ db_access,
541
+ engine,
542
+ sql_query_settings["imageRepository"],
543
+ sql_query_settings["pullSecret"],
544
+ admin_secret_name,
545
+ resource_prefix,
546
+ settings,
547
+ connections["user"],
548
+ connections["admin"],
549
+ )
550
+
551
+ # create job, delete old, failed job first
552
+ job = oc.get(
553
+ namespace_name,
554
+ "Job",
555
+ f"dbam-{db_access.name}",
556
+ allow_not_found=True,
557
+ )
558
+ if not job:
559
+ for r in managed_resources:
560
+ openshift_base.apply(
554
561
  dry_run=dry_run,
555
562
  oc_map=oc_map,
556
563
  cluster=cluster_name,
557
564
  namespace=namespace_name,
558
565
  resource_type=r.resource.kind,
559
- name=r.resource.name,
560
- enable_deletion=True,
566
+ resource=r.resource,
567
+ wait_for_namespace=False,
561
568
  )
562
- state.add(
563
- db_access.name,
564
- value=db_access.dict(by_alias=True),
565
- force=True,
569
+ return
570
+ job_status = JobStatus(
571
+ conditions=[
572
+ JobStatusCondition(type=c["type"])
573
+ for c in job["status"].get("conditions", [])
574
+ ]
566
575
  )
567
- else:
568
- logging.info(f"Job dbam-{db_access.name} appears to be still running")
576
+ if job_status.is_complete():
577
+ if job_status.has_errors():
578
+ raise JobFailedError(
579
+ f"Job dbam-{db_access.name} failed, please check logs"
580
+ )
581
+ logging.debug("job completed, cleaning up")
582
+ for r in managed_resources:
583
+ if r.clean_up:
584
+ openshift_base.delete(
585
+ dry_run=dry_run,
586
+ oc_map=oc_map,
587
+ cluster=cluster_name,
588
+ namespace=namespace_name,
589
+ resource_type=r.resource.kind,
590
+ name=r.resource.name,
591
+ enable_deletion=True,
592
+ )
593
+ state.add(
594
+ db_access.name,
595
+ value=db_access.dict(by_alias=True),
596
+ force=True,
597
+ )
598
+ else:
599
+ logging.info(f"Job dbam-{db_access.name} appears to be still running")
569
600
 
570
601
 
571
602
  class DatabaseAccessManagerIntegration(QontractReconcileIntegration):
@@ -576,10 +607,6 @@ class DatabaseAccessManagerIntegration(QontractReconcileIntegration):
576
607
  def run(self, dry_run: bool) -> None:
577
608
  settings = queries.get_app_interface_settings()
578
609
 
579
- sql_query_settings = settings.get("sqlQuery")
580
- if not sql_query_settings:
581
- raise KeyError("sqlQuery settings are required")
582
-
583
610
  state = init_state(
584
611
  integration=QONTRACT_INTEGRATION, secret_reader=self.secret_reader
585
612
  )
@@ -606,22 +633,15 @@ class DatabaseAccessManagerIntegration(QontractReconcileIntegration):
606
633
 
607
634
  for db_access in resource.database_access or []:
608
635
  try:
609
- with OC_Map(
610
- clusters=namespace.cluster.dict(by_alias=True),
611
- integration=QONTRACT_INTEGRATION,
612
- settings=settings,
613
- ) as oc_map:
614
- _process_db_access(
615
- dry_run,
616
- state,
617
- db_access,
618
- oc_map,
619
- namespace.cluster.name,
620
- namespace.name,
621
- admin_secret_name,
622
- get_db_engine(resource),
623
- sql_query_settings,
624
- )
636
+ _process_db_access(
637
+ dry_run,
638
+ state,
639
+ db_access,
640
+ namespace,
641
+ admin_secret_name,
642
+ get_db_engine(resource),
643
+ settings,
644
+ )
625
645
  except JobFailedError:
626
646
  encounteredErrors = True
627
647
 
@@ -1,5 +1,8 @@
1
1
  from collections import defaultdict
2
- from typing import Callable
2
+ from typing import (
3
+ Any,
4
+ Callable,
5
+ )
3
6
  from unittest.mock import MagicMock
4
7
 
5
8
  import pytest
@@ -13,6 +16,7 @@ from reconcile.database_access_manager import (
13
16
  JobStatusCondition,
14
17
  PSQLScriptGenerator,
15
18
  _create_database_connection_parameter,
19
+ _DBDonnections,
16
20
  _generate_password,
17
21
  _populate_resources,
18
22
  _process_db_access,
@@ -20,8 +24,8 @@ from reconcile.database_access_manager import (
20
24
  from reconcile.gql_definitions.terraform_resources.database_access_manager import (
21
25
  DatabaseAccessAccessV1,
22
26
  DatabaseAccessV1,
27
+ NamespaceV1,
23
28
  )
24
- from reconcile.utils.oc import OC_Map
25
29
  from reconcile.utils.openshift_resource import OpenshiftResource
26
30
 
27
31
 
@@ -52,6 +56,19 @@ def db_access_access(
52
56
  )
53
57
 
54
58
 
59
+ @pytest.fixture
60
+ def db_access_namespace(gql_class_factory: Callable[..., NamespaceV1]) -> NamespaceV1:
61
+ return gql_class_factory(
62
+ NamespaceV1,
63
+ {
64
+ "name": "test-namespace",
65
+ "cluster": {
66
+ "name": "test-cluster",
67
+ },
68
+ },
69
+ )
70
+
71
+
55
72
  @pytest.fixture
56
73
  def db_access_complete(
57
74
  db_access: DatabaseAccessV1, db_access_access: DatabaseAccessAccessV1
@@ -71,6 +88,17 @@ def db_connection_parameter():
71
88
  )
72
89
 
73
90
 
91
+ @pytest.fixture
92
+ def db_admin_connection_parameter():
93
+ return DatabaseConnectionParameters(
94
+ host="localhost",
95
+ port="5432",
96
+ user="admin",
97
+ password="adminpw", # notsecret
98
+ database="test",
99
+ )
100
+
101
+
74
102
  @pytest.fixture
75
103
  def db_secret_dict() -> dict[str, dict[str, str]]:
76
104
  return {
@@ -102,6 +130,7 @@ def _assert_create_script(script: str) -> None:
102
130
  assert "REVOKE ALL ON DATABASE" in script
103
131
  assert 'CREATE ROLE "test" WITH LOGIN PASSWORD' in script
104
132
  assert "CREATE SCHEMA IF NOT EXISTS" in script
133
+ assert 'GRANT "test" to "admin";' in script
105
134
 
106
135
 
107
136
  def _assert_grant_access(script: str) -> None:
@@ -109,11 +138,14 @@ def _assert_grant_access(script: str) -> None:
109
138
 
110
139
 
111
140
  def test_generate_create_user(
112
- db_access: DatabaseAccessV1, db_connection_parameter: DatabaseConnectionParameters
141
+ db_access: DatabaseAccessV1,
142
+ db_connection_parameter: DatabaseConnectionParameters,
143
+ db_admin_connection_parameter: DatabaseConnectionParameters,
113
144
  ) -> None:
114
145
  s = PSQLScriptGenerator(
115
146
  db_access=db_access,
116
147
  connection_parameter=db_connection_parameter,
148
+ admin_connection_parameter=db_admin_connection_parameter,
117
149
  engine="postgres",
118
150
  )
119
151
  script = s._generate_create_user()
@@ -124,12 +156,14 @@ def test_generate_access(
124
156
  db_access: DatabaseAccessV1,
125
157
  db_access_access: DatabaseAccessAccessV1,
126
158
  db_connection_parameter: DatabaseConnectionParameters,
159
+ db_admin_connection_parameter: DatabaseConnectionParameters,
127
160
  ):
128
161
  db_access.access = [db_access_access]
129
162
 
130
163
  s = PSQLScriptGenerator(
131
164
  db_access=db_access,
132
165
  connection_parameter=db_connection_parameter,
166
+ admin_connection_parameter=db_connection_parameter,
133
167
  engine="postgres",
134
168
  )
135
169
  script = s._generate_db_access()
@@ -139,10 +173,12 @@ def test_generate_access(
139
173
  def test_generate_complete(
140
174
  db_access_complete: DatabaseAccessV1,
141
175
  db_connection_parameter: DatabaseConnectionParameters,
176
+ db_admin_connection_parameter: DatabaseConnectionParameters,
142
177
  ):
143
178
  s = PSQLScriptGenerator(
144
179
  db_access=db_access_complete,
145
180
  connection_parameter=db_connection_parameter,
181
+ admin_connection_parameter=db_admin_connection_parameter,
146
182
  engine="postgres",
147
183
  )
148
184
  script = s.generate_script()
@@ -169,6 +205,7 @@ def test_populate_resources(
169
205
  mocker: MockerFixture,
170
206
  db_access: DatabaseAccessV1,
171
207
  db_connection_parameter: DatabaseConnectionParameters,
208
+ db_admin_connection_parameter: DatabaseConnectionParameters,
172
209
  openshift_resource_secet: OpenshiftResource,
173
210
  ):
174
211
  mocker.patch(
@@ -189,7 +226,8 @@ def test_populate_resources(
189
226
  admin_secret_name="db-secret",
190
227
  resource_prefix="dbam-foo",
191
228
  settings={"foo": "bar"},
192
- database_connection=db_connection_parameter,
229
+ user_connection=db_connection_parameter,
230
+ admin_connection=db_admin_connection_parameter,
193
231
  )
194
232
 
195
233
  r_kinds = [r.resource.kind for r in reources]
@@ -210,7 +248,7 @@ def test__create_database_connection_parameter_user_exists(
210
248
  admin_secret_name="db-secret",
211
249
  user_secret_name="db-user-secret",
212
250
  )
213
- assert p == DatabaseConnectionParameters(
251
+ conn = DatabaseConnectionParameters(
214
252
  host="localhost",
215
253
  port="5432",
216
254
  user="test",
@@ -218,6 +256,10 @@ def test__create_database_connection_parameter_user_exists(
218
256
  database="test",
219
257
  )
220
258
 
259
+ assert p["user"] == conn
260
+ assert p["admin"] == conn
261
+ assert oc.get.call_count == 2
262
+
221
263
 
222
264
  def test__create_database_connection_parameter_user_missing(
223
265
  db_access: DatabaseAccessV1,
@@ -238,7 +280,7 @@ def test__create_database_connection_parameter_user_missing(
238
280
  admin_secret_name="db-secret",
239
281
  user_secret_name="db-user-secret",
240
282
  )
241
- assert p == DatabaseConnectionParameters(
283
+ conn = DatabaseConnectionParameters(
242
284
  host="localhost",
243
285
  port="5432",
244
286
  user="test",
@@ -246,6 +288,13 @@ def test__create_database_connection_parameter_user_missing(
246
288
  database="test",
247
289
  )
248
290
 
291
+ admin_conn = conn.copy()
292
+ admin_conn.password = "hduhsdfuhsdf"
293
+
294
+ assert p["user"] == conn
295
+ assert p["admin"] == admin_conn
296
+ assert oc.get.call_count == 2
297
+
249
298
 
250
299
  def test_generate_password():
251
300
  assert len(_generate_password()) == 32
@@ -257,19 +306,20 @@ def dbam_state(mocker: MockerFixture) -> MockerFixture:
257
306
  return mocker.patch("reconcile.database_access_manager.State", autospec=True)
258
307
 
259
308
 
260
- @pytest.fixture
261
- def dbam_oc_map(mocker: MockerFixture) -> MockerFixture:
262
- return mocker.patch("reconcile.database_access_manager.OC_Map", autospec=True)
263
-
264
-
265
309
  @pytest.fixture
266
310
  def dbam_process_mocks(
267
- openshift_resource_secet: OpenshiftResource, mocker: MockerFixture
311
+ openshift_resource_secet: OpenshiftResource,
312
+ mocker: MockerFixture,
313
+ db_connection_parameter: DatabaseConnectionParameters,
314
+ db_admin_connection_parameter: DatabaseConnectionParameters,
268
315
  ) -> DBAMResource:
269
316
  expected_resource = DBAMResource(resource=openshift_resource_secet, clean_up=True)
270
317
  mocker.patch(
271
318
  "reconcile.database_access_manager._create_database_connection_parameter",
272
- return_value=db_connection_parameter,
319
+ return_value=_DBDonnections(
320
+ user=db_connection_parameter,
321
+ admin=db_admin_connection_parameter,
322
+ ),
273
323
  )
274
324
  mocker.patch(
275
325
  "reconcile.database_access_manager._populate_resources",
@@ -278,17 +328,31 @@ def dbam_process_mocks(
278
328
  return expected_resource
279
329
 
280
330
 
331
+ @pytest.fixture
332
+ def ai_settings() -> dict[str, Any]:
333
+ d: dict[str, Any] = defaultdict(str)
334
+ d["sqlQuery"] = {
335
+ "imageRepository": {"foo": "bar"},
336
+ "pullSecret": {"foo": "bar"},
337
+ }
338
+ return d
339
+
340
+
281
341
  def test__process_db_access_job_pass(
282
342
  db_access: DatabaseAccessV1,
343
+ db_access_namespace: NamespaceV1,
283
344
  dbam_state: MagicMock,
284
- dbam_oc_map: MagicMock,
285
345
  dbam_process_mocks: DBAMResource,
286
346
  mocker: MockerFixture,
347
+ ai_settings: dict[str, Any],
287
348
  ):
288
349
  dbam_state.exists.return_value = False
289
350
  oc = mocker.patch("reconcile.utils.oc.OCNative", autospec=True)
290
351
  oc.get.return_value = {"status": {"conditions": [{"type": "Complete"}]}}
291
- dbam_oc_map.get_cluster.return_value = oc
352
+
353
+ oc_map = mocker.patch("reconcile.database_access_manager.OC_Map", autospec=True)
354
+ oc_map.return_value.__enter__.return_value = oc_map
355
+ oc_map.get_cluster.return_value = oc
292
356
 
293
357
  ob_delete = mocker.patch(
294
358
  "reconcile.database_access_manager.openshift_base.delete", autospec=True
@@ -298,20 +362,18 @@ def test__process_db_access_job_pass(
298
362
  False,
299
363
  dbam_state,
300
364
  db_access,
301
- dbam_oc_map,
302
- "test-cluster",
303
- namespace_name="test-namepsace",
365
+ namespace=db_access_namespace,
304
366
  admin_secret_name="db-secret",
305
367
  engine="postgres",
306
- settings=defaultdict(str),
368
+ settings=ai_settings,
307
369
  )
308
370
 
309
371
  assert ob_delete.call_count == 1
310
372
  ob_delete.assert_called_once_with(
311
373
  dry_run=False,
312
- oc_map=dbam_oc_map,
374
+ oc_map=oc_map,
313
375
  cluster="test-cluster",
314
- namespace="test-namepsace",
376
+ namespace="test-namespace",
315
377
  resource_type="secret",
316
378
  name=dbam_process_mocks.resource.name,
317
379
  enable_deletion=True,
@@ -321,41 +383,43 @@ def test__process_db_access_job_pass(
321
383
  def test__process_db_access_job_error(
322
384
  db_access: DatabaseAccessV1,
323
385
  dbam_state: MagicMock,
324
- dbam_oc_map: MagicMock,
386
+ db_access_namespace: NamespaceV1,
325
387
  dbam_process_mocks: DBAMResource,
326
388
  mocker: MockerFixture,
389
+ ai_settings: dict[str, Any],
327
390
  ):
328
- dbam_state.exists.return_value = False
329
391
  oc = mocker.patch("reconcile.utils.oc.OCNative", autospec=True)
330
392
  oc.get.return_value = {"status": {"conditions": [{"type": "Failed"}]}}
331
- dbam_oc_map.get_cluster.return_value = oc
393
+ oc_map = mocker.patch("reconcile.database_access_manager.OC_Map", autospec=True)
394
+ oc_map.return_value.__enter__.return_value = oc_map
395
+ oc_map.get_cluster.return_value = oc
332
396
 
333
397
  with pytest.raises(JobFailedError):
334
398
  _process_db_access(
335
399
  False,
336
400
  dbam_state,
337
401
  db_access,
338
- dbam_oc_map,
339
- "test-cluster",
340
- namespace_name="test-namepsace",
402
+ namespace=db_access_namespace,
341
403
  admin_secret_name="db-secret",
342
404
  engine="postgres",
343
- settings=defaultdict(str),
405
+ settings=ai_settings,
344
406
  )
345
407
 
346
408
 
347
409
  def test__process_db_access_state_diff(
348
410
  db_access: DatabaseAccessV1,
349
411
  dbam_state: MagicMock,
350
- dbam_oc_map: MagicMock,
412
+ db_access_namespace: NamespaceV1,
351
413
  dbam_process_mocks: DBAMResource,
352
414
  mocker: MockerFixture,
415
+ ai_settings: dict[str, Any],
353
416
  ):
354
- dbam_state.exists.return_value = True
355
417
  dbam_state.get.return_value = {}
356
418
  oc = mocker.patch("reconcile.utils.oc.OCNative", autospec=True)
357
419
  oc.get.return_value = False
358
- dbam_oc_map.get_cluster.return_value = oc
420
+ oc_map = mocker.patch("reconcile.database_access_manager.OC_Map", autospec=True)
421
+ oc_map.return_value.__enter__.return_value = oc_map
422
+ oc_map.get_cluster.return_value = oc
359
423
 
360
424
  ob_apply = mocker.patch(
361
425
  "reconcile.database_access_manager.openshift_base.apply", autospec=True
@@ -364,20 +428,18 @@ def test__process_db_access_state_diff(
364
428
  False,
365
429
  dbam_state,
366
430
  db_access,
367
- dbam_oc_map,
368
- "test-cluster",
369
- namespace_name="test-namepsace",
431
+ namespace=db_access_namespace,
370
432
  admin_secret_name="db-secret",
371
433
  engine="postgres",
372
- settings=defaultdict(str),
434
+ settings=ai_settings,
373
435
  )
374
436
 
375
437
  assert ob_apply.call_count == 1
376
438
  ob_apply.assert_called_once_with(
377
439
  dry_run=False,
378
- oc_map=dbam_oc_map,
440
+ oc_map=oc_map,
379
441
  cluster="test-cluster",
380
- namespace="test-namepsace",
442
+ namespace="test-namespace",
381
443
  resource_type="secret",
382
444
  resource=dbam_process_mocks.resource,
383
445
  wait_for_namespace=False,
@@ -386,8 +448,8 @@ def test__process_db_access_state_diff(
386
448
 
387
449
  def test__process_db_access_state_exists_matched(
388
450
  db_access: DatabaseAccessV1,
451
+ db_access_namespace: NamespaceV1,
389
452
  dbam_state: MagicMock,
390
- dbam_oc_map: OC_Map,
391
453
  ):
392
454
  dbam_state.exists.return_value = True
393
455
  dbam_state.get.return_value = db_access.dict(by_alias=True)
@@ -396,9 +458,7 @@ def test__process_db_access_state_exists_matched(
396
458
  False,
397
459
  dbam_state,
398
460
  db_access,
399
- dbam_oc_map,
400
- "test-cluster",
401
- namespace_name="test-namepsace",
461
+ namespace=db_access_namespace,
402
462
  admin_secret_name="db-secret",
403
463
  engine="postgres",
404
464
  settings=defaultdict(str),