Skip to content

Commit 3752ee9

Browse files
committed
Adding helper scripts to automate image generation and Azure VM creation. Also updating the documentation.
1 parent 07de7b3 commit 3752ee9

File tree

4 files changed

+202
-60
lines changed

4 files changed

+202
-60
lines changed

docs/CreateImageAndAzureResources.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Build an image.
2+
3+
## Create required Azure resources and generate an image
4+
5+
1. Generating required Azure resources and running a packer build for a targeted image is automated [here](../helpers/GenerateResourcesAndImage.ps1).
6+
7+
## Create a VM based on the template created by Packer
8+
9+
1. At the end of the output from running Packer above is a URL to the VM resource template with a read access token. It ends with `.json` plus a query string. Note this URL. For now, it seems like there is an [Az CLI bug](https://github.com/Azure/azure-cli/issues/5899) with specifying the template through a URI. So download the template locally and note the path of the teamplte file.
10+
1. Generating the required Azure resources and creating the VM is automated [here](../helpers/CreateAzureVMFromPackerTeamplte.ps1).
11+
1. After the VM is created, remote into it using its public IP address. You can test the installed tools or install the VSTS agent and connect it to your VSTS account.

docs/vs2017.md

Lines changed: 0 additions & 60 deletions
This file was deleted.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
Function CreateAzureVMFromPackerTemplate {
2+
<#
3+
.SYNOPSIS
4+
Creates an Azure VM from a template. Also generates network resources in Azure to make the VM accessible.
5+
6+
.DESCRIPTION
7+
Creates Azure resources and kicks off a packer image generation for the selected image type.
8+
9+
.PARAMETER SubscriptionId
10+
The Azure subscription Id where resources will be created.
11+
12+
.PARAMETER ResourceGroupName
13+
The Azure resource group name where the Azure virtual machine will be created.
14+
15+
.PARAMETER TemplatFilePath
16+
The path for the json template generated by packer during image generation locally.
17+
18+
.PARAMETER VirtualMachineName
19+
The name of the virtual machine to be generated.
20+
21+
.PARAMETER AdminUserName
22+
The administrator username for the virtual machine to be created.
23+
24+
.PARAMETER AdminPassword
25+
The administrator password for the virtual machine to be created.
26+
27+
.PARAMETER AzureLocation
28+
The location where the Azure virtual machine will be provisioned. Example: "eastus"
29+
30+
.EXAMPLE
31+
CreateAzureVMFromPackerTemplate -SubscriptionId {YourSubscriptionId} -ResourceGroupName {ResourceGroupName} -TemplateFile "C:\BuildVmImages\temporaryTemplate.json" -VirtualMachineName "testvm1" -AdminUsername "shady1" -AdminPassword "SomeSecurePassword1" -AzureLocation "eastus"
32+
#>
33+
param (
34+
[Parameter(Mandatory = $True)]
35+
[string] $SubscriptionId,
36+
[Parameter(Mandatory = $True)]
37+
[string] $ResourceGroupName,
38+
[Parameter(Mandatory = $True)]
39+
[string] $TemplateFilePath,
40+
[Parameter(Mandatory = $True)]
41+
[string] $VirtualMachineName,
42+
[Parameter(Mandatory = $True)]
43+
[string] $AdminUsername,
44+
[Parameter(Mandatory = $True)]
45+
[string] $AdminPassword,
46+
[Parameter(Mandatory = $True)]
47+
[string] $AzureLocation
48+
)
49+
50+
$vmSize = "Standard_DS2_v2"
51+
$vnetName = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper()
52+
$subnetName = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper()
53+
$nicName = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper()
54+
$publicIpName = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper()
55+
56+
Write-Host "Creating a Vnet and a Subnet"
57+
az network vnet create -g $ResourceGroupName -l $AzureLocation --name $vnetName --address-prefix 10.0.0.0/16 --subscription $subscriptionId
58+
az network vnet subnet create -g $ResourceGroupName --vnet-name $vnetName -n $subnetName --address-prefix 10.0.1.0/24 --subscription $subscriptionId
59+
60+
Write-Host "Creating a network interface card (NIC)."
61+
$nic = az network nic create -g $ResourceGroupName --vnet-name $vnetName --subnet $subnetName -n $nicName --subscription $subscriptionId
62+
$networkId = ($nic | ConvertFrom-Json).NewNIC.id
63+
64+
Write-Host "create public IP."
65+
az network public-ip create -g $ResourceGroupName -n $publicIpName --subscription $subscriptionId --allocation-method Static --location $AzureLocation --sku Standard --version IPv4
66+
67+
Write-Host "Adding the public IP to the NIC."
68+
az network nic ip-config update --name ipconfig1 --nic-name $nicName --resource-group $ResourceGroupName --subscription $subscriptionId --public-ip-address $publicIpName
69+
70+
Write-Host "Creating the VM"
71+
az group deployment create --resource-group $ResourceGroupName --subscription $subscriptionId --name $VirtualMachineName --template-file $templateFilePath --parameters vmSize=$vmSize vmName=$VirtualMachineName adminUserName=$AdminUsername adminPassword=$AdminPassword networkInterfaceId=$networkId
72+
}

helpers/GenerateResourcesAndImage.ps1

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
$ErrorActionPreference = 'Stop'
2+
3+
enum ImageType {
4+
VS2017 = 0
5+
VS2019 = 1
6+
Ubuntu1604 = 2
7+
WinCon = 3
8+
}
9+
10+
Function Get-PackerTemplatePath {
11+
param (
12+
[Parameter(Mandatory = $True)]
13+
[string] $RepositoryRoot,
14+
[Parameter(Mandatory = $True)]
15+
[ImageType] $ImageType
16+
)
17+
18+
$relativePath = "N/A"
19+
20+
switch ($ImageType) {
21+
([ImageType]::VS2017) {
22+
$relativePath = "\images\win\vs2017-Server2016-Azure.json"
23+
}
24+
([ImageType]::VS2019) {
25+
$relativePath = "\images\win\vs2019-Server2019-Azure.json"
26+
}
27+
([ImageType]::Ubuntu1604) {
28+
$relativePath = "\images\linux\ubuntu1604.json"
29+
}
30+
([ImageType]::WinCon) {
31+
$relativePath = "\images\linux\WindowsContainer1803-Azure.json"
32+
}
33+
}
34+
35+
return $RepositoryRoot + $relativePath;
36+
}
37+
38+
Function GenerateResourcesAndImage {
39+
<#
40+
.SYNOPSIS
41+
A helper function to help generate an image.
42+
43+
.DESCRIPTION
44+
Creates Azure resources and kicks off a packer image generation for the selected image type.
45+
46+
.PARAMETER SubscriptionId
47+
The Azure subscription Id where resources will be created.
48+
49+
.PARAMETER ResourceGroupName
50+
The Azure resource group name where the Azure resources will be created.
51+
52+
.PARAMETER ImageGenerationRepositoryRoot
53+
The root path of the image generation repository source.
54+
55+
.PARAMETER ImageType
56+
The type of the image being generated. Valid options are: {"VS2017", "VS2019", "Ubuntu164", "WinCon"}.
57+
58+
.PARAMETER AzureLocation
59+
The location of the resources being created in Azure. For example "East US".
60+
61+
.EXAMPLE
62+
GenerateResourcesAndImage -SubscriptionId {YourSubscriptionId} -ResourceGroupName "shsamytest1" -ImageGenerationRepositoryRoot "C:\azure-pipelines-image-generation" -ImageType Ubuntu1604 -AzureLocation "East US"
63+
#>
64+
param (
65+
[Parameter(Mandatory = $True)]
66+
[string] $SubscriptionId,
67+
[Parameter(Mandatory = $True)]
68+
[string] $ResourceGroupName,
69+
[Parameter(Mandatory = $True)]
70+
[string] $ImageGenerationRepositoryRoot,
71+
[Parameter(Mandatory = $True)]
72+
[ImageType] $ImageType,
73+
[Parameter(Mandatory = $True)]
74+
[string] $AzureLocation
75+
)
76+
77+
$builderScriptPath = Get-PackerTemplatePath -RepositoryRoot $ImageGenerationRepositoryRoot -ImageType $ImageType
78+
$ServicePrincipalClientSecret = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper();
79+
$InstallPassword = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper();
80+
81+
Login-AzureRmAccount
82+
Set-AzureRmContext -SubscriptionId $SubscriptionId
83+
84+
$alreadyExists = $true;
85+
try {
86+
Get-AzureRmResourceGroup -Name $ResourceGroupName
87+
$alreadyExists = $true
88+
Write-Verbose "Resource group was found, will delete and recreate it."
89+
}
90+
catch {
91+
Write-Verbose "Resource group was not found, will create it."
92+
$alreadyExists = $false;
93+
}
94+
95+
if ($alreadyExists) {
96+
# Cleanup the resource group if it already exitsted before
97+
Remove-AzureRmResourceGroup -Name $ResourceGroupName -Force
98+
}
99+
100+
New-AzureRmResourceGroup -Name $ResourceGroupName -Location $AzureLocation
101+
102+
$storageAccountName = $ResourceGroupName
103+
New-AzureRmStorageAccount -ResourceGroupName $ResourceGroupName -AccountName $storageAccountName -Location $AzureLocation -SkuName "Standard_LRS"
104+
105+
$spDisplayName = [System.GUID]::NewGuid().ToString().ToUpper()
106+
$sp = New-AzureRmADServicePrincipal -DisplayName $spDisplayName -Password (ConvertTo-SecureString $ServicePrincipalClientSecret -AsPlainText -Force)
107+
108+
$spAppId = $sp.ApplicationId
109+
$spClientId = $sp.ApplicationId
110+
$spObjectId = $sp.Id
111+
Sleep 60
112+
113+
New-AzureRmRoleAssignment -RoleDefinitionName Contributor -ServicePrincipalName $spAppId
114+
$sub = Get-AzureRmSubscription -SubscriptionId $SubscriptionId
115+
$tenantId = $sub.TenantId
116+
# "", "Note this variable-setting script for running Packer with these Azure resources in the future:", "==============================================================================================", "`$spClientId = `"$spClientId`"", "`$ServicePrincipalClientSecret = `"$ServicePrincipalClientSecret`"", "`$SubscriptionId = `"$SubscriptionId`"", "`$tenantId = `"$tenantId`"", "`$spObjectId = `"$spObjectId`"", "`$AzureLocation = `"$AzureLocation`"", "`$ResourceGroupName = `"$ResourceGroupName`"", "`$storageAccountName = `"$storageAccountName`"", "`$install_password = `"$install_password`"", ""
117+
118+
packer.exe build -on-error=ask -var "client_id=$($spClientId)" -var "client_secret=$($ServicePrincipalClientSecret)" -var "subscription_id=$($SubscriptionId)" -var "tenant_id=$($tenantId)" -var "object_id=$($spObjectId)" -var "location=$($AzureLocation)" -var "resource_group=$($ResourceGroupName)" -var "storage_account=$($storageAccountName)" -var "install_password=$($InstallPassword)" $builderScriptPath
119+
}

0 commit comments

Comments
 (0)