Skip to content

Commit

Permalink
feat: add initial vmss build agent (#52)
Browse files Browse the repository at this point in the history
* initial commit

* update vars

* update readme

* add overprovision property

* generate password

* add password to output

* Update

* tidy up script

* add lifecyle ignore tag

* add tf doc tags

* update readme

* Update azurerm/modules/azurerm-vmss/README.md

Co-authored-by: Rishi <[email protected]>

* update to readme

---------

Co-authored-by: Rishi <[email protected]>
  • Loading branch information
RhysBushnell and Trishisingh authored May 22, 2023
1 parent ae80132 commit 8eedb3c
Show file tree
Hide file tree
Showing 11 changed files with 576 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
# .tfstate files
*.tfstate
*.tfstate.*
*.terraform.lock.hcl
plan

# Crash log files
crash.log
Expand Down
120 changes: 120 additions & 0 deletions azurerm/modules/azurerm-vmss/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<!-- BEGIN_TF_DOCS -->
# PROJECT_NAME

DESCRIPTION:
---
Bootstraps the infrastructure for {{SELECT_APP_TYPE }}.

Will be used within the provisioned pipeline for your application depending on the options you chose.

Pipeline implementation for infrastructure relies on workspaces, you can pass in whatever workspace you want from {{ SELECT_DEPLOYMENT_TYPE }} pipeline YAML.

PREREQUISITES:
---
Azure Subscripion
- SPN
- Terraform will use this to perform the authentication for the API calls
- you will need the `client_id, subscription_id, client_secret, tenant_id`

Terraform backend
- resource group (can be manually created for the terraform remote state)
- Blob storage container for the remote state management


USAGE:
---

To activate the terraform backend for running locally we need to initialise the SPN with env vars to ensure you are running the same way as the pipeline that will ultimately be running any incremental changes.

```bash
docker run -it --rm -v $(pwd):/opt/tf-lib amidostacks/ci-tf:latest /bin/bash
This module was written to quickly provision a VMSS which will be used as a self hosted build agent within Azure DevOps.

export ARM_CLIENT_ID=xxxx \
ARM_CLIENT_SECRET=yyyyy \
ARM_SUBSCRIPTION_ID=yyyyy \
ARM_TENANT_ID=yyyyy

alternatively you can run az login

To get up and running locally you will want to create a terraform.tfvars file

TFVAR_CONTENTS='''
vnet_id = "amido-stacks-vnet-uks-dev"
rg_name = "amido-stacks-rg-uks-dev"
resource_group_location = "uksouth"
name_company = "amido"
name_project = "stacks"
name_component = "spa"
name_environment = "dev"
'''
$TFVAR_CONTENTS > terraform.tfvars
terraform workspace select dev || terraform workspace new dev
terraform init -backend-config=./backend.local.tfvars

## Known Limitiations
Work is required to enhance this module to cover wider use cases of VMSS as well as using dynatmic blocks etc to support multiple NICs and IP Configurations.

Future work should also be done to implement a packer image build. This will allow us to build the base image once and speed up the time taken to start new agents as all tools will be installed within the assigned image.

## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.13 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | ~> 3.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | ~> 3.0 |
| <a name="provider_local"></a> [local](#provider\_local) | n/a |
| <a name="provider_random"></a> [random](#provider\_random) | n/a |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [azurerm_linux_virtual_machine_scale_set.vmss](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_virtual_machine_scale_set) | resource |
| [random_password.password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource |
| [azurerm_subnet.subnet](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet) | data source |
| [local_file.sh](https://registry.terraform.io/providers/hashicorp/local/latest/docs/data-sources/file) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_ip_configuration_name"></a> [ip\_configuration\_name](#input\_ip\_configuration\_name) | Name of the IP Config on the VMs NIC. | `string` | `"primary"` | no |
| <a name="input_location_name_map"></a> [location\_name\_map](#input\_location\_name\_map) | Each region must have corresponding a shortend name for resource naming purposes | `map(string)` | <pre>{<br> "eastasia": "ase",<br> "eastus": "use",<br> "eastus2": "use2",<br> "northeurope": "eun",<br> "southeastasia": "asse",<br> "uksouth": "uks",<br> "ukwest": "ukw",<br> "westeurope": "euw",<br> "westus": "usw"<br>}</pre> | no |
| <a name="input_network_interface_name"></a> [network\_interface\_name](#input\_network\_interface\_name) | Name of the VMs NIC. | `string` | `"primary"` | no |
| <a name="input_overprovision"></a> [overprovision](#input\_overprovision) | Bool to set overprovisioning. | `bool` | `false` | no |
| <a name="input_subnet_name"></a> [subnet\_name](#input\_subnet\_name) | Name of the Subnet which the VMSS will be provisioned. | `string` | `""` | no |
| <a name="input_vmss_admin_password"></a> [vmss\_admin\_password](#input\_vmss\_admin\_password) | Password for Admin SSH Access to VMs. | `string` | `""` | no |
| <a name="input_vmss_admin_username"></a> [vmss\_admin\_username](#input\_vmss\_admin\_username) | Username for Admin SSH Access to VMs. | `string` | `""` | no |
| <a name="input_vmss_disable_password_auth"></a> [vmss\_disable\_password\_auth](#input\_vmss\_disable\_password\_auth) | Boolean to enable or disable password authentication to VMs. | `bool` | `false` | no |
| <a name="input_vmss_disk_caching"></a> [vmss\_disk\_caching](#input\_vmss\_disk\_caching) | Disk Caching options. | `string` | `"ReadWrite"` | no |
| <a name="input_vmss_image_offer"></a> [vmss\_image\_offer](#input\_vmss\_image\_offer) | Image offer. Eg UbuntuServer | `string` | `"0001-com-ubuntu-server-jammy"` | no |
| <a name="input_vmss_image_publisher"></a> [vmss\_image\_publisher](#input\_vmss\_image\_publisher) | Image Publisher. | `string` | `"Canonical"` | no |
| <a name="input_vmss_image_sku"></a> [vmss\_image\_sku](#input\_vmss\_image\_sku) | Image SKU. | `string` | `"22_04-lts-gen2"` | no |
| <a name="input_vmss_image_version"></a> [vmss\_image\_version](#input\_vmss\_image\_version) | Version of VM Image SKU required. | `string` | `"latest"` | no |
| <a name="input_vmss_instances"></a> [vmss\_instances](#input\_vmss\_instances) | Default number of instances within the scaleset. | `number` | `1` | no |
| <a name="input_vmss_name"></a> [vmss\_name](#input\_vmss\_name) | Name of the VMSS | `string` | `""` | no |
| <a name="input_vmss_resource_group_location"></a> [vmss\_resource\_group\_location](#input\_vmss\_resource\_group\_location) | Location of Resource group | `string` | `"uksouth"` | no |
| <a name="input_vmss_resource_group_name"></a> [vmss\_resource\_group\_name](#input\_vmss\_resource\_group\_name) | name of resource group | `string` | `""` | no |
| <a name="input_vmss_sku"></a> [vmss\_sku](#input\_vmss\_sku) | VM Size | `string` | `"Standard_D2s_v3"` | no |
| <a name="input_vmss_storage_account_type"></a> [vmss\_storage\_account\_type](#input\_vmss\_storage\_account\_type) | Storeage type used for VMSS Disk. | `string` | `"StandardSSD_LRS"` | no |
| <a name="input_vnet_name"></a> [vnet\_name](#input\_vnet\_name) | Name of the VNET which the VMSS will be provisioned. | `string` | `""` | no |
| <a name="input_vnet_resource_group"></a> [vnet\_resource\_group](#input\_vnet\_resource\_group) | Name of the Resource Group in which the VNET is provisioned. | `string` | `""` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_vmss_admin_password"></a> [vmss\_admin\_password](#output\_vmss\_admin\_password) | n/a |
| <a name="output_vmss_id"></a> [vmss\_id](#output\_vmss\_id) | n/a |
<!-- END_TF_DOCS -->
30 changes: 30 additions & 0 deletions azurerm/modules/azurerm-vmss/ci_cd_tool_install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/sh

# Install Powershell
# Update the list of packages
sudo apt-get update
# Install pre-requisite packages.
sudo apt-get install -y wget apt-transport-https software-properties-common ca-certificates curl gnupg build-essential
# Download the Microsoft repository GPG keys
wget -q "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb"
# Register the Microsoft repository GPG keys
sudo dpkg -i packages-microsoft-prod.deb
# Delete the the Microsoft repository GPG keys file
rm packages-microsoft-prod.deb
# Update the list of packages after we added packages.microsoft.com
sudo apt-get update
# Install PowerShell
sudo apt-get install -y powershell
# Install Modules
pwsh -NoProfile -Command "Install-Module -Name Az -Scope AllUsers -Repository PSGallery -Force"
pwsh -NoProfile -Command "Install-Module -Name Az.Accounts -Scope AllUsers -Force"
pwsh -NoProfile -Command "Install-Module -Name Az.DataFactory -Scope AllUsers -Force"
# Start PowerShell
pwsh

# Install Azure CLI
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

# Install Python
sudo apt-get update
sudo apt-get install -y python3 python3-pip
9 changes: 9 additions & 0 deletions azurerm/modules/azurerm-vmss/constraints.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 0.13"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
9 changes: 9 additions & 0 deletions azurerm/modules/azurerm-vmss/example/constraints.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 0.13"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
18 changes: 18 additions & 0 deletions azurerm/modules/azurerm-vmss/example/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
resource "azurerm_resource_group" "default" {
name = "azdo-build-test"
location = var.vmss_resource_group_location
tags = var.tags
}

module "vmss" {
source = "../../azurerm-vmss"
vmss_name = "azdo-build-test"
vmss_resource_group_name = azurerm_resource_group.default.name
vmss_resource_group_location = azurerm_resource_group.default.location
vnet_name = "amido-stacks-nonprod-euw-core"
vnet_resource_group = "amido-stacks-nonprod-euw-core"
subnet_name = "build-agent"
vmss_instances = 1
vmss_admin_username = "adminuser"
vmss_disable_password_auth = false
}
13 changes: 13 additions & 0 deletions azurerm/modules/azurerm-vmss/example/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
terraform {
backend "azurerm" {
resource_group_name = "amido-stacks-dev-euw-de"
storage_account_name = "detestdevrb"
container_name = "tfstate"
key = "vmss.terraform.tfstate"
}

}

provider "azurerm" {
features {}
}
152 changes: 152 additions & 0 deletions azurerm/modules/azurerm-vmss/example/vars.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
############################################
# NAMING
############################################
variable "vnet_name" {
type = string
default = ""
description = "Name of the VNET which the VMSS will be provisioned."
}

variable "vnet_resource_group" {
type = string
default = ""
description = "Name of the Resource Group in which the VNET is provisioned."
}

variable "subnet_name" {
type = string
default = ""
description = "Name of the Subnet which the VMSS will be provisioned."
}

variable "vmss_name" {
type = string
default = ""
description = "Name of the VMSS"
}

variable "network_interface_name" {
type = string
default = "primary"
description = "Name of the VMs NIC."
}

variable "ip_configuration_name" {
type = string
default = "primary"
description = "Name of the IP Config on the VMs NIC."
}

variable "tags" {
description = "Tags to be assigned to all resources, NB if global tagging is enabled these will get overwritten periodically"
type = map(string)
default = {}
}

variable "resource_tags" {
description = "Map of tags to be applied to all resources created as part of this module"
type = map(string)
default = {}
}

############################################
# RESOURCE INFORMATION
############################################

variable "vmss_resource_group_location" {
type = string
default = "westeurope"
description = "Location of Resource group"
}

variable "vmss_resource_group_name" {
type = string
description = "name of resource group"
default = ""
}

# Each region must have corresponding a shortend name for resource naming purposes
variable "location_name_map" {
type = map(string)

default = {
northeurope = "eun"
westeurope = "euw"
uksouth = "uks"
ukwest = "ukw"
eastus = "use"
eastus2 = "use2"
westus = "usw"
eastasia = "ase"
southeastasia = "asse"
}
}

variable "vmss_sku" {
type = string
default = "Standard_D2_v3"
description = "VM Size"
}

variable "vmss_instances" {
type = number
default = 1
description = "Default number of instances within the scaleset."
}

variable "vmss_admin_username" {
type = string
default = ""
description = "Username for Admin SSH Access to VMs."
}

variable "vmss_admin_password" {
type = string
default = ""
description = "Password for Admin SSH Access to VMs."
}

variable "vmss_disable_password_auth" {
type = bool
default = false
description = "Boolean to enable or disable password authentication to VMs."
}

variable "vmss_image_publisher" {
type = string
default = "canonical"
description = "Image Publisher."
}

variable "vmss_image_offer" {
type = string
default = "UbuntuServer"
description = "Image offer. Eg UbuntuServer"
}

variable "vmss_image_sku" {
type = string
default = "22_04-lts"
description = "Image SKU."
}

variable "vmss_image_version" {
type = string
default = "latest"
description = "Version of VM Image SKU required."
}

variable "vmss_storage_account_type" {
type = string
default = "Standard_LRS"
description = "Storeage type used for VMSS Disk."
}

variable "vmss_disk_caching" {
type = string
default = "ReadWrite"
description = "Disk Caching options."
}



Loading

0 comments on commit 8eedb3c

Please sign in to comment.