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.
- {qontract_reconcile-0.10.1rc427.dist-info → qontract_reconcile-0.10.1rc429.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc427.dist-info → qontract_reconcile-0.10.1rc429.dist-info}/RECORD +7 -7
- reconcile/database_access_manager.py +119 -99
- reconcile/test/test_database_access_manager.py +101 -41
- {qontract_reconcile-0.10.1rc427.dist-info → qontract_reconcile-0.10.1rc429.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc427.dist-info → qontract_reconcile-0.10.1rc429.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc427.dist-info → qontract_reconcile-0.10.1rc429.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc427.dist-info → qontract_reconcile-0.10.1rc429.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.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
|
{qontract_reconcile-0.10.1rc427.dist-info → qontract_reconcile-0.10.1rc429.dist-info}/RECORD
RENAMED
@@ -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=
|
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=
|
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.
|
641
|
-
qontract_reconcile-0.10.
|
642
|
-
qontract_reconcile-0.10.
|
643
|
-
qontract_reconcile-0.10.
|
644
|
-
qontract_reconcile-0.10.
|
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
|
-
|
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
|
-
|
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=
|
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,
|
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
|
-
) ->
|
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
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
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
|
-
|
512
|
-
|
513
|
-
|
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
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
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
|
-
|
560
|
-
|
566
|
+
resource=r.resource,
|
567
|
+
wait_for_namespace=False,
|
561
568
|
)
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
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
|
-
|
568
|
-
|
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
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
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
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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,
|
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=
|
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
|
-
|
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
|
-
|
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=
|
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=
|
374
|
+
oc_map=oc_map,
|
313
375
|
cluster="test-cluster",
|
314
|
-
namespace="test-
|
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
|
-
|
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
|
-
|
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
|
-
|
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=
|
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
|
-
|
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
|
-
|
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
|
-
|
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=
|
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=
|
440
|
+
oc_map=oc_map,
|
379
441
|
cluster="test-cluster",
|
380
|
-
namespace="test-
|
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
|
-
|
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),
|
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc427.dist-info → qontract_reconcile-0.10.1rc429.dist-info}/top_level.txt
RENAMED
File without changes
|