qontract-reconcile 0.10.1rc772__py3-none-any.whl → 0.10.1rc773__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.1rc772.dist-info → qontract_reconcile-0.10.1rc773.dist-info}/METADATA +1 -1
- {qontract_reconcile-0.10.1rc772.dist-info → qontract_reconcile-0.10.1rc773.dist-info}/RECORD +9 -9
- reconcile/slack_usergroups.py +39 -49
- reconcile/test/test_slack_usergroups.py +66 -55
- reconcile/utils/metrics.py +6 -0
- reconcile/utils/slack_api.py +27 -0
- {qontract_reconcile-0.10.1rc772.dist-info → qontract_reconcile-0.10.1rc773.dist-info}/WHEEL +0 -0
- {qontract_reconcile-0.10.1rc772.dist-info → qontract_reconcile-0.10.1rc773.dist-info}/entry_points.txt +0 -0
- {qontract_reconcile-0.10.1rc772.dist-info → qontract_reconcile-0.10.1rc773.dist-info}/top_level.txt +0 -0
{qontract_reconcile-0.10.1rc772.dist-info → qontract_reconcile-0.10.1rc773.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.1rc773
|
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.1rc772.dist-info → qontract_reconcile-0.10.1rc773.dist-info}/RECORD
RENAMED
@@ -104,7 +104,7 @@ reconcile/sendgrid_teammates.py,sha256=oO8QbLb4s1o8A6CGiCagN9CmS05BSS_WLztuY0Ym9
|
|
104
104
|
reconcile/service_dependencies.py,sha256=PMKP9vc6oL-78rzyF_RE8DzLSQMSqN8vCqt9sWpBLAM,4470
|
105
105
|
reconcile/signalfx_endpoint_monitoring.py,sha256=D1m8iq0EAKie0OD59FOcVCtpWWZ7xlo6lwBS9urwMIk,2894
|
106
106
|
reconcile/slack_base.py,sha256=K3fSYx46G1djoPb07_C9j6ChhMCt5LgV5l6v2TFkNZk,3479
|
107
|
-
reconcile/slack_usergroups.py,sha256=
|
107
|
+
reconcile/slack_usergroups.py,sha256=6G-KjcqacqqhJDsl-KMC-t5M9oexUpSSUc1yGyt2zvY,27120
|
108
108
|
reconcile/sql_query.py,sha256=FAQI9EIHsokZBbGwvGU4vnjg1fHemxpYQE20UtCB1qo,25941
|
109
109
|
reconcile/status.py,sha256=cY4IJFXemhxptRJqR4qaaOWqei9e4jgLXuVSGajMsjg,544
|
110
110
|
reconcile/status_board.py,sha256=nA74_133jukxVShjPKJpkXOA3vggDTTEhYTegoXbN1M,8632
|
@@ -514,7 +514,7 @@ reconcile/test/test_saasherder.py,sha256=1_GyiXxxNqKSKE7PrtFJL7tUFg77d1oQPZzNBZW
|
|
514
514
|
reconcile/test/test_saasherder_allowed_secret_paths.py,sha256=5NHQwNJO66at6HiyMZ5sVRTQDwxdvlOQo0KmkBWCw5Q,4853
|
515
515
|
reconcile/test/test_secret_reader.py,sha256=kz7nzcPjvA08cytnvcA_PMA98AEyqJWsESkYeRn5xCk,4994
|
516
516
|
reconcile/test/test_slack_base.py,sha256=gpbWOLNxMMX6fyAbs1JakhLTnwfedb3f7WpUae4tQZE,5060
|
517
|
-
reconcile/test/test_slack_usergroups.py,sha256=
|
517
|
+
reconcile/test/test_slack_usergroups.py,sha256=wmS7xgl4U1jx4gu8qIDlljkhZxb_y8F6tR4UteyrlZE,24899
|
518
518
|
reconcile/test/test_sql_query.py,sha256=rC-lf1_isT9i2ZIV9W0hkUkLi2oBIjZMRMhk-6mV-34,11029
|
519
519
|
reconcile/test/test_status_board.py,sha256=go3YSWo03OLIdK95SuiDJa1Nqk-eN_9QtS7dfmu9__8,7875
|
520
520
|
reconcile/test/test_terraform_aws_route53.py,sha256=xHggb8K1P76OyCfFcogbkmyKle-NlUylcbDnuv3IqvY,771
|
@@ -632,7 +632,7 @@ reconcile/utils/keycloak.py,sha256=UqOsAcHKmmIunroWB5YzC1fUZ3S3aq6L7trn6vLRmXY,3
|
|
632
632
|
reconcile/utils/ldap_client.py,sha256=ho4veSrHqQWs0YhLFyKeD-duCwY8Nc5gUIA5qLENuMY,2502
|
633
633
|
reconcile/utils/lean_terraform_client.py,sha256=zReyNPJbr2uOdrdh8Qfe-OZQBoRwxb5Za_ddeoUCYVk,4064
|
634
634
|
reconcile/utils/make.py,sha256=QaEwucrzbl8-VHS66Wfdjfo0ubmAcvt_hZGpiGsKU50,231
|
635
|
-
reconcile/utils/metrics.py,sha256=
|
635
|
+
reconcile/utils/metrics.py,sha256=ot4dBO-KLZRowvNozm7jG0RWjcVsH1SL-lQ0jJgBBZM,18645
|
636
636
|
reconcile/utils/models.py,sha256=It_Q1WNIvw_EDCsiSWzIgpSPr_X9jMgbJI-DR3N23xY,4677
|
637
637
|
reconcile/utils/oauth2_backend_application_session.py,sha256=6W16sMpnWEPFDUX7qi5Cui2yOnmLfpgUxWtB3Ii35D0,4177
|
638
638
|
reconcile/utils/oc.py,sha256=ILAlP-AZMtWeyAepLoMnYbDJfyyMs-Z0fOEo9JXQfkE,65490
|
@@ -657,7 +657,7 @@ reconcile/utils/ruamel.py,sha256=FzL4_L0FnMOUZmgThrZSMJs5MTdXwiy-E9MZWfk8bh8,397
|
|
657
657
|
reconcile/utils/secret_reader.py,sha256=2DeYAAQFjUULEKlLw3UDAUoND6gbqvCh9uKPtlc-0us,10403
|
658
658
|
reconcile/utils/semver_helper.py,sha256=-WfPOMSA2v1h7hT3PwVf-Htg7wOsoKlQC1JdmDX2Ars,1268
|
659
659
|
reconcile/utils/sharding.py,sha256=gkYf0lD3IUKQPEmdRJZ70mdDT1c9qWjbdP7evRsUis4,839
|
660
|
-
reconcile/utils/slack_api.py,sha256=
|
660
|
+
reconcile/utils/slack_api.py,sha256=2t9jeCS7V3sHSMk-ByRcjmh-2uVvGELCfJqm1nu_hKI,17395
|
661
661
|
reconcile/utils/smtp_client.py,sha256=gJNbBQJpAt5PX4t_TaeNHsXM8vt50bFgndml6yK2b5o,2800
|
662
662
|
reconcile/utils/sqs_gateway.py,sha256=gFl9DM4DmGnptuxTOe4lS3YTyE80eSAvK42ljS8h4dA,2287
|
663
663
|
reconcile/utils/state.py,sha256=FK8NLT1xyumuXpYRm0Nk6pWpOE_U6-NovGn6zKCw8vw,16298
|
@@ -785,8 +785,8 @@ tools/test/test_app_interface_metrics_exporter.py,sha256=SX7qL3D1SIRKFo95FoQztvf
|
|
785
785
|
tools/test/test_qontract_cli.py,sha256=w2l4BHB09k1d-BGJ1jBUNCqDv7zkqYrMHojQXg-21kQ,4155
|
786
786
|
tools/test/test_sd_app_sre_alert_report.py,sha256=v363r9zM7__0kR5K6mvJoGFcM9BvE33fWAayrqkpojA,2116
|
787
787
|
tools/test/test_sre_checkpoints.py,sha256=SKqPPTl9ua0RFdSSofnoQX-JZE6dFLO3LRhfQzqtfh8,2607
|
788
|
-
qontract_reconcile-0.10.
|
789
|
-
qontract_reconcile-0.10.
|
790
|
-
qontract_reconcile-0.10.
|
791
|
-
qontract_reconcile-0.10.
|
792
|
-
qontract_reconcile-0.10.
|
788
|
+
qontract_reconcile-0.10.1rc773.dist-info/METADATA,sha256=BTq0sMtbXDJnJ9rUZhlAz0JpFDJzcRvLfNx2a3jCmFU,2382
|
789
|
+
qontract_reconcile-0.10.1rc773.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
790
|
+
qontract_reconcile-0.10.1rc773.dist-info/entry_points.txt,sha256=rIxI5zWtHNlfpDeq1a7pZXAPoqf7HG32KMTN3MeWK_8,429
|
791
|
+
qontract_reconcile-0.10.1rc773.dist-info/top_level.txt,sha256=l5ISPoXzt0SdR4jVdkfa7RPSKNc8zAHYWAnR-Dw8Ey8,24
|
792
|
+
qontract_reconcile-0.10.1rc773.dist-info/RECORD,,
|
reconcile/slack_usergroups.py
CHANGED
@@ -110,8 +110,9 @@ class State(BaseModel):
|
|
110
110
|
usergroup: str = ""
|
111
111
|
description: str = ""
|
112
112
|
users: set[SlackObject] = set()
|
113
|
+
user_names: set[str] = set()
|
113
114
|
channels: set[SlackObject] = set()
|
114
|
-
|
115
|
+
channel_names: set[str] = set()
|
115
116
|
|
116
117
|
def __bool__(self) -> bool:
|
117
118
|
return self.workspace != "" # noqa: PLC1901
|
@@ -392,7 +393,6 @@ def include_user_to_cluster_usergroup(
|
|
392
393
|
|
393
394
|
|
394
395
|
def get_desired_state(
|
395
|
-
slack_map: SlackMap,
|
396
396
|
pagerduty_map: PagerDutyMap,
|
397
397
|
permissions: Iterable[PermissionSlackUsergroupV1],
|
398
398
|
users: Iterable[User],
|
@@ -418,9 +418,6 @@ def get_desired_state(
|
|
418
418
|
not in managed usergroups {p.workspace.managed_usergroups}"
|
419
419
|
)
|
420
420
|
|
421
|
-
slack = slack_map[p.workspace.name].slack
|
422
|
-
ugid = slack.get_usergroup_id(usergroup)
|
423
|
-
|
424
421
|
all_user_names = [get_slack_username(u) for r in p.roles or [] for u in r.users]
|
425
422
|
slack_usernames_pagerduty = get_usernames_from_pagerduty(
|
426
423
|
pagerduties=p.pagerduty or [],
|
@@ -442,27 +439,16 @@ def get_desired_state(
|
|
442
439
|
)
|
443
440
|
all_user_names.extend(slack_usernames_schedule)
|
444
441
|
|
445
|
-
user_names =
|
446
|
-
slack_users = {
|
447
|
-
SlackObject(pk=pk, name=name)
|
448
|
-
for pk, name in slack.get_users_by_names(sorted(user_names)).items()
|
449
|
-
}
|
450
|
-
slack_channels = {
|
451
|
-
SlackObject(pk=pk, name=name)
|
452
|
-
for pk, name in slack.get_channels_by_names(
|
453
|
-
sorted(p.channels or [])
|
454
|
-
).items()
|
455
|
-
}
|
442
|
+
user_names = set(all_user_names)
|
456
443
|
|
457
444
|
try:
|
458
|
-
desired_state[p.workspace.name][usergroup].
|
445
|
+
desired_state[p.workspace.name][usergroup].user_names.update(user_names)
|
459
446
|
except KeyError:
|
460
447
|
desired_state.setdefault(p.workspace.name, {})[usergroup] = State(
|
461
448
|
workspace=p.workspace.name,
|
462
449
|
usergroup=usergroup,
|
463
|
-
|
464
|
-
|
465
|
-
channels=slack_channels,
|
450
|
+
user_names=user_names,
|
451
|
+
channel_names=sorted(p.channels or []),
|
466
452
|
description=p.description,
|
467
453
|
)
|
468
454
|
return desired_state
|
@@ -492,7 +478,7 @@ def get_desired_state_cluster_usergroups(
|
|
492
478
|
for u in openshift_users_desired_state
|
493
479
|
if u["cluster"] == cluster.name
|
494
480
|
]
|
495
|
-
cluster_usernames =
|
481
|
+
cluster_usernames = set({
|
496
482
|
get_slack_username(u)
|
497
483
|
for u in users
|
498
484
|
if include_user_to_cluster_usergroup(u, cluster, desired_cluster_users)
|
@@ -509,29 +495,16 @@ def get_desired_state_cluster_usergroups(
|
|
509
495
|
if desired_workspace_name and desired_workspace_name != workspace:
|
510
496
|
continue
|
511
497
|
|
512
|
-
ugid = spec.slack.get_usergroup_id(cluster_user_group)
|
513
|
-
slack_users = {
|
514
|
-
SlackObject(pk=pk, name=name)
|
515
|
-
for pk, name in spec.slack.get_users_by_names(
|
516
|
-
sorted(cluster_usernames)
|
517
|
-
).items()
|
518
|
-
}
|
519
|
-
slack_channels = {
|
520
|
-
SlackObject(pk=pk, name=name)
|
521
|
-
for pk, name in spec.slack.get_channels_by_names([
|
522
|
-
spec.slack.channel
|
523
|
-
]).items()
|
524
|
-
}
|
525
|
-
|
526
498
|
try:
|
527
|
-
desired_state[workspace][cluster_user_group].
|
499
|
+
desired_state[workspace][cluster_user_group].user_names.update(
|
500
|
+
cluster_usernames
|
501
|
+
)
|
528
502
|
except KeyError:
|
529
503
|
desired_state.setdefault(workspace, {})[cluster_user_group] = State(
|
530
504
|
workspace=workspace,
|
531
505
|
usergroup=cluster_user_group,
|
532
|
-
|
533
|
-
|
534
|
-
channels=slack_channels,
|
506
|
+
user_names=cluster_usernames,
|
507
|
+
channel_names=set([spec.slack.channel]),
|
535
508
|
description=f"Users with access to the {cluster.name} cluster",
|
536
509
|
)
|
537
510
|
return desired_state
|
@@ -558,8 +531,7 @@ def _create_usergroups(
|
|
558
531
|
])
|
559
532
|
if not dry_run:
|
560
533
|
try:
|
561
|
-
|
562
|
-
desired_ug_state.usergroup_id = usergroup_id
|
534
|
+
slack_client.create_usergroup(desired_ug_state.usergroup)
|
563
535
|
except SlackApiError as error:
|
564
536
|
logging.error(error)
|
565
537
|
error_occurred = True
|
@@ -597,13 +569,14 @@ def _update_usergroup_users_from_state(
|
|
597
569
|
|
598
570
|
if not dry_run:
|
599
571
|
try:
|
600
|
-
|
572
|
+
ugid = slack_client.get_usergroup_id(desired_ug_state.usergroup)
|
573
|
+
if not ugid:
|
601
574
|
logging.info(
|
602
575
|
f"Usergroup {desired_ug_state.usergroup} does not exist yet. Skipping for now."
|
603
576
|
)
|
604
577
|
return
|
605
578
|
slack_client.update_usergroup_users(
|
606
|
-
id=
|
579
|
+
id=ugid,
|
607
580
|
users_list=sorted([user.pk for user in desired_ug_state.users]),
|
608
581
|
)
|
609
582
|
except SlackApiError as error:
|
@@ -658,13 +631,14 @@ def _update_usergroup_from_state(
|
|
658
631
|
|
659
632
|
if not dry_run:
|
660
633
|
try:
|
661
|
-
|
634
|
+
ugid = slack_client.get_usergroup_id(desired_ug_state.usergroup)
|
635
|
+
if not ugid:
|
662
636
|
logging.info(
|
663
637
|
f"Usergroup {desired_ug_state.usergroup} does not exist yet. Skipping for now."
|
664
638
|
)
|
665
639
|
return
|
666
640
|
slack_client.update_usergroup(
|
667
|
-
id=
|
641
|
+
id=ugid,
|
668
642
|
channels_list=sorted([
|
669
643
|
channel.pk for channel in desired_ug_state.channels
|
670
644
|
]),
|
@@ -689,24 +663,40 @@ def act(
|
|
689
663
|
usergroup, State()
|
690
664
|
)
|
691
665
|
|
666
|
+
slack_client = slack_map[workspace].slack
|
667
|
+
|
668
|
+
desired_ug_state.users = {
|
669
|
+
SlackObject(pk=pk, name=name)
|
670
|
+
for pk, name in slack_client.get_users_by_names(
|
671
|
+
sorted(desired_ug_state.user_names)
|
672
|
+
).items()
|
673
|
+
}
|
674
|
+
|
675
|
+
desired_ug_state.channels = {
|
676
|
+
SlackObject(pk=pk, name=name)
|
677
|
+
for pk, name in slack_client.get_channels_by_names(
|
678
|
+
sorted(desired_ug_state.channel_names or [])
|
679
|
+
).items()
|
680
|
+
}
|
681
|
+
|
692
682
|
_create_usergroups(
|
693
683
|
current_ug_state,
|
694
684
|
desired_ug_state,
|
695
|
-
slack_client=
|
685
|
+
slack_client=slack_client,
|
696
686
|
dry_run=dry_run,
|
697
687
|
)
|
698
688
|
|
699
689
|
_update_usergroup_users_from_state(
|
700
690
|
current_ug_state,
|
701
691
|
desired_ug_state,
|
702
|
-
slack_client=
|
692
|
+
slack_client=slack_client,
|
703
693
|
dry_run=dry_run,
|
704
694
|
)
|
705
695
|
|
706
696
|
_update_usergroup_from_state(
|
707
697
|
current_ug_state,
|
708
698
|
desired_ug_state,
|
709
|
-
slack_client=
|
699
|
+
slack_client=slack_client,
|
710
700
|
dry_run=dry_run,
|
711
701
|
)
|
712
702
|
|
@@ -760,7 +750,6 @@ def run(
|
|
760
750
|
|
761
751
|
# run
|
762
752
|
desired_state = get_desired_state(
|
763
|
-
slack_map=slack_map,
|
764
753
|
pagerduty_map=pagerduty_map,
|
765
754
|
permissions=permissions,
|
766
755
|
users=users,
|
@@ -776,6 +765,7 @@ def run(
|
|
776
765
|
)
|
777
766
|
# merge the two desired states recursively
|
778
767
|
desired_state = deep_update(desired_state, desired_state_cluster_usergroups)
|
768
|
+
|
779
769
|
current_state = get_current_state(
|
780
770
|
slack_map=slack_map,
|
781
771
|
desired_workspace_name=workspace_name,
|
@@ -62,7 +62,9 @@ def base_state():
|
|
62
62
|
usergroup="usergroup-1",
|
63
63
|
usergroup_id="USERGA",
|
64
64
|
users={SlackObject(name="username", pk="USERA")},
|
65
|
+
user_names={"username"},
|
65
66
|
channels={SlackObject(name="channelname", pk="CHANA")},
|
67
|
+
channel_names={"channelname"},
|
66
68
|
description="Some description",
|
67
69
|
)
|
68
70
|
}
|
@@ -402,8 +404,6 @@ def test_include_user_to_cluster_usergroup(mocker: MockerFixture, user: UserV1)
|
|
402
404
|
def test_get_desired_state(
|
403
405
|
mocker: MockerFixture,
|
404
406
|
permissions: Sequence[PermissionSlackUsergroupV1],
|
405
|
-
slack_map: SlackMap,
|
406
|
-
slack_client_mock: Mock,
|
407
407
|
user: UserV1,
|
408
408
|
) -> None:
|
409
409
|
mocker.patch(
|
@@ -413,21 +413,13 @@ def test_get_desired_state(
|
|
413
413
|
"reconcile.slack_usergroups.get_slack_usernames_from_owners"
|
414
414
|
).return_value = ["repo-user"]
|
415
415
|
mock_pagerduty_map = create_autospec(PagerDutyMap)
|
416
|
-
slack_client_mock.get_usergroup_id.return_value = "ugid"
|
417
416
|
result = integ.get_desired_state(
|
418
|
-
slack_map,
|
419
417
|
mock_pagerduty_map,
|
420
418
|
permissions[1:],
|
421
419
|
[user],
|
422
420
|
desired_workspace_name=None,
|
423
421
|
desired_usergroup_name=None,
|
424
422
|
)
|
425
|
-
assert slack_client_mock.get_users_by_names.call_args_list == [
|
426
|
-
call(["repo-user", "slack_username", "user1"]),
|
427
|
-
]
|
428
|
-
assert slack_client_mock.get_channels_by_names.call_args_list == [
|
429
|
-
call(["sd-sre-platform", "sre-operators"])
|
430
|
-
]
|
431
423
|
|
432
424
|
assert result == {
|
433
425
|
"coreos": {
|
@@ -436,7 +428,9 @@ def test_get_desired_state(
|
|
436
428
|
usergroup="saas-osd-operators",
|
437
429
|
description="SREP managed-cluster-config owners (managed via app-interface)",
|
438
430
|
users=set(),
|
431
|
+
user_names={"repo-user", "user1", "slack_username"},
|
439
432
|
channels=set(),
|
433
|
+
channel_names={"sre-operators", "sd-sre-platform"},
|
440
434
|
usergroup_id="ugid",
|
441
435
|
)
|
442
436
|
}
|
@@ -444,26 +438,18 @@ def test_get_desired_state(
|
|
444
438
|
|
445
439
|
|
446
440
|
def test_get_desired_state_cluster_usergroups(
|
447
|
-
mocker: MockerFixture, slack_map: SlackMap,
|
441
|
+
mocker: MockerFixture, slack_map: SlackMap, user: UserV1
|
448
442
|
) -> None:
|
449
443
|
mocker.patch("reconcile.openshift_users.fetch_desired_state", autospec=True)
|
450
444
|
mocker.patch(
|
451
445
|
"reconcile.slack_usergroups.include_user_to_cluster_usergroup"
|
452
446
|
).return_value = True
|
453
|
-
slack_client_mock.get_usergroup_id.return_value = "ugid"
|
454
447
|
|
455
448
|
cluster = ClusterV1(name="cluster1", auth=[], disable={"integrations": []})
|
456
449
|
result = integ.get_desired_state_cluster_usergroups(
|
457
450
|
slack_map, [cluster], [user], None, None
|
458
451
|
)
|
459
|
-
|
460
|
-
call(["slack"]),
|
461
|
-
call(["slack"]),
|
462
|
-
]
|
463
|
-
assert slack_client_mock.get_channels_by_names.call_args_list == [
|
464
|
-
call(["channel"]),
|
465
|
-
call(["channel"]),
|
466
|
-
]
|
452
|
+
|
467
453
|
assert result == {
|
468
454
|
"coreos": {
|
469
455
|
"cluster1-cluster": State(
|
@@ -471,7 +457,9 @@ def test_get_desired_state_cluster_usergroups(
|
|
471
457
|
usergroup="cluster1-cluster",
|
472
458
|
description="Users with access to the cluster1 cluster",
|
473
459
|
users=set(),
|
460
|
+
user_names={"slack"},
|
474
461
|
channels=set(),
|
462
|
+
channel_names={"channel"},
|
475
463
|
usergroup_id="ugid",
|
476
464
|
)
|
477
465
|
},
|
@@ -481,7 +469,9 @@ def test_get_desired_state_cluster_usergroups(
|
|
481
469
|
usergroup="cluster1-cluster",
|
482
470
|
description="Users with access to the cluster1 cluster",
|
483
471
|
users=set(),
|
472
|
+
user_names={"slack"},
|
484
473
|
channels=set(),
|
474
|
+
channel_names={"channel"},
|
485
475
|
usergroup_id="ugid",
|
486
476
|
)
|
487
477
|
},
|
@@ -489,26 +479,18 @@ def test_get_desired_state_cluster_usergroups(
|
|
489
479
|
|
490
480
|
|
491
481
|
def test_get_desired_state_non_existing_usergroup(
|
492
|
-
mocker: MockerFixture, slack_map: SlackMap,
|
482
|
+
mocker: MockerFixture, slack_map: SlackMap, user: UserV1
|
493
483
|
) -> None:
|
494
484
|
mocker.patch("reconcile.openshift_users.fetch_desired_state", autospec=True)
|
495
485
|
mocker.patch(
|
496
486
|
"reconcile.slack_usergroups.include_user_to_cluster_usergroup"
|
497
487
|
).return_value = True
|
498
|
-
slack_client_mock.get_usergroup_id.return_value = None
|
499
488
|
|
500
489
|
cluster = ClusterV1(name="cluster1", auth=[], disable={"integrations": []})
|
501
490
|
result = integ.get_desired_state_cluster_usergroups(
|
502
491
|
slack_map, [cluster], [user], None, None
|
503
492
|
)
|
504
|
-
|
505
|
-
call(["slack"]),
|
506
|
-
call(["slack"]),
|
507
|
-
]
|
508
|
-
assert slack_client_mock.get_channels_by_names.call_args_list == [
|
509
|
-
call(["channel"]),
|
510
|
-
call(["channel"]),
|
511
|
-
]
|
493
|
+
|
512
494
|
assert result == {
|
513
495
|
"coreos": {
|
514
496
|
"cluster1-cluster": State(
|
@@ -516,7 +498,9 @@ def test_get_desired_state_non_existing_usergroup(
|
|
516
498
|
usergroup="cluster1-cluster",
|
517
499
|
description="Users with access to the cluster1 cluster",
|
518
500
|
users=set(),
|
501
|
+
user_names={"slack"},
|
519
502
|
channels=set(),
|
503
|
+
channel_names={"channel"},
|
520
504
|
usergroup_id=None,
|
521
505
|
)
|
522
506
|
},
|
@@ -526,7 +510,9 @@ def test_get_desired_state_non_existing_usergroup(
|
|
526
510
|
usergroup="cluster1-cluster",
|
527
511
|
description="Users with access to the cluster1 cluster",
|
528
512
|
users=set(),
|
513
|
+
user_names={"slack"},
|
529
514
|
channels=set(),
|
515
|
+
channel_names={"channel"},
|
530
516
|
usergroup_id=None,
|
531
517
|
)
|
532
518
|
},
|
@@ -597,6 +583,9 @@ def test_act_empty_current_state(
|
|
597
583
|
desired_state = base_state
|
598
584
|
|
599
585
|
slack_client_mock.create_usergroup.return_value = "USERGA"
|
586
|
+
slack_client_mock.get_usergroup_id.return_value = "USERGA"
|
587
|
+
slack_client_mock.get_users_by_names.return_value = {"USERA": "username"}
|
588
|
+
slack_client_mock.get_channels_by_names.return_value = {"CHANA": "someotherchannel"}
|
600
589
|
|
601
590
|
act(current_state, desired_state, slack_map, dry_run=False)
|
602
591
|
|
@@ -615,10 +604,12 @@ def test_act_update_usergroup_users(
|
|
615
604
|
current_state = base_state
|
616
605
|
desired_state = copy.deepcopy(base_state)
|
617
606
|
|
618
|
-
|
619
|
-
|
620
|
-
|
607
|
+
slack_client_mock.get_usergroup_id.return_value = "USERGA"
|
608
|
+
slack_client_mock.get_users_by_names.return_value = {
|
609
|
+
"USERB": "someotherusername",
|
610
|
+
"USERC": "anotheruser",
|
621
611
|
}
|
612
|
+
slack_client_mock.get_channels_by_names.return_value = {"CHANA": "channelname"}
|
622
613
|
|
623
614
|
act(current_state, desired_state, slack_map, dry_run=False)
|
624
615
|
|
@@ -634,9 +625,11 @@ def test_act_update_usergroup_channels(
|
|
634
625
|
current_state = base_state
|
635
626
|
desired_state = copy.deepcopy(base_state)
|
636
627
|
|
637
|
-
desired_state["slack-workspace"]["usergroup-1"].
|
638
|
-
|
639
|
-
|
628
|
+
desired_state["slack-workspace"]["usergroup-1"].channel_names = {"CHANB"}
|
629
|
+
|
630
|
+
slack_client_mock.get_usergroup_id.return_value = "USERGA"
|
631
|
+
slack_client_mock.get_users_by_names.return_value = {"USERA": "username"}
|
632
|
+
slack_client_mock.get_channels_by_names.return_value = {"CHANB": "channel"}
|
640
633
|
|
641
634
|
act(current_state, desired_state, slack_map, dry_run=False)
|
642
635
|
|
@@ -656,6 +649,10 @@ def test_act_update_usergroup_description(
|
|
656
649
|
"usergroup-1"
|
657
650
|
].description = "A different description"
|
658
651
|
|
652
|
+
slack_client_mock.get_usergroup_id.return_value = "USERGA"
|
653
|
+
slack_client_mock.get_users_by_names.return_value = {"USERA": "username"}
|
654
|
+
slack_client_mock.get_channels_by_names.return_value = {"CHANA": "channel"}
|
655
|
+
|
659
656
|
act(current_state, desired_state, slack_map, dry_run=False)
|
660
657
|
|
661
658
|
assert slack_client_mock.update_usergroup.call_args_list == [
|
@@ -675,9 +672,10 @@ def test_act_update_usergroup_desc_and_channels(
|
|
675
672
|
desired_state["slack-workspace"][
|
676
673
|
"usergroup-1"
|
677
674
|
].description = "A different description"
|
678
|
-
|
679
|
-
|
680
|
-
}
|
675
|
+
|
676
|
+
slack_client_mock.get_usergroup_id.return_value = "USERGA"
|
677
|
+
slack_client_mock.get_users_by_names.return_value = {"USERA": "username"}
|
678
|
+
slack_client_mock.get_channels_by_names.return_value = {"CHANB": "someotherchannel"}
|
681
679
|
|
682
680
|
act(current_state, desired_state, slack_map, dry_run=False)
|
683
681
|
|
@@ -692,21 +690,40 @@ def test_act_update_usergroup_desc_and_channels(
|
|
692
690
|
def test_act_add_new_usergroups(
|
693
691
|
base_state: SlackState, slack_map: SlackMap, slack_client_mock: Mock
|
694
692
|
) -> None:
|
693
|
+
def get_users(users: set[str]) -> dict[str, str]:
|
694
|
+
if "username" in users:
|
695
|
+
return {"USERA": "username"}
|
696
|
+
if "userb" in users:
|
697
|
+
return {"USERB": "userb", "USERC": "userc"}
|
698
|
+
return {"USERF": "userf", "USERG": "userg"}
|
699
|
+
|
700
|
+
def get_channels(channels: set[str]) -> dict[str, str]:
|
701
|
+
if "channelname" in channels:
|
702
|
+
return {"CHANA": "channelname"}
|
703
|
+
if "channelb" in channels:
|
704
|
+
return {"CHANB": "channelb", "CHANC": "channelc"}
|
705
|
+
return {"CHANF": "channelf", "CHANG": "channelg"}
|
706
|
+
|
707
|
+
def get_ugid(usergroup: str) -> str:
|
708
|
+
if usergroup == "usergroup-1":
|
709
|
+
return "USERGA"
|
710
|
+
if usergroup == "usergroup-2":
|
711
|
+
return "USERGB"
|
712
|
+
return "USERGC"
|
713
|
+
|
695
714
|
current_state = base_state
|
696
715
|
desired_state = copy.deepcopy(base_state)
|
697
716
|
|
717
|
+
slack_client_mock.get_usergroup_id.side_effect = get_ugid
|
718
|
+
slack_client_mock.get_users_by_names.side_effect = get_users
|
719
|
+
slack_client_mock.get_channels_by_names.side_effect = get_channels
|
720
|
+
|
698
721
|
desired_state["slack-workspace"]["usergroup-2"] = State(
|
699
722
|
workspace="slack-workspace",
|
700
723
|
usergroup="usergroup-2",
|
701
724
|
usergroup_id="USERGB",
|
702
|
-
|
703
|
-
|
704
|
-
SlackObject(pk="USERC", name="userc"),
|
705
|
-
],
|
706
|
-
channels=[
|
707
|
-
SlackObject(pk="CHANB", name="channelb"),
|
708
|
-
SlackObject(pk="CHANC", name="channelc"),
|
709
|
-
],
|
725
|
+
user_names={"userb", "userc"},
|
726
|
+
channel_names={"channelb", "channelc"},
|
710
727
|
description="A new usergroup",
|
711
728
|
)
|
712
729
|
|
@@ -714,14 +731,8 @@ def test_act_add_new_usergroups(
|
|
714
731
|
workspace="slack-workspace",
|
715
732
|
usergroup="usergroup-3",
|
716
733
|
usergroup_id="USERGC",
|
717
|
-
|
718
|
-
|
719
|
-
SlackObject(pk="USERG", name="userg"),
|
720
|
-
],
|
721
|
-
channels=[
|
722
|
-
SlackObject(pk="CHANF", name="channelf"),
|
723
|
-
SlackObject(pk="CHANG", name="channelg"),
|
724
|
-
],
|
734
|
+
user_names={"userf", "userg"},
|
735
|
+
channel_names={"channelf", "channelg"},
|
725
736
|
description="Another new usergroup",
|
726
737
|
)
|
727
738
|
slack_client_mock.create_usergroup.side_effect = ["USERGB", "USERGC"]
|
reconcile/utils/metrics.py
CHANGED
@@ -115,6 +115,12 @@ ocm_request = Counter(
|
|
115
115
|
labelnames=["verb", "client_id"],
|
116
116
|
)
|
117
117
|
|
118
|
+
slack_request = Counter(
|
119
|
+
name="qontract_reconcile_slack_request_total",
|
120
|
+
documentation="Number of calls made to Slack API",
|
121
|
+
labelnames=["resource", "verb"],
|
122
|
+
)
|
123
|
+
|
118
124
|
|
119
125
|
#
|
120
126
|
# Class based metrics
|
reconcile/utils/slack_api.py
CHANGED
@@ -24,6 +24,8 @@ from slack_sdk.http_retry import (
|
|
24
24
|
RetryState,
|
25
25
|
)
|
26
26
|
|
27
|
+
from reconcile.utils.metrics import slack_request
|
28
|
+
|
27
29
|
MAX_RETRIES = 5
|
28
30
|
TIMEOUT = 30
|
29
31
|
|
@@ -201,6 +203,9 @@ class SlackApi:
|
|
201
203
|
self.channel = channel
|
202
204
|
self.chat_kwargs = chat_kwargs
|
203
205
|
|
206
|
+
self._user_groups_initialized = False
|
207
|
+
self.usergroups: list[dict] = []
|
208
|
+
|
204
209
|
if init_usergroups:
|
205
210
|
self._initiate_usergroups()
|
206
211
|
|
@@ -235,6 +240,7 @@ class SlackApi:
|
|
235
240
|
)
|
236
241
|
|
237
242
|
def do_send(c: str, t: str) -> None:
|
243
|
+
slack_request.labels("chat.postMessage", "POST").inc()
|
238
244
|
self._sc.chat_postMessage(channel=c, text=t, **self.chat_kwargs)
|
239
245
|
|
240
246
|
try:
|
@@ -283,6 +289,8 @@ class SlackApi:
|
|
283
289
|
|
284
290
|
channels_found = self.get_channels_by_names(self.channel)
|
285
291
|
[channel_id] = [k for k in channels_found if channels_found[k] == self.channel]
|
292
|
+
slack_request.labels("conversations.info", "GET").inc()
|
293
|
+
|
286
294
|
info = self._sc.conversations_info(channel=channel_id)
|
287
295
|
if not info.data["channel"]["is_member"]: # type: ignore[call-overload]
|
288
296
|
self._sc.conversations_join(channel=channel_id)
|
@@ -300,17 +308,26 @@ class SlackApi:
|
|
300
308
|
:raises slack_sdk.errors.SlackApiError: if unsuccessful response from
|
301
309
|
Slack API
|
302
310
|
"""
|
311
|
+
slack_request.labels("usergroups.list", "GET").inc()
|
312
|
+
|
303
313
|
result = self._sc.usergroups_list(include_users=True)
|
304
314
|
self.usergroups = result["usergroups"]
|
315
|
+
self._user_groups_initialized = True
|
305
316
|
|
306
317
|
def get_usergroup(self, handle: str) -> dict[str, Any]:
|
318
|
+
if not self._user_groups_initialized:
|
319
|
+
self._initiate_usergroups()
|
307
320
|
usergroup = [g for g in self.usergroups if g["handle"] == handle]
|
308
321
|
if len(usergroup) != 1:
|
309
322
|
raise UsergroupNotFoundException(handle)
|
310
323
|
return usergroup[0]
|
311
324
|
|
312
325
|
def create_usergroup(self, handle: str) -> str:
|
326
|
+
slack_request.labels("usergroups.create", "POST").inc()
|
327
|
+
|
313
328
|
response = self._sc.usergroups_create(name=handle, handle=handle)
|
329
|
+
# Invalidate the usergroups list cache
|
330
|
+
self._user_groups_initialized = False
|
314
331
|
return response["usergroup"]["id"]
|
315
332
|
|
316
333
|
def update_usergroup(
|
@@ -326,6 +343,8 @@ class SlackApi:
|
|
326
343
|
:raises slack_sdk.errors.SlackApiError: if unsuccessful response from
|
327
344
|
Slack API
|
328
345
|
"""
|
346
|
+
slack_request.labels("usergroups.update", "POST").inc()
|
347
|
+
|
329
348
|
self._sc.usergroups_update(
|
330
349
|
usergroup=id, channels=channels_list, description=description
|
331
350
|
)
|
@@ -346,6 +365,8 @@ class SlackApi:
|
|
346
365
|
users_list = [self.get_random_deleted_user()]
|
347
366
|
|
348
367
|
try:
|
368
|
+
slack_request.labels("usergroups.users.update", "POST").inc()
|
369
|
+
|
349
370
|
self._sc.usergroups_users_update(usergroup=id, users=users_list)
|
350
371
|
except SlackApiError as e:
|
351
372
|
# Slack can throw an invalid_users error when emptying groups, but
|
@@ -374,6 +395,8 @@ class SlackApi:
|
|
374
395
|
:raises UserNotFoundException: if the Slack user is not found
|
375
396
|
"""
|
376
397
|
try:
|
398
|
+
slack_request.labels("users.lookupByEmail", "GET").inc()
|
399
|
+
|
377
400
|
result = self._sc.users_lookupByEmail(email=f"{user_name}@{mail_address}")
|
378
401
|
except SlackApiError as e:
|
379
402
|
if e.response["error"] == "users_not_found":
|
@@ -433,6 +456,8 @@ class SlackApi:
|
|
433
456
|
additional_kwargs.update(method_config)
|
434
457
|
|
435
458
|
while True:
|
459
|
+
slack_request.labels(f"{api_key}.list", "GET").inc()
|
460
|
+
|
436
461
|
result = self._sc.api_call(
|
437
462
|
"{}.list".format(api_key), http_verb="GET", params=additional_kwargs
|
438
463
|
)
|
@@ -473,6 +498,8 @@ class SlackApi:
|
|
473
498
|
responses = []
|
474
499
|
keep_fetching = True
|
475
500
|
while True:
|
501
|
+
slack_request.labels("conversations.history", "GET").inc()
|
502
|
+
|
476
503
|
response = self._sc.conversations_history(
|
477
504
|
cursor=cursor, channel=self.channel, **self.chat_kwargs
|
478
505
|
)
|
File without changes
|
File without changes
|
{qontract_reconcile-0.10.1rc772.dist-info → qontract_reconcile-0.10.1rc773.dist-info}/top_level.txt
RENAMED
File without changes
|