catocli 3.0.13__py3-none-any.whl → 3.0.18__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.
Potentially problematic release.
This version of catocli might be problematic. Click here for more details.
- catocli/Utils/clidriver.py +8 -8
- catocli/Utils/help_formatter.py +77 -9
- catocli/__init__.py +1 -1
- catocli/parsers/custom/query_eventsFeed/README.md +94 -0
- catocli/parsers/custom/scim/README.md +346 -0
- catocli/parsers/custom/scim/scim_client.py +132 -26
- catocli/parsers/custom/scim/scim_commands.py +14 -56
- catocli/parsers/customParserApiClient.py +7 -0
- catocli/parsers/query_accountMetrics/README.md +9 -9
- catocli/parsers/query_appStats/README.md +9 -9
- catocli/parsers/query_appStatsTimeSeries/README.md +10 -10
- catocli/parsers/query_auditFeed/README.md +9 -9
- catocli/parsers/query_events/README.md +9 -9
- catocli/parsers/query_eventsTimeSeries/README.md +9 -9
- catocli/parsers/query_socketPortMetrics/README.md +9 -9
- catocli/parsers/query_socketPortMetricsTimeSeries/README.md +9 -9
- {catocli-3.0.13.dist-info → catocli-3.0.18.dist-info}/METADATA +1 -1
- {catocli-3.0.13.dist-info → catocli-3.0.18.dist-info}/RECORD +23 -21
- schema/catolib.py +9 -9
- {catocli-3.0.13.dist-info → catocli-3.0.18.dist-info}/WHEEL +0 -0
- {catocli-3.0.13.dist-info → catocli-3.0.18.dist-info}/entry_points.txt +0 -0
- {catocli-3.0.13.dist-info → catocli-3.0.18.dist-info}/licenses/LICENSE +0 -0
- {catocli-3.0.13.dist-info → catocli-3.0.18.dist-info}/top_level.txt +0 -0
|
@@ -74,6 +74,9 @@ class CatoSCIMClient:
|
|
|
74
74
|
self.verbose = verbose
|
|
75
75
|
self.call_count = 0
|
|
76
76
|
|
|
77
|
+
# Parse accountId and sourceId from the SCIM URL
|
|
78
|
+
self.account_id, self.source_id = self._parse_scim_url(self.baseurl)
|
|
79
|
+
|
|
77
80
|
# Configure module logger
|
|
78
81
|
if isinstance(log_level, int):
|
|
79
82
|
# Backwards compatibility: 0=CRITICAL+1, 1=ERROR, 2=INFO, 3=DEBUG
|
|
@@ -93,6 +96,52 @@ class CatoSCIMClient:
|
|
|
93
96
|
logger.warning("SSL certificate verification is disabled - this is insecure!")
|
|
94
97
|
|
|
95
98
|
logger.debug(f"Initialized CatoSCIMClient with baseurl: {self.baseurl}")
|
|
99
|
+
logger.debug(f"Parsed accountId: {self.account_id}, sourceId: {self.source_id}")
|
|
100
|
+
|
|
101
|
+
def _parse_scim_url(self, scim_url):
|
|
102
|
+
"""
|
|
103
|
+
Parse accountId and sourceId from SCIM URL.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
scim_url: SCIM URL in format https://scimservice.catonetworks.com:4443/scim/v2/{accountId}/{sourceId}
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
tuple: (account_id, source_id)
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
ValueError: If URL format is invalid
|
|
113
|
+
"""
|
|
114
|
+
if not scim_url:
|
|
115
|
+
raise ValueError("SCIM URL is required")
|
|
116
|
+
|
|
117
|
+
try:
|
|
118
|
+
parsed = urllib.parse.urlparse(scim_url)
|
|
119
|
+
path_parts = parsed.path.strip('/').split('/')
|
|
120
|
+
|
|
121
|
+
# Expected path: ['scim', 'v2', 'accountId', 'sourceId']
|
|
122
|
+
if len(path_parts) < 4 or path_parts[0] != 'scim' or path_parts[1] != 'v2':
|
|
123
|
+
raise ValueError(
|
|
124
|
+
f"Invalid SCIM URL format. Expected: https://scimservice.catonetworks.com:4443/scim/v2/{{accountId}}/{{sourceId}}, "
|
|
125
|
+
f"got: {scim_url}"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
account_id = path_parts[2]
|
|
129
|
+
source_id = path_parts[3]
|
|
130
|
+
|
|
131
|
+
# Validate that they are numeric (optional, but helpful for catching errors)
|
|
132
|
+
try:
|
|
133
|
+
int(account_id)
|
|
134
|
+
int(source_id)
|
|
135
|
+
except ValueError:
|
|
136
|
+
logger.warning(f"Non-numeric accountId ({account_id}) or sourceId ({source_id}) in SCIM URL: {scim_url}")
|
|
137
|
+
|
|
138
|
+
return account_id, source_id
|
|
139
|
+
|
|
140
|
+
except (IndexError, AttributeError) as e:
|
|
141
|
+
raise ValueError(
|
|
142
|
+
f"Failed to parse SCIM URL: {scim_url}. "
|
|
143
|
+
f"Expected format: https://scimservice.catonetworks.com:4443/scim/v2/{{accountId}}/{{sourceId}}"
|
|
144
|
+
) from e
|
|
96
145
|
|
|
97
146
|
def send(self, method="GET", path="/", request_data=None):
|
|
98
147
|
"""
|
|
@@ -477,27 +526,74 @@ class CatoSCIMClient:
|
|
|
477
526
|
|
|
478
527
|
return True, groups
|
|
479
528
|
|
|
480
|
-
def get_user(self, userid):
|
|
529
|
+
def get_user(self, userid, excluded_attributes=None):
|
|
481
530
|
"""
|
|
482
531
|
Gets a user by their ID.
|
|
483
532
|
|
|
484
533
|
Args:
|
|
485
534
|
userid: SCIM user ID to retrieve
|
|
535
|
+
excluded_attributes: Optional comma-separated list of attributes to exclude
|
|
486
536
|
|
|
487
537
|
Returns:
|
|
488
538
|
Tuple of (success_boolean, user_data)
|
|
539
|
+
|
|
540
|
+
Note:
|
|
541
|
+
accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
489
542
|
"""
|
|
490
543
|
logger.info(f'Getting user: {userid}')
|
|
491
|
-
|
|
544
|
+
|
|
545
|
+
# Build query parameters if excluded_attributes is provided
|
|
546
|
+
path = f'/Users/{userid}'
|
|
547
|
+
if excluded_attributes:
|
|
548
|
+
path += f'?excludedAttributes={urllib.parse.quote(excluded_attributes)}'
|
|
549
|
+
|
|
550
|
+
return self.send("GET", path)
|
|
492
551
|
|
|
493
|
-
def get_users(self):
|
|
552
|
+
def get_users(self, count=None, start_index=None, params=None):
|
|
494
553
|
"""
|
|
495
|
-
Returns
|
|
554
|
+
Returns users with optional pagination and filtering support.
|
|
555
|
+
|
|
556
|
+
Args:
|
|
557
|
+
count: Optional maximum number of users to return
|
|
558
|
+
start_index: Optional starting index for pagination (1-based)
|
|
559
|
+
params: Optional additional query parameters
|
|
496
560
|
|
|
497
561
|
Returns:
|
|
498
|
-
Tuple of (success_boolean,
|
|
562
|
+
Tuple of (success_boolean, list_of_users_or_paginated_response)
|
|
563
|
+
|
|
564
|
+
Note:
|
|
565
|
+
accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
499
566
|
"""
|
|
500
|
-
logger.info('Fetching
|
|
567
|
+
logger.info('Fetching users')
|
|
568
|
+
|
|
569
|
+
# If specific pagination parameters are provided, return paginated response
|
|
570
|
+
if count is not None or start_index is not None:
|
|
571
|
+
# Build query parameters
|
|
572
|
+
query_params = []
|
|
573
|
+
if count is not None:
|
|
574
|
+
query_params.append(f'count={count}')
|
|
575
|
+
if start_index is not None:
|
|
576
|
+
query_params.append(f'startIndex={start_index}')
|
|
577
|
+
|
|
578
|
+
# Add any additional params
|
|
579
|
+
if params and isinstance(params, dict):
|
|
580
|
+
for key, value in params.items():
|
|
581
|
+
query_params.append(f'{key}={urllib.parse.quote(str(value))}')
|
|
582
|
+
|
|
583
|
+
query_string = '&'.join(query_params)
|
|
584
|
+
path = f'/Users?{query_string}' if query_string else '/Users'
|
|
585
|
+
|
|
586
|
+
logger.debug(f'Sending paginated users request: {path}')
|
|
587
|
+
success, response = self.send("GET", path)
|
|
588
|
+
|
|
589
|
+
if success:
|
|
590
|
+
# Return the full paginated response format
|
|
591
|
+
return True, response
|
|
592
|
+
else:
|
|
593
|
+
logger.error(f'Error retrieving users: {response}')
|
|
594
|
+
return False, response
|
|
595
|
+
|
|
596
|
+
# Default behavior: fetch all users (backward compatibility)
|
|
501
597
|
users = []
|
|
502
598
|
iteration = 0
|
|
503
599
|
while True:
|
|
@@ -609,27 +705,34 @@ class CatoSCIMClient:
|
|
|
609
705
|
|
|
610
706
|
Returns:
|
|
611
707
|
Tuple of (success_boolean, response_data)
|
|
708
|
+
|
|
709
|
+
Note:
|
|
710
|
+
accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
612
711
|
"""
|
|
613
712
|
logger.info(f'Updating user {userid}')
|
|
614
713
|
|
|
714
|
+
if user_data is None:
|
|
715
|
+
raise ValueError("user_data is required")
|
|
716
|
+
|
|
615
717
|
# Send the request
|
|
616
718
|
success, result = self.send("PUT", f'/Users/{userid}', user_data)
|
|
617
719
|
return success, result
|
|
618
720
|
|
|
619
|
-
def patch_user(self, user_id,
|
|
721
|
+
def patch_user(self, user_id, patch_request):
|
|
620
722
|
"""
|
|
621
|
-
Patch a SCIM user with partial updates (PATCH operation)
|
|
723
|
+
Patch a SCIM user with partial updates (PATCH operation).
|
|
622
724
|
|
|
623
725
|
Args:
|
|
624
726
|
user_id: SCIM user ID to patch
|
|
625
|
-
account_id: SCIM account identifier
|
|
626
|
-
source_id: SCIM source identifier
|
|
627
727
|
patch_request: PatchRequestDTO containing Operations array
|
|
628
728
|
|
|
629
729
|
Returns:
|
|
630
730
|
Tuple of (success_boolean, response_data)
|
|
731
|
+
|
|
732
|
+
Note:
|
|
733
|
+
accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
631
734
|
"""
|
|
632
|
-
logger.info(f'Patching user {user_id} in account {account_id}, source {source_id}')
|
|
735
|
+
logger.info(f'Patching user {user_id} in account {self.account_id}, source {self.source_id}')
|
|
633
736
|
|
|
634
737
|
# The SCIM API expects the full path format: /scim/v2/{accountId}/{sourceId}/Users/{id}
|
|
635
738
|
# But our base URL already includes the /scim/v2/{accountId}/{sourceId} part,
|
|
@@ -638,19 +741,20 @@ class CatoSCIMClient:
|
|
|
638
741
|
success, result = self.send("PATCH", path, patch_request)
|
|
639
742
|
return success, result
|
|
640
743
|
|
|
641
|
-
def delete_user(self, user_id
|
|
744
|
+
def delete_user(self, user_id):
|
|
642
745
|
"""
|
|
643
|
-
Delete a SCIM user (DELETE operation)
|
|
746
|
+
Delete a SCIM user (DELETE operation).
|
|
644
747
|
|
|
645
748
|
Args:
|
|
646
749
|
user_id: SCIM user ID to delete
|
|
647
|
-
account_id: SCIM account identifier
|
|
648
|
-
source_id: SCIM source identifier
|
|
649
750
|
|
|
650
751
|
Returns:
|
|
651
752
|
Tuple of (success_boolean, response_data)
|
|
753
|
+
|
|
754
|
+
Note:
|
|
755
|
+
accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
652
756
|
"""
|
|
653
|
-
logger.info(f'Deleting user {user_id} in account {account_id}, source {source_id}')
|
|
757
|
+
logger.info(f'Deleting user {user_id} in account {self.account_id}, source {self.source_id}')
|
|
654
758
|
|
|
655
759
|
# The SCIM API expects the full path format: /scim/v2/{accountId}/{sourceId}/Users/{id}
|
|
656
760
|
# But our base URL already includes the /scim/v2/{accountId}/{sourceId} part,
|
|
@@ -659,20 +763,21 @@ class CatoSCIMClient:
|
|
|
659
763
|
success, result = self.send("DELETE", path)
|
|
660
764
|
return success, result
|
|
661
765
|
|
|
662
|
-
def patch_group(self, group_id,
|
|
766
|
+
def patch_group(self, group_id, patch_request):
|
|
663
767
|
"""
|
|
664
|
-
Patch a SCIM group with partial updates (PATCH operation)
|
|
768
|
+
Patch a SCIM group with partial updates (PATCH operation).
|
|
665
769
|
|
|
666
770
|
Args:
|
|
667
771
|
group_id: SCIM group ID to patch
|
|
668
|
-
account_id: SCIM account identifier
|
|
669
|
-
source_id: SCIM source identifier
|
|
670
772
|
patch_request: PatchRequestDTO containing Operations array
|
|
671
773
|
|
|
672
774
|
Returns:
|
|
673
775
|
Tuple of (success_boolean, response_data)
|
|
776
|
+
|
|
777
|
+
Note:
|
|
778
|
+
accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
674
779
|
"""
|
|
675
|
-
logger.info(f'Patching group {group_id} in account {account_id}, source {source_id}')
|
|
780
|
+
logger.info(f'Patching group {group_id} in account {self.account_id}, source {self.source_id}')
|
|
676
781
|
|
|
677
782
|
# The SCIM API expects the full path format: /scim/v2/{accountId}/{sourceId}/Groups/{id}
|
|
678
783
|
# But our base URL already includes the /scim/v2/{accountId}/{sourceId} part,
|
|
@@ -681,19 +786,20 @@ class CatoSCIMClient:
|
|
|
681
786
|
success, result = self.send("PATCH", path, patch_request)
|
|
682
787
|
return success, result
|
|
683
788
|
|
|
684
|
-
def delete_group(self, group_id
|
|
789
|
+
def delete_group(self, group_id):
|
|
685
790
|
"""
|
|
686
|
-
Delete a SCIM group (DELETE operation)
|
|
791
|
+
Delete a SCIM group (DELETE operation).
|
|
687
792
|
|
|
688
793
|
Args:
|
|
689
794
|
group_id: SCIM group ID to delete
|
|
690
|
-
account_id: SCIM account identifier
|
|
691
|
-
source_id: SCIM source identifier
|
|
692
795
|
|
|
693
796
|
Returns:
|
|
694
797
|
Tuple of (success_boolean, response_data)
|
|
798
|
+
|
|
799
|
+
Note:
|
|
800
|
+
accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
695
801
|
"""
|
|
696
|
-
logger.info(f'Deleting group {group_id} in account {account_id}, source {source_id}')
|
|
802
|
+
logger.info(f'Deleting group {group_id} in account {self.account_id}, source {self.source_id}')
|
|
697
803
|
|
|
698
804
|
# The SCIM API expects the full path format: /scim/v2/{accountId}/{sourceId}/Groups/{id}
|
|
699
805
|
# But our base URL already includes the /scim/v2/{accountId}/{sourceId} part,
|
|
@@ -598,24 +598,17 @@ def scim_get_user(args, configuration=None):
|
|
|
598
598
|
|
|
599
599
|
# Extract required path parameters
|
|
600
600
|
user_id = json_data.get('user_id') or json_data.get('id')
|
|
601
|
-
source_id = json_data.get('source_id')
|
|
602
601
|
|
|
603
602
|
# Extract optional query parameters
|
|
604
603
|
excluded_attributes = json_data.get('excluded_attributes')
|
|
605
604
|
|
|
606
|
-
# Get accountID from configuration
|
|
607
|
-
account_id = getattr(args, 'accountID', None) or getattr(configuration, 'accountID', None) if configuration else None
|
|
608
|
-
|
|
609
605
|
if not user_id:
|
|
610
606
|
return handle_scim_error("Missing required field: user_id (or id)", args.verbose)
|
|
611
|
-
if not account_id:
|
|
612
|
-
return handle_scim_error("Missing accountID. Please ensure your Cato configuration is set up correctly.", args.verbose)
|
|
613
|
-
if not source_id:
|
|
614
|
-
return handle_scim_error("Missing required field: source_id", args.verbose)
|
|
615
607
|
|
|
616
608
|
# Get SCIM client and execute operation
|
|
609
|
+
# accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
617
610
|
client = get_scim_client(verbose=hasattr(args, 'verbose') and args.verbose)
|
|
618
|
-
success, result = client.get_user(user_id,
|
|
611
|
+
success, result = client.get_user(user_id, excluded_attributes)
|
|
619
612
|
|
|
620
613
|
return format_scim_response(
|
|
621
614
|
success, result, f"Get user {user_id}",
|
|
@@ -637,25 +630,15 @@ def scim_get_users(args, configuration=None):
|
|
|
637
630
|
except json.JSONDecodeError as e:
|
|
638
631
|
return handle_scim_error(f"Invalid JSON input: {e}", args.verbose)
|
|
639
632
|
|
|
640
|
-
# Extract required path parameters
|
|
641
|
-
source_id = json_data.get('source_id')
|
|
642
|
-
|
|
643
633
|
# Extract optional query parameters
|
|
644
634
|
count = json_data.get('count')
|
|
645
635
|
start_index = json_data.get('start_index') or json_data.get('startIndex')
|
|
646
636
|
params = json_data.get('params', {})
|
|
647
637
|
|
|
648
|
-
# Get accountID from configuration
|
|
649
|
-
account_id = getattr(args, 'accountID', None) or getattr(configuration, 'accountID', None) if configuration else None
|
|
650
|
-
|
|
651
|
-
if not account_id:
|
|
652
|
-
return handle_scim_error("Missing accountID. Please ensure your Cato configuration is set up correctly.", args.verbose)
|
|
653
|
-
if not source_id:
|
|
654
|
-
return handle_scim_error("Missing required field: source_id", args.verbose)
|
|
655
|
-
|
|
656
638
|
# Get SCIM client and execute operation
|
|
639
|
+
# accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
657
640
|
client = get_scim_client(verbose=hasattr(args, 'verbose') and args.verbose)
|
|
658
|
-
success, result = client.get_users(
|
|
641
|
+
success, result = client.get_users(count, start_index, params)
|
|
659
642
|
|
|
660
643
|
if success:
|
|
661
644
|
# Handle both direct array response and ListResponse format
|
|
@@ -839,16 +822,10 @@ def scim_update_user(args, configuration=None):
|
|
|
839
822
|
|
|
840
823
|
# Extract required path parameters
|
|
841
824
|
user_id = json_data.get('user_id') or json_data.get('id')
|
|
842
|
-
account_id = json_data.get('account_id')
|
|
843
|
-
source_id = json_data.get('source_id')
|
|
844
825
|
user_data = json_data.get('user_data', json_data)
|
|
845
826
|
|
|
846
827
|
if not user_id:
|
|
847
828
|
return handle_scim_error("Missing required field: user_id (or id)", args.verbose)
|
|
848
|
-
if not account_id:
|
|
849
|
-
return handle_scim_error("Missing required field: account_id", args.verbose)
|
|
850
|
-
if not source_id:
|
|
851
|
-
return handle_scim_error("Missing required field: source_id", args.verbose)
|
|
852
829
|
if not user_data:
|
|
853
830
|
return handle_scim_error("Missing required field: user_data", args.verbose)
|
|
854
831
|
|
|
@@ -857,8 +834,9 @@ def scim_update_user(args, configuration=None):
|
|
|
857
834
|
return handle_scim_error("User data must be a JSON object", args.verbose)
|
|
858
835
|
|
|
859
836
|
# Get SCIM client and execute operation
|
|
837
|
+
# accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
860
838
|
client = get_scim_client(verbose=hasattr(args, 'verbose') and args.verbose)
|
|
861
|
-
success, result = client.update_user(user_id,
|
|
839
|
+
success, result = client.update_user(user_id, user_data)
|
|
862
840
|
|
|
863
841
|
return format_scim_response(
|
|
864
842
|
success, result, f"Update user {user_id}",
|
|
@@ -890,18 +868,12 @@ def scim_patch_user(args, configuration=None):
|
|
|
890
868
|
|
|
891
869
|
# Extract required path parameters
|
|
892
870
|
user_id = json_data.get('user_id') or json_data.get('id')
|
|
893
|
-
account_id = json_data.get('account_id')
|
|
894
|
-
source_id = json_data.get('source_id')
|
|
895
871
|
|
|
896
872
|
# Extract patch request data
|
|
897
873
|
patch_data = json_data.get('patch_data', json_data)
|
|
898
874
|
|
|
899
875
|
if not user_id:
|
|
900
876
|
return handle_scim_error("Missing required field: user_id (or id)", args.verbose)
|
|
901
|
-
if not account_id:
|
|
902
|
-
return handle_scim_error("Missing required field: account_id", args.verbose)
|
|
903
|
-
if not source_id:
|
|
904
|
-
return handle_scim_error("Missing required field: source_id", args.verbose)
|
|
905
877
|
|
|
906
878
|
# Build PatchRequestDTO according to swagger schema
|
|
907
879
|
patch_request = {
|
|
@@ -930,8 +902,9 @@ def scim_patch_user(args, configuration=None):
|
|
|
930
902
|
return handle_scim_error(f"Operation {i+1}: Invalid operation '{op['op']}'. Must be 'add', 'remove', or 'replace'", args.verbose)
|
|
931
903
|
|
|
932
904
|
# Get SCIM client and execute operation
|
|
905
|
+
# accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
933
906
|
client = get_scim_client(verbose=hasattr(args, 'verbose') and args.verbose)
|
|
934
|
-
success, result = client.patch_user(user_id,
|
|
907
|
+
success, result = client.patch_user(user_id, patch_request)
|
|
935
908
|
|
|
936
909
|
return format_scim_response(
|
|
937
910
|
success, result, f"Patch user {user_id}",
|
|
@@ -963,19 +936,14 @@ def scim_delete_user(args, configuration=None):
|
|
|
963
936
|
|
|
964
937
|
# Extract required path parameters
|
|
965
938
|
user_id = json_data.get('user_id') or json_data.get('id')
|
|
966
|
-
account_id = json_data.get('account_id')
|
|
967
|
-
source_id = json_data.get('source_id')
|
|
968
939
|
|
|
969
940
|
if not user_id:
|
|
970
941
|
return handle_scim_error("Missing required field: user_id (or id)", args.verbose)
|
|
971
|
-
if not account_id:
|
|
972
|
-
return handle_scim_error("Missing required field: account_id", args.verbose)
|
|
973
|
-
if not source_id:
|
|
974
|
-
return handle_scim_error("Missing required field: source_id", args.verbose)
|
|
975
942
|
|
|
976
943
|
# Get SCIM client and execute operation
|
|
944
|
+
# accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
977
945
|
client = get_scim_client(verbose=hasattr(args, 'verbose') and args.verbose)
|
|
978
|
-
success, result = client.delete_user(user_id
|
|
946
|
+
success, result = client.delete_user(user_id)
|
|
979
947
|
|
|
980
948
|
return format_scim_response(
|
|
981
949
|
success, result, f"Delete user {user_id}",
|
|
@@ -1007,18 +975,12 @@ def scim_patch_group(args, configuration=None):
|
|
|
1007
975
|
|
|
1008
976
|
# Extract required path parameters
|
|
1009
977
|
group_id = json_data.get('group_id') or json_data.get('id')
|
|
1010
|
-
account_id = json_data.get('account_id')
|
|
1011
|
-
source_id = json_data.get('source_id')
|
|
1012
978
|
|
|
1013
979
|
# Extract patch request data
|
|
1014
980
|
patch_data = json_data.get('patch_data', json_data)
|
|
1015
981
|
|
|
1016
982
|
if not group_id:
|
|
1017
983
|
return handle_scim_error("Missing required field: group_id (or id)", args.verbose)
|
|
1018
|
-
if not account_id:
|
|
1019
|
-
return handle_scim_error("Missing required field: account_id", args.verbose)
|
|
1020
|
-
if not source_id:
|
|
1021
|
-
return handle_scim_error("Missing required field: source_id", args.verbose)
|
|
1022
984
|
|
|
1023
985
|
# Build PatchRequestDTO according to swagger schema
|
|
1024
986
|
patch_request = {
|
|
@@ -1047,8 +1009,9 @@ def scim_patch_group(args, configuration=None):
|
|
|
1047
1009
|
return handle_scim_error(f"Operation {i+1}: Invalid operation '{op['op']}'. Must be 'add', 'remove', or 'replace'", args.verbose)
|
|
1048
1010
|
|
|
1049
1011
|
# Get SCIM client and execute operation
|
|
1012
|
+
# accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
1050
1013
|
client = get_scim_client(verbose=hasattr(args, 'verbose') and args.verbose)
|
|
1051
|
-
success, result = client.patch_group(group_id,
|
|
1014
|
+
success, result = client.patch_group(group_id, patch_request)
|
|
1052
1015
|
|
|
1053
1016
|
return format_scim_response(
|
|
1054
1017
|
success, result, f"Patch group {group_id}",
|
|
@@ -1080,19 +1043,14 @@ def scim_delete_group(args, configuration=None):
|
|
|
1080
1043
|
|
|
1081
1044
|
# Extract required path parameters
|
|
1082
1045
|
group_id = json_data.get('group_id') or json_data.get('id')
|
|
1083
|
-
account_id = json_data.get('account_id')
|
|
1084
|
-
source_id = json_data.get('source_id')
|
|
1085
1046
|
|
|
1086
1047
|
if not group_id:
|
|
1087
1048
|
return handle_scim_error("Missing required field: group_id (or id)", args.verbose)
|
|
1088
|
-
if not account_id:
|
|
1089
|
-
return handle_scim_error("Missing required field: account_id", args.verbose)
|
|
1090
|
-
if not source_id:
|
|
1091
|
-
return handle_scim_error("Missing required field: source_id", args.verbose)
|
|
1092
1049
|
|
|
1093
1050
|
# Get SCIM client and execute operation
|
|
1051
|
+
# accountId and sourceId are automatically extracted from the SCIM URL in credentials
|
|
1094
1052
|
client = get_scim_client(verbose=hasattr(args, 'verbose') and args.verbose)
|
|
1095
|
-
success, result = client.delete_group(group_id
|
|
1053
|
+
success, result = client.delete_group(group_id)
|
|
1096
1054
|
|
|
1097
1055
|
return format_scim_response(
|
|
1098
1056
|
success, result, f"Delete group {group_id}",
|
|
@@ -754,6 +754,13 @@ def get_help_enhanced(path):
|
|
|
754
754
|
doc = f"{path}/README.md"
|
|
755
755
|
abs_path = os.path.join(pwd, doc)
|
|
756
756
|
|
|
757
|
+
# If not found, try custom path (for commands like query_eventsFeed)
|
|
758
|
+
if not os.path.exists(abs_path):
|
|
759
|
+
custom_doc = f"custom/{path}/README.md"
|
|
760
|
+
custom_abs_path = os.path.join(pwd, custom_doc)
|
|
761
|
+
if os.path.exists(custom_abs_path):
|
|
762
|
+
abs_path = custom_abs_path
|
|
763
|
+
|
|
757
764
|
try:
|
|
758
765
|
with open(abs_path, "r", encoding='utf-8') as f:
|
|
759
766
|
content = f.read()
|
|
@@ -44,19 +44,19 @@ catocli query accountMetrics '{
|
|
|
44
44
|
The `timeFrame` parameter supports both relative time ranges and absolute date ranges:
|
|
45
45
|
|
|
46
46
|
**Relative Time Ranges:**
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
47
|
+
- "last.PT5M" = Previous 5 minutes
|
|
48
|
+
- "last.PT1H" = Previous 1 hour
|
|
49
|
+
- "last.P1D" = Previous 1 day
|
|
50
|
+
- "last.P14D" = Previous 14 days
|
|
51
|
+
- "last.P1M" = Previous 1 month
|
|
52
52
|
|
|
53
53
|
**Absolute Date Ranges:**
|
|
54
54
|
Format: `"utc.YYYY-MM-{DD/HH:MM:SS--DD/HH:MM:SS}"`
|
|
55
55
|
|
|
56
|
-
- Single day:
|
|
57
|
-
- Multiple days:
|
|
58
|
-
- Specific hours:
|
|
59
|
-
- Across months:
|
|
56
|
+
- Single day: "utc.2023-02-{28/00:00:00--28/23:59:59}"
|
|
57
|
+
- Multiple days: "utc.2023-02-{25/00:00:00--28/23:59:59}"
|
|
58
|
+
- Specific hours: "utc.2023-02-{28/09:00:00--28/17:00:00}"
|
|
59
|
+
- Across months: "utc.2023-{01-28/00:00:00--02-03/23:59:59}"
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
#### Operation Arguments for query.accountMetrics ####
|
|
@@ -115,19 +115,19 @@ catocli query appStats '{
|
|
|
115
115
|
The `timeFrame` parameter supports both relative time ranges and absolute date ranges:
|
|
116
116
|
|
|
117
117
|
**Relative Time Ranges:**
|
|
118
|
-
-
|
|
119
|
-
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
118
|
+
- "last.PT5M" = Previous 5 minutes
|
|
119
|
+
- "last.PT1H" = Previous 1 hour
|
|
120
|
+
- "last.P1D" = Previous 1 day
|
|
121
|
+
- "last.P14D" = Previous 14 days
|
|
122
|
+
- "last.P1M" = Previous 1 month
|
|
123
123
|
|
|
124
124
|
**Absolute Date Ranges:**
|
|
125
125
|
Format: `"utc.YYYY-MM-{DD/HH:MM:SS--DD/HH:MM:SS}"`
|
|
126
126
|
|
|
127
|
-
- Single day:
|
|
128
|
-
- Multiple days:
|
|
129
|
-
- Specific hours:
|
|
130
|
-
- Across months:
|
|
127
|
+
- Single day: "utc.2023-02-{28/00:00:00--28/23:59:59}"
|
|
128
|
+
- Multiple days: "utc.2023-02-{25/00:00:00--28/23:59:59}"
|
|
129
|
+
- Specific hours: "utc.2023-02-{28/09:00:00--28/17:00:00}"
|
|
130
|
+
- Across months: "utc.2023-{01-28/00:00:00--02-03/23:59:59}"
|
|
131
131
|
|
|
132
132
|
|
|
133
133
|
#### Operation Arguments for query.appStats ####
|
|
@@ -72,7 +72,7 @@ catocli query appStatsTimeSeries '{
|
|
|
72
72
|
"fieldName": "traffic"
|
|
73
73
|
}
|
|
74
74
|
],
|
|
75
|
-
"timeFrame": "last.
|
|
75
|
+
"timeFrame": "last.P1D"
|
|
76
76
|
}'
|
|
77
77
|
```
|
|
78
78
|
|
|
@@ -124,19 +124,19 @@ catocli query appStatsTimeSeries '{
|
|
|
124
124
|
The `timeFrame` parameter supports both relative time ranges and absolute date ranges:
|
|
125
125
|
|
|
126
126
|
**Relative Time Ranges:**
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
127
|
+
- "last.PT5M" = Previous 5 minutes
|
|
128
|
+
- "last.PT1H" = Previous 1 hour
|
|
129
|
+
- "last.P1D" = Previous 1 day
|
|
130
|
+
- "last.P14D" = Previous 14 days
|
|
131
|
+
- "last.P1M" = Previous 1 month
|
|
132
132
|
|
|
133
133
|
**Absolute Date Ranges:**
|
|
134
134
|
Format: `"utc.YYYY-MM-{DD/HH:MM:SS--DD/HH:MM:SS}"`
|
|
135
135
|
|
|
136
|
-
- Single day:
|
|
137
|
-
- Multiple days:
|
|
138
|
-
- Specific hours:
|
|
139
|
-
- Across months:
|
|
136
|
+
- Single day: "utc.2023-02-{28/00:00:00--28/23:59:59}"
|
|
137
|
+
- Multiple days: "utc.2023-02-{25/00:00:00--28/23:59:59}"
|
|
138
|
+
- Specific hours: "utc.2023-02-{28/09:00:00--28/17:00:00}"
|
|
139
|
+
- Across months: "utc.2023-{01-28/00:00:00--02-03/23:59:59}"
|
|
140
140
|
|
|
141
141
|
|
|
142
142
|
#### Operation Arguments for query.appStatsTimeSeries ####
|
|
@@ -40,19 +40,19 @@ catocli query auditFeed '{
|
|
|
40
40
|
The `timeFrame` parameter supports both relative time ranges and absolute date ranges:
|
|
41
41
|
|
|
42
42
|
**Relative Time Ranges:**
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
43
|
+
- "last.PT5M" = Previous 5 minutes
|
|
44
|
+
- "last.PT1H" = Previous 1 hour
|
|
45
|
+
- "last.P1D" = Previous 1 day
|
|
46
|
+
- "last.P14D" = Previous 14 days
|
|
47
|
+
- "last.P1M" = Previous 1 month
|
|
48
48
|
|
|
49
49
|
**Absolute Date Ranges:**
|
|
50
50
|
Format: `"utc.YYYY-MM-{DD/HH:MM:SS--DD/HH:MM:SS}"`
|
|
51
51
|
|
|
52
|
-
- Single day:
|
|
53
|
-
- Multiple days:
|
|
54
|
-
- Specific hours:
|
|
55
|
-
- Across months:
|
|
52
|
+
- Single day: "utc.2023-02-{28/00:00:00--28/23:59:59}"
|
|
53
|
+
- Multiple days: "utc.2023-02-{25/00:00:00--28/23:59:59}"
|
|
54
|
+
- Specific hours: "utc.2023-02-{28/09:00:00--28/17:00:00}"
|
|
55
|
+
- Across months: "utc.2023-{01-28/00:00:00--02-03/23:59:59}"
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
#### Operation Arguments for query.auditFeed ####
|
|
@@ -46,19 +46,19 @@ catocli query events '{
|
|
|
46
46
|
The `timeFrame` parameter supports both relative time ranges and absolute date ranges:
|
|
47
47
|
|
|
48
48
|
**Relative Time Ranges:**
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
49
|
+
- "last.PT5M" = Previous 5 minutes
|
|
50
|
+
- "last.PT1H" = Previous 1 hour
|
|
51
|
+
- "last.P1D" = Previous 1 day
|
|
52
|
+
- "last.P14D" = Previous 14 days
|
|
53
|
+
- "last.P1M" = Previous 1 month
|
|
54
54
|
|
|
55
55
|
**Absolute Date Ranges:**
|
|
56
56
|
Format: `"utc.YYYY-MM-{DD/HH:MM:SS--DD/HH:MM:SS}"`
|
|
57
57
|
|
|
58
|
-
- Single day:
|
|
59
|
-
- Multiple days:
|
|
60
|
-
- Specific hours:
|
|
61
|
-
- Across months:
|
|
58
|
+
- Single day: "utc.2023-02-{28/00:00:00--28/23:59:59}"
|
|
59
|
+
- Multiple days: "utc.2023-02-{25/00:00:00--28/23:59:59}"
|
|
60
|
+
- Specific hours: "utc.2023-02-{28/09:00:00--28/17:00:00}"
|
|
61
|
+
- Across months: "utc.2023-{01-28/00:00:00--02-03/23:59:59}"
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
#### Operation Arguments for query.events ####
|
|
@@ -44,19 +44,19 @@ catocli query eventsTimeSeries '{
|
|
|
44
44
|
The `timeFrame` parameter supports both relative time ranges and absolute date ranges:
|
|
45
45
|
|
|
46
46
|
**Relative Time Ranges:**
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
47
|
+
- "last.PT5M" = Previous 5 minutes
|
|
48
|
+
- "last.PT1H" = Previous 1 hour
|
|
49
|
+
- "last.P1D" = Previous 1 day
|
|
50
|
+
- "last.P14D" = Previous 14 days
|
|
51
|
+
- "last.P1M" = Previous 1 month
|
|
52
52
|
|
|
53
53
|
**Absolute Date Ranges:**
|
|
54
54
|
Format: `"utc.YYYY-MM-{DD/HH:MM:SS--DD/HH:MM:SS}"`
|
|
55
55
|
|
|
56
|
-
- Single day:
|
|
57
|
-
- Multiple days:
|
|
58
|
-
- Specific hours:
|
|
59
|
-
- Across months:
|
|
56
|
+
- Single day: "utc.2023-02-{28/00:00:00--28/23:59:59}"
|
|
57
|
+
- Multiple days: "utc.2023-02-{25/00:00:00--28/23:59:59}"
|
|
58
|
+
- Specific hours: "utc.2023-02-{28/09:00:00--28/17:00:00}"
|
|
59
|
+
- Across months: "utc.2023-{01-28/00:00:00--02-03/23:59:59}"
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
#### Operation Arguments for query.eventsTimeSeries ####
|