Skip to content

Commit 163562f

Browse files
feat: updated scripts to run manually, added azd template and devcontainer setup (#490)
* updated post deployment scripts such that it can be run via container as well manually * updated main.json * add scripts for Cosmos DB access and process sample data * correct variable assignment for extraction paths in copy_kb_files.sh * correct variable usage for extraction paths in copy_kb_files.sh * correct extraction path variable names in copy_kb_files.sh * improve virtual environment activation handling for cross-platform compatibility * add create_sql_user_and_role.sh script and integrate it into process_sample_data.sh * refactor process_sample_data.sh to improve parameter retrieval and usage validation * add devcontainer configuration, update azure.yaml, and enhance SQL user creation script * moved sqlcmd_setup.sh * refactor devcontainer setup: replace sqlcmd_setup.sh with setup_env.sh for improved environment configuration * remove .vscode from .gitignore * updated main.json
1 parent d2a957a commit 163562f

File tree

12 files changed

+666
-76
lines changed

12 files changed

+666
-76
lines changed

.devcontainer/devcontainer.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
2+
// README at: https://github.com/devcontainers/templates/tree/main/src/python
3+
{
4+
"name": "Python 3",
5+
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
6+
"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bullseye",
7+
"features": {
8+
"ghcr.io/devcontainers/features/azure-cli:1": {
9+
"installBicep": true,
10+
"version": "latest",
11+
"bicepVersion": "latest"
12+
},
13+
"ghcr.io/jlaundry/devcontainer-features/mssql-odbc-driver:1": {
14+
"version": "18"
15+
},
16+
"ghcr.io/azure/azure-dev/azd:0": {
17+
"version": "stable"
18+
}
19+
},
20+
"customizations": {
21+
"vscode": {
22+
"extensions": [
23+
"ms-python.python",
24+
"ms-azuretools.vscode-azcli",
25+
"ms-azuretools.vscode-bicep",
26+
"ms-azuretools.azure-dev"
27+
]
28+
}
29+
},
30+
"postCreateCommand": "chmod +x ./.devcontainer/setup_env.sh && bash ./.devcontainer/setup_env.sh",
31+
"remoteUser": "vscode",
32+
"hostRequirements": {
33+
"memory": "4gb"
34+
}
35+
}

.devcontainer/setup_env.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/bin/bash
2+
3+
git fetch
4+
git pull
5+
6+
# provide execute permission to quotacheck script
7+
chmod +x ./infra/scripts/checkquota.sh
8+
9+
# Add the path to ~/.bashrc for persistence
10+
if ! grep -q '/opt/mssql-tools18/bin' ~/.bashrc; then
11+
echo 'export PATH="$PATH:/opt/mssql-tools18/bin"' >> ~/.bashrc
12+
fi
13+
14+
# Export the path for the current session
15+
export PATH="$PATH:/opt/mssql-tools18/bin"
16+
17+
# Verify sqlcmd is available
18+
if ! command -v sqlcmd &> /dev/null; then
19+
echo "sqlcmd is not available in the PATH. Please check the installation."
20+
exit 1
21+
fi

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,8 @@ FodyWeavers.xsd
396396

397397
# JetBrains Rider
398398
*.sln.iml
399+
400+
.venv
401+
402+
scriptenv
403+
.azure

app-azure.yaml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
2+
3+
name: sample-app-aoai-chatgpt
4+
metadata:
5+
template: sample-app-aoai-chatgpt@0.0.1-beta
6+
services:
7+
backend:
8+
project: .
9+
language: py
10+
host: appservice
11+
hooks:
12+
prepackage:
13+
windows:
14+
shell: pwsh
15+
run: cd ./frontend;npm install;npm run build
16+
interactive: true
17+
continueOnError: false
18+
posix:
19+
shell: sh
20+
run: cd ./frontend;npm install;npm run build
21+
interactive: true
22+
continueOnError: false
23+
hooks:
24+
preprovision:
25+
windows:
26+
shell: pwsh
27+
run: ./scripts/auth_init.ps1
28+
interactive: true
29+
continueOnError: false
30+
posix:
31+
shell: sh
32+
run: ./scripts/auth_init.sh
33+
interactive: true
34+
continueOnError: false
35+
postprovision:
36+
windows:
37+
shell: pwsh
38+
run: ./scripts/auth_update.ps1;./scripts/prepdocs.ps1;
39+
interactive: true
40+
continueOnError: false
41+
posix:
42+
shell: sh
43+
run: ./scripts/auth_update.sh;./scripts/prepdocs.sh;
44+
interactive: true
45+
continueOnError: false

azure.yaml

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,34 @@
11
# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json
22

3-
name: sample-app-aoai-chatgpt
3+
name: build-your-own-copilot-solution-accelerator
4+
45
metadata:
5-
template: sample-app-aoai-chatgpt@0.0.1-beta
6-
services:
7-
backend:
8-
project: .
9-
language: py
10-
host: appservice
11-
hooks:
12-
prepackage:
13-
windows:
14-
shell: pwsh
15-
run: cd ./frontend;npm install;npm run build
16-
interactive: true
17-
continueOnError: false
18-
posix:
19-
shell: sh
20-
run: cd ./frontend;npm install;npm run build
21-
interactive: true
22-
continueOnError: false
6+
template: build-your-own-copilot-solution-accelerator@1.0
7+
name: build-your-own-copilot-solution-accelerator@1.0
8+
9+
infra:
10+
provider: bicep
11+
path: infra/bicep
12+
module: main
13+
2314
hooks:
24-
preprovision:
25-
windows:
26-
shell: pwsh
27-
run: ./scripts/auth_init.ps1
28-
interactive: true
29-
continueOnError: false
30-
posix:
31-
shell: sh
32-
run: ./scripts/auth_init.sh
33-
interactive: true
34-
continueOnError: false
35-
postprovision:
36-
windows:
37-
shell: pwsh
38-
run: ./scripts/auth_update.ps1;./scripts/prepdocs.ps1;
39-
interactive: true
40-
continueOnError: false
41-
posix:
42-
shell: sh
43-
run: ./scripts/auth_update.sh;./scripts/prepdocs.sh;
44-
interactive: true
45-
continueOnError: false
15+
postprovision:
16+
windows:
17+
run: |
18+
Write-Host "Web app URL: "
19+
Write-Host "$env:WEB_APP_URL" -ForegroundColor Cyan
20+
Write-Host "`nRun the following command in your Bash terminal. It will grant the necessary permissions between resources and your user account, and also process and load the sample data into the application."
21+
Write-Host "bash ./infra/scripts/process_sample_data.sh" -ForegroundColor Cyan
22+
shell: pwsh
23+
continueOnError: false
24+
interactive: true
25+
posix:
26+
run: |
27+
echo "Web app URL: "
28+
echo $WEB_APP_URL
29+
echo ""
30+
echo "Run the following command in your Bash terminal. It will grant the necessary permissions between resources and your user account, and also process and load the sample data into the application."
31+
echo "bash ./infra/scripts/process_sample_data.sh"
32+
shell: sh
33+
continueOnError: false
34+
interactive: true

infra/bicep/deploy_post_deployment_scripts.bicep

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ resource containerApp 'Microsoft.App/containerApps@2022-03-01' = {
7070
memory: '4.0Gi'
7171
}
7272
command: [
73-
'/bin/sh', '-c', 'mkdir -p /scripts && apk add --no-cache curl bash jq py3-pip gcc musl-dev libffi-dev openssl-dev python3-dev && pip install --upgrade azure-cli && apk add --no-cache --virtual .build-deps build-base unixodbc-dev && curl -s -o msodbcsql18_18.4.1.1-1_amd64.apk https://download.microsoft.com/download/7/6/d/76de322a-d860-4894-9945-f0cc5d6a45f8/msodbcsql18_18.4.1.1-1_amd64.apk && curl -s -o mssql-tools18_18.4.1.1-1_amd64.apk https://download.microsoft.com/download/7/6/d/76de322a-d860-4894-9945-f0cc5d6a45f8/mssql-tools18_18.4.1.1-1_amd64.apk && apk add --allow-untrusted msodbcsql18_18.4.1.1-1_amd64.apk && apk add --allow-untrusted mssql-tools18_18.4.1.1-1_amd64.apk && curl -s -o /scripts/copy_kb_files.sh ${setupCopyKbFiles} && chmod +x /scripts/copy_kb_files.sh && sh -x /scripts/copy_kb_files.sh ${storageAccountName} ${containerName} ${baseUrl} ${managedIdentityClientId} && curl -s -o /scripts/run_create_index_scripts.sh ${setupCreateIndexScriptsUrl} && chmod +x /scripts/run_create_index_scripts.sh && sh -x /scripts/run_create_index_scripts.sh ${baseUrl} ${keyVaultName} ${managedIdentityClientId} && apk add --no-cache ca-certificates less ncurses-terminfo-base krb5-libs libgcc libintl libssl3 libstdc++ tzdata userspace-rcu zlib icu-libs curl && apk -X https://dl-cdn.alpinelinux.org/alpine/edge/main add --no-cache lttng-ust openssh-client && curl -L https://github.com/PowerShell/PowerShell/releases/download/v7.5.0/powershell-7.5.0-linux-musl-x64.tar.gz -o /tmp/powershell.tar.gz && mkdir -p /opt/microsoft/powershell/7 && tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 && chmod +x /opt/microsoft/powershell/7/pwsh && ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh && curl -s -o /scripts/create-sql-user-and-role.ps1 ${createSqlUserAndRoleScriptsUrl} && chmod +x /scripts/create-sql-user-and-role.ps1 && pwsh -File /scripts/create-sql-user-and-role.ps1 -SqlServerName ${sqlServerName} -SqlDatabaseName ${sqlDbName} -ClientId ${sqlUsers[0].principalId} -DisplayName ${sqlUsers[0].principalName} -ManagedIdentityClientId ${managedIdentityClientId} -DatabaseRole ${sqlUsers[0].databaseRoles[0]} && pwsh -File /scripts/create-sql-user-and-role.ps1 -SqlServerName ${sqlServerName} -SqlDatabaseName ${sqlDbName} -ClientId ${sqlUsers[1].principalId} -DisplayName ${sqlUsers[1].principalName} -ManagedIdentityClientId ${managedIdentityClientId} -DatabaseRole ${sqlUsers[1].databaseRoles[0]} && pwsh -File /scripts/create-sql-user-and-role.ps1 -SqlServerName ${sqlServerName} -SqlDatabaseName ${sqlDbName} -ClientId ${sqlUsers[1].principalId} -DisplayName ${sqlUsers[1].principalName} -ManagedIdentityClientId ${managedIdentityClientId} -DatabaseRole ${sqlUsers[1].databaseRoles[1]} && az login --identity --client-id ${managedIdentityClientId} && az containerapp update --name ${containerAppName} --resource-group ${resourceGroupName} --min-replicas 0 --cpu 0.25 --memory 0.5Gi && az containerapp revision deactivate -g ${resourceGroupName} --revision $(az containerapp revision list -n ${containerAppName} -g ${resourceGroupName} --query "[0].name" -o tsv) && echo "Container app setup completed successfully."'
73+
'/bin/sh', '-c', 'mkdir -p /scripts && apk add --no-cache curl bash jq py3-pip gcc musl-dev libffi-dev openssl-dev python3-dev && pip install --upgrade azure-cli && apk add --no-cache --virtual .build-deps build-base unixodbc-dev && curl -s -o msodbcsql18_18.4.1.1-1_amd64.apk https://download.microsoft.com/download/7/6/d/76de322a-d860-4894-9945-f0cc5d6a45f8/msodbcsql18_18.4.1.1-1_amd64.apk && curl -s -o mssql-tools18_18.4.1.1-1_amd64.apk https://download.microsoft.com/download/7/6/d/76de322a-d860-4894-9945-f0cc5d6a45f8/mssql-tools18_18.4.1.1-1_amd64.apk && apk add --allow-untrusted msodbcsql18_18.4.1.1-1_amd64.apk && apk add --allow-untrusted mssql-tools18_18.4.1.1-1_amd64.apk && curl -s -o /scripts/copy_kb_files.sh ${setupCopyKbFiles} && chmod +x /scripts/copy_kb_files.sh && sh -x /scripts/copy_kb_files.sh ${storageAccountName} ${containerName} ${baseUrl} ${managedIdentityClientId} && curl -s -o /scripts/run_create_index_scripts.sh ${setupCreateIndexScriptsUrl} && chmod +x /scripts/run_create_index_scripts.sh && sh -x /scripts/run_create_index_scripts.sh ${keyVaultName} ${baseUrl} ${managedIdentityClientId} && apk add --no-cache ca-certificates less ncurses-terminfo-base krb5-libs libgcc libintl libssl3 libstdc++ tzdata userspace-rcu zlib icu-libs curl && apk -X https://dl-cdn.alpinelinux.org/alpine/edge/main add --no-cache lttng-ust openssh-client && curl -L https://github.com/PowerShell/PowerShell/releases/download/v7.5.0/powershell-7.5.0-linux-musl-x64.tar.gz -o /tmp/powershell.tar.gz && mkdir -p /opt/microsoft/powershell/7 && tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7 && chmod +x /opt/microsoft/powershell/7/pwsh && ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh && curl -s -o /scripts/create-sql-user-and-role.ps1 ${createSqlUserAndRoleScriptsUrl} && chmod +x /scripts/create-sql-user-and-role.ps1 && pwsh -File /scripts/create-sql-user-and-role.ps1 -SqlServerName ${sqlServerName} -SqlDatabaseName ${sqlDbName} -ClientId ${sqlUsers[0].principalId} -DisplayName ${sqlUsers[0].principalName} -ManagedIdentityClientId ${managedIdentityClientId} -DatabaseRole ${sqlUsers[0].databaseRoles[0]} && pwsh -File /scripts/create-sql-user-and-role.ps1 -SqlServerName ${sqlServerName} -SqlDatabaseName ${sqlDbName} -ClientId ${sqlUsers[1].principalId} -DisplayName ${sqlUsers[1].principalName} -ManagedIdentityClientId ${managedIdentityClientId} -DatabaseRole ${sqlUsers[1].databaseRoles[0]} && pwsh -File /scripts/create-sql-user-and-role.ps1 -SqlServerName ${sqlServerName} -SqlDatabaseName ${sqlDbName} -ClientId ${sqlUsers[1].principalId} -DisplayName ${sqlUsers[1].principalName} -ManagedIdentityClientId ${managedIdentityClientId} -DatabaseRole ${sqlUsers[1].databaseRoles[1]} && az login --identity --client-id ${managedIdentityClientId} && az containerapp update --name ${containerAppName} --resource-group ${resourceGroupName} --min-replicas 0 --cpu 0.25 --memory 0.5Gi && az containerapp revision deactivate -g ${resourceGroupName} --revision $(az containerapp revision list -n ${containerAppName} -g ${resourceGroupName} --query "[0].name" -o tsv) && echo "Container app setup completed successfully."'
7474
]
7575
env: [
7676
{

infra/bicep/main.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"_generator": {
66
"name": "bicep",
77
"version": "0.34.44.8038",
8-
"templateHash": "7940000667981168161"
8+
"templateHash": "13074623986840466778"
99
}
1010
},
1111
"parameters": {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/bin/bash
2+
3+
# Variables
4+
resource_group="$1"
5+
account_name="$2"
6+
managedIdentityClientId="$3"
7+
8+
# Authenticate with Azure
9+
if az account show &> /dev/null; then
10+
echo "Already authenticated with Azure."
11+
else
12+
if [ -n "$managedIdentityClientId" ]; then
13+
# Use managed identity if running in Azure
14+
echo "Authenticating with Managed Identity..."
15+
az login --identity --client-id ${managedIdentityClientId}
16+
else
17+
# Use Azure CLI login if running locally
18+
echo "Authenticating with Azure CLI..."
19+
az login
20+
fi
21+
echo "Not authenticated with Azure. Attempting to authenticate..."
22+
fi
23+
24+
echo "Getting signed in user id"
25+
signed_user_id=$(az ad signed-in-user show --query id -o tsv)
26+
27+
# Check if the user has the Cosmos DB Built-in Data Contributor role
28+
echo "Checking if user has the Cosmos DB Built-in Data Contributor role"
29+
roleExists=$(az cosmosdb sql role assignment list \
30+
--resource-group $resource_group \
31+
--account-name $account_name \
32+
--query "[?roleDefinitionId.ends_with(@, '00000000-0000-0000-0000-000000000002') && principalId == '$signed_user_id']" -o tsv)
33+
34+
# Check if the role exists
35+
if [ -n "$roleExists" ]; then
36+
echo "User already has the Cosmos DB Built-in Data Contributer role."
37+
else
38+
echo "User does not have the Cosmos DB Built-in Data Contributer role. Assigning the role."
39+
MSYS_NO_PATHCONV=1 az cosmosdb sql role assignment create \
40+
--resource-group $resource_group \
41+
--account-name $account_name \
42+
--role-definition-id 00000000-0000-0000-0000-000000000002 \
43+
--principal-id $signed_user_id \
44+
--scope "/" \
45+
--output none
46+
if [ $? -eq 0 ]; then
47+
echo "Cosmos DB Built-in Data Contributer role assigned successfully."
48+
else
49+
echo "Failed to assign Cosmos DB Built-in Data Contributer role."
50+
fi
51+
fi
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/bin/bash
2+
3+
# Parameters
4+
SqlServerName="$1"
5+
SqlDatabaseName="$2"
6+
UserRoleJSONArray="$3"
7+
ManagedIdentityClientId="$6"
8+
9+
# Function to check if a command exists or runs successfully
10+
function check_command() {
11+
if ! eval "$1" &> /dev/null; then
12+
echo "Error: Command '$1' failed or is not installed."
13+
exit 1
14+
fi
15+
}
16+
17+
# Ensure required commands are available
18+
check_command "az --version"
19+
check_command "sqlcmd '-?'"
20+
21+
# Authenticate with Azure
22+
if az account show &> /dev/null; then
23+
echo "Already authenticated with Azure."
24+
else
25+
if [ -n "$ManagedIdentityClientId" ]; then
26+
# Use managed identity if running in Azure
27+
echo "Authenticating with Managed Identity..."
28+
az login --identity --client-id ${ManagedIdentityClientId}
29+
else
30+
# Use Azure CLI login if running locally
31+
echo "Authenticating with Azure CLI..."
32+
az login
33+
fi
34+
echo "Not authenticated with Azure. Attempting to authenticate..."
35+
fi
36+
37+
SQL_QUERY=""
38+
#loop through the JSON array and create users and assign roles using grep and sed
39+
count=1
40+
while read -r json_object; do
41+
# Extract fields from the JSON object using grep and sed
42+
clientId=$(echo "$json_object" | grep -o '"clientId": *"[^"]*"' | sed 's/"clientId": *"\([^"]*\)"/\1/')
43+
displayName=$(echo "$json_object" | grep -o '"displayName": *"[^"]*"' | sed 's/"displayName": *"\([^"]*\)"/\1/')
44+
role=$(echo "$json_object" | grep -o '"role": *"[^"]*"' | sed 's/"role": *"\([^"]*\)"/\1/')
45+
46+
# Append to SQL_QUERY with dynamic variable names
47+
SQL_QUERY+="
48+
DECLARE @username$count nvarchar(max) = N'$displayName';
49+
DECLARE @clientId$count uniqueidentifier = '$clientId';
50+
DECLARE @sid$count NVARCHAR(max) = CONVERT(VARCHAR(max), CONVERT(VARBINARY(16), @clientId$count), 1);
51+
DECLARE @cmd$count NVARCHAR(max) = N'CREATE USER [' + @username$count + '] WITH SID = ' + @sid$count + ', TYPE = E;';
52+
IF NOT EXISTS (SELECT * FROM sys.database_principals WHERE name = @username$count)
53+
BEGIN
54+
EXEC(@cmd$count)
55+
END
56+
EXEC sp_addrolemember '$role', @username$count;
57+
"
58+
59+
# Increment the count
60+
count=$((count + 1))
61+
done < <(echo "$UserRoleJSONArray" | grep -o '{[^}]*}')
62+
63+
#create heredoc for the SQL query
64+
SQL_QUERY_FINAL=$(cat <<EOF
65+
$SQL_QUERY
66+
EOF
67+
)
68+
69+
70+
71+
# SQL query to create the user and assign the role
72+
# SQL_QUERY=$(cat <<EOF
73+
# DECLARE @username nvarchar(max) = N'$DisplayName';
74+
# DECLARE @clientId uniqueidentifier = '$ClientId';
75+
# DECLARE @sid NVARCHAR(max) = CONVERT(VARCHAR(max), CONVERT(VARBINARY(16), @clientId), 1);
76+
# DECLARE @cmd NVARCHAR(max) = N'CREATE USER [' + @username + '] WITH SID = ' + @sid + ', TYPE = E;';
77+
# IF NOT EXISTS (SELECT * FROM sys.database_principals WHERE name = @username)
78+
# BEGIN
79+
# EXEC(@cmd)
80+
# END
81+
# EXEC sp_addrolemember '$DatabaseRole', @username;
82+
# EOF
83+
# )
84+
85+
# # Output the SQL query for debugging
86+
# echo "SQL Query:"
87+
# echo "$SQL_QUERY_FINAL"
88+
89+
# Check if OS is Windows
90+
OS=$(uname | tr '[:upper:]' '[:lower:]')
91+
92+
if [[ "$OS" == "mingw"* || "$OS" == "cygwin"* || "$OS" == "msys"* ]]; then
93+
echo "Running on Windows OS, will use interactive login"
94+
echo "Getting signed in user email"
95+
UserEmail=$(az ad signed-in-user show --query userPrincipalName -o tsv)
96+
# Execute the SQL query
97+
echo "Executing SQL query..."
98+
sqlcmd -S "$SqlServerName" -d "$SqlDatabaseName" -G -U "$UserEmail" -Q "$SQL_QUERY_FINAL" || {
99+
echo "Failed to execute SQL query."
100+
exit 1
101+
}
102+
else
103+
echo "Running on Linux or macOS, will use access token"
104+
mkdir -p usersql
105+
# Get an access token for the Azure SQL Database
106+
echo "Retrieving access token..."
107+
az account get-access-token --resource https://database.windows.net --output tsv | cut -f 1 | tr -d '\n' | iconv -f ascii -t UTF-16LE > usersql/tokenFile
108+
if [ $? -ne 0 ]; then
109+
echo "Failed to retrieve access token."
110+
exit 1
111+
fi
112+
errorFlag=false
113+
# Execute the SQL query
114+
echo "Executing SQL query..."
115+
sqlcmd -S "$SqlServerName" -d "$SqlDatabaseName" -G -P usersql/tokenFile -Q "$SQL_QUERY_FINAL" || {
116+
echo "Failed to execute SQL query."
117+
errorFlag=true
118+
}
119+
#delete the usersql directory
120+
rm -rf usersql
121+
if [ "$errorFlag" = true ]; then
122+
exit 1
123+
fi
124+
fi
125+
126+
127+
echo "SQL user and role assignment completed successfully."

0 commit comments

Comments
 (0)