Skip to content

Commit 5a884b3

Browse files
Merge pull request #2403 from solliancenet/cj-fix-authorization-097-beta1352
Fix issue with role assignment deletion
2 parents 2c344e1 + e3a33a4 commit 5a884b3

File tree

19 files changed

+369
-36
lines changed

19 files changed

+369
-36
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,3 +403,4 @@ dist
403403
**/foundationallm-certificates.SecretProviderClass.json
404404
**/foundationallm_external_modules**
405405
certs.zip
406+
/samples/python/.env

samples/python/.env.example

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# This file is an example of the .env file that should be created in the same directory as this file.
2+
MANAGEMENT_API_SCOPE = "MANAGEMENT_API_CLIENT_ID/.default" # Replace MANAGEMENT_API_CLIENT_ID with the actual client ID of the Management API application.
3+
MANAGEMENT_API_ENDPOINT = "https://..." # Replace with the actual endpoint of the Management API application.
4+
5+
CORE_API_SCOPE = "CORE_API_CLIENT_ID/.default" # Replace CORE_API_CLIENT_ID with the actual client ID of the Core API application.
6+
CORE_API_ENDPOINT = "https://..." # Replace with the actual endpoint of the Core API application.
7+
8+
FOUNDATIONALLM_INSTANCE_ID = "FOUNDATIONALLM_INSTANCE_ID" # Replace FOUNDATIONALLM_INSTANCE_ID with the actual FoundationaLLM instance identifier.

samples/python/clients/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from .core_client import CoreClient
2+
from .management_client import ManagementClient\

samples/python/clients/api_client.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
'''
2+
Generic API client for FoundationLLM.
3+
This client is used to interact with the FoundationLLM APIs.
4+
'''
5+
6+
from urllib.parse import urlparse
7+
8+
import requests
9+
from simple_jwt import jwt
10+
11+
from azure.identity import AzureCliCredential
12+
13+
class APIClient:
14+
'''
15+
Generic API client for FoundationLLM.
16+
This client is used to interact with the FoundationLLM APIs.
17+
'''
18+
19+
def __init__(
20+
self,
21+
api_scope: str,
22+
api_endpoint: str,
23+
foundationallm_instance_id: str):
24+
25+
self.__api_scope = api_scope
26+
self.__api_endpoint = api_endpoint
27+
self.__foundationallm_instance_id = foundationallm_instance_id
28+
29+
self.__verify_ssl = (urlparse(api_endpoint.lower()).hostname != "localhost")
30+
31+
self.__credential = AzureCliCredential()
32+
self.__token = self.__credential.get_token(self.__api_scope).token
33+
34+
def __ensure_valid_token(self):
35+
'''
36+
Ensure that the token is valid.
37+
If the token is expired, get a new one.
38+
'''
39+
if not self.__token:
40+
self.__token = self.__credential.get_token(self.__api_scope).token
41+
42+
if jwt.is_expired(self.__token):
43+
self.__token = self.__credential.get_token(self.__api_scope).token
44+
45+
def post_request(
46+
self,
47+
route: str,
48+
data: dict,
49+
include_instance: bool = True) -> dict:
50+
'''
51+
Post a request to the API.
52+
- param data: The data to post.
53+
- param route: The route to post to.
54+
- param include_instance: Whether to include the instance ID in the route.
55+
56+
Return: The response from the API.
57+
'''
58+
self.__ensure_valid_token()
59+
60+
headers = {
61+
"Authorization": f"Bearer {self.__token}",
62+
"Content-Type": "application/json"
63+
}
64+
65+
response = requests.post(
66+
f"{self.__api_endpoint}/instances/{self.__foundationallm_instance_id}/{route}" if include_instance \
67+
else f"{self.__api_endpoint}/{route}",
68+
headers=headers,
69+
json=data,
70+
timeout=60,
71+
verify=self.__verify_ssl
72+
)
73+
74+
response.raise_for_status()
75+
76+
return response.json()
77+
78+
def get_request(
79+
self,
80+
route:str,
81+
include_instance: bool = True) -> dict:
82+
'''
83+
Post a request to the API.
84+
- param route: The route to post to.
85+
- param include_instance: Whether to include the instance ID in the route.
86+
87+
Return: The response from the API.
88+
'''
89+
self.__ensure_valid_token()
90+
91+
headers = {
92+
"Authorization": f"Bearer {self.__token}"
93+
}
94+
95+
response = requests.get(
96+
f"{self.__api_endpoint}/instances/{self.__foundationallm_instance_id}/{route}" if include_instance \
97+
else f"{self.__api_endpoint}/{route}",
98+
headers=headers,
99+
timeout=60,
100+
verify=self.__verify_ssl
101+
)
102+
103+
response.raise_for_status()
104+
105+
return response.json()

samples/python/clients/core_client.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
'''
2+
Core API client for FoundationLLM.
3+
This client is used to interact with the FoundationLLM Core API.
4+
'''
5+
6+
from .api_client import APIClient
7+
8+
class CoreClient(APIClient):
9+
'''
10+
Core API client for FoundationLLM.
11+
This client is used to interact with the FoundationLLM Core API.
12+
'''
13+
14+
def get_agents(self) -> dict:
15+
'''
16+
Retrieves the list of agents.
17+
'''
18+
19+
result = self.get_request(
20+
"completions/agents"
21+
)
22+
23+
return result
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
'''
2+
Management API client for FoundationLLM.
3+
This client is used to interact with the FoundationLLM Management API.
4+
'''
5+
6+
from .api_client import APIClient
7+
8+
class ManagementClient(APIClient):
9+
'''
10+
Management API client for FoundationLLM.
11+
This client is used to interact with the FoundationLLM Management API.
12+
'''
13+
14+
def __init__(
15+
self,
16+
api_scope: str,
17+
api_endpoint: str,
18+
foundationallm_instance_id: str):
19+
20+
super().__init__(
21+
api_scope,
22+
api_endpoint,
23+
foundationallm_instance_id
24+
)
25+
26+
self.default_text_partitioning_profile = "text_partition_default"
27+
self.default_text_embedding_profile = "text_embedding_profile_gateway_embedding3large"
28+
29+
# region: Agents
30+
31+
# region: Agent workflows
32+
33+
def get_agent_workflows(self) -> dict:
34+
'''
35+
Retrieves the list of agent workflows.
36+
'''
37+
38+
result = self.get_request(
39+
"providers/FoundationaLLM.Agent/workflows"
40+
)
41+
42+
return result
43+
44+
# endregion
45+
46+
# endregion
47+
48+
# region: Vectorization pipelines
49+
50+
def create_vectorization_pipeline(
51+
self,
52+
pipeline_name: str,
53+
pipeline_description: str,
54+
data_source_name: str,
55+
vector_store_name: str
56+
) -> dict:
57+
'''
58+
Creates a vectorization pipeline.
59+
- pipeline_name: The name of the pipeline.
60+
- pipeline_description: The description of the pipeline.
61+
- data_source_name: The name of the data source.
62+
- vector_store_name: The name of the vector store.
63+
'''
64+
65+
result = self.post_request(
66+
f"providers/FoundationaLLM.Vectorization/vectorizationPipelines/{pipeline_name}",
67+
{
68+
"name": pipeline_name,
69+
"description": pipeline_description,
70+
"data_source_object_id": f"/instances/{self.__foundationallm_instance_id}/providers/FoundationaLLM.DataSource/dataSources/{data_source_name}",
71+
"text_partitioning_profile_object_id": f"/instances/{self.__foundationallm_instance_id}/providers/FoundationaLLM.Vectorization/textPartitioningProfiles/{self.default_text_partitioning_profile}",
72+
"text_embedding_profile_object_id": f"/instances/{self.__foundationallm_instance_id}/providers/FoundationaLLM.Vectorization/textEmbeddingProfiles/{self.default_text_embedding_profile}",
73+
"indexing_profile_object_id": f"/instances/{self.__foundationallm_instance_id}/providers/FoundationaLLM.Vectorization/indexingProfiles/{vector_store_name}",
74+
"trigger_type": "Manual"
75+
}
76+
)
77+
78+
return result
79+
80+
def get_vectorization_pipeline(
81+
self,
82+
pipeline_name: str
83+
) -> dict:
84+
'''
85+
Retrieves a vectorization pipeline.
86+
- pipeline_name: The name of the pipeline.
87+
'''
88+
89+
result = self.get_request(
90+
f"providers/FoundationaLLM.Vectorization/vectorizationPipelines/{pipeline_name}"
91+
)
92+
93+
return result
94+
95+
def activate_vectorization_pipeline(
96+
self,
97+
pipeline_name: str
98+
) -> dict:
99+
'''
100+
Activates a vectorization pipeline.
101+
- pipeline_name: The name of the pipeline.
102+
'''
103+
104+
result = self.post_request(
105+
f"providers/FoundationaLLM.Vectorization/vectorizationPipelines/{pipeline_name}/activate",
106+
{}
107+
)
108+
109+
return result
110+
111+
def get_vectorization_pipeline_execution(
112+
self,
113+
pipeline_name: str,
114+
execution_id: str
115+
) -> dict:
116+
'''
117+
Retrieves a vectorization pipeline execution.
118+
- pipeline_name: The name of the pipeline.
119+
- execution_id: The ID of the execution.
120+
'''
121+
122+
result = self.get_request(
123+
f"providers/FoundationaLLM.Vectorization/vectorizationPipelines/{pipeline_name}/vectorizationPipelineExecutions/{execution_id}"
124+
)
125+
126+
return result
127+
128+
# endregion

samples/python/core_agents.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'''
2+
This samepl shows how to retrieve the list of agents available to the user.
3+
'''
4+
5+
import os
6+
from dotenv import load_dotenv
7+
8+
from clients import CoreClient
9+
10+
# Load environment variables from .env file
11+
load_dotenv()
12+
13+
core_client = CoreClient(
14+
os.getenv("CORE_API_SCOPE"),
15+
os.getenv("CORE_API_ENDPOINT"),
16+
os.getenv("FOUNDATIONALLM_INSTANCE_ID")
17+
)
18+
19+
result = core_client.get_agents()
20+
21+
print(result)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'''
2+
This sample shows how to retrieve the list of agent workflows.
3+
'''
4+
5+
import os
6+
from dotenv import load_dotenv
7+
8+
from clients import ManagementClient
9+
10+
# Load environment variables from .env file
11+
load_dotenv()
12+
13+
management_client = ManagementClient(
14+
os.getenv("MANAGEMENT_API_SCOPE"),
15+
os.getenv("MANAGEMENT_API_ENDPOINT"),
16+
os.getenv("FOUNDATIONALLM_INSTANCE_ID")
17+
)
18+
19+
result = management_client.get_agent_workflows()
20+
21+
print(result)

src/dotnet/Agent/ResourceProviders/AgentResourceProviderService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ private async Task<ResourceProviderUpsertResult> UpdateAgent(
435435
var roleAssignmentDescription = $"Reader role for the {agent.Name} agent's virtual security group";
436436
var roleAssignmentResult = await _authorizationServiceClient.CreateRoleAssignment(
437437
_instanceSettings.Id,
438-
new RoleAssignmentRequest()
438+
new RoleAssignmentCreateRequest()
439439
{
440440
Name = roleAssignmentName,
441441
Description = roleAssignmentDescription,
@@ -458,7 +458,7 @@ private async Task<ResourceProviderUpsertResult> UpdateAgent(
458458
roleAssignmentName = Guid.NewGuid().ToString();
459459
roleAssignmentResult = await _authorizationServiceClient.CreateRoleAssignment(
460460
_instanceSettings.Id,
461-
new RoleAssignmentRequest()
461+
new RoleAssignmentCreateRequest()
462462
{
463463
Name = roleAssignmentName,
464464
Description = roleAssignmentDescription,

src/dotnet/Authorization/ResourceProviders/AuthorizationResourceProviderService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ private async Task<ResourceProviderUpsertResult> UpdateRoleAssignments(ResourceP
128128

129129
var roleAssignmentResult = await _authorizationServiceClient.CreateRoleAssignment(
130130
_instanceSettings.Id,
131-
new RoleAssignmentRequest()
131+
new RoleAssignmentCreateRequest()
132132
{
133133
Name = roleAssignment.Name,
134134
Description = roleAssignment.Description,

src/dotnet/AuthorizationAPI/Controllers/RoleAssignmentsController.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,21 @@ public IActionResult GetRoleAssignments(string instanceId, [FromBody] RoleAssign
3535
/// Assigns a role to an Entra ID user or group.
3636
/// </summary>
3737
/// <param name="instanceId">The FoundationaLLM instance identifier.</param>
38-
/// <param name="roleAssignmentRequest">The role assignment request.</param>
38+
/// <param name="roleAssignmentCreateRequest">The role assignment create request.</param>
3939
/// <returns>The role assignment result.</returns>
4040
[HttpPost]
41-
public async Task<IActionResult> AssignRole(string instanceId, RoleAssignmentRequest roleAssignmentRequest) =>
42-
new OkObjectResult(await _authorizationCore.CreateRoleAssignment(instanceId, roleAssignmentRequest));
41+
public async Task<IActionResult> AssignRole(string instanceId, RoleAssignmentCreateRequest roleAssignmentCreateRequest) =>
42+
new OkObjectResult(await _authorizationCore.CreateRoleAssignment(instanceId, roleAssignmentCreateRequest));
4343

4444
/// <summary>
4545
/// Revokes a role from an Entra ID user or group.
4646
/// </summary>
4747
/// <param name="instanceId">The FoundationaLLM instance identifier.</param>
48-
/// <param name="roleAssignment">The role assignment object identifier.</param>
48+
/// <param name="roleAssignmentName">The role assignment object identifier.</param>
4949
/// <returns>The role assignment result.</returns>
50-
[HttpDelete("{*roleAssignment}")]
51-
public async Task<IActionResult> RevokeRoleAssignment(string instanceId, string roleAssignment) =>
52-
new OkObjectResult(await _authorizationCore.DeleteRoleAssignment(instanceId, roleAssignment));
50+
[HttpDelete("{*roleAssignmentName}")]
51+
public async Task<IActionResult> RevokeRoleAssignment(string instanceId, string roleAssignmentName) =>
52+
new OkObjectResult(await _authorizationCore.DeleteRoleAssignment(instanceId, roleAssignmentName));
5353

5454
#endregion
5555
}

0 commit comments

Comments
 (0)