Add support for optionally building Azure VMs with additional disks.
This commit is contained in:
parent
487b1d7167
commit
efcdbfeab9
|
@ -12,6 +12,11 @@ const (
|
|||
BuilderId = "Azure.ResourceManagement.VMImage"
|
||||
)
|
||||
|
||||
type AdditionalDiskArtifact struct {
|
||||
AdditionalDiskUri string
|
||||
AdditionalDiskUriReadOnlySas string
|
||||
}
|
||||
|
||||
type Artifact struct {
|
||||
// VHD
|
||||
StorageAccountLocation string
|
||||
|
@ -24,6 +29,9 @@ type Artifact struct {
|
|||
ManagedImageResourceGroupName string
|
||||
ManagedImageName string
|
||||
ManagedImageLocation string
|
||||
|
||||
// Additional Disks
|
||||
AdditionalDisks *[]AdditionalDiskArtifact
|
||||
}
|
||||
|
||||
func NewManagedImageArtifact(resourceGroup, name, location string) (*Artifact, error) {
|
||||
|
@ -53,12 +61,28 @@ func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string)
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var additional_disks *[]AdditionalDiskArtifact
|
||||
if template.Resources[0].Properties.StorageProfile.DataDisks != nil {
|
||||
data_disks := make([]AdditionalDiskArtifact, len(template.Resources[0].Properties.StorageProfile.DataDisks))
|
||||
for i, additionaldisk := range template.Resources[0].Properties.StorageProfile.DataDisks {
|
||||
additionalVhdUri, err := url.Parse(additionaldisk.Image.Uri)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data_disks[i].AdditionalDiskUri = additionalVhdUri.String()
|
||||
data_disks[i].AdditionalDiskUriReadOnlySas = getSasUrl(getStorageUrlPath(additionalVhdUri))
|
||||
}
|
||||
additional_disks = &data_disks
|
||||
}
|
||||
|
||||
return &Artifact{
|
||||
OSDiskUri: vhdUri.String(),
|
||||
OSDiskUriReadOnlySas: getSasUrl(getStorageUrlPath(vhdUri)),
|
||||
TemplateUri: templateUri.String(),
|
||||
TemplateUriReadOnlySas: getSasUrl(getStorageUrlPath(templateUri)),
|
||||
|
||||
AdditionalDisks: additional_disks,
|
||||
|
||||
StorageAccountLocation: template.Resources[0].Location,
|
||||
}, nil
|
||||
}
|
||||
|
@ -128,6 +152,12 @@ func (a *Artifact) String() string {
|
|||
buf.WriteString(fmt.Sprintf("OSDiskUriReadOnlySas: %s\n", a.OSDiskUriReadOnlySas))
|
||||
buf.WriteString(fmt.Sprintf("TemplateUri: %s\n", a.TemplateUri))
|
||||
buf.WriteString(fmt.Sprintf("TemplateUriReadOnlySas: %s\n", a.TemplateUriReadOnlySas))
|
||||
if a.AdditionalDisks != nil {
|
||||
for i, additionaldisk := range *a.AdditionalDisks {
|
||||
buf.WriteString(fmt.Sprintf("AdditionalDiskUri (datadisk-%d): %s\n", i+1, additionaldisk.AdditionalDiskUri))
|
||||
buf.WriteString(fmt.Sprintf("AdditionalDiskUriReadOnlySas (datadisk-%d): %s\n", i+1, additionaldisk.AdditionalDiskUriReadOnlySas))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf.String()
|
||||
|
|
|
@ -82,6 +82,60 @@ func TestArtifactString(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAdditionalDiskArtifactString(t *testing.T) {
|
||||
template := CaptureTemplate{
|
||||
Resources: []CaptureResources{
|
||||
{
|
||||
Properties: CaptureProperties{
|
||||
StorageProfile: CaptureStorageProfile{
|
||||
OSDisk: CaptureDisk{
|
||||
Image: CaptureUri{
|
||||
Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd",
|
||||
},
|
||||
},
|
||||
DataDisks: []CaptureDisk{
|
||||
CaptureDisk{
|
||||
Image: CaptureUri{
|
||||
Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Location: "southcentralus",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
artifact, err := NewArtifact(&template, getFakeSasUrl)
|
||||
if err != nil {
|
||||
t.Fatalf("err=%s", err)
|
||||
}
|
||||
|
||||
testSubject := artifact.String()
|
||||
if !strings.Contains(testSubject, "OSDiskUri: https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd") {
|
||||
t.Errorf("Expected String() output to contain OSDiskUri")
|
||||
}
|
||||
if !strings.Contains(testSubject, "OSDiskUriReadOnlySas: SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd") {
|
||||
t.Errorf("Expected String() output to contain OSDiskUriReadOnlySas")
|
||||
}
|
||||
if !strings.Contains(testSubject, "TemplateUri: https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json") {
|
||||
t.Errorf("Expected String() output to contain TemplateUri")
|
||||
}
|
||||
if !strings.Contains(testSubject, "TemplateUriReadOnlySas: SAS-Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json") {
|
||||
t.Errorf("Expected String() output to contain TemplateUriReadOnlySas")
|
||||
}
|
||||
if !strings.Contains(testSubject, "StorageAccountLocation: southcentralus") {
|
||||
t.Errorf("Expected String() output to contain StorageAccountLocation")
|
||||
}
|
||||
if !strings.Contains(testSubject, "AdditionalDiskUri (datadisk-1): https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd") {
|
||||
t.Errorf("Expected String() output to contain AdditionalDiskUri")
|
||||
}
|
||||
if !strings.Contains(testSubject, "AdditionalDiskUriReadOnlySas (datadisk-1): SAS-Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd") {
|
||||
t.Errorf("Expected String() output to contain AdditionalDiskUriReadOnlySas")
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifactProperties(t *testing.T) {
|
||||
template := CaptureTemplate{
|
||||
Resources: []CaptureResources{
|
||||
|
@ -122,6 +176,65 @@ func TestArtifactProperties(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAdditionalDiskArtifactProperties(t *testing.T) {
|
||||
template := CaptureTemplate{
|
||||
Resources: []CaptureResources{
|
||||
{
|
||||
Properties: CaptureProperties{
|
||||
StorageProfile: CaptureStorageProfile{
|
||||
OSDisk: CaptureDisk{
|
||||
Image: CaptureUri{
|
||||
Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd",
|
||||
},
|
||||
},
|
||||
DataDisks: []CaptureDisk{
|
||||
CaptureDisk{
|
||||
Image: CaptureUri{
|
||||
Uri: "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Location: "southcentralus",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
testSubject, err := NewArtifact(&template, getFakeSasUrl)
|
||||
if err != nil {
|
||||
t.Fatalf("err=%s", err)
|
||||
}
|
||||
|
||||
if testSubject.OSDiskUri != "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd" {
|
||||
t.Errorf("Expected template to be 'https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", testSubject.OSDiskUri)
|
||||
}
|
||||
if testSubject.OSDiskUriReadOnlySas != "SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd" {
|
||||
t.Errorf("Expected template to be 'SAS-Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", testSubject.OSDiskUriReadOnlySas)
|
||||
}
|
||||
if testSubject.TemplateUri != "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json" {
|
||||
t.Errorf("Expected template to be 'https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json', but got %s", testSubject.TemplateUri)
|
||||
}
|
||||
if testSubject.TemplateUriReadOnlySas != "SAS-Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json" {
|
||||
t.Errorf("Expected template to be 'SAS-Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json', but got %s", testSubject.TemplateUriReadOnlySas)
|
||||
}
|
||||
if testSubject.StorageAccountLocation != "southcentralus" {
|
||||
t.Errorf("Expected StorageAccountLocation to be 'southcentral', but got %s", testSubject.StorageAccountLocation)
|
||||
}
|
||||
if testSubject.AdditionalDisks == nil {
|
||||
t.Errorf("Expected AdditionalDisks to be not nil")
|
||||
}
|
||||
if len(*testSubject.AdditionalDisks) != 1 {
|
||||
t.Errorf("Expected AdditionalDisks to have one additional disk, but got %d", len(*testSubject.AdditionalDisks))
|
||||
}
|
||||
if (*testSubject.AdditionalDisks)[0].AdditionalDiskUri != "https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd" {
|
||||
t.Errorf("Expected additional disk uri to be 'https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", (*testSubject.AdditionalDisks)[0].AdditionalDiskUri)
|
||||
}
|
||||
if (*testSubject.AdditionalDisks)[0].AdditionalDiskUriReadOnlySas != "SAS-Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd" {
|
||||
t.Errorf("Expected additional disk sas to be 'SAS-Images/images/packer-datadisk-1.4085bb15-3644-4641-b9cd-f575918640b4.vhd', but got %s", (*testSubject.AdditionalDisks)[0].AdditionalDiskUriReadOnlySas)
|
||||
}
|
||||
}
|
||||
|
||||
func TestArtifactOverHypenatedCaptureUri(t *testing.T) {
|
||||
template := CaptureTemplate{
|
||||
Resources: []CaptureResources{
|
||||
|
|
|
@ -181,10 +181,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
},
|
||||
&packerCommon.StepProvision{},
|
||||
NewStepGetOSDisk(azureClient, ui),
|
||||
NewStepGetAdditionalDisks(azureClient, ui),
|
||||
NewStepPowerOffCompute(azureClient, ui),
|
||||
NewStepCaptureImage(azureClient, ui),
|
||||
NewStepDeleteResourceGroup(azureClient, ui),
|
||||
NewStepDeleteOSDisk(azureClient, ui),
|
||||
NewStepDeleteAdditionalDisks(azureClient, ui),
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("Builder does not support the os_type '%s'", b.config.OSType)
|
||||
|
|
|
@ -24,6 +24,7 @@ type CaptureDisk struct {
|
|||
|
||||
type CaptureStorageProfile struct {
|
||||
OSDisk CaptureDisk `json:"osDisk"`
|
||||
DataDisks []CaptureDisk `json:"dataDisks"`
|
||||
}
|
||||
|
||||
type CaptureOSProfile struct {
|
||||
|
|
|
@ -50,8 +50,34 @@ var captureTemplate01 = `{
|
|||
"vhd": {
|
||||
"uri": "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/osDisk.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd"
|
||||
},
|
||||
"caching": "ReadWrite"
|
||||
},
|
||||
"dataDisks": [
|
||||
{
|
||||
"lun": 0,
|
||||
"name": "packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd",
|
||||
"createOption": "Empty",
|
||||
"image": {
|
||||
"uri": "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd"
|
||||
},
|
||||
"vhd": {
|
||||
"uri": "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-0.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd"
|
||||
},
|
||||
"caching": "ReadWrite"
|
||||
},
|
||||
{
|
||||
"lun": 1,
|
||||
"name": "packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd",
|
||||
"createOption": "Empty",
|
||||
"image": {
|
||||
"uri": "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd"
|
||||
},
|
||||
"vhd": {
|
||||
"uri": "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-1.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd"
|
||||
},
|
||||
"caching": "ReadWrite"
|
||||
}
|
||||
]
|
||||
},
|
||||
"osProfile": {
|
||||
"computerName": "[parameters('vmName')]",
|
||||
|
@ -169,6 +195,42 @@ func TestCaptureParseJson(t *testing.T) {
|
|||
t.Errorf("Resources[0].Properties.StorageProfile.OSDisk.Caching's value was unexpected: %s", osDisk.Caching)
|
||||
}
|
||||
|
||||
// == Resources/Properties/StorageProfile/DataDisks ================
|
||||
dataDisks := testSubject.Resources[0].Properties.StorageProfile.DataDisks
|
||||
if len(dataDisks) != 2 {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.DataDisks, 2 disks expected but was: %d", len(dataDisks))
|
||||
}
|
||||
if dataDisks[0].Name != "packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Name's value was unexpected: %s", dataDisks[0].Name)
|
||||
}
|
||||
if dataDisks[0].CreateOption != "Empty" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].CreateOption's value was unexpected: %s", dataDisks[0].CreateOption)
|
||||
}
|
||||
if dataDisks[0].Image.Uri != "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-0.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Image.Uri's value was unexpected: %s", dataDisks[0].Image.Uri)
|
||||
}
|
||||
if dataDisks[0].Vhd.Uri != "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-0.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Vhd.Uri's value was unexpected: %s", dataDisks[0].Vhd.Uri)
|
||||
}
|
||||
if dataDisks[0].Caching != "ReadWrite" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[0].Caching's value was unexpected: %s", dataDisks[0].Caching)
|
||||
}
|
||||
if dataDisks[1].Name != "packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Name's value was unexpected: %s", dataDisks[1].Name)
|
||||
}
|
||||
if dataDisks[1].CreateOption != "Empty" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].CreateOption's value was unexpected: %s", dataDisks[1].CreateOption)
|
||||
}
|
||||
if dataDisks[1].Image.Uri != "http://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-datadisk-1.32118633-6dc9-449f-83b6-a7d2983bec14.vhd" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Image.Uri's value was unexpected: %s", dataDisks[1].Image.Uri)
|
||||
}
|
||||
if dataDisks[1].Vhd.Uri != "http://storage.blob.core.windows.net/vmcontainerce1a1b75-f480-47cb-8e6e-55142e4a5f68/datadisk-1.ce1a1b75-f480-47cb-8e6e-55142e4a5f68.vhd" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Vhd.Uri's value was unexpected: %s", dataDisks[1].Vhd.Uri)
|
||||
}
|
||||
if dataDisks[1].Caching != "ReadWrite" {
|
||||
t.Errorf("Resources[0].Properties.StorageProfile.dataDisks[1].Caching's value was unexpected: %s", dataDisks[1].Caching)
|
||||
}
|
||||
|
||||
// == Resources/Properties/OSProfile ============================
|
||||
osProfile := testSubject.Resources[0].Properties.OSProfile
|
||||
if osProfile.AdminPassword != "[parameters('adminPassword')]" {
|
||||
|
|
|
@ -112,6 +112,9 @@ type Config struct {
|
|||
OSType string `mapstructure:"os_type"`
|
||||
OSDiskSizeGB int32 `mapstructure:"os_disk_size_gb"`
|
||||
|
||||
// Additional Disks
|
||||
AdditionalDiskSize []int32 `mapstructure:"disk_additional_size"`
|
||||
|
||||
// Runtime Values
|
||||
UserName string
|
||||
Password string
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
package arm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
type StepDeleteAdditionalDisk struct {
|
||||
client *AzureClient
|
||||
delete func(string, string) error
|
||||
deleteManaged func(string, string) error
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
}
|
||||
|
||||
func NewStepDeleteAdditionalDisks(client *AzureClient, ui packer.Ui) *StepDeleteAdditionalDisk {
|
||||
var step = &StepDeleteAdditionalDisk{
|
||||
client: client,
|
||||
say: func(message string) { ui.Say(message) },
|
||||
error: func(e error) { ui.Error(e.Error()) },
|
||||
}
|
||||
|
||||
step.delete = step.deleteBlob
|
||||
step.deleteManaged = step.deleteManagedDisk
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepDeleteAdditionalDisk) deleteBlob(storageContainerName string, blobName string) error {
|
||||
blob := s.client.BlobStorageClient.GetContainerReference(storageContainerName).GetBlobReference(blobName)
|
||||
err := blob.Delete(nil)
|
||||
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepDeleteAdditionalDisk) deleteManagedDisk(resourceGroupName string, imageName string) error {
|
||||
xs := strings.Split(imageName, "/")
|
||||
diskName := xs[len(xs)-1]
|
||||
_, errChan := s.client.DisksClient.Delete(resourceGroupName, diskName, nil)
|
||||
err := <-errChan
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepDeleteAdditionalDisk) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Deleting the temporary Additional disk ...")
|
||||
|
||||
var dataDisks = state.Get(constants.ArmAdditionalDiskVhds).([]string)
|
||||
var isManagedDisk = state.Get(constants.ArmIsManagedImage).(bool)
|
||||
var isExistingResourceGroup = state.Get(constants.ArmIsExistingResourceGroup).(bool)
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
|
||||
if dataDisks == nil {
|
||||
s.say(fmt.Sprintf(" -> No Additional Disks specified"))
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
if isManagedDisk && !isExistingResourceGroup {
|
||||
s.say(fmt.Sprintf(" -> Additional Disk : skipping, managed disk was used..."))
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
for i, additionaldisk := range dataDisks {
|
||||
s.say(fmt.Sprintf(" -> Additional Disk %d: '%s'", i+1, additionaldisk))
|
||||
var err error
|
||||
if isManagedDisk {
|
||||
err = s.deleteManaged(resourceGroupName, additionaldisk)
|
||||
if err != nil {
|
||||
s.say("Failed to delete the managed Additional Disk!")
|
||||
return processStepResult(err, s.error, state)
|
||||
}
|
||||
} else {
|
||||
u, err := url.Parse(additionaldisk)
|
||||
if err != nil {
|
||||
s.say("Failed to parse the Additional Disk's VHD URI!")
|
||||
return processStepResult(err, s.error, state)
|
||||
}
|
||||
|
||||
xs := strings.Split(u.Path, "/")
|
||||
if len(xs) < 3 {
|
||||
err = errors.New("Failed to parse Additional Disk's VHD URI!")
|
||||
} else {
|
||||
var storageAccountName = xs[1]
|
||||
var blobName = strings.Join(xs[2:], "/")
|
||||
|
||||
err = s.delete(storageAccountName, blobName)
|
||||
}
|
||||
if err != nil {
|
||||
return processStepResult(err, s.error, state)
|
||||
}
|
||||
}
|
||||
}
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (*StepDeleteAdditionalDisk) Cleanup(multistep.StateBag) {
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
package arm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
)
|
||||
|
||||
func TestStepDeleteAdditionalDiskShouldFailIfGetFails(t *testing.T) {
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(string, string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://storage.blob.core.windows.net/images/pkrvm_os.vhd"})
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok == false {
|
||||
t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepDeleteAdditionalDiskShouldPassIfGetPasses(t *testing.T) {
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://storage.blob.core.windows.net/images/pkrvm_os.vhd"})
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepDeleteAdditionalDiskShouldTakeStepArgumentsFromStateBag(t *testing.T) {
|
||||
var actualStorageContainerName string
|
||||
var actualBlobName string
|
||||
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(storageContainerName string, blobName string) error {
|
||||
actualStorageContainerName = storageContainerName
|
||||
actualBlobName = blobName
|
||||
return nil
|
||||
},
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://storage.blob.core.windows.net/images/pkrvm_os.vhd"})
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if actualStorageContainerName != "images" {
|
||||
t.Fatalf("Expected the storage container name to be 'images', but found '%s'.", actualStorageContainerName)
|
||||
}
|
||||
|
||||
if actualBlobName != "pkrvm_os.vhd" {
|
||||
t.Fatalf("Expected the blob name to be 'pkrvm_os.vhd', but found '%s'.", actualBlobName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepDeleteAdditionalDiskShouldHandleComplexStorageContainerNames(t *testing.T) {
|
||||
var actualStorageContainerName string
|
||||
var actualBlobName string
|
||||
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(storageContainerName string, blobName string) error {
|
||||
actualStorageContainerName = storageContainerName
|
||||
actualBlobName = blobName
|
||||
return nil
|
||||
},
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://storage.blob.core.windows.net/abc/def/pkrvm_os.vhd"})
|
||||
testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if actualStorageContainerName != "abc" {
|
||||
t.Fatalf("Expected the storage container name to be 'abc/def', but found '%s'.", actualStorageContainerName)
|
||||
}
|
||||
|
||||
if actualBlobName != "def/pkrvm_os.vhd" {
|
||||
t.Fatalf("Expected the blob name to be 'pkrvm_os.vhd', but found '%s'.", actualBlobName)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepDeleteAdditionalDiskShouldFailIfVHDNameCannotBeURLParsed(t *testing.T) {
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
}
|
||||
|
||||
// Invalid URL per https://golang.org/src/net/url/url_test.go
|
||||
stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"http://[fe80::1%en0]/"})
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%v'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok == false {
|
||||
t.Fatalf("Expected the step to not stateBag['%s'], but it was.", constants.Error)
|
||||
}
|
||||
}
|
||||
func TestStepDeleteAdditionalDiskShouldFailIfVHDNameIsTooShort(t *testing.T) {
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
}
|
||||
|
||||
stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"storage.blob.core.windows.net/abc"})
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok == false {
|
||||
t.Fatalf("Expected the step to not stateBag['%s'], but it was.", constants.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepDeleteAdditionalDiskShouldPassIfManagedDiskInTempResourceGroup(t *testing.T) {
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
stateBag.Put(constants.ArmAdditionalDiskVhds, []string{"subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk"})
|
||||
stateBag.Put(constants.ArmIsManagedImage, true)
|
||||
stateBag.Put(constants.ArmIsExistingResourceGroup, false)
|
||||
stateBag.Put(constants.ArmResourceGroupName, "testgroup")
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepDeleteAdditionalDiskShouldFailIfManagedDiskInExistingResourceGroupFailsToDelete(t *testing.T) {
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(string, string) error { return errors.New("UNIT TEST FAIL!") },
|
||||
}
|
||||
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
stateBag.Put(constants.ArmAdditionalDiskVhds, []string{"subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk"})
|
||||
stateBag.Put(constants.ArmIsManagedImage, true)
|
||||
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
|
||||
stateBag.Put(constants.ArmResourceGroupName, "testgroup")
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok == false {
|
||||
t.Fatalf("Expected the step to not stateBag['%s'], but it was.", constants.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepDeleteAdditionalDiskShouldFailIfManagedDiskInExistingResourceGroupIsDeleted(t *testing.T) {
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
}
|
||||
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
stateBag.Put(constants.ArmAdditionalDiskVhds, []string{"subscriptions/123-456-789/resourceGroups/existingresourcegroup/providers/Microsoft.Compute/disks/osdisk"})
|
||||
stateBag.Put(constants.ArmIsManagedImage, true)
|
||||
stateBag.Put(constants.ArmIsExistingResourceGroup, true)
|
||||
stateBag.Put(constants.ArmResourceGroupName, "testgroup")
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func DeleteTestStateBagStepDeleteAdditionalDisk(osDiskVhds []string) multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
stateBag.Put(constants.ArmAdditionalDiskVhds, osDiskVhds)
|
||||
stateBag.Put(constants.ArmIsManagedImage, false)
|
||||
stateBag.Put(constants.ArmIsExistingResourceGroup, false)
|
||||
stateBag.Put(constants.ArmResourceGroupName, "testgroup")
|
||||
|
||||
return stateBag
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package arm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
type StepGetDataDisk struct {
|
||||
client *AzureClient
|
||||
query func(resourceGroupName string, computeName string) (compute.VirtualMachine, error)
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
}
|
||||
|
||||
func NewStepGetAdditionalDisks(client *AzureClient, ui packer.Ui) *StepGetDataDisk {
|
||||
var step = &StepGetDataDisk{
|
||||
client: client,
|
||||
say: func(message string) { ui.Say(message) },
|
||||
error: func(e error) { ui.Error(e.Error()) },
|
||||
}
|
||||
|
||||
step.query = step.queryCompute
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepGetDataDisk) queryCompute(resourceGroupName string, computeName string) (compute.VirtualMachine, error) {
|
||||
vm, err := s.client.VirtualMachinesClient.Get(resourceGroupName, computeName, "")
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
}
|
||||
return vm, err
|
||||
}
|
||||
|
||||
func (s *StepGetDataDisk) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Querying the machine's additional disks properties ...")
|
||||
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
var computeName = state.Get(constants.ArmComputeName).(string)
|
||||
|
||||
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
|
||||
s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName))
|
||||
|
||||
vm, err := s.query(resourceGroupName, computeName)
|
||||
if err != nil {
|
||||
state.Put(constants.Error, err)
|
||||
s.error(err)
|
||||
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if vm.StorageProfile.DataDisks != nil {
|
||||
var vhdUri string
|
||||
additional_disks := make([]string, len(*vm.StorageProfile.DataDisks))
|
||||
for i, additionaldisk := range *vm.StorageProfile.DataDisks {
|
||||
if additionaldisk.Vhd != nil {
|
||||
vhdUri = *additionaldisk.Vhd.URI
|
||||
s.say(fmt.Sprintf(" -> Additional Disk %d : '%s'", i+1, vhdUri))
|
||||
} else {
|
||||
vhdUri = *additionaldisk.ManagedDisk.ID
|
||||
s.say(fmt.Sprintf(" -> Managed Additional Disk %d : '%s'", i+1, vhdUri))
|
||||
}
|
||||
additional_disks[i] = vhdUri
|
||||
}
|
||||
state.Put(constants.ArmAdditionalDiskVhds, additional_disks)
|
||||
}
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (*StepGetDataDisk) Cleanup(multistep.StateBag) {
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
package arm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
)
|
||||
|
||||
func TestStepGetAdditionalDiskShouldFailIfGetFails(t *testing.T) {
|
||||
var testSubject = &StepGetDataDisk{
|
||||
query: func(string, string) (compute.VirtualMachine, error) {
|
||||
return createVirtualMachineWithDataDisksFromUri("test.vhd"), fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepGetAdditionalDisks()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionHalt {
|
||||
t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok == false {
|
||||
t.Fatalf("Expected the step to set stateBag['%s'], but it was not.", constants.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepGetAdditionalDiskShouldPassIfGetPasses(t *testing.T) {
|
||||
var testSubject = &StepGetDataDisk{
|
||||
query: func(string, string) (compute.VirtualMachine, error) {
|
||||
return createVirtualMachineWithDataDisksFromUri("test.vhd"), nil
|
||||
},
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepGetAdditionalDisks()
|
||||
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok == true {
|
||||
t.Fatalf("Expected the step to not set stateBag['%s'], but it was.", constants.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStepGetAdditionalDiskShouldTakeValidateArgumentsFromStateBag(t *testing.T) {
|
||||
var actualResourceGroupName string
|
||||
var actualComputeName string
|
||||
|
||||
var testSubject = &StepGetDataDisk{
|
||||
query: func(resourceGroupName string, computeName string) (compute.VirtualMachine, error) {
|
||||
actualResourceGroupName = resourceGroupName
|
||||
actualComputeName = computeName
|
||||
|
||||
return createVirtualMachineWithDataDisksFromUri("test.vhd"), nil
|
||||
},
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepGetAdditionalDisks()
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
|
||||
if result != multistep.ActionContinue {
|
||||
t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result)
|
||||
}
|
||||
|
||||
var expectedComputeName = stateBag.Get(constants.ArmComputeName).(string)
|
||||
var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string)
|
||||
|
||||
if actualComputeName != expectedComputeName {
|
||||
t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.")
|
||||
}
|
||||
|
||||
if actualResourceGroupName != expectedResourceGroupName {
|
||||
t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.")
|
||||
}
|
||||
|
||||
expectedAdditionalDiskVhds, ok := stateBag.GetOk(constants.ArmAdditionalDiskVhds)
|
||||
if !ok {
|
||||
t.Fatalf("Expected the state bag to have a value for '%s', but it did not.", constants.ArmAdditionalDiskVhds)
|
||||
}
|
||||
|
||||
expectedAdditionalDiskVhd := expectedAdditionalDiskVhds.([]string)
|
||||
if expectedAdditionalDiskVhd[0] != "test.vhd" {
|
||||
t.Fatalf("Expected the value of stateBag[%s] to be 'test.vhd', but got '%s'.", constants.ArmAdditionalDiskVhds, expectedAdditionalDiskVhd[0])
|
||||
}
|
||||
}
|
||||
|
||||
func createTestStateBagStepGetAdditionalDisks() multistep.StateBag {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
stateBag.Put(constants.ArmComputeName, "Unit Test: ComputeName")
|
||||
stateBag.Put(constants.ArmResourceGroupName, "Unit Test: ResourceGroupName")
|
||||
|
||||
return stateBag
|
||||
}
|
||||
|
||||
func createVirtualMachineWithDataDisksFromUri(vhdUri string) compute.VirtualMachine {
|
||||
vm := compute.VirtualMachine{
|
||||
VirtualMachineProperties: &compute.VirtualMachineProperties{
|
||||
StorageProfile: &compute.StorageProfile{
|
||||
OsDisk: &compute.OSDisk{
|
||||
Vhd: &compute.VirtualHardDisk{
|
||||
URI: &vhdUri,
|
||||
},
|
||||
},
|
||||
DataDisks: &[]compute.DataDisk{
|
||||
compute.DataDisk{
|
||||
Vhd: &compute.VirtualHardDisk{
|
||||
URI: &vhdUri,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
return vm
|
||||
}
|
|
@ -73,6 +73,10 @@ func GetVirtualMachineDeployment(config *Config) (*resources.Deployment, error)
|
|||
builder.SetOSDiskSizeGB(config.OSDiskSizeGB)
|
||||
}
|
||||
|
||||
if len(config.AdditionalDiskSize) > 0 {
|
||||
builder.SetAdditionalDisks(config.AdditionalDiskSize, config.CustomManagedImageName != "" || (config.ManagedImageName != "" && config.ImagePublisher != ""))
|
||||
}
|
||||
|
||||
if config.customData != "" {
|
||||
builder.SetCustomData(config.customData)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
{
|
||||
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"adminPassword": {
|
||||
"type": "string"
|
||||
},
|
||||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"osDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"storageAccountBlobEndpoint": {
|
||||
"type": "string"
|
||||
},
|
||||
"vmName": {
|
||||
"type": "string"
|
||||
},
|
||||
"vmSize": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "[variables('publicIPAddressApiVersion')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('publicIPAddressName')]",
|
||||
"properties": {
|
||||
"dnsSettings": {
|
||||
"domainNameLabel": "[parameters('dnsNameForPublicIP')]"
|
||||
},
|
||||
"publicIPAllocationMethod": "[variables('publicIPAddressType')]"
|
||||
},
|
||||
"type": "Microsoft.Network/publicIPAddresses"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('virtualNetworksApiVersion')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('virtualNetworkName')]",
|
||||
"properties": {
|
||||
"addressSpace": {
|
||||
"addressPrefixes": [
|
||||
"[variables('addressPrefix')]"
|
||||
]
|
||||
},
|
||||
"subnets": [
|
||||
{
|
||||
"name": "[variables('subnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('subnetAddressPrefix')]"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('networkInterfacesApiVersion')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
|
||||
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('nicName')]",
|
||||
"properties": {
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"name": "ipconfig",
|
||||
"properties": {
|
||||
"privateIPAllocationMethod": "Dynamic",
|
||||
"publicIPAddress": {
|
||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]"
|
||||
},
|
||||
"subnet": {
|
||||
"id": "[variables('subnetRef')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersion')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[parameters('vmName')]",
|
||||
"properties": {
|
||||
"diagnosticsProfile": {
|
||||
"bootDiagnostics": {
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"hardwareProfile": {
|
||||
"vmSize": "[parameters('vmSize')]"
|
||||
},
|
||||
"networkProfile": {
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"osProfile": {
|
||||
"adminPassword": "[parameters('adminPassword')]",
|
||||
"adminUsername": "[parameters('adminUsername')]",
|
||||
"computerName": "[parameters('vmName')]",
|
||||
"linuxConfiguration": {
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "",
|
||||
"path": "[variables('sshKeyPath')]"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storageProfile": {
|
||||
"dataDisks": [
|
||||
{
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "Empty",
|
||||
"diskSizeGB": 32,
|
||||
"lun": 0,
|
||||
"name": "datadisk-1",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/datadisk-', '1','.vhd')]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"imageReference": {
|
||||
"offer": "--image-offer--",
|
||||
"publisher": "--image-publisher--",
|
||||
"sku": "--image-sku--",
|
||||
"version": "--version--"
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Compute/virtualMachines"
|
||||
}
|
||||
],
|
||||
"variables": {
|
||||
"addressPrefix": "10.0.0.0/16",
|
||||
"apiVersion": "2017-03-30",
|
||||
"location": "[resourceGroup().location]",
|
||||
"managedDiskApiVersion": "2017-03-30",
|
||||
"networkInterfacesApiVersion": "2017-04-01",
|
||||
"nicName": "packerNic",
|
||||
"publicIPAddressApiVersion": "2017-04-01",
|
||||
"publicIPAddressName": "packerPublicIP",
|
||||
"publicIPAddressType": "Dynamic",
|
||||
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",
|
||||
"subnetAddressPrefix": "10.0.0.0/24",
|
||||
"subnetName": "packerSubnet",
|
||||
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
|
||||
"virtualNetworkName": "packerNetwork",
|
||||
"virtualNetworkResourceGroup": "[resourceGroup().name]",
|
||||
"virtualNetworksApiVersion": "2017-04-01",
|
||||
"vmStorageAccountContainerName": "images",
|
||||
"vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,178 @@
|
|||
{
|
||||
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"adminPassword": {
|
||||
"type": "string"
|
||||
},
|
||||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"osDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"storageAccountBlobEndpoint": {
|
||||
"type": "string"
|
||||
},
|
||||
"vmName": {
|
||||
"type": "string"
|
||||
},
|
||||
"vmSize": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "[variables('publicIPAddressApiVersion')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('publicIPAddressName')]",
|
||||
"properties": {
|
||||
"dnsSettings": {
|
||||
"domainNameLabel": "[parameters('dnsNameForPublicIP')]"
|
||||
},
|
||||
"publicIPAllocationMethod": "[variables('publicIPAddressType')]"
|
||||
},
|
||||
"type": "Microsoft.Network/publicIPAddresses"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('virtualNetworksApiVersion')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('virtualNetworkName')]",
|
||||
"properties": {
|
||||
"addressSpace": {
|
||||
"addressPrefixes": [
|
||||
"[variables('addressPrefix')]"
|
||||
]
|
||||
},
|
||||
"subnets": [
|
||||
{
|
||||
"name": "[variables('subnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('subnetAddressPrefix')]"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('networkInterfacesApiVersion')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
|
||||
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('nicName')]",
|
||||
"properties": {
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"name": "ipconfig",
|
||||
"properties": {
|
||||
"privateIPAllocationMethod": "Dynamic",
|
||||
"publicIPAddress": {
|
||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]"
|
||||
},
|
||||
"subnet": {
|
||||
"id": "[variables('subnetRef')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersion')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[parameters('vmName')]",
|
||||
"properties": {
|
||||
"diagnosticsProfile": {
|
||||
"bootDiagnostics": {
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"hardwareProfile": {
|
||||
"vmSize": "[parameters('vmSize')]"
|
||||
},
|
||||
"networkProfile": {
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"osProfile": {
|
||||
"adminPassword": "[parameters('adminPassword')]",
|
||||
"adminUsername": "[parameters('adminUsername')]",
|
||||
"computerName": "[parameters('vmName')]",
|
||||
"linuxConfiguration": {
|
||||
"ssh": {
|
||||
"publicKeys": [
|
||||
{
|
||||
"keyData": "",
|
||||
"path": "[variables('sshKeyPath')]"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storageProfile": {
|
||||
"dataDisks": [
|
||||
{
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "Empty",
|
||||
"diskSizeGB": 32,
|
||||
"lun": 0,
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"name": "datadisk-1"
|
||||
}
|
||||
],
|
||||
"imageReference": {
|
||||
"offer": "--image-offer--",
|
||||
"publisher": "--image-publisher--",
|
||||
"sku": "--image-sku--",
|
||||
"version": "--version--"
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "fromImage",
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"name": "osdisk",
|
||||
"osType": "Linux"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Compute/virtualMachines"
|
||||
}
|
||||
],
|
||||
"variables": {
|
||||
"addressPrefix": "10.0.0.0/16",
|
||||
"apiVersion": "2017-03-30",
|
||||
"location": "[resourceGroup().location]",
|
||||
"managedDiskApiVersion": "2017-03-30",
|
||||
"networkInterfacesApiVersion": "2017-04-01",
|
||||
"nicName": "packerNic",
|
||||
"publicIPAddressApiVersion": "2017-04-01",
|
||||
"publicIPAddressName": "packerPublicIP",
|
||||
"publicIPAddressType": "Dynamic",
|
||||
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",
|
||||
"subnetAddressPrefix": "10.0.0.0/24",
|
||||
"subnetName": "packerSubnet",
|
||||
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
|
||||
"virtualNetworkName": "packerNetwork",
|
||||
"virtualNetworkResourceGroup": "[resourceGroup().name]",
|
||||
"virtualNetworksApiVersion": "2017-04-01",
|
||||
"vmStorageAccountContainerName": "images",
|
||||
"vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
|
||||
}
|
||||
}
|
|
@ -355,6 +355,76 @@ func TestVirtualMachineDeployment10(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Ensure the VM template is correct when building with additional unmanaged disks
|
||||
func TestVirtualMachineDeployment11(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"location": "ignore",
|
||||
"subscription_id": "ignore",
|
||||
"os_type": constants.Target_Linux,
|
||||
"communicator": "none",
|
||||
"image_publisher": "--image-publisher--",
|
||||
"image_offer": "--image-offer--",
|
||||
"image_sku": "--image-sku--",
|
||||
"image_version": "--version--",
|
||||
|
||||
"disk_additional_size": []uint{32},
|
||||
|
||||
"resource_group_name": "packergroup",
|
||||
"storage_account": "packerartifacts",
|
||||
"capture_name_prefix": "packer",
|
||||
"capture_container_name": "packerimages",
|
||||
}
|
||||
|
||||
c, _, err := newConfig(config, getPackerConfiguration())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deployment, err := GetVirtualMachineDeployment(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the VM template is correct when building with additional managed disks
|
||||
func TestVirtualMachineDeployment12(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"location": "ignore",
|
||||
"subscription_id": "ignore",
|
||||
"os_type": constants.Target_Linux,
|
||||
"communicator": "none",
|
||||
"image_publisher": "--image-publisher--",
|
||||
"image_offer": "--image-offer--",
|
||||
"image_sku": "--image-sku--",
|
||||
"image_version": "--version--",
|
||||
|
||||
"disk_additional_size": []uint{32},
|
||||
|
||||
"managed_image_name": "ManagedImageName",
|
||||
"managed_image_resource_group_name": "ManagedImageResourceGroupName",
|
||||
}
|
||||
|
||||
c, _, err := newConfig(config, getPackerConfiguration())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deployment, err := GetVirtualMachineDeployment(c)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = approvaltests.VerifyJSONStruct(t, deployment.Properties.Template)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure the link values are not set, and the concrete values are set.
|
||||
func TestKeyVaultDeployment00(t *testing.T) {
|
||||
c, _, _ := newConfig(getArmBuilderConfiguration(), getPackerConfiguration())
|
||||
|
|
|
@ -21,6 +21,7 @@ const (
|
|||
ArmKeyVaultName string = "arm.KeyVaultName"
|
||||
ArmLocation string = "arm.Location"
|
||||
ArmOSDiskVhd string = "arm.OSDiskVhd"
|
||||
ArmAdditionalDiskVhds string = "arm.AdditionalDiskVhds"
|
||||
ArmPublicIPAddressName string = "arm.PublicIPAddressName"
|
||||
ArmResourceGroupName string = "arm.ResourceGroupName"
|
||||
ArmIsResourceGroupCreated string = "arm.IsResourceGroupCreated"
|
||||
|
|
|
@ -48,10 +48,23 @@ type OSDiskUnion struct {
|
|||
ManagedDisk *compute.ManagedDiskParameters `json:"managedDisk,omitempty"`
|
||||
}
|
||||
|
||||
type DataDiskUnion struct {
|
||||
Lun *int `json:"lun,omitempty"`
|
||||
BlobURI *string `json:"blobUri,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Vhd *compute.VirtualHardDisk `json:"vhd,omitempty"`
|
||||
Image *compute.VirtualHardDisk `json:"image,omitempty"`
|
||||
Caching compute.CachingTypes `json:"caching,omitempty"`
|
||||
CreateOption compute.DiskCreateOptionTypes `json:"createOption,omitempty"`
|
||||
DiskSizeGB *int32 `json:"diskSizeGB,omitempty"`
|
||||
ManagedDisk *compute.ManagedDiskParameters `json:"managedDisk,omitempty"`
|
||||
}
|
||||
|
||||
// Union of the StorageProfile and ImageStorageProfile types.
|
||||
type StorageProfileUnion struct {
|
||||
ImageReference *compute.ImageReference `json:"imageReference,omitempty"`
|
||||
OsDisk *OSDiskUnion `json:"osDisk,omitempty"`
|
||||
DataDisks *[]DataDiskUnion `json:"dataDisks,omitempty"`
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
|
|
@ -191,6 +191,35 @@ func (s *TemplateBuilder) SetOSDiskSizeGB(diskSizeGB int32) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *TemplateBuilder) SetAdditionalDisks(diskSizeGB []int32, isManaged bool) error {
|
||||
resource, err := s.getResourceByType(resourceVirtualMachine)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
profile := resource.Properties.StorageProfile
|
||||
dataDisks := make([]DataDiskUnion, len(diskSizeGB))
|
||||
|
||||
for i, additionalsize := range diskSizeGB {
|
||||
dataDisks[i].DiskSizeGB = to.Int32Ptr(additionalsize)
|
||||
dataDisks[i].Lun = to.IntPtr(i)
|
||||
dataDisks[i].Name = to.StringPtr(fmt.Sprintf("datadisk-%d", i+1))
|
||||
dataDisks[i].CreateOption = "Empty"
|
||||
dataDisks[i].Caching = "ReadWrite"
|
||||
if isManaged {
|
||||
dataDisks[i].Vhd = nil
|
||||
dataDisks[i].ManagedDisk = profile.OsDisk.ManagedDisk
|
||||
} else {
|
||||
dataDisks[i].Vhd = &compute.VirtualHardDisk{
|
||||
URI: to.StringPtr(fmt.Sprintf("[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/datadisk-', '%d','.vhd')]", i+1)),
|
||||
}
|
||||
dataDisks[i].ManagedDisk = nil
|
||||
}
|
||||
}
|
||||
profile.DataDisks = &dataDisks
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *TemplateBuilder) SetCustomData(customData string) error {
|
||||
resource, err := s.getResourceByType(resourceVirtualMachine)
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
{
|
||||
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"adminPassword": {
|
||||
"type": "string"
|
||||
},
|
||||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"osDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"storageAccountBlobEndpoint": {
|
||||
"type": "string"
|
||||
},
|
||||
"vmName": {
|
||||
"type": "string"
|
||||
},
|
||||
"vmSize": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "[variables('publicIPAddressApiVersion')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('publicIPAddressName')]",
|
||||
"properties": {
|
||||
"dnsSettings": {
|
||||
"domainNameLabel": "[parameters('dnsNameForPublicIP')]"
|
||||
},
|
||||
"publicIPAllocationMethod": "[variables('publicIPAddressType')]"
|
||||
},
|
||||
"type": "Microsoft.Network/publicIPAddresses"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('virtualNetworksApiVersion')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('virtualNetworkName')]",
|
||||
"properties": {
|
||||
"addressSpace": {
|
||||
"addressPrefixes": [
|
||||
"[variables('addressPrefix')]"
|
||||
]
|
||||
},
|
||||
"subnets": [
|
||||
{
|
||||
"name": "[variables('subnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('subnetAddressPrefix')]"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('networkInterfacesApiVersion')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
|
||||
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('nicName')]",
|
||||
"properties": {
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"name": "ipconfig",
|
||||
"properties": {
|
||||
"privateIPAllocationMethod": "Dynamic",
|
||||
"publicIPAddress": {
|
||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]"
|
||||
},
|
||||
"subnet": {
|
||||
"id": "[variables('subnetRef')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersion')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[parameters('vmName')]",
|
||||
"properties": {
|
||||
"diagnosticsProfile": {
|
||||
"bootDiagnostics": {
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"hardwareProfile": {
|
||||
"vmSize": "[parameters('vmSize')]"
|
||||
},
|
||||
"networkProfile": {
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"osProfile": {
|
||||
"adminPassword": "[parameters('adminPassword')]",
|
||||
"adminUsername": "[parameters('adminUsername')]",
|
||||
"computerName": "[parameters('vmName')]",
|
||||
"secrets": [
|
||||
{
|
||||
"sourceVault": {
|
||||
"id": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults', '--test-key-vault-name')]"
|
||||
},
|
||||
"vaultCertificates": [
|
||||
{
|
||||
"certificateStore": "My",
|
||||
"certificateUrl": "--test-winrm-certificate-url--"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"windowsConfiguration": {
|
||||
"provisionVMAgent": true,
|
||||
"winRM": {
|
||||
"listeners": [
|
||||
{
|
||||
"certificateUrl": "--test-winrm-certificate-url--",
|
||||
"protocol": "https"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storageProfile": {
|
||||
"dataDisks": [
|
||||
{
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "Empty",
|
||||
"diskSizeGB": 32,
|
||||
"lun": 0,
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"name": "datadisk-1"
|
||||
},
|
||||
{
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "Empty",
|
||||
"diskSizeGB": 64,
|
||||
"lun": 1,
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"name": "datadisk-2"
|
||||
}
|
||||
],
|
||||
"imageReference": {
|
||||
"offer": "2012-R2-Datacenter",
|
||||
"publisher": "WindowsServer",
|
||||
"sku": "latest",
|
||||
"version": "2015-1"
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "fromImage",
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"name": "osdisk",
|
||||
"osType": "Windows"
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Compute/virtualMachines"
|
||||
}
|
||||
],
|
||||
"variables": {
|
||||
"addressPrefix": "10.0.0.0/16",
|
||||
"apiVersion": "2017-03-30",
|
||||
"location": "[resourceGroup().location]",
|
||||
"managedDiskApiVersion": "2017-03-30",
|
||||
"networkInterfacesApiVersion": "2017-04-01",
|
||||
"nicName": "packerNic",
|
||||
"publicIPAddressApiVersion": "2017-04-01",
|
||||
"publicIPAddressName": "packerPublicIP",
|
||||
"publicIPAddressType": "Dynamic",
|
||||
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",
|
||||
"subnetAddressPrefix": "10.0.0.0/24",
|
||||
"subnetName": "packerSubnet",
|
||||
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
|
||||
"virtualNetworkName": "packerNetwork",
|
||||
"virtualNetworkResourceGroup": "[resourceGroup().name]",
|
||||
"virtualNetworksApiVersion": "2017-04-01",
|
||||
"vmStorageAccountContainerName": "images",
|
||||
"vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
{
|
||||
"$schema": "http://schema.management.azure.com/schemas/2014-04-01-preview/deploymentTemplate.json",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"adminPassword": {
|
||||
"type": "string"
|
||||
},
|
||||
"adminUsername": {
|
||||
"type": "string"
|
||||
},
|
||||
"dnsNameForPublicIP": {
|
||||
"type": "string"
|
||||
},
|
||||
"osDiskName": {
|
||||
"type": "string"
|
||||
},
|
||||
"storageAccountBlobEndpoint": {
|
||||
"type": "string"
|
||||
},
|
||||
"vmName": {
|
||||
"type": "string"
|
||||
},
|
||||
"vmSize": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"resources": [
|
||||
{
|
||||
"apiVersion": "[variables('publicIPAddressApiVersion')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('publicIPAddressName')]",
|
||||
"properties": {
|
||||
"dnsSettings": {
|
||||
"domainNameLabel": "[parameters('dnsNameForPublicIP')]"
|
||||
},
|
||||
"publicIPAllocationMethod": "[variables('publicIPAddressType')]"
|
||||
},
|
||||
"type": "Microsoft.Network/publicIPAddresses"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('virtualNetworksApiVersion')]",
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('virtualNetworkName')]",
|
||||
"properties": {
|
||||
"addressSpace": {
|
||||
"addressPrefixes": [
|
||||
"[variables('addressPrefix')]"
|
||||
]
|
||||
},
|
||||
"subnets": [
|
||||
{
|
||||
"name": "[variables('subnetName')]",
|
||||
"properties": {
|
||||
"addressPrefix": "[variables('subnetAddressPrefix')]"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/virtualNetworks"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('networkInterfacesApiVersion')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('publicIPAddressName'))]",
|
||||
"[concat('Microsoft.Network/virtualNetworks/', variables('virtualNetworkName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[variables('nicName')]",
|
||||
"properties": {
|
||||
"ipConfigurations": [
|
||||
{
|
||||
"name": "ipconfig",
|
||||
"properties": {
|
||||
"privateIPAllocationMethod": "Dynamic",
|
||||
"publicIPAddress": {
|
||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses', variables('publicIPAddressName'))]"
|
||||
},
|
||||
"subnet": {
|
||||
"id": "[variables('subnetRef')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"type": "Microsoft.Network/networkInterfaces"
|
||||
},
|
||||
{
|
||||
"apiVersion": "[variables('apiVersion')]",
|
||||
"dependsOn": [
|
||||
"[concat('Microsoft.Network/networkInterfaces/', variables('nicName'))]"
|
||||
],
|
||||
"location": "[variables('location')]",
|
||||
"name": "[parameters('vmName')]",
|
||||
"properties": {
|
||||
"diagnosticsProfile": {
|
||||
"bootDiagnostics": {
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"hardwareProfile": {
|
||||
"vmSize": "[parameters('vmSize')]"
|
||||
},
|
||||
"networkProfile": {
|
||||
"networkInterfaces": [
|
||||
{
|
||||
"id": "[resourceId('Microsoft.Network/networkInterfaces', variables('nicName'))]"
|
||||
}
|
||||
]
|
||||
},
|
||||
"osProfile": {
|
||||
"adminPassword": "[parameters('adminPassword')]",
|
||||
"adminUsername": "[parameters('adminUsername')]",
|
||||
"computerName": "[parameters('vmName')]",
|
||||
"secrets": [
|
||||
{
|
||||
"sourceVault": {
|
||||
"id": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults', '--test-key-vault-name')]"
|
||||
},
|
||||
"vaultCertificates": [
|
||||
{
|
||||
"certificateStore": "My",
|
||||
"certificateUrl": "--test-winrm-certificate-url--"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"windowsConfiguration": {
|
||||
"provisionVMAgent": true,
|
||||
"winRM": {
|
||||
"listeners": [
|
||||
{
|
||||
"certificateUrl": "--test-winrm-certificate-url--",
|
||||
"protocol": "https"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storageProfile": {
|
||||
"dataDisks": [
|
||||
{
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "Empty",
|
||||
"diskSizeGB": 32,
|
||||
"lun": 0,
|
||||
"name": "datadisk-1",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/datadisk-', '1','.vhd')]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "Empty",
|
||||
"diskSizeGB": 64,
|
||||
"lun": 1,
|
||||
"name": "datadisk-2",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/datadisk-', '2','.vhd')]"
|
||||
}
|
||||
}
|
||||
],
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "Microsoft.Compute/virtualMachines"
|
||||
}
|
||||
],
|
||||
"variables": {
|
||||
"addressPrefix": "10.0.0.0/16",
|
||||
"apiVersion": "2017-03-30",
|
||||
"location": "[resourceGroup().location]",
|
||||
"managedDiskApiVersion": "2017-03-30",
|
||||
"networkInterfacesApiVersion": "2017-04-01",
|
||||
"nicName": "packerNic",
|
||||
"publicIPAddressApiVersion": "2017-04-01",
|
||||
"publicIPAddressName": "packerPublicIP",
|
||||
"publicIPAddressType": "Dynamic",
|
||||
"sshKeyPath": "[concat('/home/',parameters('adminUsername'),'/.ssh/authorized_keys')]",
|
||||
"subnetAddressPrefix": "10.0.0.0/24",
|
||||
"subnetName": "packerSubnet",
|
||||
"subnetRef": "[concat(variables('vnetID'),'/subnets/',variables('subnetName'))]",
|
||||
"virtualNetworkName": "packerNetwork",
|
||||
"virtualNetworkResourceGroup": "[resourceGroup().name]",
|
||||
"virtualNetworksApiVersion": "2017-04-01",
|
||||
"vmStorageAccountContainerName": "images",
|
||||
"vnetID": "[resourceId(variables('virtualNetworkResourceGroup'), 'Microsoft.Network/virtualNetworks', variables('virtualNetworkName'))]"
|
||||
}
|
||||
}
|
|
@ -120,3 +120,64 @@ func TestBuildWindows00(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Windows build with additional disk for an managed build
|
||||
func TestBuildWindows01(t *testing.T) {
|
||||
testSubject, err := NewTemplateBuilder(BasicTemplate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = testSubject.BuildWindows("--test-key-vault-name", "--test-winrm-certificate-url--")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = testSubject.SetManagedMarketplaceImage("MicrosoftWindowsServer", "WindowsServer", "2012-R2-Datacenter", "latest", "2015-1", "1", "Premium_LRS")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = testSubject.SetAdditionalDisks([]int32{32, 64}, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
doc, err := testSubject.ToJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = approvaltests.VerifyJSONBytes(t, []byte(*doc))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Windows build with additional disk for an unmanaged build
|
||||
func TestBuildWindows02(t *testing.T) {
|
||||
testSubject, err := NewTemplateBuilder(BasicTemplate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = testSubject.BuildWindows("--test-key-vault-name", "--test-winrm-certificate-url--")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = testSubject.SetAdditionalDisks([]int32{32, 64}, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
doc, err := testSubject.ToJSON()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = approvaltests.VerifyJSONBytes(t, []byte(*doc))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,6 +149,10 @@ Providing `temp_resource_group_name` or `location` in combination with `build_re
|
|||
- `os_disk_size_gb` (number) Specify the size of the OS disk in GB (gigabytes). Values of zero or less than zero are
|
||||
ignored.
|
||||
|
||||
- `disk_additional_size` (array of integers) - The size(s) of any additional
|
||||
hard disks for the VM in gigabytes. If this is not specified then the VM
|
||||
will only contain an OS disk.
|
||||
|
||||
- `os_type` (string) If either `Linux` or `Windows` is specified Packer will
|
||||
automatically configure authentication credentials for the provisioned machine. For
|
||||
`Linux` this configures an SSH authorized key. For `Windows` this
|
||||
|
|
Loading…
Reference in New Issue