Skip to content

cyber-scot/terraform-azurerm-vm-start-stop-solution

Repository files navigation

Information

All credit for this solution goes to Microsoft and documentation on the solution specifically can be found at Microsoft's GitHub repo and the documentation on Microsoft Docs

This module also utilised the use of aztfexport, so again, full credit to Microsoft 😄

The code in this repo is purely for deploying the Microsoft solution using terraform, rather than the default ARM template deployment

For any specific issues with the terraform deployment, you can raise issues and improvements here, with the azurerm provider or with terraform itself

Potential Infrastructure Improvements for v1.1.0 (PRs welcome)

These are some known issues in the infrastructure for the v1.0.0 deployment. PRs are welcome on these suggestions for a v1.1.0 release. These issues should also exist in the Microsoft ARM template deployment as the v1.0.0 build aims to be a like-for-like replacement with some extra utilities on naming and configuration options

  • Enabling the Storage Account firewall causes logic app deployment issues. It is disabled by default in the Microsoft deployment and by default in v1.0.0
  • Disable storage account keys and use managed identities
    • Switch to optional user-assigned managed identity for all resources (e.g. id-start-stop-solution)
  • Private endpoint support and VNet integration for function app
  • HTTPS only mode fails
  • Sometimes, when first creating start/stop, alerts may not be created properly due to app insights instance calls failures. Running apply for a second time seems to resolve this.
data "azurerm_client_config" "current" {}

locals {
  hidden_link_tags = {
    "hidden-link:${azurerm_resource_group.this.id}/providers/Microsoft.Insights/components/${azurerm_resource_group.this.name}" = "Resource"
  }
  combined_hidden_link_tags = merge(var.tags, local.hidden_link_tags)

  solution_tags = {
    SolutionName = "StartStopV2"
  }

  solution_merged_tags = merge(var.tags, local.solution_tags)
}

resource "azurerm_resource_group" "this" {
  name     = "rg-${var.name}"
  location = var.location
  tags     = var.tags
}

resource "azurerm_management_lock" "rg_lock" {
  count      = var.lock_level != null && var.lock_level != "" ? 1 : 0
  name       = "lock-${var.name}"
  scope      = azurerm_resource_group.this.id
  lock_level = var.lock_level
  notes      = "Resource Group '${var.name}' is locked with '${var.lock_level}' level."
}

resource "azurerm_log_analytics_workspace" "law" {
  count                              = var.create_law_linked_app_insights && var.create_new_law ? 1 : 0
  name                               = try(var.law_name, null) != null ? var.law_name : "law-${var.name}"
  location                           = azurerm_resource_group.this.location
  resource_group_name                = azurerm_resource_group.this.name
  allow_resource_only_permissions    = try(var.allow_resource_only_permissions, true)
  local_authentication_disabled      = try(var.local_authentication_disabled, true)
  cmk_for_query_forced               = try(var.cmk_for_query_forced, false, null)
  sku                                = title(try(var.law_sku, null))
  retention_in_days                  = try(var.retention_in_days, null)
  reservation_capacity_in_gb_per_day = var.law_sku == "CapacityReservation" ? var.reservation_capacity_in_gb_per_day : null
  daily_quota_gb                     = title(var.law_sku) == "Free" ? "0.5" : try(var.daily_quota_gb, null)
  internet_ingestion_enabled         = try(var.internet_ingestion_enabled, null)
  internet_query_enabled             = try(var.internet_query_enabled, null)
  tags                               = try(var.tags, null)
}

data "azurerm_log_analytics_workspace" "read_created_law" {
  count               = var.create_law_linked_app_insights && !var.create_new_law ? 1 : 0
  name                = element(azurerm_log_analytics_workspace.law.*.name, 0)
  resource_group_name = azurerm_resource_group.this.name
}

resource "azurerm_application_insights" "app_insights" {
  name                = var.app_insights_name != null ? var.app_insights_name : "appi-${var.name}"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name
  application_type    = "web"
  disable_ip_masking  = null
  sampling_percentage = 0
  tags                = try(var.tags, null)

  workspace_id = var.create_law_linked_app_insights ? (
    var.create_new_law && var.law_id == null ? azurerm_log_analytics_workspace.law[0].id : var.law_id
  ) : null
}

resource "azurerm_monitor_action_group" "notification_group_ag" {
  name                = var.notification_action_group_name != null ? var.notification_action_group_name : "StartStopV2_VM_Notification"
  resource_group_name = azurerm_resource_group.this.name
  short_name          = var.notification_action_group_short_name != null ? var.notification_action_group_short_name : "StStAlertV2"
  tags                = local.solution_merged_tags
  dynamic "email_receiver" {
    for_each = var.email_receivers
    content {
      email_address = email_receiver.value.email_address
      name          = email_receiver.value.name
    }
  }
}

resource "azurerm_monitor_action_group" "app_insights_ag" {
  name                = var.smart_detection_action_group_name != null ? var.smart_detection_action_group_name : "Application Insights Smart Detection"
  resource_group_name = azurerm_resource_group.this.name
  short_name          = var.smart_detection_action_group_short_name != null ? var.smart_detection_action_group_short_name : "SmartDetect"
  tags                = local.solution_merged_tags
  arm_role_receiver {
    name                    = "Monitoring Contributor"
    role_id                 = "749f88d5-cbae-40b8-bcfc-e573ddc772fa"
    use_common_alert_schema = true
  }
  arm_role_receiver {
    name                    = "Monitoring Reader"
    role_id                 = "43d0d8ad-25c7-4714-9337-8ba259a9fe05"
    use_common_alert_schema = true
  }
}

resource "azurerm_monitor_scheduled_query_rules_alert_v2" "auto_stop_query_alert_rules" {
  description          = "Start/Stop VMs during off-hours : AutoStop azure function has attempted an action"
  evaluation_frequency = "PT5M"
  location             = azurerm_resource_group.this.location
  name                 = var.auto_stop_query_alert_name != null ? var.auto_stop_query_alert_name : "AutoStop_VM_AzFunc"
  resource_group_name  = azurerm_resource_group.this.name
  scopes               = var.auto_stop_query_alert_scopes != [] ? toset([azurerm_application_insights.app_insights.id]) : var.auto_stop_query_alert_scopes
  severity             = 4
  tags                 = local.combined_hidden_link_tags
  window_duration      = "PT5M"
  action {
    action_groups = var.auto_stop_query_action_groups != [] ? toset([azurerm_monitor_action_group.notification_group_ag.id]) : var.auto_stop_query_action_groups
  }
  criteria {
    operator                = "GreaterThan"
    query                   = <<-EOT
      traces
      | where (operation_Name contains "AutoStop")
      | where (message hasprefix "~AutoStop")
      | extend output = substring(message,1)
      | summarize by message, output
      | project output
    EOT
    threshold               = 0
    time_aggregation_method = "Count"
    failing_periods {
      minimum_failing_periods_to_trigger_alert = 1
      number_of_evaluation_periods             = 1
    }
  }
}

resource "azurerm_monitor_scheduled_query_rules_alert_v2" "scheduled_query_alert_rules" {
  description          = "Start/Stop VMs during off-hours : Scheduled azure function has attempted an action"
  evaluation_frequency = "PT5M"
  location             = azurerm_resource_group.this.location
  name                 = var.scheduled_start_stop_query_alert_name != null ? var.scheduled_start_stop_query_alert_name : "ScheduledStartStop_AzFunc"
  resource_group_name  = azurerm_resource_group.this.name
  scopes               = var.scheduled_query_alert_scopes != [] ? toset([azurerm_application_insights.app_insights.id]) : var.scheduled_query_alert_scopes
  severity             = 4
  tags                 = local.combined_hidden_link_tags
  window_duration      = "PT5M"
  action {
    action_groups = var.scheduled_query_action_groups != [] ? toset([azurerm_monitor_action_group.notification_group_ag.id]) : var.scheduled_query_action_groups
  }
  criteria {
    operator                = "GreaterThan"
    query                   = <<-EOT
    traces
    | where (operation_Name contains "Scheduled")
    | where (message hasprefix "~Scheduled")
    | extend output = substring(message,1)
    | summarize by message, output
    | project output
  EOT
    threshold               = 0
    time_aggregation_method = "Count"

    failing_periods {
      minimum_failing_periods_to_trigger_alert = 1
      number_of_evaluation_periods             = 1
    }
  }
}

resource "azurerm_monitor_scheduled_query_rules_alert_v2" "sequenced_query_alert_rules" {
  description          = "Start/Stop VMs during off-hours : Sequenced azure function has attempted an action"
  evaluation_frequency = "PT5M"
  location             = azurerm_resource_group.this.location
  name                 = var.scheduled_start_stop_query_alert_name != null ? var.scheduled_start_stop_query_alert_name : "SequencedStartStop_AzFunc"
  resource_group_name  = azurerm_resource_group.this.name
  scopes               = var.sequenced_query_alert_scopes != [] ? toset([azurerm_application_insights.app_insights.id]) : var.sequenced_query_alert_scopes
  severity             = 4
  tags                 = local.combined_hidden_link_tags
  window_duration      = "PT5M"
  action {
    action_groups = var.sequenced_query_action_groups != [] ? toset([azurerm_monitor_action_group.notification_group_ag.id]) : var.sequenced_query_action_groups
  }
  criteria {
    operator                = "GreaterThan"
    query                   = <<-EOT
    traces
    | where (operation_Name contains "Scheduled")
    | where (message hasprefix "~Sequenced")
    | extend output = substring(message,1)
    | summarize by message, output
    | project output
  EOT
    threshold               = 0
    time_aggregation_method = "Count"

    failing_periods {
      minimum_failing_periods_to_trigger_alert = 1
      number_of_evaluation_periods             = 1
    }
  }
}

resource "azurerm_monitor_smart_detector_alert_rule" "app_insights_anomalies_detector" {
  description         = "Failure Anomalies notifies you of an unusual rise in the rate of failed HTTP requests or dependency calls."
  detector_type       = "FailureAnomaliesDetector"
  frequency           = "PT1M"
  name                = "Failure Anomalies - ${azurerm_application_insights.app_insights.name}"
  resource_group_name = azurerm_resource_group.this.name
  scope_resource_ids  = [azurerm_application_insights.app_insights.id]
  severity            = "Sev3"
  tags                = local.solution_merged_tags
  action_group {
    ids = [azurerm_monitor_action_group.app_insights_ag.id]
  }
}

locals {
  storage_merged_ip_rules = concat(
    split(",", azurerm_windows_function_app.function_app.outbound_ip_addresses),
    split(",", azurerm_windows_function_app.function_app.possible_outbound_ip_addresses),
    azurerm_logic_app_workflow.logic_app_auto_stop.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_auto_stop.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_auto_stop.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_auto_stop.workflow_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_start.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_start.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_start.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_start.workflow_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_stop.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_stop.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_stop.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_stop.workflow_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_start.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_start.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_start.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_start.workflow_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_stop.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_stop.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_stop.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_stop.workflow_endpoint_ip_addresses,
    var.storage_account_firewall_user_ip_rules
  )

  all_solution_ips = toset(concat(
    split(",", azurerm_windows_function_app.function_app.outbound_ip_addresses),
    split(",", azurerm_windows_function_app.function_app.possible_outbound_ip_addresses),
    azurerm_logic_app_workflow.logic_app_auto_stop.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_auto_stop.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_auto_stop.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_auto_stop.workflow_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_start.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_start.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_start.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_start.workflow_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_stop.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_stop.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_stop.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_sequenced_stop.workflow_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_start.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_start.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_start.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_start.workflow_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_stop.connector_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_stop.connector_endpoint_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_stop.workflow_outbound_ip_addresses,
    azurerm_logic_app_workflow.logic_app_scheduled_stop.workflow_endpoint_ip_addresses,
  ))
}

resource "azurerm_storage_account_network_rules" "storage_rules" {
  storage_account_id         = azurerm_storage_account.storage.id
  default_action             = var.storage_account_firewall_default_action
  bypass                     = var.storage_account_firewall_bypass
  virtual_network_subnet_ids = var.storage_account_firewall_subnet_ids
  ip_rules                   = local.storage_merged_ip_rules
}


resource "azurerm_role_assignment" "client_blob_owner" {
  count                = var.use_user_assigned_identity == true && var.assign_current_client_blob_owner == true ? 1 : 0
  principal_id         = data.azurerm_client_config.current.object_id
  scope                = format("/subscriptions/%s", data.azurerm_client_config.current.subscription_id)
  role_definition_name = "Storage Blob Data Owner"
}

resource "azurerm_role_assignment" "client_smb_contributor" {
  count                = var.use_user_assigned_identity == true && var.assign_current_client_smb_contributor == true ? 1 : 0
  principal_id         = data.azurerm_client_config.current.object_id
  scope                = format("/subscriptions/%s", data.azurerm_client_config.current.subscription_id)
  role_definition_name = "Storage File Data SMB Share Contributor"
}

resource "azurerm_role_assignment" "client_queue_contributor" {
  count                = var.use_user_assigned_identity == true && var.assign_current_client_queue_contributor == true ? 1 : 0
  principal_id         = data.azurerm_client_config.current.object_id
  scope                = format("/subscriptions/%s", data.azurerm_client_config.current.subscription_id)
  role_definition_name = "Storage Queue Data Contributor"
}

resource "azurerm_role_assignment" "client_table_contributor" {
  count                = var.use_user_assigned_identity == true && var.assign_current_client_table_contributor == true ? 1 : 0
  principal_id         = data.azurerm_client_config.current.object_id
  scope                = format("/subscriptions/%s", data.azurerm_client_config.current.subscription_id)
  role_definition_name = "Storage Table Data Contributor"
}

resource "azurerm_storage_account" "storage" {
  depends_on = [
    azurerm_role_assignment.client_blob_owner[0],
    azurerm_role_assignment.client_queue_contributor[0],
    azurerm_role_assignment.client_smb_contributor[0],
    azurerm_role_assignment.client_table_contributor[0]
  ]
  account_kind                    = "StorageV2"
  account_replication_type        = "LRS"
  account_tier                    = "Standard"
  allow_nested_items_to_be_public = false
  location                        = azurerm_resource_group.this.location
  min_tls_version                 = "TLS1_2"
  name                            = var.storage_account_name != null ? var.storage_account_name : "sa${var.name}"
  resource_group_name             = azurerm_resource_group.this.name
  tags                            = local.solution_merged_tags
  public_network_access_enabled   = var.storage_account_public_network_access_enabled
  shared_access_key_enabled       = var.storage_account_shared_access_keys_enabled

  dynamic "identity" {
    for_each = var.use_user_assigned_identity == true ? [1] : []
    content {
      type         = "UserAssigned"
      identity_ids = toset([azurerm_user_assigned_identity.uid[0].id])
    }
  }
}

resource "azurerm_storage_container" "web_jobs_hosts" {
  name                 = "azure-webjobs-hosts"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_storage_container" "web_jobs_secrets" {
  name                 = "azure-webjobs-secrets"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_storage_queue" "auto_update_request_queue" {
  name                 = "auto-update-request-queue"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_storage_queue" "create_alert_request" {
  name                 = "create-alert-request"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_storage_queue" "execution_request" {
  name                 = "execution-request"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_storage_queue" "orchestration_request" {
  name                 = "orchestration-request"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_storage_queue" "savings_request_queue" {
  name                 = "savings-request-queue"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_storage_table" "auto_update_request_details_store_table" {
  name                 = "autoupdaterequestdetailsstoretable"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_storage_table" "requests_store_stable" {
  name                 = "requeststoretable"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_storage_table" "subscription_requests_store_stable" {
  name                 = "subscriptionrequeststoretable"
  storage_account_name = azurerm_storage_account.storage.name
}

resource "azurerm_service_plan" "fnc_asp" {
  location            = azurerm_resource_group.this.location
  name                = var.app_service_plan_name != null ? var.app_service_plan_name : "asp-${var.name}"
  os_type             = "Windows"
  resource_group_name = azurerm_resource_group.this.name
  sku_name            = "Y1"
  tags                = local.solution_merged_tags
}

locals {
  default_app_settings = {
    AzureWebJobsDisableHomepage                         = "true"
    WEBSITE_CONTENTAZUREFILECONNECTIONSTRING            = "DefaultEndpointsProtocol=https;AccountName=${azurerm_storage_account.storage.name};AccountKey=${azurerm_storage_account.storage.primary_access_key}"
    WEBSITE_RUN_FROM_PACKAGE                            = var.start_stop_source_url
    APPLICATIONINSIGHTS_CONNECTION_STRING               = azurerm_application_insights.app_insights.connection_string
    APPINSIGHTS_INSTRUMENTATIONKEY                      = azurerm_application_insights.app_insights.instrumentation_key
    SOURCE_CODE_ORIGIN                                  = var.attempt_fetch_remote_start_stop_code == true ? var.start_stop_source_url : "local"
    "AzureClientOptions:ApplicationInsightName"         = var.app_insights_name != null ? var.app_insights_name : "appi-${var.name}"
    MSDEPLOY_RENAME_LOCKED_FILES                        = "1"
    "AzureClientOptions:ApplicationInsightRegion"       = azurerm_resource_group.this.location
    "AzureClientOptions:AutoUpdateRegionsUri"           = "https://startstopv2prod.blob.core.windows.net/artifacts/AutoUpdateRegionsGA.json"
    "AzureClientOptions:AutoUpdateTemplateUri"          = "https://startstopv2prod.blob.core.windows.net/artifacts/ssv2autoupdate.json"
    "AzureClientOptions:AzEnabled"                      = "false"
    "AzureClientOptions:AzureEnvironment"               = "AzureGlobalCloud"
    "AzureClientOptions:EnableAutoUpdate"               = "true"
    "AzureClientOptions:FunctionAppName"                = var.function_app_name != null ? var.function_app_name : "fnc-${var.name}"
    "AzureClientOptions:ResourceGroup"                  = azurerm_resource_group.this.name
    "AzureClientOptions:ResourceGroupRegion"            = azurerm_resource_group.this.location
    "AzureClientOptions:StorageAccountName"             = azurerm_storage_account.storage.name
    "AzureClientOptions:SubscriptionId"                 = data.azurerm_client_config.current.subscription_id
    "AzureClientOptions:TenantId"                       = data.azurerm_client_config.current.tenant_id
    "AzureClientOptions:Version"                        = "1.1.20221110.1"
    AzureWebJobsDisableHomepage                         = "true"
    "CentralizedLoggingOptions:InstrumentationKey"      = var.microsoft_instrumentation_key != null ? var.microsoft_instrumentation_key : "294eafc8-410b-4170-aecb-dfaa5cb6eeaa"
    "CentralizedLoggingOptions:Version"                 = "1.1.20221110.1"
    "StorageOptions:AutoUpdateRequestDetailsStoreTable" = azurerm_storage_table.auto_update_request_details_store_table.name
    "StorageOptions:AutoUpdateRequestQueue"             = azurerm_storage_queue.auto_update_request_queue.name
    "StorageOptions:CreateAutoStopAlertRequestQueue"    = azurerm_storage_queue.create_alert_request.name
    "StorageOptions:ExecutionRequestQueue"              = azurerm_storage_queue.execution_request.name
    "StorageOptions:OrchestrationRequestQueue"          = azurerm_storage_queue.orchestration_request.name
    "StorageOptions:RequestStoreTable"                  = azurerm_storage_table.requests_store_stable.name
    "StorageOptions:SavingsRequestQueue"                = azurerm_storage_queue.savings_request_queue.name
    "StorageOptions:StorageAccountConnectionString"     = "DefaultEndpointsProtocol=https;AccountName=${azurerm_storage_account.storage.name};AccountKey=${azurerm_storage_account.storage.primary_access_key}"
    "StorageOptions:SubscriptionRequestStoreTable"      = azurerm_storage_table.subscription_requests_store_stable.name
  }
  new_app_settings = {
    "AzureWebJobsStorage__blobServiceUri"  = "https://${azurerm_storage_account.storage.name}.blob.core.windows.net"
    "AzureWebJobsStorage__queueServiceUri" = "https://${azurerm_storage_account.storage.name}.queue.core.windows.net"
    "AzureWebJobsStorage__tableServiceUri" = "https://${azurerm_storage_account.storage.name}.table.core.windows.net"
    AzureWebJobsStorage                    = "DefaultEndpointsProtocol=https;AccountName=${azurerm_storage_account.storage.name};AccountKey=${azurerm_storage_account.storage.primary_access_key}"
    APPLICATIONINSIGHTS_CONNECTION_STRING  = azurerm_application_insights.app_insights.connection_string
    APPINSIGHTS_INSTRUMENTATIONKEY         = azurerm_application_insights.app_insights.instrumentation_key
    FUNCTIONS_EXTENSION_VERSION            = "~4"
    WEBSITE_NODE_DEFAULT_VERSION           = "~10"
    "WEBSITE_CONTENTSHARE"                 = var.function_app_name != null ? var.function_app_name : "fnc-${var.name}"
  }
  app_settings = merge(local.new_app_settings, local.default_app_settings)
}

resource "azurerm_windows_function_app" "function_app" {
  app_settings = local.app_settings

  builtin_logging_enabled    = false
  client_certificate_enabled = true
  location                   = azurerm_resource_group.this.location
  name                       = var.function_app_name != null ? var.function_app_name : "fnc-${var.name}"
  resource_group_name        = azurerm_resource_group.this.name
  service_plan_id            = azurerm_service_plan.fnc_asp.id
  storage_account_access_key = azurerm_storage_account.storage.primary_access_key
  storage_account_name       = azurerm_storage_account.storage.name
  https_only                 = var.function_app_https_only
  tags                       = local.solution_merged_tags

  dynamic "identity" {
    for_each = var.use_user_assigned_identity == true ? [1] : []
    content {
      type         = "UserAssigned"
      identity_ids = toset([azurerm_user_assigned_identity.uid[0].id])
    }
  }

  dynamic "identity" {
    for_each = var.use_user_assigned_identity == false ? [1] : []
    content {
      type = "SystemAssigned"
    }
  }

  site_config {
    application_stack {
      dotnet_version = "v6.0"
    }

    ftps_state = "FtpsOnly"
  }
}

resource "azurerm_user_assigned_identity" "uid" {
  count               = var.use_user_assigned_identity == true ? 1 : 0
  location            = azurerm_resource_group.this.location
  name                = var.user_assigned_identity_name != null ? var.user_assigned_identity_name : "uid-ststv2"
  resource_group_name = azurerm_resource_group.this.name
}

resource "azurerm_role_assignment" "id_contributor" {
  principal_id         = var.use_user_assigned_identity == true ? azurerm_user_assigned_identity.uid[0].principal_id : azurerm_windows_function_app.function_app.identity[0].principal_id
  scope                = format("/subscriptions/%s", data.azurerm_client_config.current.subscription_id)
  role_definition_name = "Contributor"
}

resource "azurerm_role_assignment" "id_blob_owner" {
  count                = var.use_user_assigned_identity == true ? 1 : 0
  principal_id         = var.use_user_assigned_identity == true ? azurerm_user_assigned_identity.uid[0].principal_id : azurerm_windows_function_app.function_app.identity[0].principal_id
  scope                = format("/subscriptions/%s", data.azurerm_client_config.current.subscription_id)
  role_definition_name = "Storage Blob Data Owner"
}

resource "azurerm_role_assignment" "id_smb_contributor" {
  count                = var.use_user_assigned_identity == true ? 1 : 0
  principal_id         = var.use_user_assigned_identity == true ? azurerm_user_assigned_identity.uid[0].principal_id : azurerm_windows_function_app.function_app.identity[0].principal_id
  scope                = format("/subscriptions/%s", data.azurerm_client_config.current.subscription_id)
  role_definition_name = "Storage File Data SMB Share Contributor"
}

resource "azurerm_role_assignment" "id_queue_contributor" {
  count                = var.use_user_assigned_identity == true ? 1 : 0
  principal_id         = var.use_user_assigned_identity == true ? azurerm_user_assigned_identity.uid[0].principal_id : azurerm_windows_function_app.function_app.identity[0].principal_id
  scope                = format("/subscriptions/%s", data.azurerm_client_config.current.subscription_id)
  role_definition_name = "Storage Queue Data Contributor"
}

resource "azurerm_role_assignment" "id_table_contributor" {
  count                = var.use_user_assigned_identity == true ? 1 : 0
  principal_id         = var.use_user_assigned_identity == true ? azurerm_user_assigned_identity.uid[0].principal_id : azurerm_windows_function_app.function_app.identity[0].principal_id
  scope                = format("/subscriptions/%s", data.azurerm_client_config.current.subscription_id)
  role_definition_name = "Storage Table Data Contributor"
}

resource "time_sleep" "wait_120_seconds" {
  depends_on = [azurerm_role_assignment.id_contributor]

  create_duration = "120s"
}

resource "azurerm_logic_app_workflow" "logic_app_auto_stop" {
  depends_on          = [time_sleep.wait_120_seconds]
  enabled             = var.auto_stop_logic_app_enabled
  location            = azurerm_resource_group.this.location
  name                = var.auto_stop_logic_app_name != null ? var.auto_stop_logic_app_name : "ststv2_vms_AutoStop"
  resource_group_name = azurerm_resource_group.this.name
  tags                = local.solution_merged_tags

  dynamic "identity" {
    for_each = var.use_user_assigned_identity == true ? [1] : []
    content {
      type         = "UserAssigned"
      identity_ids = toset([azurerm_user_assigned_identity.uid[0].id])
    }
  }
}


resource "azurerm_logic_app_action_custom" "auto_stop_terminate" {
  depends_on = [
    time_sleep.wait_120_seconds,
    azurerm_logic_app_action_custom.auto_stop_function,
  ]

  body = jsonencode({
    "actions" : {
      "Terminate" : {
        "inputs" : {
          "runError" : {
            "code" : "@{outputs('AutoStop')['statusCode']}",
            "message" : "@{body('AutoStop')}"
          },
          "runStatus" : "Failed"
        },
        "type" : "Terminate"
      }
    },
    "runAfter" : {
      "Function-Try" : ["Failed", "Skipped", "TimedOut"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_auto_stop.id
  name         = "Function-Catch"
}

resource "azurerm_logic_app_action_custom" "auto_stop_success_function" {
  depends_on = [
    azurerm_windows_function_app.function_app,
    azurerm_logic_app_action_custom.auto_stop_terminate
  ]
  body = jsonencode({
    "runAfter" : {
      "Function-Try" : ["Succeeded"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_auto_stop.id
  name         = "Function-Success"
}

resource "azurerm_logic_app_action_custom" "auto_stop_function" {
  depends_on = [
    time_sleep.wait_120_seconds
  ]

  body = jsonencode({
    "actions" : {
      "AutoStop" : {
        "inputs" : {
          "body" : {
            "Action" : "stop",
            "AutoStop_Condition" : "LessThan",
            "AutoStop_Description" : "Alert to stop the VM if the CPU % exceed the threshold",
            "AutoStop_Frequency" : "00:05:00",
            "AutoStop_MetricName" : "Percentage CPU",
            "AutoStop_Severity" : "2",
            "AutoStop_Threshold" : "5",
            "AutoStop_TimeAggregationOperator" : "Average",
            "AutoStop_TimeWindow" : "06:00:00",
            "EnableClassic" : false,
            "RequestScopes" : {
              "ResourceGroups" : "${toset(var.auto_stop_resource_group_scopes)}"
            }
          },
          "function" : {
            "id" : "${azurerm_windows_function_app.function_app.id}/functions/Scheduled"
          }
        },
        "type" : "Function"
      }
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_auto_stop.id
  name         = "Function-Try"
}

resource "azurerm_logic_app_trigger_recurrence" "auto_stop_recurrence_trigger" {
  depends_on = [
    azurerm_windows_function_app.function_app
  ]
  frequency    = var.auto_stop_logic_app_evaluation_frequency
  interval     = var.auto_stop_logic_app_evaluation_interval_number
  start_time   = var.auto_stop_logic_app_evaluation_interval_start_time
  time_zone    = var.logic_app_default_timezone != null ? var.logic_app_default_timezone : "GMT Standard Time"
  logic_app_id = azurerm_logic_app_workflow.logic_app_auto_stop.id
  name         = "Recurrence"

  dynamic "schedule" {
    for_each = [for s in var.auto_stop_schedules : s if length(s.days) > 0 || length(s.hours) > 0 || length(s.minutes) > 0]
    content {
      on_these_days    = schedule.value.days
      at_these_hours   = schedule.value.hours
      at_these_minutes = schedule.value.minutes
    }
  }
}

resource "azurerm_logic_app_workflow" "logic_app_scheduled_start" {
  enabled             = var.scheduled_start_logic_app_enabled
  location            = azurerm_resource_group.this.location
  name                = var.scheduled_start_logic_app_name != null ? var.scheduled_start_logic_app_name : "ststv2_vms_Scheduled_start"
  resource_group_name = azurerm_resource_group.this.name
  tags                = local.solution_merged_tags

  dynamic "identity" {
    for_each = var.use_user_assigned_identity == true ? [1] : []
    content {
      type         = "UserAssigned"
      identity_ids = toset([azurerm_user_assigned_identity.uid[0].id])
    }
  }
}


resource "azurerm_logic_app_action_custom" "scheduled_start_terminate" {
  depends_on = [
    azurerm_windows_function_app.function_app,
    azurerm_logic_app_action_custom.scheduled_start_start_function
  ]

  body = jsonencode({
    "actions" : {
      "Terminate" : {
        "inputs" : {
          "runError" : {
            "code" : "@{outputs('Scheduled')['statusCode']}",
            "message" : "@{body('Scheduled')}"
          },
          "runStatus" : "Failed"
        },
        "type" : "Terminate"
      }
    },
    "runAfter" : {
      "Function-Try" : ["Failed", "Skipped", "TimedOut"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_scheduled_start.id
  name         = "Function-Catch"
}

resource "azurerm_logic_app_action_custom" "scheduled_start_success_function" {
  depends_on = [
    azurerm_windows_function_app.function_app,
    azurerm_logic_app_action_custom.scheduled_start_start_function
  ]

  body = jsonencode({
    "runAfter" : {
      "Function-Try" : ["Succeeded"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_scheduled_start.id
  name         = "Function-Success"
}

resource "azurerm_logic_app_action_custom" "scheduled_start_start_function" {
  depends_on = [
    time_sleep.wait_120_seconds,
    azurerm_logic_app_action_custom.auto_stop_function
  ]
  body = jsonencode({
    "actions" : {
      "Scheduled" : {
        "inputs" : {
          "body" : {
            "Action" : "start",
            "EnableClassic" : false,
            "RequestScopes" : {
              "ResourceGroups" : "${toset(var.scheduled_start_resource_group_scopes)}"
            }
          },
          "function" : {
            "id" : "${azurerm_windows_function_app.function_app.id}/functions/Scheduled"
          }
        },
        "type" : "Function"
      }
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_scheduled_start.id
  name         = "Function-Try"
}

resource "azurerm_logic_app_trigger_recurrence" "scheduled_start_daily_trigger" {
  depends_on = [
    time_sleep.wait_120_seconds
  ]

  frequency    = var.scheduled_start_logic_app_evaluation_frequency
  interval     = var.scheduled_start_logic_app_evaluation_interval_number
  start_time   = var.scheduled_start_logic_app_evaluation_interval_start_time
  time_zone    = var.logic_app_default_timezone != null ? var.logic_app_default_timezone : "GMT Standard Time"
  logic_app_id = azurerm_logic_app_workflow.logic_app_scheduled_start.id
  name         = "Recurrence"

  dynamic "schedule" {
    for_each = [for s in var.scheduled_start_schedules : s if length(s.days) > 0 || length(s.hours) > 0 || length(s.minutes) > 0]
    content {
      on_these_days    = schedule.value.days
      at_these_hours   = schedule.value.hours
      at_these_minutes = schedule.value.minutes
    }
  }
}

resource "azurerm_logic_app_workflow" "logic_app_scheduled_stop" {
  enabled             = var.scheduled_stop_logic_app_enabled
  location            = azurerm_resource_group.this.location
  name                = var.scheduled_stop_logic_app_name != null ? var.scheduled_stop_logic_app_name : "ststv2_vms_Scheduled_stop"
  resource_group_name = azurerm_resource_group.this.name
  tags                = local.solution_merged_tags

  dynamic "identity" {
    for_each = var.use_user_assigned_identity == true ? [1] : []
    content {
      type         = "UserAssigned"
      identity_ids = toset([azurerm_user_assigned_identity.uid[0].id])
    }
  }
}

resource "azurerm_logic_app_action_custom" "scheduled_stop_failed_function" {
  depends_on = [
    azurerm_windows_function_app.function_app,
    azurerm_logic_app_action_custom.scheduled_stop_stop_function
  ]

  body = jsonencode({
    "actions" : {
      "Terminate" : {
        "inputs" : {
          "runError" : {
            "code" : "@{outputs('Scheduled')['statusCode']}",
            "message" : "@{body('Scheduled')}"
          },
          "runStatus" : "Failed"
        },
        "type" : "Terminate"
      }
    },
    "runAfter" : {
      "Function-Try" : ["Failed", "Skipped", "TimedOut"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_scheduled_stop.id
  name         = "Function-Catch"
}

resource "azurerm_logic_app_action_custom" "scheduled_stop_succeeded_function" {
  depends_on = [
    azurerm_windows_function_app.function_app,
    azurerm_logic_app_action_custom.scheduled_stop_stop_function,
  ]

  body = jsonencode({
    "runAfter" : {
      "Function-Try" : ["Succeeded"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_scheduled_stop.id
  name         = "Function-Success"
}

resource "azurerm_logic_app_action_custom" "scheduled_stop_stop_function" {
  depends_on = [
    time_sleep.wait_120_seconds,
    azurerm_logic_app_action_custom.scheduled_start_start_function
  ]
  body = jsonencode({
    "actions" : {
      "Scheduled" : {
        "inputs" : {
          "body" : {
            "Action" : "stop",
            "EnableClassic" : false,
            "RequestScopes" : {
              "ResourceGroups" : "${toset(var.scheduled_stop_resource_group_scopes)}"
            }
          },
          "function" : {
            "id" : "${azurerm_windows_function_app.function_app.id}/functions/Scheduled"
          }
        },
        "type" : "Function"
      }
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_scheduled_stop.id
  name         = "Function-Try"
}

resource "azurerm_logic_app_trigger_recurrence" "scheduled_stop_daily_recurrence" {
  depends_on = [
    azurerm_windows_function_app.function_app
  ]
  frequency    = var.scheduled_stop_logic_app_evaluation_frequency
  interval     = var.scheduled_stop_logic_app_evaluation_interval_number
  start_time   = var.scheduled_stop_logic_app_evaluation_interval_start_time
  time_zone    = var.logic_app_default_timezone != null ? var.logic_app_default_timezone : "GMT Standard Time"
  logic_app_id = azurerm_logic_app_workflow.logic_app_scheduled_stop.id
  name         = "Recurrence"

  dynamic "schedule" {
    for_each = [for s in var.scheduled_stop_schedules : s if length(s.days) > 0 || length(s.hours) > 0 || length(s.minutes) > 0]
    content {
      on_these_days    = schedule.value.days
      at_these_hours   = schedule.value.hours
      at_these_minutes = schedule.value.minutes
    }
  }
}

resource "azurerm_logic_app_workflow" "logic_app_sequenced_start" {
  enabled             = var.sequenced_start_logic_app_enabled
  location            = azurerm_resource_group.this.location
  name                = var.sequenced_start_logic_app_name != null ? var.sequenced_start_logic_app_name : "ststv2_vms_Sequenced_start"
  resource_group_name = azurerm_resource_group.this.name
  tags                = local.solution_merged_tags

  dynamic "identity" {
    for_each = var.use_user_assigned_identity == true ? [1] : []
    content {
      type         = "UserAssigned"
      identity_ids = toset([azurerm_user_assigned_identity.uid[0].id])
    }
  }
}

resource "azurerm_logic_app_action_custom" "sequenced_start_failed_action" {
  depends_on = [
    azurerm_windows_function_app.function_app,
    azurerm_logic_app_action_custom.sequenced_start_start_function
  ]

  body = jsonencode({
    "actions" : {
      "Terminate" : {
        "inputs" : {
          "runError" : {
            "code" : "@{outputs('Scheduled')['statusCode']}",
            "message" : "@{body('Scheduled')}"
          },
          "runStatus" : "Failed"
        },
        "type" : "Terminate"
      }
    },
    "runAfter" : {
      "Function-Try" : ["Failed", "Skipped", "TimedOut"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_sequenced_start.id
  name         = "Function-Catch"
}

resource "azurerm_logic_app_action_custom" "sequenced_start_success_action" {
  depends_on = [
    azurerm_windows_function_app.function_app,
    azurerm_logic_app_action_custom.sequenced_start_start_function
  ]

  body = jsonencode({
    "runAfter" : {
      "Function-Try" : ["Succeeded"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_sequenced_start.id
  name         = "Function-Success"
}

resource "azurerm_logic_app_action_custom" "sequenced_start_start_function" {
  depends_on = [
    time_sleep.wait_120_seconds,
    azurerm_logic_app_action_custom.scheduled_stop_stop_function
  ]
  body = jsonencode({
    "actions" : {
      "Scheduled" : {
        "inputs" : {
          "body" : {
            "Action" : "start",
            "RequestScopes" : {
              "ResourceGroups" : "${toset(var.sequenced_start_resource_group_scopes)}",
              "Sequenced" : true
            }
          },
          "function" : {
            "id" : "${azurerm_windows_function_app.function_app.id}/functions/Scheduled"
          }
        },
        "type" : "Function"
      }
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_sequenced_start.id
  name         = "Function-Try"
}


resource "azurerm_logic_app_trigger_recurrence" "sequenced_start_daily_trigger" {
  depends_on = [
    azurerm_windows_function_app.function_app
  ]
  frequency    = var.sequenced_start_logic_app_evaluation_frequency
  interval     = var.sequenced_start_logic_app_evaluation_interval_number
  start_time   = var.sequenced_start_logic_app_evaluation_interval_start_time
  time_zone    = var.logic_app_default_timezone != null ? var.logic_app_default_timezone : "GMT Standard Time"
  logic_app_id = azurerm_logic_app_workflow.logic_app_sequenced_start.id
  name         = "Recurrence"

  dynamic "schedule" {
    for_each = [for s in var.sequenced_start_schedules : s if length(s.days) > 0 || length(s.hours) > 0 || length(s.minutes) > 0]
    content {
      on_these_days    = schedule.value.days
      at_these_hours   = schedule.value.hours
      at_these_minutes = schedule.value.minutes
    }
  }
}

resource "azurerm_logic_app_workflow" "logic_app_sequenced_stop" {
  enabled             = var.sequenced_stop_logic_app_enabled
  location            = azurerm_resource_group.this.location
  name                = var.sequenced_stop_logic_app_name != null ? var.sequenced_stop_logic_app_name : "ststv2_vms_Sequenced_stop"
  resource_group_name = azurerm_resource_group.this.name
  tags                = local.solution_merged_tags

  dynamic "identity" {
    for_each = var.use_user_assigned_identity == true ? [1] : []
    content {
      type         = "UserAssigned"
      identity_ids = toset([azurerm_user_assigned_identity.uid[0].id])
    }
  }
}


resource "azurerm_logic_app_action_custom" "sequenced_stop_termination_function" {
  depends_on = [
    azurerm_windows_function_app.function_app,
    azurerm_logic_app_action_custom.sequenced_stop_stop_action,

  ]

  body = jsonencode({
    "actions" : {
      "Terminate" : {
        "inputs" : {
          "runError" : {
            "code" : "@{outputs('Scheduled')['statusCode']}",
            "message" : "@{body('Scheduled')}"
          },
          "runStatus" : "Failed"
        },
        "type" : "Terminate"
      }
    },
    "runAfter" : {
      "Function-Try" : ["Failed", "Skipped", "TimedOut"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_sequenced_stop.id
  name         = "Function-Catch"
}

resource "azurerm_logic_app_action_custom" "sequenced_stop_success_action" {
  depends_on = [
    azurerm_windows_function_app.function_app,
    azurerm_logic_app_action_custom.sequenced_stop_stop_action,
  ]

  body = jsonencode({
    "runAfter" : {
      "Function-Try" : ["Succeeded"]
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_sequenced_stop.id
  name         = "Function-Success"
}

resource "azurerm_logic_app_action_custom" "sequenced_stop_stop_action" {
  depends_on = [
    time_sleep.wait_120_seconds,
    azurerm_logic_app_action_custom.sequenced_start_start_function
  ]
  body = jsonencode({
    "actions" : {
      "Scheduled" : {
        "inputs" : {
          "body" : {
            "Action" : "stop",
            "RequestScopes" : {
              "ResourceGroups" : "${toset(var.sequenced_stop_resource_group_scopes)}",
              "Sequenced" : true
            }
          },
          "function" : {
            "id" : "${azurerm_windows_function_app.function_app.id}/functions/Scheduled"
          }
        },
        "type" : "Function"
      }
    },
    "type" : "Scope"
  })

  logic_app_id = azurerm_logic_app_workflow.logic_app_sequenced_stop.id
  name         = "Function-Try"
}

resource "azurerm_logic_app_trigger_recurrence" "sequenced_stop_daily_trigger" {
  depends_on = [
    azurerm_windows_function_app.function_app
  ]
  frequency    = var.sequenced_stop_logic_app_evaluation_frequency
  interval     = var.sequenced_stop_logic_app_evaluation_interval_number
  start_time   = var.sequenced_stop_logic_app_evaluation_interval_start_time
  time_zone    = var.logic_app_default_timezone != null ? var.logic_app_default_timezone : "GMT Standard Time"
  logic_app_id = azurerm_logic_app_workflow.logic_app_sequenced_stop.id
  name         = "Recurrence"

  dynamic "schedule" {
    for_each = [for s in var.sequenced_stop_schedules : s if length(s.days) > 0 || length(s.hours) > 0 || length(s.minutes) > 0]
    content {
      on_these_days    = schedule.value.days
      at_these_hours   = schedule.value.hours
      at_these_minutes = schedule.value.minutes
    }
  }
}

locals {
  dashboard_tag = {
    hidden-title = "StartStopV2_Dashboard"
  }

  merged_dashboard_tags = merge(local.dashboard_tag, local.solution_merged_tags)

  dashboard = {

  }
}

resource "azurerm_portal_dashboard" "dashboard" {
  dashboard_properties = <<DASHBOARD_PROPERTIES
{
"lenses": {
      "0": {
        "order": 0,
        "parts": {
          "0": {
            "position": {
              "x": 0,
              "y": 0,
              "colSpan": 3,
              "rowSpan": 4
            },
            "metadata": {
              "inputs": [],
              "type": "Extension/HubsExtension/PartType/MarkdownPart",
              "settings": {
                "content": {
                  "settings": {
                    "content": "This is your StartStop VMs dashboard.\n\nFor more information view [doc](https://github.com/microsoft/startstopv2-deployments/blob/main/README.md)\n\n**Deployment information**\n> **Subscription :** CyberScot-Prd  \n> **Resource Group :** ${azurerm_application_insights.app_insights.resource_group_name}  \n> **Application Insights :** ${azurerm_application_insights.app_insights.name}",
                    "title": "Welcome!",
                    "subtitle": "",
                    "markdownSource": 1
                  }
                }
              }
            }
          },
          "1": {
            "position": {
              "x": 3,
              "y": 0,
              "colSpan": 5,
              "rowSpan": 4
            },
            "metadata": {
              "inputs": [
                {
                  "name": "ComponentId",
                  "value": {
                    "SubscriptionId": "${data.azurerm_client_config.current.subscription_id}",
                    "ResourceGroup": "${azurerm_application_insights.app_insights.resource_group_name}",
                    "Name": "${azurerm_application_insights.app_insights.name}",
                    "ResourceId": "${azurerm_application_insights.app_insights.id}"
                  }
                },
                {
                  "name": "Query",
                  "value": "traces \n| where customDimensions.prop__Name == \"VmExecutionsAttempted\" and customDimensions.prop__Successful == true\n| project      \n    action = tostring(customDimensions.prop__ActionType),\n    value = customDimensions.prop__value,\n    timestamp\n| summarize request_count=sum(toreal(value)) by action,bin(timestamp, 1h)\n"
                },
                {
                  "name": "TimeRange",
                  "value": "PT30M"
                },
                {
                  "name": "Dimensions",
                  "value": {
                    "xAxis": {
                      "name": "timestamp",
                      "type": "datetime"
                    },
                    "yAxis": [
                      {
                        "name": "request_count",
                        "type": "real"
                      }
                    ],
                    "splitBy": [
                      {
                        "name": "action",
                        "type": "string"
                      }
                    ],
                    "aggregation": "Sum"
                  }
                },
                {
                  "name": "Version",
                  "value": "1.0"
                },
                {
                  "name": "PartId",
                  "value": "1873282b-e618-432b-8147-bd0cfb34cf73"
                },
                {
                  "name": "PartTitle",
                  "value": "Successful Start and Stop Actions Taken"
                },
                {
                  "name": "PartSubTitle",
                  "value": "Total count of successful start and stop actions taken against your virtual machines by the StartStop service."
                },
                {
                  "name": "resourceTypeMode",
                  "value": "components"
                },
                {
                  "name": "ControlType",
                  "value": "FrameControlChart"
                },
                {
                  "name": "SpecificChart",
                  "value": "UnstackedColumn"
                },
                {
                  "name": "DashboardId",
                  "isOptional": true
                },
                {
                  "name": "Scope",
                  "isOptional": true
                },
                {
                  "name": "DraftRequestParameters",
                  "isOptional": true
                },
                {
                  "name": "LegendOptions",
                  "isOptional": true
                },
                {
                  "name": "IsQueryContainTimeRange",
                  "isOptional": true
                }
              ],
              "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart",
              "settings": {
                "content": {
                  "Query": "traces \n| where customDimensions.prop__Name == \"VmExecutionsAttempted\" and customDimensions.prop__Successful == true\n| project      \n    action = tostring(customDimensions.prop__ActionType),\n    value = customDimensions.prop__Value,\n    timestamp\n| summarize request_count=sum(toreal(value)) by action,bin(timestamp, 1h)\n\n",
                  "LegendOptions": {
                    "isEnabled": true,
                    "position": "Bottom"
                  }
                }
              }
            }
          },
          "2": {
            "position": {
              "x": 8,
              "y": 0,
              "colSpan": 5,
              "rowSpan": 4
            },
            "metadata": {
              "inputs": [
                {
                  "name": "resourceTypeMode",
                  "value": "components",
                  "isOptional": true
                },
                {
                  "name": "ComponentId",
                  "value": {
                    "SubscriptionId": "${data.azurerm_client_config.current.subscription_id}",
                    "ResourceGroup": "${azurerm_application_insights.app_insights.resource_group_name}",
                    "Name": "${azurerm_application_insights.app_insights.name}",
                    "ResourceId": "${azurerm_application_insights.app_insights.id}"
                  },
                  "isOptional": true
                },
                {
                  "name": "Scope",
                  "isOptional": true
                },
                {
                  "name": "PartId",
                  "value": "1873282b-e618-432b-8147-bd0cfb34cf73",
                  "isOptional": true
                },
                {
                  "name": "Version",
                  "value": "1.0",
                  "isOptional": true
                },
                {
                  "name": "TimeRange",
                  "value": "PT30M",
                  "isOptional": true
                },
                {
                  "name": "DashboardId",
                  "isOptional": true
                },
                {
                  "name": "DraftRequestParameters",
                  "isOptional": true
                },
                {
                  "name": "Query",
                  "value": "traces \n| where customDimensions.prop__Name == \"VmExecutionsAttempted\" and customDimensions.prop__Successful == true\n| project      \n    action = tostring(customDimensions.prop__ActionType),\n    value = customDimensions.prop__value,\n    timestamp\n| summarize request_count=sum(toreal(value)) by action,bin(timestamp, 1h)\n",
                  "isOptional": true
                },
                {
                  "name": "ControlType",
                  "value": "FrameControlChart",
                  "isOptional": true
                },
                {
                  "name": "SpecificChart",
                  "value": "UnstackedColumn",
                  "isOptional": true
                },
                {
                  "name": "PartTitle",
                  "value": "Successful Start and Stop Actions Taken",
                  "isOptional": true
                },
                {
                  "name": "PartSubTitle",
                  "value": "Total count of successful start and stop actions taken against your virtual machines by the StartStop service.",
                  "isOptional": true
                },
                {
                  "name": "Dimensions",
                  "value": {
                    "xAxis": {
                      "name": "timestamp",
                      "type": "datetime"
                    },
                    "yAxis": [
                      {
                        "name": "request_count",
                        "type": "real"
                      }
                    ],
                    "splitBy": [
                      {
                        "name": "action",
                        "type": "string"
                      }
                    ],
                    "aggregation": "Sum"
                  },
                  "isOptional": true
                },
                {
                  "name": "LegendOptions",
                  "isOptional": true
                },
                {
                  "name": "IsQueryContainTimeRange",
                  "isOptional": true
                }
              ],
              "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart",
              "settings": {
                "content": {
                  "Query": "traces \n| where customDimensions.prop__Name == \"VmExecutionsAttempted\" and customDimensions.prop__Successful == false\n| project      \n    action = tostring(customDimensions.prop__ActionType),\n    value = customDimensions.prop__Value,\n    timestamp\n| summarize request_count=sum(toreal(value)) by action,bin(timestamp, 1h)\n\n",
                  "ControlType": "AnalyticsGrid",
                  "LegendOptions": {
                    "isEnabled": true,
                    "position": "Bottom"
                  }
                }
              },
              "partHeader": {
                "title": "Failed Start and Stop Actions Taken",
                "subtitle": ""
              }
            }
          },
          "3": {
            "position": {
              "x": 0,
              "y": 4,
              "colSpan": 9,
              "rowSpan": 4
            },
            "metadata": {
              "inputs": [
                {
                  "name": "Version",
                  "value": "1.0"
                },
                {
                  "name": "PartId",
                  "value": "15b42e68-24a8-4715-ae79-067f634ce119"
                },
                {
                  "name": "PartTitle",
                  "value": "Recently attempted actions on VMs"
                },
                {
                  "name": "PartSubTitle",
                  "value": "Virtual machines which recently had a start or stop action attempted."
                },
                {
                  "name": "ComponentId",
                  "value": {
                    "SubscriptionId": "${data.azurerm_client_config.current.subscription_id}",
                    "ResourceGroup": "${azurerm_application_insights.app_insights.resource_group_name}",
                    "Name": "${azurerm_application_insights.app_insights.name}",
                    "ResourceId": "${azurerm_application_insights.app_insights.id}"
                  }
                },
                {
                  "name": "Query",
                  "value": "traces\n| where customDimensions.prop__Name == \"VmExecutionsAttempted\"\n| project      \n  action = customDimensions.prop__ActionType,\n  virtual_machine = customDimensions.prop__ResourceName,\n  resource_group = customDimensions.prop__ResourceGroup,\n  subscription_ID = customDimensions.prop__SubscriptionId,\n  timestamp\n| order by timestamp desc\n"
                },
                {
                  "name": "TimeRange",
                  "value": "P1D"
                },
                {
                  "name": "resourceTypeMode",
                  "value": "components"
                },
                {
                  "name": "ControlType",
                  "value": "AnalyticsGrid"
                },
                {
                  "name": "Dimensions",
                  "isOptional": true
                },
                {
                  "name": "DashboardId",
                  "isOptional": true
                },
                {
                  "name": "SpecificChart",
                  "isOptional": true
                },
                {
                  "name": "Scope",
                  "isOptional": true
                },
                {
                  "name": "DraftRequestParameters",
                  "isOptional": true
                },
                {
                  "name": "LegendOptions",
                  "isOptional": true
                },
                {
                  "name": "IsQueryContainTimeRange",
                  "isOptional": true
                }
              ],
              "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart",
              "settings": {},
              "asset": {
                "idInputName": "ComponentId",
                "type": "ApplicationInsights"
              }
            }
          },
          "4": {
            "position": {
              "x": 9,
              "y": 4,
              "colSpan": 4,
              "rowSpan": 4
            },
            "metadata": {
              "inputs": [
                {
                  "name": "ComponentId",
                  "value": {
                    "SubscriptionId": "${data.azurerm_client_config.current.subscription_id}",
                    "ResourceGroup": "${azurerm_application_insights.app_insights.resource_group_name}",
                    "Name": "${azurerm_application_insights.app_insights.name}",
                    "ResourceId": "${azurerm_application_insights.app_insights.id}"
                  },
                  "isOptional": true
                },
                {
                  "name": "Dimensions",
                  "value": {
                    "xAxis": {
                      "name": "action",
                      "type": "string"
                    },
                    "yAxis": [
                      {
                        "name": "request_count",
                        "type": "real"
                      }
                    ],
                    "splitBy": [],
                    "aggregation": "Sum"
                  },
                  "isOptional": true
                },
                {
                  "name": "Query",
                  "value": "traces\n| where customDimensions.prop__Name == \"VmExecutionsAttempted\" and customDimensions.prop__Successful == true\n| project      \n    action = tostring(customDimensions.prop__ActionType),\n    value = toreal(customDimensions.prop__value),\n    timestamp\n| summarize request_count=sum(value) by action,bin(timestamp, 1h)\n",
                  "isOptional": true
                },
                {
                  "name": "PartTitle",
                  "value": "Start & Stop (%)",
                  "isOptional": true
                },
                {
                  "name": "PartSubTitle",
                  "value": "Total % count of start and stop action",
                  "isOptional": true
                },
                {
                  "name": "PartId",
                  "value": "08ad6984-455d-440c-9596-73760a4178c3",
                  "isOptional": true
                },
                {
                  "name": "Version",
                  "value": "1.0",
                  "isOptional": true
                },
                {
                  "name": "resourceTypeMode",
                  "value": "components",
                  "isOptional": true
                },
                {
                  "name": "TimeRange",
                  "value": "P30D",
                  "isOptional": true
                },
                {
                  "name": "DashboardId",
                  "isOptional": true
                },
                {
                  "name": "ControlType",
                  "value": "FrameControlChart",
                  "isOptional": true
                },
                {
                  "name": "SpecificChart",
                  "value": "Donut",
                  "isOptional": true
                },
                {
                  "name": "Scope",
                  "isOptional": true
                },
                {
                  "name": "DraftRequestParameters",
                  "isOptional": true
                },
                {
                  "name": "LegendOptions",
                  "isOptional": true
                },
                {
                  "name": "IsQueryContainTimeRange",
                  "isOptional": true
                }
              ],
              "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart",
              "settings": {
                "content": {
                  "Query": "traces\n| where customDimensions.prop__Name == \"VmExecutionsAttempted\" and customDimensions.prop__Successful == true\n| project      \n    action = tostring(customDimensions.prop__ActionType),\n    value = toreal(customDimensions.prop__Value),\n    timestamp\n| summarize request_count=sum(value) by action,bin(timestamp, 1h)\n\n",
                  "LegendOptions": {
                    "isEnabled": true,
                    "position": "Bottom"
                  }
                }
              }
            }
          },
          "5": {
            "position": {
              "x": 0,
              "y": 8,
              "colSpan": 6,
              "rowSpan": 4
            },
            "metadata": {
              "inputs": [
                {
                  "name": "ComponentId",
                  "value": {
                    "SubscriptionId": "${data.azurerm_client_config.current.subscription_id}",
                    "ResourceGroup": "${azurerm_application_insights.app_insights.resource_group_name}",
                    "Name": "${azurerm_application_insights.app_insights.name}",
                    "ResourceId": "${azurerm_application_insights.app_insights.id}"
                  }
                },
                {
                  "name": "Query",
                  "value": "(traces\n| where customDimensions.prop__Name == \"NoPiiScheduleRequests\" and tobool(customDimensions.prop__Sequenced)\n| project scenario = \"Sequenced\",      value = toreal(customDimensions.prop__value),      timestamp)\n| union\n(traces\n| where customDimensions.prop__Name == \"NoPiiScheduleRequests\" and tobool(customDimensions.prop__Sequenced) == false\n| project scenario = \"Scheduled\",      value = toreal(customDimensions.prop__value),      timestamp)\n| union\n(traces\n| where customDimensions.prop__Name == \"NoPiiAutoStopRequests\"\n| project scenario = \"AutoStop\",      value = toreal(customDimensions.prop__value),      timestamp)\n| summarize request_count=sum(value) by scenario,bin(timestamp, 15m)\n"
                },
                {
                  "name": "TimeRange",
                  "value": "PT1H"
                },
                {
                  "name": "Dimensions",
                  "value": {
                    "xAxis": {
                      "name": "timestamp",
                      "type": "datetime"
                    },
                    "yAxis": [
                      {
                        "name": "request_count",
                        "type": "real"
                      }
                    ],
                    "splitBy": [
                      {
                        "name": "scenario",
                        "type": "string"
                      }
                    ],
                    "aggregation": "Sum"
                  }
                },
                {
                  "name": "Version",
                  "value": "1.0"
                },
                {
                  "name": "PartId",
                  "value": "1b21d06a-2b57-4d5a-b912-1fe272b12de9"
                },
                {
                  "name": "PartTitle",
                  "value": "StartStop Scenarios"
                },
                {
                  "name": "PartSubTitle",
                  "value": "Count of recently executed schedules, sequenced, and auto stop scenarios."
                },
                {
                  "name": "resourceTypeMode",
                  "value": "components"
                },
                {
                  "name": "ControlType",
                  "value": "FrameControlChart"
                },
                {
                  "name": "SpecificChart",
                  "value": "StackedColumn"
                },
                {
                  "name": "DashboardId",
                  "isOptional": true
                },
                {
                  "name": "Scope",
                  "isOptional": true
                },
                {
                  "name": "DraftRequestParameters",
                  "isOptional": true
                },
                {
                  "name": "LegendOptions",
                  "isOptional": true
                },
                {
                  "name": "IsQueryContainTimeRange",
                  "isOptional": true
                }
              ],
              "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart",
              "settings": {
                "content": {
                  "Query": "(traces\n| where customDimensions.prop__Name == \"NoPiiScheduleRequests\" and tobool(customDimensions.prop__Sequenced)\n| project scenario = \"Sequenced\",      value = toreal(customDimensions.prop__Value),      timestamp)\n| union\n(traces\n| where customDimensions.prop__Name == \"NoPiiScheduleRequests\" and tobool(customDimensions.prop__Sequenced) == false\n| project scenario = \"Scheduled\",      value = toreal(customDimensions.prop__Value),      timestamp)\n| union\n(traces\n| where customDimensions.prop__Name == \"NoPiiAutoStopRequests\"\n| project scenario = \"AutoStop\",      value = toreal(customDimensions.prop__Value),      timestamp)\n| summarize request_count=sum(value) by scenario,bin(timestamp, 15m)\n\n",
                  "LegendOptions": {
                    "isEnabled": true,
                    "position": "Bottom"
                  }
                }
              }
            }
          },
          "6": {
            "position": {
              "x": 6,
              "y": 8,
              "colSpan": 4,
              "rowSpan": 4
            },
            "metadata": {
              "inputs": [
                {
                  "name": "ComponentId",
                  "value": {
                    "SubscriptionId": "${data.azurerm_client_config.current.subscription_id}",
                    "ResourceGroup": "${azurerm_application_insights.app_insights.resource_group_name}",
                    "Name": "${azurerm_application_insights.app_insights.name}",
                    "ResourceId": "${azurerm_application_insights.app_insights.id}"
                  },
                  "isOptional": true
                },
                {
                  "name": "Dimensions",
                  "value": {
                    "xAxis": {
                      "name": "scenario",
                      "type": "string"
                    },
                    "yAxis": [
                      {
                        "name": "request_count",
                        "type": "real"
                      }
                    ],
                    "splitBy": [],
                    "aggregation": "Sum"
                  },
                  "isOptional": true
                },
                {
                  "name": "Query",
                  "value": "(traces\n| where customDimensions.prop__Name == \"NoPiiScheduleRequests\" and tobool(customDimensions.prop__Sequenced)\n| project scenario = \"Sequenced\",      value = toreal(customDimensions.prop__value),      timestamp)\n| union (traces\n| where customDimensions.prop__Name == \"NoPiiScheduleRequests\" and tobool(customDimensions.prop__Sequenced) == false\n| project scenario = \"Scheduled\",      value = toreal(customDimensions.prop__value),      timestamp)\n| union (traces\n| where customDimensions.prop__Name == \"NoPiiAutoStopRequests\"\n| project scenario = \"AutoStop\",      value = toreal(customDimensions.prop__value),      timestamp)\n| summarize request_count=sum(value) by scenario\n",
                  "isOptional": true
                },
                {
                  "name": "PartTitle",
                  "value": "Count by Scenarios",
                  "isOptional": true
                },
                {
                  "name": "PartSubTitle",
                  "value": "Count of recently executed Scenarios",
                  "isOptional": true
                },
                {
                  "name": "PartId",
                  "value": "7c4418b6-9831-46ae-b5d9-5c6b611ae16f",
                  "isOptional": true
                },
                {
                  "name": "Version",
                  "value": "1.0",
                  "isOptional": true
                },
                {
                  "name": "resourceTypeMode",
                  "value": "components",
                  "isOptional": true
                },
                {
                  "name": "TimeRange",
                  "value": "P30D",
                  "isOptional": true
                },
                {
                  "name": "DashboardId",
                  "isOptional": true
                },
                {
                  "name": "ControlType",
                  "value": "FrameControlChart",
                  "isOptional": true
                },
                {
                  "name": "SpecificChart",
                  "value": "Donut",
                  "isOptional": true
                },
                {
                  "name": "Scope",
                  "isOptional": true
                },
                {
                  "name": "DraftRequestParameters",
                  "isOptional": true
                },
                {
                  "name": "LegendOptions",
                  "isOptional": true
                },
                {
                  "name": "IsQueryContainTimeRange",
                  "isOptional": true
                }
              ],
              "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart",
              "settings": {
                "content": {
                  "Query": "(traces\n| where customDimensions.prop__Name == \"NoPiiScheduleRequests\" and tobool(customDimensions.prop__Sequenced)\n| project scenario = \"Sequenced\",      value = toreal(customDimensions.prop__Value),      timestamp)\n| union (traces\n| where customDimensions.prop__Name == \"NoPiiScheduleRequests\" and tobool(customDimensions.prop__Sequenced) == false\n| project scenario = \"Scheduled\",      value = toreal(customDimensions.prop__Value),      timestamp)\n| union (traces\n| where customDimensions.prop__Name == \"NoPiiAutoStopRequests\"\n| project scenario = \"AutoStop\",      value = toreal(customDimensions.prop__Value),      timestamp)\n| summarize request_count=sum(value) by scenario\n\n",
                  "LegendOptions": {
                    "isEnabled": true,
                    "position": "Bottom"
                  }
                }
              }
            }
          },
          "7": {
            "position": {
              "x": 10,
              "y": 8,
              "colSpan": 3,
              "rowSpan": 4
            },
            "metadata": {
              "inputs": [
                {
                  "name": "ComponentId",
                  "value": {
                    "SubscriptionId": "${data.azurerm_client_config.current.subscription_id}",
                    "ResourceGroup": "${azurerm_application_insights.app_insights.resource_group_name}",
                    "Name": "${azurerm_application_insights.app_insights.name}",
                    "ResourceId": "${azurerm_application_insights.app_insights.id}"
                  },
                  "isOptional": true
                },
                {
                  "name": "Dimensions",
                  "value": {
                    "xAxis": {
                      "name": "resource_group",
                      "type": "string"
                    },
                    "yAxis": [
                      {
                        "name": "count_",
                        "type": "long"
                      }
                    ],
                    "splitBy": [],
                    "aggregation": "Sum"
                  },
                  "isOptional": true
                },
                {
                  "name": "Query",
                  "value": "traces\n| where customDimensions.prop__Name == \"VmExecutionsAttempted\"\n| project  resource_group = tostring(customDimensions.prop__ResourceGroup)\n| summarize count() by resource_group\n",
                  "isOptional": true
                },
                {
                  "name": "PartTitle",
                  "value": "Count by Resource Group",
                  "isOptional": true
                },
                {
                  "name": "PartSubTitle",
                  "value": "Resource Groups which recently had a start or stop action",
                  "isOptional": true
                },
                {
                  "name": "PartId",
                  "value": "2aef6442-2811-49df-b349-d58e1d868ab5",
                  "isOptional": true
                },
                {
                  "name": "Version",
                  "value": "1.0",
                  "isOptional": true
                },
                {
                  "name": "resourceTypeMode",
                  "value": "components",
                  "isOptional": true
                },
                {
                  "name": "TimeRange",
                  "value": "P30D",
                  "isOptional": true
                },
                {
                  "name": "DashboardId",
                  "isOptional": true
                },
                {
                  "name": "ControlType",
                  "value": "FrameControlChart",
                  "isOptional": true
                },
                {
                  "name": "SpecificChart",
                  "value": "Donut",
                  "isOptional": true
                },
                {
                  "name": "Scope",
                  "isOptional": true
                },
                {
                  "name": "DraftRequestParameters",
                  "isOptional": true
                },
                {
                  "name": "LegendOptions",
                  "isOptional": true
                },
                {
                  "name": "IsQueryContainTimeRange",
                  "isOptional": true
                }
              ],
              "type": "Extension/Microsoft_OperationsManagementSuite_Workspace/PartType/LogsDashboardPart",
              "settings": {}
            }
          }
        }
      }
    }
}
DASHBOARD_PROPERTIES
  location             = azurerm_resource_group.this.location
  name                 = var.dashboard_name != null ? var.dashboard_name : "StartStopV2_Dashboard"
  resource_group_name  = azurerm_resource_group.this.name
  tags                 = local.merged_dashboard_tags
}

Requirements

No requirements.

Providers

Name Version
azurerm n/a
time n/a

Modules

No modules.

Resources

Name Type
azurerm_application_insights.app_insights resource
azurerm_log_analytics_workspace.law resource
azurerm_logic_app_action_custom.auto_stop_function resource
azurerm_logic_app_action_custom.auto_stop_success_function resource
azurerm_logic_app_action_custom.auto_stop_terminate resource
azurerm_logic_app_action_custom.scheduled_start_start_function resource
azurerm_logic_app_action_custom.scheduled_start_success_function resource
azurerm_logic_app_action_custom.scheduled_start_terminate resource
azurerm_logic_app_action_custom.scheduled_stop_failed_function resource
azurerm_logic_app_action_custom.scheduled_stop_stop_function resource
azurerm_logic_app_action_custom.scheduled_stop_succeeded_function resource
azurerm_logic_app_action_custom.sequenced_start_failed_action resource
azurerm_logic_app_action_custom.sequenced_start_start_function resource
azurerm_logic_app_action_custom.sequenced_start_success_action resource
azurerm_logic_app_action_custom.sequenced_stop_stop_action resource
azurerm_logic_app_action_custom.sequenced_stop_success_action resource
azurerm_logic_app_action_custom.sequenced_stop_termination_function resource
azurerm_logic_app_trigger_recurrence.auto_stop_recurrence_trigger resource
azurerm_logic_app_trigger_recurrence.scheduled_start_daily_trigger resource
azurerm_logic_app_trigger_recurrence.scheduled_stop_daily_recurrence resource
azurerm_logic_app_trigger_recurrence.sequenced_start_daily_trigger resource
azurerm_logic_app_trigger_recurrence.sequenced_stop_daily_trigger resource
azurerm_logic_app_workflow.logic_app_auto_stop resource
azurerm_logic_app_workflow.logic_app_scheduled_start resource
azurerm_logic_app_workflow.logic_app_scheduled_stop resource
azurerm_logic_app_workflow.logic_app_sequenced_start resource
azurerm_logic_app_workflow.logic_app_sequenced_stop resource
azurerm_management_lock.rg_lock resource
azurerm_monitor_action_group.app_insights_ag resource
azurerm_monitor_action_group.notification_group_ag resource
azurerm_monitor_scheduled_query_rules_alert_v2.auto_stop_query_alert_rules resource
azurerm_monitor_scheduled_query_rules_alert_v2.scheduled_query_alert_rules resource
azurerm_monitor_scheduled_query_rules_alert_v2.sequenced_query_alert_rules resource
azurerm_monitor_smart_detector_alert_rule.app_insights_anomalies_detector resource
azurerm_portal_dashboard.dashboard resource
azurerm_resource_group.this resource
azurerm_role_assignment.client_blob_owner resource
azurerm_role_assignment.client_queue_contributor resource
azurerm_role_assignment.client_smb_contributor resource
azurerm_role_assignment.client_table_contributor resource
azurerm_role_assignment.id_blob_owner resource
azurerm_role_assignment.id_contributor resource
azurerm_role_assignment.id_queue_contributor resource
azurerm_role_assignment.id_smb_contributor resource
azurerm_role_assignment.id_table_contributor resource
azurerm_service_plan.fnc_asp resource
azurerm_storage_account.storage resource
azurerm_storage_account_network_rules.storage_rules resource
azurerm_storage_container.web_jobs_hosts resource
azurerm_storage_container.web_jobs_secrets resource
azurerm_storage_queue.auto_update_request_queue resource
azurerm_storage_queue.create_alert_request resource
azurerm_storage_queue.execution_request resource
azurerm_storage_queue.orchestration_request resource
azurerm_storage_queue.savings_request_queue resource
azurerm_storage_table.auto_update_request_details_store_table resource
azurerm_storage_table.requests_store_stable resource
azurerm_storage_table.subscription_requests_store_stable resource
azurerm_user_assigned_identity.uid resource
azurerm_windows_function_app.function_app resource
time_sleep.wait_120_seconds resource
azurerm_client_config.current data source
azurerm_log_analytics_workspace.read_created_law data source

Inputs

Name Description Type Default Required
allow_resource_only_permissions Whether users require permissions to resources to view logs bool true no
app_insights_name The name of the App insights string null no
app_service_plan_name The name of the app service plan string null no
assign_current_client_blob_owner Whether the current client should be assigned roles for the storage account bool false no
assign_current_client_queue_contributor Whether the current client should be assigned roles for the storage account bool false no
assign_current_client_smb_contributor Whether the current client should be assigned roles for the storage account bool false no
assign_current_client_table_contributor Whether the current client should be assigned roles for the storage account bool false no
attempt_fetch_remote_start_stop_code Whether the start/stop code should be remote fetched bool false no
auto_stop_logic_app_enabled Whether auto_stop logic app is enabled bool false no
auto_stop_logic_app_evaluation_frequency What frequency the auto stop logic app should be evaluating at, for example, Hour, Day etc string "Hour" no
auto_stop_logic_app_evaluation_interval_number What number the auto stop logic app should be evaluating at, for example, Hour, Day etc string 8 no
auto_stop_logic_app_evaluation_interval_start_time What frequency the auto_stop logic app should be evaluating at, for example, Hour, Day etc string null no
auto_stop_logic_app_name The name of the auto_stop logic app string null no
auto_stop_query_action_groups The action groups for the auto_stop_query set(string) [] no
auto_stop_query_alert_name The name of the alert name string null no
auto_stop_query_alert_scopes The name of the alert name set(string) [] no
auto_stop_resource_group_scopes The scopes for the auto_stop logic app resource groups set(string)
[
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg1/",
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg2/"
]
no
auto_stop_schedules A list of schedules for auto_stop logic app
list(object({
days = optional(list(string), [])
hours = optional(list(number), [])
minutes = optional(list(number), [])
}))
[] no
cmk_for_query_forced Whether or not a Customer Managed Key for the query is forced bool false no
create_law_linked_app_insights Whether a law workspace linked app insights should be used - if set false, the old type which will be used which will be deprecated in Feb 2024 bool false no
create_new_law Whether or not you wish to create a new workspace, if set to true, a new one will be created, if set to false, a data read will be performed on a data source bool false no
daily_quota_gb The amount of gb set for max daily ingetion string "30" no
dashboard_name The name of the dashboard that is made for the start stop solution string null no
email_receivers List of email receivers for the action group
list(object({
email_address = string
name = string
}))
[] no
function_app_https_only Whether the function app should be function app only bool false no
function_app_name The name of function app string null no
internet_ingestion_enabled Whether internet ingestion is enabled bool null no
internet_query_enabled Whether or not your workspace can be queried from the internet bool null no
law_id The ID of the log analytics workspace id to link app insights too string null no
law_name The name of a log analytics workspace string null no
law_sku The sku of the log analytics workspace string "PerGB2018" no
local_authentication_disabled Whether local authentication is enabled, defaults to false bool false no
location The location (region) the resource should be put in, e.g. uksouth string n/a yes
lock_level The name of the lock_level, can only be CanNotDelete or Readonly string null no
logic_app_default_timezone The timezone in which all logic app schedules are set to string null no
microsoft_instrumentation_key The centralised microsoft instrumentation key for start/stop telemetry string null no
name The name of the resource string n/a yes
notification_action_group_name The name of the Start/Start alert action group string null no
notification_action_group_short_name The short name for the notification, normally used in SMS string null no
reservation_capacity_in_gb_per_day The reservation capacity gb per day, can only be used with CapacityReservation SKU string "30" no
retention_in_days The number of days for retention, between 7 and 730 string "30" no
scheduled_query_action_groups The action groups for the scheduled_query set(string) [] no
scheduled_query_alert_scopes The action groups for the scheduled_scopes set(string) [] no
scheduled_start_logic_app_enabled Whether scheduled_start logic app is enabled bool false no
scheduled_start_logic_app_evaluation_frequency What frequency the scheduled_start logic app should be evaluating at, for example, Hour, Day etc string null no
scheduled_start_logic_app_evaluation_interval_number What frequency the scheduled_start logic app should be evaluating at, for example, Hour, Day etc number null no
scheduled_start_logic_app_evaluation_interval_start_time What frequency the scheduled_start logic app should be evaluating at, for example, Hour, Day etc string null no
scheduled_start_logic_app_name The name of the scheduled start name string null no
scheduled_start_resource_group_scopes The scopes for the scheduled start logic app resource groups set(string)
[
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg1/",
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg2/"
]
no
scheduled_start_schedules A list of schedules for scheduled_start logic app
list(object({
days = optional(list(string), [])
hours = optional(list(number), [])
minutes = optional(list(number), [])
}))
[] no
scheduled_start_stop_query_alert_name The name of the scheduled start stop function string null no
scheduled_stop_logic_app_enabled Whether sequenced_stop logic app is enabled bool false no
scheduled_stop_logic_app_evaluation_frequency What frequency the scheduled_stop logic app should be evaluating at, for example, Hour, Day etc string "Hour" no
scheduled_stop_logic_app_evaluation_interval_number What frequency the scheduled_stop logic app should be evaluating at, for example, Hour, Day etc number 8 no
scheduled_stop_logic_app_evaluation_interval_start_time What frequency the scheduled_stop logic app should be evaluating at, for example, Hour, Day etc string null no
scheduled_stop_logic_app_name The name of the scheduled_stop logic app string null no
scheduled_stop_resource_group_scopes The scopes for the scheduled stop logic app resource groups set(string)
[
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg1/",
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg2/"
]
no
scheduled_stop_schedules A list of schedules for scheduled_stop logic app
list(object({
days = optional(list(string), [])
hours = optional(list(number), [])
minutes = optional(list(number), [])
}))
[] no
sequenced_query_action_groups The action groups for the sequenced_query set(string) [] no
sequenced_query_alert_scopes The action groups for the sequenced_scopes set(string) [] no
sequenced_start_logic_app_enabled Whether sequenced_start logic app is enabled bool false no
sequenced_start_logic_app_evaluation_frequency What frequency the sequenced_start logic app should be evaluating at, for example, Hour, Day etc string "Hour" no
sequenced_start_logic_app_evaluation_interval_number What frequency the sequenced_start logic app should be evaluating at, for example, Hour, Day etc number 8 no
sequenced_start_logic_app_evaluation_interval_start_time What frequency the sequenced_start logic app should be evaluating at, for example, Hour, Day etc string null no
sequenced_start_logic_app_name The name of the sequenced start logic app name string null no
sequenced_start_resource_group_scopes The scopes for the sequenced start logic app resource groups set(string)
[
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg1/",
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg2/"
]
no
sequenced_start_schedules A list of schedules for sequenced_start logic app
list(object({
days = optional(list(string), [])
hours = optional(list(number), [])
minutes = optional(list(number), [])
}))
[] no
sequenced_stop_logic_app_enabled Whether sequenced_stop logic app is enabled bool false no
sequenced_stop_logic_app_evaluation_frequency What frequency the sequenced_stop logic app should be evaluating at, for example, Hour, Day etc string "Hour" no
sequenced_stop_logic_app_evaluation_interval_number What frequency the sequenced_stop logic app should be evaluating at, for example, Hour, Day etc number 8 no
sequenced_stop_logic_app_evaluation_interval_start_time What frequency the sequenced_stop logic app should be evaluating at, for example, Hour, Day etc string null no
sequenced_stop_logic_app_name The name of the sequenced stop logic app string null no
sequenced_stop_resource_group_scopes The scopes for the sequenced stop logic app resource groups set(string)
[
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg1/",
"/subscriptions/11111111-2222-3333-4444-555555555555/resourceGroups/rg2/"
]
no
sequenced_stop_schedules A list of schedules for sequenced_stop logic app
list(object({
days = optional(list(string), [])
hours = optional(list(number), [])
minutes = optional(list(number), [])
}))
[] no
smart_detection_action_group_name The smart detection ag name string null no
smart_detection_action_group_short_name The short name for the smart detection action group string null no
start_stop_source_url The URL of the source file for start/stop string "https://startstopv2prod.blob.core.windows.net/artifacts/StartStopV2.zip" no
storage_account_firewall_bypass The bypass features of the storage account firewall set(string)
[
"AzureServices",
"Logging",
"Metrics"
]
no
storage_account_firewall_default_action The default action of the storage account firewall string "Allow" no
storage_account_firewall_subnet_ids List of subnet_ids list(string) [] no
storage_account_firewall_user_ip_rules List of user-specified IP rules list(string) [] no
storage_account_fiwall_subnet_ids List of user-specified subnet IDs list(string) [] no
storage_account_name The name of the storage account to be made string null no
storage_account_public_network_access_enabled Whether public network access are enabled on the storage account bool true no
storage_account_shared_access_keys_enabled Whether shared access keys are enabled on the storage account bool true no
tags The tags assigned to the resource map(string) n/a yes
use_user_assigned_identity Whether to use user assigned managed identity for the solution bool false no
user_assigned_identity_name The name of the user assigned identity, if used string null no

Outputs

Name Description
all_solution_ips All the public IPs from function apps and logic apps made by this solution
app_insights_action_group_id The ID of the Application Insights Action Group.
app_insights_action_group_name The name of the Application Insights Action Group.
app_insights_anomalies_detector_id The ID of the Application Insights Anomalies Detector.
app_insights_anomalies_detector_name The name of the Application Insights Anomalies Detector.
app_insights_id The ID of the Application Insights.
app_insights_key The Instrumentation Key of the Application Insights.
app_insights_name The name of the Application Insights.
auto_stop_function_id The ID of the Logic App Custom Action for Auto Stop Function.
auto_stop_logic_app_ips IP Addresses for the Auto Stop Logic App
auto_stop_query_alert_rules_id The ID of the Auto Stop Query Alert Rules.
auto_stop_query_alert_rules_name The name of the Auto Stop Query Alert Rules.
auto_stop_recurrence_trigger_id The ID of the Logic App Recurrence Trigger for Auto Stop.
auto_stop_recurrence_trigger_name The name of the Logic App Recurrence Trigger for Auto Stop.
auto_stop_success_function_id The ID of the Logic App Custom Action for Auto Stop Success Function.
auto_stop_terminate_id The ID of the Logic App Custom Action for Auto Stop Terminate.
auto_update_request_details_store_table_name The name of the Auto Update Request Details Store Table.
auto_update_request_queue_name The name of the Auto Update Request Queue.
create_alert_request_queue_name The name of the Create Alert Request Queue.
dashboard_id The id of the dashboard
dashboard_name The name of the dashboard
execution_request_queue_name The name of the Execution Request Queue.
function_app_id The ID of the Windows Function App.
function_app_name The name of the Windows Function App.
function_app_principal_id The Principal ID of the Windows Function App's System Assigned Identity.
function_outbound_ips The outbound IPs of the Windows Function App.
function_outbound_ips_list The outbound IPs of the Windows Function App in list format.
function_possible_outbound_ips The possible_outbound IPs of the Windows Function App.
function_possible_outbound_ips_list The possible_outbound IPs of the Windows Function App in list format.
law_id The ID of the Log Analytics Workspace.
law_name The name of the Log Analytics Workspace.
logic_app_auto_stop_id The ID of the Logic App Workflow for Auto Stop.
logic_app_auto_stop_name The name of the Logic App Workflow for Auto Stop.
logic_app_scheduled_start_id The ID of the Logic App Workflow for Scheduled Start.
logic_app_scheduled_start_name The name of the Logic App Workflow for Scheduled Start.
logic_app_scheduled_stop_id The ID of the Logic App Workflow for Scheduled Stop.
logic_app_scheduled_stop_name The name of the Logic App Workflow for Scheduled Stop.
logic_app_sequenced_start_id The ID of the Logic App Workflow for Sequenced Start.
logic_app_sequenced_start_name The name of the Logic App Workflow for Sequenced Start.
logic_app_sequenced_stop_id The ID of the Logic App Workflow for Sequenced Stop.
logic_app_sequenced_stop_name The name of the Logic App Workflow for Sequenced Stop.
notification_action_group_id The ID of the Notification Action Group.
notification_action_group_name The name of the Notification Action Group.
orchestration_request_queue_name The name of the Orchestration Request Queue.
requests_store_table_name The name of the Requests Store Table.
rg_id The id of the resource group
rg_location The location of the resource group
rg_name The name of the resource group
rg_tags The tags of the resource group
role_assignment_id The ID of the Role Assignment.
role_assignment_principal_id The Principal ID associated with the Role Assignment.
role_assignment_role_definition_name The Role Definition Name associated with the Role Assignment.
savings_request_queue_name The name of the Savings Request Queue.
scheduled_query_alert_rules_id The ID of the Scheduled Query Alert Rules.
scheduled_query_alert_rules_name The name of the Scheduled Query Alert Rules.
scheduled_start_daily_trigger_id The ID of the Logic App Recurrence Trigger for Scheduled Start.
scheduled_start_daily_trigger_name The name of the Logic App Recurrence Trigger for Scheduled Start.
scheduled_start_logic_app_ips IP Addresses for the Scheduled Start Logic App
scheduled_start_start_function_id The ID of the Logic App Custom Action for Scheduled Start Start Function.
scheduled_start_success_function_id The ID of the Logic App Custom Action for Scheduled Start Success Function.
scheduled_start_terminate_id The ID of the Logic App Custom Action for Scheduled Start Terminate.
scheduled_stop_daily_recurrence_id The ID of the Logic App Recurrence Trigger for Scheduled Stop.
scheduled_stop_daily_recurrence_name The name of the Logic App Recurrence Trigger for Scheduled Stop.
scheduled_stop_failed_function_id The ID of the Logic App Custom Action for Scheduled Stop Failed Function.
scheduled_stop_logic_app_ips IP Addresses for the Scheduled Stop Logic App
scheduled_stop_stop_function_id The ID of the Logic App Custom Action for Scheduled Stop Stop Function.
scheduled_stop_succeeded_function_id The ID of the Logic App Custom Action for Scheduled Stop Succeeded Function.
sequenced_start_daily_trigger_id The ID of the Logic App Recurrence Trigger for Sequenced Start.
sequenced_start_daily_trigger_name The name of the Logic App Recurrence Trigger for Sequenced Start.
sequenced_start_failed_action_id The ID of the Logic App Custom Action for Sequenced Start Failed Action.
sequenced_start_logic_app_ips IP Addresses for the Sequenced Start Logic App
sequenced_start_start_function_id The ID of the Logic App Custom Action for Sequenced Start Start Function.
sequenced_start_success_action_id The ID of the Logic App Custom Action for Sequenced Start Success Action.
sequenced_stop_daily_trigger_id The ID of the Logic App Recurrence Trigger for Sequenced Stop.
sequenced_stop_daily_trigger_name The name of the Logic App Recurrence Trigger for Sequenced Stop.
sequenced_stop_logic_app_ips IP Addresses for the Sequenced Stop Logic App
sequenced_stop_stop_action_id The ID of the Logic App Custom Action for Sequenced Stop Action.
sequenced_stop_success_action_id The ID of the Logic App Custom Action for Sequenced Stop Success Action.
sequenced_stop_termination_function_id The ID of the Logic App Custom Action for Sequenced Stop Termination Function.
service_plan_id The ID of the Service Plan.
service_plan_name The name of the Service Plan.
storage_account_id The ID of the Storage Account.
storage_account_name The name of the Storage Account.
subscription_requests_store_table_name The name of the Subscription Requests Store Table.
web_jobs_hosts_container_name The name of the Web Jobs Hosts Storage Container.
web_jobs_secrets_container_name The name of the Web Jobs Secrets Storage Container.