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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/app_registration_setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ To enable secure automation and integration with Azure and Power Platform, you n
1. Login to your Power Platform:

```shell
pac auth create
pac auth create --deviceCode
```

1. Create new **App Registration**:
Expand Down
2 changes: 1 addition & 1 deletion docs/cicd.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ All infrastructure for CI/CD lives under `cicd/` and can be customized to meet y

## Prerequisites

- Working local environment of this template. If you do not have one, Follow the step by step instructions for setting up your [**Local Environment**](../README.md#local-environment)
- Working local environment of this template. If you do not have one, Follow the step by step instructions for setting up your [**Local Environment**](../README.md#local-environment).
- An Azure subscription with either User Access Administrator or Owner permissions to create workload identity resources like service principal, and OIDC to be used by the GitHub Actions.
- GitHub CLI (`gh`) installed and authenticated to trigger the bootstrap workflow from your terminal.

Expand Down
13 changes: 13 additions & 0 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Troubleshooting tips

## Quota error during deployment

If you see an InsufficientQuota error mentioning "Tokens Per Minute", the requested `scale.capacity` (thousands of TPM) exceeds your subscription's available quota — lower `scale.capacity` in TFVARS or request a quota increase in the Azure portal.

## Private endpoint fails with AccountProvisioningStateInvalid

This occurs when Terraform tries to create the private endpoint before the Azure OpenAI (Cognitive Services) account leaves the `Accepted` state; wait until the resource shows `Succeeded` (portal or `az resource show`) and re-run the provisioning (`azd provision`).

## Use GitHub Copilot to help troubleshoot

If you're unsure how to fix a deployment error, open the relevant files in VS Code and use GitHub Copilot for suggestions. Copilot can propose TFVARS overrides, sample values, terraform plan snippets, or concise support-request wording; always review and test generated suggestions before applying them.
50 changes: 40 additions & 10 deletions infra/main.ai.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

# Wait for network infrastructure to be ready
resource "time_sleep" "wait_for_network_ready" {
depends_on = [
module.copilot_studio
]
create_duration = "30s"
}

module "azure_open_ai" {
# checkov:skip=CKV2_AZURE_22: Customer-managed keys should be added in production usage but are not included here for simplicity.
# checkov:skip=CKV_AZURE_236: The Power Platform AI Search connector only supports service principal, API key, or interactive auth.
Expand Down Expand Up @@ -32,19 +40,41 @@ module "azure_open_ai" {
]
}

private_endpoints = {
pe_endpoint = {
name = "pe-${azurecaf_name.main_names.results["azurerm_cognitive_account"]}"
private_service_connection_name = "pe_endpoint_connection"
subnet_resource_id = local.pe_primary_subnet_id
}
}
managed_identities = {
system_assigned = true
}
tags = var.tags

depends_on = [module.copilot_studio]
depends_on = [time_sleep.wait_for_network_ready]
}

# Wait for Azure OpenAI service to be fully provisioned
resource "time_sleep" "wait_for_openai_provisioning" {
depends_on = [module.azure_open_ai]
create_duration = "60s"

# Ensure the OpenAI service is in a ready state before proceeding with private endpoint creation
triggers = {
openai_id = module.azure_open_ai.resource.id
}
}

# Create private endpoint separately to ensure OpenAI service is fully ready
resource "azurerm_private_endpoint" "openai_pe" {
name = "pe-${azurecaf_name.main_names.results["azurerm_cognitive_account"]}"
location = local.primary_azure_region
resource_group_name = local.resource_group_name
subnet_id = local.pe_primary_subnet_id
tags = var.tags

private_service_connection {
name = "pe_endpoint_connection"
private_connection_resource_id = module.azure_open_ai.resource.id
subresource_names = ["account"]
is_manual_connection = false
}

depends_on = [time_sleep.wait_for_openai_provisioning]
}

# Private DNS zone for Azure OpenAI private endpoint resolution
Expand All @@ -69,12 +99,12 @@ resource "azurerm_private_dns_zone_virtual_network_link" "aoai_dns_links" {
}

# DNS A record for Azure OpenAI private endpoint
# The module creates the private endpoint, so we reference it from the module outputs
# Reference the separately created private endpoint
resource "azurerm_private_dns_a_record" "aoai_dns_record" {
name = module.azure_open_ai.resource.name
zone_name = azurerm_private_dns_zone.aoai_dns.name
resource_group_name = local.resource_group_name
ttl = 10
records = [module.azure_open_ai.private_endpoints["pe_endpoint"].private_service_connection[0].private_ip_address]
records = [azurerm_private_endpoint.openai_pe.private_service_connection[0].private_ip_address]
tags = var.tags
}
14 changes: 14 additions & 0 deletions infra/main.app_insights.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,27 @@

resource "random_uuid" "uid" {}

resource "azurerm_log_analytics_workspace" "monitoring" {
count = var.include_log_analytics ? 1 : 0

daily_quota_gb = -1
location = local.primary_azure_region
name = azurecaf_name.main_names.results["azurerm_log_analytics_workspace"]
resource_group_name = local.resource_group_name
retention_in_days = var.log_analytics_retention_in_days
sku = "PerGB2018"
tags = var.tags
}

resource "azurerm_application_insights" "insights" {
count = var.include_app_insights ? 1 : 0

application_type = "web"
location = local.primary_azure_region
name = "${var.resource_prefix}-appinsights-${var.resource_suffix}"
resource_group_name = local.resource_group_name
workspace_id = var.include_log_analytics ? azurerm_log_analytics_workspace.monitoring[0].id : null
tags = var.tags
}

resource "azurerm_application_insights_workbook" "workbook" {
Expand Down
Loading
Loading