Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: enable Azure PostgreSQL Server testing #772

Merged
merged 4 commits into from
Apr 12, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions examples/azure/terraform-azure-postgresql-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Terraform Azure PostgreSQL DB Example

This folder contains a 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 a database for PostgreSQL.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a link to azure postgres database https://azure.microsoft.com/services/postgresql/ , not mysql

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved

- A [Azure PostgreSQL Database](https://azure.microsoft.com/services/mysql/).

Check out [test/azure/terraform_azure_postgresqldb_example_test.go](./../../../test/azure/terraform_azure_postgresqldb_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_mysqldb_example_test.go`
omichels marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix to build the terraform_azure_postgresqldb_example_test.go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved

1. `go test -v -timeout 60m -tags azure -run TestPostgreSQLDatabase`

53 changes: 53 additions & 0 deletions examples/azure/terraform-azure-postgresql-example/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY AN PostgreSQL Database
# This is an example of how to deploy an Azure PostgreSQL database.
# See test/terraform_azure_example_test.go for how to write automated tests for this code.
# ---------------------------------------------------------------------------------------------------------------------


# ---------------------------------------------------------------------------------------------------------------------
# CONFIGURE OUR AZURE CONNECTION
# ---------------------------------------------------------------------------------------------------------------------
provider "azurerm" {
features {}
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY A RESOURCE GROUP
# ---------------------------------------------------------------------------------------------------------------------
resource "azurerm_resource_group" "rg" {
omichels marked this conversation as resolved.
Show resolved Hide resolved
name = "postgresql-rg"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add location variable in variable.tf, then use it to set the location. see other azure samples for ref #

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved

location = "West Europe"
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY AZURE PostgreSQL SERVER
# ---------------------------------------------------------------------------------------------------------------------
resource "azurerm_postgresql_server" "postgresqlserver" {
name = "postgresqlserver-${var.postfix}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name

sku_name = "B_Gen5_2"

storage_mb = 5120
backup_retention_days = 7
geo_redundant_backup_enabled = false
auto_grow_enabled = true

administrator_login = "pgsqladmin"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please use random_password to create the administrator_login_password, See sample #

# Random password is used as an example to simplify the deployment and improve the security of the database.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved

administrator_login_password = "H@Sh1CoR3!"
version = "11"
ssl_enforcement_enabled = true
}

# ---------------------------------------------------------------------------------------------------------------------
# DEPLOY AZURE PostgreSQL Database
# ---------------------------------------------------------------------------------------------------------------------
resource "azurerm_postgresql_database" "postgresqldb" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add -${var.postfix} to the resource name to avoid resource collision

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name conflict can happen on postgresqlserver only, not on database.
A server can host multiple databases.

name = "postgresqldb"
resource_group_name = azurerm_resource_group.rg.name
server_name = azurerm_postgresql_server.postgresqlserver.name
charset = "UTF8"
collation = "English_United States.1252"
}
12 changes: 12 additions & 0 deletions examples/azure/terraform-azure-postgresql-example/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
output "sku_name" {
value = azurerm_postgresql_server.postgresqlserver.sku_name
}

output "servername" {
value = azurerm_postgresql_server.postgresqlserver.name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra newline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved


}

output "rgname" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Please rename to "resource_group_name" and move to the top of the file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved

value = azurerm_resource_group.rg.name
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline to the end of the file, consider running terraform fmt

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add newline to the end of the file, consider running terraform fmt

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used terraform fmt

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "postfix" {
description = "A postfix string to centrally mitigate resource name collisions."
type = string
default = "resource"
}
135 changes: 135 additions & 0 deletions modules/azure/postgresql.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package azure

import (
"context"

"github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql"
"github.com/gruntwork-io/terratest/modules/testing"
"github.com/stretchr/testify/require"
)

// GetPostgreSQLServerClientE is a helper function that will setup a postgresql server client.
func GetPostgreSQLServerClientE(subscriptionID string) (*postgresql.ServersClient, error) {
// Validate Azure subscription ID
subscriptionID, err := getTargetAzureSubscription(subscriptionID)
if err != nil {
return nil, err
}

// Create a postgresql server client
postgresqlClient := postgresql.NewServersClient(subscriptionID)

// Create an authorizer
authorizer, err := NewAuthorizer()
if err != nil {
return nil, err
}

// Attach authorizer to the client
postgresqlClient.Authorizer = *authorizer

return &postgresqlClient, nil
}

// GetPostgresqlServer is a helper function that gets the server.
// This function would fail the test if there is an error.
func GetPostgresqlServer(t testing.TestingT, resGroupName string, serverName string, subscriptionID string) *postgresql.Server {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make all the functions consistent and use PostgreSQL instead of Postgresql?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@omichels could you please update the PR to resolve the last comment, or give me access to your repo and I would do it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"all functions consistent using PostgreSQL"
commit: 00727ae

postgresqlServer, err := GetPostgresqlServerE(t, subscriptionID, resGroupName, serverName)
require.NoError(t, err)

return postgresqlServer
}

// GetPostgresqlServerE is a helper function that gets the server.
func GetPostgresqlServerE(t testing.TestingT, subscriptionID string, resGroupName string, serverName string) (*postgresql.Server, error) {
// Create a postgresql Server client
postgresqlClient, err := GetPostgreSQLServerClientE(subscriptionID)
if err != nil {
return nil, err
}

// Get the corresponding server client
postgresqlServer, err := postgresqlClient.Get(context.Background(), resGroupName, serverName)
if err != nil {
return nil, err
}

//Return server
return &postgresqlServer, nil
}

// GetPostgresqlDBClientE is a helper function that will setup a postgresql DB client.
func GetPostgresqlDBClientE(subscriptionID string) (*postgresql.DatabasesClient, error) {
// Validate Azure subscription ID
subscriptionID, err := getTargetAzureSubscription(subscriptionID)
if err != nil {
return nil, err
}

// Create a postgresql db client
postgresqlDBClient := postgresql.NewDatabasesClient(subscriptionID)

// Create an authorizer
authorizer, err := NewAuthorizer()
if err != nil {
return nil, err
}

// Attach authorizer to the client
postgresqlDBClient.Authorizer = *authorizer

return &postgresqlDBClient, nil
}

//GetPostgresqlDB is a helper function that gets the database.
// This function would fail the test if there is an error.
func GetPostgresqlDB(t testing.TestingT, resGroupName string, serverName string, dbName string, subscriptionID string) *postgresql.Database {
database, err := GetPostgresqlDBE(t, subscriptionID, resGroupName, serverName, dbName)
require.NoError(t, err)

return database
}

//GetPostgresqlDBE is a helper function that gets the database.
func GetPostgresqlDBE(t testing.TestingT, subscriptionID string, resGroupName string, serverName string, dbName string) (*postgresql.Database, error) {
// Create a postgresql db client
postgresqldbClient, err := GetPostgresqlDBClientE(subscriptionID)
if err != nil {
return nil, err
}

// Get the corresponding db client
postgresqlDb, err := postgresqldbClient.Get(context.Background(), resGroupName, serverName, dbName)
if err != nil {
return nil, err
}

//Return DB
return &postgresqlDb, nil
}

//ListPostgresqlDB is a helper function that gets all databases per server.
func ListPostgresqlDB(t testing.TestingT, subscriptionID string, resGroupName string, serverName string) []postgresql.Database {
dblist, err := ListPostgresqlDBE(t, subscriptionID, resGroupName, serverName)
require.NoError(t, err)

return dblist
}

//ListPostgresqlDBE is a helper function that gets all databases per server.
func ListPostgresqlDBE(t testing.TestingT, subscriptionID string, resGroupName string, serverName string) ([]postgresql.Database, error) {
// Create a postgresql db client
postgresqldbClient, err := GetPostgresqlDBClientE(subscriptionID)
if err != nil {
return nil, err
}

// Get the corresponding db client
postgresqlDbs, err := postgresqldbClient.ListByServer(context.Background(), resGroupName, serverName)
if err != nil {
return nil, err
}

//Return DB lists
return *postgresqlDbs.Value, nil
}
40 changes: 40 additions & 0 deletions modules/azure/postgresql_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// +build azure

// NOTE: We use build tags to differentiate azure testing because we currently do not have azure access setup for
// CircleCI.

package azure

import (
"testing"

"github.com/stretchr/testify/require"
)

/*
The below tests are currently stubbed out, with the expectation that they will throw errors.
If/when CRUD methods are introduced for Azure PostgreSQL server and database, these tests can be extended
*/

func TestGetPostgreSQLServerE(t *testing.T) {
t.Parallel()

resGroupName := ""
serverName := ""
subscriptionID := ""

_, err := GetPostgresqlServerE(t, subscriptionID, resGroupName, serverName)
require.Error(t, err)
}

func TestGetPostgreSQLDBE(t *testing.T) {
t.Parallel()

resGroupName := ""
serverName := ""
subscriptionID := ""
dbName := ""

_, err := GetPostgresqlDBE(t, subscriptionID, resGroupName, serverName, dbName)
require.Error(t, err)
}
47 changes: 47 additions & 0 deletions test/azure/terraform_azure_postgresql_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package test

import (
"os"
"strings"
"testing"

"github.com/gruntwork-io/terratest/modules/azure"
"github.com/gruntwork-io/terratest/modules/random"
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)

func TestPostgreSQLDatabase(t *testing.T) {
t.Parallel()

uniquePostfix := strings.ToLower(random.UniqueId())

// website::tag::1:: Configure Terraform setting up a path to Terraform code.
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
TerraformDir: "../../examples/azure/terraform-azure-postgresql-example",
Vars: map[string]interface{}{
"postfix": uniquePostfix,
},
NoColor: true,
})
// website::tag::4:: At the end of the test, run `terraform destroy` to clean up any resources that were created
defer terraform.Destroy(t, terraformOptions)

// website::tag::2:: Run `terraform init` and `terraform apply`. Fail the test if there are any errors.
terraform.InitAndApply(t, terraformOptions)

subscriptionID := os.Getenv("ARM_SUBSCRIPTION_ID")

// website::tag::3:: Run `terraform output` to get the values of output variables
expectedServername := "postgresqlserver-" + uniquePostfix // see fixture
actualServername := terraform.Output(t, terraformOptions, "servername")
rgName := terraform.Output(t, terraformOptions, "rgname")
expectedSkuName := terraform.Output(t, terraformOptions, "sku_name")

// website::tag::4:: Get the Server details and assert them against the terraform output
actualServer := azure.GetPostgresqlServer(t, rgName, actualServername, subscriptionID)
// Verify
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please assert the actualServer is not nil instead

assert.Equal(t, expectedServername, actualServername)
assert.Equal(t, expectedSkuName, *actualServer.Sku.Name)

}