Skip to content

Commit

Permalink
Add Azure Front Door module (#1031)
Browse files Browse the repository at this point in the history
* AFD instance & endpoint function

* terraform format fixes

* PR fixes

* Includes more PR changes previously missed

* missed renames in example tests
  • Loading branch information
cmaclaughlin authored Nov 19, 2021
1 parent e19192d commit 9f1ad42
Show file tree
Hide file tree
Showing 9 changed files with 517 additions and 0 deletions.
30 changes: 30 additions & 0 deletions examples/azure/terraform-azure-frontdoor-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Terraform Azure Front Door Example

This folder contains a simple Terraform module that deploys resources in [Azure](https://azure.microsoft.com/) to demonstrate
how you can use Terratest to write automated tests for your Azure Terraform code. This module deploys an [Azure Front Door](https://azure.microsoft.com/en-us/services/frontdoor/).

Check out [test/azure/terraform_azure_frontdoor_example_test.go](./../../../test/azure/terraform_azure_frontdoor_example_test.go) to see how you can write automated tests for this module and validate the configuration of the parameters and options.

**WARNING**: This module and the automated tests for it deploy real resources into your Azure account which can cost you money.

## Running this module manually

1. Sign up for [Azure](https://azure.microsoft.com/).
1. Configure your Azure credentials using one of the [supported methods for Azure CLI
tools](https://docs.microsoft.com/en-us/cli/azure/azure-cli-configuration?view=azure-cli-latest)
1. Install [Terraform](https://www.terraform.io/) and make sure it's on your `PATH`.
1. Ensure [environment variables](../README.md#review-environment-variables) are available
1. Run `terraform init`
1. Run `terraform apply`
1. When you're done, run `terraform destroy`.

## Running automated tests against this module

1. Sign up for [Azure](https://azure.microsoft.com/)
1. Configure your Azure credentials using one of the [supported methods for Azure CLI
tools](https://docs.microsoft.com/en-us/cli/azure/azure-cli-configuration?view=azure-cli-latest)
1. Install [Terraform](https://www.terraform.io/) and make sure it's on your `PATH`
1. Configure your Terratest [Go test environment](../README.md)
1. `cd test/azure`
1. `go build terraform_azure_frontdoor_example_test.go`
1. `go test -v -timeout 60m -tags azure -run TestTerraformAzureFrontDoorExample`
70 changes: 70 additions & 0 deletions examples/azure/terraform-azure-frontdoor-example/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY AN AZURE FRONT DOOR
# This is an example of how to deploy an Azure Front Door with the minimum resources.
# ---------------------------------------------------------------------------------------------------------------------
# See test/azure/terraform_azure_frontdoor_example_test.go for how to write automated tests for this code.
# ---------------------------------------------------------------------------------------------------------------------

terraform {
required_version = ">=0.14.0"
}

provider "azurerm" {
features {}
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY A RESOURCE GROUP
# ---------------------------------------------------------------------------------------------------------------------

resource "azurerm_resource_group" "rg" {
name = "terratest-frontdoor-rg-${var.postfix}"
location = var.location
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY FRONT DOOR
# ---------------------------------------------------------------------------------------------------------------------

resource "azurerm_frontdoor" "frontdoor" {
name = "terratest-afd-${var.postfix}"
resource_group_name = azurerm_resource_group.rg.name
enforce_backend_pools_certificate_name_check = false

routing_rule {
name = "terratestRoutingRule1"
accepted_protocols = ["Http", "Https"]
patterns_to_match = ["/*"]
frontend_endpoints = ["terratestEndpoint"]
forwarding_configuration {
forwarding_protocol = "MatchRequest"
backend_pool_name = "terratestBackend"
}
}

backend_pool_load_balancing {
name = "terratestLoadBalanceSetting"
}

backend_pool_health_probe {
name = "terratestHealthProbeSetting"
}

backend_pool {
name = "terratestBackend"
backend {
host_header = var.backend_host
address = var.backend_host
http_port = 80
https_port = 443
}

load_balancing_name = "terratestLoadBalanceSetting"
health_probe_name = "terratestHealthProbeSetting"
}

frontend_endpoint {
name = "terratestEndpoint"
host_name = "terratest-afd-${var.postfix}.azurefd.net"
}
}
18 changes: 18 additions & 0 deletions examples/azure/terraform-azure-frontdoor-example/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
output "resource_group_name" {
value = azurerm_resource_group.rg.name
}

output "front_door_name" {
description = "Specifies the name of the Front Door service."
value = azurerm_frontdoor.frontdoor.name
}

output "front_door_url" {
description = "Specifies the host name of the frontend_endpoint. Must be a domain name."
value = azurerm_frontdoor.frontdoor.frontend_endpoint[0].host_name
}

output "front_door_endpoint_name" {
description = "Specifies the friendly name of the frontend_endpoint"
value = azurerm_frontdoor.frontdoor.frontend_endpoint[0].name
}
32 changes: 32 additions & 0 deletions examples/azure/terraform-azure-frontdoor-example/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# ---------------------------------------------------------------------------------------------------------------------
# ENVIRONMENT VARIABLES
# Define these secrets as environment variables
# ---------------------------------------------------------------------------------------------------------------------

# ARM_CLIENT_ID
# ARM_CLIENT_SECRET
# ARM_SUBSCRIPTION_ID
# ARM_TENANT_ID

# ---------------------------------------------------------------------------------------------------------------------
# OPTIONAL PARAMETERS
# These parameters have reasonable defaults.
# ---------------------------------------------------------------------------------------------------------------------

variable "location" {
description = "The Azure location where to deploy your resources too"
type = string
default = "East US"
}

variable "postfix" {
description = "A postfix string to centrally mitigate resource name collisions"
type = string
default = "resource"
}

variable "backend_host" {
description = "The IP address or FQDN of the backend"
type = string
default = "www.bing.com"
}
41 changes: 41 additions & 0 deletions modules/azure/client_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"os"
"reflect"

"github.com/Azure/azure-sdk-for-go/profiles/latest/frontdoor/mgmt/frontdoor"
"github.com/Azure/azure-sdk-for-go/profiles/latest/mysql/mgmt/mysql"
"github.com/Azure/azure-sdk-for-go/profiles/latest/resources/mgmt/resources"
"github.com/Azure/azure-sdk-for-go/profiles/latest/sql/mgmt/sql"
Expand Down Expand Up @@ -707,6 +708,46 @@ func CreateContainerInstanceClientE(subscriptionID string) (*containerinstance.C
return &instanceClient, nil
}

// CreateFrontDoorClientE returns an AFD client instance configured with the
// correct BaseURI depending on the Azure environment that is currently setup (or "Public", if none is setup).
func CreateFrontDoorClientE(subscriptionID string) (*frontdoor.FrontDoorsClient, error) {
// Validate Azure subscription ID
subscriptionID, err := getTargetAzureSubscription(subscriptionID)
if err != nil {
return nil, err
}

// Lookup environment URI
baseURI, err := getEnvironmentEndpointE(ResourceManagerEndpointName)
if err != nil {
return nil, err
}

// create client
client := frontdoor.NewFrontDoorsClientWithBaseURI(baseURI, subscriptionID)
return &client, nil
}

// CreateFrontDoorFrontendEndpointClientE returns an AFD Frontend Endpoints client instance configured with the
// correct BaseURI depending on the Azure environment that is currently setup (or "Public", if none is setup).
func CreateFrontDoorFrontendEndpointClientE(subscriptionID string) (*frontdoor.FrontendEndpointsClient, error) {
// Validate Azure subscription ID
subscriptionID, err := getTargetAzureSubscription(subscriptionID)
if err != nil {
return nil, err
}

// Lookup environment URI
baseURI, err := getEnvironmentEndpointE(ResourceManagerEndpointName)
if err != nil {
return nil, err
}

// create client
client := frontdoor.NewFrontendEndpointsClientWithBaseURI(baseURI, subscriptionID)
return &client, nil
}

// GetKeyVaultURISuffixE returns the proper KeyVault URI suffix for the configured Azure environment.
// This function would fail the test if there is an error.
func GetKeyVaultURISuffixE() (string, error) {
Expand Down
68 changes: 68 additions & 0 deletions modules/azure/client_factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,3 +288,71 @@ func TestLoadBalancerClientBaseURISetCorrectly(t *testing.T) {
})
}
}

func TestFrontDoorClientBaseURISetCorrectly(t *testing.T) {
var cases = []struct {
CaseName string
EnvironmentName string
ExpectedBaseURI string
}{
{"GovCloud/FrontDoorClient", govCloudEnvName, autorest.USGovernmentCloud.ResourceManagerEndpoint},
{"PublicCloud/FrontDoorClient", publicCloudEnvName, autorest.PublicCloud.ResourceManagerEndpoint},
{"ChinaCloud/FrontDoorClient", chinaCloudEnvName, autorest.ChinaCloud.ResourceManagerEndpoint},
{"GermanCloud/FrontDoorClient", germanyCloudEnvName, autorest.GermanCloud.ResourceManagerEndpoint},
}

// save any current env value and restore on exit
currentEnv := os.Getenv(AzureEnvironmentEnvName)
defer os.Setenv(AzureEnvironmentEnvName, currentEnv)

for _, tt := range cases {
// The following is necessary to make sure testCase's values don't
// get updated due to concurrency within the scope of t.Run(..) below
tt := tt
t.Run(tt.CaseName, func(t *testing.T) {
// Override env setting
os.Setenv(AzureEnvironmentEnvName, tt.EnvironmentName)

// Get a Front Door client
client, err := CreateFrontDoorClientE("")
require.NoError(t, err)

// Check for correct ARM URI
assert.Equal(t, tt.ExpectedBaseURI, client.BaseURI)
})
}
}

func TestFrontDoorFrontendEndpointClientBaseURISetCorrectly(t *testing.T) {
var cases = []struct {
CaseName string
EnvironmentName string
ExpectedBaseURI string
}{
{"GovCloud/FrontDoorClient", govCloudEnvName, autorest.USGovernmentCloud.ResourceManagerEndpoint},
{"PublicCloud/FrontDoorClient", publicCloudEnvName, autorest.PublicCloud.ResourceManagerEndpoint},
{"ChinaCloud/FrontDoorClient", chinaCloudEnvName, autorest.ChinaCloud.ResourceManagerEndpoint},
{"GermanCloud/FrontDoorClient", germanyCloudEnvName, autorest.GermanCloud.ResourceManagerEndpoint},
}

// save any current env value and restore on exit
currentEnv := os.Getenv(AzureEnvironmentEnvName)
defer os.Setenv(AzureEnvironmentEnvName, currentEnv)

for _, tt := range cases {
// The following is necessary to make sure testCase's values don't
// get updated due to concurrency within the scope of t.Run(..) below
tt := tt
t.Run(tt.CaseName, func(t *testing.T) {
// Override env setting
os.Setenv(AzureEnvironmentEnvName, tt.EnvironmentName)

// Get a AFD frontend endpoint client
client, err := CreateFrontDoorFrontendEndpointClientE("")
require.NoError(t, err)

// Check for correct ARM URI
assert.Equal(t, tt.ExpectedBaseURI, client.BaseURI)
})
}
}
Loading

0 comments on commit 9f1ad42

Please sign in to comment.