pltr-cli 0.4.0__py3-none-any.whl → 0.5.1__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.
- pltr/__init__.py +1 -1
- pltr/cli.py +22 -0
- pltr/commands/connectivity.py +432 -0
- pltr/commands/dataset.py +577 -0
- pltr/commands/mediasets.py +422 -0
- pltr/commands/orchestration.py +642 -0
- pltr/commands/project.py +440 -0
- pltr/commands/resource.py +499 -0
- pltr/commands/resource_role.py +454 -0
- pltr/commands/space.py +662 -0
- pltr/services/connectivity.py +305 -0
- pltr/services/dataset.py +603 -10
- pltr/services/mediasets.py +293 -0
- pltr/services/orchestration.py +457 -0
- pltr/services/project.py +232 -0
- pltr/services/resource.py +289 -0
- pltr/services/resource_role.py +321 -0
- pltr/services/space.py +354 -0
- pltr/utils/formatting.py +745 -0
- pltr_cli-0.5.1.dist-info/METADATA +513 -0
- {pltr_cli-0.4.0.dist-info → pltr_cli-0.5.1.dist-info}/RECORD +24 -12
- pltr/services/dataset_full.py +0 -302
- pltr/services/dataset_v2.py +0 -128
- pltr_cli-0.4.0.dist-info/METADATA +0 -287
- {pltr_cli-0.4.0.dist-info → pltr_cli-0.5.1.dist-info}/WHEEL +0 -0
- {pltr_cli-0.4.0.dist-info → pltr_cli-0.5.1.dist-info}/entry_points.txt +0 -0
- {pltr_cli-0.4.0.dist-info → pltr_cli-0.5.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Resource service wrapper for Foundry SDK filesystem API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional, Dict, List
|
|
6
|
+
|
|
7
|
+
from .base import BaseService
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ResourceService(BaseService):
|
|
11
|
+
"""Service wrapper for Foundry resource operations using filesystem API."""
|
|
12
|
+
|
|
13
|
+
def _get_service(self) -> Any:
|
|
14
|
+
"""Get the Foundry filesystem service."""
|
|
15
|
+
return self.client.filesystem
|
|
16
|
+
|
|
17
|
+
def get_resource(self, resource_rid: str) -> Dict[str, Any]:
|
|
18
|
+
"""
|
|
19
|
+
Get information about a specific resource.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
resource_rid: Resource Identifier
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Resource information dictionary
|
|
26
|
+
"""
|
|
27
|
+
try:
|
|
28
|
+
resource = self.service.Resource.get(resource_rid, preview=True)
|
|
29
|
+
return self._format_resource_info(resource)
|
|
30
|
+
except Exception as e:
|
|
31
|
+
raise RuntimeError(f"Failed to get resource {resource_rid}: {e}")
|
|
32
|
+
|
|
33
|
+
def list_resources(
|
|
34
|
+
self,
|
|
35
|
+
folder_rid: Optional[str] = None,
|
|
36
|
+
resource_type: Optional[str] = None,
|
|
37
|
+
page_size: Optional[int] = None,
|
|
38
|
+
page_token: Optional[str] = None,
|
|
39
|
+
) -> List[Dict[str, Any]]:
|
|
40
|
+
"""
|
|
41
|
+
List resources, optionally filtered by folder and type.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
folder_rid: Folder Resource Identifier to filter by (optional)
|
|
45
|
+
resource_type: Resource type to filter by (optional)
|
|
46
|
+
page_size: Number of items per page (optional)
|
|
47
|
+
page_token: Pagination token (optional)
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
List of resource information dictionaries
|
|
51
|
+
"""
|
|
52
|
+
try:
|
|
53
|
+
resources = []
|
|
54
|
+
list_params: Dict[str, Any] = {"preview": True}
|
|
55
|
+
|
|
56
|
+
if folder_rid:
|
|
57
|
+
list_params["folder_rid"] = folder_rid
|
|
58
|
+
if resource_type:
|
|
59
|
+
list_params["resource_type"] = resource_type
|
|
60
|
+
if page_size:
|
|
61
|
+
list_params["page_size"] = page_size
|
|
62
|
+
if page_token:
|
|
63
|
+
list_params["page_token"] = page_token
|
|
64
|
+
|
|
65
|
+
# The list method returns an iterator
|
|
66
|
+
for resource in self.service.Resource.list(**list_params):
|
|
67
|
+
resources.append(self._format_resource_info(resource))
|
|
68
|
+
return resources
|
|
69
|
+
except Exception as e:
|
|
70
|
+
raise RuntimeError(f"Failed to list resources: {e}")
|
|
71
|
+
|
|
72
|
+
def get_resources_batch(self, resource_rids: List[str]) -> List[Dict[str, Any]]:
|
|
73
|
+
"""
|
|
74
|
+
Get multiple resources in a single request.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
resource_rids: List of resource RIDs (max 1000)
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
List of resource information dictionaries
|
|
81
|
+
"""
|
|
82
|
+
if len(resource_rids) > 1000:
|
|
83
|
+
raise ValueError("Maximum batch size is 1000 resources")
|
|
84
|
+
|
|
85
|
+
try:
|
|
86
|
+
response = self.service.Resource.get_batch(body=resource_rids, preview=True)
|
|
87
|
+
resources = []
|
|
88
|
+
for resource in response.resources:
|
|
89
|
+
resources.append(self._format_resource_info(resource))
|
|
90
|
+
return resources
|
|
91
|
+
except Exception as e:
|
|
92
|
+
raise RuntimeError(f"Failed to get resources batch: {e}")
|
|
93
|
+
|
|
94
|
+
def get_resource_metadata(self, resource_rid: str) -> Dict[str, Any]:
|
|
95
|
+
"""
|
|
96
|
+
Get metadata for a specific resource.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
resource_rid: Resource Identifier
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
Resource metadata dictionary
|
|
103
|
+
"""
|
|
104
|
+
try:
|
|
105
|
+
metadata = self.service.Resource.get_metadata(resource_rid, preview=True)
|
|
106
|
+
return self._format_metadata(metadata)
|
|
107
|
+
except Exception as e:
|
|
108
|
+
raise RuntimeError(
|
|
109
|
+
f"Failed to get metadata for resource {resource_rid}: {e}"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
def set_resource_metadata(
|
|
113
|
+
self, resource_rid: str, metadata: Dict[str, Any]
|
|
114
|
+
) -> Dict[str, Any]:
|
|
115
|
+
"""
|
|
116
|
+
Set metadata for a specific resource.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
resource_rid: Resource Identifier
|
|
120
|
+
metadata: Metadata dictionary to set
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Updated resource metadata
|
|
124
|
+
"""
|
|
125
|
+
try:
|
|
126
|
+
updated_metadata = self.service.Resource.set_metadata(
|
|
127
|
+
resource_rid=resource_rid,
|
|
128
|
+
body=metadata,
|
|
129
|
+
preview=True,
|
|
130
|
+
)
|
|
131
|
+
return self._format_metadata(updated_metadata)
|
|
132
|
+
except Exception as e:
|
|
133
|
+
raise RuntimeError(
|
|
134
|
+
f"Failed to set metadata for resource {resource_rid}: {e}"
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
def delete_resource_metadata(self, resource_rid: str, keys: List[str]) -> None:
|
|
138
|
+
"""
|
|
139
|
+
Delete specific metadata keys for a resource.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
resource_rid: Resource Identifier
|
|
143
|
+
keys: List of metadata keys to delete
|
|
144
|
+
|
|
145
|
+
Raises:
|
|
146
|
+
RuntimeError: If deletion fails
|
|
147
|
+
"""
|
|
148
|
+
try:
|
|
149
|
+
self.service.Resource.delete_metadata(
|
|
150
|
+
resource_rid=resource_rid,
|
|
151
|
+
body={"keys": keys},
|
|
152
|
+
preview=True,
|
|
153
|
+
)
|
|
154
|
+
except Exception as e:
|
|
155
|
+
raise RuntimeError(
|
|
156
|
+
f"Failed to delete metadata for resource {resource_rid}: {e}"
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
def move_resource(
|
|
160
|
+
self, resource_rid: str, target_folder_rid: str
|
|
161
|
+
) -> Dict[str, Any]:
|
|
162
|
+
"""
|
|
163
|
+
Move a resource to a different folder.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
resource_rid: Resource Identifier
|
|
167
|
+
target_folder_rid: Target folder Resource Identifier
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Updated resource information
|
|
171
|
+
"""
|
|
172
|
+
try:
|
|
173
|
+
resource = self.service.Resource.move(
|
|
174
|
+
resource_rid=resource_rid,
|
|
175
|
+
body={"target_folder_rid": target_folder_rid},
|
|
176
|
+
preview=True,
|
|
177
|
+
)
|
|
178
|
+
return self._format_resource_info(resource)
|
|
179
|
+
except Exception as e:
|
|
180
|
+
raise RuntimeError(f"Failed to move resource {resource_rid}: {e}")
|
|
181
|
+
|
|
182
|
+
def search_resources(
|
|
183
|
+
self,
|
|
184
|
+
query: str,
|
|
185
|
+
resource_type: Optional[str] = None,
|
|
186
|
+
folder_rid: Optional[str] = None,
|
|
187
|
+
page_size: Optional[int] = None,
|
|
188
|
+
page_token: Optional[str] = None,
|
|
189
|
+
) -> List[Dict[str, Any]]:
|
|
190
|
+
"""
|
|
191
|
+
Search for resources by query string.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
query: Search query string
|
|
195
|
+
resource_type: Resource type to filter by (optional)
|
|
196
|
+
folder_rid: Folder to search within (optional)
|
|
197
|
+
page_size: Number of items per page (optional)
|
|
198
|
+
page_token: Pagination token (optional)
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
List of matching resource information dictionaries
|
|
202
|
+
"""
|
|
203
|
+
try:
|
|
204
|
+
resources = []
|
|
205
|
+
search_params: Dict[str, Any] = {
|
|
206
|
+
"query": query,
|
|
207
|
+
"preview": True,
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if resource_type:
|
|
211
|
+
search_params["resource_type"] = resource_type
|
|
212
|
+
if folder_rid:
|
|
213
|
+
search_params["folder_rid"] = folder_rid
|
|
214
|
+
if page_size:
|
|
215
|
+
search_params["page_size"] = page_size
|
|
216
|
+
if page_token:
|
|
217
|
+
search_params["page_token"] = page_token
|
|
218
|
+
|
|
219
|
+
# The search method returns an iterator
|
|
220
|
+
for resource in self.service.Resource.search(**search_params):
|
|
221
|
+
resources.append(self._format_resource_info(resource))
|
|
222
|
+
return resources
|
|
223
|
+
except Exception as e:
|
|
224
|
+
raise RuntimeError(f"Failed to search resources: {e}")
|
|
225
|
+
|
|
226
|
+
def _format_resource_info(self, resource: Any) -> Dict[str, Any]:
|
|
227
|
+
"""
|
|
228
|
+
Format resource information for consistent output.
|
|
229
|
+
|
|
230
|
+
Args:
|
|
231
|
+
resource: Resource object from Foundry SDK
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
Formatted resource information dictionary
|
|
235
|
+
"""
|
|
236
|
+
return {
|
|
237
|
+
"rid": getattr(resource, "rid", None),
|
|
238
|
+
"display_name": getattr(resource, "display_name", None),
|
|
239
|
+
"name": getattr(resource, "name", None),
|
|
240
|
+
"description": getattr(resource, "description", None),
|
|
241
|
+
"path": getattr(resource, "path", None),
|
|
242
|
+
"type": getattr(resource, "type", None),
|
|
243
|
+
"folder_rid": getattr(resource, "folder_rid", None),
|
|
244
|
+
"created_by": getattr(resource, "created_by", None),
|
|
245
|
+
"created_time": self._format_timestamp(
|
|
246
|
+
getattr(resource, "created_time", None)
|
|
247
|
+
),
|
|
248
|
+
"modified_by": getattr(resource, "modified_by", None),
|
|
249
|
+
"modified_time": self._format_timestamp(
|
|
250
|
+
getattr(resource, "modified_time", None)
|
|
251
|
+
),
|
|
252
|
+
"size_bytes": getattr(resource, "size_bytes", None),
|
|
253
|
+
"trash_status": getattr(resource, "trash_status", None),
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
def _format_metadata(self, metadata: Any) -> Dict[str, Any]:
|
|
257
|
+
"""
|
|
258
|
+
Format metadata for consistent output.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
metadata: Metadata object from Foundry SDK
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
Formatted metadata dictionary
|
|
265
|
+
"""
|
|
266
|
+
if hasattr(metadata, "__dict__"):
|
|
267
|
+
return dict(metadata.__dict__)
|
|
268
|
+
elif isinstance(metadata, dict):
|
|
269
|
+
return metadata
|
|
270
|
+
else:
|
|
271
|
+
return {"raw": str(metadata)}
|
|
272
|
+
|
|
273
|
+
def _format_timestamp(self, timestamp: Any) -> Optional[str]:
|
|
274
|
+
"""
|
|
275
|
+
Format timestamp for display.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
timestamp: Timestamp object from SDK
|
|
279
|
+
|
|
280
|
+
Returns:
|
|
281
|
+
Formatted timestamp string or None
|
|
282
|
+
"""
|
|
283
|
+
if timestamp is None:
|
|
284
|
+
return None
|
|
285
|
+
|
|
286
|
+
# Handle different timestamp formats from the SDK
|
|
287
|
+
if hasattr(timestamp, "time"):
|
|
288
|
+
return str(timestamp.time)
|
|
289
|
+
return str(timestamp)
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Resource Role service wrapper for Foundry SDK filesystem API.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional, Dict, List
|
|
6
|
+
|
|
7
|
+
from .base import BaseService
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class ResourceRoleService(BaseService):
|
|
11
|
+
"""Service wrapper for Foundry resource role operations using filesystem API."""
|
|
12
|
+
|
|
13
|
+
def _get_service(self) -> Any:
|
|
14
|
+
"""Get the Foundry filesystem service."""
|
|
15
|
+
return self.client.filesystem
|
|
16
|
+
|
|
17
|
+
def grant_role(
|
|
18
|
+
self,
|
|
19
|
+
resource_rid: str,
|
|
20
|
+
principal_id: str,
|
|
21
|
+
principal_type: str,
|
|
22
|
+
role_name: str,
|
|
23
|
+
) -> Dict[str, Any]:
|
|
24
|
+
"""
|
|
25
|
+
Grant a role to a principal on a resource.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
resource_rid: Resource Identifier
|
|
29
|
+
principal_id: Principal (user/group) identifier
|
|
30
|
+
principal_type: Principal type ('User' or 'Group')
|
|
31
|
+
role_name: Role name to grant
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Role grant information
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
role_grant: Dict[str, Any] = {
|
|
38
|
+
"principal_id": principal_id,
|
|
39
|
+
"principal_type": principal_type,
|
|
40
|
+
"role_name": role_name,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
result = self.service.ResourceRole.grant(
|
|
44
|
+
resource_rid=resource_rid,
|
|
45
|
+
body=role_grant,
|
|
46
|
+
preview=True,
|
|
47
|
+
)
|
|
48
|
+
return self._format_role_grant(result)
|
|
49
|
+
except Exception as e:
|
|
50
|
+
raise RuntimeError(
|
|
51
|
+
f"Failed to grant role '{role_name}' to {principal_type} '{principal_id}' on resource {resource_rid}: {e}"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def revoke_role(
|
|
55
|
+
self,
|
|
56
|
+
resource_rid: str,
|
|
57
|
+
principal_id: str,
|
|
58
|
+
principal_type: str,
|
|
59
|
+
role_name: str,
|
|
60
|
+
) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Revoke a role from a principal on a resource.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
resource_rid: Resource Identifier
|
|
66
|
+
principal_id: Principal (user/group) identifier
|
|
67
|
+
principal_type: Principal type ('User' or 'Group')
|
|
68
|
+
role_name: Role name to revoke
|
|
69
|
+
|
|
70
|
+
Raises:
|
|
71
|
+
RuntimeError: If revocation fails
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
role_revocation: Dict[str, Any] = {
|
|
75
|
+
"principal_id": principal_id,
|
|
76
|
+
"principal_type": principal_type,
|
|
77
|
+
"role_name": role_name,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
self.service.ResourceRole.revoke(
|
|
81
|
+
resource_rid=resource_rid,
|
|
82
|
+
body=role_revocation,
|
|
83
|
+
preview=True,
|
|
84
|
+
)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
raise RuntimeError(
|
|
87
|
+
f"Failed to revoke role '{role_name}' from {principal_type} '{principal_id}' on resource {resource_rid}: {e}"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def list_resource_roles(
|
|
91
|
+
self,
|
|
92
|
+
resource_rid: str,
|
|
93
|
+
principal_type: Optional[str] = None,
|
|
94
|
+
page_size: Optional[int] = None,
|
|
95
|
+
page_token: Optional[str] = None,
|
|
96
|
+
) -> List[Dict[str, Any]]:
|
|
97
|
+
"""
|
|
98
|
+
List all roles granted on a resource.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
resource_rid: Resource Identifier
|
|
102
|
+
principal_type: Filter by principal type ('User' or 'Group', optional)
|
|
103
|
+
page_size: Number of items per page (optional)
|
|
104
|
+
page_token: Pagination token (optional)
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
List of role grant information dictionaries
|
|
108
|
+
"""
|
|
109
|
+
try:
|
|
110
|
+
role_grants = []
|
|
111
|
+
list_params: Dict[str, Any] = {"preview": True}
|
|
112
|
+
|
|
113
|
+
if principal_type:
|
|
114
|
+
list_params["principal_type"] = principal_type
|
|
115
|
+
if page_size:
|
|
116
|
+
list_params["page_size"] = page_size
|
|
117
|
+
if page_token:
|
|
118
|
+
list_params["page_token"] = page_token
|
|
119
|
+
|
|
120
|
+
# The list method returns an iterator
|
|
121
|
+
for role_grant in self.service.ResourceRole.list(
|
|
122
|
+
resource_rid, **list_params
|
|
123
|
+
):
|
|
124
|
+
role_grants.append(self._format_role_grant(role_grant))
|
|
125
|
+
return role_grants
|
|
126
|
+
except Exception as e:
|
|
127
|
+
raise RuntimeError(f"Failed to list roles for resource {resource_rid}: {e}")
|
|
128
|
+
|
|
129
|
+
def get_principal_roles(
|
|
130
|
+
self,
|
|
131
|
+
principal_id: str,
|
|
132
|
+
principal_type: str,
|
|
133
|
+
resource_rid: Optional[str] = None,
|
|
134
|
+
page_size: Optional[int] = None,
|
|
135
|
+
page_token: Optional[str] = None,
|
|
136
|
+
) -> List[Dict[str, Any]]:
|
|
137
|
+
"""
|
|
138
|
+
Get all roles granted to a principal, optionally filtered by resource.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
principal_id: Principal (user/group) identifier
|
|
142
|
+
principal_type: Principal type ('User' or 'Group')
|
|
143
|
+
resource_rid: Filter by resource RID (optional)
|
|
144
|
+
page_size: Number of items per page (optional)
|
|
145
|
+
page_token: Pagination token (optional)
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
List of role grant information dictionaries
|
|
149
|
+
"""
|
|
150
|
+
try:
|
|
151
|
+
role_grants = []
|
|
152
|
+
list_params = {
|
|
153
|
+
"principal_id": principal_id,
|
|
154
|
+
"principal_type": principal_type,
|
|
155
|
+
"preview": True,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if resource_rid:
|
|
159
|
+
list_params["resource_rid"] = resource_rid
|
|
160
|
+
if page_size:
|
|
161
|
+
list_params["page_size"] = page_size
|
|
162
|
+
if page_token:
|
|
163
|
+
list_params["page_token"] = page_token
|
|
164
|
+
|
|
165
|
+
# The get_principal_roles method returns an iterator
|
|
166
|
+
for role_grant in self.service.ResourceRole.get_principal_roles(
|
|
167
|
+
**list_params
|
|
168
|
+
):
|
|
169
|
+
role_grants.append(self._format_role_grant(role_grant))
|
|
170
|
+
return role_grants
|
|
171
|
+
except Exception as e:
|
|
172
|
+
raise RuntimeError(
|
|
173
|
+
f"Failed to get roles for {principal_type} '{principal_id}': {e}"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
def bulk_grant_roles(
|
|
177
|
+
self,
|
|
178
|
+
resource_rid: str,
|
|
179
|
+
role_grants: List[Dict[str, str]],
|
|
180
|
+
) -> List[Dict[str, Any]]:
|
|
181
|
+
"""
|
|
182
|
+
Grant multiple roles in a single request.
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
resource_rid: Resource Identifier
|
|
186
|
+
role_grants: List of role grant specifications, each containing:
|
|
187
|
+
- principal_id: Principal identifier
|
|
188
|
+
- principal_type: 'User' or 'Group'
|
|
189
|
+
- role_name: Role name to grant
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
List of granted role information dictionaries
|
|
193
|
+
"""
|
|
194
|
+
try:
|
|
195
|
+
result = self.service.ResourceRole.bulk_grant(
|
|
196
|
+
resource_rid=resource_rid,
|
|
197
|
+
body={"role_grants": role_grants},
|
|
198
|
+
preview=True,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
granted_roles = []
|
|
202
|
+
if hasattr(result, "role_grants"):
|
|
203
|
+
for role_grant in result.role_grants:
|
|
204
|
+
granted_roles.append(self._format_role_grant(role_grant))
|
|
205
|
+
|
|
206
|
+
return granted_roles
|
|
207
|
+
except Exception as e:
|
|
208
|
+
raise RuntimeError(
|
|
209
|
+
f"Failed to bulk grant roles on resource {resource_rid}: {e}"
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def bulk_revoke_roles(
|
|
213
|
+
self,
|
|
214
|
+
resource_rid: str,
|
|
215
|
+
role_revocations: List[Dict[str, str]],
|
|
216
|
+
) -> None:
|
|
217
|
+
"""
|
|
218
|
+
Revoke multiple roles in a single request.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
resource_rid: Resource Identifier
|
|
222
|
+
role_revocations: List of role revocation specifications, each containing:
|
|
223
|
+
- principal_id: Principal identifier
|
|
224
|
+
- principal_type: 'User' or 'Group'
|
|
225
|
+
- role_name: Role name to revoke
|
|
226
|
+
|
|
227
|
+
Raises:
|
|
228
|
+
RuntimeError: If revocation fails
|
|
229
|
+
"""
|
|
230
|
+
try:
|
|
231
|
+
self.service.ResourceRole.bulk_revoke(
|
|
232
|
+
resource_rid=resource_rid,
|
|
233
|
+
body={"role_revocations": role_revocations},
|
|
234
|
+
preview=True,
|
|
235
|
+
)
|
|
236
|
+
except Exception as e:
|
|
237
|
+
raise RuntimeError(
|
|
238
|
+
f"Failed to bulk revoke roles on resource {resource_rid}: {e}"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def get_available_roles(self, resource_rid: str) -> List[Dict[str, Any]]:
|
|
242
|
+
"""
|
|
243
|
+
Get all available roles for a resource type.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
resource_rid: Resource Identifier
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
List of available role information dictionaries
|
|
250
|
+
"""
|
|
251
|
+
try:
|
|
252
|
+
roles = []
|
|
253
|
+
for role in self.service.ResourceRole.get_available_roles(
|
|
254
|
+
resource_rid, preview=True
|
|
255
|
+
):
|
|
256
|
+
roles.append(self._format_role_info(role))
|
|
257
|
+
return roles
|
|
258
|
+
except Exception as e:
|
|
259
|
+
raise RuntimeError(
|
|
260
|
+
f"Failed to get available roles for resource {resource_rid}: {e}"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
def _format_role_grant(self, role_grant: Any) -> Dict[str, Any]:
|
|
264
|
+
"""
|
|
265
|
+
Format role grant information for consistent output.
|
|
266
|
+
|
|
267
|
+
Args:
|
|
268
|
+
role_grant: Role grant object from Foundry SDK
|
|
269
|
+
|
|
270
|
+
Returns:
|
|
271
|
+
Formatted role grant information dictionary
|
|
272
|
+
"""
|
|
273
|
+
return {
|
|
274
|
+
"resource_rid": getattr(role_grant, "resource_rid", None),
|
|
275
|
+
"principal_id": getattr(role_grant, "principal_id", None),
|
|
276
|
+
"principal_type": getattr(role_grant, "principal_type", None),
|
|
277
|
+
"role_name": getattr(role_grant, "role_name", None),
|
|
278
|
+
"granted_by": getattr(role_grant, "granted_by", None),
|
|
279
|
+
"granted_time": self._format_timestamp(
|
|
280
|
+
getattr(role_grant, "granted_time", None)
|
|
281
|
+
),
|
|
282
|
+
"expires_at": self._format_timestamp(
|
|
283
|
+
getattr(role_grant, "expires_at", None)
|
|
284
|
+
),
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
def _format_role_info(self, role: Any) -> Dict[str, Any]:
|
|
288
|
+
"""
|
|
289
|
+
Format role information for consistent output.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
role: Role object from Foundry SDK
|
|
293
|
+
|
|
294
|
+
Returns:
|
|
295
|
+
Formatted role information dictionary
|
|
296
|
+
"""
|
|
297
|
+
return {
|
|
298
|
+
"name": getattr(role, "name", None),
|
|
299
|
+
"display_name": getattr(role, "display_name", None),
|
|
300
|
+
"description": getattr(role, "description", None),
|
|
301
|
+
"permissions": getattr(role, "permissions", []),
|
|
302
|
+
"is_owner_like": getattr(role, "is_owner_like", False),
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
def _format_timestamp(self, timestamp: Any) -> Optional[str]:
|
|
306
|
+
"""
|
|
307
|
+
Format timestamp for display.
|
|
308
|
+
|
|
309
|
+
Args:
|
|
310
|
+
timestamp: Timestamp object from SDK
|
|
311
|
+
|
|
312
|
+
Returns:
|
|
313
|
+
Formatted timestamp string or None
|
|
314
|
+
"""
|
|
315
|
+
if timestamp is None:
|
|
316
|
+
return None
|
|
317
|
+
|
|
318
|
+
# Handle different timestamp formats from the SDK
|
|
319
|
+
if hasattr(timestamp, "time"):
|
|
320
|
+
return str(timestamp.time)
|
|
321
|
+
return str(timestamp)
|