Add dev workflow support for azure compute module (#28)

* Add support of test kitchen on azure compute module.
* Add test case for local.
* add test ruby file for terraform state file.
* Update readme and test case.
* Update the Gemfile for version range.
* Update the commit for minimum version for ruby in README.md.
* Introduce Rake and Travis-CI for compute module.
* add badge for travis ci result.
* Update the travis file to download and install terraform.
* add matrix for osx.
* add gpg valiation for terraform.
* add TERRAFORM_VERSION as global env var.
* disable os x build by default.
This commit is contained in:
Su Shi 2017-11-22 12:43:52 -08:00 коммит произвёл David Tesar
Родитель c1e280bd81
Коммит fe8216a211
20 изменённых файлов: 367 добавлений и 65 удалений

8
.gitignore поставляемый
Просмотреть файл

@ -25,4 +25,10 @@ Session.vim
tags
# IDE configs
.idea
.idea
# Ruby download package lock file.
Gemfile.lock
# Test Kitchen files.
.kitchen

36
.kitchen.yml Normal file
Просмотреть файл

@ -0,0 +1,36 @@
---
driver:
name: "terraform"
directory: "test/integration/fixtures"
parallelism: 1
variable_files:
- "test/integration/fixtures/testing.tfvars"
provisioner:
name: "terraform"
platforms:
-
name: "ubuntu"
transport:
name: "ssh"
ssh_key: ~/.ssh/id_rsa
verifier:
name: "terraform"
groups:
-
name: "remote"
controls:
- "operating_system"
hostnames: "test_target_public_dns"
port: 22
username: "azureuser"
-
name: "local"
controls:
- "state_file"
suites:
- name: "compute"

48
.travis.yml Normal file
Просмотреть файл

@ -0,0 +1,48 @@
# Build matrix / environment variable are explained on:
# http://about.travis-ci.org/docs/user/build-configuration/
# This file can be validated on:
# http://lint.travis-ci.org/
dist: trusty
sudo: required
language: ruby
rvm:
- 2.3
env:
global:
- TERRAFORM_VERSION=0.10.8
matrix:
- TERRAFORM_OS_ARCH=linux_amd64
matrix:
include:
- os: linux
env: TERRAFORM_OS_ARCH=linux_amd64
# - os: osx
# env: TERRAFORM_OS_ARCH=darwin_amd64
before_install:
# Update Gem.
- gem update --system
- gem --version
# Install GPG for OS X
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew list gpg > /dev/null 2>&1 || brew install gpg; fi
install:
# Import hashicorp's keys.
- curl https://keybase.io/hashicorp/pgp_keys.asc | gpg --import
# Download the binary and signature files.
- curl -Os https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_${TERRAFORM_OS_ARCH}.zip
- curl -Os https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_SHA256SUMS
- curl -Os https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_SHA256SUMS.sig
# Verify the signature file is untampered.
- gpg --verify terraform_${TERRAFORM_VERSION}_SHA256SUMS.sig terraform_${TERRAFORM_VERSION}_SHA256SUMS
# Verify the SHASUM matches the binary.
- shasum -a 256 -c terraform_${TERRAFORM_VERSION}_SHA256SUMS 2>&1 | grep "${TERRAFORM_VERSION}_${TERRAFORM_OS_ARCH}.zip:\sOK"
# Install terraform locally and add into PATH.
- mv terraform_${TERRAFORM_VERSION}_${TERRAFORM_OS_ARCH}.zip terraform.zip
- unzip terraform.zip
- sudo mkdir /usr/local/terraform
- sudo mv terraform /usr/local/terraform
- rm -f terraform && rm -f terraform_hash && rm -f terraform.zip
- export PATH="/usr/local/terraform":$PATH
# Install gems.
- bundle install
script:
- rake build

12
Gemfile Normal file
Просмотреть файл

@ -0,0 +1,12 @@
ruby "~> 2.3.0"
source 'https://rubygems.org/'
gem 'rake', '~>12.2.0'
group :test do
gem 'colorize', '~>0.8.0'
gem 'kitchen-terraform', '~>2.1.0'
gem 'rspec', '~>3.7.0'
gem 'test-kitchen', '~>1.16.0'
end

Просмотреть файл

@ -1,3 +1,6 @@
# terraform-azurerm-compute #
[![Build Status](https://travis-ci.org/Azure/terraform-azurerm-compute.svg?branch=master)](https://travis-ci.org/Azure/terraform-azurerm-compute)
Deploys 1+ Virtual Machines to your provided VNet
=================================================
@ -141,6 +144,21 @@ More specifically this provisions:
```
Run Test
-----
### Requirements
- [Git](https://git-scm.com/downloads)
- [Ruby **(~> 2.3)**](https://www.ruby-lang.org/en/downloads/)
- [Bundler **(~> 1.15)**](https://bundler.io/)
- [Terraform **(~> 0.10.8)**](https://www.terraform.io/downloads.html)
- [Configure Terraform for Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/terraform-install-configure)
- [Generate and add SSH Key](https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/)(save the key in ~/.ssh/id_rsa)
### Quick Start
1. `bundle install`
2. `rake build`
3. `rake e2e`
Authors
=======
Originally created by [David Tesar](http://github.com/dtzar)

67
Rakefile Normal file
Просмотреть файл

@ -0,0 +1,67 @@
require 'colorize'
require 'rspec/core/rake_task'
require_relative 'build/file_utils'
require_relative 'build/static_utils'
namespace :presteps do
task :clean_up do
clean_up_kitchen
clean_up_terraform
end
end
namespace :static do
task :style do
style_tf
end
task :lint do
lint_tf
end
task :format do
format_tf
end
end
namespace :integration do
task :converge do
exit_code = `kitchen converge`
if exit_code != 0
raise "ERROR: Test kitchen converge failed! #{exit_code}\n"
end
end
task :verify do
exit_code = `kitchen verify`
if exit_code != 0
raise "ERROR: Test kitchen verify failed! #{exit_code}\n"
end
end
task :test do
exit_code = `kitchen test`
if exit_code != 0
raise "ERROR: Test kitchen test failed! #{exit_code}\n"
end
end
task :destroy do
exit_code = `kitchen destroy`
if exit_code != 0
raise "ERROR: Test kitchen destroy failed! #{exit_code}\n"
end
end
end
task :prereqs => [ 'presteps:clean_up' ]
task :validate => [ 'static:style', 'static:lint' ]
task :format => [ 'static:format' ]
task :build => [ 'prereqs', 'validate' ]
task :unit => []
task :e2e => [ 'integration:test' ]
task :default => [ 'build' ]
task :full => [ 'build', 'unit', 'e2e']

15
build/file_utils.rb Normal file
Просмотреть файл

@ -0,0 +1,15 @@
require 'fileutils'
def clean_up_kitchen
if File.exists? '.kitchen'
print "INFO: Cleaning up the .kitchen folder...\n"
FileUtils.rm_rf('.kitchen')
end
end
def clean_up_terraform
if File.exists? '.terraform'
print "INFO: Cleaning up the .terraform folder...\n"
FileUtils.rm_rf('.terraform')
end
end

41
build/static_utils.rb Normal file
Просмотреть файл

@ -0,0 +1,41 @@
require 'colorize'
require 'fileutils'
def lint_tf
# Do the linting on current working folder.
print "INFO: Linting Terraform configurations...\n".yellow
message = `terraform validate -check-variables=false 2>&1`
# Check the linting message.
if not message.empty?
raise "ERROR: Linting Terraform configurations failed!\n#{message}\n".red
else
print "INFO: Done!\n".green
end
end
def style_tf
# Do the style checking on current working folder.
print "INFO: Styling Terraform configurations...\n".yellow
message = `terraform fmt -check=true 2>&1`
# Check the styling message.
if not message.empty?
raise "ERROR: Styling Terraform configurations failed!\n#{message}\n".red
else
print "INFO: Done!\n".green
end
end
def format_tf
# Apply the canonical format and style on current working folder.
print "INFO: Formatting Terraform configurations...\n".yellow
message = `terraform fmt -diff=true 2>&1`
# Check the styling message.
if not message.empty?
raise "ERROR: Formatting Terraform configurations failed!\n#{message}\n".red
else
print "INFO: Done!\n".green
end
end

42
main.tf
Просмотреть файл

@ -7,7 +7,7 @@ provider "random" {
}
module "os" {
source = "os"
source = "./os"
vm_os_simple = "${var.vm_os_simple}"
}
@ -21,17 +21,18 @@ resource "random_id" "vm-sa" {
keepers = {
vm_hostname = "${var.vm_hostname}"
}
byte_length = 6
}
resource "azurerm_storage_account" "vm-sa" {
count = "${var.boot_diagnostics == "true" ? 1 : 0}"
name = "bootdiag${lower(random_id.vm-sa.hex)}"
resource_group_name = "${azurerm_resource_group.vm.name}"
location = "${var.location}"
account_tier = "${element(split("_", var.boot_diagnostics_sa_type),0)}"
count = "${var.boot_diagnostics == "true" ? 1 : 0}"
name = "bootdiag${lower(random_id.vm-sa.hex)}"
resource_group_name = "${azurerm_resource_group.vm.name}"
location = "${var.location}"
account_tier = "${element(split("_", var.boot_diagnostics_sa_type),0)}"
account_replication_type = "${element(split("_", var.boot_diagnostics_sa_type),1)}"
tags = "${var.tags}"
tags = "${var.tags}"
}
resource "azurerm_virtual_machine" "vm-linux" {
@ -66,7 +67,6 @@ resource "azurerm_virtual_machine" "vm-linux" {
}
os_profile_linux_config {
disable_password_authentication = true
ssh_keys {
@ -78,7 +78,7 @@ resource "azurerm_virtual_machine" "vm-linux" {
tags = "${var.tags}"
boot_diagnostics {
enabled = "${var.boot_diagnostics}"
enabled = "${var.boot_diagnostics}"
storage_uri = "${var.boot_diagnostics == "true" ? join(",", azurerm_storage_account.vm-sa.*.primary_blob_endpoint) : "" }"
}
}
@ -123,7 +123,6 @@ resource "azurerm_virtual_machine" "vm-linux-with-datadisk" {
}
os_profile_linux_config {
disable_password_authentication = true
ssh_keys {
@ -135,7 +134,7 @@ resource "azurerm_virtual_machine" "vm-linux-with-datadisk" {
tags = "${var.tags}"
boot_diagnostics {
enabled = "${var.boot_diagnostics}"
enabled = "${var.boot_diagnostics}"
storage_uri = "${var.boot_diagnostics == "true" ? join(",", azurerm_storage_account.vm-sa.*.primary_blob_endpoint) : "" }"
}
}
@ -176,10 +175,9 @@ resource "azurerm_virtual_machine" "vm-windows" {
os_profile_windows_config {}
boot_diagnostics {
enabled = "${var.boot_diagnostics}"
enabled = "${var.boot_diagnostics}"
storage_uri = "${var.boot_diagnostics == "true" ? join(",", azurerm_storage_account.vm-sa.*.primary_blob_endpoint) : "" }"
}
}
resource "azurerm_virtual_machine" "vm-windows-with-datadisk" {
@ -213,7 +211,7 @@ resource "azurerm_virtual_machine" "vm-windows-with-datadisk" {
lun = 0
disk_size_gb = "${var.data_disk_size_gb}"
managed_disk_type = "${var.data_sa_type}"
}
}
os_profile {
computer_name = "${var.vm_hostname}"
@ -223,10 +221,10 @@ resource "azurerm_virtual_machine" "vm-windows-with-datadisk" {
tags = "${var.tags}"
os_profile_windows_config {}
boot_diagnostics {
enabled = "${var.boot_diagnostics}"
os_profile_windows_config {}
boot_diagnostics {
enabled = "${var.boot_diagnostics}"
storage_uri = "${var.boot_diagnostics == "true" ? join(",", azurerm_storage_account.vm-sa.*.primary_blob_endpoint) : "" }"
}
}
@ -276,9 +274,9 @@ resource "azurerm_network_interface" "vm" {
network_security_group_id = "${azurerm_network_security_group.vm.id}"
ip_configuration {
name = "ipconfig${count.index}"
subnet_id = "${var.vnet_subnet_id}"
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "${length(azurerm_public_ip.vm.*.id) > 0 ? element(concat(azurerm_public_ip.vm.*.id, list("")), count.index) : ""}"
name = "ipconfig${count.index}"
subnet_id = "${var.vnet_subnet_id}"
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "${length(azurerm_public_ip.vm.*.id) > 0 ? element(concat(azurerm_public_ip.vm.*.id, list("")), count.index) : ""}"
}
}

Просмотреть файл

@ -1,16 +1,15 @@
output "calculated_value_os_publisher" {
value = "${element(split(",", lookup(var.standard_os, var.vm_os_simple, "")), 0)}"
value = "${element(split(",", lookup(var.standard_os, var.vm_os_simple, "")), 0)}"
}
output "calculated_value_os_offer" {
value = "${element(split(",", lookup(var.standard_os, var.vm_os_simple, "")), 1)}"
output "calculated_value_os_offer" {
value = "${element(split(",", lookup(var.standard_os, var.vm_os_simple, "")), 1)}"
}
output "calculated_value_os_sku" {
value = "${element(split(",", lookup(var.standard_os, var.vm_os_simple, "")), 2)}"
output "calculated_value_os_sku" {
value = "${element(split(",", lookup(var.standard_os, var.vm_os_simple, "")), 2)}"
}
output "calculated_remote_port" {
value = "${element(split(",", lookup(var.standard_os, var.vm_os_simple, "")), 0) == "MicrosoftWindowsServer" ? 3389 : 22}"
}
value = "${element(split(",", lookup(var.standard_os, var.vm_os_simple, "")), 0) == "MicrosoftWindowsServer" ? 3389 : 22}"
}

Просмотреть файл

@ -4,7 +4,7 @@ variable "vm_os_simple" {
# Definition of the standard OS with "SimpleName" = "publisher,offer,sku"
variable "standard_os" {
default = {
default = {
"UbuntuServer" = "Canonical,UbuntuServer,16.04-LTS"
"WindowsServer" = "MicrosoftWindowsServer,WindowsServer,2016-Datacenter"
"RHEL" = "RedHat,RHEL,7.3"
@ -13,5 +13,5 @@ variable "standard_os" {
"Debian" = "credativ,Debian,8"
"CoreOS" = "CoreOS,CoreOS,Stable"
"SLES" = "SUSE,SLES,12-SP2"
}
}
}

Просмотреть файл

@ -1,39 +1,39 @@
output "vm_ids" {
description = "Virtual machine ids created."
value = "${concat(azurerm_virtual_machine.vm-windows.*.id, azurerm_virtual_machine.vm-linux.*.id)}"
value = "${concat(azurerm_virtual_machine.vm-windows.*.id, azurerm_virtual_machine.vm-linux.*.id)}"
}
output "network_security_group_id" {
description = "id of the security group provisioned"
value = "${azurerm_network_security_group.vm.id}"
value = "${azurerm_network_security_group.vm.id}"
}
output "network_interface_ids" {
description = "ids of the vm nics provisoned."
value = "${azurerm_network_interface.vm.*.id}"
value = "${azurerm_network_interface.vm.*.id}"
}
output "network_interface_private_ip"{
output "network_interface_private_ip" {
description = "private ip addresses of the vm nics"
value = "${azurerm_network_interface.vm.*.private_ip_address}"
value = "${azurerm_network_interface.vm.*.private_ip_address}"
}
output "public_ip_id" {
description = "id of the public ip address provisoned."
value = "${azurerm_public_ip.vm.*.id}"
value = "${azurerm_public_ip.vm.*.id}"
}
output "public_ip_address" {
description = "The actual ip address allocated for the resource."
value = "${azurerm_public_ip.vm.*.ip_address}"
value = "${azurerm_public_ip.vm.*.ip_address}"
}
output "public_ip_dns_name" {
description = "fqdn to connect to the first vm provisioned."
value = "${azurerm_public_ip.vm.*.fqdn}"
value = "${azurerm_public_ip.vm.*.fqdn}"
}
output "availability_set_id" {
description = "id of the availability set where the vms are provisioned."
value = "${azurerm_availability_set.vm.id}"
}
value = "${azurerm_availability_set.vm.id}"
}

Просмотреть файл

@ -0,0 +1,10 @@
# More info please refer to: https://www.inspec.io/docs/
# Define unique test case suite.
control 'operating_system' do
# Define how critical this control is.
impact 1.0
# The actual test case.
describe command('lsb_release -a') do
its('stdout') { should match (/Ubuntu/) }
end
end

Просмотреть файл

@ -0,0 +1,18 @@
# More info please refer to: https://www.inspec.io/docs/
# Get path to terraform state file from attribute of kitchen-terraform.
terraform_state = attribute "terraform_state", {}
# Define how critical this control is.
control "state_file" do
# Define how critical this control is.
impact 0.6
# The actual test case.
describe "the Terraform state file" do
# Get json object of terraform state file.
subject do json(terraform_state).terraform_version end
# Validate the terraform version number field.
it "is accessible" do is_expected.to match /\d+\.\d+\.\d+/ end
end
end

Просмотреть файл

@ -0,0 +1,3 @@
---
name: compute
version: 0.1.0

Просмотреть файл

@ -0,0 +1,16 @@
module "linuxservers" {
source = "../../../"
location = "${var.location}"
vm_os_simple = "${var.vm_os_simple}"
public_ip_dns = ["${var.public_ip_dns}"]
vnet_subnet_id = "${module.network.vnet_subnets[0]}"
ssh_key = "${var.ssh_key}"
resource_group_name = "${var.resource_group_name}"
}
module "network" {
source = "Azure/network/azurerm"
location = "${var.location}"
resource_group_name = "${var.resource_group_name}"
allow_ssh_traffic = true
}

Просмотреть файл

@ -0,0 +1,3 @@
output "test_target_public_dns" {
value = "${module.linuxservers.public_ip_dns_name}"
}

Просмотреть файл

@ -0,0 +1,5 @@
location = "West US 2"
ssh_key = "~/.ssh/id_rsa.pub"
resource_group_name = "azure_compute_e2e"
vm_os_simple = "UbuntuServer"
public_ip_dns = "linsimplevmips"

Просмотреть файл

@ -0,0 +1,5 @@
variable "location" {}
variable "ssh_key" {}
variable "resource_group_name" {}
variable "vm_os_simple" {}
variable "public_ip_dns" {}

Просмотреть файл

@ -13,12 +13,12 @@ variable "vnet_subnet_id" {
variable "public_ip_dns" {
description = "Optional globally unique per datacenter region domain name label to apply to each public ip address. e.g. thisvar.varlocation.cloudapp.azure.com where you specify only thisvar here. This is an array of names which will pair up sequentially to the number of public ips defined in var.nb_public_ip. One name or empty string is required for every public ip. If no public ip is desired, then set this to an array with a single empty string."
default = [""]
default = [""]
}
variable "admin_password" {
description = "The admin password to be used on the VMSS that will be deployed. The password must meet the complexity requirements of Azure"
default = ""
default = ""
}
variable "ssh_key" {
@ -28,7 +28,7 @@ variable "ssh_key" {
variable "remote_port" {
description = "Remote tcp port to be used for access to the vms created via the nsg applied to the nics."
default = ""
default = ""
}
variable "admin_username" {
@ -53,83 +53,85 @@ variable "nb_instances" {
variable "vm_hostname" {
description = "local name of the VM"
default = "myvm"
default = "myvm"
}
variable "vm_os_simple" {
description = "Specify UbuntuServer, WindowsServer, RHEL, openSUSE-Leap, CentOS, Debian, CoreOS and SLES to get the latest image version of the specified os. Do not provide this value if a custom value is used for vm_os_publisher, vm_os_offer, and vm_os_sku."
default = ""
default = ""
}
variable "vm_os_publisher" {
description = "The name of the publisher of the image that you want to deploy. Not necessary if using vm_os_simple."
default = ""
default = ""
}
variable "vm_os_offer" {
description = "The name of the offer of the image that you want to deploy. Not necessary if using vm_os_simple."
default = ""
default = ""
}
variable "vm_os_sku" {
description = "The sku of the image that you want to deploy. Not necessary if using vm_os_simple."
default = ""
default = ""
}
variable "vm_os_version" {
description = "The version of the image that you want to deploy."
default = "latest"
default = "latest"
}
variable "vm_os_id" {
description = "The ID of the image that you want to deploy if you are using a custom image."
default = ""
default = ""
}
variable "tags" {
type = "map"
type = "map"
description = "A map of the tags to use on the resources that are deployed with this module."
default = {
source = "terraform"
}
}
variable "public_ip_address_allocation" {
description = "Defines how an IP address is assigned. Options are Static or Dynamic."
default = "dynamic"
default = "dynamic"
}
variable "nb_public_ip" {
description = "Number of public IPs to assign corresponding to one IP per vm. Set to 0 to not assign any public IP addresses."
default = "1"
default = "1"
}
variable "delete_os_disk_on_termination" {
description = "Delete datadisk when machine is terminated"
default = "false"
description = "Delete datadisk when machine is terminated"
default = "false"
}
variable "data_sa_type" {
description = "Data Disk Storage Account type"
default = "Standard_LRS"
default = "Standard_LRS"
}
variable "data_disk_size_gb" {
description = "Storage data disk size size"
default = ""
default = ""
}
variable "data_disk" {
type = "string"
type = "string"
description = "Set to true to add a datadisk."
default = "false"
default = "false"
}
variable "boot_diagnostics" {
description = "(Optional) Enable or Disable boot diagnostics"
default = "false"
default = "false"
}
variable "boot_diagnostics_sa_type" {
description = "(Optional) Storage account type for boot diagnostics"
default = "Standard_LRS"
description = "(Optional) Storage account type for boot diagnostics"
default = "Standard_LRS"
}