1
0
Форкнуть 0

ACI DevOps Agent Terraform Module

* add terraform module configuration
* add documentation
* add validation tests and end-to-end tests
* add Azure pipeline
This commit is contained in:
Julien Corioland 2020-06-05 10:47:10 +02:00 коммит произвёл GitHub
Родитель cd600bb923
Коммит d6360df82b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
31 изменённых файлов: 1706 добавлений и 2 удалений

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

@ -0,0 +1,47 @@
# Local .terraform directories
**/.terraform/*
terraform.tfstate.d/
logs/
# Variable files
terraform.tfvars
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
# Go vendor directory
vendor/
# Files generated by terratest
.test-data/
# Terraform log file
terraform.log
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
*.plan
# Golang
go.sum
.vscode/
# IDE configs
.idea
# Ruby download package lock file.
Gemfile.lock
# Mac folder attribute file
.DS_Store

36
Dockerfile Normal file
Просмотреть файл

@ -0,0 +1,36 @@
# Pull the base image with given version.
ARG BUILD_TERRAFORM_VERSION="0.12.20"
FROM mcr.microsoft.com/terraform-test:${BUILD_TERRAFORM_VERSION}
ARG MODULE_NAME="terraform-azure-devops-eagent-aci"
# Declare default build configurations for terraform.
ARG BUILD_ARM_SUBSCRIPTION_ID=""
ARG BUILD_ARM_CLIENT_ID=""
ARG BUILD_ARM_CLIENT_SECRET=""
ARG BUILD_ARM_TENANT_ID=""
ARG BUILD_ARM_TEST_LOCATION="WestEurope"
ARG BUILD_ARM_TEST_LOCATION_ALT="WestUS"
# Set environment variables for terraform runtime.
ENV ARM_SUBSCRIPTION_ID=${BUILD_ARM_SUBSCRIPTION_ID}
ENV ARM_CLIENT_ID=${BUILD_ARM_CLIENT_ID}
ENV ARM_CLIENT_SECRET=${BUILD_ARM_CLIENT_SECRET}
ENV ARM_TENANT_ID=${BUILD_ARM_TENANT_ID}
ENV ARM_TEST_LOCATION=${BUILD_ARM_TEST_LOCATION}
ENV ARM_TEST_LOCATION_ALT=${BUILD_ARM_TEST_LOCATION_ALT}
# Set work directory.
RUN mkdir /go
RUN mkdir /go/bin
RUN mkdir /go/src
RUN mkdir /go/src/${MODULE_NAME}
COPY . /go/src/${MODULE_NAME}
WORKDIR /go/src/${MODULE_NAME}
# Install dep.
ENV GOPATH /go
ENV PATH /usr/local/go/bin:$GOPATH/bin:$PATH
RUN /bin/bash -c "curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh"
RUN ["bundle", "install", "--gemfile", "./Gemfile"]

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

@ -0,0 +1,9 @@
source 'https://rubygems.org/' do
group :test do
git 'https://github.com/Azure/terramodtest.git' do
gem 'terramodtest', tag: '0.5.0'
end
end
end

292
README.md
Просмотреть файл

@ -1,9 +1,297 @@
# terraform-azurerm-aci-devops-agent
# Contributing
This repository contains a Terraform module that helps you to deploy [Azure DevOps self-hosted agents](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/agents?view=azure-devops&tabs=browser#install) running on Azure Container Instance.
You can choose to deploy Linux or Windows agents, provide custom Docker images for the agents to include the tools you really need. It also give you the option to deploy the agents into a private virtual network, if the agents needs to access internal resources.
## How-to use this module to deploy Azure DevOps agents
### Build the Docker images
This module requires that you build your own Linux and/or Windows Docker images, to run the Azure DevOps agents. The [docker](docker/README.md) contains Dockerfile and instructions for both.
### Create an Azure DevOps agent pool and personal access token
Before running this module, you need to [create an agent pool in your Azure DevOps organization](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/pools-queues?view=azure-devops&tabs=yaml%2Cbrowser#creating-agent-pools) and a [personal access token](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-linux?view=azure-devops#permissions) that it authorized to manage this agent pool.
This module has 3 variables related to Azure DevOps:
- `azure_devops_org_name`: the name of your Azure DevOps organization (if you are connecting to `https://dev.azure.com/helloworld`, then `helloworld` is your organization name)
- `azure_devops_personal_access_token`: the personal access token that you have generated
- `agent_pool_name`: both in the `linux_agents_configuration` and `windows_agents_configuration`, it is the name of the agent pool that you have created in which the Linux or Windows agents must be deployed
### Terraform ACI DevOps Agents usage
#### Create or use an existing a resource group
This module offers to create a new resource group to deploy the Azure Container instances into it, or import an existing one. This behavior is controlled using the `create_resource_group` flag:
- if `create_resource_group` is set to true, the module will create a resource group named `resource_group_name` in the `location` region
- if `create_resource_group` is set to false, the module will import a resource group data source with the name `resource_group_name`
#### Terraform ACI DevOps Agents - Deploy Linux Agents
The configuration below can be used to deploy Linux DevOps agents using Azure Container Instances.
```hcl
module "aci-devops-agent" {
source = "Azure/aci-devops-agent/azurerm"
resource_group_name = "rg-linux-devops-agents"
location = "westeurope"
enable_vnet_integration = false
create_resource_group = true
linux_agents_configuration = {
agent_name_prefix = "linux-agent"
agent_pool_name = "DEVOPS_POOL_NAME"
count = 2,
docker_image = "jcorioland/aci-devops-agent"
docker_tag = "0.2-linux"
cpu = 1
memory = 4
}
azure_devops_org_name = "DEVOPS_ORG_NAME"
azure_devops_personal_access_token = "DEVOPS_PERSONAL_ACCESS_TOKEN"
}
```
Then, you can just Terraform it:
```bash
terraform init
terraform plan -out aci-linux-devops-agents.plan
terraform apply "aci-linux-devops-agents.plan"
```
You can destroy everything using `terraform destroy`:
```bash
terraform destroy
```
#### Terraform ACI DevOps Agents - Deploy Linux agents in an existing virtual network
The configuration below can be used to deploy Azure DevOps agents in Linux containers, in an existing virtual network.
```hcl
resource "azurerm_resource_group" "vnet-rg" {
name = "rg-aci-devops-network"
location = "westeurope"
}
resource "azurerm_virtual_network" "vnet" {
name = "vnet-aci-devops"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.vnet-rg.location
resource_group_name = azurerm_resource_group.vnet-rg.name
}
resource "azurerm_subnet" "aci-subnet" {
name = "aci-subnet"
resource_group_name = azurerm_resource_group.vnet-rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.1.0/24"]
delegation {
name = "acidelegation"
service_delegation {
name = "Microsoft.ContainerInstance/containerGroups"
actions = ["Microsoft.Network/virtualNetworks/subnets/join/action", "Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action"]
}
}
}
module "aci-devops-agent" {
source = "Azure/aci-devops-agent/azurerm"
resource_group_name = "rg-linux-devops-agents"
location = "westeurope"
enable_vnet_integration = true
create_resource_group = true
vnet_resource_group_name = azurerm_resource_group.vnet-rg.name
vnet_name = azurerm_virtual_network.vnet.name
subnet_name = azurerm_subnet.aci-subnet.name
linux_agents_configuration = {
agent_name_prefix = "linux-agent"
agent_pool_name = "DEVOPS_POOL_NAME"
count = 2,
docker_image = "jcorioland/aci-devops-agent"
docker_tag = "0.2-linux"
cpu = 1
memory = 4
}
azure_devops_org_name = "DEVOPS_ORG_NAME"
azure_devops_personal_access_token = "DEVOPS_PERSONAL_ACCESS_TOKEN"
}
```
Then, you can just Terraform it:
```bash
terraform init
terraform plan -out aci-linux-devops-agents.plan
terraform apply "aci-linux-devops-agents.plan"
```
You can destroy everything using `terraform destroy`:
```bash
terraform destroy
```
#### Terraform ACI DevOps Agents - Deploy both Linux and Windows agents
The configuration below can be used to deploy Azure DevOps Linux and Windows agents in containers on ACI.
```hcl
module "aci-devops-agent" {
source = "Azure/aci-devops-agent/azurerm"
resource_group_name = "rg-aci-devops-agents-we"
location = "westeurope"
enable_vnet_integration = false
create_resource_group = true
linux_agents_configuration = {
agent_name_prefix = "linux-agent"
agent_pool_name = "DEVOPS_POOL_NAME"
count = 2,
docker_image = "jcorioland/aci-devops-agent"
docker_tag = "0.2-linux"
cpu = 1
memory = 4
}
windows_agents_configuration = {
agent_name_prefix = "windows-agent"
agent_pool_name = "DEVOPS_POOL_NAME"
count = 2,
docker_image = "jcorioland/aci-devops-agent"
docker_tag = "0.2-win"
cpu = 1
memory = 4
}
azure_devops_org_name = "DEVOPS_ORG_NAME"
azure_devops_personal_access_token = "DEVOPS_PERSONAL_ACCESS_TOKEN"
}
```
Then, you can just Terraform it:
```bash
terraform init
terraform plan -out aci-devops-agents.plan
terraform apply "aci-devops-agents.plan"
```
You can destroy everything using `terraform destroy`:
```bash
terraform destroy
```
## Test
### Configurations
- [Configure Terraform for Azure](https://docs.microsoft.com/en-us/azure/virtual-machines/linux/terraform-install-configure)
We provide 2 ways to build, run, and test the module on a local development machine. [Native (Mac/Linux)](#native-maclinux) or [Docker](#docker).
### Native (Mac/Linux)
#### Prerequisites
- [Ruby **(~> 2.3)**](https://www.ruby-lang.org/en/downloads/)
- [Bundler **(~> 1.15)**](https://bundler.io/)
- [Terraform **(~> 0.11.7)**](https://www.terraform.io/downloads.html)
- [Golang **(~> 1.12.3)**](https://golang.org/dl/)
#### Environment setup
We provide simple script to quickly set up module development environment:
```sh
$ curl -sSL https://raw.githubusercontent.com/Azure/terramodtest/master/tool/env_setup.sh | sudo bash
```
#### Run test
Then simply run it in local shell:
```sh
$ bundle install
$ rake build
$ rake full
```
### Docker
We provide a Dockerfile to build a new image based `FROM` the `microsoft/terraform-test` Docker hub image which adds additional tools / packages specific for this module (see Custom Image section). Alternatively use only the `microsoft/terraform-test` Docker hub image [by using these instructions](https://github.com/Azure/terraform-test).
#### Prerequisites
- [Docker](https://www.docker.com/community-edition#/download)
#### Custom Image
This builds the custom image:
```sh
$ docker build --build-arg BUILD_ARM_SUBSCRIPTION_ID=$ARM_SUBSCRIPTION_ID --build-arg BUILD_ARM_CLIENT_ID=$ARM_CLIENT_ID --build-arg BUILD_ARM_CLIENT_SECRET=$ARM_CLIENT_SECRET --build-arg BUILD_ARM_TENANT_ID=$ARM_TENANT_ID -t azure-devops-agent-aci-test .
```
This runs the build and unit tests:
```sh
$ docker run --rm \
-e TF_VAR_azure_devops_org_name=$AZDO_ORG_NAME \
-e TF_VAR_azure_devops_personal_access_token=$AZDO_PAT \
-e TF_VAR_azure_devops_pool_name=$AZDO_POOL_NAME \
azure-devops-agent-aci-test /bin/bash -c "bundle install && rake build"
```
This runs the end to end tests:
```sh
$ docker run --rm \
-e TF_VAR_azure_devops_org_name=$AZDO_ORG_NAME \
-e TF_VAR_azure_devops_personal_access_token=$AZDO_PAT \
-e TF_VAR_azure_devops_pool_name=$AZDO_POOL_NAME \
azure-devops-agent-aci-test /bin/bash -c "bundle install && rake e2e"
```
This runs the full tests:
```sh
$ docker run --rm \
-e TF_VAR_azure_devops_org_name=$AZDO_ORG_NAME \
-e TF_VAR_azure_devops_personal_access_token=$AZDO_PAT \
-e TF_VAR_azure_devops_pool_name=$AZDO_POOL_NAME \
azure-devops-agent-aci-test /bin/bash -c "bundle install && rake full"
```
With:
- `AZDO_ORG_NAME` being the name of the Azure DevOps organization
- `AZDO_PAT` being the personal access token to connect to Azure DevOps
- `AZDO_POOL_NAME` being the name of the Azure DevOps agent pool
## Authors
Originally created by [Julien Corioland](http://github.com/jcorioland)
## License
[MIT](LICENSE)
## Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
the rights to use your contribution. For details, visit [https://cla.opensource.microsoft.com](https://cla.opensource.microsoft.com).
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions

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

@ -0,0 +1,54 @@
# Official gems.
require 'colorize'
require 'rspec/core/rake_task'
# Git repo gems.
require 'bundler/setup'
require 'terramodtest'
namespace :presteps do
task :ensure do
puts "Using go mod to install required go packages.\n"
success = system ("cd test && go mod download")
if not success
raise "ERROR: go mod download failed!\n".red
end
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 :test do
success = system ("cd test && go test -v ./ -timeout 30m -parallel 1")
if not success
raise "ERROR: Go test failed!\n".red
end
end
end
task :prereqs => [ 'presteps:ensure' ]
task :validate => [ 'static:style', 'static:lint' ]
task :format => [ 'static:format' ]
task :build => [ 'prereqs', 'validate' ]
task :unit => []
task :e2e => [ 'prereqs', 'integration:test' ]
task :default => [ 'build' ]
task :full => [ 'build', 'unit', 'e2e' ]

63
azure-pipeline.yaml Normal file
Просмотреть файл

@ -0,0 +1,63 @@
# Azure Pipeline that runs module integration tests
trigger: none
variables:
- group: AzureDevOpsACI.Secrets
- name: dockerImage
value: 'terraform-azure-devops-aci'
- name: terraformVersion
value: 0.12.25
- name: vmImage
value: ubuntu-latest
- name: serviceConnection
value: "terraform-azure-devops-aci"
stages:
- stage: AzureDevOpsACITerraformModule
displayName: AZure DevOps ACI Agents Terraform Module - CI
jobs:
- job: AzureDevOpsACITerraformModuleJob
displayName: AZure DevOps ACI Agents Terraform Module - CI Job
pool:
vmImage: $(vmImage)
cancelTimeoutInMinutes: 30
steps:
- task: AzureCLI@1
displayName: Get Azure Credentials for Terraform
inputs:
azureSubscription: $(serviceConnection)
scriptLocation: inlineScript
inlineScript: |
set -eu
subscriptionId=$(az account show --query id -o tsv)
echo "##vso[task.setvariable variable=ARM_CLIENT_ID;issecret=true]$servicePrincipalId"
echo "##vso[task.setvariable variable=ARM_CLIENT_SECRET;issecret=true]$servicePrincipalKey"
echo "##vso[task.setvariable variable=ARM_SUBSCRIPTION_ID;issecret=true]$subscriptionId"
echo "##vso[task.setvariable variable=ARM_TENANT_ID;issecret=true]$tenantId"
addSpnToEnvironment: true
- task: Docker@2
displayName: Build Terratest Docker Image
inputs:
command: build
repository: $(dockerImage)
dockerfile: '$(System.DefaultWorkingDirectory)/Dockerfile'
buildContext: $(System.DefaultWorkingDirectory)
arguments: --build-arg BUILD_ARM_SUBSCRIPTION_ID=$(ARM_SUBSCRIPTION_ID) --build-arg BUILD_ARM_CLIENT_ID=$(ARM_CLIENT_ID) --build-arg BUILD_ARM_CLIENT_SECRET=$(ARM_CLIENT_SECRET) --build-arg BUILD_ARM_TENANT_ID=$(ARM_TENANT_ID)
tags: |
$(Build.BuildId)
- script: |
docker run --rm \
-e TF_VAR_azure_devops_org_name=$(AZDO_ORG_NAME) \
-e TF_VAR_azure_devops_personal_access_token=$(AZDO_PAT) \
-e TF_VAR_azure_devops_pool_name=$(AZDO_POOL_NAME) \
$(dockerImage):$(Build.BuildId) /bin/bash -c "bundle install && rake build"
displayName: Run validation tests
- script: |
docker run --rm \
-e TF_VAR_azure_devops_org_name=$(AZDO_ORG_NAME) \
-e TF_VAR_azure_devops_personal_access_token=$(AZDO_PAT) \
-e TF_VAR_azure_devops_pool_name=$(AZDO_POOL_NAME) \
$(dockerImage):$(Build.BuildId) /bin/bash -c "bundle install && rake full"
displayName: Run full end to end tests
condition: succeeded()

3
docker/README.md Normal file
Просмотреть файл

@ -0,0 +1,3 @@
# Docker images for Azure DevOps agents
This folder contains Dockerfiles and instructions to build your own [Linux](linux/README.md) or [Windows](windows/README.md) Docker images.

25
docker/linux/Dockerfile Normal file
Просмотреть файл

@ -0,0 +1,25 @@
FROM ubuntu:16.04
# To make it easier for build and release pipelines to run apt-get,
# configure apt to not require confirmation (assume the -y argument by default)
ENV DEBIAN_FRONTEND=noninteractive
RUN echo "APT::Get::Assume-Yes \"true\";" > /etc/apt/apt.conf.d/90assumeyes
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
ca-certificates \
curl \
jq \
git \
iputils-ping \
libcurl3 \
libicu55 \
libunwind8 \
netcat
WORKDIR /azp
COPY ./start.sh .
RUN chmod +x start.sh
CMD ["./start.sh"]

17
docker/linux/README.md Normal file
Просмотреть файл

@ -0,0 +1,17 @@
# Linux Agent Docker Image
This image is based on the [official documentation](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/docker?view=azure-devops#linux).
> Note: You can update the [Dockerfile](Dockerfile) to add any software that your require into the Azure DevOps agent, if you don't want to have to download the bits during all pipelines executions.
## Build it
```bash
docker built -t YOUR_IMAGE_NAME:YOUR_IMAGE_TAG .
```
## Push it
```bash
docker push YOUR_IMAGE_NAME:YOUR_IMAGE_TAG
```

98
docker/linux/start.sh Normal file
Просмотреть файл

@ -0,0 +1,98 @@
#!/bin/bash
set -e
if [ -z "$AZP_URL" ]; then
echo 1>&2 "error: missing AZP_URL environment variable"
exit 1
fi
if [ -z "$AZP_TOKEN_FILE" ]; then
if [ -z "$AZP_TOKEN" ]; then
echo 1>&2 "error: missing AZP_TOKEN environment variable"
exit 1
fi
AZP_TOKEN_FILE=/azp/.token
echo -n $AZP_TOKEN > "$AZP_TOKEN_FILE"
fi
unset AZP_TOKEN
if [ -n "$AZP_WORK" ]; then
mkdir -p "$AZP_WORK"
fi
rm -rf /azp/agent
mkdir /azp/agent
cd /azp/agent
export AGENT_ALLOW_RUNASROOT="1"
cleanup() {
if [ -e config.sh ]; then
print_header "Cleanup. Removing Azure Pipelines agent..."
./config.sh remove --unattended \
--auth PAT \
--token $(cat "$AZP_TOKEN_FILE")
fi
}
print_header() {
lightcyan='\033[1;36m'
nocolor='\033[0m'
echo -e "${lightcyan}$1${nocolor}"
}
# Let the agent ignore the token env variables
export VSO_AGENT_IGNORE=AZP_TOKEN,AZP_TOKEN_FILE
# ACI in private vnet require time to get access to Internet
sleep 30
print_header "1. Determining matching Azure Pipelines agent..."
AZP_AGENT_RESPONSE=$(curl -LsS \
-u user:$(cat "$AZP_TOKEN_FILE") \
-H 'Accept:application/json;api-version=3.0-preview' \
"$AZP_URL/_apis/distributedtask/packages/agent?platform=linux-x64")
if echo "$AZP_AGENT_RESPONSE" | jq . >/dev/null 2>&1; then
AZP_AGENTPACKAGE_URL=$(echo "$AZP_AGENT_RESPONSE" \
| jq -r '.value | map([.version.major,.version.minor,.version.patch,.downloadUrl]) | sort | .[length-1] | .[3]')
fi
if [ -z "$AZP_AGENTPACKAGE_URL" -o "$AZP_AGENTPACKAGE_URL" == "null" ]; then
echo 1>&2 "error: could not determine a matching Azure Pipelines agent - check that account '$AZP_URL' is correct and the token is valid for that account"
exit 1
fi
print_header "2. Downloading and installing Azure Pipelines agent..."
curl -LsS $AZP_AGENTPACKAGE_URL | tar -xz & wait $!
source ./env.sh
trap 'cleanup; exit 130' INT
trap 'cleanup; exit 143' TERM
print_header "3. Configuring Azure Pipelines agent..."
./config.sh --unattended \
--agent "${AZP_AGENT_NAME:-$(hostname)}" \
--url "$AZP_URL" \
--auth PAT \
--token $(cat "$AZP_TOKEN_FILE") \
--pool "${AZP_POOL:-Default}" \
--work "${AZP_WORK:-_work}" \
--replace \
--acceptTeeEula & wait $!
# remove the administrative token before accepting work
rm $AZP_TOKEN_FILE
print_header "4. Running Azure Pipelines agent..."
# `exec` the node runtime so it's aware of TERM and INT signals
# AgentService.js understands how to handle agent self-update and restart
exec ./externals/node/bin/node ./bin/AgentService.js interactive

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

@ -0,0 +1,7 @@
FROM mcr.microsoft.com/windows/servercore:ltsc2019
WORKDIR /azp
COPY start.ps1 .
CMD powershell .\start.ps1

17
docker/windows/README.md Normal file
Просмотреть файл

@ -0,0 +1,17 @@
# Windows Agent Docker Image
This image is based on the [official documentation](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/docker?view=azure-devops#windows).
> Note: You can update the [Dockerfile](Dockerfile) to add any software that your require into the Azure DevOps agent, if you don't want to have to download the bits during all pipelines executions.
## Build it
```bash
docker built -t YOUR_IMAGE_NAME:YOUR_IMAGE_TAG .
```
## Push it
```bash
docker push YOUR_IMAGE_NAME:YOUR_IMAGE_TAG
```

71
docker/windows/start.ps1 Normal file
Просмотреть файл

@ -0,0 +1,71 @@
if (-not (Test-Path Env:AZP_URL)) {
Write-Error "error: missing AZP_URL environment variable"
exit 1
}
if (-not (Test-Path Env:AZP_TOKEN_FILE)) {
if (-not (Test-Path Env:AZP_TOKEN)) {
Write-Error "error: missing AZP_TOKEN environment variable"
exit 1
}
$Env:AZP_TOKEN_FILE = "\azp\.token"
$Env:AZP_TOKEN | Out-File -FilePath $Env:AZP_TOKEN_FILE
}
Remove-Item Env:AZP_TOKEN
if ($Env:AZP_WORK -and -not (Test-Path Env:AZP_WORK)) {
New-Item $Env:AZP_WORK -ItemType directory | Out-Null
}
New-Item "\azp\agent" -ItemType directory | Out-Null
# Let the agent ignore the token env variables
$Env:VSO_AGENT_IGNORE = "AZP_TOKEN,AZP_TOKEN_FILE"
Set-Location agent
Write-Host "1. Determining matching Azure Pipelines agent..." -ForegroundColor Cyan
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$(Get-Content ${Env:AZP_TOKEN_FILE})"))
$package = Invoke-RestMethod -Headers @{Authorization=("Basic $base64AuthInfo")} "$(${Env:AZP_URL})/_apis/distributedtask/packages/agent?platform=win-x64&`$top=1"
$packageUrl = $package[0].Value.downloadUrl
Write-Host $packageUrl
Write-Host "2. Downloading and installing Azure Pipelines agent..." -ForegroundColor Cyan
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($packageUrl, "$(Get-Location)\agent.zip")
Expand-Archive -Path "agent.zip" -DestinationPath "\azp\agent"
try
{
Write-Host "3. Configuring Azure Pipelines agent..." -ForegroundColor Cyan
.\config.cmd --unattended `
--agent "$(if (Test-Path Env:AZP_AGENT_NAME) { ${Env:AZP_AGENT_NAME} } else { ${Env:computername} })" `
--url "$(${Env:AZP_URL})" `
--auth PAT `
--token "$(Get-Content ${Env:AZP_TOKEN_FILE})" `
--pool "$(if (Test-Path Env:AZP_POOL) { ${Env:AZP_POOL} } else { 'Default' })" `
--work "$(if (Test-Path Env:AZP_WORK) { ${Env:AZP_WORK} } else { '_work' })" `
--replace
# remove the administrative token before accepting work
Remove-Item $Env:AZP_TOKEN_FILE
Write-Host "4. Running Azure Pipelines agent..." -ForegroundColor Cyan
.\run.cmd
}
finally
{
Write-Host "Cleanup. Removing Azure Pipelines agent..." -ForegroundColor Cyan
.\config.cmd remove --unattended `
--auth PAT `
--token "$(Get-Content ${Env:AZP_TOKEN_FILE})"
}

116
main.tf Normal file
Просмотреть файл

@ -0,0 +1,116 @@
resource "azurerm_resource_group" "rg" {
# the resource group is created only if the flag create_resource_group is set to true
count = var.create_resource_group ? 1 : 0
name = var.resource_group_name
location = var.location
}
data "azurerm_resource_group" "rg" {
# the resource group is imported only if the flag create_resource_group is set to false
count = var.create_resource_group ? 0 : 1
name = var.resource_group_name
}
data "azurerm_subnet" "subnet" {
# the subnet is imported only enable_vnet_integration is true
count = var.enable_vnet_integration ? 1 : 0
name = var.subnet_name
virtual_network_name = var.vnet_name
resource_group_name = var.vnet_resource_group_name
}
# Linux Agents - deployed only if variable linux_agents_configuration.count > 0
resource "azurerm_network_profile" "linux_network_profile" {
count = var.enable_vnet_integration ? var.linux_agents_configuration.count : 0
name = "linuxnetprofile${count.index}"
location = var.location
resource_group_name = var.create_resource_group ? azurerm_resource_group.rg[0].name : data.azurerm_resource_group.rg[0].name
container_network_interface {
name = "linuxnic${count.index}"
ip_configuration {
name = "linuxip${count.index}"
subnet_id = data.azurerm_subnet.subnet[0].id
}
}
}
resource "azurerm_container_group" "linux-container-group" {
count = var.linux_agents_configuration.count
name = "${var.linux_agents_configuration.agent_name_prefix}-${count.index}"
location = var.location
resource_group_name = var.create_resource_group ? azurerm_resource_group.rg[0].name : data.azurerm_resource_group.rg[0].name
ip_address_type = var.enable_vnet_integration ? "private" : "public"
os_type = "linux"
network_profile_id = var.enable_vnet_integration ? azurerm_network_profile.linux_network_profile[count.index].id : null
container {
name = "${var.linux_agents_configuration.agent_name_prefix}-${count.index}"
image = "${var.linux_agents_configuration.docker_image}:${var.linux_agents_configuration.docker_tag}"
cpu = var.linux_agents_configuration.cpu
memory = var.linux_agents_configuration.memory
# this field seems to be mandatory (error happens if not there). See https://github.com/terraform-providers/terraform-provider-azurerm/issues/1697#issuecomment-608669422
ports {
port = 80
protocol = "TCP"
}
environment_variables = {
AZP_URL = "https://dev.azure.com/${var.azure_devops_org_name}"
AZP_POOL = var.linux_agents_configuration.agent_pool_name
AZP_TOKEN = var.azure_devops_personal_access_token
AZP_AGENT_NAME = "${var.linux_agents_configuration.agent_name_prefix}-${count.index}"
}
}
}
# Windows Agents - deployed only if variable windows_agents_configuration.count > 0
resource "azurerm_network_profile" "windows_network_profile" {
count = var.enable_vnet_integration ? var.windows_agents_configuration.count : 0
name = "windowsnetprofile${count.index}"
location = var.location
resource_group_name = var.create_resource_group ? azurerm_resource_group.rg[0].name : data.azurerm_resource_group.rg[0].name
container_network_interface {
name = "windowsnic${count.index}"
ip_configuration {
name = "windowsip${count.index}"
subnet_id = data.azurerm_subnet.subnet[0].id
}
}
}
resource "azurerm_container_group" "windows-container-group" {
count = var.windows_agents_configuration.count
name = "${var.windows_agents_configuration.agent_name_prefix}-${count.index}"
location = var.location
resource_group_name = var.create_resource_group ? azurerm_resource_group.rg[0].name : data.azurerm_resource_group.rg[0].name
ip_address_type = var.enable_vnet_integration ? "private" : "public"
os_type = "windows"
network_profile_id = var.enable_vnet_integration ? azurerm_network_profile.windows_network_profile[count.index].id : null
container {
name = "${var.windows_agents_configuration.agent_name_prefix}-${count.index}"
image = "${var.windows_agents_configuration.docker_image}:${var.windows_agents_configuration.docker_tag}"
cpu = var.windows_agents_configuration.cpu
memory = var.windows_agents_configuration.memory
# this field seems to be mandatory (error happens if not there). See https://github.com/terraform-providers/terraform-provider-azurerm/issues/1697#issuecomment-608669422
ports {
port = 80
protocol = "TCP"
}
environment_variables = {
AZP_URL = "https://dev.azure.com/${var.azure_devops_org_name}"
AZP_POOL = var.windows_agents_configuration.agent_pool_name
AZP_TOKEN = var.azure_devops_personal_access_token
AZP_AGENT_NAME = "${var.windows_agents_configuration.agent_name_prefix}-${count.index}"
}
}
}

39
output.tf Normal file
Просмотреть файл

@ -0,0 +1,39 @@
output "has_linux_agents" {
value = length(azurerm_container_group.linux-container-group) > 0 ? true : false
description = "A flag that indicates if Linux agents have been deployed with the current configuration."
}
output "linux_agents_count" {
value = length(azurerm_container_group.linux-container-group)
description = "A number that indicates the number of Linux agents that have been deployed with the current configuration."
}
output "linux_agents_names" {
value = azurerm_container_group.linux-container-group.*.name
description = "An array that contains the names of Linux agents that have been deployed with the current configuration."
}
output "vnet_integration_enabled" {
value = var.enable_vnet_integration
description = "A flag that indicates if the vnet integration has been enabled with the current configuration."
}
output "subnet_id" {
value = var.enable_vnet_integration ? data.azurerm_subnet.subnet[0].id : ""
description = "If the vnet integration is enabled, the id of the subnet in which the agents are deployed."
}
output "has_windows_agents" {
value = length(azurerm_container_group.windows-container-group) > 0 ? true : false
description = "A flag that indicates if Windows agents have been deployed with the current configuration."
}
output "windows_agents_count" {
value = length(azurerm_container_group.windows-container-group)
description = "A number that indicates the number of Windows agents that have been deployed with the current configuration."
}
output "windows_agents_names" {
value = azurerm_container_group.windows-container-group.*.name
description = "An array that contains the names of Windows agents that have been deployed with the current configuration."
}

3
provider.tf Normal file
Просмотреть файл

@ -0,0 +1,3 @@
provider "azurerm" {
features {}
}

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

@ -0,0 +1,389 @@
package test
import (
"context"
"fmt"
"math/rand"
"os"
"strconv"
"testing"
"time"
"github.com/gruntwork-io/terratest/modules/terraform"
test_structure "github.com/gruntwork-io/terratest/modules/test-structure"
"github.com/microsoft/azure-devops-go-api/azuredevops"
"github.com/microsoft/azure-devops-go-api/azuredevops/taskagent"
)
// This function tests the deployment of Azure DevOps Linux agents
func TestDeployAzureDevOpsLinuxAgents(t *testing.T) {
t.Parallel()
fixtureFolder := "./fixture/linux-agents"
// generate a random suffix for the test
rand.Seed(time.Now().UnixNano())
randomInt := rand.Intn(9999)
randomSuffix := strconv.Itoa(randomInt)
os.Setenv("TF_VAR_random_suffix", randomSuffix)
// randomize the agent pool name
devopsPoolName := os.Getenv("TF_VAR_azure_devops_pool_name")
testPoolName := fmt.Sprintf("%s-%s", devopsPoolName, randomSuffix)
os.Setenv("TF_VAR_azure_devops_pool_name", testPoolName)
devopsOrganizationName := os.Getenv("TF_VAR_azure_devops_org_name")
devopsPersonalAccessToken := os.Getenv("TF_VAR_azure_devops_personal_access_token")
devopsOrganizationURL := fmt.Sprintf("https://dev.azure.com/%s", devopsOrganizationName)
defer deleteAzureDevOpsAgentTestPool(testPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
err := createAzureDevOpsAgentTestPool(testPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot create Azure DevOps agent pool for the test: %v", err)
}
// Deploy the example
test_structure.RunTestStage(t, "setup", func() {
terraformOptions := configureTerraformOptions(t, fixtureFolder)
// Save the options so later test stages can use them
test_structure.SaveTerraformOptions(t, fixtureFolder, terraformOptions)
// This will init and apply the resources and fail the test if there are any errors
terraform.InitAndApply(t, terraformOptions)
})
// Check whether the length of output meets the requirement
test_structure.RunTestStage(t, "validate", func() {
// add wait time for ACI to get connectivity
time.Sleep(45 * time.Second)
// ensure deployment was successful
expectedAgentsCount := 2
actualAgentsCount, err := getAgentsCount(testPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot retrieve the number of agents that were deployed: %v", err)
}
if expectedAgentsCount != actualAgentsCount {
t.Fatalf("Test failed. Expected number of agents is %d. Actual number of agents is %d", expectedAgentsCount, actualAgentsCount)
}
})
// At the end of the test, clean up any resources that were created
test_structure.RunTestStage(t, "teardown", func() {
terraformOptions := test_structure.LoadTerraformOptions(t, fixtureFolder)
terraform.Destroy(t, terraformOptions)
})
}
// This function tests the deployment of Azure DevOps Linux agents into an existing virtual network
func TestDeployAzureDevOpsLinuxAgentsInVirtualNetwork(t *testing.T) {
t.Parallel()
fixtureFolder := "./fixture/linux-agents-vnet"
// generate a random suffix for the test
rand.Seed(time.Now().UnixNano())
randomInt := rand.Intn(9999)
randomSuffix := strconv.Itoa(randomInt)
os.Setenv("TF_VAR_random_suffix", randomSuffix)
// randomize the agent pool name
devopsPoolName := os.Getenv("TF_VAR_azure_devops_pool_name")
testPoolName := fmt.Sprintf("%s-%s", devopsPoolName, randomSuffix)
os.Setenv("TF_VAR_azure_devops_pool_name", testPoolName)
devopsOrganizationName := os.Getenv("TF_VAR_azure_devops_org_name")
devopsPersonalAccessToken := os.Getenv("TF_VAR_azure_devops_personal_access_token")
devopsOrganizationURL := fmt.Sprintf("https://dev.azure.com/%s", devopsOrganizationName)
defer deleteAzureDevOpsAgentTestPool(testPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
err := createAzureDevOpsAgentTestPool(testPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot create Azure DevOps agent pool for the test: %v", err)
}
// Deploy the example
test_structure.RunTestStage(t, "setup", func() {
terraformOptions := configureTerraformOptions(t, fixtureFolder)
// Save the options so later test stages can use them
test_structure.SaveTerraformOptions(t, fixtureFolder, terraformOptions)
// This will init and apply the resources and fail the test if there are any errors
terraform.InitAndApply(t, terraformOptions)
})
// Check whether the length of output meets the requirement
test_structure.RunTestStage(t, "validate", func() {
// add wait time for ACI to get connectivity
time.Sleep(45 * time.Second)
// ensure deployment was successful
expectedAgentsCount := 2
actualAgentsCount, err := getAgentsCount(testPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot retrieve the number of agents that were deployed: %v", err)
}
if expectedAgentsCount != actualAgentsCount {
t.Fatalf("Test failed. Expected number of agents is %d. Actual number of agents is %d", expectedAgentsCount, actualAgentsCount)
}
})
// At the end of the test, clean up any resources that were created
test_structure.RunTestStage(t, "teardown", func() {
terraformOptions := test_structure.LoadTerraformOptions(t, fixtureFolder)
terraform.Destroy(t, terraformOptions)
})
}
// This function tests the deployment of Azure DevOps Linux and Windows agents
func TestDeployAzureDevOpsLinuxAndWindowsAgents(t *testing.T) {
t.Parallel()
fixtureFolder := "./fixture/linux-and-windows-agents"
// generate a random suffix for the test
rand.Seed(time.Now().UnixNano())
randomInt := rand.Intn(9999)
randomSuffix := strconv.Itoa(randomInt)
os.Setenv("TF_VAR_random_suffix", randomSuffix)
// create random Linux agent pool name
linuxTestPoolName := fmt.Sprintf("linux-e2e-agents-%s", randomSuffix)
os.Setenv("TF_VAR_linux_azure_devops_pool_name", linuxTestPoolName)
// create random Windows agent pool name
windowsTestPoolName := fmt.Sprintf("windows-e2e-agents-%s", randomSuffix)
os.Setenv("TF_VAR_windows_azure_devops_pool_name", windowsTestPoolName)
devopsOrganizationName := os.Getenv("TF_VAR_azure_devops_org_name")
devopsPersonalAccessToken := os.Getenv("TF_VAR_azure_devops_personal_access_token")
devopsOrganizationURL := fmt.Sprintf("https://dev.azure.com/%s", devopsOrganizationName)
// create the Linux agents pool
defer deleteAzureDevOpsAgentTestPool(linuxTestPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
err := createAzureDevOpsAgentTestPool(linuxTestPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot create Azure DevOps Linux agent pool for the test: %v", err)
}
// create the Windows agents pool
defer deleteAzureDevOpsAgentTestPool(windowsTestPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
err = createAzureDevOpsAgentTestPool(windowsTestPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot create Azure DevOps Linux agent pool for the test: %v", err)
}
// Deploy the example
test_structure.RunTestStage(t, "setup", func() {
terraformOptions := configureTerraformOptions(t, fixtureFolder)
// Save the options so later test stages can use them
test_structure.SaveTerraformOptions(t, fixtureFolder, terraformOptions)
// This will init and apply the resources and fail the test if there are any errors
terraform.InitAndApply(t, terraformOptions)
})
// Check whether the length of output meets the requirement
test_structure.RunTestStage(t, "validate", func() {
// add wait time for ACI to get connectivity + pull Windows image
time.Sleep(150 * time.Second)
// ensure deployment was successful for Linux agents
expectedLinuxAgentsCount := 2
actualLinuxAgentsCount, err := getAgentsCount(linuxTestPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot retrieve the number of Linux agents that were deployed: %v", err)
}
if expectedLinuxAgentsCount != actualLinuxAgentsCount {
t.Fatalf("Test failed. Expected number of Linux agents is %d. Actual number of Linux agents is %d", expectedLinuxAgentsCount, actualLinuxAgentsCount)
}
// ensure deployment was successful for Windows agents
expectedWindowsAgentsCount := 2
actualWindowsAgentsCount, err := getAgentsCount(windowsTestPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot retrieve the number of Windows agents that were deployed: %v", err)
}
if expectedWindowsAgentsCount != actualWindowsAgentsCount {
t.Fatalf("Test failed. Expected number of Windows agents is %d. Actual number of Windows agents is %d", expectedWindowsAgentsCount, actualWindowsAgentsCount)
}
})
// At the end of the test, clean up any resources that were created
test_structure.RunTestStage(t, "teardown", func() {
terraformOptions := test_structure.LoadTerraformOptions(t, fixtureFolder)
terraform.Destroy(t, terraformOptions)
})
}
// This function tests the deployment of Azure DevOps Linux agents into an existing resource group
func TestDeployAzureDevOpsLinuxAgentsIntoExistingRresourceGroup(t *testing.T) {
t.Parallel()
fixtureFolder := "./fixture/linux-agents-import-rg"
// generate a random suffix for the test
rand.Seed(time.Now().UnixNano())
randomInt := rand.Intn(9999)
randomSuffix := strconv.Itoa(randomInt)
os.Setenv("TF_VAR_random_suffix", randomSuffix)
// randomize the agent pool name
devopsPoolName := os.Getenv("TF_VAR_azure_devops_pool_name")
testPoolName := fmt.Sprintf("%s-%s", devopsPoolName, randomSuffix)
os.Setenv("TF_VAR_azure_devops_pool_name", testPoolName)
devopsOrganizationName := os.Getenv("TF_VAR_azure_devops_org_name")
devopsPersonalAccessToken := os.Getenv("TF_VAR_azure_devops_personal_access_token")
devopsOrganizationURL := fmt.Sprintf("https://dev.azure.com/%s", devopsOrganizationName)
defer deleteAzureDevOpsAgentTestPool(testPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
err := createAzureDevOpsAgentTestPool(testPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot create Azure DevOps agent pool for the test: %v", err)
}
// Deploy the example
test_structure.RunTestStage(t, "setup", func() {
terraformOptions := configureTerraformOptions(t, fixtureFolder)
// Save the options so later test stages can use them
test_structure.SaveTerraformOptions(t, fixtureFolder, terraformOptions)
// This will init and apply the resources and fail the test if there are any errors
terraform.InitAndApply(t, terraformOptions)
})
// Check whether the length of output meets the requirement
test_structure.RunTestStage(t, "validate", func() {
// add wait time for ACI to get connectivity
time.Sleep(45 * time.Second)
// ensure deployment was successful
expectedAgentsCount := 2
actualAgentsCount, err := getAgentsCount(testPoolName, devopsOrganizationURL, devopsPersonalAccessToken)
if err != nil {
t.Fatalf("Cannot retrieve the number of agents that were deployed: %v", err)
}
if expectedAgentsCount != actualAgentsCount {
t.Fatalf("Test failed. Expected number of agents is %d. Actual number of agents is %d", expectedAgentsCount, actualAgentsCount)
}
})
// At the end of the test, clean up any resources that were created
test_structure.RunTestStage(t, "teardown", func() {
terraformOptions := test_structure.LoadTerraformOptions(t, fixtureFolder)
terraform.Destroy(t, terraformOptions)
})
}
func configureTerraformOptions(t *testing.T, fixtureFolder string) *terraform.Options {
terraformOptions := &terraform.Options{
// The path to where our Terraform code is located
TerraformDir: fixtureFolder,
// Variables to pass to our Terraform code using -var options
Vars: map[string]interface{}{},
}
return terraformOptions
}
func getAgentsCount(devopsPoolName string, devopsOrganizationURL string, devopsPersonalAccessToken string) (int, error) {
ctx := context.Background()
devopsConnection := azuredevops.NewPatConnection(devopsOrganizationURL, devopsPersonalAccessToken)
devopsTaskAgentClient, err := taskagent.NewClient(ctx, devopsConnection)
if err != nil {
return -1, err
}
agentPool, err := getAgentPool(ctx, devopsTaskAgentClient, devopsPoolName)
if err != nil {
return -1, err
}
getAgentsArgs := taskagent.GetAgentsArgs{
PoolId: agentPool.Id,
}
agents, err := devopsTaskAgentClient.GetAgents(ctx, getAgentsArgs)
if err != nil {
return -1, err
}
return len(*agents), nil
}
func createAzureDevOpsAgentTestPool(devopsPoolName string, devopsOrganizationURL string, devopsPersonalAccessToken string) error {
ctx := context.Background()
devopsConnection := azuredevops.NewPatConnection(devopsOrganizationURL, devopsPersonalAccessToken)
devopsTaskAgentClient, err := taskagent.NewClient(ctx, devopsConnection)
if err != nil {
return err
}
addAgentPoolArgs := taskagent.AddAgentPoolArgs{
Pool: &taskagent.TaskAgentPool{
Name: &devopsPoolName,
PoolType: &taskagent.TaskAgentPoolTypeValues.Automation,
},
}
_, err = devopsTaskAgentClient.AddAgentPool(ctx, addAgentPoolArgs)
if err != nil {
return err
}
return nil
}
func deleteAzureDevOpsAgentTestPool(devopsPoolName string, devopsOrganizationURL string, devopsPersonalAccessToken string) error {
ctx := context.Background()
devopsConnection := azuredevops.NewPatConnection(devopsOrganizationURL, devopsPersonalAccessToken)
devopsTaskAgentClient, err := taskagent.NewClient(ctx, devopsConnection)
if err != nil {
return err
}
agentPoolToDelete, err := getAgentPool(ctx, devopsTaskAgentClient, devopsPoolName)
if err != nil {
return err
}
deleteAgentPoolArgs := taskagent.DeleteAgentPoolArgs{
PoolId: agentPoolToDelete.Id,
}
return devopsTaskAgentClient.DeleteAgentPool(ctx, deleteAgentPoolArgs)
}
func getAgentPool(ctx context.Context, devopsTaskAgentClient taskagent.Client, devopsPoolName string) (*taskagent.TaskAgentPool, error) {
getAgentPoolsArgs := taskagent.GetAgentPoolsArgs{
PoolName: &devopsPoolName,
}
matchingAgentPools, err := devopsTaskAgentClient.GetAgentPools(ctx, getAgentPoolsArgs)
if err != nil {
return nil, err
}
if matchingAgentPools == nil || len(*matchingAgentPools) == 0 {
return nil, fmt.Errorf("Cannot find an agent pool that matches name: %s", devopsPoolName)
}
return &(*matchingAgentPools)[0], nil
}

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

@ -0,0 +1,23 @@
resource "azurerm_resource_group" "rg" {
name = "rg-terraform-azure-devops-agents-e2e-tests-${var.random_suffix}"
location = var.location
}
module "aci-devops-agent" {
source = "../../../"
enable_vnet_integration = false
create_resource_group = false
linux_agents_configuration = {
agent_name_prefix = "linuxagent-${var.random_suffix}"
count = var.agents_count
docker_image = var.agent_docker_image
docker_tag = var.agent_docker_tag
agent_pool_name = var.azure_devops_pool_name
cpu = 1
memory = 4
}
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
azure_devops_org_name = var.azure_devops_org_name
azure_devops_personal_access_token = var.azure_devops_personal_access_token
}

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

@ -0,0 +1,3 @@
provider "azurerm" {
features {}
}

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

@ -0,0 +1,43 @@
variable azure_devops_org_name {
type = string
description = "The name of the Azure DevOps organization in which the containerized agents will be deployed (e.g. https://dev.azure.com/YOUR_ORGANIZATION_NAME, must exist)"
}
variable azure_devops_pool_name {
type = string
description = "The name of the Azure DevOps agent pool in which the containerized agents will be deployed (must exist)"
}
variable azure_devops_personal_access_token {
type = string
description = "The personal access token to use to connect to Azure DevOps (see https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-windows?view=azure-devops#permissions)"
}
variable location {
type = string
description = "The Azure location to use"
default = "westeurope"
}
variable agent_docker_image {
type = string
description = "The Docker image to use for the Linux agent"
default = "jcorioland/aci-devops-agent"
}
variable agent_docker_tag {
type = string
description = "The Docker tag to use for the Linux agent"
default = "0.2-linux"
}
variable agents_count {
type = number
description = "The number of agents to create"
default = 2
}
variable random_suffix {
type = number
description = "A random suffix for resources generated during the test"
}

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

@ -0,0 +1,49 @@
resource "azurerm_resource_group" "vnet-rg" {
name = "rg-aci-devops-network-${var.random_suffix}"
location = var.location
}
resource "azurerm_virtual_network" "vnet" {
name = "vnet-aci-devops-${var.random_suffix}"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.vnet-rg.location
resource_group_name = azurerm_resource_group.vnet-rg.name
}
resource "azurerm_subnet" "aci-subnet" {
name = "aci-subnet-${var.random_suffix}"
resource_group_name = azurerm_resource_group.vnet-rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.1.0/24"]
delegation {
name = "acidelegation"
service_delegation {
name = "Microsoft.ContainerInstance/containerGroups"
actions = ["Microsoft.Network/virtualNetworks/subnets/join/action", "Microsoft.Network/virtualNetworks/subnets/prepareNetworkPolicies/action"]
}
}
}
module "aci-devops-agent" {
source = "../../../"
enable_vnet_integration = true
create_resource_group = true
vnet_resource_group_name = azurerm_resource_group.vnet-rg.name
vnet_name = azurerm_virtual_network.vnet.name
subnet_name = azurerm_subnet.aci-subnet.name
linux_agents_configuration = {
agent_name_prefix = "linuxagent-${var.random_suffix}"
count = var.agents_count
docker_image = var.agent_docker_image
docker_tag = var.agent_docker_tag
agent_pool_name = var.azure_devops_pool_name
cpu = 1
memory = 4
}
resource_group_name = "rg-terraform-azure-devops-agents-e2e-tests-${var.random_suffix}"
location = var.location
azure_devops_org_name = var.azure_devops_org_name
azure_devops_personal_access_token = var.azure_devops_personal_access_token
}

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

@ -0,0 +1,3 @@
provider "azurerm" {
features {}
}

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

@ -0,0 +1,43 @@
variable azure_devops_org_name {
type = string
description = "The name of the Azure DevOps organization in which the containerized agents will be deployed (e.g. https://dev.azure.com/YOUR_ORGANIZATION_NAME, must exist)"
}
variable azure_devops_pool_name {
type = string
description = "The name of the Azure DevOps agent pool in which the containerized agents will be deployed (must exist)"
}
variable azure_devops_personal_access_token {
type = string
description = "The personal access token to use to connect to Azure DevOps (see https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-windows?view=azure-devops#permissions)"
}
variable location {
type = string
description = "The Azure location to use"
default = "westus"
}
variable agent_docker_image {
type = string
description = "The Docker image to use for the Linux agent"
default = "jcorioland/aci-devops-agent"
}
variable agent_docker_tag {
type = string
description = "The Docker tag to use for the Linux agent"
default = "0.2-linux"
}
variable agents_count {
type = number
description = "The number of agents to create"
default = 2
}
variable random_suffix {
type = number
description = "A random suffix for resources generated during the test"
}

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

@ -0,0 +1,18 @@
module "aci-devops-agent" {
source = "../../../"
enable_vnet_integration = false
create_resource_group = true
linux_agents_configuration = {
agent_name_prefix = "linuxagent-${var.random_suffix}"
count = var.agents_count
docker_image = var.agent_docker_image
docker_tag = var.agent_docker_tag
agent_pool_name = var.azure_devops_pool_name
cpu = 1
memory = 4
}
resource_group_name = "rg-terraform-azure-devops-agents-e2e-tests-${var.random_suffix}"
location = var.location
azure_devops_org_name = var.azure_devops_org_name
azure_devops_personal_access_token = var.azure_devops_personal_access_token
}

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

@ -0,0 +1,3 @@
provider "azurerm" {
features {}
}

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

@ -0,0 +1,43 @@
variable azure_devops_org_name {
type = string
description = "The name of the Azure DevOps organization in which the containerized agents will be deployed (e.g. https://dev.azure.com/YOUR_ORGANIZATION_NAME, must exist)"
}
variable azure_devops_pool_name {
type = string
description = "The name of the Azure DevOps agent pool in which the containerized agents will be deployed (must exist)"
}
variable azure_devops_personal_access_token {
type = string
description = "The personal access token to use to connect to Azure DevOps (see https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-windows?view=azure-devops#permissions)"
}
variable location {
type = string
description = "The Azure location to use"
default = "westeurope"
}
variable agent_docker_image {
type = string
description = "The Docker image to use for the Linux agent"
default = "jcorioland/aci-devops-agent"
}
variable agent_docker_tag {
type = string
description = "The Docker tag to use for the Linux agent"
default = "0.2-linux"
}
variable agents_count {
type = number
description = "The number of agents to create"
default = 2
}
variable random_suffix {
type = number
description = "A random suffix for resources generated during the test"
}

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

@ -0,0 +1,27 @@
module "aci-devops-agent" {
source = "../../../"
enable_vnet_integration = false
create_resource_group = true
linux_agents_configuration = {
agent_name_prefix = "linux-agent-${var.random_suffix}"
count = 2,
docker_image = var.linux_agent_docker_image
docker_tag = var.linux_agent_docker_tag
agent_pool_name = var.linux_azure_devops_pool_name
cpu = 1
memory = 4
}
windows_agents_configuration = {
agent_name_prefix = "windows-agent-${var.random_suffix}"
count = 2,
docker_image = var.windows_agent_docker_image
docker_tag = var.windows_agent_docker_tag
agent_pool_name = var.windows_azure_devops_pool_name
cpu = 1
memory = 4
}
resource_group_name = "rg-terraform-azure-devops-agents-e2e-tests-${var.random_suffix}"
location = var.location
azure_devops_org_name = var.azure_devops_org_name
azure_devops_personal_access_token = var.azure_devops_personal_access_token
}

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

@ -0,0 +1,3 @@
provider "azurerm" {
features {}
}

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

@ -0,0 +1,62 @@
variable azure_devops_org_name {
type = string
description = "The name of the Azure DevOps organization in which the containerized agents will be deployed (e.g. https://dev.azure.com/YOUR_ORGANIZATION_NAME, must exist)"
}
variable azure_devops_personal_access_token {
type = string
description = "The personal access token to use to connect to Azure DevOps (see https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-windows?view=azure-devops#permissions)"
}
variable linux_azure_devops_pool_name {
type = string
description = "The name of the Azure DevOps agent pool in which the linux containerized agents will be deployed (must exist)"
default = "linux-e2e-agents"
}
variable windows_azure_devops_pool_name {
type = string
description = "The name of the Azure DevOps agent pool in which the windows containerized agents will be deployed (must exist)"
default = "windows-e2e-agents"
}
variable location {
type = string
description = "The Azure location to use"
default = "westeurope"
}
variable linux_agent_docker_image {
type = string
description = "The Docker image to use for the Linux agent"
default = "jcorioland/aci-devops-agent"
}
variable linux_agent_docker_tag {
type = string
description = "The Docker tag to use for the Linux agent"
default = "0.2-linux"
}
variable windows_agent_docker_image {
type = string
description = "The Docker image to use for the Windows agent"
default = "jcorioland/aci-devops-agent"
}
variable windows_agent_docker_tag {
type = string
description = "The Docker tag to use for the Windows agent"
default = "0.2-win"
}
variable agents_count {
type = number
description = "The number of agents to create"
default = 2
}
variable random_suffix {
type = number
description = "A random suffix for resources generated during the test"
}

9
test/go.mod Normal file
Просмотреть файл

@ -0,0 +1,9 @@
module test
go 1.13
require (
github.com/docker/distribution v2.7.1+incompatible
github.com/gruntwork-io/terratest v0.27.2
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b1
)

93
variables.tf Normal file
Просмотреть файл

@ -0,0 +1,93 @@
variable resource_group_name {
type = string
description = "The name of the resource group in which the containerized agents will be deployed"
}
variable location {
type = string
description = "The Azure location to use for deployment"
}
variable create_resource_group {
type = bool
default = true
description = "(Optional) A flag that indicates if the resource group in which the agents will be deployed must be created (true) or imported (false)."
}
variable enable_vnet_integration {
type = bool
default = false
description = "(Optional) A flag that indicates if the containerized agents must be deployed into an existing virtual network"
}
variable vnet_resource_group_name {
type = string
default = ""
description = "(Optional) The name of the resource group that contains the virtual network in which the containerized agents will be deployed"
}
variable vnet_name {
type = string
default = ""
description = "(Optional) The name of the virtual network in which the containerized agents will be deployed"
}
variable subnet_name {
type = string
default = ""
description = "(Optional) The name of the subnet of the vnet in which the containerized agents will be deployed"
}
variable azure_devops_org_name {
type = string
description = "The name of the Azure DevOps organization in which the containerized agents will be deployed (e.g. https://dev.azure.com/YOUR_ORGANIZATION_NAME, must exist)"
}
variable azure_devops_personal_access_token {
type = string
description = "The personal access token to use to connect to Azure DevOps (see https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/v2-windows?view=azure-devops#permissions)"
}
variable linux_agents_configuration {
type = object({
count = string,
docker_image = string,
docker_tag = string,
agent_name_prefix = string,
agent_pool_name = string,
cpu = string,
memory = string
})
description = "(Optional) The configuration of the Linux agents to deploy"
default = {
count = 0,
docker_image = "",
docker_tag = "",
agent_name_prefix = "",
agent_pool_name = "",
cpu = "1",
memory = "2"
}
}
variable windows_agents_configuration {
type = object({
count = string,
docker_image = string,
docker_tag = string,
agent_name_prefix = string,
agent_pool_name = string,
cpu = string,
memory = string
})
description = "(Optional) The configuration of the Windows agents to deploy"
default = {
count = 0,
docker_image = "",
docker_tag = "",
agent_name_prefix = "",
agent_pool_name = "",
cpu = "1",
memory = "2"
}
}