Skip to content

Commit

Permalink
Merge pull request #631 from rguthriemsft/pull-request-627
Browse files Browse the repository at this point in the history
feat: adding Azure Network module
  • Loading branch information
yorinasub17 authored Sep 30, 2020
2 parents 229c49f + 7226a3d commit 48e24df
Show file tree
Hide file tree
Showing 18 changed files with 1,170 additions and 15 deletions.
16 changes: 8 additions & 8 deletions examples/azure/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Terratest Configuration and Setup

Terratest uses Go to make calls to Azure through the azure-sdk-for-go library and independently confirm the actual Azure resource property matches the expected state provided by Terraform output variables.
Terratest uses Go to make calls to Azure through the azure-sdk-for-go library and independently confirm the actual Azure resource property matches the expected state provided by Terraform output variables.

* Instructions for running each Azure Terratest module are included in each Terraform example sub-folder:
* examples/azure/terraform-azure-*-example/README.md
* Tests wich assert against expected Terraform output values are located in the the respective go files of the folder:
* [test/azure/terraform-azure-*-example_test.go](../../test/azure)
* Test APIs which provide the actual Azure resource property values via the azure-sdk-for-go are located in the folder:
* [modules/azure](../../modules/azure)
- Instructions for running each Azure Terratest module are included in each Terraform example sub-folder:
- examples/azure/terraform-azure-\*-example/README.md
- Tests which assert against expected Terraform output values are located in the the respective go files of the folder:
- [test/azure/terraform-azure-\*-example_test.go](../../test/azure)
- Test APIs which provide the actual Azure resource property values via the azure-sdk-for-go are located in the folder:
- [modules/azure](../../modules/azure)

## Go Dependencies

Expand Down Expand Up @@ -44,7 +44,7 @@ export ARM_SUBSCRIPTION_ID=your_subscription_id
export ARM_TENANT_ID=your_tenant_id
```

Note, in a Windows environment, these should be set as **system environment variables**. We can use a PowerShell console with administrative rights to update these environment variables:
Note, in a Windows environment, these should be set as **system environment variables**. We can use a PowerShell console with administrative rights to update these environment variables:

```powershell
[System.Environment]::SetEnvironmentVariable("ARM_CLIENT_ID",$your_app_id,[System.EnvironmentVariableTarget]::Machine)
Expand Down
43 changes: 43 additions & 0 deletions examples/azure/terraform-azure-network-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Terraform Azure Network 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 to a Virtual Network two Network Interface Cards, one with an internal only IP and another with an internal and external Public IP.

- A [Virtual Network](https://azure.microsoft.com/en-us/services/virtual-network/) module that includes the following resources:
- [Virtual Network](https://docs.microsoft.com/en-us/azure/virtual-network/) with the name specified in the `virtual_network_name` variable.
- [Subnet](https://docs.microsoft.com/en-us/rest/api/virtualnetwork/subnets) with the name specified in the `subnet_name` variable.
- [Public Address](https://docs.microsoft.com/en-us/azure/virtual-network/public-ip-addresses) with the name specified in the `public_ip_name` variable.
- [Internal Network Interface](https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-network-interface) with the name specified in the `network_interface_internal` variable.
- [ExternalNetwork Interface](https://docs.microsoft.com/en-us/azure/virtual-network/virtual-network-network-interface) with the name specified in the `network_interface_external` variable.

Check out [test/azure/terraform_azure_network_test.go](/test/azure/terraform_azure_network_example_test.go) to see how you can write
automated tests for this module.

Note that the Azure Virtual Network, Subnet, Network Interface and Public IP resources in this module don't actually do anything; it just runs the resources for
demonstration purposes.

**WARNING**: This module and the automated tests for it deploy real resources into your Azure account which can cost you
money. The resources are all part of the [Azure Free Account](https://azure.microsoft.com/en-us/free/), so if you haven't used that up,
it should be free, but you are completely responsible for all Azure charges.

## 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_network_example_test.go`
1. `go test -v -run TestTerraformAzureNetworkExample`
98 changes: 98 additions & 0 deletions examples/azure/terraform-azure-network-example/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY AN AZURE NETWORK
# This is an example of how to deploy frequent Azure Networking Resources. Note this network doesn't actually do
# anything and is only created for the example to test their commonly needed and integrated properties.
# ---------------------------------------------------------------------------------------------------------------------
# See test/azure/terraform_azure_network_example_test.go for how to write automated tests for this code.
# ---------------------------------------------------------------------------------------------------------------------

provider "azurerm" {
version = "~>2.20"
features {}
}

# ---------------------------------------------------------------------------------------------------------------------
# PIN TERRAFORM VERSION TO >= 0.12
# The examples have been upgraded to 0.12 syntax
# ---------------------------------------------------------------------------------------------------------------------

terraform {
# This module is now only being tested with Terraform 0.13.x. However, to make upgrading easier, we are setting
# 0.12.26 as the minimum version, as that version added support for required_providers with source URLs, making it
# forwards compatible with 0.13.x code.
required_version = ">= 0.12.26"
}

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

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

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY VIRTUAL NETWORK
# ---------------------------------------------------------------------------------------------------------------------

resource "azurerm_virtual_network" "net" {
name = "vnet-${var.postfix}"
location = azurerm_resource_group.net.location
resource_group_name = azurerm_resource_group.net.name
address_space = ["10.0.0.0/16"]
dns_servers = [var.dns_ip_01, var.dns_ip_02]
}

resource "azurerm_subnet" "net" {
name = "subnet-${var.postfix}"
resource_group_name = azurerm_resource_group.net.name
virtual_network_name = azurerm_virtual_network.net.name
address_prefixes = [var.subnet_prefix]
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY PRIVATE NETWORK INTERFACE
# ---------------------------------------------------------------------------------------------------------------------

resource "azurerm_network_interface" "net01" {
name = "nic-private-${var.postfix}"
location = azurerm_resource_group.net.location
resource_group_name = azurerm_resource_group.net.name

ip_configuration {
name = "terratestconfiguration1"
subnet_id = azurerm_subnet.net.id
private_ip_address_allocation = "Static"
private_ip_address = var.private_ip
}
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY PUBLIC ADDRESS AND NETWORK INTERFACE
# ---------------------------------------------------------------------------------------------------------------------

resource "azurerm_public_ip" "net" {
name = "pip-${var.postfix}"
resource_group_name = azurerm_resource_group.net.name
location = azurerm_resource_group.net.location
allocation_method = "Static"
ip_version = "IPv4"
sku = "Basic"
idle_timeout_in_minutes = "4"
domain_name_label = var.domain_name_label
}

resource "azurerm_network_interface" "net02" {
name = "nic-public-${var.postfix}"
location = azurerm_resource_group.net.location
resource_group_name = azurerm_resource_group.net.name

ip_configuration {
name = "terratestconfiguration1"
subnet_id = azurerm_subnet.net.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.net.id
}
}

25 changes: 25 additions & 0 deletions examples/azure/terraform-azure-network-example/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
output "resource_group_name" {
value = azurerm_resource_group.net.name
}

output "virtual_network_name" {
value = azurerm_virtual_network.net.name
}

output "subnet_name" {
value = azurerm_subnet.net.name
}

output "public_address_name" {
value = azurerm_public_ip.net.name
}

output "network_interface_internal" {
value = azurerm_network_interface.net01.name
}

output "network_interface_external" {
value = azurerm_network_interface.net02.name
}


60 changes: 60 additions & 0 deletions examples/azure/terraform-azure-network-example/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# ---------------------------------------------------------------------------------------------------------------------
# ENVIRONMENT VARIABLES
# Define these secrets as environment variables
# ---------------------------------------------------------------------------------------------------------------------

# ARM_CLIENT_ID
# ARM_CLIENT_SECRET
# ARM_SUBSCRIPTION_ID
# ARM_TENANT_ID

# ---------------------------------------------------------------------------------------------------------------------
# REQUIRED PARAMETERS
# You must provide a value for each of these parameters.
# ---------------------------------------------------------------------------------------------------------------------

variable "domain_name_label" {
description = "The Domain Name Label for the Public IP Address"
type = string
}

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

variable "dns_ip_01" {
description = "The first DNS Server IP for the Virtual Network"
type = string
default = "10.0.0.5"
}

variable "dns_ip_02" {
description = "The second DNS Server IP for the Virtual Network"
type = string
default = "10.0.0.6"
}

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

variable "postfix" {
description = "The postfix that will be attached to all resources deployed"
type = string
default = "resource"
}

variable "private_ip" {
description = "The Static Private IP for the Internal NIC"
type = string
default = "10.0.20.5"
}

variable "subnet_prefix" {
description = "The subnet range of IPs for the Virtual Network"
type = string
default = "10.0.20.0/24"
}
3 changes: 3 additions & 0 deletions modules/azure/availabilityset.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ func AvailabilitySetExists(t testing.TestingT, avsName string, resGroupName stri
func AvailabilitySetExistsE(t testing.TestingT, avsName string, resGroupName string, subscriptionID string) (bool, error) {
_, err := GetAvailabilitySetE(t, avsName, resGroupName, subscriptionID)
if err != nil {
if ResourceNotFoundErrorExists(err) {
return false, nil
}
return false, err
}
return true, nil
Expand Down
2 changes: 1 addition & 1 deletion modules/azure/compute.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/require"
)

// GetVirtualMachineClientE is a helper function that will setup an Azure Virtual Machine client on your behalf
// GetVirtualMachineClientE is a helper function that will setup an Azure Virtual Machine client on your behalf.
func GetVirtualMachineClientE(subscriptionID string) (*compute.VirtualMachinesClient, error) {
// Validate Azure subscription ID
subscriptionID, err := getTargetAzureSubscription(subscriptionID)
Expand Down
34 changes: 33 additions & 1 deletion modules/azure/errors.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package azure

import "fmt"
import (
"fmt"

"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
)

// SubscriptionIDNotFound is an error that occurs when the Azure Subscription ID could not be found or was not provided
type SubscriptionIDNotFound struct{}
Expand All @@ -16,6 +21,21 @@ func (err ResourceGroupNameNotFound) Error() string {
return fmt.Sprintf("Could not find an Azure Resource Group name in expected environment variable %s and one was not provided for this test.", AzureResGroupName)
}

// FailedToParseError is returned when an object cannot be parsed
type FailedToParseError struct {
objectType string
objectID string
}

func (err FailedToParseError) Error() string {
return fmt.Sprintf("Failed to parse %s with ID %s", err.objectType, err.objectID)
}

// NewFailedToParseError creates a new not found error when an expected object is not found in the search space
func NewFailedToParseError(objectType string, objectID string) FailedToParseError {
return FailedToParseError{objectType, objectID}
}

// NotFoundError is returned when an expected object is not found in the search spa
type NotFoundError struct {
objectType string
Expand All @@ -31,3 +51,15 @@ func (err NotFoundError) Error() string {
func NewNotFoundError(objectType string, objectID string, region string) NotFoundError {
return NotFoundError{objectType, objectID, region}
}

// ResourceNotFoundErrorExists checks the Service Error Code for the 'Resource Not Found' error
func ResourceNotFoundErrorExists(err error) bool {
if err != nil {
if autorestError, ok := err.(autorest.DetailedError); ok {
if requestError, ok := autorestError.Original.(*azure.RequestError); ok {
return (requestError.ServiceError.Code == "ResourceNotFound")
}
}
}
return false
}
Loading

0 comments on commit 48e24df

Please sign in to comment.