diff --git a/azure.yaml b/azure.yaml index d0a4db1..afccfcc 100644 --- a/azure.yaml +++ b/azure.yaml @@ -1,10 +1,8 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/v1.0/azure.yaml.json -# TODO: do we need hooks? -# TODO: do we need all of the variables? name: azd-get-started-with-ai-agents metadata: - template: azd-get-started-with-ai-agents@0.0.1-beta + template: azdc-get-started-with-ai-agents@0.0.1-beta services: api: @@ -13,20 +11,6 @@ services: host: containerapp docker: remoteBuild: true - -hooks: - postprovision: - windows: - shell: pwsh - run: ./scripts/write_env.ps1 - continueOnError: true - interactive: true - posix: - shell: sh - run: ./scripts/write_env.sh - continueOnError: true - interactive: true - pipeline: variables: - AZURE_RESOURCE_GROUP @@ -58,4 +42,24 @@ pipeline: - AZURE_AI_EMBED_MODEL_VERSION - AZURE_AI_EMBED_DIMENSIONS - AZURE_AI_SEARCH_INDEX_NAME - - AZURE_EXISTING_AIPROJECT_CONNECTION_STRING \ No newline at end of file + - AZURE_EXISTING_AIPROJECT_CONNECTION_STRING + - AZURE_EXISTING_AIPROJECT_CONNECTION_STRING +resources: + ai-project: + type: ai.project + connStringFromEnvVar: AZURE_EXISTING_AIPROJECT_CONNECTION_STRING + api: + type: host.containerapp + uses: + - ai-project + port: 50505 + env: + # Required ENV VARS for the app to run + # AZURE_AIPROJECT_CONNECTION_STRING is automatically set by azd + - name: AZURE_AI_AGENT_NAME + value: agent-template-assistant + - name: AZURE_AI_AGENT_DEPLOYMENT_NAME + value: gpt-4o-mini + - name: RUNNING_IN_PRODUCTION + value: "true" + diff --git a/docs/deploy_customization.md b/docs/deploy_customization.md deleted file mode 100644 index 82c5c64..0000000 --- a/docs/deploy_customization.md +++ /dev/null @@ -1,90 +0,0 @@ - -# Getting Started with Agents Using Azure AI Foundry: Deployment customization - -This document describes how to customize the deployment of the Agents Chat with Azure AI Foundry. Once you follow the steps here, you can run `azd up` as described in the [Deploying](./README.md#deploying) steps. - -* [Disabling resources](#disabling-resources) -* [Customizing resource names](#customizing-resource-names) -* [Customizing model deployments](#customizing-model-deployments) - -## Disabling resources - -Disabling a resource will stop that resource from being created and deployed to your Azure Project. - -* To disable AI Search, run `azd env set USE_SEARCH_SERVICE false` -* To disable Application Insights, run `azd env set USE_APPLICATION_INSIGHTS false` -* To disable Container Registry, run `azd env set USE_CONTAINER_REGISTRY false` - -Once you disable these resources, they will not be deployed when you run `azd up`. - -## Customizing resource names - -By default, this template will use a naming convention with unique strings to prevent naming collisions within Azure. -To override default naming conventions, the following keys can be set: - -* `AZURE_AIHUB_NAME` - The name of the AI Foundry Hub resource -* `AZURE_AIPROJECT_NAME` - The name of the AI Foundry Project -* `AZURE_AIENDPOINT_NAME` - The name of the AI Foundry online endpoint used for deployments -* `AZURE_AISERVICES_NAME` - The name of the Azure AI service -* `AZURE_SEARCH_SERVICE_NAME` - The name of the Azure Search service -* `AZURE_STORAGE_ACCOUNT_NAME` - The name of the Storage Account -* `AZURE_KEYVAULT_NAME` - The name of the Key Vault -* `AZURE_CONTAINER_REGISTRY_NAME` - The name of the container registry -* `AZURE_APPLICATION_INSIGHTS_NAME` - The name of the Application Insights instance -* `AZURE_LOG_ANALYTICS_WORKSPACE_NAME` - The name of the Log Analytics workspace used by Application Insights - -To override any of those resource names, run `azd env set ` before running `azd up`. - -## Customizing model deployments - -For more information on the Azure OpenAI models and non-Microsoft models that can be used in your deployment, view the [list of models supported by Azure AI Agent Service](https://learn.microsoft.com/azure/ai-services/agents/concepts/model-region-support). - -To customize the model deployments, you can set the following environment variables: - -### Using a different chat model - -Change the agent model format (either OpenAI or Microsoft): - -```shell -azd env set AZURE_AI_AGENT_MODEL_FORMAT Microsoft -``` - -Change the agent model name: - -```shell -azd env set AZURE_AI_AGENT_MODEL_NAME gpt-4o-mini -``` - -Set the version of the agent model: - -```shell -azd env set AZURE_AI_AGENT_MODEL_VERSION 2024-07-18 -``` - -### Setting capacity and deployment SKU - -For quota regions, you may find yourself needing to modify the default capacity and deployment SKU. The default tokens per minute deployed in this template is 50,000. - -Change the capacity (in thousands of tokens per minute) of the agent deployment: - -```shell -azd env set AZURE_AI_AGENT_DEPLOYMENT_CAPACITY 50 -``` - -Change the SKU of the agent deployment: - -```shell -azd env set AZURE_AI_AGENT_DEPLOYMENT_SKU Standard -``` - -Change the capacity (in thousands of tokens per minute) of the embeddings deployment: - -```shell -azd env set AZURE_AI_EMBED_DEPLOYMENT_CAPACITY 50 -``` - -Change the SKU of the embeddings deployment: - -```shell -azd env set AZURE_AI_EMBED_DEPLOYMENT_SKU Standard -``` diff --git a/infra/abbreviations.json b/infra/abbreviations.json deleted file mode 100644 index 292beef..0000000 --- a/infra/abbreviations.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "analysisServicesServers": "as", - "apiManagementService": "apim-", - "appConfigurationStores": "appcs-", - "appManagedEnvironments": "cae-", - "appContainerApps": "ca-", - "authorizationPolicyDefinitions": "policy-", - "automationAutomationAccounts": "aa-", - "blueprintBlueprints": "bp-", - "blueprintBlueprintsArtifacts": "bpa-", - "cacheRedis": "redis-", - "cdnProfiles": "cdnp-", - "cdnProfilesEndpoints": "cdne-", - "cognitiveServicesAccounts": "cog-", - "cognitiveServicesFormRecognizer": "cog-fr-", - "cognitiveServicesTextAnalytics": "cog-ta-", - "computeAvailabilitySets": "avail-", - "computeCloudServices": "cld-", - "computeDiskEncryptionSets": "des", - "computeDisks": "disk", - "computeDisksOs": "osdisk", - "computeGalleries": "gal", - "computeSnapshots": "snap-", - "computeVirtualMachines": "vm", - "computeVirtualMachineScaleSets": "vmss-", - "containerInstanceContainerGroups": "ci", - "containerRegistryRegistries": "cr", - "containerServiceManagedClusters": "aks-", - "databricksWorkspaces": "dbw-", - "dataFactoryFactories": "adf-", - "dataLakeAnalyticsAccounts": "dla", - "dataLakeStoreAccounts": "dls", - "dataMigrationServices": "dms-", - "dBforMySQLServers": "mysql-", - "dBforPostgreSQLServers": "psql-", - "devicesIotHubs": "iot-", - "devicesProvisioningServices": "provs-", - "devicesProvisioningServicesCertificates": "pcert-", - "documentDBDatabaseAccounts": "cosmos-", - "eventGridDomains": "evgd-", - "eventGridDomainsTopics": "evgt-", - "eventGridEventSubscriptions": "evgs-", - "eventHubNamespaces": "evhns-", - "eventHubNamespacesEventHubs": "evh-", - "hdInsightClustersHadoop": "hadoop-", - "hdInsightClustersHbase": "hbase-", - "hdInsightClustersKafka": "kafka-", - "hdInsightClustersMl": "mls-", - "hdInsightClustersSpark": "spark-", - "hdInsightClustersStorm": "storm-", - "hybridComputeMachines": "arcs-", - "insightsActionGroups": "ag-", - "insightsComponents": "appi-", - "keyVaultVaults": "kv-", - "kubernetesConnectedClusters": "arck", - "kustoClusters": "dec", - "kustoClustersDatabases": "dedb", - "loadTesting": "lt-", - "logicIntegrationAccounts": "ia-", - "logicWorkflows": "logic-", - "machineLearningServicesWorkspaces": "mlw-", - "managedIdentityUserAssignedIdentities": "id-", - "managementManagementGroups": "mg-", - "migrateAssessmentProjects": "migr-", - "networkApplicationGateways": "agw-", - "networkApplicationSecurityGroups": "asg-", - "networkAzureFirewalls": "afw-", - "networkBastionHosts": "bas-", - "networkConnections": "con-", - "networkDnsZones": "dnsz-", - "networkExpressRouteCircuits": "erc-", - "networkFirewallPolicies": "afwp-", - "networkFirewallPoliciesWebApplication": "waf", - "networkFirewallPoliciesRuleGroups": "wafrg", - "networkFrontDoors": "fd-", - "networkFrontdoorWebApplicationFirewallPolicies": "fdfp-", - "networkLoadBalancersExternal": "lbe-", - "networkLoadBalancersInternal": "lbi-", - "networkLoadBalancersInboundNatRules": "rule-", - "networkLocalNetworkGateways": "lgw-", - "networkNatGateways": "ng-", - "networkNetworkInterfaces": "nic-", - "networkNetworkSecurityGroups": "nsg-", - "networkNetworkSecurityGroupsSecurityRules": "nsgsr-", - "networkNetworkWatchers": "nw-", - "networkPrivateDnsZones": "pdnsz-", - "networkPrivateLinkServices": "pl-", - "networkPublicIPAddresses": "pip-", - "networkPublicIPPrefixes": "ippre-", - "networkRouteFilters": "rf-", - "networkRouteTables": "rt-", - "networkRouteTablesRoutes": "udr-", - "networkTrafficManagerProfiles": "traf-", - "networkVirtualNetworkGateways": "vgw-", - "networkVirtualNetworks": "vnet-", - "networkVirtualNetworksSubnets": "snet-", - "networkVirtualNetworksVirtualNetworkPeerings": "peer-", - "networkVirtualWans": "vwan-", - "networkVpnGateways": "vpng-", - "networkVpnGatewaysVpnConnections": "vcn-", - "networkVpnGatewaysVpnSites": "vst-", - "notificationHubsNamespaces": "ntfns-", - "notificationHubsNamespacesNotificationHubs": "ntf-", - "operationalInsightsWorkspaces": "log-", - "portalDashboards": "dash-", - "powerBIDedicatedCapacities": "pbi-", - "purviewAccounts": "pview-", - "recoveryServicesVaults": "rsv-", - "resourcesResourceGroups": "rg-", - "searchSearchServices": "srch-", - "serviceBusNamespaces": "sb-", - "serviceBusNamespacesQueues": "sbq-", - "serviceBusNamespacesTopics": "sbt-", - "serviceEndPointPolicies": "se-", - "serviceFabricClusters": "sf-", - "signalRServiceSignalR": "sigr", - "sqlManagedInstances": "sqlmi-", - "sqlServers": "sql-", - "sqlServersDataWarehouse": "sqldw-", - "sqlServersDatabases": "sqldb-", - "sqlServersDatabasesStretch": "sqlstrdb-", - "storageStorageAccounts": "st", - "storageStorageAccountsVm": "stvm", - "storSimpleManagers": "ssimp", - "streamAnalyticsCluster": "asa-", - "synapseWorkspaces": "syn", - "synapseWorkspacesAnalyticsWorkspaces": "synw", - "synapseWorkspacesSqlPoolsDedicated": "syndp", - "synapseWorkspacesSqlPoolsSpark": "synsp", - "timeSeriesInsightsEnvironments": "tsi-", - "webServerFarms": "plan-", - "webSitesAppService": "app-", - "webSitesAppServiceEnvironment": "ase-", - "webSitesFunctions": "func-", - "webStaticSites": "stapp-" -} \ No newline at end of file diff --git a/infra/api.bicep b/infra/api.bicep deleted file mode 100644 index 7fe2170..0000000 --- a/infra/api.bicep +++ /dev/null @@ -1,90 +0,0 @@ -param name string -param location string = resourceGroup().location -param tags object = {} - -param identityName string -param containerAppsEnvironmentName string -param containerRegistryName string -param serviceName string = 'api' -param exists bool -param projectConnectionString string -param agentDeploymentName string -param searchConnectionName string -param embeddingDeploymentName string -param aiSearchIndexName string -param embeddingDeploymentDimensions string -param searchServiceEndpoint string -param agentName string -param agentID string - -resource apiIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { - name: identityName - location: location -} - -var env = [ - { - name: 'AZURE_CLIENT_ID' - value: apiIdentity.properties.clientId - } - { - name: 'AZURE_AIPROJECT_CONNECTION_STRING' - value: projectConnectionString - } - { - name: 'AZURE_AI_AGENT_NAME' - value: agentName - } - { - name: 'AZURE_AI_AGENT_ID' - value: agentID - } - { - name: 'AZURE_AI_AGENT_DEPLOYMENT_NAME' - value: agentDeploymentName - } - { - name: 'AZURE_AI_EMBED_DEPLOYMENT_NAME' - value: embeddingDeploymentName - } - { - name: 'AZURE_AI_SEARCH_INDEX_NAME' - value: aiSearchIndexName - } - { - name: 'AZURE_AI_EMBED_DIMENSIONS' - value: embeddingDeploymentDimensions - } - { - name: 'RUNNING_IN_PRODUCTION' - value: 'true' - } - { - name: 'AZURE_AI_SEARCH_CONNECTION_NAME' - value: searchConnectionName - } - { - name: 'AZURE_AI_SEARCH_ENDPOINT' - value: searchServiceEndpoint - } -] - -module app 'core/host/container-app-upsert.bicep' = { - name: '${serviceName}-container-app-module' - params: { - name: name - location: location - tags: union(tags, { 'azd-service-name': serviceName }) - identityName: apiIdentity.name - exists: exists - containerAppsEnvironmentName: containerAppsEnvironmentName - containerRegistryName: containerRegistryName - targetPort: 50505 - env: env - } -} - -output SERVICE_API_IDENTITY_PRINCIPAL_ID string = apiIdentity.properties.principalId -output SERVICE_API_NAME string = app.outputs.name -output SERVICE_API_URI string = app.outputs.uri -output SERVICE_API_IMAGE_NAME string = app.outputs.imageName diff --git a/infra/core/ai/cognitiveservices.bicep b/infra/core/ai/cognitiveservices.bicep deleted file mode 100644 index a3c7e2f..0000000 --- a/infra/core/ai/cognitiveservices.bicep +++ /dev/null @@ -1,57 +0,0 @@ -metadata description = 'Creates an Azure Cognitive Services instance.' -param name string -param location string = resourceGroup().location -param tags object = {} -@description('The custom subdomain name used to access the API. Defaults to the value of the name parameter.') -param customSubDomainName string = name -param disableLocalAuth bool = false -param deployments array = [] -param kind string = 'OpenAI' -//param kind string = 'AIServices' - -@allowed([ 'Enabled', 'Disabled' ]) -param publicNetworkAccess string = 'Enabled' -param sku object = { - name: 'S0' -} - -param allowedIpRules array = [] -param networkAcls object = empty(allowedIpRules) ? { - defaultAction: 'Allow' -} : { - ipRules: allowedIpRules - defaultAction: 'Deny' -} - -resource account 'Microsoft.CognitiveServices/accounts@2023-05-01' = { - name: name - location: location - tags: tags - kind: kind - properties: { - customSubDomainName: customSubDomainName - publicNetworkAccess: publicNetworkAccess - networkAcls: networkAcls - disableLocalAuth: disableLocalAuth - } - sku: sku -} - -@batchSize(1) -resource deployment 'Microsoft.CognitiveServices/accounts/deployments@2023-05-01' = [for deployment in deployments: { - parent: account - name: deployment.name - properties: { - model: deployment.model - raiPolicyName: contains(deployment, 'raiPolicyName') ? deployment.raiPolicyName : null - } - sku: contains(deployment, 'sku') ? deployment.sku : { - name: 'Standard' - capacity: 20 - } -}] - -output endpoint string = account.properties.endpoint -output endpoints object = account.properties.endpoints -output id string = account.id -output name string = account.name diff --git a/infra/core/ai/hub-dependencies.bicep b/infra/core/ai/hub-dependencies.bicep deleted file mode 100644 index 26e6ed0..0000000 --- a/infra/core/ai/hub-dependencies.bicep +++ /dev/null @@ -1,172 +0,0 @@ -param location string = resourceGroup().location -param tags object = {} - -@description('Name of the key vault') -param keyVaultName string -@description('Name of the storage account') -param storageAccountName string -@description('Name of the AI Service') -param aiServicesName string -@description('Array of OpenAI model deployments') -param aiServiceModelDeployments array = [] -@description('Name of the Log Analytics workspace') -param logAnalyticsName string = '' -@description('Name of the Application Insights instance') -param applicationInsightsName string = '' -@description('Name of the container registry') -param containerRegistryName string = '' -@description('Name of the Azure Cognitive Search service') -param searchServiceName string = '' - -module keyVault '../security/keyvault.bicep' = { - name: 'keyvault' - params: { - location: location - tags: tags - name: keyVaultName - } -} - -module storageAccount '../storage/storage-account.bicep' = { - name: 'storageAccount' - params: { - location: location - tags: tags - name: storageAccountName - containers: [ - { - name: 'default' - } - ] - files: [ - { - name: 'default' - } - ] - queues: [ - { - name: 'default' - } - ] - tables: [ - { - name: 'default' - } - ] - corsRules: [ - { - allowedOrigins: [ - 'https://mlworkspace.azure.ai' - 'https://ml.azure.com' - 'https://*.ml.azure.com' - 'https://ai.azure.com' - 'https://*.ai.azure.com' - 'https://mlworkspacecanary.azure.ai' - 'https://mlworkspace.azureml-test.net' - ] - allowedMethods: [ - 'GET' - 'HEAD' - 'POST' - 'PUT' - 'DELETE' - 'OPTIONS' - 'PATCH' - ] - maxAgeInSeconds: 1800 - exposedHeaders: [ - '*' - ] - allowedHeaders: [ - '*' - ] - } - ] - deleteRetentionPolicy: { - allowPermanentDelete: false - enabled: false - } - shareDeleteRetentionPolicy: { - enabled: true - days: 7 - } - } -} - -module logAnalytics '../monitor/loganalytics.bicep' = - if (!empty(logAnalyticsName)) { - name: 'logAnalytics' - params: { - location: location - tags: tags - name: logAnalyticsName - } - } - -module applicationInsights '../monitor/applicationinsights.bicep' = - if (!empty(applicationInsightsName) && !empty(logAnalyticsName)) { - name: 'applicationInsights' - params: { - location: location - tags: tags - name: applicationInsightsName - logAnalyticsWorkspaceId: !empty(logAnalyticsName) ? logAnalytics.outputs.id : '' - } - } - -module containerRegistry '../host/container-registry.bicep' = - if (!empty(containerRegistryName)) { - name: 'containerRegistry' - params: { - location: location - tags: tags - name: containerRegistryName - } - } - -module cognitiveServices '../ai/cognitiveservices.bicep' = { - name: 'cognitiveServices' - params: { - location: location - tags: tags - name: aiServicesName - kind: 'AIServices' - deployments: aiServiceModelDeployments - } -} - -module searchService '../search/search-services.bicep' = - if (!empty(searchServiceName)) { - name: 'searchService' - params: { - location: location - tags: tags - name: searchServiceName - semanticSearch: 'free' - authOptions: { aadOrApiKey: { aadAuthFailureMode: 'http401WithBearerChallenge'}} - } - } - -output keyVaultId string = keyVault.outputs.id -output keyVaultName string = keyVault.outputs.name -output keyVaultEndpoint string = keyVault.outputs.endpoint - -output storageAccountId string = storageAccount.outputs.id -output storageAccountName string = storageAccount.outputs.name - -output containerRegistryId string = !empty(containerRegistryName) ? containerRegistry.outputs.id : '' -output containerRegistryName string = !empty(containerRegistryName) ? containerRegistry.outputs.name : '' -output containerRegistryEndpoint string = !empty(containerRegistryName) ? containerRegistry.outputs.loginServer : '' - -output applicationInsightsId string = !empty(applicationInsightsName) ? applicationInsights.outputs.id : '' -output applicationInsightsName string = !empty(applicationInsightsName) ? applicationInsights.outputs.name : '' -output logAnalyticsWorkspaceId string = !empty(logAnalyticsName) ? logAnalytics.outputs.id : '' -output logAnalyticsWorkspaceName string = !empty(logAnalyticsName) ? logAnalytics.outputs.name : '' - -output aiServiceId string = cognitiveServices.outputs.id -output aiServicesName string = cognitiveServices.outputs.name -output aiServiceEndpoint string = cognitiveServices.outputs.endpoints['OpenAI Language Model Instance API'] - -output searchServiceId string = !empty(searchServiceName) ? searchService.outputs.id : '' -output searchServiceName string = !empty(searchServiceName) ? searchService.outputs.name : '' -output searchServiceEndpoint string = !empty(searchServiceName) ? searchService.outputs.endpoint : '' diff --git a/infra/core/ai/hub.bicep b/infra/core/ai/hub.bicep deleted file mode 100644 index e139896..0000000 --- a/infra/core/ai/hub.bicep +++ /dev/null @@ -1,105 +0,0 @@ -@description('The AI Foundry Hub Resource name') -param name string -@description('The display name of the AI Foundry Hub Resource') -param displayName string = name -@description('The storage account ID to use for the AI Foundry Hub Resource') -param storageAccountId string -@description('The key vault ID to use for the AI Foundry Hub Resource') -param keyVaultId string -@description('The application insights ID to use for the AI Foundry Hub Resource') -param applicationInsightsId string = '' -@description('The container registry ID to use for the AI Foundry Hub Resource') -param containerRegistryId string = '' -@description('The AI Services account name to use for the AI Foundry Hub Resource') -param aiServicesName string -@description('The AI Services connection name to use for the AI Foundry Hub Resource') -param aiServicesConnectionName string -@description('The Azure Cognitive Search service name to use for the AI Foundry Hub Resource') -param aiSearchName string = '' -@description('The Azure Cognitive Search service connection name to use for the AI Foundry Hub Resource') -param aiSearchConnectionName string - - -@description('The SKU name to use for the AI Foundry Hub Resource') -param skuName string = 'Basic' -@description('The SKU tier to use for the AI Foundry Hub Resource') -@allowed(['Basic', 'Free', 'Premium', 'Standard']) -param skuTier string = 'Basic' -@description('The public network access setting to use for the AI Foundry Hub Resource') -@allowed(['Enabled','Disabled']) -param publicNetworkAccess string = 'Enabled' - -param location string = resourceGroup().location -param tags object = {} - -resource hub 'Microsoft.MachineLearningServices/workspaces@2024-07-01-preview' = { - name: name - location: location - tags: tags - sku: { - name: skuName - tier: skuTier - } - kind: 'Hub' - identity: { - type: 'SystemAssigned' - } - properties: { - friendlyName: displayName - storageAccount: storageAccountId - keyVault: keyVaultId - applicationInsights: !empty(applicationInsightsId) ? applicationInsightsId : null - containerRegistry: !empty(containerRegistryId) ? containerRegistryId : null - hbiWorkspace: false - managedNetwork: { - isolationMode: 'Disabled' - } - v1LegacyMode: false - publicNetworkAccess: publicNetworkAccess - } - - resource aiServiceConnection 'connections' = { - name: aiServicesConnectionName - properties: { - category: 'AIServices' - authType: 'ApiKey' - isSharedToAll: true - target: aiService.properties.endpoint - metadata: { - ApiVersion: '2023-07-01-preview' - ApiType: 'azure' - ResourceId: aiService.id - } - credentials: { - key: aiService.listKeys().key1 - } - } - } - - resource searchConnection 'connections' = - if (!empty(aiSearchName)) { - name: aiSearchConnectionName - properties: { - category: 'CognitiveSearch' - authType: 'ApiKey' - isSharedToAll: true - target: 'https://${search.name}.search.windows.net/' - credentials: { - key: !empty(aiSearchName) ? search.listAdminKeys().primaryKey : '' - } - } - } -} - -resource aiService 'Microsoft.CognitiveServices/accounts@2023-05-01' existing = { - name: aiServicesName -} - -resource search 'Microsoft.Search/searchServices@2021-04-01-preview' existing = - if (!empty(aiSearchName)) { - name: aiSearchName - } - -output name string = hub.name -output id string = hub.id -output principalId string = hub.identity.principalId diff --git a/infra/core/ai/project.bicep b/infra/core/ai/project.bicep deleted file mode 100644 index 63ad04d..0000000 --- a/infra/core/ai/project.bicep +++ /dev/null @@ -1,76 +0,0 @@ -@description('The AI Foundry Hub Resource name') -param name string -@description('The display name of the AI Foundry Hub Resource') -param displayName string = name -@description('The name of the AI Foundry Hub Resource where this project should be created') -param hubName string -@description('The name of the key vault resource to grant access to the project') -param keyVaultName string - -@description('The SKU name to use for the AI Foundry Hub Resource') -param skuName string = 'Basic' -@description('The SKU tier to use for the AI Foundry Hub Resource') -@allowed(['Basic', 'Free', 'Premium', 'Standard']) -param skuTier string = 'Basic' -@description('The public network access setting to use for the AI Foundry Hub Resource') -@allowed(['Enabled','Disabled']) -param publicNetworkAccess string = 'Enabled' - -param location string = resourceGroup().location -param tags object = {} - -resource project 'Microsoft.MachineLearningServices/workspaces@2024-01-01-preview' = { - name: name - location: location - tags: tags - sku: { - name: skuName - tier: skuTier - } - kind: 'Project' - identity: { - type: 'SystemAssigned' - } - properties: { - friendlyName: displayName - hbiWorkspace: false - v1LegacyMode: false - publicNetworkAccess: publicNetworkAccess - hubResourceId: hub.id - } -} - -module keyVaultAccess '../security/keyvault-access.bicep' = { - name: 'keyvault-access' - params: { - keyVaultName: keyVaultName - principalId: project.identity.principalId - } -} - -module mlServiceRoleDataScientist '../security/role.bicep' = { - name: 'ml-service-role-data-scientist' - params: { - principalId: project.identity.principalId - roleDefinitionId: 'f6c7c914-8db3-469d-8ca1-694a8f32e121' - principalType: 'ServicePrincipal' - } -} - -module mlServiceRoleSecretsReader '../security/role.bicep' = { - name: 'ml-service-role-secrets-reader' - params: { - principalId: project.identity.principalId - roleDefinitionId: 'ea01e6af-a1c1-4350-9563-ad00f8c72ec5' - principalType: 'ServicePrincipal' - } -} - -resource hub 'Microsoft.MachineLearningServices/workspaces@2024-01-01-preview' existing = { - name: hubName -} - -output id string = project.id -output name string = project.name -output principalId string = project.identity.principalId -output discoveryUrl string = project.properties.discoveryUrl diff --git a/infra/core/config/configstore.bicep b/infra/core/config/configstore.bicep deleted file mode 100644 index 96818f1..0000000 --- a/infra/core/config/configstore.bicep +++ /dev/null @@ -1,48 +0,0 @@ -metadata description = 'Creates an Azure App Configuration store.' - -@description('The name for the Azure App Configuration store') -param name string - -@description('The Azure region/location for the Azure App Configuration store') -param location string = resourceGroup().location - -@description('Custom tags to apply to the Azure App Configuration store') -param tags object = {} - -@description('Specifies the names of the key-value resources. The name is a combination of key and label with $ as delimiter. The label is optional.') -param keyValueNames array = [] - -@description('Specifies the values of the key-value resources.') -param keyValueValues array = [] - -@description('The principal ID to grant access to the Azure App Configuration store') -param principalId string - -resource configStore 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = { - name: name - location: location - sku: { - name: 'standard' - } - tags: tags -} - -resource configStoreKeyValue 'Microsoft.AppConfiguration/configurationStores/keyValues@2023-03-01' = [for (item, i) in keyValueNames: { - parent: configStore - name: item - properties: { - value: keyValueValues[i] - tags: tags - } -}] - -module configStoreAccess '../security/configstore-access.bicep' = { - name: 'app-configuration-access' - params: { - configStoreName: name - principalId: principalId - } - dependsOn: [configStore] -} - -output endpoint string = configStore.properties.endpoint diff --git a/infra/core/database/cosmos/cosmos-account.bicep b/infra/core/database/cosmos/cosmos-account.bicep deleted file mode 100644 index 6f8747f..0000000 --- a/infra/core/database/cosmos/cosmos-account.bicep +++ /dev/null @@ -1,49 +0,0 @@ -metadata description = 'Creates an Azure Cosmos DB account.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' -param keyVaultName string - -@allowed([ 'GlobalDocumentDB', 'MongoDB', 'Parse' ]) -param kind string - -resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' = { - name: name - kind: kind - location: location - tags: tags - properties: { - consistencyPolicy: { defaultConsistencyLevel: 'Session' } - locations: [ - { - locationName: location - failoverPriority: 0 - isZoneRedundant: false - } - ] - databaseAccountOfferType: 'Standard' - enableAutomaticFailover: false - enableMultipleWriteLocations: false - apiProperties: (kind == 'MongoDB') ? { serverVersion: '4.2' } : {} - capabilities: [ { name: 'EnableServerless' } ] - } -} - -resource cosmosConnectionString 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - parent: keyVault - name: connectionStringKey - properties: { - value: cosmos.listConnectionStrings().connectionStrings[0].connectionString - } -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { - name: keyVaultName -} - -output connectionStringKey string = connectionStringKey -output endpoint string = cosmos.properties.documentEndpoint -output id string = cosmos.id -output name string = cosmos.name diff --git a/infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep b/infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep deleted file mode 100644 index 4aafbf3..0000000 --- a/infra/core/database/cosmos/mongo/cosmos-mongo-account.bicep +++ /dev/null @@ -1,23 +0,0 @@ -metadata description = 'Creates an Azure Cosmos DB for MongoDB account.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param keyVaultName string -param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' - -module cosmos '../../cosmos/cosmos-account.bicep' = { - name: 'cosmos-account' - params: { - name: name - location: location - connectionStringKey: connectionStringKey - keyVaultName: keyVaultName - kind: 'MongoDB' - tags: tags - } -} - -output connectionStringKey string = cosmos.outputs.connectionStringKey -output endpoint string = cosmos.outputs.endpoint -output id string = cosmos.outputs.id diff --git a/infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep b/infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep deleted file mode 100644 index 2a67057..0000000 --- a/infra/core/database/cosmos/mongo/cosmos-mongo-db.bicep +++ /dev/null @@ -1,47 +0,0 @@ -metadata description = 'Creates an Azure Cosmos DB for MongoDB account with a database.' -param accountName string -param databaseName string -param location string = resourceGroup().location -param tags object = {} - -param collections array = [] -param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING' -param keyVaultName string - -module cosmos 'cosmos-mongo-account.bicep' = { - name: 'cosmos-mongo-account' - params: { - name: accountName - location: location - keyVaultName: keyVaultName - tags: tags - connectionStringKey: connectionStringKey - } -} - -resource database 'Microsoft.DocumentDB/databaseAccounts/mongodbDatabases@2022-08-15' = { - name: '${accountName}/${databaseName}' - tags: tags - properties: { - resource: { id: databaseName } - } - - resource list 'collections' = [for collection in collections: { - name: collection.name - properties: { - resource: { - id: collection.id - shardKey: { _id: collection.shardKey } - indexes: [ { key: { keys: [ collection.indexKey ] } } ] - } - } - }] - - dependsOn: [ - cosmos - ] -} - -output connectionStringKey string = connectionStringKey -output databaseName string = databaseName -output endpoint string = cosmos.outputs.endpoint diff --git a/infra/core/database/cosmos/sql/cosmos-sql-account.bicep b/infra/core/database/cosmos/sql/cosmos-sql-account.bicep deleted file mode 100644 index 8431135..0000000 --- a/infra/core/database/cosmos/sql/cosmos-sql-account.bicep +++ /dev/null @@ -1,22 +0,0 @@ -metadata description = 'Creates an Azure Cosmos DB for NoSQL account.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param keyVaultName string - -module cosmos '../../cosmos/cosmos-account.bicep' = { - name: 'cosmos-account' - params: { - name: name - location: location - tags: tags - keyVaultName: keyVaultName - kind: 'GlobalDocumentDB' - } -} - -output connectionStringKey string = cosmos.outputs.connectionStringKey -output endpoint string = cosmos.outputs.endpoint -output id string = cosmos.outputs.id -output name string = cosmos.outputs.name diff --git a/infra/core/database/cosmos/sql/cosmos-sql-db.bicep b/infra/core/database/cosmos/sql/cosmos-sql-db.bicep deleted file mode 100644 index 265880d..0000000 --- a/infra/core/database/cosmos/sql/cosmos-sql-db.bicep +++ /dev/null @@ -1,74 +0,0 @@ -metadata description = 'Creates an Azure Cosmos DB for NoSQL account with a database.' -param accountName string -param databaseName string -param location string = resourceGroup().location -param tags object = {} - -param containers array = [] -param keyVaultName string -param principalIds array = [] - -module cosmos 'cosmos-sql-account.bicep' = { - name: 'cosmos-sql-account' - params: { - name: accountName - location: location - tags: tags - keyVaultName: keyVaultName - } -} - -resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2022-05-15' = { - name: '${accountName}/${databaseName}' - properties: { - resource: { id: databaseName } - } - - resource list 'containers' = [for container in containers: { - name: container.name - properties: { - resource: { - id: container.id - partitionKey: { paths: [ container.partitionKey ] } - } - options: {} - } - }] - - dependsOn: [ - cosmos - ] -} - -module roleDefinition 'cosmos-sql-role-def.bicep' = { - name: 'cosmos-sql-role-definition' - params: { - accountName: accountName - } - dependsOn: [ - cosmos - database - ] -} - -// We need batchSize(1) here because sql role assignments have to be done sequentially -@batchSize(1) -module userRole 'cosmos-sql-role-assign.bicep' = [for principalId in principalIds: if (!empty(principalId)) { - name: 'cosmos-sql-user-role-${uniqueString(principalId)}' - params: { - accountName: accountName - roleDefinitionId: roleDefinition.outputs.id - principalId: principalId - } - dependsOn: [ - cosmos - database - ] -}] - -output accountId string = cosmos.outputs.id -output accountName string = cosmos.outputs.name -output connectionStringKey string = cosmos.outputs.connectionStringKey -output databaseName string = databaseName -output endpoint string = cosmos.outputs.endpoint -output roleDefinitionId string = roleDefinition.outputs.id diff --git a/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep b/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep deleted file mode 100644 index 3949efe..0000000 --- a/infra/core/database/cosmos/sql/cosmos-sql-role-assign.bicep +++ /dev/null @@ -1,19 +0,0 @@ -metadata description = 'Creates a SQL role assignment under an Azure Cosmos DB account.' -param accountName string - -param roleDefinitionId string -param principalId string = '' - -resource role 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2022-05-15' = { - parent: cosmos - name: guid(roleDefinitionId, principalId, cosmos.id) - properties: { - principalId: principalId - roleDefinitionId: roleDefinitionId - scope: cosmos.id - } -} - -resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { - name: accountName -} diff --git a/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep b/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep deleted file mode 100644 index 778d6dc..0000000 --- a/infra/core/database/cosmos/sql/cosmos-sql-role-def.bicep +++ /dev/null @@ -1,30 +0,0 @@ -metadata description = 'Creates a SQL role definition under an Azure Cosmos DB account.' -param accountName string - -resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2022-08-15' = { - parent: cosmos - name: guid(cosmos.id, accountName, 'sql-role') - properties: { - assignableScopes: [ - cosmos.id - ] - permissions: [ - { - dataActions: [ - 'Microsoft.DocumentDB/databaseAccounts/readMetadata' - 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*' - 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*' - ] - notDataActions: [] - } - ] - roleName: 'Reader Writer' - type: 'CustomRole' - } -} - -resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = { - name: accountName -} - -output id string = roleDefinition.id diff --git a/infra/core/database/mysql/flexibleserver.bicep b/infra/core/database/mysql/flexibleserver.bicep deleted file mode 100644 index 8319f1c..0000000 --- a/infra/core/database/mysql/flexibleserver.bicep +++ /dev/null @@ -1,65 +0,0 @@ -metadata description = 'Creates an Azure Database for MySQL - Flexible Server.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param sku object -param storage object -param administratorLogin string -@secure() -param administratorLoginPassword string -param highAvailabilityMode string = 'Disabled' -param databaseNames array = [] -param allowAzureIPsFirewall bool = false -param allowAllIPsFirewall bool = false -param allowedSingleIPs array = [] - -// MySQL version -param version string - -resource mysqlServer 'Microsoft.DBforMySQL/flexibleServers@2023-06-30' = { - location: location - tags: tags - name: name - sku: sku - properties: { - version: version - administratorLogin: administratorLogin - administratorLoginPassword: administratorLoginPassword - storage: storage - highAvailability: { - mode: highAvailabilityMode - } - } - - resource database 'databases' = [for name in databaseNames: { - name: name - }] - - resource firewall_all 'firewallRules' = if (allowAllIPsFirewall) { - name: 'allow-all-IPs' - properties: { - startIpAddress: '0.0.0.0' - endIpAddress: '255.255.255.255' - } - } - - resource firewall_azure 'firewallRules' = if (allowAzureIPsFirewall) { - name: 'allow-all-azure-internal-IPs' - properties: { - startIpAddress: '0.0.0.0' - endIpAddress: '0.0.0.0' - } - } - - resource firewall_single 'firewallRules' = [for ip in allowedSingleIPs: { - name: 'allow-single-${replace(ip, '.', '')}' - properties: { - startIpAddress: ip - endIpAddress: ip - } - }] - -} - -output MYSQL_DOMAIN_NAME string = mysqlServer.properties.fullyQualifiedDomainName diff --git a/infra/core/database/postgresql/flexibleserver.bicep b/infra/core/database/postgresql/flexibleserver.bicep deleted file mode 100644 index 7e26b1a..0000000 --- a/infra/core/database/postgresql/flexibleserver.bicep +++ /dev/null @@ -1,65 +0,0 @@ -metadata description = 'Creates an Azure Database for PostgreSQL - Flexible Server.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param sku object -param storage object -param administratorLogin string -@secure() -param administratorLoginPassword string -param databaseNames array = [] -param allowAzureIPsFirewall bool = false -param allowAllIPsFirewall bool = false -param allowedSingleIPs array = [] - -// PostgreSQL version -param version string - -// Latest official version 2022-12-01 does not have Bicep types available -resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = { - location: location - tags: tags - name: name - sku: sku - properties: { - version: version - administratorLogin: administratorLogin - administratorLoginPassword: administratorLoginPassword - storage: storage - highAvailability: { - mode: 'Disabled' - } - } - - resource database 'databases' = [for name in databaseNames: { - name: name - }] - - resource firewall_all 'firewallRules' = if (allowAllIPsFirewall) { - name: 'allow-all-IPs' - properties: { - startIpAddress: '0.0.0.0' - endIpAddress: '255.255.255.255' - } - } - - resource firewall_azure 'firewallRules' = if (allowAzureIPsFirewall) { - name: 'allow-all-azure-internal-IPs' - properties: { - startIpAddress: '0.0.0.0' - endIpAddress: '0.0.0.0' - } - } - - resource firewall_single 'firewallRules' = [for ip in allowedSingleIPs: { - name: 'allow-single-${replace(ip, '.', '')}' - properties: { - startIpAddress: ip - endIpAddress: ip - } - }] - -} - -output POSTGRES_DOMAIN_NAME string = postgresServer.properties.fullyQualifiedDomainName diff --git a/infra/core/database/sqlserver/sqlserver.bicep b/infra/core/database/sqlserver/sqlserver.bicep deleted file mode 100644 index 84f2cc2..0000000 --- a/infra/core/database/sqlserver/sqlserver.bicep +++ /dev/null @@ -1,130 +0,0 @@ -metadata description = 'Creates an Azure SQL Server instance.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param appUser string = 'appUser' -param databaseName string -param keyVaultName string -param sqlAdmin string = 'sqlAdmin' -param connectionStringKey string = 'AZURE-SQL-CONNECTION-STRING' - -@secure() -param sqlAdminPassword string -@secure() -param appUserPassword string - -resource sqlServer 'Microsoft.Sql/servers@2022-05-01-preview' = { - name: name - location: location - tags: tags - properties: { - version: '12.0' - minimalTlsVersion: '1.2' - publicNetworkAccess: 'Enabled' - administratorLogin: sqlAdmin - administratorLoginPassword: sqlAdminPassword - } - - resource database 'databases' = { - name: databaseName - location: location - } - - resource firewall 'firewallRules' = { - name: 'Azure Services' - properties: { - // Allow all clients - // Note: range [0.0.0.0-0.0.0.0] means "allow all Azure-hosted clients only". - // This is not sufficient, because we also want to allow direct access from developer machine, for debugging purposes. - startIpAddress: '0.0.0.1' - endIpAddress: '255.255.255.254' - } - } -} - -resource sqlDeploymentScript 'Microsoft.Resources/deploymentScripts@2020-10-01' = { - name: '${name}-deployment-script' - location: location - kind: 'AzureCLI' - properties: { - azCliVersion: '2.37.0' - retentionInterval: 'PT1H' // Retain the script resource for 1 hour after it ends running - timeout: 'PT5M' // Five minutes - cleanupPreference: 'OnSuccess' - environmentVariables: [ - { - name: 'APPUSERNAME' - value: appUser - } - { - name: 'APPUSERPASSWORD' - secureValue: appUserPassword - } - { - name: 'DBNAME' - value: databaseName - } - { - name: 'DBSERVER' - value: sqlServer.properties.fullyQualifiedDomainName - } - { - name: 'SQLCMDPASSWORD' - secureValue: sqlAdminPassword - } - { - name: 'SQLADMIN' - value: sqlAdmin - } - ] - - scriptContent: ''' -wget https://github.com/microsoft/go-sqlcmd/releases/download/v0.8.1/sqlcmd-v0.8.1-linux-x64.tar.bz2 -tar x -f sqlcmd-v0.8.1-linux-x64.tar.bz2 -C . - -cat < ./initDb.sql -drop user if exists ${APPUSERNAME} -go -create user ${APPUSERNAME} with password = '${APPUSERPASSWORD}' -go -alter role db_owner add member ${APPUSERNAME} -go -SCRIPT_END - -./sqlcmd -S ${DBSERVER} -d ${DBNAME} -U ${SQLADMIN} -i ./initDb.sql - ''' - } -} - -resource sqlAdminPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - parent: keyVault - name: 'sqlAdminPassword' - properties: { - value: sqlAdminPassword - } -} - -resource appUserPasswordSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - parent: keyVault - name: 'appUserPassword' - properties: { - value: appUserPassword - } -} - -resource sqlAzureConnectionStringSercret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - parent: keyVault - name: connectionStringKey - properties: { - value: '${connectionString}; Password=${appUserPassword}' - } -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { - name: keyVaultName -} - -var connectionString = 'Server=${sqlServer.properties.fullyQualifiedDomainName}; Database=${sqlServer::database.name}; User=${appUser}' -output connectionStringKey string = connectionStringKey -output databaseName string = sqlServer::database.name diff --git a/infra/core/gateway/apim.bicep b/infra/core/gateway/apim.bicep deleted file mode 100644 index be7464f..0000000 --- a/infra/core/gateway/apim.bicep +++ /dev/null @@ -1,79 +0,0 @@ -metadata description = 'Creates an Azure API Management instance.' -param name string -param location string = resourceGroup().location -param tags object = {} - -@description('The email address of the owner of the service') -@minLength(1) -param publisherEmail string = 'noreply@microsoft.com' - -@description('The name of the owner of the service') -@minLength(1) -param publisherName string = 'n/a' - -@description('The pricing tier of this API Management service') -@allowed([ - 'Consumption' - 'Developer' - 'Standard' - 'Premium' -]) -param sku string = 'Consumption' - -@description('The instance size of this API Management service.') -@allowed([ 0, 1, 2 ]) -param skuCount int = 0 - -@description('Azure Application Insights Name') -param applicationInsightsName string - -resource apimService 'Microsoft.ApiManagement/service@2021-08-01' = { - name: name - location: location - tags: union(tags, { 'azd-service-name': name }) - sku: { - name: sku - capacity: (sku == 'Consumption') ? 0 : ((sku == 'Developer') ? 1 : skuCount) - } - properties: { - publisherEmail: publisherEmail - publisherName: publisherName - // Custom properties are not supported for Consumption SKU - customProperties: sku == 'Consumption' ? {} : { - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_GCM_SHA256': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA256': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA256': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_256_CBC_SHA': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TLS_RSA_WITH_AES_128_CBC_SHA': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Ciphers.TripleDes168': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls10': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Tls11': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Protocols.Ssl30': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls10': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Tls11': 'false' - 'Microsoft.WindowsAzure.ApiManagement.Gateway.Security.Backend.Protocols.Ssl30': 'false' - } - } -} - -resource apimLogger 'Microsoft.ApiManagement/service/loggers@2021-12-01-preview' = if (!empty(applicationInsightsName)) { - name: 'app-insights-logger' - parent: apimService - properties: { - credentials: { - instrumentationKey: applicationInsights.properties.InstrumentationKey - } - description: 'Logger to Azure Application Insights' - isBuffered: false - loggerType: 'applicationInsights' - resourceId: applicationInsights.id - } -} - -resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) { - name: applicationInsightsName -} - -output apimServiceName string = apimService.name diff --git a/infra/core/host/ai-environment.bicep b/infra/core/host/ai-environment.bicep deleted file mode 100644 index 9910d01..0000000 --- a/infra/core/host/ai-environment.bicep +++ /dev/null @@ -1,113 +0,0 @@ -@minLength(1) -@description('Primary location for all resources') -param location string - -@description('The AI Hub resource name.') -param hubName string -@description('The AI Project resource name.') -param projectName string -@description('The Key Vault resource name.') -param keyVaultName string -@description('The Storage Account resource name.') -param storageAccountName string -@description('The AI Services resource name.') -param aiServicesName string -@description('The AI Services connection name.') -param aiServicesConnectionName string -@description('The AI Services model deployments.') -param aiServiceModelDeployments array = [] -@description('The Log Analytics resource name.') -param logAnalyticsName string = '' -@description('The Application Insights resource name.') -param applicationInsightsName string = '' -@description('The Container Registry resource name.') -param containerRegistryName string = '' -@description('The Azure Search resource name.') -param searchServiceName string = '' -@description('The Azure Search connection name.') -param searchConnectionName string = '' -param tags object = {} - -module hubDependencies '../ai/hub-dependencies.bicep' = { - name: 'hubDependencies' - params: { - location: location - tags: tags - keyVaultName: keyVaultName - storageAccountName: storageAccountName - containerRegistryName: containerRegistryName - applicationInsightsName: applicationInsightsName - logAnalyticsName: logAnalyticsName - aiServicesName: aiServicesName - aiServiceModelDeployments: aiServiceModelDeployments - searchServiceName: searchServiceName - } -} - -module hub '../ai/hub.bicep' = { - name: 'hub' - params: { - location: location - tags: tags - name: hubName - displayName: hubName - keyVaultId: hubDependencies.outputs.keyVaultId - storageAccountId: hubDependencies.outputs.storageAccountId - containerRegistryId: hubDependencies.outputs.containerRegistryId - applicationInsightsId: hubDependencies.outputs.applicationInsightsId - aiServicesName: hubDependencies.outputs.aiServicesName - aiServicesConnectionName: aiServicesConnectionName - aiSearchName: hubDependencies.outputs.searchServiceName - aiSearchConnectionName: searchConnectionName - } -} - -module project '../ai/project.bicep' = { - name: 'project' - params: { - location: location - tags: tags - name: projectName - displayName: projectName - hubName: hub.outputs.name - keyVaultName: hubDependencies.outputs.keyVaultName - } -} - -// Outputs -// Resource Group -output resourceGroupName string = resourceGroup().name - -// Hub -output hubName string = hub.outputs.name -output hubPrincipalId string = hub.outputs.principalId - -// Project -output projectName string = project.outputs.name -output projectPrincipalId string = project.outputs.principalId - -// Key Vault -output keyVaultName string = hubDependencies.outputs.keyVaultName -output keyVaultEndpoint string = hubDependencies.outputs.keyVaultEndpoint - -// Application Insights -output applicationInsightsName string = hubDependencies.outputs.applicationInsightsName -output logAnalyticsWorkspaceName string = hubDependencies.outputs.logAnalyticsWorkspaceName - -// Container Registry -output containerRegistryName string = hubDependencies.outputs.containerRegistryName -output containerRegistryEndpoint string = hubDependencies.outputs.containerRegistryEndpoint - -// Storage Account -output storageAccountName string = hubDependencies.outputs.storageAccountName - -// AI Services -output aiServicesName string = hubDependencies.outputs.aiServicesName -output aiServiceEndpoint string = hubDependencies.outputs.aiServiceEndpoint - -// Search -output searchServiceName string = hubDependencies.outputs.searchServiceName -output searchServiceEndpoint string = hubDependencies.outputs.searchServiceEndpoint - -//Discoveryurl -output discoveryUrl string = project.outputs.discoveryUrl diff --git a/infra/core/host/aks-agent-pool.bicep b/infra/core/host/aks-agent-pool.bicep deleted file mode 100644 index 9c76435..0000000 --- a/infra/core/host/aks-agent-pool.bicep +++ /dev/null @@ -1,18 +0,0 @@ -metadata description = 'Adds an agent pool to an Azure Kubernetes Service (AKS) cluster.' -param clusterName string - -@description('The agent pool name') -param name string - -@description('The agent pool configuration') -param config object - -resource aksCluster 'Microsoft.ContainerService/managedClusters@2023-10-02-preview' existing = { - name: clusterName -} - -resource nodePool 'Microsoft.ContainerService/managedClusters/agentPools@2023-10-02-preview' = { - parent: aksCluster - name: name - properties: config -} diff --git a/infra/core/host/aks-managed-cluster.bicep b/infra/core/host/aks-managed-cluster.bicep deleted file mode 100644 index de562a6..0000000 --- a/infra/core/host/aks-managed-cluster.bicep +++ /dev/null @@ -1,140 +0,0 @@ -metadata description = 'Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool.' -@description('The name for the AKS managed cluster') -param name string - -@description('The name of the resource group for the managed resources of the AKS cluster') -param nodeResourceGroupName string = '' - -@description('The Azure region/location for the AKS resources') -param location string = resourceGroup().location - -@description('Custom tags to apply to the AKS resources') -param tags object = {} - -@description('Kubernetes Version') -param kubernetesVersion string = '1.27.7' - -@description('Whether RBAC is enabled for local accounts') -param enableRbac bool = true - -// Add-ons -@description('Whether web app routing (preview) add-on is enabled') -param webAppRoutingAddon bool = true - -// AAD Integration -@description('Enable Azure Active Directory integration') -param enableAad bool = false - -@description('Enable RBAC using AAD') -param enableAzureRbac bool = false - -@description('The Tenant ID associated to the Azure Active Directory') -param aadTenantId string = tenant().tenantId - -@description('The load balancer SKU to use for ingress into the AKS cluster') -@allowed([ 'basic', 'standard' ]) -param loadBalancerSku string = 'standard' - -@description('Network plugin used for building the Kubernetes network.') -@allowed([ 'azure', 'kubenet', 'none' ]) -param networkPlugin string = 'azure' - -@description('Network policy used for building the Kubernetes network.') -@allowed([ 'azure', 'calico' ]) -param networkPolicy string = 'azure' - -@description('If set to true, getting static credentials will be disabled for this cluster.') -param disableLocalAccounts bool = false - -@description('The managed cluster SKU.') -@allowed([ 'Free', 'Paid', 'Standard' ]) -param sku string = 'Free' - -@description('Configuration of AKS add-ons') -param addOns object = {} - -@description('The log analytics workspace id used for logging & monitoring') -param workspaceId string = '' - -@description('The node pool configuration for the System agent pool') -param systemPoolConfig object - -@description('The DNS prefix to associate with the AKS cluster') -param dnsPrefix string = '' - -resource aks 'Microsoft.ContainerService/managedClusters@2023-10-02-preview' = { - name: name - location: location - tags: tags - identity: { - type: 'SystemAssigned' - } - sku: { - name: 'Base' - tier: sku - } - properties: { - nodeResourceGroup: !empty(nodeResourceGroupName) ? nodeResourceGroupName : 'rg-mc-${name}' - kubernetesVersion: kubernetesVersion - dnsPrefix: empty(dnsPrefix) ? '${name}-dns' : dnsPrefix - enableRBAC: enableRbac - aadProfile: enableAad ? { - managed: true - enableAzureRBAC: enableAzureRbac - tenantID: aadTenantId - } : null - agentPoolProfiles: [ - systemPoolConfig - ] - networkProfile: { - loadBalancerSku: loadBalancerSku - networkPlugin: networkPlugin - networkPolicy: networkPolicy - } - disableLocalAccounts: disableLocalAccounts && enableAad - addonProfiles: addOns - ingressProfile: { - webAppRouting: { - enabled: webAppRoutingAddon - } - } - } -} - -var aksDiagCategories = [ - 'cluster-autoscaler' - 'kube-controller-manager' - 'kube-audit-admin' - 'guard' -] - -// TODO: Update diagnostics to be its own module -// Blocking issue: https://github.com/Azure/bicep/issues/622 -// Unable to pass in a `resource` scope or unable to use string interpolation in resource types -resource diagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(workspaceId)) { - name: 'aks-diagnostics' - scope: aks - properties: { - workspaceId: workspaceId - logs: [for category in aksDiagCategories: { - category: category - enabled: true - }] - metrics: [ - { - category: 'AllMetrics' - enabled: true - } - ] - } -} - -@description('The resource name of the AKS cluster') -output clusterName string = aks.name - -@description('The AKS cluster identity') -output clusterIdentity object = { - clientId: aks.properties.identityProfile.kubeletidentity.clientId - objectId: aks.properties.identityProfile.kubeletidentity.objectId - resourceId: aks.properties.identityProfile.kubeletidentity.resourceId -} diff --git a/infra/core/host/aks.bicep b/infra/core/host/aks.bicep deleted file mode 100644 index 536a534..0000000 --- a/infra/core/host/aks.bicep +++ /dev/null @@ -1,280 +0,0 @@ -metadata description = 'Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool as well as an additional user agent pool.' -@description('The name for the AKS managed cluster') -param name string - -@description('The name for the Azure container registry (ACR)') -param containerRegistryName string - -@description('The name of the connected log analytics workspace') -param logAnalyticsName string = '' - -@description('The name of the keyvault to grant access') -param keyVaultName string - -@description('The Azure region/location for the AKS resources') -param location string = resourceGroup().location - -@description('Custom tags to apply to the AKS resources') -param tags object = {} - -@description('AKS add-ons configuration') -param addOns object = { - azurePolicy: { - enabled: true - config: { - version: 'v2' - } - } - keyVault: { - enabled: true - config: { - enableSecretRotation: 'true' - rotationPollInterval: '2m' - } - } - openServiceMesh: { - enabled: false - config: {} - } - omsAgent: { - enabled: true - config: {} - } - applicationGateway: { - enabled: false - config: {} - } -} - -@description('The managed cluster SKU.') -@allowed([ 'Free', 'Paid', 'Standard' ]) -param sku string = 'Free' - -@description('The load balancer SKU to use for ingress into the AKS cluster') -@allowed([ 'basic', 'standard' ]) -param loadBalancerSku string = 'standard' - -@description('Network plugin used for building the Kubernetes network.') -@allowed([ 'azure', 'kubenet', 'none' ]) -param networkPlugin string = 'azure' - -@description('Network policy used for building the Kubernetes network.') -@allowed([ 'azure', 'calico' ]) -param networkPolicy string = 'azure' - -@description('The DNS prefix to associate with the AKS cluster') -param dnsPrefix string = '' - -@description('The name of the resource group for the managed resources of the AKS cluster') -param nodeResourceGroupName string = '' - -@allowed([ - 'CostOptimised' - 'Standard' - 'HighSpec' - 'Custom' -]) -@description('The System Pool Preset sizing') -param systemPoolType string = 'CostOptimised' - -@allowed([ - '' - 'CostOptimised' - 'Standard' - 'HighSpec' - 'Custom' -]) -@description('The User Pool Preset sizing') -param agentPoolType string = '' - -// Configure system / user agent pools -@description('Custom configuration of system node pool') -param systemPoolConfig object = {} -@description('Custom configuration of user node pool') -param agentPoolConfig object = {} - -@description('Id of the user or app to assign application roles') -param principalId string = '' - -@description('Kubernetes Version') -param kubernetesVersion string = '1.27.7' - -@description('The Tenant ID associated to the Azure Active Directory') -param aadTenantId string = tenant().tenantId - -@description('Whether RBAC is enabled for local accounts') -param enableRbac bool = true - -@description('If set to true, getting static credentials will be disabled for this cluster.') -param disableLocalAccounts bool = false - -@description('Enable RBAC using AAD') -param enableAzureRbac bool = false - -// Add-ons -@description('Whether web app routing (preview) add-on is enabled') -param webAppRoutingAddon bool = true - -// Configure AKS add-ons -var omsAgentConfig = (!empty(logAnalyticsName) && !empty(addOns.omsAgent) && addOns.omsAgent.enabled) ? union( - addOns.omsAgent, - { - config: { - logAnalyticsWorkspaceResourceID: logAnalytics.id - } - } -) : {} - -var addOnsConfig = union( - (!empty(addOns.azurePolicy) && addOns.azurePolicy.enabled) ? { azurepolicy: addOns.azurePolicy } : {}, - (!empty(addOns.keyVault) && addOns.keyVault.enabled) ? { azureKeyvaultSecretsProvider: addOns.keyVault } : {}, - (!empty(addOns.openServiceMesh) && addOns.openServiceMesh.enabled) ? { openServiceMesh: addOns.openServiceMesh } : {}, - (!empty(addOns.omsAgent) && addOns.omsAgent.enabled) ? { omsagent: omsAgentConfig } : {}, - (!empty(addOns.applicationGateway) && addOns.applicationGateway.enabled) ? { ingressApplicationGateway: addOns.applicationGateway } : {} -) - -// Link to existing log analytics workspace when available -resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' existing = if (!empty(logAnalyticsName)) { - name: logAnalyticsName -} - -var systemPoolSpec = !empty(systemPoolConfig) ? systemPoolConfig : nodePoolPresets[systemPoolType] - -// Create the primary AKS cluster resources and system node pool -module managedCluster 'aks-managed-cluster.bicep' = { - name: 'managed-cluster' - params: { - name: name - location: location - tags: tags - systemPoolConfig: union( - { name: 'npsystem', mode: 'System' }, - nodePoolBase, - systemPoolSpec - ) - nodeResourceGroupName: nodeResourceGroupName - sku: sku - dnsPrefix: dnsPrefix - kubernetesVersion: kubernetesVersion - addOns: addOnsConfig - workspaceId: !empty(logAnalyticsName) ? logAnalytics.id : '' - enableAad: enableAzureRbac && aadTenantId != '' - disableLocalAccounts: disableLocalAccounts - aadTenantId: aadTenantId - enableRbac: enableRbac - enableAzureRbac: enableAzureRbac - webAppRoutingAddon: webAppRoutingAddon - loadBalancerSku: loadBalancerSku - networkPlugin: networkPlugin - networkPolicy: networkPolicy - } -} - -var hasAgentPool = !empty(agentPoolConfig) || !empty(agentPoolType) -var agentPoolSpec = hasAgentPool && !empty(agentPoolConfig) ? agentPoolConfig : empty(agentPoolType) ? {} : nodePoolPresets[agentPoolType] - -// Create additional user agent pool when specified -module agentPool 'aks-agent-pool.bicep' = if (hasAgentPool) { - name: 'aks-node-pool' - params: { - clusterName: managedCluster.outputs.clusterName - name: 'npuserpool' - config: union({ name: 'npuser', mode: 'User' }, nodePoolBase, agentPoolSpec) - } -} - -// Creates container registry (ACR) -module containerRegistry 'container-registry.bicep' = { - name: 'container-registry' - params: { - name: containerRegistryName - location: location - tags: tags - workspaceId: !empty(logAnalyticsName) ? logAnalytics.id : '' - } -} - -// Grant ACR Pull access from cluster managed identity to container registry -module containerRegistryAccess '../security/registry-access.bicep' = { - name: 'cluster-container-registry-access' - params: { - containerRegistryName: containerRegistry.outputs.name - principalId: managedCluster.outputs.clusterIdentity.objectId - } -} - -// Give AKS cluster access to the specified principal -module clusterAccess '../security/aks-managed-cluster-access.bicep' = if (enableAzureRbac || disableLocalAccounts) { - name: 'cluster-access' - params: { - clusterName: managedCluster.outputs.clusterName - principalId: principalId - } -} - -// Give the AKS Cluster access to KeyVault -module clusterKeyVaultAccess '../security/keyvault-access.bicep' = { - name: 'cluster-keyvault-access' - params: { - keyVaultName: keyVaultName - principalId: managedCluster.outputs.clusterIdentity.objectId - } -} - -// Helpers for node pool configuration -var nodePoolBase = { - osType: 'Linux' - maxPods: 30 - type: 'VirtualMachineScaleSets' - upgradeSettings: { - maxSurge: '33%' - } -} - -var nodePoolPresets = { - CostOptimised: { - vmSize: 'Standard_B4ms' - count: 1 - minCount: 1 - maxCount: 3 - enableAutoScaling: true - availabilityZones: [] - } - Standard: { - vmSize: 'Standard_DS2_v2' - count: 3 - minCount: 3 - maxCount: 5 - enableAutoScaling: true - availabilityZones: [ - '1' - '2' - '3' - ] - } - HighSpec: { - vmSize: 'Standard_D4s_v3' - count: 3 - minCount: 3 - maxCount: 5 - enableAutoScaling: true - availabilityZones: [ - '1' - '2' - '3' - ] - } -} - -// Module outputs -@description('The resource name of the AKS cluster') -output clusterName string = managedCluster.outputs.clusterName - -@description('The AKS cluster identity') -output clusterIdentity object = managedCluster.outputs.clusterIdentity - -@description('The resource name of the ACR') -output containerRegistryName string = containerRegistry.outputs.name - -@description('The login server for the container registry') -output containerRegistryLoginServer string = containerRegistry.outputs.loginServer diff --git a/infra/core/host/appservice-appsettings.bicep b/infra/core/host/appservice-appsettings.bicep deleted file mode 100644 index f4b22f8..0000000 --- a/infra/core/host/appservice-appsettings.bicep +++ /dev/null @@ -1,17 +0,0 @@ -metadata description = 'Updates app settings for an Azure App Service.' -@description('The name of the app service resource within the current resource group scope') -param name string - -@description('The app settings to be applied to the app service') -@secure() -param appSettings object - -resource appService 'Microsoft.Web/sites@2022-03-01' existing = { - name: name -} - -resource settings 'Microsoft.Web/sites/config@2022-03-01' = { - name: 'appsettings' - parent: appService - properties: appSettings -} diff --git a/infra/core/host/appservice.bicep b/infra/core/host/appservice.bicep deleted file mode 100644 index bef4d2b..0000000 --- a/infra/core/host/appservice.bicep +++ /dev/null @@ -1,123 +0,0 @@ -metadata description = 'Creates an Azure App Service in an existing Azure App Service plan.' -param name string -param location string = resourceGroup().location -param tags object = {} - -// Reference Properties -param applicationInsightsName string = '' -param appServicePlanId string -param keyVaultName string = '' -param managedIdentity bool = !empty(keyVaultName) - -// Runtime Properties -@allowed([ - 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' -]) -param runtimeName string -param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' -param runtimeVersion string - -// Microsoft.Web/sites Properties -param kind string = 'app,linux' - -// Microsoft.Web/sites/config -param allowedOrigins array = [] -param alwaysOn bool = true -param appCommandLine string = '' -@secure() -param appSettings object = {} -param clientAffinityEnabled bool = false -param enableOryxBuild bool = contains(kind, 'linux') -param functionAppScaleLimit int = -1 -param linuxFxVersion string = runtimeNameAndVersion -param minimumElasticInstanceCount int = -1 -param numberOfWorkers int = -1 -param scmDoBuildDuringDeployment bool = false -param use32BitWorkerProcess bool = false -param ftpsState string = 'FtpsOnly' -param healthCheckPath string = '' - -resource appService 'Microsoft.Web/sites@2022-03-01' = { - name: name - location: location - tags: tags - kind: kind - properties: { - serverFarmId: appServicePlanId - siteConfig: { - linuxFxVersion: linuxFxVersion - alwaysOn: alwaysOn - ftpsState: ftpsState - minTlsVersion: '1.2' - appCommandLine: appCommandLine - numberOfWorkers: numberOfWorkers != -1 ? numberOfWorkers : null - minimumElasticInstanceCount: minimumElasticInstanceCount != -1 ? minimumElasticInstanceCount : null - use32BitWorkerProcess: use32BitWorkerProcess - functionAppScaleLimit: functionAppScaleLimit != -1 ? functionAppScaleLimit : null - healthCheckPath: healthCheckPath - cors: { - allowedOrigins: union([ 'https://portal.azure.com', 'https://ms.portal.azure.com' ], allowedOrigins) - } - } - clientAffinityEnabled: clientAffinityEnabled - httpsOnly: true - } - - identity: { type: managedIdentity ? 'SystemAssigned' : 'None' } - - resource basicPublishingCredentialsPoliciesFtp 'basicPublishingCredentialsPolicies' = { - name: 'ftp' - properties: { - allow: false - } - } - - resource basicPublishingCredentialsPoliciesScm 'basicPublishingCredentialsPolicies' = { - name: 'scm' - properties: { - allow: false - } - } -} - -// Updates to the single Microsoft.sites/web/config resources that need to be performed sequentially -// sites/web/config 'appsettings' -module configAppSettings 'appservice-appsettings.bicep' = { - name: '${name}-appSettings' - params: { - name: appService.name - appSettings: union(appSettings, - { - SCM_DO_BUILD_DURING_DEPLOYMENT: string(scmDoBuildDuringDeployment) - ENABLE_ORYX_BUILD: string(enableOryxBuild) - }, - runtimeName == 'python' && appCommandLine == '' ? { PYTHON_ENABLE_GUNICORN_MULTIWORKERS: 'true'} : {}, - !empty(applicationInsightsName) ? { APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights.properties.ConnectionString } : {}, - !empty(keyVaultName) ? { AZURE_KEY_VAULT_ENDPOINT: keyVault.properties.vaultUri } : {}) - } -} - -// sites/web/config 'logs' -resource configLogs 'Microsoft.Web/sites/config@2022-03-01' = { - name: 'logs' - parent: appService - properties: { - applicationLogs: { fileSystem: { level: 'Verbose' } } - detailedErrorMessages: { enabled: true } - failedRequestsTracing: { enabled: true } - httpLogs: { fileSystem: { enabled: true, retentionInDays: 1, retentionInMb: 35 } } - } - dependsOn: [configAppSettings] -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = if (!(empty(keyVaultName))) { - name: keyVaultName -} - -resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) { - name: applicationInsightsName -} - -output identityPrincipalId string = managedIdentity ? appService.identity.principalId : '' -output name string = appService.name -output uri string = 'https://${appService.properties.defaultHostName}' diff --git a/infra/core/host/appserviceplan.bicep b/infra/core/host/appserviceplan.bicep deleted file mode 100644 index 2e37e04..0000000 --- a/infra/core/host/appserviceplan.bicep +++ /dev/null @@ -1,22 +0,0 @@ -metadata description = 'Creates an Azure App Service plan.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param kind string = '' -param reserved bool = true -param sku object - -resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { - name: name - location: location - tags: tags - sku: sku - kind: kind - properties: { - reserved: reserved - } -} - -output id string = appServicePlan.id -output name string = appServicePlan.name diff --git a/infra/core/host/container-app-upsert.bicep b/infra/core/host/container-app-upsert.bicep deleted file mode 100644 index 5e05f89..0000000 --- a/infra/core/host/container-app-upsert.bicep +++ /dev/null @@ -1,110 +0,0 @@ -metadata description = 'Creates or updates an existing Azure Container App.' -param name string -param location string = resourceGroup().location -param tags object = {} - -@description('The environment name for the container apps') -param containerAppsEnvironmentName string - -@description('The number of CPU cores allocated to a single container instance, e.g., 0.5') -param containerCpuCoreCount string = '0.5' - -@description('The maximum number of replicas to run. Must be at least 1.') -@minValue(1) -param containerMaxReplicas int = 10 - -@description('The amount of memory allocated to a single container instance, e.g., 1Gi') -param containerMemory string = '1.0Gi' - -@description('The minimum number of replicas to run. Must be at least 1.') -@minValue(1) -param containerMinReplicas int = 1 - -@description('The name of the container') -param containerName string = 'main' - -@description('The name of the container registry') -param containerRegistryName string = '' - -@description('Hostname suffix for container registry. Set when deploying to sovereign clouds') -param containerRegistryHostSuffix string = 'azurecr.io' - -@allowed([ 'http', 'grpc' ]) -@description('The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC') -param daprAppProtocol string = 'http' - -@description('Enable or disable Dapr for the container app') -param daprEnabled bool = false - -@description('The Dapr app ID') -param daprAppId string = containerName - -@description('Specifies if the resource already exists') -param exists bool = false - -@description('Specifies if Ingress is enabled for the container app') -param ingressEnabled bool = true - -@description('The type of identity for the resource') -@allowed([ 'None', 'SystemAssigned', 'UserAssigned' ]) -param identityType string = 'None' - -@description('The name of the user-assigned identity') -param identityName string = '' - -@description('The name of the container image') -param imageName string = '' - -@description('The secrets required for the container') -@secure() -param secrets object = {} - -@description('The environment variables for the container') -param env array = [] - -@description('Specifies if the resource ingress is exposed externally') -param external bool = true - -@description('The service binds associated with the container') -param serviceBinds array = [] - -@description('The target port for the container') -param targetPort int = 80 - -resource existingApp 'Microsoft.App/containerApps@2023-05-02-preview' existing = if (exists) { - name: name -} - -module app 'container-app.bicep' = { - name: '${deployment().name}-update' - params: { - name: name - location: location - tags: tags - identityType: identityType - identityName: identityName - ingressEnabled: ingressEnabled - containerName: containerName - containerAppsEnvironmentName: containerAppsEnvironmentName - containerRegistryName: containerRegistryName - containerRegistryHostSuffix: containerRegistryHostSuffix - containerCpuCoreCount: containerCpuCoreCount - containerMemory: containerMemory - containerMinReplicas: containerMinReplicas - containerMaxReplicas: containerMaxReplicas - daprEnabled: daprEnabled - daprAppId: daprAppId - daprAppProtocol: daprAppProtocol - secrets: secrets - external: external - env: env - imageName: !empty(imageName) ? imageName : exists ? existingApp.properties.template.containers[0].image : '' - targetPort: targetPort - serviceBinds: serviceBinds - } -} - -output defaultDomain string = app.outputs.defaultDomain -output imageName string = app.outputs.imageName -output name string = app.outputs.name -output uri string = app.outputs.uri diff --git a/infra/core/host/container-app.bicep b/infra/core/host/container-app.bicep deleted file mode 100644 index c64fc82..0000000 --- a/infra/core/host/container-app.bicep +++ /dev/null @@ -1,169 +0,0 @@ -metadata description = 'Creates a container app in an Azure Container App environment.' -param name string -param location string = resourceGroup().location -param tags object = {} - -@description('Allowed origins') -param allowedOrigins array = [] - -@description('Name of the environment for container apps') -param containerAppsEnvironmentName string - -@description('CPU cores allocated to a single container instance, e.g., 0.5') -param containerCpuCoreCount string = '0.5' - -@description('The maximum number of replicas to run. Must be at least 1.') -@minValue(1) -param containerMaxReplicas int = 10 - -@description('Memory allocated to a single container instance, e.g., 1Gi') -param containerMemory string = '1.0Gi' - -@description('The minimum number of replicas to run. Must be at least 1.') -param containerMinReplicas int = 1 - -@description('The name of the container') -param containerName string = 'main' - -@description('The name of the container registry') -param containerRegistryName string = '' - -@description('Hostname suffix for container registry. Set when deploying to sovereign clouds') -param containerRegistryHostSuffix string = 'azurecr.io' - -@description('The protocol used by Dapr to connect to the app, e.g., http or grpc') -@allowed([ 'http', 'grpc' ]) -param daprAppProtocol string = 'http' - -@description('The Dapr app ID') -param daprAppId string = containerName - -@description('Enable Dapr') -param daprEnabled bool = false - -@description('The environment variables for the container') -param env array = [] - -@description('Specifies if the resource ingress is exposed externally') -param external bool = true - -@description('The name of the user-assigned identity') -param identityName string = '' - -@description('The type of identity for the resource') -@allowed([ 'None', 'SystemAssigned', 'UserAssigned' ]) -param identityType string = 'None' - -@description('The name of the container image') -param imageName string = '' - -@description('Specifies if Ingress is enabled for the container app') -param ingressEnabled bool = true - -param revisionMode string = 'Single' - -@description('The secrets required for the container') -@secure() -param secrets object = {} - -@description('The service binds associated with the container') -param serviceBinds array = [] - -@description('The name of the container apps add-on to use. e.g. redis') -param serviceType string = '' - -@description('The target port for the container') -param targetPort int = 80 - -resource userIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (!empty(identityName)) { - name: identityName -} - -// Private registry support requires both an ACR name and a User Assigned managed identity -var usePrivateRegistry = !empty(identityName) && !empty(containerRegistryName) - -// Automatically set to `UserAssigned` when an `identityName` has been set -var normalizedIdentityType = !empty(identityName) ? 'UserAssigned' : identityType - -module containerRegistryAccess '../security/registry-access.bicep' = if (usePrivateRegistry) { - name: '${deployment().name}-registry-access' - params: { - containerRegistryName: containerRegistryName - principalId: usePrivateRegistry ? userIdentity.properties.principalId : '' - } -} - -resource app 'Microsoft.App/containerApps@2023-05-02-preview' = { - name: name - location: location - tags: tags - // It is critical that the identity is granted ACR pull access before the app is created - // otherwise the container app will throw a provision error - // This also forces us to use an user assigned managed identity since there would no way to - // provide the system assigned identity with the ACR pull access before the app is created - dependsOn: usePrivateRegistry ? [ containerRegistryAccess ] : [] - identity: { - type: normalizedIdentityType - userAssignedIdentities: !empty(identityName) && normalizedIdentityType == 'UserAssigned' ? { '${userIdentity.id}': {} } : null - } - properties: { - managedEnvironmentId: containerAppsEnvironment.id - configuration: { - activeRevisionsMode: revisionMode - ingress: ingressEnabled ? { - external: external - targetPort: targetPort - transport: 'auto' - corsPolicy: { - allowedOrigins: union([ 'https://portal.azure.com', 'https://ms.portal.azure.com' ], allowedOrigins) - } - } : null - dapr: daprEnabled ? { - enabled: true - appId: daprAppId - appProtocol: daprAppProtocol - appPort: ingressEnabled ? targetPort : 0 - } : { enabled: false } - secrets: [for secret in items(secrets): { - name: secret.key - value: secret.value - }] - service: !empty(serviceType) ? { type: serviceType } : null - registries: usePrivateRegistry ? [ - { - server: '${containerRegistryName}.${containerRegistryHostSuffix}' - identity: userIdentity.id - } - ] : [] - } - template: { - serviceBinds: !empty(serviceBinds) ? serviceBinds : null - containers: [ - { - image: !empty(imageName) ? imageName : 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' - name: containerName - env: env - resources: { - cpu: json(containerCpuCoreCount) - memory: containerMemory - } - } - ] - scale: { - minReplicas: containerMinReplicas - maxReplicas: containerMaxReplicas - } - } - } -} - -resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' existing = { - name: containerAppsEnvironmentName -} - -output defaultDomain string = containerAppsEnvironment.properties.defaultDomain -output identityPrincipalId string = normalizedIdentityType == 'None' ? '' : (empty(identityName) ? app.identity.principalId : userIdentity.properties.principalId) -output imageName string = imageName -output name string = app.name -output serviceBind object = !empty(serviceType) ? { serviceId: app.id, name: name } : {} -output uri string = ingressEnabled ? 'https://${app.properties.configuration.ingress.fqdn}' : '' diff --git a/infra/core/host/container-apps-environment.bicep b/infra/core/host/container-apps-environment.bicep deleted file mode 100644 index 20f4632..0000000 --- a/infra/core/host/container-apps-environment.bicep +++ /dev/null @@ -1,41 +0,0 @@ -metadata description = 'Creates an Azure Container Apps environment.' -param name string -param location string = resourceGroup().location -param tags object = {} - -@description('Name of the Application Insights resource') -param applicationInsightsName string = '' - -@description('Specifies if Dapr is enabled') -param daprEnabled bool = false - -@description('Name of the Log Analytics workspace') -param logAnalyticsWorkspaceName string - -resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { - name: name - location: location - tags: tags - properties: { - appLogsConfiguration: { - destination: 'log-analytics' - logAnalyticsConfiguration: { - customerId: logAnalyticsWorkspace.properties.customerId - sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey - } - } - daprAIInstrumentationKey: daprEnabled && !empty(applicationInsightsName) ? applicationInsights.properties.InstrumentationKey : '' - } -} - -resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = { - name: logAnalyticsWorkspaceName -} - -resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (daprEnabled && !empty(applicationInsightsName)) { - name: applicationInsightsName -} - -output defaultDomain string = containerAppsEnvironment.properties.defaultDomain -output id string = containerAppsEnvironment.id -output name string = containerAppsEnvironment.name diff --git a/infra/core/host/container-apps.bicep b/infra/core/host/container-apps.bicep deleted file mode 100644 index 1c656e2..0000000 --- a/infra/core/host/container-apps.bicep +++ /dev/null @@ -1,40 +0,0 @@ -metadata description = 'Creates an Azure Container Registry and an Azure Container Apps environment.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param containerAppsEnvironmentName string -param containerRegistryName string -param containerRegistryResourceGroupName string = '' -param containerRegistryAdminUserEnabled bool = false -param logAnalyticsWorkspaceName string -param applicationInsightsName string = '' - -module containerAppsEnvironment 'container-apps-environment.bicep' = { - name: '${name}-container-apps-environment' - params: { - name: containerAppsEnvironmentName - location: location - tags: tags - logAnalyticsWorkspaceName: logAnalyticsWorkspaceName - applicationInsightsName: applicationInsightsName - } -} - -module containerRegistry 'container-registry.bicep' = { - name: '${name}-container-registry' - scope: !empty(containerRegistryResourceGroupName) ? resourceGroup(containerRegistryResourceGroupName) : resourceGroup() - params: { - name: containerRegistryName - location: location - adminUserEnabled: containerRegistryAdminUserEnabled - tags: tags - } -} - -output defaultDomain string = containerAppsEnvironment.outputs.defaultDomain -output environmentName string = containerAppsEnvironment.outputs.name -output environmentId string = containerAppsEnvironment.outputs.id - -output registryLoginServer string = containerRegistry.outputs.loginServer -output registryName string = containerRegistry.outputs.name diff --git a/infra/core/host/container-registry.bicep b/infra/core/host/container-registry.bicep deleted file mode 100644 index d14731c..0000000 --- a/infra/core/host/container-registry.bicep +++ /dev/null @@ -1,137 +0,0 @@ -metadata description = 'Creates an Azure Container Registry.' -param name string -param location string = resourceGroup().location -param tags object = {} - -@description('Indicates whether admin user is enabled') -param adminUserEnabled bool = false - -@description('Indicates whether anonymous pull is enabled') -param anonymousPullEnabled bool = false - -@description('Azure ad authentication as arm policy settings') -param azureADAuthenticationAsArmPolicy object = { - status: 'enabled' -} - -@description('Indicates whether data endpoint is enabled') -param dataEndpointEnabled bool = false - -@description('Encryption settings') -param encryption object = { - status: 'disabled' -} - -@description('Export policy settings') -param exportPolicy object = { - status: 'enabled' -} - -@description('Metadata search settings') -param metadataSearch string = 'Disabled' - -@description('Options for bypassing network rules') -param networkRuleBypassOptions string = 'AzureServices' - -@description('Public network access setting') -param publicNetworkAccess string = 'Enabled' - -@description('Quarantine policy settings') -param quarantinePolicy object = { - status: 'disabled' -} - -@description('Retention policy settings') -param retentionPolicy object = { - days: 7 - status: 'disabled' -} - -@description('Scope maps setting') -param scopeMaps array = [] - -@description('SKU settings') -param sku object = { - name: 'Basic' -} - -@description('Soft delete policy settings') -param softDeletePolicy object = { - retentionDays: 7 - status: 'disabled' -} - -@description('Trust policy settings') -param trustPolicy object = { - type: 'Notary' - status: 'disabled' -} - -@description('Zone redundancy setting') -param zoneRedundancy string = 'Disabled' - -@description('The log analytics workspace ID used for logging and monitoring') -param workspaceId string = '' - -// 2023-11-01-preview needed for metadataSearch -resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-11-01-preview' = { - name: name - location: location - tags: tags - sku: sku - properties: { - adminUserEnabled: adminUserEnabled - anonymousPullEnabled: anonymousPullEnabled - dataEndpointEnabled: dataEndpointEnabled - encryption: encryption - metadataSearch: metadataSearch - networkRuleBypassOptions: networkRuleBypassOptions - policies:{ - quarantinePolicy: quarantinePolicy - trustPolicy: trustPolicy - retentionPolicy: retentionPolicy - exportPolicy: exportPolicy - azureADAuthenticationAsArmPolicy: azureADAuthenticationAsArmPolicy - softDeletePolicy: softDeletePolicy - } - publicNetworkAccess: publicNetworkAccess - zoneRedundancy: zoneRedundancy - } - - resource scopeMap 'scopeMaps' = [for scopeMap in scopeMaps: { - name: scopeMap.name - properties: scopeMap.properties - }] -} - -// TODO: Update diagnostics to be its own module -// Blocking issue: https://github.com/Azure/bicep/issues/622 -// Unable to pass in a `resource` scope or unable to use string interpolation in resource types -resource diagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(workspaceId)) { - name: 'registry-diagnostics' - scope: containerRegistry - properties: { - workspaceId: workspaceId - logs: [ - { - category: 'ContainerRegistryRepositoryEvents' - enabled: true - } - { - category: 'ContainerRegistryLoginEvents' - enabled: true - } - ] - metrics: [ - { - category: 'AllMetrics' - enabled: true - timeGrain: 'PT1M' - } - ] - } -} - -output id string = containerRegistry.id -output loginServer string = containerRegistry.properties.loginServer -output name string = containerRegistry.name diff --git a/infra/core/host/functions.bicep b/infra/core/host/functions.bicep deleted file mode 100644 index 7070a2c..0000000 --- a/infra/core/host/functions.bicep +++ /dev/null @@ -1,86 +0,0 @@ -metadata description = 'Creates an Azure Function in an existing Azure App Service plan.' -param name string -param location string = resourceGroup().location -param tags object = {} - -// Reference Properties -param applicationInsightsName string = '' -param appServicePlanId string -param keyVaultName string = '' -param managedIdentity bool = !empty(keyVaultName) -param storageAccountName string - -// Runtime Properties -@allowed([ - 'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom' -]) -param runtimeName string -param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}' -param runtimeVersion string - -// Function Settings -@allowed([ - '~4', '~3', '~2', '~1' -]) -param extensionVersion string = '~4' - -// Microsoft.Web/sites Properties -param kind string = 'functionapp,linux' - -// Microsoft.Web/sites/config -param allowedOrigins array = [] -param alwaysOn bool = true -param appCommandLine string = '' -@secure() -param appSettings object = {} -param clientAffinityEnabled bool = false -param enableOryxBuild bool = contains(kind, 'linux') -param functionAppScaleLimit int = -1 -param linuxFxVersion string = runtimeNameAndVersion -param minimumElasticInstanceCount int = -1 -param numberOfWorkers int = -1 -param scmDoBuildDuringDeployment bool = true -param use32BitWorkerProcess bool = false -param healthCheckPath string = '' - -module functions 'appservice.bicep' = { - name: '${name}-functions' - params: { - name: name - location: location - tags: tags - allowedOrigins: allowedOrigins - alwaysOn: alwaysOn - appCommandLine: appCommandLine - applicationInsightsName: applicationInsightsName - appServicePlanId: appServicePlanId - appSettings: union(appSettings, { - AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}' - FUNCTIONS_EXTENSION_VERSION: extensionVersion - FUNCTIONS_WORKER_RUNTIME: runtimeName - }) - clientAffinityEnabled: clientAffinityEnabled - enableOryxBuild: enableOryxBuild - functionAppScaleLimit: functionAppScaleLimit - healthCheckPath: healthCheckPath - keyVaultName: keyVaultName - kind: kind - linuxFxVersion: linuxFxVersion - managedIdentity: managedIdentity - minimumElasticInstanceCount: minimumElasticInstanceCount - numberOfWorkers: numberOfWorkers - runtimeName: runtimeName - runtimeVersion: runtimeVersion - runtimeNameAndVersion: runtimeNameAndVersion - scmDoBuildDuringDeployment: scmDoBuildDuringDeployment - use32BitWorkerProcess: use32BitWorkerProcess - } -} - -resource storage 'Microsoft.Storage/storageAccounts@2021-09-01' existing = { - name: storageAccountName -} - -output identityPrincipalId string = managedIdentity ? functions.outputs.identityPrincipalId : '' -output name string = functions.outputs.name -output uri string = functions.outputs.uri diff --git a/infra/core/host/ml-online-endpoint.bicep b/infra/core/host/ml-online-endpoint.bicep deleted file mode 100644 index cf03e79..0000000 --- a/infra/core/host/ml-online-endpoint.bicep +++ /dev/null @@ -1,82 +0,0 @@ -metadata description = 'Creates an Azure Container Registry.' -param name string -param serviceName string -param location string = resourceGroup().location -param tags object = {} -param aiProjectName string -param aiHubName string -param keyVaultName string -param kind string = 'Managed' -param authMode string = 'Key' - -resource endpoint 'Microsoft.MachineLearningServices/workspaces/onlineEndpoints@2023-10-01' = { - name: name - location: location - parent: workspace - kind: kind - tags: union(tags, { 'azd-service-name': serviceName }) - identity: { - type: 'SystemAssigned' - } - properties: { - authMode: authMode - } -} - -var azureMLDataScientist = resourceId('Microsoft.Authorization/roleDefinitions', 'f6c7c914-8db3-469d-8ca1-694a8f32e121') - -resource azureMLDataScientistRoleHub 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(subscription().id, resourceGroup().id, aiHubName, name, azureMLDataScientist) - scope: hubWorkspace - properties: { - principalId: endpoint.identity.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: azureMLDataScientist - } -} - -resource azureMLDataScientistRoleWorkspace 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(subscription().id, resourceGroup().id, aiProjectName, name, azureMLDataScientist) - scope: workspace - properties: { - principalId: endpoint.identity.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: azureMLDataScientist - } -} - -var azureMLWorkspaceConnectionSecretsReader = resourceId( - 'Microsoft.Authorization/roleDefinitions', - 'ea01e6af-a1c1-4350-9563-ad00f8c72ec5' -) - -resource azureMLWorkspaceConnectionSecretsReaderRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(subscription().id, resourceGroup().id, aiProjectName, name, azureMLWorkspaceConnectionSecretsReader) - scope: endpoint - properties: { - principalId: endpoint.identity.principalId - principalType: 'ServicePrincipal' - roleDefinitionId: azureMLWorkspaceConnectionSecretsReader - } -} - -module keyVaultAccess '../security/keyvault-access.bicep' = { - name: '${name}-keyvault-access' - params: { - keyVaultName: keyVaultName - principalId: endpoint.identity.principalId - } -} - -resource hubWorkspace 'Microsoft.MachineLearningServices/workspaces@2023-08-01-preview' existing = { - name: aiHubName -} - -resource workspace 'Microsoft.MachineLearningServices/workspaces@2023-08-01-preview' existing = { - name: aiProjectName -} - -output name string = endpoint.name -output scoringEndpoint string = endpoint.properties.scoringUri -output swaggerEndpoint string = endpoint.properties.swaggerUri -output principalId string = endpoint.identity.principalId diff --git a/infra/core/host/staticwebapp.bicep b/infra/core/host/staticwebapp.bicep deleted file mode 100644 index cedaf90..0000000 --- a/infra/core/host/staticwebapp.bicep +++ /dev/null @@ -1,22 +0,0 @@ -metadata description = 'Creates an Azure Static Web Apps instance.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param sku object = { - name: 'Free' - tier: 'Free' -} - -resource web 'Microsoft.Web/staticSites@2022-03-01' = { - name: name - location: location - tags: tags - sku: sku - properties: { - provider: 'Custom' - } -} - -output name string = web.name -output uri string = 'https://${web.properties.defaultHostname}' diff --git a/infra/core/monitor/applicationinsights-dashboard.bicep b/infra/core/monitor/applicationinsights-dashboard.bicep deleted file mode 100644 index d082e66..0000000 --- a/infra/core/monitor/applicationinsights-dashboard.bicep +++ /dev/null @@ -1,1236 +0,0 @@ -metadata description = 'Creates a dashboard for an Application Insights instance.' -param name string -param applicationInsightsName string -param location string = resourceGroup().location -param tags object = {} - -// 2020-09-01-preview because that is the latest valid version -resource applicationInsightsDashboard 'Microsoft.Portal/dashboards@2020-09-01-preview' = { - name: name - location: location - tags: tags - properties: { - lenses: [ - { - order: 0 - parts: [ - { - position: { - x: 0 - y: 0 - colSpan: 2 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'id' - value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - { - name: 'Version' - value: '1.0' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart' - asset: { - idInputName: 'id' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'overview' - } - } - { - position: { - x: 2 - y: 0 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'Version' - value: '1.0' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'ProactiveDetection' - } - } - { - position: { - x: 3 - y: 0 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'ResourceId' - value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/QuickPulseButtonSmallPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - } - } - { - position: { - x: 4 - y: 0 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'TimeContext' - value: { - durationMs: 86400000 - endTime: null - createdTime: '2018-05-04T01:20:33.345Z' - isInitialTime: true - grain: 1 - useDashboardTimeRange: false - } - } - { - name: 'Version' - value: '1.0' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/AvailabilityNavButtonPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - } - } - { - position: { - x: 5 - y: 0 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'TimeContext' - value: { - durationMs: 86400000 - endTime: null - createdTime: '2018-05-08T18:47:35.237Z' - isInitialTime: true - grain: 1 - useDashboardTimeRange: false - } - } - { - name: 'ConfigurationId' - value: '78ce933e-e864-4b05-a27b-71fd55a6afad' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/AppMapButtonPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - } - } - { - position: { - x: 0 - y: 1 - colSpan: 3 - rowSpan: 1 - } - metadata: { - inputs: [] - type: 'Extension/HubsExtension/PartType/MarkdownPart' - settings: { - content: { - settings: { - content: '# Usage' - title: '' - subtitle: '' - } - } - } - } - } - { - position: { - x: 3 - y: 1 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'TimeContext' - value: { - durationMs: 86400000 - endTime: null - createdTime: '2018-05-04T01:22:35.782Z' - isInitialTime: true - grain: 1 - useDashboardTimeRange: false - } - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/UsageUsersOverviewPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - } - } - { - position: { - x: 4 - y: 1 - colSpan: 3 - rowSpan: 1 - } - metadata: { - inputs: [] - type: 'Extension/HubsExtension/PartType/MarkdownPart' - settings: { - content: { - settings: { - content: '# Reliability' - title: '' - subtitle: '' - } - } - } - } - } - { - position: { - x: 7 - y: 1 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ResourceId' - value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - { - name: 'DataModel' - value: { - version: '1.0.0' - timeContext: { - durationMs: 86400000 - createdTime: '2018-05-04T23:42:40.072Z' - isInitialTime: false - grain: 1 - useDashboardTimeRange: false - } - } - isOptional: true - } - { - name: 'ConfigurationId' - value: '8a02f7bf-ac0f-40e1-afe9-f0e72cfee77f' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart' - isAdapter: true - asset: { - idInputName: 'ResourceId' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'failures' - } - } - { - position: { - x: 8 - y: 1 - colSpan: 3 - rowSpan: 1 - } - metadata: { - inputs: [] - type: 'Extension/HubsExtension/PartType/MarkdownPart' - settings: { - content: { - settings: { - content: '# Responsiveness\r\n' - title: '' - subtitle: '' - } - } - } - } - } - { - position: { - x: 11 - y: 1 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ResourceId' - value: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - { - name: 'DataModel' - value: { - version: '1.0.0' - timeContext: { - durationMs: 86400000 - createdTime: '2018-05-04T23:43:37.804Z' - isInitialTime: false - grain: 1 - useDashboardTimeRange: false - } - } - isOptional: true - } - { - name: 'ConfigurationId' - value: '2a8ede4f-2bee-4b9c-aed9-2db0e8a01865' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart' - isAdapter: true - asset: { - idInputName: 'ResourceId' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'performance' - } - } - { - position: { - x: 12 - y: 1 - colSpan: 3 - rowSpan: 1 - } - metadata: { - inputs: [] - type: 'Extension/HubsExtension/PartType/MarkdownPart' - settings: { - content: { - settings: { - content: '# Browser' - title: '' - subtitle: '' - } - } - } - } - } - { - position: { - x: 15 - y: 1 - colSpan: 1 - rowSpan: 1 - } - metadata: { - inputs: [ - { - name: 'ComponentId' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'MetricsExplorerJsonDefinitionId' - value: 'BrowserPerformanceTimelineMetrics' - } - { - name: 'TimeContext' - value: { - durationMs: 86400000 - createdTime: '2018-05-08T12:16:27.534Z' - isInitialTime: false - grain: 1 - useDashboardTimeRange: false - } - } - { - name: 'CurrentFilter' - value: { - eventTypes: [ - 4 - 1 - 3 - 5 - 2 - 6 - 13 - ] - typeFacets: {} - isPermissive: false - } - } - { - name: 'id' - value: { - Name: applicationInsights.name - SubscriptionId: subscription().subscriptionId - ResourceGroup: resourceGroup().name - } - } - { - name: 'Version' - value: '1.0' - } - ] - #disable-next-line BCP036 - type: 'Extension/AppInsightsExtension/PartType/MetricsExplorerBladePinnedPart' - asset: { - idInputName: 'ComponentId' - type: 'ApplicationInsights' - } - defaultMenuItemId: 'browser' - } - } - { - position: { - x: 0 - y: 2 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'sessions/count' - aggregationType: 5 - namespace: 'microsoft.insights/components/kusto' - metricVisualization: { - displayName: 'Sessions' - color: '#47BDF5' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'users/count' - aggregationType: 5 - namespace: 'microsoft.insights/components/kusto' - metricVisualization: { - displayName: 'Users' - color: '#7E58FF' - } - } - ] - title: 'Unique sessions and users' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - openBladeOnClick: { - openBlade: true - destinationBlade: { - extensionName: 'HubsExtension' - bladeName: 'ResourceMenuBlade' - parameters: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - menuid: 'segmentationUsers' - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 4 - y: 2 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'requests/failed' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Failed requests' - color: '#EC008C' - } - } - ] - title: 'Failed requests' - visualization: { - chartType: 3 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - openBladeOnClick: { - openBlade: true - destinationBlade: { - extensionName: 'HubsExtension' - bladeName: 'ResourceMenuBlade' - parameters: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - menuid: 'failures' - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 8 - y: 2 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'requests/duration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Server response time' - color: '#00BCF2' - } - } - ] - title: 'Server response time' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - openBladeOnClick: { - openBlade: true - destinationBlade: { - extensionName: 'HubsExtension' - bladeName: 'ResourceMenuBlade' - parameters: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - menuid: 'performance' - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 12 - y: 2 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'browserTimings/networkDuration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Page load network connect time' - color: '#7E58FF' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'browserTimings/processingDuration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Client processing time' - color: '#44F1C8' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'browserTimings/sendDuration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Send request time' - color: '#EB9371' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'browserTimings/receiveDuration' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Receiving response time' - color: '#0672F1' - } - } - ] - title: 'Average page load time breakdown' - visualization: { - chartType: 3 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 0 - y: 5 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'availabilityResults/availabilityPercentage' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Availability' - color: '#47BDF5' - } - } - ] - title: 'Average availability' - visualization: { - chartType: 3 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - openBladeOnClick: { - openBlade: true - destinationBlade: { - extensionName: 'HubsExtension' - bladeName: 'ResourceMenuBlade' - parameters: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - menuid: 'availability' - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 4 - y: 5 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'exceptions/server' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Server exceptions' - color: '#47BDF5' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'dependencies/failed' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Dependency failures' - color: '#7E58FF' - } - } - ] - title: 'Server exceptions and Dependency failures' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 8 - y: 5 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'performanceCounters/processorCpuPercentage' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Processor time' - color: '#47BDF5' - } - } - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'performanceCounters/processCpuPercentage' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Process CPU' - color: '#7E58FF' - } - } - ] - title: 'Average processor and process CPU utilization' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 12 - y: 5 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'exceptions/browser' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Browser exceptions' - color: '#47BDF5' - } - } - ] - title: 'Browser exceptions' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 0 - y: 8 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'availabilityResults/count' - aggregationType: 7 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Availability test results count' - color: '#47BDF5' - } - } - ] - title: 'Availability test results count' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 4 - y: 8 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'performanceCounters/processIOBytesPerSecond' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Process IO rate' - color: '#47BDF5' - } - } - ] - title: 'Average process I/O rate' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - { - position: { - x: 8 - y: 8 - colSpan: 4 - rowSpan: 3 - } - metadata: { - inputs: [ - { - name: 'options' - value: { - chart: { - metrics: [ - { - resourceMetadata: { - id: '/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Insights/components/${applicationInsights.name}' - } - name: 'performanceCounters/memoryAvailableBytes' - aggregationType: 4 - namespace: 'microsoft.insights/components' - metricVisualization: { - displayName: 'Available memory' - color: '#47BDF5' - } - } - ] - title: 'Average available memory' - visualization: { - chartType: 2 - legendVisualization: { - isVisible: true - position: 2 - hideSubtitle: false - } - axisVisualization: { - x: { - isVisible: true - axisType: 2 - } - y: { - isVisible: true - axisType: 1 - } - } - } - } - } - } - { - name: 'sharedTimeRange' - isOptional: true - } - ] - #disable-next-line BCP036 - type: 'Extension/HubsExtension/PartType/MonitorChartPart' - settings: {} - } - } - ] - } - ] - } -} - -resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = { - name: applicationInsightsName -} diff --git a/infra/core/monitor/applicationinsights.bicep b/infra/core/monitor/applicationinsights.bicep deleted file mode 100644 index 850e9fe..0000000 --- a/infra/core/monitor/applicationinsights.bicep +++ /dev/null @@ -1,31 +0,0 @@ -metadata description = 'Creates an Application Insights instance based on an existing Log Analytics workspace.' -param name string -param dashboardName string = '' -param location string = resourceGroup().location -param tags object = {} -param logAnalyticsWorkspaceId string - -resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { - name: name - location: location - tags: tags - kind: 'web' - properties: { - Application_Type: 'web' - WorkspaceResourceId: logAnalyticsWorkspaceId - } -} - -module applicationInsightsDashboard 'applicationinsights-dashboard.bicep' = if (!empty(dashboardName)) { - name: 'application-insights-dashboard' - params: { - name: dashboardName - location: location - applicationInsightsName: applicationInsights.name - } -} - -output connectionString string = applicationInsights.properties.ConnectionString -output id string = applicationInsights.id -output instrumentationKey string = applicationInsights.properties.InstrumentationKey -output name string = applicationInsights.name diff --git a/infra/core/monitor/loganalytics.bicep b/infra/core/monitor/loganalytics.bicep deleted file mode 100644 index 33f9dc2..0000000 --- a/infra/core/monitor/loganalytics.bicep +++ /dev/null @@ -1,22 +0,0 @@ -metadata description = 'Creates a Log Analytics workspace.' -param name string -param location string = resourceGroup().location -param tags object = {} - -resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = { - name: name - location: location - tags: tags - properties: any({ - retentionInDays: 30 - features: { - searchVersion: 1 - } - sku: { - name: 'PerGB2018' - } - }) -} - -output id string = logAnalytics.id -output name string = logAnalytics.name diff --git a/infra/core/monitor/monitoring.bicep b/infra/core/monitor/monitoring.bicep deleted file mode 100644 index 7476125..0000000 --- a/infra/core/monitor/monitoring.bicep +++ /dev/null @@ -1,33 +0,0 @@ -metadata description = 'Creates an Application Insights instance and a Log Analytics workspace.' -param logAnalyticsName string -param applicationInsightsName string -param applicationInsightsDashboardName string = '' -param location string = resourceGroup().location -param tags object = {} - -module logAnalytics 'loganalytics.bicep' = { - name: 'loganalytics' - params: { - name: logAnalyticsName - location: location - tags: tags - } -} - -module applicationInsights 'applicationinsights.bicep' = { - name: 'applicationinsights' - params: { - name: applicationInsightsName - location: location - tags: tags - dashboardName: applicationInsightsDashboardName - logAnalyticsWorkspaceId: logAnalytics.outputs.id - } -} - -output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString -output applicationInsightsId string = applicationInsights.outputs.id -output applicationInsightsInstrumentationKey string = applicationInsights.outputs.instrumentationKey -output applicationInsightsName string = applicationInsights.outputs.name -output logAnalyticsWorkspaceId string = logAnalytics.outputs.id -output logAnalyticsWorkspaceName string = logAnalytics.outputs.name diff --git a/infra/core/networking/cdn-endpoint.bicep b/infra/core/networking/cdn-endpoint.bicep deleted file mode 100644 index 5e8ab69..0000000 --- a/infra/core/networking/cdn-endpoint.bicep +++ /dev/null @@ -1,52 +0,0 @@ -metadata description = 'Adds an endpoint to an Azure CDN profile.' -param name string -param location string = resourceGroup().location -param tags object = {} - -@description('The name of the CDN profile resource') -@minLength(1) -param cdnProfileName string - -@description('Delivery policy rules') -param deliveryPolicyRules array = [] - -@description('The origin URL for the endpoint') -@minLength(1) -param originUrl string - -resource endpoint 'Microsoft.Cdn/profiles/endpoints@2022-05-01-preview' = { - parent: cdnProfile - name: name - location: location - tags: tags - properties: { - originHostHeader: originUrl - isHttpAllowed: false - isHttpsAllowed: true - queryStringCachingBehavior: 'UseQueryString' - optimizationType: 'GeneralWebDelivery' - origins: [ - { - name: replace(originUrl, '.', '-') - properties: { - hostName: originUrl - originHostHeader: originUrl - priority: 1 - weight: 1000 - enabled: true - } - } - ] - deliveryPolicy: { - rules: deliveryPolicyRules - } - } -} - -resource cdnProfile 'Microsoft.Cdn/profiles@2022-05-01-preview' existing = { - name: cdnProfileName -} - -output id string = endpoint.id -output name string = endpoint.name -output uri string = 'https://${endpoint.properties.hostName}' diff --git a/infra/core/networking/cdn-profile.bicep b/infra/core/networking/cdn-profile.bicep deleted file mode 100644 index 27669ee..0000000 --- a/infra/core/networking/cdn-profile.bicep +++ /dev/null @@ -1,34 +0,0 @@ -metadata description = 'Creates an Azure CDN profile.' -param name string -param location string = resourceGroup().location -param tags object = {} - -@description('The pricing tier of this CDN profile') -@allowed([ - 'Custom_Verizon' - 'Premium_AzureFrontDoor' - 'Premium_Verizon' - 'StandardPlus_955BandWidth_ChinaCdn' - 'StandardPlus_AvgBandWidth_ChinaCdn' - 'StandardPlus_ChinaCdn' - 'Standard_955BandWidth_ChinaCdn' - 'Standard_Akamai' - 'Standard_AvgBandWidth_ChinaCdn' - 'Standard_AzureFrontDoor' - 'Standard_ChinaCdn' - 'Standard_Microsoft' - 'Standard_Verizon' -]) -param sku string = 'Standard_Microsoft' - -resource profile 'Microsoft.Cdn/profiles@2022-05-01-preview' = { - name: name - location: location - tags: tags - sku: { - name: sku - } -} - -output id string = profile.id -output name string = profile.name diff --git a/infra/core/networking/cdn.bicep b/infra/core/networking/cdn.bicep deleted file mode 100644 index de98a1f..0000000 --- a/infra/core/networking/cdn.bicep +++ /dev/null @@ -1,42 +0,0 @@ -metadata description = 'Creates an Azure CDN profile with a single endpoint.' -param location string = resourceGroup().location -param tags object = {} - -@description('Name of the CDN endpoint resource') -param cdnEndpointName string - -@description('Name of the CDN profile resource') -param cdnProfileName string - -@description('Delivery policy rules') -param deliveryPolicyRules array = [] - -@description('Origin URL for the CDN endpoint') -param originUrl string - -module cdnProfile 'cdn-profile.bicep' = { - name: 'cdn-profile' - params: { - name: cdnProfileName - location: location - tags: tags - } -} - -module cdnEndpoint 'cdn-endpoint.bicep' = { - name: 'cdn-endpoint' - params: { - name: cdnEndpointName - location: location - tags: tags - cdnProfileName: cdnProfile.outputs.name - originUrl: originUrl - deliveryPolicyRules: deliveryPolicyRules - } -} - -output endpointName string = cdnEndpoint.outputs.name -output endpointId string = cdnEndpoint.outputs.id -output profileName string = cdnProfile.outputs.name -output profileId string = cdnProfile.outputs.id -output uri string = cdnEndpoint.outputs.uri diff --git a/infra/core/search/search-services.bicep b/infra/core/search/search-services.bicep deleted file mode 100644 index d9c619a..0000000 --- a/infra/core/search/search-services.bicep +++ /dev/null @@ -1,68 +0,0 @@ -metadata description = 'Creates an Azure AI Search instance.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param sku object = { - name: 'standard' -} - -param authOptions object = {} -param disableLocalAuth bool = false -param disabledDataExfiltrationOptions array = [] -param encryptionWithCmk object = { - enforcement: 'Unspecified' -} -@allowed([ - 'default' - 'highDensity' -]) -param hostingMode string = 'default' -param networkRuleSet object = { - bypass: 'None' - ipRules: [] -} -param partitionCount int = 1 -@allowed([ - 'enabled' - 'disabled' -]) -param publicNetworkAccess string = 'enabled' -param replicaCount int = 1 -@allowed([ - 'disabled' - 'free' - 'standard' -]) -param semanticSearch string = 'disabled' - -var searchIdentityProvider = (sku.name == 'free') ? null : { - type: 'SystemAssigned' -} - -resource search 'Microsoft.Search/searchServices@2021-04-01-preview' = { - name: name - location: location - tags: tags - // The free tier does not support managed identity - identity: searchIdentityProvider - properties: { - authOptions: authOptions - disableLocalAuth: disableLocalAuth - disabledDataExfiltrationOptions: disabledDataExfiltrationOptions - encryptionWithCmk: encryptionWithCmk - hostingMode: hostingMode - networkRuleSet: networkRuleSet - partitionCount: partitionCount - publicNetworkAccess: publicNetworkAccess - replicaCount: replicaCount - semanticSearch: semanticSearch - } - sku: sku -} - -output id string = search.id -output endpoint string = 'https://${name}.search.windows.net/' -output name string = search.name -output principalId string = !empty(searchIdentityProvider) ? search.identity.principalId : '' - diff --git a/infra/core/security/aks-managed-cluster-access.bicep b/infra/core/security/aks-managed-cluster-access.bicep deleted file mode 100644 index dec984e..0000000 --- a/infra/core/security/aks-managed-cluster-access.bicep +++ /dev/null @@ -1,19 +0,0 @@ -metadata description = 'Assigns RBAC role to the specified AKS cluster and principal.' -param clusterName string -param principalId string - -var aksClusterAdminRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b') - -resource aksRole 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - scope: aksCluster // Use when specifying a scope that is different than the deployment scope - name: guid(subscription().id, resourceGroup().id, principalId, aksClusterAdminRole) - properties: { - roleDefinitionId: aksClusterAdminRole - principalType: 'User' - principalId: principalId - } -} - -resource aksCluster 'Microsoft.ContainerService/managedClusters@2023-10-02-preview' existing = { - name: clusterName -} diff --git a/infra/core/security/appinsights-access.bicep b/infra/core/security/appinsights-access.bicep deleted file mode 100644 index 2d3b7cd..0000000 --- a/infra/core/security/appinsights-access.bicep +++ /dev/null @@ -1,19 +0,0 @@ -metadata description = 'Assigns MonitoringMetricsContributor role to Application Insights.' -param appInsightsName string -param principalId string - -resource appInsights 'Microsoft.Insights/components@2020-02-02' existing = { - name: appInsightsName -} - -//var monitoringMetricsPublisherRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb') -var monitoringMetricsContributorRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa') - -resource monitoringMetricsContributorRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - scope: appInsights // Use when specifying a scope that is different than the deployment scope - name: guid(subscription().id, resourceGroup().id, principalId, monitoringMetricsContributorRole) - properties: { - roleDefinitionId: monitoringMetricsContributorRole - principalId: principalId - } -} diff --git a/infra/core/security/configstore-access.bicep b/infra/core/security/configstore-access.bicep deleted file mode 100644 index de72b94..0000000 --- a/infra/core/security/configstore-access.bicep +++ /dev/null @@ -1,21 +0,0 @@ -@description('Name of Azure App Configuration store') -param configStoreName string - -@description('The principal ID of the service principal to assign the role to') -param principalId string - -resource configStore 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = { - name: configStoreName -} - -var configStoreDataReaderRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071') - -resource configStoreDataReaderRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(subscription().id, resourceGroup().id, principalId, configStoreDataReaderRole) - scope: configStore - properties: { - roleDefinitionId: configStoreDataReaderRole - principalId: principalId - principalType: 'ServicePrincipal' - } -} diff --git a/infra/core/security/keyvault-access.bicep b/infra/core/security/keyvault-access.bicep deleted file mode 100644 index 316775f..0000000 --- a/infra/core/security/keyvault-access.bicep +++ /dev/null @@ -1,22 +0,0 @@ -metadata description = 'Assigns an Azure Key Vault access policy.' -param name string = 'add' - -param keyVaultName string -param permissions object = { secrets: [ 'get', 'list' ] } -param principalId string - -resource keyVaultAccessPolicies 'Microsoft.KeyVault/vaults/accessPolicies@2022-07-01' = { - parent: keyVault - name: name - properties: { - accessPolicies: [ { - objectId: principalId - tenantId: subscription().tenantId - permissions: permissions - } ] - } -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { - name: keyVaultName -} diff --git a/infra/core/security/keyvault-secret.bicep b/infra/core/security/keyvault-secret.bicep deleted file mode 100644 index 7441b29..0000000 --- a/infra/core/security/keyvault-secret.bicep +++ /dev/null @@ -1,31 +0,0 @@ -metadata description = 'Creates or updates a secret in an Azure Key Vault.' -param name string -param tags object = {} -param keyVaultName string -param contentType string = 'string' -@description('The value of the secret. Provide only derived values like blob storage access, but do not hard code any secrets in your templates') -@secure() -param secretValue string - -param enabled bool = true -param exp int = 0 -param nbf int = 0 - -resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2022-07-01' = { - name: name - tags: tags - parent: keyVault - properties: { - attributes: { - enabled: enabled - exp: exp - nbf: nbf - } - contentType: contentType - value: secretValue - } -} - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { - name: keyVaultName -} diff --git a/infra/core/security/keyvault.bicep b/infra/core/security/keyvault.bicep deleted file mode 100644 index 663ec00..0000000 --- a/infra/core/security/keyvault.bicep +++ /dev/null @@ -1,27 +0,0 @@ -metadata description = 'Creates an Azure Key Vault.' -param name string -param location string = resourceGroup().location -param tags object = {} - -param principalId string = '' - -resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { - name: name - location: location - tags: tags - properties: { - tenantId: subscription().tenantId - sku: { family: 'A', name: 'standard' } - accessPolicies: !empty(principalId) ? [ - { - objectId: principalId - permissions: { secrets: [ 'get', 'list' ] } - tenantId: subscription().tenantId - } - ] : [] - } -} - -output endpoint string = keyVault.properties.vaultUri -output id string = keyVault.id -output name string = keyVault.name diff --git a/infra/core/security/registry-access.bicep b/infra/core/security/registry-access.bicep deleted file mode 100644 index fc66837..0000000 --- a/infra/core/security/registry-access.bicep +++ /dev/null @@ -1,19 +0,0 @@ -metadata description = 'Assigns ACR Pull permissions to access an Azure Container Registry.' -param containerRegistryName string -param principalId string - -var acrPullRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d') - -resource aksAcrPull 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - scope: containerRegistry // Use when specifying a scope that is different than the deployment scope - name: guid(subscription().id, resourceGroup().id, principalId, acrPullRole) - properties: { - roleDefinitionId: acrPullRole - principalType: 'ServicePrincipal' - principalId: principalId - } -} - -resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' existing = { - name: containerRegistryName -} diff --git a/infra/core/security/role.bicep b/infra/core/security/role.bicep deleted file mode 100644 index 001290e..0000000 --- a/infra/core/security/role.bicep +++ /dev/null @@ -1,22 +0,0 @@ -metadata description = 'Creates a role assignment for a service principal.' -param principalId string - -@allowed([ - 'Device' - 'ForeignGroup' - 'Group' - 'ServicePrincipal' - 'User' - '' -]) -param principalType string = '' -param roleDefinitionId string - -resource role 'Microsoft.Authorization/roleAssignments@2022-04-01' = { - name: guid(subscription().id, resourceGroup().id, principalId, roleDefinitionId) - properties: { - principalId: principalId - principalType: principalType - roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId) - } -} diff --git a/infra/core/storage/storage-account.bicep b/infra/core/storage/storage-account.bicep deleted file mode 100644 index 6149fb2..0000000 --- a/infra/core/storage/storage-account.bicep +++ /dev/null @@ -1,101 +0,0 @@ -metadata description = 'Creates an Azure storage account.' -param name string -param location string = resourceGroup().location -param tags object = {} - -@allowed([ - 'Cool' - 'Hot' - 'Premium' ]) -param accessTier string = 'Hot' -param allowBlobPublicAccess bool = true -param allowCrossTenantReplication bool = true -param allowSharedKeyAccess bool = true -param containers array = [] -param corsRules array = [] -param defaultToOAuthAuthentication bool = false -param deleteRetentionPolicy object = {} -@allowed([ 'AzureDnsZone', 'Standard' ]) -param dnsEndpointType string = 'Standard' -param files array = [] -param kind string = 'StorageV2' -param minimumTlsVersion string = 'TLS1_2' -param queues array = [] -param shareDeleteRetentionPolicy object = {} -param supportsHttpsTrafficOnly bool = true -param tables array = [] -param networkAcls object = { - bypass: 'AzureServices' - defaultAction: 'Allow' -} -@allowed([ 'Enabled', 'Disabled' ]) -param publicNetworkAccess string = 'Enabled' -param sku object = { name: 'Standard_LRS' } - -resource storage 'Microsoft.Storage/storageAccounts@2023-01-01' = { - name: name - location: location - tags: tags - kind: kind - sku: sku - properties: { - accessTier: accessTier - allowBlobPublicAccess: allowBlobPublicAccess - allowCrossTenantReplication: allowCrossTenantReplication - allowSharedKeyAccess: allowSharedKeyAccess - defaultToOAuthAuthentication: defaultToOAuthAuthentication - dnsEndpointType: dnsEndpointType - minimumTlsVersion: minimumTlsVersion - networkAcls: networkAcls - publicNetworkAccess: publicNetworkAccess - supportsHttpsTrafficOnly: supportsHttpsTrafficOnly - } - - resource blobServices 'blobServices' = if (!empty(containers)) { - name: 'default' - properties: { - cors: { - corsRules: corsRules - } - deleteRetentionPolicy: deleteRetentionPolicy - } - resource container 'containers' = [for container in containers: { - name: container.name - properties: { - publicAccess: contains(container, 'publicAccess') ? container.publicAccess : 'None' - } - }] - } - - resource fileServices 'fileServices' = if (!empty(files)) { - name: 'default' - properties: { - cors: { - corsRules: corsRules - } - shareDeleteRetentionPolicy: shareDeleteRetentionPolicy - } - } - - resource queueServices 'queueServices' = if (!empty(queues)) { - name: 'default' - properties: { - - } - resource queue 'queues' = [for queue in queues: { - name: queue.name - properties: { - metadata: {} - } - }] - } - - resource tableServices 'tableServices' = if (!empty(tables)) { - name: 'default' - properties: {} - } -} - -output id string = storage.id -output name string = storage.name -output primaryEndpoints object = storage.properties.primaryEndpoints diff --git a/infra/core/testing/loadtesting.bicep b/infra/core/testing/loadtesting.bicep deleted file mode 100644 index 4678108..0000000 --- a/infra/core/testing/loadtesting.bicep +++ /dev/null @@ -1,15 +0,0 @@ -param name string -param location string = resourceGroup().location -param managedIdentity bool = false -param tags object = {} - -resource loadTest 'Microsoft.LoadTestService/loadTests@2022-12-01' = { - name: name - location: location - tags: tags - identity: { type: managedIdentity ? 'SystemAssigned' : 'None' } - properties: { - } -} - -output loadTestingName string = loadTest.name diff --git a/infra/main.bicep b/infra/main.bicep deleted file mode 100644 index abb7884..0000000 --- a/infra/main.bicep +++ /dev/null @@ -1,444 +0,0 @@ -targetScope = 'subscription' - -@minLength(1) -@maxLength(64) -@description('Name of the the environment which is used to generate a short unique hash used in all resources.') -param environmentName string - -@minLength(1) -@description('Location for all resources') -// Look for desired models on the availability table: -// https://learn.microsoft.com/azure/ai-services/openai/concepts/models#global-standard-model-availability -@allowed([ - 'australiaeast' - 'brazilsouth' - 'canadaeast' - 'eastus' - 'eastus2' - 'francecentral' - 'germanywestcentral' - 'japaneast' - 'koreacentral' - 'northcentralus' - 'norwayeast' - 'polandcentral' - 'spaincentral' - 'southafricanorth' - 'southcentralus' - 'southindia' - 'swedencentral' - 'switzerlandnorth' - 'uksouth' - 'westeurope' - 'westus' - 'westus3' -]) -@metadata({ - azd: { - type: 'location' - } -}) -param location string - -@description('Use this parameter to use an existing AI project connection string') -param aiExistingProjectConnectionString string = '' -@description('The Azure resource group where new resources will be deployed') -param resourceGroupName string = '' -@description('The Azure AI Foundry Hub resource name. If ommited will be generated') -param aiHubName string = '' -@description('The Azure AI Foundry project name. If ommited will be generated') -param aiProjectName string = '' -@description('The application insights resource name. If ommited will be generated') -param applicationInsightsName string = '' -@description('The AI Services resource name. If ommited will be generated') -param aiServicesName string = '' -@description('The AI Services connection name. If ommited will use a default value') -param aiServicesConnectionName string = '' -@description('The Azure Container Registry resource name. If ommited will be generated') -param containerRegistryName string = '' -@description('The Azure Key Vault resource name. If ommited will be generated') -param keyVaultName string = '' -@description('The Azure Search resource name. If ommited will be generated') -param searchServiceName string = '' -@description('The Azure Search connection name. If ommited will use a default value') -param searchConnectionName string = '' -@description('The search index name') -param aiSearchIndexName string = '' -@description('The Azure Storage Account resource name. If ommited will be generated') -param storageAccountName string = '' -@description('The log analytics workspace name. If ommited will be generated') -param logAnalyticsWorkspaceName string = '' -@description('Id of the user or app to assign application roles') -param principalId string = '' - -// Chat completion model -@description('Format of the chat model to deploy') -@allowed(['Microsoft', 'OpenAI']) -param agentModelFormat string -@description('Name of agent to deploy') -param agentName string -@description('ID of agent to deploy') -param aiAgentID string = '' -@description('Name of the chat model to deploy') -param agentModelName string -@description('Name of the model deployment') -param agentDeploymentName string - -@description('Version of the chat model to deploy') -// See version availability in this table: -// https://learn.microsoft.com/azure/ai-services/openai/concepts/models#global-standard-model-availability -param agentModelVersion string - -@description('Sku of the chat deployment') -param agentDeploymentSku string - -@description('Capacity of the chat deployment') -// You can increase this, but capacity is limited per model/region, so you will get errors if you go over -// https://learn.microsoft.com/en-us/azure/ai-services/openai/quotas-limits -param agentDeploymentCapacity int - -// Embedding model -@description('Format of the embedding model to deploy') -@allowed(['Microsoft', 'OpenAI']) -param embedModelFormat string - -@description('Name of the embedding model to deploy') -param embedModelName string -@description('Name of the embedding model deployment') -param embeddingDeploymentName string -@description('Embedding model dimensionality') -param embeddingDeploymentDimensions string - -@description('Version of the embedding model to deploy') -// See version availability in this table: -// https://learn.microsoft.com/azure/ai-services/openai/concepts/models#embeddings-models -@secure() -param embedModelVersion string - -@description('Sku of the embeddings model deployment') -param embedDeploymentSku string - -@description('Capacity of the embedding deployment') -// You can increase this, but capacity is limited per model/region, so you will get errors if you go over -// https://learn.microsoft.com/azure/ai-services/openai/quotas-limits -param embedDeploymentCapacity int - -param useContainerRegistry bool = true -param useApplicationInsights bool = true -@description('Do we want to use the Azure AI Search') -param useSearchService bool = false - -@description('Random seed to be used during generation of new resources suffixes.') -param seed string = newGuid() - -var abbrs = loadJsonContent('./abbreviations.json') -var resourceToken = toLower(uniqueString(subscription().id, environmentName, location, seed)) -var projectName = !empty(aiProjectName) ? aiProjectName : 'ai-project-${resourceToken}' -var tags = { 'azd-env-name': environmentName } - -var agentID = !empty(aiAgentID) ? aiAgentID : '' - -var aiChatModel = [ - { - name: agentDeploymentName - model: { - format: agentModelFormat - name: agentModelName - version: agentModelVersion - } - sku: { - name: agentDeploymentSku - capacity: agentDeploymentCapacity - } - } -] -var aiEmbeddingModel = [ - { - name: embeddingDeploymentName - model: { - format: embedModelFormat - name: embedModelName - version: embedModelVersion - } - sku: { - name: embedDeploymentSku - capacity: embedDeploymentCapacity - } - } -] - -var aiDeployments = concat( - aiChatModel, - useSearchService ? aiEmbeddingModel : []) - -//for container and app api -param apiAppExists bool = false - -// Organize resources in a resource group -resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = { - name: !empty(resourceGroupName) ? resourceGroupName : '${abbrs.resourcesResourceGroups}${environmentName}' - location: location - tags: tags -} - -var logAnalyticsWorkspaceResolvedName = !useApplicationInsights - ? '' - : !empty(logAnalyticsWorkspaceName) - ? logAnalyticsWorkspaceName - : '${abbrs.operationalInsightsWorkspaces}${resourceToken}' - -var resolvedSearchServiceName = !useSearchService - ? '' - : !empty(searchServiceName) ? searchServiceName : '${abbrs.searchSearchServices}${resourceToken}' - -var containerRegistryResolvedName = !useContainerRegistry - ? '' - : !empty(containerRegistryName) ? containerRegistryName : '${abbrs.containerRegistryRegistries}${resourceToken}' - -module ai 'core/host/ai-environment.bicep' = if (empty(aiExistingProjectConnectionString)) { - name: 'ai' - scope: rg - params: { - location: location - tags: tags - hubName: !empty(aiHubName) ? aiHubName : 'ai-hub-${resourceToken}' - projectName: projectName - keyVaultName: !empty(keyVaultName) ? keyVaultName : '${abbrs.keyVaultVaults}${resourceToken}' - storageAccountName: !empty(storageAccountName) - ? storageAccountName - : '${abbrs.storageStorageAccounts}${resourceToken}' - aiServicesName: !empty(aiServicesName) ? aiServicesName : 'aoai-${resourceToken}' - aiServicesConnectionName: !empty(aiServicesConnectionName) ? aiServicesConnectionName : 'aoai-${resourceToken}' - aiServiceModelDeployments: aiDeployments - logAnalyticsName: logAnalyticsWorkspaceResolvedName - applicationInsightsName: !useApplicationInsights - ? '' - : !empty(applicationInsightsName) ? applicationInsightsName : '${abbrs.insightsComponents}${resourceToken}' - containerRegistryName: containerRegistryResolvedName - searchServiceName: resolvedSearchServiceName - searchConnectionName: !useSearchService - ? '' - : !empty(searchConnectionName) ? searchConnectionName : 'search-service-connection' - } -} - -var searchServiceEndpoint = !useSearchService - ? '' - : ai.outputs.searchServiceEndpoint - -// If bringing an existing AI project, set up the log analytics workspace here -module logAnalytics 'core/monitor/loganalytics.bicep' = if (!empty(aiExistingProjectConnectionString)) { - name: 'logAnalytics' - scope: rg - params: { - location: location - tags: tags - name: logAnalyticsWorkspaceResolvedName - } -} - -var hostName = empty(aiExistingProjectConnectionString) ? split(ai.outputs.discoveryUrl, '/')[2] : '' -var projectConnectionString = empty(hostName) - ? aiExistingProjectConnectionString - : '${hostName};${subscription().subscriptionId};${rg.name};${projectName}' - -var resolvedApplicationInsightsName = !useApplicationInsights || !empty(aiExistingProjectConnectionString) - ? '' - : !empty(applicationInsightsName) ? applicationInsightsName : '${abbrs.insightsComponents}${resourceToken}' - -module monitoringMetricsContribuitorRoleAzureAIDeveloperRG 'core/security/appinsights-access.bicep' = if (!empty(resolvedApplicationInsightsName)) { - name: 'monitoringmetricscontributor-role-azureai-developer-rg' - scope: rg - params: { - appInsightsName: resolvedApplicationInsightsName - principalId: api.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID - } -} - -resource existingProjectRG 'Microsoft.Resources/resourceGroups@2021-04-01' existing = if (!empty(aiExistingProjectConnectionString)) { - name: split(aiExistingProjectConnectionString, ';')[2] -} - -module userRoleAzureAIDeveloperBackendExistingProjectRG 'core/security/role.bicep' = if (!empty(aiExistingProjectConnectionString)) { - name: 'backend-role-azureai-developer-existing-project-rg' - scope: existingProjectRG - params: { - principalId: api.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID - roleDefinitionId: '64702f94-c441-49e6-a78b-ef80e0188fee' - } -} - -//Container apps host and api -// Container apps host (including container registry) -module containerApps 'core/host/container-apps.bicep' = { - name: 'container-apps' - scope: rg - params: { - name: 'app' - location: location - tags: tags - containerAppsEnvironmentName: 'containerapps-env-${resourceToken}' - containerRegistryName: empty(aiExistingProjectConnectionString) - ? ai.outputs.containerRegistryName - : containerRegistryResolvedName - logAnalyticsWorkspaceName: empty(aiExistingProjectConnectionString) - ? ai.outputs.logAnalyticsWorkspaceName - : logAnalytics.outputs.name - } -} - -// API app -module api 'api.bicep' = { - name: 'api' - scope: rg - params: { - name: 'ca-api-${resourceToken}' - location: location - tags: tags - identityName: '${abbrs.managedIdentityUserAssignedIdentities}api-${resourceToken}' - containerAppsEnvironmentName: containerApps.outputs.environmentName - containerRegistryName: containerApps.outputs.registryName - projectConnectionString: projectConnectionString - agentDeploymentName: agentDeploymentName - searchConnectionName: searchConnectionName - aiSearchIndexName: aiSearchIndexName - searchServiceEndpoint: searchServiceEndpoint - embeddingDeploymentName: embeddingDeploymentName - embeddingDeploymentDimensions: embeddingDeploymentDimensions - agentName: agentName - agentID: agentID - exists: apiAppExists - } -} - -module userAcrRolePush 'core/security/role.bicep' = if (!empty(principalId)) { - name: 'user-role-acr-push' - scope: rg - params: { - principalId: principalId - roleDefinitionId: '8311e382-0749-4cb8-b61a-304f252e45ec' - } -} - -module userAcrRolePull 'core/security/role.bicep' = if (!empty(principalId)) { - name: 'user-role-acr-pull' - scope: rg - params: { - principalId: principalId - roleDefinitionId: '7f951dda-4ed3-4680-a7ca-43fe172d538d' - } -} - -module userRoleDataScientist 'core/security/role.bicep' = if (!empty(principalId)) { - name: 'user-role-data-scientist' - scope: rg - params: { - principalId: principalId - roleDefinitionId: 'f6c7c914-8db3-469d-8ca1-694a8f32e121' - } -} - -module userRoleSecretsReader 'core/security/role.bicep' = if (!empty(principalId)) { - name: 'user-role-secrets-reader' - scope: rg - params: { - principalId: principalId - roleDefinitionId: 'ea01e6af-a1c1-4350-9563-ad00f8c72ec5' - } -} - -module userRoleAzureAIDeveloper 'core/security/role.bicep' = if (!empty(principalId)) { - name: 'user-role-azureai-developer' - scope: rg - params: { - principalId: principalId - roleDefinitionId: '64702f94-c441-49e6-a78b-ef80e0188fee' - } -} - -module backendRoleSearchIndexDataContributorRG 'core/security/role.bicep' = if (useSearchService) { - name: 'backend-role-azure-index-data-contributor-rg' - scope: rg - params: { - principalId: api.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID - roleDefinitionId: '8ebe5a00-799e-43f5-93ac-243d3dce84a7' - } -} - -module backendRoleSearchIndexDataReaderRG 'core/security/role.bicep' = if (useSearchService) { - name: 'backend-role-azure-index-data-reader-rg' - scope: rg - params: { - principalId: api.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID - roleDefinitionId: '1407120a-92aa-4202-b7e9-c0e197c71c8f' - } -} - -module backendRoleSearchServiceContributorRG 'core/security/role.bicep' = if (useSearchService) { - name: 'backend-role-azure-search-service-contributor-rg' - scope: rg - params: { - principalId: api.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID - roleDefinitionId: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' - } -} - -module userRoleSearchIndexDataContributorRG 'core/security/role.bicep' = if (useSearchService && !empty(principalId)) { - name: 'user-role-azure-index-data-contributor-rg' - scope: rg - params: { - principalId: principalId - roleDefinitionId: '8ebe5a00-799e-43f5-93ac-243d3dce84a7' - } -} - -module userRoleSearchIndexDataReaderRG 'core/security/role.bicep' = if (useSearchService && !empty(principalId)) { - name: 'user-role-azure-index-data-reader-rg' - scope: rg - params: { - principalId: principalId - roleDefinitionId: '1407120a-92aa-4202-b7e9-c0e197c71c8f' - } -} - -module userRoleSearchServiceContributorRG 'core/security/role.bicep' = if (useSearchService && !empty(principalId)) { - name: 'user-role-azure-search-service-contributor-rg' - scope: rg - params: { - principalId: principalId - roleDefinitionId: '7ca78c08-252a-4471-8644-bb5ff32d4ba0' - } -} - -module backendRoleAzureAIDeveloperRG 'core/security/role.bicep' = { - name: 'backend-role-azureai-developer-rg' - scope: rg - params: { - principalId: api.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID - roleDefinitionId: '64702f94-c441-49e6-a78b-ef80e0188fee' - } -} - -output AZURE_RESOURCE_GROUP string = rg.name - -// Outputs required for local development server -output AZURE_TENANT_ID string = tenant().tenantId -output AZURE_AIPROJECT_CONNECTION_STRING string = projectConnectionString -output AZURE_AI_AGENT_DEPLOYMENT_NAME string = agentDeploymentName -output AZURE_AI_SEARCH_CONNECTION_NAME string = searchConnectionName -output AZURE_AI_EMBED_DEPLOYMENT_NAME string = embeddingDeploymentName -output AZURE_AI_SEARCH_INDEX_NAME string = aiSearchIndexName -output AZURE_AI_SEARCH_ENDPOINT string = searchServiceEndpoint -output AZURE_AI_EMBED_DIMENSIONS string = embeddingDeploymentDimensions -output AZURE_AI_AGENT_NAME string = agentName -output AZURE_AI_AGENT_ID string = agentID - -// Outputs required by azd for ACA -output AZURE_CONTAINER_ENVIRONMENT_NAME string = containerApps.outputs.environmentName -output AZURE_CONTAINER_REGISTRY_NAME string = containerApps.outputs.registryName -output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerApps.outputs.registryLoginServer -output SERVICE_API_IDENTITY_PRINCIPAL_ID string = api.outputs.SERVICE_API_IDENTITY_PRINCIPAL_ID -output SERVICE_API_NAME string = api.outputs.SERVICE_API_NAME -output SERVICE_API_URI string = api.outputs.SERVICE_API_URI -output SERVICE_API_IMAGE_NAME string = api.outputs.SERVICE_API_IMAGE_NAME -output SERVICE_API_ENDPOINTS array = ['${api.outputs.SERVICE_API_URI}'] diff --git a/infra/main.parameters.json b/infra/main.parameters.json deleted file mode 100644 index 1752da8..0000000 --- a/infra/main.parameters.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", - "contentVersion": "1.0.0.0", - "parameters": { - "environmentName": { - "value": "${AZURE_ENV_NAME}" - }, - "location": { - "value": "${AZURE_LOCATION}" - }, - "principalId": { - "value": "${AZURE_PRINCIPAL_ID}" - }, - "resourceGroupName": { - "value": "${AZURE_RESOURCE_GROUP}" - }, - "aiHubName": { - "value": "${AZURE_AIHUB_NAME}" - }, - "aiProjectName": { - "value": "${AZURE_AIPROJECT_NAME}" - }, - "aiServicesName": { - "value": "${AZURE_AISERVICES_NAME}" - }, - "searchServiceName": { - "value": "${AZURE_SEARCH_SERVICE_NAME}" - }, - "applicationInsightsName": { - "value": "${AZURE_APPLICATION_INSIGHTS_NAME}" - }, - "containerRegistryName": { - "value": "${AZURE_CONTAINER_REGISTRY_NAME}" - }, - "keyVaultName": { - "value": "${AZURE_KEYVAULT_NAME}" - }, - "storageAccountName": { - "value": "${AZURE_STORAGE_ACCOUNT_NAME}" - }, - "logAnalyticsWorkspaceName": { - "value": "${AZURE_LOG_ANALYTICS_WORKSPACE_NAME}" - }, - "useContainerRegistry": { - "value": "${USE_CONTAINER_REGISTRY=true}" - }, - "useApplicationInsights": { - "value": "${USE_APPLICATION_INSIGHTS=true}" - }, - "useSearchService": { - "value": "${USE_AZURE_AI_SEARCH_SERVICE=false}" - }, - "agentName": { - "value": "${AZURE_AI_AGENT_NAME=agent-template-assistant}" - }, - "aiAgentID": { - "value": "${AZURE_AI_AGENT_ID}" - }, - "agentDeploymentName": { - "value": "${AZURE_AI_AGENT_MODEL_NAME=gpt-4o-mini}" - }, - "agentModelFormat": { - "value": "${AZURE_AI_AGENT_MODEL_FORMAT=OpenAI}" - }, - "agentModelName": { - "value": "${AZURE_AI_AGENT_MODEL_NAME=gpt-4o-mini}" - }, - "agentModelVersion": { - "value": "${AZURE_AI_AGENT_MODEL_VERSION=2024-07-18}" - }, - "agentDeploymentSku": { - "value": "${AZURE_AI_AGENT_DEPLOYMENT_SKU=GlobalStandard}" - }, - "agentDeploymentCapacity": { - "value": "${AZURE_AI_AGENT_DEPLOYMENT_CAPACITY=50}" - }, - "embeddingDeploymentName": { - "value": "${AZURE_AI_EMBED_DEPLOYMENT_NAME=text-embedding-3-small}" - }, - "embedModelFormat": { - "value": "${AZURE_AI_EMBED_MODEL_FORMAT=OpenAI}" - }, - "embedModelName": { - "value": "${AZURE_AI_EMBED_MODEL_NAME=text-embedding-3-small}" - }, - "embedModelVersion": { - "value": "${AZURE_AI_EMBED_MODEL_VERSION=1}" - }, - "embedDeploymentSku": { - "value": "${AZURE_AI_EMBED_DEPLOYMENT_SKU=Standard}" - }, - "embedDeploymentCapacity": { - "value": "${AZURE_AI_EMBED_DEPLOYMENT_CAPACITY=50}" - }, - "embeddingDeploymentDimensions": { - "value": "${AZURE_AI_EMBED_DIMENSIONS=100}" - }, - "apiAppExists": { - "value": "${SERVICE_API_RESOURCE_EXISTS=false}" - }, - "aiExistingProjectConnectionString": { - "value": "${AZURE_EXISTING_AIPROJECT_CONNECTION_STRING}" - }, - "aiSearchIndexName": { - "value": "${AZURE_AI_SEARCH_INDEX_NAME=index_sample}" - } - } -} diff --git a/next-steps.md b/next-steps.md deleted file mode 100644 index de03a19..0000000 --- a/next-steps.md +++ /dev/null @@ -1,91 +0,0 @@ -# Next Steps after `azd init` - -## Table of Contents - -1. [Next Steps](#next-steps) -2. [What was added](#what-was-added) -3. [Billing](#billing) -4. [Troubleshooting](#troubleshooting) - -## Next Steps - -### Provision infrastructure and deploy application code - -Run `azd up` to provision your infrastructure and deploy to Azure (or run `azd provision` then `azd deploy` to accomplish the tasks separately). Visit the service endpoints listed to see your application up-and-running! - -To troubleshoot any issues, see [troubleshooting](#troubleshooting). - -### Configure environment variables for running services - -Configure environment variables for running services by updating `settings` in [main.parameters.json](./infra/main.parameters.json). - -### Configure CI/CD pipeline - -1. Create a workflow pipeline file locally. The following starters are available: - - [Deploy with GitHub Actions](https://github.com/Azure-Samples/azd-starter-bicep/blob/main/.github/workflows/azure-dev.yml) - - [Deploy with Azure Pipelines](https://github.com/Azure-Samples/azd-starter-bicep/blob/main/.azdo/pipelines/azure-dev.yml) -2. Run `azd pipeline config` to configure the deployment pipeline to connect securely to Azure. - -## What was added - -### Infrastructure configuration - -To describe the infrastructure and application, `azure.yaml` along with Infrastructure as Code files using Bicep were added with the following directory structure: - -```yaml -- azure.yaml # azd project configuration -- infra/ # Infrastructure-as-code Bicep files - - main.bicep # Subscription level resources - - resources.bicep # Primary resource group resources - - modules/ # Library modules -``` - -The resources declared in [resources.bicep](./infra/resources.bicep) are provisioned when running `azd up` or `azd provision`. -This includes: - - -- Azure Container App to host the 'src' service. - -More information about [Bicep](https://aka.ms/bicep) language. - -### Build from source (no Dockerfile) - -#### Build with Buildpacks using Oryx - -If your project does not contain a Dockerfile, we will use [Buildpacks](https://buildpacks.io/) using [Oryx](https://github.com/microsoft/Oryx/blob/main/doc/README.md) to create an image for the services in `azure.yaml` and get your containerized app onto Azure. - -To produce and run the docker image locally: - -1. Run `azd package` to build the image. -2. Copy the *Image Tag* shown. -3. Run `docker run -it ` to run the image locally. - -#### Exposed port - -Oryx will automatically set `PORT` to a default value of `80` (port `8080` for Java). Additionally, it will auto-configure supported web servers such as `gunicorn` and `ASP .NET Core` to listen to the target `PORT`. If your application already listens to the port specified by the `PORT` variable, the application will work out-of-the-box. Otherwise, you may need to perform one of the steps below: - -1. Update your application code or configuration to listen to the port specified by the `PORT` variable -1. (Alternatively) Search for `targetPort` in a .bicep file under the `infra/app` folder, and update the variable to match the port used by the application. - -## Billing - -Visit the *Cost Management + Billing* page in Azure Portal to track current spend. For more information about how you're billed, and how you can monitor the costs incurred in your Azure subscriptions, visit [billing overview](https://learn.microsoft.com/azure/developer/intro/azure-developer-billing). - -## Troubleshooting - -Q: I visited the service endpoint listed, and I'm seeing a blank page, a generic welcome page, or an error page. - -A: Your service may have failed to start, or it may be missing some configuration settings. To investigate further: - -1. Run `azd show`. Click on the link under "View in Azure Portal" to open the resource group in Azure Portal. -2. Navigate to the specific Container App service that is failing to deploy. -3. Click on the failing revision under "Revisions with Issues". -4. Review "Status details" for more information about the type of failure. -5. Observe the log outputs from Console log stream and System log stream to identify any errors. -6. If logs are written to disk, use *Console* in the navigation to connect to a shell within the running container. - -For more troubleshooting information, visit [Container Apps troubleshooting](https://learn.microsoft.com/azure/container-apps/troubleshooting). - -### Additional information - -For additional information about setting up your `azd` project, visit our official [docs](https://learn.microsoft.com/azure/developer/azure-developer-cli/make-azd-compatible?pivots=azd-convert). diff --git a/scripts/write_env.ps1 b/scripts/write_env.ps1 deleted file mode 100644 index 9ba3d8b..0000000 --- a/scripts/write_env.ps1 +++ /dev/null @@ -1,29 +0,0 @@ -# Define the .env file path -$envFilePath = "src\.env" - -# Clear the contents of the .env file -Set-Content -Path $envFilePath -Value "" - -# Append new values to the .env file -$azureAiProjectConnectionString = azd env get-value AZURE_AIPROJECT_CONNECTION_STRING -$azureAiagentDeploymentName = azd env get-value AZURE_AI_AGENT_DEPLOYMENT_NAME -$azureAiAgentId = azd env get-value AZURE_AI_AGENT_ID -$azureAiAgentName = azd env get-value AZURE_AI_AGENT_NAME -$azureTenantId = azd env get-value AZURE_TENANT_ID -$searchConnectionName = azd env get-value AZURE_AI_SEARCH_CONNECTION_NAME -$azureAIEmbedDeploymentName = azd env get-value AZURE_AI_EMBED_DEPLOYMENT_NAME -$azureAIEmbedDimensions = azd env get-value AZURE_AI_EMBED_DIMENSIONS -$azureAISearchIndexName = azd env get-value AZURE_AI_SEARCH_INDEX_NAME -$azureAISearchEndpoint = azd env get-value AZURE_AI_SEARCH_ENDPOINT - -Add-Content -Path $envFilePath -Value "AZURE_AIPROJECT_CONNECTION_STRING=$azureAiProjectConnectionString" -Add-Content -Path $envFilePath -Value "AZURE_AI_AGENT_DEPLOYMENT_NAME=$azureAiagentDeploymentName" -Add-Content -Path $envFilePath -Value "AZURE_AI_AGENT_ID=$azureAiAgentId" -Add-Content -Path $envFilePath -Value "AZURE_TENANT_ID=$azureTenantId" -Add-Content -Path $envFilePath -Value "AZURE_AI_SEARCH_CONNECTION_NAME=$searchConnectionName" -Add-Content -Path $envFilePath -Value "AZURE_AI_EMBED_DEPLOYMENT_NAME=$azureAIEmbedDeploymentName" -Add-Content -Path $envFilePath -Value "AZURE_AI_EMBED_DIMENSIONS=$azureAIEmbedDimensions" -Add-Content -Path $envFilePath -Value "AZURE_AI_SEARCH_INDEX_NAME=$azureAISearchIndexName" -Add-Content -Path $envFilePath -Value "AZURE_AI_SEARCH_ENDPOINT=$azureAISearchEndpoint" -Add-Content -Path $envFilePath -Value "AZURE_AI_AGENT_NAME=$azureAiAgentName" -Add-Content -Path $envFilePath -Value "AZURE_TENANT_ID=$azureTenantId" \ No newline at end of file diff --git a/scripts/write_env.sh b/scripts/write_env.sh deleted file mode 100755 index 03477ee..0000000 --- a/scripts/write_env.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# Define the .env file path -ENV_FILE_PATH="src/.env" - -# Clear the contents of the .env file -> $ENV_FILE_PATH - -echo "AZURE_AIPROJECT_CONNECTION_STRING=$(azd env get-value AZURE_AIPROJECT_CONNECTION_STRING)" >> $ENV_FILE_PATH -echo "AZURE_AI_AGENT_DEPLOYMENT_NAME=$(azd env get-value AZURE_AI_AGENT_DEPLOYMENT_NAME)" >> $ENV_FILE_PATH -echo "AZURE_AI_AGENT_ID=$(azd env get-value AZURE_AI_AGENT_ID)" >> $ENV_FILE_PATH -echo "AZURE_TENANT_ID=$(azd env get-value AZURE_TENANT_ID)" >> $ENV_FILE_PATH -echo "AZURE_AI_SEARCH_CONNECTION_NAME=$(azd env get-value AZURE_AI_SEARCH_CONNECTION_NAME)" >> $ENV_FILE_PATH -echo "AZURE_AI_EMBED_DEPLOYMENT_NAME=$(azd env get-value AZURE_AI_EMBED_DEPLOYMENT_NAME)" >> $ENV_FILE_PATH -echo "AZURE_AI_EMBED_DIMENSIONS=$(azd env get-value AZURE_AI_EMBED_DIMENSIONS)" >> $ENV_FILE_PATH -echo "AZURE_AI_SEARCH_INDEX_NAME=$(azd env get-value AZURE_AI_SEARCH_INDEX_NAME)" >> $ENV_FILE_PATH -echo "AZURE_AI_SEARCH_ENDPOINT=$(azd env get-value AZURE_AI_SEARCH_ENDPOINT)" >> $ENV_FILE_PATH -echo "AZURE_AI_AGENT_NAME=$(azd env get-value AZURE_AI_AGENT_NAME)" >> $ENV_FILE_PATH -echo "AZURE_TENANT_ID=$(azd env get-value AZURE_TENANT_ID)" >> $ENV_FILE_PATH -exit 0 \ No newline at end of file