Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 37 additions & 26 deletions Deployment/main.bicep
Original file line number Diff line number Diff line change
@@ -1,57 +1,67 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

targetScope = 'resourceGroup'

@minLength(3)
@maxLength(20)
@description('A unique prefix for all resources in this deployment. This should be 3-20 characters long:')
param environmentName string

@description('The Data Center where the model is deployed.')
param modeldatacenter string
var abbrs = loadJsonContent('./abbreviations.json')

targetScope = 'subscription'
var resourceprefix = padLeft(take(uniqueString(deployment().name), 5), 5, '0')
@description('Azure data center region where resources will be deployed. This should be a valid Azure region, e.g., eastus, westus, etc.')
param location string

var uniqueId = toLower(uniqueString(subscription().id, environmentName, location))
var resourceprefix = padLeft(take(uniqueId, 10), 10, '0')
var resourceprefix_name = 'kmgs'

// Create a resource group
resource gs_resourcegroup 'Microsoft.Resources/resourceGroups@2021-04-01' = {
name: '${abbrs.managementGovernance.resourceGroup}${resourceprefix_name}${resourceprefix}'
location: deployment().location
}
var resourceGroupLocation = resourceGroup().location

// Load the abbrevations file required to name the azure resources.
var abbrs = loadJsonContent('./abbreviations.json')


// Create a storage account
module gs_storageaccount 'bicep/azurestorageaccount.bicep' = {
name: '${abbrs.storage.storageAccount}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
storageAccountName: '${abbrs.storage.storageAccount}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}

// Create a Azure Search Service
module gs_azsearch 'bicep/azuresearch.bicep' = {
name: '${abbrs.ai.aiSearch}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
searchServiceName: '${abbrs.ai.aiSearch}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}


// Create Container Registry
module gs_containerregistry 'bicep/azurecontainerregistry.bicep' = {
name: '${abbrs.containers.containerRegistry}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
acrName: '${abbrs.containers.containerRegistry}${resourceprefix_name}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}

// Create AKS Cluster
module gs_aks 'bicep/azurekubernetesservice.bicep' = {
name: '${abbrs.compute.arcEnabledKubernetesCluster}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
aksName: '${abbrs.compute.arcEnabledKubernetesCluster}${resourceprefix_name}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
dependsOn: [
gs_containerregistry
Expand All @@ -76,7 +86,7 @@ module gs_aks 'bicep/azurekubernetesservice.bicep' = {
// Create Azure Cognitive Service
module gs_azcognitiveservice 'bicep/azurecognitiveservice.bicep' = {
name: '${abbrs.ai.documentIntelligence}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
cognitiveServiceName: '${abbrs.ai.documentIntelligence}${resourceprefix_name}${resourceprefix}'
location: 'eastus'
Expand All @@ -86,7 +96,7 @@ module gs_azcognitiveservice 'bicep/azurecognitiveservice.bicep' = {
// Create Azure Open AI Service
module gs_openaiservice 'bicep/azureopenaiservice.bicep' = {
name: '${abbrs.ai.openAIService}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
openAIServiceName: '${abbrs.ai.openAIService}${resourceprefix_name}${resourceprefix}'
// GPT-4-32K model & GPT-4o available Data center information.
Expand All @@ -99,7 +109,7 @@ module gs_openaiservice 'bicep/azureopenaiservice.bicep' = {
// Set the minimum capacity of each model
// Based on customer's Model capacity, it needs to be updated in Azure Portal.
module gs_openaiservicemodels_gpt4o 'bicep/azureopenaiservicemodel.bicep' = {
scope: gs_resourcegroup
scope: resourceGroup()
name: 'gpt-4o-mini'
params: {
parentResourceName: gs_openaiservice.outputs.openAIServiceName
Expand All @@ -119,7 +129,7 @@ module gs_openaiservicemodels_gpt4o 'bicep/azureopenaiservicemodel.bicep' = {
}

module gs_openaiservicemodels_text_embedding 'bicep/azureopenaiservicemodel.bicep' = {
scope: gs_resourcegroup
scope: resourceGroup()
name: 'text-embedding-large'
params: {
parentResourceName: gs_openaiservice.outputs.openAIServiceName
Expand All @@ -140,25 +150,26 @@ module gs_openaiservicemodels_text_embedding 'bicep/azureopenaiservicemodel.bice
// Create Azure Cosmos DB Mongo
module gs_cosmosdb 'bicep/azurecosmosdb.bicep' = {
name: '${abbrs.databases.cosmosDBDatabase}${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
cosmosDbAccountName: '${abbrs.databases.cosmosDBDatabase}${resourceprefix_name}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}

// Create Azure App Configuration
module gs_appconfig 'bicep/azureappconfigservice.bicep' = {
name: 'appconfig-${resourceprefix_name}${resourceprefix}'
scope: gs_resourcegroup
scope: resourceGroup()
params: {
appConfigName: 'appconfig-${resourceprefix_name}${resourceprefix}'
location: deployment().location
location: resourceGroupLocation
}
}

// return all resource names as a output
output gs_resourcegroup_name string = '${abbrs.managementGovernance.resourceGroup}${resourceprefix_name}${resourceprefix}'
// output gs_resourcegroup_name string = '${abbrs.managementGovernance.resourceGroup}${resourceprefix_name}${resourceprefix}'
output gs_resourcegroup_name string = resourceGroup().name
output gs_solution_prefix string = '${resourceprefix_name}${resourceprefix}'
output gs_storageaccount_name string = gs_storageaccount.outputs.storageAccountName
output gs_azsearch_name string = gs_azsearch.outputs.searchServiceName
Expand Down Expand Up @@ -189,5 +200,5 @@ output gs_appconfig_endpoint string = gs_appconfig.outputs.appConfigEndpoint
output gs_containerregistry_endpoint string = gs_containerregistry.outputs.acrEndpoint

//return resourcegroup resource ID
output gs_resourcegroup_id string = gs_resourcegroup.id
output gs_resourcegroup_id string = resourceGroup().id

9 changes: 9 additions & 0 deletions Deployment/resourcePrefix.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
targetScope = 'subscription'

param environmentName string
param location string

var uniqueId = toLower(uniqueString(subscription().id, environmentName, location))
var resourceprefix = padLeft(take(uniqueId, 10), 10, '0')

output resourcePrefix string = resourceprefix
120 changes: 92 additions & 28 deletions Deployment/resourcedeployment.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ function ValidateVariableIsNullOrEmpty {
function PromptForParameters {
param(
[string]$subscriptionID,
[string]$environmentName,
[string]$resourceGroupName,
[string]$location,
[string]$modelLocation,
[string]$email
Expand Down Expand Up @@ -105,6 +107,16 @@ function PromptForParameters {
$subscriptionID = Read-Host -Prompt '> '
}

if (-not $environmentName) {
Write-Host "Please enter Environment name" -ForegroundColor Cyan
$environmentName = Read-Host -Prompt '> '
}

if (-not $resourceGroupName) {
Write-Host "Please enter your Azure Resource Group Name to deploy your resources (leave blank to auto-generate one)" -ForegroundColor Cyan
$resourceGroupName = Read-Host -Prompt '> '
}

if (-not $location) {
Write-Host "Please enter the Azure Data Center Region to deploy your resources" -ForegroundColor Cyan
Write-Host "Available regions are:" -ForegroundColor Cyan
Expand All @@ -125,37 +137,41 @@ function PromptForParameters {
}

return @{
subscriptionID = $subscriptionID
location = $location
modelLocation = $modelLocation
email = $email
subscriptionID = $subscriptionID
environmentName = $environmentName
resourceGroupName = $resourceGroupName
location = $location
modelLocation = $modelLocation
email = $email
}
}

# Prompt for parameters with kind messages
$params = PromptForParameters -subscriptionID $subscriptionID -location $location -modelLocation $modelLocation -email $email
$params = PromptForParameters -subscriptionID $subscriptionID -environmentName $environmentName -resourceGroupName $resourceGroupName -location $location -modelLocation $modelLocation -email $email
# Assign the parameters to variables
$subscriptionID = $params.subscriptionID
$environmentName = $params.environmentName
$resourceGroupName = $params.resourceGroupName
$location = $params.location
$modelLocation = $params.modelLocation
$email = $params.email

function LoginAzure([string]$subscriptionID) {
Write-Host "Log in to Azure.....`r`n" -ForegroundColor Yellow
Write-Host "Log in to Azure.....`r`n" -ForegroundColor Yellow
if ($env:CI -eq "true"){

az login --service-principal `
--username $env:AZURE_CLIENT_ID `
--password $env:AZURE_CLIENT_SECRET `
--tenant $env:AZURE_TENANT_ID
--username $env:AZURE_CLIENT_ID `
--password $env:AZURE_CLIENT_SECRET `
--tenant $env:AZURE_TENANT_ID
write-host "CI deployment mode"
}
}
else{
az login
az login
write-host "manual deployment mode"
}
az account set --subscription $subscriptionID
Write-Host "Switched subscription to '$subscriptionID' `r`n" -ForegroundColor Yellow
}
az account set --subscription $subscriptionID
Write-Host "Switched subscription to '$subscriptionID' `r`n" -ForegroundColor Yellow
}

function DeployAzureResources([string]$location, [string]$modelLocation) {
Expand All @@ -169,9 +185,53 @@ function DeployAzureResources([string]$location, [string]$modelLocation) {
# Make deployment name unique by appending random number
$deploymentName = "KM_SA_Deployment$randomNumberPadded"


if (-not $resourceGroupName) {
# Generate a new RG name using your existing logic

# Load abbreviation from abbreviations.json (optional)
$abbrs = Get-Content -Raw -Path "./abbreviations.json" | ConvertFrom-Json
if (-not $abbrs -or -not $abbrs.managementGovernance.resourceGroup) {
Write-Host "abbreviations.json is missing or malformed."
failureBanner
exit 1
}
$rgPrefix = $abbrs.managementGovernance.resourceGroup # e.g., "rg-"

# Constants
$resourceprefix_name = "kmgs"

# Call Bicep to generate resourcePrefix
$resourcePrefix = az deployment sub create `
--location $location `
--name $deploymentName `
--template-file ./resourcePrefix.bicep `
--parameters environmentName=$environmentName location=$location `
--query "properties.outputs.resourcePrefix.value" `
-o tsv

# Final Resource Group Name
$resourceGroupName = "$rgPrefix$resourceprefix_name$resourcePrefix"

Write-Host "Generated Resource Group Name: $resourceGroupName"

Write-Host "No RG provided. Creating new RG: $resourceGroupName" -ForegroundColor Yellow
az group create --name $resourceGroupName --location $location --tags EnvironmentName=$environmentName | Out-Null
}
else {
$exists = az group exists --name $resourceGroupName | ConvertFrom-Json
if (-not $exists) {
Write-Host "Specified RG does not exist. Creating RG: $resourceGroupName" -ForegroundColor Yellow
az group create --name $resourceGroupName --location $location --tags EnvironmentName=$environmentName | Out-Null
}
else {
Write-Host "Using existing RG: $resourceGroupName" -ForegroundColor Green
}
}

# Perform a what-if deployment to preview changes
Write-Host "Evaluating Deployment resource availabilities to preview changes..." -ForegroundColor Yellow
$whatIfResult = az deployment sub what-if --template-file .\main.bicep --location $location --name $deploymentName --parameters modeldatacenter=$modelLocation
$whatIfResult = az deployment group what-if --resource-group $resourceGroupName --template-file .\main.bicep --name $deploymentName --parameters modeldatacenter=$modelLocation location=$location environmentName=$environmentName

if ($LASTEXITCODE -ne 0) {
Write-Host "There might be something wrong with your deployment." -ForegroundColor Red
Expand All @@ -181,7 +241,8 @@ function DeployAzureResources([string]$location, [string]$modelLocation) {
}
# Proceed with the actual deployment
Write-Host "Proceeding with Deployment..." -ForegroundColor Yellow
$deploymentResult = az deployment sub create --template-file .\main.bicep --location $location --name $deploymentName --parameters modeldatacenter=$modelLocation
Write-Host "Resource Group Name: $resourceGroupName" -ForegroundColor Yellow
$deploymentResult = az deployment group create --resource-group $resourceGroupName --template-file .\main.bicep --name $deploymentName --parameters modeldatacenter=$modelLocation location=$location environmentName=$environmentName
# Check if deploymentResult is valid
ValidateVariableIsNullOrEmpty -variableValue $deploymentResult -variableName "Deployment Result"
if ($LASTEXITCODE -ne 0) {
Expand Down Expand Up @@ -391,7 +452,7 @@ class DeploymentResult {
# Azure App Configuration
$this.AzAppConfigEndpoint = $jsonString.properties.outputs.gs_appconfig_endpoint.value
# App Config Name
$this.AzAppConfigName = "appconfig" + $this.ResourceGroupName
$this.AzAppConfigName = "appconfig-" + $jsonString.properties.outputs.gs_solution_prefix.value

}
}
Expand Down Expand Up @@ -438,6 +499,9 @@ try {
Write-Host "Deploying Azure resources in $location region.....`r`n" -ForegroundColor Yellow

$resultJson = DeployAzureResources -location $location -modelLocation $modelLocation

# Ensure ResourceGroupName is set correctly
$deploymentResult.ResourceGroupName = $resourceGroupName
# Map the deployment result to DeploymentResult object
$deploymentResult.MapResult($resultJson)
# Display the deployment result
Expand Down Expand Up @@ -530,7 +594,7 @@ try {
'{gpt-4o-modelname}' = $deploymentResult.AzGPT4oModelName
'{azureopenaiembedding-deployment}' = $deploymentResult.AzGPTEmbeddingModelName
'{kernelmemory-endpoint}' = "http://kernelmemory-service"
}
}

## Load and update the AI service configuration template
$aiServiceConfigTemplate = Get-Content -Path .\appconfig\aiservice\appconfig.jsonl -Raw
Expand All @@ -550,7 +614,7 @@ try {
$filePath = Join-Path $scriptDirectory ".\appconfig\aiservice\appsettings.dev.jsonl"

## Other variables
$appConfigName = $deploymentResult.AzAppConfigName -replace "rg-", "-"
$appConfigName = $deploymentResult.AzAppConfigName

## Output the file path for verification
#write-host "Using file path: $filePath"
Expand Down Expand Up @@ -731,7 +795,7 @@ try {
# Validate if System Assigned Identity is null or empty
ValidateVariableIsNullOrEmpty -variableValue $systemAssignedIdentity -variableName "System-assigned managed identity"

# Validate if ResourceGroupId is null or empty
# Validate if ResourceGroupId is null or empty
ValidateVariableIsNullOrEmpty -variableValue $deploymentResult.ResourceGroupId -variableName "ResourceGroupId"

# Assign the role for aks system assigned managed identity to App Configuration Data Reader role with the scope of Resourcegroup
Expand Down Expand Up @@ -848,7 +912,7 @@ try {
Wait-ForCertManager


#======================================================================================================================================================================
#======================================================================================================================================================================
# Validate AzAppConfigEndpoint IsNull Or Empty.
ValidateVariableIsNullOrEmpty -variableValue $deploymentResult.AzAppConfigEndpoint -variableName "Azure App Configuration Endpoint"
# App Deployment after finishing the AKS infrastructure setup
Expand Down Expand Up @@ -933,7 +997,7 @@ try {
docker build "../App/frontend-app/." --no-cache -t $acrFrontAppTag
docker push $acrFrontAppTag

#======================================================================================================================================================================
#======================================================================================================================================================================

# 7.2. Deploy ClusterIssuer in Kubernetes for SSL/TLS certificate
kubectl apply -f "./kubernetes/deploy.certclusterissuer.yaml"
Expand Down Expand Up @@ -962,12 +1026,12 @@ try {
successBanner

$messageString = "Please find the deployment details below: `r`n" +
"1. Check Front Web Application with this URL - https://${fqdn} `n`r" +
"2. Check GPT Model's TPM rate in your resource group - $($deploymentResult.ResourceGroupName) `n`r" +
"Please set each value high as much as you can set`n`r" +
"`t- Open AI Resource Name - $($deploymentResult.AzOpenAiServiceName) `n`r" +
"`t- GPT4o Model - $($deploymentResult.AzGPT4oModelName) `n`r" +
"`t- GPT Embedding Model - $($deploymentResult.AzGPTEmbeddingModelName) `n`r"
"1. Check Front Web Application with this URL - https://${fqdn} `n`r" +
"2. Check GPT Model's TPM rate in your resource group - $($deploymentResult.ResourceGroupName) `n`r" +
"Please set each value high as much as you can set`n`r" +
"`t- Open AI Resource Name - $($deploymentResult.AzOpenAiServiceName) `n`r" +
"`t- GPT4o Model - $($deploymentResult.AzGPT4oModelName) `n`r" +
"`t- GPT Embedding Model - $($deploymentResult.AzGPTEmbeddingModelName) `n`r"
Write-Host $messageString -ForegroundColor Yellow
Write-Host "Don't forget to control the TPM rate for your GPT and Embedding Model in Azure Open AI Studio Deployments section." -ForegroundColor Red
Write-Host "After controlling the TPM rate for your GPT and Embedding Model, let's start Data file import process with this command." -ForegroundColor Yellow
Expand Down