Add to vagrant post-processor support for Azure
This commit is contained in:
parent
0633189c98
commit
d796edc783
|
@ -18,6 +18,9 @@ type AdditionalDiskArtifact struct {
|
|||
}
|
||||
|
||||
type Artifact struct {
|
||||
// OS type: Linux, Windows
|
||||
OSType string
|
||||
|
||||
// VHD
|
||||
StorageAccountLocation string
|
||||
OSDiskUri string
|
||||
|
@ -29,20 +32,23 @@ type Artifact struct {
|
|||
ManagedImageResourceGroupName string
|
||||
ManagedImageName string
|
||||
ManagedImageLocation string
|
||||
ManagedImageId string
|
||||
|
||||
// Additional Disks
|
||||
AdditionalDisks *[]AdditionalDiskArtifact
|
||||
}
|
||||
|
||||
func NewManagedImageArtifact(resourceGroup, name, location string) (*Artifact, error) {
|
||||
func NewManagedImageArtifact(osType, resourceGroup, name, location, id string) (*Artifact, error) {
|
||||
return &Artifact{
|
||||
ManagedImageResourceGroupName: resourceGroup,
|
||||
ManagedImageName: name,
|
||||
ManagedImageLocation: location,
|
||||
ManagedImageId: id,
|
||||
OSType: osType,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string) (*Artifact, error) {
|
||||
func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string, osType string) (*Artifact, error) {
|
||||
if template == nil {
|
||||
return nil, fmt.Errorf("nil capture template")
|
||||
}
|
||||
|
@ -76,6 +82,7 @@ func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string)
|
|||
}
|
||||
|
||||
return &Artifact{
|
||||
OSType: osType,
|
||||
OSDiskUri: vhdUri.String(),
|
||||
OSDiskUriReadOnlySas: getSasUrl(getStorageUrlPath(vhdUri)),
|
||||
TemplateUri: templateUri.String(),
|
||||
|
@ -142,9 +149,11 @@ func (a *Artifact) String() string {
|
|||
var buf bytes.Buffer
|
||||
|
||||
buf.WriteString(fmt.Sprintf("%s:\n\n", a.BuilderId()))
|
||||
buf.WriteString(fmt.Sprintf("OSType: %s\n", a.OSType))
|
||||
if a.isManagedImage() {
|
||||
buf.WriteString(fmt.Sprintf("ManagedImageResourceGroupName: %s\n", a.ManagedImageResourceGroupName))
|
||||
buf.WriteString(fmt.Sprintf("ManagedImageName: %s\n", a.ManagedImageName))
|
||||
buf.WriteString(fmt.Sprintf("ManagedImageId: %s\n", a.ManagedImageId))
|
||||
buf.WriteString(fmt.Sprintf("ManagedImageLocation: %s\n", a.ManagedImageLocation))
|
||||
} else {
|
||||
buf.WriteString(fmt.Sprintf("StorageAccountLocation: %s\n", a.StorageAccountLocation))
|
||||
|
|
|
@ -28,7 +28,7 @@ func TestArtifactId(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
artifact, err := NewArtifact(&template, getFakeSasUrl)
|
||||
artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux")
|
||||
if err != nil {
|
||||
t.Fatalf("err=%s", err)
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ func TestArtifactString(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
artifact, err := NewArtifact(&template, getFakeSasUrl)
|
||||
artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux")
|
||||
if err != nil {
|
||||
t.Fatalf("err=%s", err)
|
||||
}
|
||||
|
@ -80,6 +80,9 @@ func TestArtifactString(t *testing.T) {
|
|||
if !strings.Contains(testSubject, "StorageAccountLocation: southcentralus") {
|
||||
t.Errorf("Expected String() output to contain StorageAccountLocation")
|
||||
}
|
||||
if !strings.Contains(testSubject, "OSType: Linux") {
|
||||
t.Errorf("Expected String() output to contain OSType")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdditionalDiskArtifactString(t *testing.T) {
|
||||
|
@ -107,7 +110,7 @@ func TestAdditionalDiskArtifactString(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
artifact, err := NewArtifact(&template, getFakeSasUrl)
|
||||
artifact, err := NewArtifact(&template, getFakeSasUrl, "Linux")
|
||||
if err != nil {
|
||||
t.Fatalf("err=%s", err)
|
||||
}
|
||||
|
@ -128,6 +131,9 @@ func TestAdditionalDiskArtifactString(t *testing.T) {
|
|||
if !strings.Contains(testSubject, "StorageAccountLocation: southcentralus") {
|
||||
t.Errorf("Expected String() output to contain StorageAccountLocation")
|
||||
}
|
||||
if !strings.Contains(testSubject, "OSType: Linux") {
|
||||
t.Errorf("Expected String() output to contain OSType")
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
@ -154,7 +160,7 @@ func TestArtifactProperties(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
testSubject, err := NewArtifact(&template, getFakeSasUrl)
|
||||
testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux")
|
||||
if err != nil {
|
||||
t.Fatalf("err=%s", err)
|
||||
}
|
||||
|
@ -174,6 +180,9 @@ func TestArtifactProperties(t *testing.T) {
|
|||
if testSubject.StorageAccountLocation != "southcentralus" {
|
||||
t.Errorf("Expected StorageAccountLocation to be 'southcentral', but got %s", testSubject.StorageAccountLocation)
|
||||
}
|
||||
if testSubject.OSType != "Linux" {
|
||||
t.Errorf("Expected OSType to be 'Linux', but got %s", testSubject.OSType)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdditionalDiskArtifactProperties(t *testing.T) {
|
||||
|
@ -201,7 +210,7 @@ func TestAdditionalDiskArtifactProperties(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
testSubject, err := NewArtifact(&template, getFakeSasUrl)
|
||||
testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux")
|
||||
if err != nil {
|
||||
t.Fatalf("err=%s", err)
|
||||
}
|
||||
|
@ -221,6 +230,9 @@ func TestAdditionalDiskArtifactProperties(t *testing.T) {
|
|||
if testSubject.StorageAccountLocation != "southcentralus" {
|
||||
t.Errorf("Expected StorageAccountLocation to be 'southcentral', but got %s", testSubject.StorageAccountLocation)
|
||||
}
|
||||
if testSubject.OSType != "Linux" {
|
||||
t.Errorf("Expected OSType to be 'Linux', but got %s", testSubject.OSType)
|
||||
}
|
||||
if testSubject.AdditionalDisks == nil {
|
||||
t.Errorf("Expected AdditionalDisks to be not nil")
|
||||
}
|
||||
|
@ -253,7 +265,7 @@ func TestArtifactOverHyphenatedCaptureUri(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
testSubject, err := NewArtifact(&template, getFakeSasUrl)
|
||||
testSubject, err := NewArtifact(&template, getFakeSasUrl, "Linux")
|
||||
if err != nil {
|
||||
t.Fatalf("err=%s", err)
|
||||
}
|
||||
|
@ -266,7 +278,7 @@ func TestArtifactOverHyphenatedCaptureUri(t *testing.T) {
|
|||
func TestArtifactRejectMalformedTemplates(t *testing.T) {
|
||||
template := CaptureTemplate{}
|
||||
|
||||
_, err := NewArtifact(&template, getFakeSasUrl)
|
||||
_, err := NewArtifact(&template, getFakeSasUrl, "Linux")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected artifact creation to fail, but it succeeded.")
|
||||
}
|
||||
|
@ -289,7 +301,7 @@ func TestArtifactRejectMalformedStorageUri(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
_, err := NewArtifact(&template, getFakeSasUrl)
|
||||
_, err := NewArtifact(&template, getFakeSasUrl, "Linux")
|
||||
if err == nil {
|
||||
t.Fatalf("Expected artifact creation to fail, but it succeeded.")
|
||||
}
|
||||
|
|
|
@ -254,8 +254,14 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
return nil, errors.New("Build was halted.")
|
||||
}
|
||||
|
||||
osType := "Linux"
|
||||
if b.config.OSType == constants.Target_Windows {
|
||||
osType = "Windows"
|
||||
}
|
||||
|
||||
if b.config.isManagedImage() {
|
||||
return NewManagedImageArtifact(b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, b.config.manageImageLocation)
|
||||
managedImageID := fmt.Sprintf("/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Compute/images/%s", b.config.SubscriptionID, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName)
|
||||
return NewManagedImageArtifact(osType, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, b.config.manageImageLocation, managedImageID)
|
||||
} else if template, ok := b.stateBag.GetOk(constants.ArmCaptureTemplate); ok {
|
||||
return NewArtifact(
|
||||
template.(*CaptureTemplate),
|
||||
|
@ -266,7 +272,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
options.Expiry = time.Now().AddDate(0, 1, 0).UTC() // one month
|
||||
sasUrl, _ := blob.GetSASURI(options)
|
||||
return sasUrl
|
||||
})
|
||||
},
|
||||
osType)
|
||||
}
|
||||
|
||||
return &Artifact{}, nil
|
||||
|
|
|
@ -7,6 +7,7 @@ type MockArtifact struct {
|
|||
IdValue string
|
||||
StateValues map[string]interface{}
|
||||
DestroyCalled bool
|
||||
StringValue string
|
||||
}
|
||||
|
||||
func (a *MockArtifact) BuilderId() string {
|
||||
|
@ -34,8 +35,12 @@ func (a *MockArtifact) Id() string {
|
|||
return id
|
||||
}
|
||||
|
||||
func (*MockArtifact) String() string {
|
||||
return "string"
|
||||
func (a *MockArtifact) String() string {
|
||||
str := a.StringValue
|
||||
if str == "" {
|
||||
str = "string"
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func (a *MockArtifact) State(name string) interface{} {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
package vagrant
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
type AzureProvider struct{}
|
||||
|
||||
func (p *AzureProvider) KeepInputArtifact() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (p *AzureProvider) Process(ui packer.Ui, artifact packer.Artifact, dir string) (vagrantfile string, metadata map[string]interface{}, err error) {
|
||||
// Create the metadata
|
||||
metadata = map[string]interface{}{"provider": "azure"}
|
||||
|
||||
var AzureImageProps map[string]string
|
||||
AzureImageProps = make(map[string]string)
|
||||
|
||||
// HACK(double16): It appears we can not access the Azure Artifact directly, so parse String()
|
||||
artifactString := artifact.String()
|
||||
ui.Message(fmt.Sprintf("artifact string: '%s'", artifactString))
|
||||
lines := strings.Split(artifactString, "\n")
|
||||
for l := 0; l < len(lines); l++ {
|
||||
split := strings.Split(lines[l], ": ")
|
||||
if len(split) > 1 {
|
||||
AzureImageProps[strings.TrimSpace(split[0])] = strings.TrimSpace(split[1])
|
||||
}
|
||||
}
|
||||
ui.Message(fmt.Sprintf("artifact string parsed: %+v", AzureImageProps))
|
||||
|
||||
if AzureImageProps["ManagedImageId"] != "" {
|
||||
vagrantfile = fmt.Sprintf(managedImageVagrantfile, AzureImageProps["ManagedImageLocation"], AzureImageProps["ManagedImageId"])
|
||||
} else if AzureImageProps["OSDiskUri"] != "" {
|
||||
vagrantfile = fmt.Sprintf(vhdVagrantfile, AzureImageProps["StorageAccountLocation"], AzureImageProps["OSDiskUri"], AzureImageProps["OSType"])
|
||||
} else {
|
||||
err = fmt.Errorf("No managed image nor VHD URI found in artifact: %s", artifactString)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var managedImageVagrantfile = `
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.provider :azure do |azure, override|
|
||||
azure.location = "%s"
|
||||
azure.vm_managed_image_id = "%s"
|
||||
override.winrm.transport = :ssl
|
||||
override.winrm.port = 5986
|
||||
end
|
||||
end
|
||||
`
|
||||
|
||||
var vhdVagrantfile = `
|
||||
Vagrant.configure("2") do |config|
|
||||
config.vm.provider :azure do |azure, override|
|
||||
azure.location = "%s"
|
||||
azure.vm_vhd_uri = "%s"
|
||||
azure.vm_operating_system = "%s"
|
||||
override.winrm.transport = :ssl
|
||||
override.winrm.port = 5986
|
||||
end
|
||||
end
|
||||
`
|
|
@ -0,0 +1,94 @@
|
|||
package vagrant
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
func TestAzureProvider_impl(t *testing.T) {
|
||||
var _ Provider = new(AzureProvider)
|
||||
}
|
||||
|
||||
func TestAzureProvider_KeepInputArtifact(t *testing.T) {
|
||||
p := new(AzureProvider)
|
||||
|
||||
if !p.KeepInputArtifact() {
|
||||
t.Fatal("should keep input artifact")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAzureProvider_ManagedImage(t *testing.T) {
|
||||
p := new(AzureProvider)
|
||||
ui := testUi()
|
||||
artifact := &packer.MockArtifact{
|
||||
StringValue: `Azure.ResourceManagement.VMImage:
|
||||
|
||||
OSType: Linux
|
||||
ManagedImageResourceGroupName: packerruns
|
||||
ManagedImageName: packer-1533651633
|
||||
ManagedImageId: /subscriptions/e6229913-d9c3-4ddd-99a4-9e1ef3beaa1b/resourceGroups/packerruns/providers/Microsoft.Compute/images/packer-1533675589
|
||||
ManagedImageLocation: westus`,
|
||||
}
|
||||
|
||||
vagrantfile, _, err := p.Process(ui, artifact, "foo")
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
result := `azure.location = "westus"`
|
||||
if !strings.Contains(vagrantfile, result) {
|
||||
t.Fatalf("wrong substitution: %s", vagrantfile)
|
||||
}
|
||||
result = `azure.vm_managed_image_id = "/subscriptions/e6229913-d9c3-4ddd-99a4-9e1ef3beaa1b/resourceGroups/packerruns/providers/Microsoft.Compute/images/packer-1533675589"`
|
||||
if !strings.Contains(vagrantfile, result) {
|
||||
t.Fatalf("wrong substitution: %s", vagrantfile)
|
||||
}
|
||||
// DO NOT set resource group in Vagrantfile, it should be separate from the image
|
||||
result = `azure.resource_group_name`
|
||||
if strings.Contains(vagrantfile, result) {
|
||||
t.Fatalf("wrong substitution: %s", vagrantfile)
|
||||
}
|
||||
result = `azure.vm_operating_system`
|
||||
if strings.Contains(vagrantfile, result) {
|
||||
t.Fatalf("wrong substitution: %s", vagrantfile)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAzureProvider_VHD(t *testing.T) {
|
||||
p := new(AzureProvider)
|
||||
ui := testUi()
|
||||
artifact := &packer.MockArtifact{
|
||||
IdValue: "https://packerbuildswest.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.96ed2120-591d-4900-95b0-ee8e985f2213.vhd",
|
||||
StringValue: `Azure.ResourceManagement.VMImage:
|
||||
|
||||
OSType: Linux
|
||||
StorageAccountLocation: westus
|
||||
OSDiskUri: https://packerbuildswest.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.96ed2120-591d-4900-95b0-ee8e985f2213.vhd
|
||||
OSDiskUriReadOnlySas: https://packerbuildswest.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.96ed2120-591d-4900-95b0-ee8e985f2213.vhd?se=2018-09-07T18%3A36%3A34Z&sig=xUiFvwAviPYoP%2Bc91vErqvwYR1eK4x%2BAx7YLMe84zzU%3D&sp=r&sr=b&sv=2016-05-31
|
||||
TemplateUri: https://packerbuildswest.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.96ed2120-591d-4900-95b0-ee8e985f2213.json
|
||||
TemplateUriReadOnlySas: https://packerbuildswest.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.96ed2120-591d-4900-95b0-ee8e985f2213.json?se=2018-09-07T18%3A36%3A34Z&sig=lDxePyAUCZbfkB5ddiofimXfwk5INn%2F9E2BsnqIKC9Q%3D&sp=r&sr=b&sv=2016-05-31`,
|
||||
}
|
||||
|
||||
vagrantfile, _, err := p.Process(ui, artifact, "foo")
|
||||
if err != nil {
|
||||
t.Fatalf("should not have error: %s", err)
|
||||
}
|
||||
result := `azure.location = "westus"`
|
||||
if !strings.Contains(vagrantfile, result) {
|
||||
t.Fatalf("wrong substitution: %s", vagrantfile)
|
||||
}
|
||||
result = `azure.vm_vhd_uri = "https://packerbuildswest.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.96ed2120-591d-4900-95b0-ee8e985f2213.vhd"`
|
||||
if !strings.Contains(vagrantfile, result) {
|
||||
t.Fatalf("wrong substitution: %s", vagrantfile)
|
||||
}
|
||||
result = `azure.vm_operating_system = "Linux"`
|
||||
if !strings.Contains(vagrantfile, result) {
|
||||
t.Fatalf("wrong substitution: %s", vagrantfile)
|
||||
}
|
||||
// DO NOT set resource group in Vagrantfile, it should be separate from the image
|
||||
result = `azure.resource_group_name`
|
||||
if strings.Contains(vagrantfile, result) {
|
||||
t.Fatalf("wrong substitution: %s", vagrantfile)
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ var builtins = map[string]string{
|
|||
"MSOpenTech.hyperv": "hyperv",
|
||||
"transcend.qemu": "libvirt",
|
||||
"ustream.lxc": "lxc",
|
||||
"Azure.ResourceManagement.VMImage": "azure",
|
||||
"packer.post-processor.docker-import": "docker",
|
||||
"packer.post-processor.docker-tag": "docker",
|
||||
"packer.post-processor.docker-push": "docker",
|
||||
|
@ -244,6 +245,8 @@ func providerForName(name string) Provider {
|
|||
return new(GoogleProvider)
|
||||
case "lxc":
|
||||
return new(LXCProvider)
|
||||
case "azure":
|
||||
return new(AzureProvider)
|
||||
case "docker":
|
||||
return new(DockerProvider)
|
||||
default:
|
||||
|
|
|
@ -33,6 +33,7 @@ providers.
|
|||
- AWS
|
||||
- DigitalOcean
|
||||
- Google
|
||||
- Azure
|
||||
- Hyper-V
|
||||
- LXC
|
||||
- Parallels
|
||||
|
@ -108,6 +109,7 @@ The available provider names are:
|
|||
- `aws`
|
||||
- `digitalocean`
|
||||
- `google`
|
||||
- `azure`
|
||||
- `hyperv`
|
||||
- `parallels`
|
||||
- `libvirt`
|
||||
|
|
Loading…
Reference in New Issue