Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5f6958803 |
+2
-4
@@ -1,4 +1,2 @@
|
||||
* text=auto
|
||||
*.go text eol=lf
|
||||
*.sh text eol=lf
|
||||
common/test-fixtures/root/* eol=lf
|
||||
|
||||
common/test-fixtures/root/* eol=lf
|
||||
+1
-2
@@ -23,5 +23,4 @@ packer-test*.log
|
||||
.idea/
|
||||
*.iml
|
||||
Thumbs.db
|
||||
/packer.exe
|
||||
.project
|
||||
/packer.exe
|
||||
@@ -10,7 +10,6 @@ go:
|
||||
- 1.9.x
|
||||
- 1.x
|
||||
|
||||
|
||||
install:
|
||||
- make deps
|
||||
|
||||
|
||||
+5
-111
@@ -1,122 +1,16 @@
|
||||
## 1.2.4 (May 29, 2018)
|
||||
## (UNRELEASED)
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
* builder/amazon: Can now force the chroot builder to mount an entire block
|
||||
device instead of a partition [GH-6194]
|
||||
* builder/azure: windows-sql-cloud is now in the default list of projects to
|
||||
check for provided images. [GH-6210]
|
||||
* builder/chroot: A new template option, `nvme_device_path` has been added to
|
||||
provide a workaround for users who need the amazon-chroot builder to mount
|
||||
a NVMe volume on their instances. [GH-6295]
|
||||
* builder/hyper-v: Fix command for mounting multiple disks [GH-6267]
|
||||
* builder/hyperv: Enable IP retrieval for Server 2008 R2 hosts. [GH-6219]
|
||||
* builder/hyperv: Fix bug in MAC address specification on Hyper-V. [GH-6187]
|
||||
* builder/parallels-pvm: Add missing disk compaction step. [GH-6202]
|
||||
* builder/vmware-esxi: Remove floppy files from the remote server on cleanup.
|
||||
[GH-6206]
|
||||
* communicator/winrm: Updated dependencies to fix a race condition [GH-6261]
|
||||
* core: When using `-on-error=[abort|ask]`, output the error to the user.
|
||||
[GH-6252]
|
||||
* provisioner/puppet: Extra-Arguments are no longer prematurely
|
||||
interpolated.[GH-6215]
|
||||
* provisioner/shell: Remove file stat that was causing problems uploading files
|
||||
[GH-6239]
|
||||
|
||||
### IMPROVEMENTS:
|
||||
|
||||
* builder/amazon: Amazon builders other than `chroot` now support T2 unlimited
|
||||
instances [GH-6265]
|
||||
* builder/azure: Allow device login for US government cloud. [GH-6105]
|
||||
* builder/azure: Devicelogin Support for Windows [GH-6285]
|
||||
* builder/azure: Enable simultaneous builds within one resource group.
|
||||
[GH-6231]
|
||||
* builder/azure: Faster deletion of Azure Resource Groups. [GH-6269]
|
||||
* builder/azure: Updated Azure SDK to v15.0.0 [GH-6224]
|
||||
* builder/hyper-v: Hyper-V builds now connect to vnc display by default when
|
||||
building [GH-6243]
|
||||
* builder/hyper-v: New `use_fixed_vhd_format` allows vm export in an Azure-
|
||||
compatible format [GH-6101]
|
||||
* builder/hyperv: New config option for specifying what secure boot template to
|
||||
use, allowing secure boot of linux vms. [GH-5883]
|
||||
* builder/qemu: Add support for hvf accelerator. [GH-6193]
|
||||
* builder/scaleway: Fix SSH communicator connection issue. [GH-6238]
|
||||
* core: Add opt-in Packer top-level command autocomplete [GH-5454]
|
||||
* post-processor/shell-local: New options have been added to create feature
|
||||
parity with the shell-local provisioner. This feature now works on Windows
|
||||
hosts. [GH-5956]
|
||||
* provisioner/chef: New config option allows user to skip cleanup of chef
|
||||
client staging directory. [GH-4300]
|
||||
* provisioner/shell-local: Can now access automatically-generated WinRM
|
||||
password as variable [GH-6251]
|
||||
* provisoner/shell-local: New options have been added to create feature parity
|
||||
with the shell-local post-processor. This feature now works on Windows
|
||||
hosts. [GH-5956]
|
||||
|
||||
## 1.2.3 (April 25, 2018)
|
||||
|
||||
### BUG FIXES:
|
||||
|
||||
* builder/azure: Azure CLI may now be logged into several accounts. [GH-6087]
|
||||
* builder/ebssurrogate: Snapshot all launch devices. [GH-6056]
|
||||
* builder/hyper-v: Fix CopyExportedVirtualMachine script so it works with
|
||||
links. [GH-6082]
|
||||
* builder/oracle-classic: Fix panics when cleaning up resources that haven't
|
||||
been created. [GH-6095]
|
||||
* builder/parallels: Allow user to cancel build while the OS is starting up.
|
||||
[GH-6166]
|
||||
* builder/qemu: Avoid warning when using raw format. [GH-6080]
|
||||
* post-processor/vagrant: Large VMDKs should no longer show a 0-byte size on OS X. [GH-6084]
|
||||
* builder/scaleway: Fix compilation issues on solaris/amd64. [GH-6069]
|
||||
* builder/virtualbox: Fix broken scancodes in boot_command. [GH-6067]
|
||||
* builder/vmware-iso: Fail in validation if user gives wrong remote_type value.
|
||||
[GH-4563]
|
||||
* builder/vmware: Fixed a case-sensitivity issue when determing the network
|
||||
type during the cloning step in the vmware-vmx builder. [GH-6057]
|
||||
* builder/vmware: Fixes the DHCP lease and configuration pathfinders for VMware
|
||||
Player. [GH-6096]
|
||||
* builder/vmware: Multi-disk VM's can be properly handled by the compacting
|
||||
stage. [GH-6074]
|
||||
* common/bootcommand: Fix numerous bugs in the boot command code, and make
|
||||
supported features consistent across builders. [GH-6129]
|
||||
* communicator/ssh: Stop trying to discover whether destination is a directory
|
||||
from uploader. [GH-6124]
|
||||
* post-processor/vagrant: Large VMDKs should no longer show a 0-byte size on OS
|
||||
X. [GH-6084]
|
||||
* post-processor/vsphere: Fix encoding of spaces in passwords for upload.
|
||||
[GH-6110]
|
||||
* provisioner/ansible: Pass the inventory_directory configuration option to
|
||||
ansible -i when it is set. [GH-6065]
|
||||
* provisioner/powershell: fix bug with SSH communicator + cygwin. [GH-6160]
|
||||
* provisioner/powershell: The {{.WinRMPassword}} template variable now works
|
||||
with parallel builders. [GH-6144]
|
||||
* common/bootcommand: Fix numerous bugs in the boot command code, and make supported features consistent across builders. [GH-6129]
|
||||
|
||||
### IMPROVEMENTS:
|
||||
|
||||
* builder/alicloud: Update aliyungo common package. [GH-6157]
|
||||
* builder/amazon: Expose more source ami data as template variables. [GH-6088]
|
||||
* builder/amazon: Setting `force_delete` will only delete AMIs owned by the
|
||||
user. This should prevent failures where we try to delete an AMI with a
|
||||
matching name, but owned by someone else. [GH-6111]
|
||||
* builder/azure: Users of Powershell provisioner may access the randomly-
|
||||
generated winrm password using the template variable {{.WinRMPassword}}.
|
||||
[GH-6113]
|
||||
* builder/google: Users of Powershell provisioner may access the randomly-
|
||||
generated winrm password using the template variable {{.WinRMPassword}}.
|
||||
[GH-6141]
|
||||
* builder/hyper-v: User can now configure hyper-v disk block size. [GH-5941]
|
||||
* builder/openstack: Add configuration option for `instance_name`. [GH-6041]
|
||||
* builder/oracle-classic: Better validation of destination image name.
|
||||
[GH-6089]
|
||||
* builder/oracle-oci: New config options for user data and user data file.
|
||||
[GH-6079]
|
||||
* builder/oracle-oci: use the official OCI sdk instead of handcrafted client.
|
||||
[GH-6142]
|
||||
* builder/triton: Add support to Skip TLS Verification of Triton Certificate.
|
||||
[GH-6039]
|
||||
* provisioner/ansible: Ansible users may provide a custom inventory file.
|
||||
[GH-6107]
|
||||
* provisioner/file: New `generated` tag allows users to upload files created
|
||||
during Packer run. [GH-3891]
|
||||
user. This should prevent failures where we try to delete an AMI with
|
||||
a matching name, but owned by someone else. [GH-6111]
|
||||
|
||||
## 1.2.2 (March 26, 2018)
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package ecs
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
@@ -69,7 +68,6 @@ func TestRunConfigPrepare_UserData(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
c.UserData = "foo"
|
||||
@@ -94,7 +92,6 @@ func TestRunConfigPrepare_UserDataFile(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
c.UserDataFile = tf.Name()
|
||||
|
||||
@@ -33,10 +33,9 @@ type Config struct {
|
||||
CommandWrapper string `mapstructure:"command_wrapper"`
|
||||
CopyFiles []string `mapstructure:"copy_files"`
|
||||
DevicePath string `mapstructure:"device_path"`
|
||||
NVMEDevicePath string `mapstructure:"nvme_device_path"`
|
||||
FromScratch bool `mapstructure:"from_scratch"`
|
||||
MountOptions []string `mapstructure:"mount_options"`
|
||||
MountPartition string `mapstructure:"mount_partition"`
|
||||
MountPartition int `mapstructure:"mount_partition"`
|
||||
MountPath string `mapstructure:"mount_path"`
|
||||
PostMountCommands []string `mapstructure:"post_mount_commands"`
|
||||
PreMountCommands []string `mapstructure:"pre_mount_commands"`
|
||||
@@ -113,8 +112,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
b.config.MountPath = "/mnt/packer-amazon-chroot-volumes/{{.Device}}"
|
||||
}
|
||||
|
||||
if b.config.MountPartition == "" {
|
||||
b.config.MountPartition = "1"
|
||||
if b.config.MountPartition == 0 {
|
||||
b.config.MountPartition = 1
|
||||
}
|
||||
|
||||
// Accumulate any errors or warnings
|
||||
|
||||
@@ -3,8 +3,8 @@ package chroot
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sl "github.com/hashicorp/packer/common/shell-local"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/hashicorp/packer/post-processor/shell-local"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
@@ -21,9 +21,7 @@ func RunLocalCommands(commands []string, wrappedCommand CommandWrapper, ctx inte
|
||||
}
|
||||
|
||||
ui.Say(fmt.Sprintf("Executing command: %s", command))
|
||||
comm := &sl.Communicator{
|
||||
ExecuteCommand: []string{command},
|
||||
}
|
||||
comm := &shell_local.Communicator{}
|
||||
cmd := &packer.RemoteCmd{Command: command}
|
||||
if err := cmd.StartWithUi(comm, ui); err != nil {
|
||||
return fmt.Errorf("Error executing command: %s", err)
|
||||
|
||||
@@ -26,7 +26,7 @@ type mountPathData struct {
|
||||
// mount_device_cleanup CleanupFunc - To perform early cleanup
|
||||
type StepMountDevice struct {
|
||||
MountOptions []string
|
||||
MountPartition string
|
||||
MountPartition int
|
||||
|
||||
mountPath string
|
||||
}
|
||||
@@ -35,10 +35,6 @@ func (s *StepMountDevice) Run(_ context.Context, state multistep.StateBag) multi
|
||||
config := state.Get("config").(*Config)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
device := state.Get("device").(string)
|
||||
if config.NVMEDevicePath != "" {
|
||||
// customizable device path for mounting NVME block devices on c5 and m5 HVM
|
||||
device = config.NVMEDevicePath
|
||||
}
|
||||
wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)
|
||||
|
||||
var virtualizationType string
|
||||
@@ -51,7 +47,6 @@ func (s *StepMountDevice) Run(_ context.Context, state multistep.StateBag) multi
|
||||
}
|
||||
|
||||
ctx := config.ctx
|
||||
|
||||
ctx.Data = &mountPathData{Device: filepath.Base(device)}
|
||||
mountPath, err := interpolate.Render(config.MountPath, &ctx)
|
||||
|
||||
@@ -80,9 +75,8 @@ func (s *StepMountDevice) Run(_ context.Context, state multistep.StateBag) multi
|
||||
}
|
||||
|
||||
deviceMount := device
|
||||
|
||||
if virtualizationType == "hvm" && s.MountPartition != "0" {
|
||||
deviceMount = fmt.Sprintf("%s%s", device, s.MountPartition)
|
||||
if virtualizationType == "hvm" {
|
||||
deviceMount = fmt.Sprintf("%s%d", device, s.MountPartition)
|
||||
}
|
||||
state.Put("deviceMount", deviceMount)
|
||||
|
||||
@@ -103,7 +97,7 @@ func (s *StepMountDevice) Run(_ context.Context, state multistep.StateBag) multi
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
log.Printf("[DEBUG] (step mount) mount command is %s", mountCommand)
|
||||
|
||||
cmd := ShellCommand(mountCommand)
|
||||
cmd.Stderr = stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/packer/common/uuid"
|
||||
@@ -30,26 +30,25 @@ func (d *AmiFilterOptions) Empty() bool {
|
||||
type RunConfig struct {
|
||||
AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address"`
|
||||
AvailabilityZone string `mapstructure:"availability_zone"`
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance"`
|
||||
EbsOptimized bool `mapstructure:"ebs_optimized"`
|
||||
EnableT2Unlimited bool `mapstructure:"enable_t2_unlimited"`
|
||||
IamInstanceProfile string `mapstructure:"iam_instance_profile"`
|
||||
InstanceInitiatedShutdownBehavior string `mapstructure:"shutdown_behavior"`
|
||||
InstanceType string `mapstructure:"instance_type"`
|
||||
RunTags map[string]string `mapstructure:"run_tags"`
|
||||
SecurityGroupId string `mapstructure:"security_group_id"`
|
||||
SecurityGroupIds []string `mapstructure:"security_group_ids"`
|
||||
SourceAmi string `mapstructure:"source_ami"`
|
||||
SourceAmiFilter AmiFilterOptions `mapstructure:"source_ami_filter"`
|
||||
SpotPrice string `mapstructure:"spot_price"`
|
||||
SpotPriceAutoProduct string `mapstructure:"spot_price_auto_product"`
|
||||
DisableStopInstance bool `mapstructure:"disable_stop_instance"`
|
||||
SecurityGroupId string `mapstructure:"security_group_id"`
|
||||
SecurityGroupIds []string `mapstructure:"security_group_ids"`
|
||||
TemporarySGSourceCidr string `mapstructure:"temporary_security_group_source_cidr"`
|
||||
SubnetId string `mapstructure:"subnet_id"`
|
||||
TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"`
|
||||
TemporarySGSourceCidr string `mapstructure:"temporary_security_group_source_cidr"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
VpcId string `mapstructure:"vpc_id"`
|
||||
WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout"`
|
||||
VpcId string `mapstructure:"vpc_id"`
|
||||
InstanceInitiatedShutdownBehavior string `mapstructure:"shutdown_behavior"`
|
||||
|
||||
// Communicator settings
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
@@ -85,39 +84,32 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
c.SSHInterface != "public_dns" &&
|
||||
c.SSHInterface != "private_dns" &&
|
||||
c.SSHInterface != "" {
|
||||
errs = append(errs, fmt.Errorf("Unknown interface type: %s", c.SSHInterface))
|
||||
errs = append(errs, errors.New(fmt.Sprintf("Unknown interface type: %s", c.SSHInterface)))
|
||||
}
|
||||
|
||||
if c.SSHKeyPairName != "" {
|
||||
if c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" && c.Comm.SSHPrivateKey == "" {
|
||||
errs = append(errs, fmt.Errorf("ssh_private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))
|
||||
errs = append(errs, errors.New("ssh_private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))
|
||||
} else if c.Comm.SSHPrivateKey == "" && !c.Comm.SSHAgentAuth {
|
||||
errs = append(errs, fmt.Errorf("ssh_private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified."))
|
||||
errs = append(errs, errors.New("ssh_private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified."))
|
||||
}
|
||||
}
|
||||
|
||||
if c.SourceAmi == "" && c.SourceAmiFilter.Empty() {
|
||||
errs = append(errs, fmt.Errorf("A source_ami or source_ami_filter must be specified"))
|
||||
errs = append(errs, errors.New("A source_ami or source_ami_filter must be specified"))
|
||||
}
|
||||
|
||||
if c.InstanceType == "" {
|
||||
errs = append(errs, fmt.Errorf("An instance_type must be specified"))
|
||||
errs = append(errs, errors.New("An instance_type must be specified"))
|
||||
}
|
||||
|
||||
if c.SpotPrice == "auto" {
|
||||
if c.SpotPriceAutoProduct == "" {
|
||||
errs = append(errs, fmt.Errorf(
|
||||
errs = append(errs, errors.New(
|
||||
"spot_price_auto_product must be specified when spot_price is auto"))
|
||||
}
|
||||
}
|
||||
|
||||
if c.SpotPriceAutoProduct != "" {
|
||||
if c.SpotPrice != "auto" {
|
||||
errs = append(errs, fmt.Errorf(
|
||||
"spot_price should be set to auto when spot_price_auto_product is specified"))
|
||||
}
|
||||
}
|
||||
|
||||
if c.UserData != "" && c.UserDataFile != "" {
|
||||
errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified."))
|
||||
} else if c.UserDataFile != "" {
|
||||
@@ -149,18 +141,6 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
errs = append(errs, fmt.Errorf("shutdown_behavior only accepts 'stop' or 'terminate' values."))
|
||||
}
|
||||
|
||||
if c.EnableT2Unlimited {
|
||||
if c.SpotPrice != "" {
|
||||
errs = append(errs, fmt.Errorf("Error: T2 Unlimited cannot be used in conjuction with Spot Instances"))
|
||||
}
|
||||
firstDotIndex := strings.Index(c.InstanceType, ".")
|
||||
if firstDotIndex == -1 {
|
||||
errs = append(errs, fmt.Errorf("Error determining main Instance Type from: %s", c.InstanceType))
|
||||
} else if c.InstanceType[0:firstDotIndex] != "t2" {
|
||||
errs = append(errs, fmt.Errorf("Error: T2 Unlimited enabled with a non-T2 Instance Type: %s", c.InstanceType))
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ func TestRunConfigPrepare_InstanceType(t *testing.T) {
|
||||
c := testConfig()
|
||||
c.InstanceType = ""
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if an instance_type is not specified")
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,14 +56,14 @@ func TestRunConfigPrepare_SourceAmi(t *testing.T) {
|
||||
c := testConfig()
|
||||
c.SourceAmi = ""
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if a source_ami (or source_ami_filter) is not specified")
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SourceAmiFilterBlank(t *testing.T) {
|
||||
c := testConfigFilter()
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if source_ami_filter is empty or not specified (and source_ami is not specified)")
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,57 +79,16 @@ func TestRunConfigPrepare_SourceAmiFilterGood(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_EnableT2UnlimitedGood(t *testing.T) {
|
||||
c := testConfig()
|
||||
// Must have a T2 instance type if T2 Unlimited is enabled
|
||||
c.InstanceType = "t2.micro"
|
||||
c.EnableT2Unlimited = true
|
||||
err := c.Prepare(nil)
|
||||
if len(err) > 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_EnableT2UnlimitedBadInstanceType(t *testing.T) {
|
||||
c := testConfig()
|
||||
// T2 Unlimited cannot be used with instance types other than T2
|
||||
c.InstanceType = "m5.large"
|
||||
c.EnableT2Unlimited = true
|
||||
err := c.Prepare(nil)
|
||||
if len(err) != 1 {
|
||||
t.Fatalf("Should error if T2 Unlimited is enabled with non-T2 instance_type")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_EnableT2UnlimitedBadWithSpotInstanceRequest(t *testing.T) {
|
||||
c := testConfig()
|
||||
// T2 Unlimited cannot be used with Spot Instances
|
||||
c.InstanceType = "t2.micro"
|
||||
c.EnableT2Unlimited = true
|
||||
c.SpotPrice = "auto"
|
||||
c.SpotPriceAutoProduct = "Linux/UNIX"
|
||||
err := c.Prepare(nil)
|
||||
if len(err) != 1 {
|
||||
t.Fatalf("Should error if T2 Unlimited has been used in conjuntion with a Spot Price request")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfigPrepare_SpotAuto(t *testing.T) {
|
||||
c := testConfig()
|
||||
c.SpotPrice = "auto"
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if spot_price_auto_product is not set and spot_price is set to auto")
|
||||
}
|
||||
|
||||
// Good - SpotPrice and SpotPriceAutoProduct are correctly set
|
||||
c.SpotPriceAutoProduct = "foo"
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
c.SpotPrice = ""
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if spot_price is not set to auto and spot_price_auto_product is set")
|
||||
c.SpotPriceAutoProduct = "foo"
|
||||
if err := c.Prepare(nil); len(err) != 0 {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,13 +119,12 @@ func TestRunConfigPrepare_UserData(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
c.UserData = "foo"
|
||||
c.UserDataFile = tf.Name()
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if user_data string and user_data_file have both been specified")
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,14 +136,13 @@ func TestRunConfigPrepare_UserDataFile(t *testing.T) {
|
||||
|
||||
c.UserDataFile = "idontexistidontthink"
|
||||
if err := c.Prepare(nil); len(err) != 1 {
|
||||
t.Fatalf("Should error if the file specified by user_data_file does not exist")
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
c.UserDataFile = tf.Name()
|
||||
|
||||
@@ -21,10 +21,9 @@ import (
|
||||
// StepGetPassword reads the password from a Windows server and sets it
|
||||
// on the WinRM config.
|
||||
type StepGetPassword struct {
|
||||
Debug bool
|
||||
Comm *communicator.Config
|
||||
Timeout time.Duration
|
||||
BuildName string
|
||||
Debug bool
|
||||
Comm *communicator.Config
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
func (s *StepGetPassword) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
@@ -95,13 +94,13 @@ WaitLoop:
|
||||
"Password (since debug is enabled): %s", s.Comm.WinRMPassword))
|
||||
}
|
||||
// store so that we can access this later during provisioning
|
||||
commonhelper.SetSharedState("winrm_password", s.Comm.WinRMPassword, s.BuildName)
|
||||
commonhelper.SetSharedState("winrm_password", s.Comm.WinRMPassword)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepGetPassword) Cleanup(multistep.StateBag) {
|
||||
commonhelper.RemoveSharedStateFile("winrm_password", s.BuildName)
|
||||
commonhelper.RemoveSharedStateFile("winrm_password")
|
||||
}
|
||||
|
||||
func (s *StepGetPassword) waitForPassword(state multistep.StateBag, cancel <-chan struct{}) (string, error) {
|
||||
|
||||
@@ -24,7 +24,6 @@ type StepRunSourceInstance struct {
|
||||
Ctx interpolate.Context
|
||||
Debug bool
|
||||
EbsOptimized bool
|
||||
EnableT2Unlimited bool
|
||||
ExpectedRootDevice string
|
||||
IamInstanceProfile string
|
||||
InstanceInitiatedShutdownBehavior string
|
||||
@@ -40,7 +39,7 @@ type StepRunSourceInstance struct {
|
||||
instanceId string
|
||||
}
|
||||
|
||||
func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepRunSourceInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
var keyName string
|
||||
if name, ok := state.GetOk("keyPair"); ok {
|
||||
@@ -117,11 +116,6 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa
|
||||
EbsOptimized: &s.EbsOptimized,
|
||||
}
|
||||
|
||||
if s.EnableT2Unlimited {
|
||||
creditOption := "unlimited"
|
||||
runOpts.CreditSpecification = &ec2.CreditSpecificationRequest{CpuCredits: &creditOption}
|
||||
}
|
||||
|
||||
// Collect tags for tagging on resource creation
|
||||
var tagSpecs []*ec2.TagSpecification
|
||||
|
||||
@@ -191,7 +185,7 @@ func (s *StepRunSourceInstance) Run(ctx context.Context, state multistep.StateBa
|
||||
describeInstance := &ec2.DescribeInstancesInput{
|
||||
InstanceIds: []*string{aws.String(instanceId)},
|
||||
}
|
||||
if err := ec2conn.WaitUntilInstanceRunningWithContext(ctx, describeInstance); err != nil {
|
||||
if err := ec2conn.WaitUntilInstanceRunning(describeInstance); err != nil {
|
||||
err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", instanceId, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
|
||||
@@ -43,7 +43,7 @@ type StepRunSpotInstance struct {
|
||||
spotRequest *ec2.SpotInstanceRequest
|
||||
}
|
||||
|
||||
func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepRunSpotInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
var keyName string
|
||||
if name, ok := state.GetOk("keyPair"); ok {
|
||||
@@ -235,7 +235,7 @@ func (s *StepRunSpotInstance) Run(ctx context.Context, state multistep.StateBag)
|
||||
describeInstance := &ec2.DescribeInstancesInput{
|
||||
InstanceIds: []*string{aws.String(instanceId)},
|
||||
}
|
||||
if err := ec2conn.WaitUntilInstanceRunningWithContext(ctx, describeInstance); err != nil {
|
||||
if err := ec2conn.WaitUntilInstanceRunning(describeInstance); err != nil {
|
||||
err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", instanceId, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
|
||||
@@ -16,7 +16,7 @@ type StepStopEBSBackedInstance struct {
|
||||
DisableStopInstance bool
|
||||
}
|
||||
|
||||
func (s *StepStopEBSBackedInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepStopEBSBackedInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
@@ -78,7 +78,7 @@ func (s *StepStopEBSBackedInstance) Run(ctx context.Context, state multistep.Sta
|
||||
|
||||
// Wait for the instance to actually stop
|
||||
ui.Say("Waiting for the instance to stop...")
|
||||
err = ec2conn.WaitUntilInstanceStoppedWithContext(ctx, &ec2.DescribeInstancesInput{
|
||||
err = ec2conn.WaitUntilInstanceStopped(&ec2.DescribeInstancesInput{
|
||||
InstanceIds: []*string{instance.InstanceId},
|
||||
})
|
||||
|
||||
|
||||
@@ -148,7 +148,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
Ctx: b.config.ctx,
|
||||
Debug: b.config.PackerDebug,
|
||||
EbsOptimized: b.config.EbsOptimized,
|
||||
EnableT2Unlimited: b.config.EnableT2Unlimited,
|
||||
ExpectedRootDevice: "ebs",
|
||||
IamInstanceProfile: b.config.IamInstanceProfile,
|
||||
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
|
||||
@@ -194,10 +193,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
},
|
||||
instanceStep,
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
BuildName: b.config.PackerBuildName,
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
},
|
||||
&communicator.StepConnect{
|
||||
Config: &b.config.RunConfig.Comm,
|
||||
|
||||
@@ -3,7 +3,6 @@ package ebs
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
awscommon "github.com/hashicorp/packer/builder/amazon/common"
|
||||
@@ -53,16 +52,7 @@ func (s *stepCreateAMI) Run(_ context.Context, state multistep.StateBag) multist
|
||||
|
||||
ui.Say("Waiting for AMI to become ready...")
|
||||
if _, err := awscommon.WaitForState(&stateChange); err != nil {
|
||||
log.Printf("Error waiting for AMI: %s", err)
|
||||
imagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{createResp.ImageId}})
|
||||
if err != nil {
|
||||
log.Printf("Unable to determine reason waiting for AMI failed: %s", err)
|
||||
err = fmt.Errorf("Unknown error waiting for AMI.")
|
||||
} else {
|
||||
stateReason := imagesResp.Images[0].StateReason
|
||||
err = fmt.Errorf("Error waiting for AMI. Reason: %s", stateReason)
|
||||
}
|
||||
|
||||
err := fmt.Errorf("Error waiting for AMI: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
|
||||
@@ -162,7 +162,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
Ctx: b.config.ctx,
|
||||
Debug: b.config.PackerDebug,
|
||||
EbsOptimized: b.config.EbsOptimized,
|
||||
EnableT2Unlimited: b.config.EnableT2Unlimited,
|
||||
ExpectedRootDevice: "ebs",
|
||||
IamInstanceProfile: b.config.IamInstanceProfile,
|
||||
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
|
||||
@@ -208,10 +207,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
},
|
||||
instanceStep,
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
BuildName: b.config.PackerBuildName,
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
},
|
||||
&communicator.StepConnect{
|
||||
Config: &b.config.RunConfig.Comm,
|
||||
|
||||
@@ -145,7 +145,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
Ctx: b.config.ctx,
|
||||
Debug: b.config.PackerDebug,
|
||||
EbsOptimized: b.config.EbsOptimized,
|
||||
EnableT2Unlimited: b.config.EnableT2Unlimited,
|
||||
ExpectedRootDevice: "ebs",
|
||||
IamInstanceProfile: b.config.IamInstanceProfile,
|
||||
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
|
||||
@@ -187,10 +186,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
BuildName: b.config.PackerBuildName,
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
},
|
||||
&communicator.StepConnect{
|
||||
Config: &b.config.RunConfig.Comm,
|
||||
|
||||
@@ -230,7 +230,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
Ctx: b.config.ctx,
|
||||
Debug: b.config.PackerDebug,
|
||||
EbsOptimized: b.config.EbsOptimized,
|
||||
EnableT2Unlimited: b.config.EnableT2Unlimited,
|
||||
IamInstanceProfile: b.config.IamInstanceProfile,
|
||||
InstanceType: b.config.InstanceType,
|
||||
IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(),
|
||||
@@ -270,10 +269,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
},
|
||||
instanceStep,
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
BuildName: b.config.PackerBuildName,
|
||||
Debug: b.config.PackerDebug,
|
||||
Comm: &b.config.RunConfig.Comm,
|
||||
Timeout: b.config.WindowsPasswordTimeout,
|
||||
},
|
||||
&communicator.StepConnect{
|
||||
Config: &b.config.RunConfig.Comm,
|
||||
|
||||
@@ -8,13 +8,13 @@ import (
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
func testConfig() (config map[string]interface{}, tf *os.File) {
|
||||
func testConfig() map[string]interface{} {
|
||||
tf, err := ioutil.TempFile("", "packer")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
config = map[string]interface{}{
|
||||
return map[string]interface{}{
|
||||
"account_id": "foo",
|
||||
"ami_name": "foo",
|
||||
"instance_type": "m1.small",
|
||||
@@ -26,8 +26,6 @@ func testConfig() (config map[string]interface{}, tf *os.File) {
|
||||
"x509_key_path": tf.Name(),
|
||||
"x509_upload_path": "/foo",
|
||||
}
|
||||
|
||||
return config, tf
|
||||
}
|
||||
|
||||
func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
@@ -40,9 +38,7 @@ func TestBuilder_ImplementsBuilder(t *testing.T) {
|
||||
|
||||
func TestBuilderPrepare_AccountId(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
config := testConfig()
|
||||
|
||||
config["account_id"] = ""
|
||||
warnings, err := b.Prepare(config)
|
||||
@@ -78,9 +74,7 @@ func TestBuilderPrepare_AccountId(t *testing.T) {
|
||||
|
||||
func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
var b Builder
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
config := testConfig()
|
||||
|
||||
// Test good
|
||||
config["ami_name"] = "foo"
|
||||
@@ -117,9 +111,7 @@ func TestBuilderPrepare_AMIName(t *testing.T) {
|
||||
|
||||
func TestBuilderPrepare_BundleDestination(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
config := testConfig()
|
||||
|
||||
config["bundle_destination"] = ""
|
||||
warnings, err := b.Prepare(config)
|
||||
@@ -137,9 +129,7 @@ func TestBuilderPrepare_BundleDestination(t *testing.T) {
|
||||
|
||||
func TestBuilderPrepare_BundlePrefix(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
config := testConfig()
|
||||
|
||||
warnings, err := b.Prepare(config)
|
||||
if len(warnings) > 0 {
|
||||
@@ -156,9 +146,7 @@ func TestBuilderPrepare_BundlePrefix(t *testing.T) {
|
||||
|
||||
func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
var b Builder
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
config := testConfig()
|
||||
|
||||
// Add a random key
|
||||
config["i_should_not_be_valid"] = true
|
||||
@@ -173,9 +161,7 @@ func TestBuilderPrepare_InvalidKey(t *testing.T) {
|
||||
|
||||
func TestBuilderPrepare_S3Bucket(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
config := testConfig()
|
||||
|
||||
config["s3_bucket"] = ""
|
||||
warnings, err := b.Prepare(config)
|
||||
@@ -198,9 +184,7 @@ func TestBuilderPrepare_S3Bucket(t *testing.T) {
|
||||
|
||||
func TestBuilderPrepare_X509CertPath(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
config := testConfig()
|
||||
|
||||
config["x509_cert_path"] = ""
|
||||
warnings, err := b.Prepare(config)
|
||||
@@ -225,7 +209,6 @@ func TestBuilderPrepare_X509CertPath(t *testing.T) {
|
||||
t.Fatalf("error tempfile: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
config["x509_cert_path"] = tf.Name()
|
||||
warnings, err = b.Prepare(config)
|
||||
@@ -239,9 +222,7 @@ func TestBuilderPrepare_X509CertPath(t *testing.T) {
|
||||
|
||||
func TestBuilderPrepare_X509KeyPath(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
config := testConfig()
|
||||
|
||||
config["x509_key_path"] = ""
|
||||
warnings, err := b.Prepare(config)
|
||||
@@ -266,7 +247,6 @@ func TestBuilderPrepare_X509KeyPath(t *testing.T) {
|
||||
t.Fatalf("error tempfile: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
defer tf.Close()
|
||||
|
||||
config["x509_key_path"] = tf.Name()
|
||||
warnings, err = b.Prepare(config)
|
||||
@@ -280,9 +260,7 @@ func TestBuilderPrepare_X509KeyPath(t *testing.T) {
|
||||
|
||||
func TestBuilderPrepare_X509UploadPath(t *testing.T) {
|
||||
b := &Builder{}
|
||||
config, tempfile := testConfig()
|
||||
defer os.Remove(tempfile.Name())
|
||||
defer tempfile.Close()
|
||||
config := testConfig()
|
||||
|
||||
config["x509_upload_path"] = ""
|
||||
warnings, err := b.Prepare(config)
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
"image": {
|
||||
"uri": "https://localhost/custom.vhd"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
|
||||
@@ -16,25 +16,25 @@ func TestNewAuthenticate(t *testing.T) {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
|
||||
if spn.Token().AccessToken != "" {
|
||||
t.Errorf("spn.Token().AccessToken: expected=\"\", actual=%s", spn.Token().AccessToken)
|
||||
if spn.Token.AccessToken != "" {
|
||||
t.Errorf("spn.Token.AccessToken: expected=\"\", actual=%s", spn.Token.AccessToken)
|
||||
}
|
||||
if spn.Token().RefreshToken != "" {
|
||||
t.Errorf("spn.Token().RefreshToken: expected=\"\", actual=%s", spn.Token().RefreshToken)
|
||||
if spn.Token.RefreshToken != "" {
|
||||
t.Errorf("spn.Token.RefreshToken: expected=\"\", actual=%s", spn.Token.RefreshToken)
|
||||
}
|
||||
if spn.Token().ExpiresIn != "" {
|
||||
t.Errorf("spn.Token().ExpiresIn: expected=\"\", actual=%s", spn.Token().ExpiresIn)
|
||||
if spn.Token.ExpiresIn != "" {
|
||||
t.Errorf("spn.Token.ExpiresIn: expected=\"\", actual=%s", spn.Token.ExpiresIn)
|
||||
}
|
||||
if spn.Token().ExpiresOn != "" {
|
||||
t.Errorf("spn.Token().ExpiresOn: expected=\"\", actual=%s", spn.Token().ExpiresOn)
|
||||
if spn.Token.ExpiresOn != "" {
|
||||
t.Errorf("spn.Token.ExpiresOn: expected=\"\", actual=%s", spn.Token.ExpiresOn)
|
||||
}
|
||||
if spn.Token().NotBefore != "" {
|
||||
t.Errorf("spn.Token().NotBefore: expected=\"\", actual=%s", spn.Token().NotBefore)
|
||||
if spn.Token.NotBefore != "" {
|
||||
t.Errorf("spn.Token.NotBefore: expected=\"\", actual=%s", spn.Token.NotBefore)
|
||||
}
|
||||
if spn.Token().Resource != "" {
|
||||
t.Errorf("spn.Token().Resource: expected=\"\", actual=%s", spn.Token().Resource)
|
||||
if spn.Token.Resource != "" {
|
||||
t.Errorf("spn.Token.Resource: expected=\"\", actual=%s", spn.Token.Resource)
|
||||
}
|
||||
if spn.Token().Type != "" {
|
||||
t.Errorf("spn.Token().Type: expected=\"\", actual=%s", spn.Token().Type)
|
||||
if spn.Token.Type != "" {
|
||||
t.Errorf("spn.Token.Type: expected=\"\", actual=%s", spn.Token.Type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package arm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
@@ -10,10 +9,11 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-01-01/network"
|
||||
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources"
|
||||
armStorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2017-10-01/storage"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/disk"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/network"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
|
||||
armStorage "github.com/Azure/azure-sdk-for-go/arm/storage"
|
||||
"github.com/Azure/azure-sdk-for-go/storage"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
@@ -39,7 +39,7 @@ type AzureClient struct {
|
||||
compute.VirtualMachinesClient
|
||||
common.VaultClient
|
||||
armStorage.AccountsClient
|
||||
compute.DisksClient
|
||||
disk.DisksClient
|
||||
|
||||
InspectorMaxLength int
|
||||
Template *CaptureTemplate
|
||||
@@ -141,7 +141,7 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string
|
||||
azureClient.DeploymentOperationsClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
|
||||
azureClient.DeploymentOperationsClient.UserAgent = fmt.Sprintf("%s %s", useragent.String(), azureClient.DeploymentOperationsClient.UserAgent)
|
||||
|
||||
azureClient.DisksClient = compute.NewDisksClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
|
||||
azureClient.DisksClient = disk.NewDisksClientWithBaseURI(cloud.ResourceManagerEndpoint, subscriptionID)
|
||||
azureClient.DisksClient.Authorizer = autorest.NewBearerAuthorizer(servicePrincipalToken)
|
||||
azureClient.DisksClient.RequestInspector = withInspection(maxlen)
|
||||
azureClient.DisksClient.ResponseInspector = byConcatDecorators(byInspecting(maxlen), errorCapture(azureClient))
|
||||
@@ -222,7 +222,7 @@ func NewAzureClient(subscriptionID, resourceGroupName, storageAccountName string
|
||||
|
||||
// If this is a managed disk build, this should be ignored.
|
||||
if resourceGroupName != "" && storageAccountName != "" {
|
||||
accountKeys, err := azureClient.AccountsClient.ListKeys(context.TODO(), resourceGroupName, storageAccountName)
|
||||
accountKeys, err := azureClient.AccountsClient.ListKeys(resourceGroupName, storageAccountName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package arm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -10,13 +9,13 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
armstorage "github.com/Azure/azure-sdk-for-go/services/storage/mgmt/2017-10-01/storage"
|
||||
"github.com/Azure/azure-sdk-for-go/storage"
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
packerAzureCommon "github.com/hashicorp/packer/builder/azure/common"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/builder/azure/common/lin"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/arm/storage"
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
packerCommon "github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
@@ -24,15 +23,15 @@ import (
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
config *Config
|
||||
stateBag multistep.StateBag
|
||||
runner multistep.Runner
|
||||
ctxCancel context.CancelFunc
|
||||
config *Config
|
||||
stateBag multistep.StateBag
|
||||
runner multistep.Runner
|
||||
}
|
||||
|
||||
const (
|
||||
DefaultSasBlobContainer = "system/Microsoft.Compute"
|
||||
DefaultSecretName = "packerKeyVaultSecret"
|
||||
DefaultSasBlobContainer = "system/Microsoft.Compute"
|
||||
DefaultSasBlobPermission = "r"
|
||||
DefaultSecretName = "packerKeyVaultSecret"
|
||||
)
|
||||
|
||||
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
@@ -52,13 +51,8 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
}
|
||||
|
||||
func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
|
||||
|
||||
ui.Say("Running builder ...")
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
b.ctxCancel = cancel
|
||||
defer cancel()
|
||||
|
||||
if err := newConfigRetriever().FillParameters(b.config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -91,18 +85,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
if err := resolver.Resolve(b.config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if b.config.ObjectID == "" {
|
||||
b.config.ObjectID = getObjectIdFromToken(ui, spnCloud)
|
||||
} else {
|
||||
ui.Message("You have provided Object_ID which is no longer needed, azure packer builder determines this dynamically from the authentication token")
|
||||
}
|
||||
|
||||
if b.config.ObjectID == "" && b.config.OSType != constants.Target_Linux {
|
||||
return nil, fmt.Errorf("could not determine the ObjectID for the user, which is required for Windows builds")
|
||||
}
|
||||
|
||||
if b.config.isManagedImage() {
|
||||
group, err := azureClient.GroupsClient.Get(ctx, b.config.ManagedImageResourceGroupName)
|
||||
group, err := azureClient.GroupsClient.Get(b.config.ManagedImageResourceGroupName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot locate the managed image resource group %s.", b.config.ManagedImageResourceGroupName)
|
||||
}
|
||||
@@ -110,14 +95,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
b.config.manageImageLocation = *group.Location
|
||||
|
||||
// If a managed image already exists it cannot be overwritten.
|
||||
_, err = azureClient.ImagesClient.Get(ctx, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, "")
|
||||
_, err = azureClient.ImagesClient.Get(b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, "")
|
||||
if err == nil {
|
||||
if b.config.PackerForce {
|
||||
_, errChan := azureClient.ImagesClient.Delete(b.config.ManagedImageResourceGroupName, b.config.ManagedImageName, nil)
|
||||
ui.Say(fmt.Sprintf("the managed image named %s already exists, but deleting it due to -force flag", b.config.ManagedImageName))
|
||||
f, err := azureClient.ImagesClient.Delete(ctx, b.config.ManagedImageResourceGroupName, b.config.ManagedImageName)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, azureClient.ImagesClient.Client)
|
||||
}
|
||||
err = <-errChan
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to delete the managed image named %s : %s", b.config.ManagedImageName, azureClient.LastError.Error())
|
||||
}
|
||||
@@ -125,13 +108,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
return nil, fmt.Errorf("the managed image named %s already exists in the resource group %s, use the -force option to automatically delete it.", b.config.ManagedImageName, b.config.ManagedImageResourceGroupName)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// User is not using Managed Images to build, warning message here that this path is being deprecated
|
||||
ui.Error("Warning: You are using Azure Packer Builder to create VHDs which is being deprecated, consider using Managed Images. Learn more http://aka.ms/packermanagedimage")
|
||||
}
|
||||
|
||||
if b.config.BuildResourceGroupName != "" {
|
||||
group, err := azureClient.GroupsClient.Get(ctx, b.config.BuildResourceGroupName)
|
||||
group, err := azureClient.GroupsClient.Get(b.config.BuildResourceGroupName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot locate the existing build resource resource group %s.", b.config.BuildResourceGroupName)
|
||||
}
|
||||
@@ -140,7 +120,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
}
|
||||
|
||||
if b.config.StorageAccount != "" {
|
||||
account, err := b.getBlobAccount(ctx, azureClient, b.config.ResourceGroupName, b.config.StorageAccount)
|
||||
account, err := b.getBlobAccount(azureClient, b.config.ResourceGroupName, b.config.StorageAccount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -197,8 +177,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
NewStepDeployTemplate(azureClient, ui, b.config, deploymentName, GetVirtualMachineDeployment),
|
||||
NewStepGetIPAddress(azureClient, ui, endpointConnectType),
|
||||
&StepSaveWinRMPassword{
|
||||
Password: b.config.tmpAdminPassword,
|
||||
BuildName: b.config.PackerBuildName,
|
||||
Password: b.config.tmpAdminPassword,
|
||||
},
|
||||
&communicator.StepConnectWinRM{
|
||||
Config: &b.config.Comm,
|
||||
@@ -260,11 +239,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
return NewArtifact(
|
||||
template.(*CaptureTemplate),
|
||||
func(name string) string {
|
||||
month := time.Now().AddDate(0, 1, 0).UTC()
|
||||
blob := azureClient.BlobStorageClient.GetContainerReference(DefaultSasBlobContainer).GetBlobReference(name)
|
||||
options := storage.BlobSASOptions{}
|
||||
options.BlobServiceSASPermissions.Read = true
|
||||
options.Expiry = time.Now().AddDate(0, 1, 0).UTC() // one month
|
||||
sasUrl, _ := blob.GetSASURI(options)
|
||||
sasUrl, _ := blob.GetSASURI(month, DefaultSasBlobPermission)
|
||||
return sasUrl
|
||||
})
|
||||
}
|
||||
@@ -302,10 +279,6 @@ func (b *Builder) isPrivateNetworkCommunication() bool {
|
||||
}
|
||||
|
||||
func (b *Builder) Cancel() {
|
||||
if b.ctxCancel != nil {
|
||||
log.Printf("Cancelling Azure builder...")
|
||||
b.ctxCancel()
|
||||
}
|
||||
if b.runner != nil {
|
||||
log.Println("Cancelling the step runner...")
|
||||
b.runner.Cancel()
|
||||
@@ -320,8 +293,8 @@ func canonicalizeLocation(location string) string {
|
||||
return strings.Replace(location, " ", "", -1)
|
||||
}
|
||||
|
||||
func (b *Builder) getBlobAccount(ctx context.Context, client *AzureClient, resourceGroupName string, storageAccountName string) (*armstorage.Account, error) {
|
||||
account, err := client.AccountsClient.GetProperties(ctx, resourceGroupName, storageAccountName)
|
||||
func (b *Builder) getBlobAccount(client *AzureClient, resourceGroupName string, storageAccountName string) (*storage.Account, error) {
|
||||
account, err := client.AccountsClient.GetProperties(resourceGroupName, storageAccountName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -333,7 +306,7 @@ func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
|
||||
stateBag.Put(constants.AuthorizedKey, b.config.sshAuthorizedKey)
|
||||
stateBag.Put(constants.PrivateKey, b.config.sshPrivateKey)
|
||||
|
||||
stateBag.Put(constants.ArmTags, b.config.AzureTags)
|
||||
stateBag.Put(constants.ArmTags, &b.config.AzureTags)
|
||||
stateBag.Put(constants.ArmComputeName, b.config.tmpComputeName)
|
||||
stateBag.Put(constants.ArmDeploymentName, b.config.tmpDeploymentName)
|
||||
if b.config.OSType == constants.Target_Windows {
|
||||
@@ -357,7 +330,6 @@ func (b *Builder) configureStateBag(stateBag multistep.StateBag) {
|
||||
stateBag.Put(constants.ArmIsManagedImage, b.config.isManagedImage())
|
||||
stateBag.Put(constants.ArmManagedImageResourceGroupName, b.config.ManagedImageResourceGroupName)
|
||||
stateBag.Put(constants.ArmManagedImageName, b.config.ManagedImageName)
|
||||
stateBag.Put(constants.ArmAsyncResourceGroupDelete, b.config.AsyncResourceGroupDelete)
|
||||
}
|
||||
|
||||
// Parameters that are only known at runtime after querying Azure.
|
||||
@@ -381,17 +353,10 @@ func (b *Builder) getServicePrincipalTokens(say func(string)) (*adal.ServicePrin
|
||||
var err error
|
||||
|
||||
if b.config.useDeviceLogin {
|
||||
say("Getting auth token for Service management endpoint")
|
||||
servicePrincipalToken, err = packerAzureCommon.Authenticate(*b.config.cloudEnvironment, b.config.TenantID, say, b.config.cloudEnvironment.ServiceManagementEndpoint)
|
||||
servicePrincipalToken, err = packerAzureCommon.Authenticate(*b.config.cloudEnvironment, b.config.TenantID, say)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
say("Getting token for Vault resource")
|
||||
servicePrincipalTokenVault, err = packerAzureCommon.Authenticate(*b.config.cloudEnvironment, b.config.TenantID, say, strings.TrimRight(b.config.cloudEnvironment.KeyVaultEndpoint, "/"))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
auth := NewAuthenticate(*b.config.cloudEnvironment, b.config.ClientID, b.config.ClientSecret, b.config.TenantID)
|
||||
|
||||
@@ -402,39 +367,11 @@ func (b *Builder) getServicePrincipalTokens(say func(string)) (*adal.ServicePrin
|
||||
|
||||
servicePrincipalTokenVault, err = auth.getServicePrincipalTokenWithResource(
|
||||
strings.TrimRight(b.config.cloudEnvironment.KeyVaultEndpoint, "/"))
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
err = servicePrincipalToken.EnsureFresh()
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = servicePrincipalTokenVault.EnsureFresh()
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return servicePrincipalToken, servicePrincipalTokenVault, nil
|
||||
}
|
||||
|
||||
func getObjectIdFromToken(ui packer.Ui, token *adal.ServicePrincipalToken) string {
|
||||
claims := jwt.MapClaims{}
|
||||
var p jwt.Parser
|
||||
|
||||
var err error
|
||||
|
||||
_, _, err = p.ParseUnverified(token.OAuthToken(), claims)
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Failed to parse the token,Error: %s", err.Error()))
|
||||
return ""
|
||||
}
|
||||
return claims["oid"].(string)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
package arm
|
||||
|
||||
// these tests require the following variables to be set,
|
||||
// although some test will only use a subset:
|
||||
//
|
||||
// * ARM_CLIENT_ID
|
||||
// * ARM_CLIENT_SECRET
|
||||
// * ARM_SUBSCRIPTION_ID
|
||||
// * ARM_OBJECT_ID
|
||||
// * ARM_STORAGE_ACCOUNT
|
||||
//
|
||||
// The subscription in question should have a resource group
|
||||
// called "packer-acceptance-test" in "South Central US" region. The
|
||||
// storage account refered to in the above variable should
|
||||
// be inside this resource group and in "South Central US" as well.
|
||||
//
|
||||
// In addition, the PACKER_ACC variable should also be set to
|
||||
// a non-empty value to enable Packer acceptance tests and the
|
||||
// options "-v -timeout 90m" should be provided to the test
|
||||
// command, e.g.:
|
||||
// go test -v -timeout 90m -run TestBuilderAcc_.*
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"fmt"
|
||||
builderT "github.com/hashicorp/packer/helper/builder/testing"
|
||||
"os"
|
||||
)
|
||||
|
||||
const DeviceLoginAcceptanceTest = "DEVICELOGIN_TEST"
|
||||
|
||||
func TestBuilderAcc_ManagedDisk_Windows(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccManagedDiskWindows,
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_ManagedDisk_Windows_DeviceLogin(t *testing.T) {
|
||||
if os.Getenv(DeviceLoginAcceptanceTest) == "" {
|
||||
t.Skip(fmt.Sprintf(
|
||||
"Device Login Acceptance tests skipped unless env '%s' set, as its requires manual step during execution",
|
||||
DeviceLoginAcceptanceTest))
|
||||
return
|
||||
}
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccManagedDiskWindowsDeviceLogin,
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_ManagedDisk_Linux(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccManagedDiskLinux,
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_ManagedDisk_Linux_DeviceLogin(t *testing.T) {
|
||||
if os.Getenv(DeviceLoginAcceptanceTest) == "" {
|
||||
t.Skip(fmt.Sprintf(
|
||||
"Device Login Acceptance tests skipped unless env '%s' set, as its requires manual step during execution",
|
||||
DeviceLoginAcceptanceTest))
|
||||
return
|
||||
}
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccManagedDiskLinuxDeviceLogin,
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_Blob_Windows(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccBlobWindows,
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuilderAcc_Blob_Linux(t *testing.T) {
|
||||
builderT.Test(t, builderT.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Builder: &Builder{},
|
||||
Template: testBuilderAccBlobLinux,
|
||||
})
|
||||
}
|
||||
|
||||
func testAccPreCheck(*testing.T) {}
|
||||
|
||||
const testBuilderAccManagedDiskWindows = `
|
||||
{
|
||||
"variables": {
|
||||
"client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}",
|
||||
"client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}",
|
||||
"subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}"
|
||||
},
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
|
||||
"client_id": "{{user ` + "`client_id`" + `}}",
|
||||
"client_secret": "{{user ` + "`client_secret`" + `}}",
|
||||
"subscription_id": "{{user ` + "`subscription_id`" + `}}",
|
||||
|
||||
"managed_image_resource_group_name": "packer-acceptance-test",
|
||||
"managed_image_name": "testBuilderAccManagedDiskWindows-{{timestamp}}",
|
||||
|
||||
"os_type": "Windows",
|
||||
"image_publisher": "MicrosoftWindowsServer",
|
||||
"image_offer": "WindowsServer",
|
||||
"image_sku": "2012-R2-Datacenter",
|
||||
|
||||
"communicator": "winrm",
|
||||
"winrm_use_ssl": "true",
|
||||
"winrm_insecure": "true",
|
||||
"winrm_timeout": "3m",
|
||||
"winrm_username": "packer",
|
||||
"async_resourcegroup_delete": "true",
|
||||
|
||||
"location": "South Central US",
|
||||
"vm_size": "Standard_DS2_v2"
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccManagedDiskWindowsDeviceLogin = `
|
||||
{
|
||||
"variables": {
|
||||
"subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}"
|
||||
},
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
|
||||
"subscription_id": "{{user ` + "`subscription_id`" + `}}",
|
||||
|
||||
"managed_image_resource_group_name": "packer-acceptance-test",
|
||||
"managed_image_name": "testBuilderAccManagedDiskWindowsDeviceLogin-{{timestamp}}",
|
||||
|
||||
"os_type": "Windows",
|
||||
"image_publisher": "MicrosoftWindowsServer",
|
||||
"image_offer": "WindowsServer",
|
||||
"image_sku": "2012-R2-Datacenter",
|
||||
|
||||
"communicator": "winrm",
|
||||
"winrm_use_ssl": "true",
|
||||
"winrm_insecure": "true",
|
||||
"winrm_timeout": "3m",
|
||||
"winrm_username": "packer",
|
||||
|
||||
"location": "South Central US",
|
||||
"vm_size": "Standard_DS2_v2"
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccManagedDiskLinux = `
|
||||
{
|
||||
"variables": {
|
||||
"client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}",
|
||||
"client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}",
|
||||
"subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}"
|
||||
},
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
|
||||
"client_id": "{{user ` + "`client_id`" + `}}",
|
||||
"client_secret": "{{user ` + "`client_secret`" + `}}",
|
||||
"subscription_id": "{{user ` + "`subscription_id`" + `}}",
|
||||
|
||||
"managed_image_resource_group_name": "packer-acceptance-test",
|
||||
"managed_image_name": "testBuilderAccManagedDiskLinux-{{timestamp}}",
|
||||
|
||||
"os_type": "Linux",
|
||||
"image_publisher": "Canonical",
|
||||
"image_offer": "UbuntuServer",
|
||||
"image_sku": "16.04-LTS",
|
||||
|
||||
"location": "South Central US",
|
||||
"vm_size": "Standard_DS2_v2"
|
||||
}]
|
||||
}
|
||||
`
|
||||
const testBuilderAccManagedDiskLinuxDeviceLogin = `
|
||||
{
|
||||
"variables": {
|
||||
"subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}"
|
||||
},
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
|
||||
"subscription_id": "{{user ` + "`subscription_id`" + `}}",
|
||||
|
||||
"managed_image_resource_group_name": "packer-acceptance-test",
|
||||
"managed_image_name": "testBuilderAccManagedDiskLinuxDeviceLogin-{{timestamp}}",
|
||||
|
||||
"os_type": "Linux",
|
||||
"image_publisher": "Canonical",
|
||||
"image_offer": "UbuntuServer",
|
||||
"image_sku": "16.04-LTS",
|
||||
"async_resourcegroup_delete": "true",
|
||||
|
||||
"location": "South Central US",
|
||||
"vm_size": "Standard_DS2_v2"
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccBlobWindows = `
|
||||
{
|
||||
"variables": {
|
||||
"client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}",
|
||||
"client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}",
|
||||
"subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}",
|
||||
"object_id": "{{env ` + "`ARM_OBJECT_ID`" + `}}",
|
||||
"storage_account": "{{env ` + "`ARM_STORAGE_ACCOUNT`" + `}}"
|
||||
},
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
|
||||
"client_id": "{{user ` + "`client_id`" + `}}",
|
||||
"client_secret": "{{user ` + "`client_secret`" + `}}",
|
||||
"subscription_id": "{{user ` + "`subscription_id`" + `}}",
|
||||
"object_id": "{{user ` + "`object_id`" + `}}",
|
||||
|
||||
"storage_account": "{{user ` + "`storage_account`" + `}}",
|
||||
"resource_group_name": "packer-acceptance-test",
|
||||
"capture_container_name": "test",
|
||||
"capture_name_prefix": "testBuilderAccBlobWin",
|
||||
|
||||
"os_type": "Windows",
|
||||
"image_publisher": "MicrosoftWindowsServer",
|
||||
"image_offer": "WindowsServer",
|
||||
"image_sku": "2012-R2-Datacenter",
|
||||
|
||||
"communicator": "winrm",
|
||||
"winrm_use_ssl": "true",
|
||||
"winrm_insecure": "true",
|
||||
"winrm_timeout": "3m",
|
||||
"winrm_username": "packer",
|
||||
|
||||
"location": "South Central US",
|
||||
"vm_size": "Standard_DS2_v2"
|
||||
}]
|
||||
}
|
||||
`
|
||||
|
||||
const testBuilderAccBlobLinux = `
|
||||
{
|
||||
"variables": {
|
||||
"client_id": "{{env ` + "`ARM_CLIENT_ID`" + `}}",
|
||||
"client_secret": "{{env ` + "`ARM_CLIENT_SECRET`" + `}}",
|
||||
"subscription_id": "{{env ` + "`ARM_SUBSCRIPTION_ID`" + `}}",
|
||||
"storage_account": "{{env ` + "`ARM_STORAGE_ACCOUNT`" + `}}"
|
||||
},
|
||||
"builders": [{
|
||||
"type": "test",
|
||||
|
||||
"client_id": "{{user ` + "`client_id`" + `}}",
|
||||
"client_secret": "{{user ` + "`client_secret`" + `}}",
|
||||
"subscription_id": "{{user ` + "`subscription_id`" + `}}",
|
||||
|
||||
"storage_account": "{{user ` + "`storage_account`" + `}}",
|
||||
"resource_group_name": "packer-acceptance-test",
|
||||
"capture_container_name": "test",
|
||||
"capture_name_prefix": "testBuilderAccBlobLinux",
|
||||
|
||||
"os_type": "Linux",
|
||||
"image_publisher": "Canonical",
|
||||
"image_offer": "UbuntuServer",
|
||||
"image_sku": "16.04-LTS",
|
||||
|
||||
"location": "South Central US",
|
||||
"vm_size": "Standard_DS2_v2"
|
||||
}]
|
||||
}
|
||||
`
|
||||
@@ -25,7 +25,6 @@ func TestStateBagShouldBePopulatedExpectedValues(t *testing.T) {
|
||||
constants.ArmStorageAccountName,
|
||||
constants.ArmVirtualMachineCaptureParameters,
|
||||
constants.ArmPublicIPAddressName,
|
||||
constants.ArmAsyncResourceGroupDelete,
|
||||
}
|
||||
|
||||
for _, v := range expectedStateBagKeys {
|
||||
|
||||
+11
-11
@@ -14,7 +14,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
"github.com/masterzen/winrm"
|
||||
@@ -151,9 +151,6 @@ type Config struct {
|
||||
|
||||
Comm communicator.Config `mapstructure:",squash"`
|
||||
ctx *interpolate.Context
|
||||
|
||||
//Cleanup
|
||||
AsyncResourceGroupDelete bool `mapstructure:"async_resourcegroup_delete"`
|
||||
}
|
||||
|
||||
type keyVaultCertificate struct {
|
||||
@@ -192,7 +189,7 @@ func (c *Config) toImageParameters() *compute.Image {
|
||||
},
|
||||
},
|
||||
Location: to.StringPtr(c.Location),
|
||||
Tags: c.AzureTags,
|
||||
Tags: &c.AzureTags,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +359,7 @@ func setRuntimeValues(c *Config) {
|
||||
|
||||
c.tmpAdminPassword = tempName.AdminPassword
|
||||
// store so that we can access this later during provisioning
|
||||
commonhelper.SetSharedState("winrm_password", c.tmpAdminPassword, c.PackerConfig.PackerBuildName)
|
||||
commonhelper.SetSharedState("winrm_password", c.tmpAdminPassword)
|
||||
|
||||
c.tmpCertificatePassword = tempName.CertificatePassword
|
||||
if c.TempComputeName == "" {
|
||||
@@ -453,7 +450,7 @@ func provideDefaultValues(c *Config) {
|
||||
}
|
||||
|
||||
if c.ManagedImageStorageAccountType == "" {
|
||||
c.managedImageStorageAccountType = compute.StorageAccountTypesStandardLRS
|
||||
c.managedImageStorageAccountType = compute.StandardLRS
|
||||
}
|
||||
|
||||
if c.ImagePublisher != "" && c.ImageVersion == "" {
|
||||
@@ -493,6 +490,9 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
|
||||
// readable by the ObjectID of the App. There may be another way to handle
|
||||
// this case, but I am not currently aware of it - send feedback.
|
||||
isUseDeviceLogin := func(c *Config) bool {
|
||||
if c.OSType == constants.Target_Windows {
|
||||
return false
|
||||
}
|
||||
|
||||
return c.SubscriptionID != "" &&
|
||||
c.ClientID == "" &&
|
||||
@@ -697,10 +697,10 @@ func assertRequiredParametersSet(c *Config, errs *packer.MultiError) {
|
||||
}
|
||||
|
||||
switch c.ManagedImageStorageAccountType {
|
||||
case "", string(compute.StorageAccountTypesStandardLRS):
|
||||
c.managedImageStorageAccountType = compute.StorageAccountTypesStandardLRS
|
||||
case string(compute.StorageAccountTypesPremiumLRS):
|
||||
c.managedImageStorageAccountType = compute.StorageAccountTypesPremiumLRS
|
||||
case "", string(compute.StandardLRS):
|
||||
c.managedImageStorageAccountType = compute.StandardLRS
|
||||
case string(compute.PremiumLRS):
|
||||
c.managedImageStorageAccountType = compute.PremiumLRS
|
||||
default:
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("The managed_image_storage_account_type %q is invalid", c.ManagedImageStorageAccountType))
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ package arm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
// List of configuration parameters that are required by the ARM builder.
|
||||
@@ -84,7 +86,7 @@ func TestConfigShouldBeAbleToOverrideDefaultedValues(t *testing.T) {
|
||||
t.Errorf("Expected 'vm_size' to be set to 'override_vm_size', but found %q!", c.VMSize)
|
||||
}
|
||||
|
||||
if c.managedImageStorageAccountType != compute.StorageAccountTypesPremiumLRS {
|
||||
if c.managedImageStorageAccountType != compute.PremiumLRS {
|
||||
t.Errorf("Expected 'managed_image_storage_account_type' to be set to 'Premium_LRS', but found %q!", c.managedImageStorageAccountType)
|
||||
}
|
||||
}
|
||||
@@ -446,6 +448,39 @@ func TestUserDeviceLoginIsEnabledForLinux(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUseDeviceLoginIsDisabledForWindows(t *testing.T) {
|
||||
config := map[string]string{
|
||||
"capture_name_prefix": "ignore",
|
||||
"capture_container_name": "ignore",
|
||||
"image_offer": "ignore",
|
||||
"image_publisher": "ignore",
|
||||
"image_sku": "ignore",
|
||||
"location": "ignore",
|
||||
"storage_account": "ignore",
|
||||
"resource_group_name": "ignore",
|
||||
"subscription_id": "ignore",
|
||||
"os_type": constants.Target_Windows,
|
||||
"communicator": "none",
|
||||
}
|
||||
|
||||
_, _, err := newConfig(config, getPackerConfiguration())
|
||||
if err == nil {
|
||||
t.Fatal("Expected test to fail, but it succeeded")
|
||||
}
|
||||
|
||||
multiError, _ := err.(*packer.MultiError)
|
||||
if len(multiError.Errors) != 2 {
|
||||
t.Errorf("Expected to find 2 errors, but found %d errors", len(multiError.Errors))
|
||||
}
|
||||
|
||||
if !strings.Contains(err.Error(), "client_id must be specified") {
|
||||
t.Error("Expected to find error for 'client_id must be specified")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "client_secret must be specified") {
|
||||
t.Error("Expected to find error for 'client_secret must be specified")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigShouldRejectMalformedCaptureNamePrefix(t *testing.T) {
|
||||
config := map[string]string{
|
||||
"capture_container_name": "ignore",
|
||||
@@ -1229,73 +1264,6 @@ func TestConfigShouldAllowTempNameOverrides(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigShouldAllowAsyncResourceGroupOverride(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"image_offer": "ignore",
|
||||
"image_publisher": "ignore",
|
||||
"image_sku": "ignore",
|
||||
"location": "ignore",
|
||||
"subscription_id": "ignore",
|
||||
"communicator": "none",
|
||||
"os_type": "linux",
|
||||
"managed_image_name": "ignore",
|
||||
"managed_image_resource_group_name": "ignore",
|
||||
"async_resourcegroup_delete": "true",
|
||||
}
|
||||
|
||||
c, _, err := newConfig(config, getPackerConfiguration())
|
||||
if err != nil {
|
||||
t.Errorf("newConfig failed with %q", err)
|
||||
}
|
||||
|
||||
if c.AsyncResourceGroupDelete != true {
|
||||
t.Errorf("expected async_resourcegroup_delete to be %q, but got %t", "async_resourcegroup_delete", c.AsyncResourceGroupDelete)
|
||||
}
|
||||
}
|
||||
func TestConfigShouldAllowAsyncResourceGroupOverrideNoValue(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"image_offer": "ignore",
|
||||
"image_publisher": "ignore",
|
||||
"image_sku": "ignore",
|
||||
"location": "ignore",
|
||||
"subscription_id": "ignore",
|
||||
"communicator": "none",
|
||||
"os_type": "linux",
|
||||
"managed_image_name": "ignore",
|
||||
"managed_image_resource_group_name": "ignore",
|
||||
}
|
||||
|
||||
c, _, err := newConfig(config, getPackerConfiguration())
|
||||
if err != nil {
|
||||
t.Errorf("newConfig failed with %q", err)
|
||||
}
|
||||
|
||||
if c.AsyncResourceGroupDelete != false {
|
||||
t.Errorf("expected async_resourcegroup_delete to be %q, but got %t", "async_resourcegroup_delete", c.AsyncResourceGroupDelete)
|
||||
}
|
||||
}
|
||||
func TestConfigShouldAllowAsyncResourceGroupOverrideBadValue(t *testing.T) {
|
||||
config := map[string]interface{}{
|
||||
"image_offer": "ignore",
|
||||
"image_publisher": "ignore",
|
||||
"image_sku": "ignore",
|
||||
"location": "ignore",
|
||||
"subscription_id": "ignore",
|
||||
"communicator": "none",
|
||||
"os_type": "linux",
|
||||
"managed_image_name": "ignore",
|
||||
"managed_image_resource_group_name": "ignore",
|
||||
"async_resourcegroup_delete": "asdasda",
|
||||
}
|
||||
|
||||
c, _, err := newConfig(config, getPackerConfiguration())
|
||||
if err != nil && c == nil {
|
||||
t.Log("newConfig failed which is expected ", err)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getArmBuilderConfiguration() map[string]string {
|
||||
m := make(map[string]string)
|
||||
for _, v := range requiredConfigValues {
|
||||
|
||||
@@ -9,11 +9,10 @@ package arm
|
||||
// used to determine values without use of a client.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
)
|
||||
|
||||
type resourceResolver struct {
|
||||
@@ -73,40 +72,33 @@ func getResourceGroupNameFromId(id string) string {
|
||||
}
|
||||
|
||||
func findManagedImageByName(client *AzureClient, name, resourceGroupName string) (*compute.Image, error) {
|
||||
images, err := client.ImagesClient.ListByResourceGroupComplete(context.TODO(), resourceGroupName)
|
||||
images, err := client.ImagesClient.ListByResourceGroup(resourceGroupName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for images.NotDone() {
|
||||
image := images.Value()
|
||||
for _, image := range *images.Value {
|
||||
if strings.EqualFold(name, *image.Name) {
|
||||
return &image, nil
|
||||
}
|
||||
if err = images.Next(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Cannot find an image named '%s' in the resource group '%s'", name, resourceGroupName)
|
||||
}
|
||||
|
||||
func findVirtualNetworkResourceGroup(client *AzureClient, name string) (string, error) {
|
||||
virtualNetworks, err := client.VirtualNetworksClient.ListAllComplete(context.TODO())
|
||||
virtualNetworks, err := client.VirtualNetworksClient.ListAll()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
resourceGroupNames := make([]string, 0)
|
||||
for virtualNetworks.NotDone() {
|
||||
virtualNetwork := virtualNetworks.Value()
|
||||
|
||||
for _, virtualNetwork := range *virtualNetworks.Value {
|
||||
if strings.EqualFold(name, *virtualNetwork.Name) {
|
||||
rgn := getResourceGroupNameFromId(*virtualNetwork.ID)
|
||||
resourceGroupNames = append(resourceGroupNames, rgn)
|
||||
}
|
||||
if err = virtualNetworks.Next(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if len(resourceGroupNames) == 0 {
|
||||
@@ -121,21 +113,19 @@ func findVirtualNetworkResourceGroup(client *AzureClient, name string) (string,
|
||||
}
|
||||
|
||||
func findVirtualNetworkSubnet(client *AzureClient, resourceGroupName string, name string) (string, error) {
|
||||
subnets, err := client.SubnetsClient.List(context.TODO(), resourceGroupName, name)
|
||||
subnets, err := client.SubnetsClient.List(resourceGroupName, name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
subnetList := subnets.Values() // only first page of subnets, but only interested in ==0 or >1
|
||||
|
||||
if len(subnetList) == 0 {
|
||||
if len(*subnets.Value) == 0 {
|
||||
return "", fmt.Errorf("Cannot find a subnet in the resource group %q associated with the virtual network called %q", resourceGroupName, name)
|
||||
}
|
||||
|
||||
if len(subnetList) > 1 {
|
||||
return "", fmt.Errorf("Found multiple subnets in the resource group %q associated with the virtual network called %q, please use virtual_network_subnet_name and virtual_network_resource_group_name to disambiguate", resourceGroupName, name)
|
||||
if len(*subnets.Value) > 1 {
|
||||
return "", fmt.Errorf("Found multiple subnets in the resource group %q associated with the virtual network called %q, please use virtual_network_subnet_name and virtual_network_resource_group_name to disambiguate", resourceGroupName, name)
|
||||
}
|
||||
|
||||
subnet := subnetList[0]
|
||||
subnet := (*subnets.Value)[0]
|
||||
return *subnet.Name, nil
|
||||
}
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
package arm
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/packer/builder/azure/common"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
)
|
||||
|
||||
func processInterruptibleResult(
|
||||
result common.InterruptibleTaskResult, sayError func(error), state multistep.StateBag) multistep.StepAction {
|
||||
if result.IsCancelled {
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
return processStepResult(result.Err, sayError, state)
|
||||
}
|
||||
|
||||
func processStepResult(
|
||||
err error, sayError func(error), state multistep.StateBag) multistep.StepAction {
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/hashicorp/packer/builder/azure/common"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
@@ -13,8 +14,8 @@ import (
|
||||
type StepCaptureImage struct {
|
||||
client *AzureClient
|
||||
generalizeVM func(resourceGroupName, computeName string) error
|
||||
captureVhd func(ctx context.Context, resourceGroupName string, computeName string, parameters *compute.VirtualMachineCaptureParameters) error
|
||||
captureManagedImage func(ctx context.Context, resourceGroupName string, computeName string, parameters *compute.Image) error
|
||||
captureVhd func(resourceGroupName string, computeName string, parameters *compute.VirtualMachineCaptureParameters, cancelCh <-chan struct{}) error
|
||||
captureManagedImage func(resourceGroupName string, computeName string, parameters *compute.Image, cancelCh <-chan struct{}) error
|
||||
get func(client *AzureClient) *CaptureTemplate
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
@@ -42,30 +43,32 @@ func NewStepCaptureImage(client *AzureClient, ui packer.Ui) *StepCaptureImage {
|
||||
}
|
||||
|
||||
func (s *StepCaptureImage) generalize(resourceGroupName string, computeName string) error {
|
||||
_, err := s.client.Generalize(context.TODO(), resourceGroupName, computeName)
|
||||
_, err := s.client.Generalize(resourceGroupName, computeName)
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepCaptureImage) captureImageFromVM(ctx context.Context, resourceGroupName string, imageName string, image *compute.Image) error {
|
||||
f, err := s.client.ImagesClient.CreateOrUpdate(ctx, resourceGroupName, imageName, *image)
|
||||
func (s *StepCaptureImage) captureImageFromVM(resourceGroupName string, imageName string, image *compute.Image, cancelCh <-chan struct{}) error {
|
||||
_, errChan := s.client.ImagesClient.CreateOrUpdate(resourceGroupName, imageName, *image, cancelCh)
|
||||
err := <-errChan
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
}
|
||||
return f.WaitForCompletion(ctx, s.client.ImagesClient.Client)
|
||||
return <-errChan
|
||||
}
|
||||
|
||||
func (s *StepCaptureImage) captureImage(ctx context.Context, resourceGroupName string, computeName string, parameters *compute.VirtualMachineCaptureParameters) error {
|
||||
f, err := s.client.VirtualMachinesClient.Capture(ctx, resourceGroupName, computeName, *parameters)
|
||||
func (s *StepCaptureImage) captureImage(resourceGroupName string, computeName string, parameters *compute.VirtualMachineCaptureParameters, cancelCh <-chan struct{}) error {
|
||||
_, errChan := s.client.Capture(resourceGroupName, computeName, *parameters, cancelCh)
|
||||
err := <-errChan
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
}
|
||||
return f.WaitForCompletion(ctx, s.client.VirtualMachinesClient.Client)
|
||||
return <-errChan
|
||||
}
|
||||
|
||||
func (s *StepCaptureImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepCaptureImage) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Capturing image ...")
|
||||
|
||||
var computeName = state.Get(constants.ArmComputeName).(string)
|
||||
@@ -83,37 +86,38 @@ func (s *StepCaptureImage) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
s.say(fmt.Sprintf(" -> Compute Name : '%s'", computeName))
|
||||
s.say(fmt.Sprintf(" -> Compute Location : '%s'", location))
|
||||
|
||||
err := s.generalizeVM(resourceGroupName, computeName)
|
||||
result := common.StartInterruptibleTask(
|
||||
func() bool {
|
||||
return common.IsStateCancelled(state)
|
||||
},
|
||||
func(cancelCh <-chan struct{}) error {
|
||||
err := s.generalizeVM(resourceGroupName, computeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
if isManagedImage {
|
||||
s.say(fmt.Sprintf(" -> Image ResourceGroupName : '%s'", targetManagedImageResourceGroupName))
|
||||
s.say(fmt.Sprintf(" -> Image Name : '%s'", targetManagedImageName))
|
||||
s.say(fmt.Sprintf(" -> Image Location : '%s'", targetManagedImageLocation))
|
||||
err = s.captureManagedImage(ctx, targetManagedImageResourceGroupName, targetManagedImageName, imageParameters)
|
||||
} else {
|
||||
err = s.captureVhd(ctx, resourceGroupName, computeName, vmCaptureParameters)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
state.Put(constants.Error, err)
|
||||
s.error(err)
|
||||
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
if isManagedImage {
|
||||
s.say(fmt.Sprintf(" -> Image ResourceGroupName : '%s'", targetManagedImageResourceGroupName))
|
||||
s.say(fmt.Sprintf(" -> Image Name : '%s'", targetManagedImageName))
|
||||
s.say(fmt.Sprintf(" -> Image Location : '%s'", targetManagedImageLocation))
|
||||
return s.captureManagedImage(targetManagedImageResourceGroupName, targetManagedImageName, imageParameters, cancelCh)
|
||||
} else {
|
||||
return s.captureVhd(resourceGroupName, computeName, vmCaptureParameters, cancelCh)
|
||||
}
|
||||
})
|
||||
|
||||
// HACK(chrboum): I do not like this. The capture method should be returning this value
|
||||
// instead having to pass in another lambda.
|
||||
// instead having to pass in another lambda. I'm in this pickle because I am using
|
||||
// common.StartInterruptibleTask which is not parametric, and only returns a type of error.
|
||||
// I could change it to interface{}, but I do not like that solution either.
|
||||
//
|
||||
// Having to resort to capturing the template via an inspector is hack, and once I can
|
||||
// resolve that I can cleanup this code too. See the comments in azure_client.go for more
|
||||
// details.
|
||||
// [paulmey]: autorest.Future now has access to the last http.Response, but I'm not sure if
|
||||
// the body is still accessible.
|
||||
template := s.get(s.client)
|
||||
state.Put(constants.ArmCaptureTemplate, template)
|
||||
|
||||
return multistep.ActionContinue
|
||||
return processInterruptibleResult(result, s.error, state)
|
||||
}
|
||||
|
||||
func (*StepCaptureImage) Cleanup(multistep.StateBag) {
|
||||
|
||||
@@ -5,14 +5,14 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
)
|
||||
|
||||
func TestStepCaptureImageShouldFailIfCaptureFails(t *testing.T) {
|
||||
var testSubject = &StepCaptureImage{
|
||||
captureVhd: func(context.Context, string, string, *compute.VirtualMachineCaptureParameters) error {
|
||||
captureVhd: func(string, string, *compute.VirtualMachineCaptureParameters, <-chan struct{}) error {
|
||||
return fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
generalizeVM: func(string, string) error {
|
||||
@@ -39,7 +39,7 @@ func TestStepCaptureImageShouldFailIfCaptureFails(t *testing.T) {
|
||||
|
||||
func TestStepCaptureImageShouldPassIfCapturePasses(t *testing.T) {
|
||||
var testSubject = &StepCaptureImage{
|
||||
captureVhd: func(context.Context, string, string, *compute.VirtualMachineCaptureParameters) error { return nil },
|
||||
captureVhd: func(string, string, *compute.VirtualMachineCaptureParameters, <-chan struct{}) error { return nil },
|
||||
generalizeVM: func(string, string) error {
|
||||
return nil
|
||||
},
|
||||
@@ -74,7 +74,7 @@ func TestStepCaptureImageShouldTakeStepArgumentsFromStateBag(t *testing.T) {
|
||||
}
|
||||
|
||||
var testSubject = &StepCaptureImage{
|
||||
captureVhd: func(_ context.Context, resourceGroupName string, computeName string, parameters *compute.VirtualMachineCaptureParameters) error {
|
||||
captureVhd: func(resourceGroupName string, computeName string, parameters *compute.VirtualMachineCaptureParameters, cancelCh <-chan struct{}) error {
|
||||
actualResourceGroupName = resourceGroupName
|
||||
actualComputeName = computeName
|
||||
actualVirtualMachineCaptureParameters = parameters
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
@@ -13,10 +13,10 @@ import (
|
||||
|
||||
type StepCreateResourceGroup struct {
|
||||
client *AzureClient
|
||||
create func(ctx context.Context, resourceGroupName string, location string, tags map[string]*string) error
|
||||
create func(resourceGroupName string, location string, tags *map[string]*string) error
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
exists func(ctx context.Context, resourceGroupName string) (bool, error)
|
||||
exists func(resourceGroupName string) (bool, error)
|
||||
}
|
||||
|
||||
func NewStepCreateResourceGroup(client *AzureClient, ui packer.Ui) *StepCreateResourceGroup {
|
||||
@@ -31,8 +31,8 @@ func NewStepCreateResourceGroup(client *AzureClient, ui packer.Ui) *StepCreateRe
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepCreateResourceGroup) createResourceGroup(ctx context.Context, resourceGroupName string, location string, tags map[string]*string) error {
|
||||
_, err := s.client.GroupsClient.CreateOrUpdate(ctx, resourceGroupName, resources.Group{
|
||||
func (s *StepCreateResourceGroup) createResourceGroup(resourceGroupName string, location string, tags *map[string]*string) error {
|
||||
_, err := s.client.GroupsClient.CreateOrUpdate(resourceGroupName, resources.Group{
|
||||
Location: &location,
|
||||
Tags: tags,
|
||||
})
|
||||
@@ -43,8 +43,8 @@ func (s *StepCreateResourceGroup) createResourceGroup(ctx context.Context, resou
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepCreateResourceGroup) doesResourceGroupExist(ctx context.Context, resourceGroupName string) (bool, error) {
|
||||
exists, err := s.client.GroupsClient.CheckExistence(ctx, resourceGroupName)
|
||||
func (s *StepCreateResourceGroup) doesResourceGroupExist(resourceGroupName string) (bool, error) {
|
||||
exists, err := s.client.GroupsClient.CheckExistence(resourceGroupName)
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func (s *StepCreateResourceGroup) doesResourceGroupExist(ctx context.Context, re
|
||||
return exists.Response.StatusCode != 404, err
|
||||
}
|
||||
|
||||
func (s *StepCreateResourceGroup) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepCreateResourceGroup) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
var doubleResource, ok = state.GetOk(constants.ArmDoubleResourceGroupNameSet)
|
||||
if ok && doubleResource.(bool) {
|
||||
err := errors.New("You have filled in both temp_resource_group_name and build_resource_group_name. Please choose one.")
|
||||
@@ -61,9 +61,9 @@ func (s *StepCreateResourceGroup) Run(ctx context.Context, state multistep.State
|
||||
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
var location = state.Get(constants.ArmLocation).(string)
|
||||
var tags = state.Get(constants.ArmTags).(map[string]*string)
|
||||
var tags = state.Get(constants.ArmTags).(*map[string]*string)
|
||||
|
||||
exists, err := s.exists(ctx, resourceGroupName)
|
||||
exists, err := s.exists(resourceGroupName)
|
||||
if err != nil {
|
||||
return processStepResult(err, s.error, state)
|
||||
}
|
||||
@@ -84,10 +84,10 @@ func (s *StepCreateResourceGroup) Run(ctx context.Context, state multistep.State
|
||||
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
|
||||
s.say(fmt.Sprintf(" -> Location : '%s'", location))
|
||||
s.say(fmt.Sprintf(" -> Tags :"))
|
||||
for k, v := range tags {
|
||||
for k, v := range *tags {
|
||||
s.say(fmt.Sprintf(" ->> %s : %s", k, *v))
|
||||
}
|
||||
err = s.create(ctx, resourceGroupName, location, tags)
|
||||
err = s.create(resourceGroupName, location, tags)
|
||||
if err == nil {
|
||||
state.Put(constants.ArmIsResourceGroupCreated, true)
|
||||
}
|
||||
@@ -115,23 +115,15 @@ func (s *StepCreateResourceGroup) Cleanup(state multistep.StateBag) {
|
||||
ui.Say("\nCleanup requested, deleting resource group ...")
|
||||
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
ctx := context.TODO()
|
||||
f, err := s.client.GroupsClient.Delete(ctx, resourceGroupName)
|
||||
if err == nil {
|
||||
if state.Get(constants.ArmAsyncResourceGroupDelete).(bool) {
|
||||
s.say(fmt.Sprintf("\n Not waiting for Resource Group delete as requested by user. Resource Group Name is %s", resourceGroupName))
|
||||
} else {
|
||||
err = f.WaitForCompletion(ctx, s.client.GroupsClient.Client)
|
||||
}
|
||||
}
|
||||
_, errChan := s.client.GroupsClient.Delete(resourceGroupName, nil)
|
||||
err := <-errChan
|
||||
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error deleting resource group. Please delete it manually.\n\n"+
|
||||
"Name: %s\n"+
|
||||
"Error: %s", resourceGroupName, err))
|
||||
return
|
||||
}
|
||||
if !state.Get(constants.ArmAsyncResourceGroupDelete).(bool) {
|
||||
ui.Say("Resource group has been deleted.")
|
||||
}
|
||||
|
||||
ui.Say("Resource group has been deleted.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,12 +20,12 @@ func TestStepCreateResourceGroupShouldFailIfBothGroupNames(t *testing.T) {
|
||||
"tag01": &value,
|
||||
}
|
||||
|
||||
stateBag.Put(constants.ArmTags, tags)
|
||||
stateBag.Put(constants.ArmTags, &tags)
|
||||
var testSubject = &StepCreateResourceGroup{
|
||||
create: func(context.Context, string, string, map[string]*string) error { return nil },
|
||||
create: func(string, string, *map[string]*string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
exists: func(context.Context, string) (bool, error) { return false, nil },
|
||||
exists: func(string) (bool, error) { return false, nil },
|
||||
}
|
||||
var result = testSubject.Run(context.Background(), stateBag)
|
||||
if result != multistep.ActionHalt {
|
||||
@@ -39,12 +39,10 @@ func TestStepCreateResourceGroupShouldFailIfBothGroupNames(t *testing.T) {
|
||||
|
||||
func TestStepCreateResourceGroupShouldFailIfCreateFails(t *testing.T) {
|
||||
var testSubject = &StepCreateResourceGroup{
|
||||
create: func(context.Context, string, string, map[string]*string) error {
|
||||
return fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
create: func(string, string, *map[string]*string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
exists: func(context.Context, string) (bool, error) { return false, nil },
|
||||
exists: func(string) (bool, error) { return false, nil },
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateResourceGroup()
|
||||
@@ -61,10 +59,10 @@ func TestStepCreateResourceGroupShouldFailIfCreateFails(t *testing.T) {
|
||||
|
||||
func TestStepCreateResourceGroupShouldFailIfExistsFails(t *testing.T) {
|
||||
var testSubject = &StepCreateResourceGroup{
|
||||
create: func(context.Context, string, string, map[string]*string) error { return nil },
|
||||
create: func(string, string, *map[string]*string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
exists: func(context.Context, string) (bool, error) { return false, errors.New("FAIL") },
|
||||
exists: func(string) (bool, error) { return false, errors.New("FAIL") },
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateResourceGroup()
|
||||
@@ -81,10 +79,10 @@ func TestStepCreateResourceGroupShouldFailIfExistsFails(t *testing.T) {
|
||||
|
||||
func TestStepCreateResourceGroupShouldPassIfCreatePasses(t *testing.T) {
|
||||
var testSubject = &StepCreateResourceGroup{
|
||||
create: func(context.Context, string, string, map[string]*string) error { return nil },
|
||||
create: func(string, string, *map[string]*string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
exists: func(context.Context, string) (bool, error) { return false, nil },
|
||||
exists: func(string) (bool, error) { return false, nil },
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateResourceGroup()
|
||||
@@ -102,10 +100,10 @@ func TestStepCreateResourceGroupShouldPassIfCreatePasses(t *testing.T) {
|
||||
func TestStepCreateResourceGroupShouldTakeStepArgumentsFromStateBag(t *testing.T) {
|
||||
var actualResourceGroupName string
|
||||
var actualLocation string
|
||||
var actualTags map[string]*string
|
||||
var actualTags *map[string]*string
|
||||
|
||||
var testSubject = &StepCreateResourceGroup{
|
||||
create: func(_ context.Context, resourceGroupName string, location string, tags map[string]*string) error {
|
||||
create: func(resourceGroupName string, location string, tags *map[string]*string) error {
|
||||
actualResourceGroupName = resourceGroupName
|
||||
actualLocation = location
|
||||
actualTags = tags
|
||||
@@ -113,7 +111,7 @@ func TestStepCreateResourceGroupShouldTakeStepArgumentsFromStateBag(t *testing.T
|
||||
},
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
exists: func(context.Context, string) (bool, error) { return false, nil },
|
||||
exists: func(string) (bool, error) { return false, nil },
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateResourceGroup()
|
||||
@@ -125,7 +123,7 @@ func TestStepCreateResourceGroupShouldTakeStepArgumentsFromStateBag(t *testing.T
|
||||
|
||||
var expectedResourceGroupName = stateBag.Get(constants.ArmResourceGroupName).(string)
|
||||
var expectedLocation = stateBag.Get(constants.ArmLocation).(string)
|
||||
var expectedTags = stateBag.Get(constants.ArmTags).(map[string]*string)
|
||||
var expectedTags = stateBag.Get(constants.ArmTags).(*map[string]*string)
|
||||
|
||||
if actualResourceGroupName != expectedResourceGroupName {
|
||||
t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.")
|
||||
@@ -135,7 +133,7 @@ func TestStepCreateResourceGroupShouldTakeStepArgumentsFromStateBag(t *testing.T
|
||||
t.Fatal("Expected the step to source 'constants.ArmResourceGroupName' from the state bag, but it did not.")
|
||||
}
|
||||
|
||||
if len(expectedTags) != len(actualTags) && expectedTags["tag01"] != actualTags["tag01"] {
|
||||
if len(*expectedTags) != len(*actualTags) && *(*expectedTags)["tag01"] != *(*actualTags)["tag01"] {
|
||||
t.Fatal("Expected the step to source 'constants.ArmTags' from the state bag, but it did not.")
|
||||
}
|
||||
|
||||
@@ -147,12 +145,10 @@ func TestStepCreateResourceGroupShouldTakeStepArgumentsFromStateBag(t *testing.T
|
||||
|
||||
func TestStepCreateResourceGroupMarkShouldFailIfTryingExistingButDoesntExist(t *testing.T) {
|
||||
var testSubject = &StepCreateResourceGroup{
|
||||
create: func(context.Context, string, string, map[string]*string) error {
|
||||
return fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
create: func(string, string, *map[string]*string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
exists: func(context.Context, string) (bool, error) { return false, nil },
|
||||
exists: func(string) (bool, error) { return false, nil },
|
||||
}
|
||||
|
||||
stateBag := createTestExistingStateBagStepCreateResourceGroup()
|
||||
@@ -169,12 +165,10 @@ func TestStepCreateResourceGroupMarkShouldFailIfTryingExistingButDoesntExist(t *
|
||||
|
||||
func TestStepCreateResourceGroupMarkShouldFailIfTryingTempButExist(t *testing.T) {
|
||||
var testSubject = &StepCreateResourceGroup{
|
||||
create: func(context.Context, string, string, map[string]*string) error {
|
||||
return fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
create: func(string, string, *map[string]*string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
exists: func(context.Context, string) (bool, error) { return true, nil },
|
||||
exists: func(string) (bool, error) { return true, nil },
|
||||
}
|
||||
|
||||
stateBag := createTestStateBagStepCreateResourceGroup()
|
||||
@@ -201,7 +195,7 @@ func createTestStateBagStepCreateResourceGroup() multistep.StateBag {
|
||||
"tag01": &value,
|
||||
}
|
||||
|
||||
stateBag.Put(constants.ArmTags, tags)
|
||||
stateBag.Put(constants.ArmTags, &tags)
|
||||
return stateBag
|
||||
}
|
||||
|
||||
@@ -217,6 +211,6 @@ func createTestExistingStateBagStepCreateResourceGroup() multistep.StateBag {
|
||||
"tag01": &value,
|
||||
}
|
||||
|
||||
stateBag.Put(constants.ArmTags, tags)
|
||||
stateBag.Put(constants.ArmTags, &tags)
|
||||
return stateBag
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
type StepDeleteAdditionalDisk struct {
|
||||
client *AzureClient
|
||||
delete func(string, string) error
|
||||
deleteManaged func(context.Context, string, string) error
|
||||
deleteManaged func(string, string) error
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
}
|
||||
@@ -43,17 +43,15 @@ func (s *StepDeleteAdditionalDisk) deleteBlob(storageContainerName string, blobN
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepDeleteAdditionalDisk) deleteManagedDisk(ctx context.Context, resourceGroupName string, diskName string) error {
|
||||
xs := strings.Split(diskName, "/")
|
||||
diskName = xs[len(xs)-1]
|
||||
f, err := s.client.DisksClient.Delete(ctx, resourceGroupName, diskName)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, s.client.DisksClient.Client)
|
||||
}
|
||||
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(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
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)
|
||||
@@ -75,7 +73,7 @@ func (s *StepDeleteAdditionalDisk) Run(ctx context.Context, state multistep.Stat
|
||||
s.say(fmt.Sprintf(" -> Additional Disk %d: '%s'", i+1, additionaldisk))
|
||||
var err error
|
||||
if isManagedDisk {
|
||||
err = s.deleteManaged(ctx, resourceGroupName, additionaldisk)
|
||||
err = s.deleteManaged(resourceGroupName, additionaldisk)
|
||||
if err != nil {
|
||||
s.say("Failed to delete the managed Additional Disk!")
|
||||
return processStepResult(err, s.error, state)
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
func TestStepDeleteAdditionalDiskShouldFailIfGetFails(t *testing.T) {
|
||||
var testSubject = &StepDeleteAdditionalDisk{
|
||||
delete: func(string, string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
deleteManaged: func(context.Context, string, string) error { return nil },
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
@@ -110,7 +110,7 @@ func TestStepDeleteAdditionalDiskShouldFailIfVHDNameCannotBeURLParsed(t *testing
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(context.Context, string, string) error { return nil },
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
}
|
||||
|
||||
// Invalid URL per https://golang.org/src/net/url/url_test.go
|
||||
@@ -130,7 +130,7 @@ func TestStepDeleteAdditionalDiskShouldFailIfVHDNameIsTooShort(t *testing.T) {
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(context.Context, string, string) error { return nil },
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
}
|
||||
|
||||
stateBag := DeleteTestStateBagStepDeleteAdditionalDisk([]string{"storage.blob.core.windows.net/abc"})
|
||||
@@ -173,7 +173,7 @@ func TestStepDeleteAdditionalDiskShouldFailIfManagedDiskInExistingResourceGroupF
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(context.Context, string, string) error { return errors.New("UNIT TEST FAIL!") },
|
||||
deleteManaged: func(string, string) error { return errors.New("UNIT TEST FAIL!") },
|
||||
}
|
||||
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
@@ -197,7 +197,7 @@ func TestStepDeleteAdditionalDiskShouldFailIfManagedDiskInExistingResourceGroupI
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(context.Context, string, string) error { return nil },
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
}
|
||||
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
type StepDeleteOSDisk struct {
|
||||
client *AzureClient
|
||||
delete func(string, string) error
|
||||
deleteManaged func(context.Context, string, string) error
|
||||
deleteManaged func(string, string) error
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
}
|
||||
@@ -43,17 +43,15 @@ func (s *StepDeleteOSDisk) deleteBlob(storageContainerName string, blobName stri
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepDeleteOSDisk) deleteManagedDisk(ctx context.Context, resourceGroupName string, imageName string) error {
|
||||
func (s *StepDeleteOSDisk) deleteManagedDisk(resourceGroupName string, imageName string) error {
|
||||
xs := strings.Split(imageName, "/")
|
||||
diskName := xs[len(xs)-1]
|
||||
f, err := s.client.DisksClient.Delete(ctx, resourceGroupName, diskName)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, s.client.DisksClient.Client)
|
||||
}
|
||||
_, errChan := s.client.DisksClient.Delete(resourceGroupName, diskName, nil)
|
||||
err := <-errChan
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepDeleteOSDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepDeleteOSDisk) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Deleting the temporary OS disk ...")
|
||||
|
||||
var osDisk = state.Get(constants.ArmOSDiskVhd).(string)
|
||||
@@ -70,7 +68,7 @@ func (s *StepDeleteOSDisk) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
|
||||
var err error
|
||||
if isManagedDisk {
|
||||
err = s.deleteManaged(ctx, resourceGroupName, osDisk)
|
||||
err = s.deleteManaged(resourceGroupName, osDisk)
|
||||
if err != nil {
|
||||
s.say("Failed to delete the managed OS Disk!")
|
||||
return processStepResult(err, s.error, state)
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
func TestStepDeleteOSDiskShouldFailIfGetFails(t *testing.T) {
|
||||
var testSubject = &StepDeleteOSDisk{
|
||||
delete: func(string, string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
deleteManaged: func(context.Context, string, string) error { return nil },
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
@@ -110,7 +110,7 @@ func TestStepDeleteOSDiskShouldFailIfVHDNameCannotBeURLParsed(t *testing.T) {
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(context.Context, string, string) error { return nil },
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
}
|
||||
|
||||
// Invalid URL per https://golang.org/src/net/url/url_test.go
|
||||
@@ -130,7 +130,7 @@ func TestStepDeleteOSDiskShouldFailIfVHDNameIsTooShort(t *testing.T) {
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(context.Context, string, string) error { return nil },
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
}
|
||||
|
||||
stateBag := DeleteTestStateBagStepDeleteOSDisk("storage.blob.core.windows.net/abc")
|
||||
@@ -173,7 +173,7 @@ func TestStepDeleteOSDiskShouldFailIfManagedDiskInExistingResourceGroupFailsToDe
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(context.Context, string, string) error { return errors.New("UNIT TEST FAIL!") },
|
||||
deleteManaged: func(string, string) error { return errors.New("UNIT TEST FAIL!") },
|
||||
}
|
||||
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
@@ -197,7 +197,7 @@ func TestStepDeleteOSDiskShouldFailIfManagedDiskInExistingResourceGroupIsDeleted
|
||||
delete: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
deleteManaged: func(context.Context, string, string) error { return nil },
|
||||
deleteManaged: func(string, string) error { return nil },
|
||||
}
|
||||
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/hashicorp/packer/builder/azure/common"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
@@ -15,7 +17,7 @@ const (
|
||||
|
||||
type StepDeleteResourceGroup struct {
|
||||
client *AzureClient
|
||||
delete func(ctx context.Context, state multistep.StateBag, resourceGroupName string) error
|
||||
delete func(state multistep.StateBag, resourceGroupName string, cancelCh <-chan struct{}) error
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
}
|
||||
@@ -31,18 +33,18 @@ func NewStepDeleteResourceGroup(client *AzureClient, ui packer.Ui) *StepDeleteRe
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepDeleteResourceGroup) deleteResourceGroup(ctx context.Context, state multistep.StateBag, resourceGroupName string) error {
|
||||
func (s *StepDeleteResourceGroup) deleteResourceGroup(state multistep.StateBag, resourceGroupName string, cancelCh <-chan struct{}) error {
|
||||
var err error
|
||||
if state.Get(constants.ArmIsExistingResourceGroup).(bool) {
|
||||
s.say("\nThe resource group was not created by Packer, only deleting individual resources ...")
|
||||
var deploymentName = state.Get(constants.ArmDeploymentName).(string)
|
||||
err = s.deleteDeploymentResources(ctx, deploymentName, resourceGroupName)
|
||||
err = s.deleteDeploymentResources(deploymentName, resourceGroupName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if keyVaultDeploymentName, ok := state.GetOk(constants.ArmKeyVaultDeploymentName); ok {
|
||||
err = s.deleteDeploymentResources(ctx, keyVaultDeploymentName.(string), resourceGroupName)
|
||||
err = s.deleteDeploymentResources(keyVaultDeploymentName.(string), resourceGroupName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -51,16 +53,8 @@ func (s *StepDeleteResourceGroup) deleteResourceGroup(ctx context.Context, state
|
||||
return nil
|
||||
} else {
|
||||
s.say("\nThe resource group was created by Packer, deleting ...")
|
||||
f, err := s.client.GroupsClient.Delete(ctx, resourceGroupName)
|
||||
if err == nil {
|
||||
if state.Get(constants.ArmAsyncResourceGroupDelete).(bool) {
|
||||
// No need to wait for the complition for delete if request is Accepted
|
||||
s.say(fmt.Sprintf("\nResource Group is being deleted, not waiting for deletion due to config. Resource Group Name '%s'", resourceGroupName))
|
||||
} else {
|
||||
f.WaitForCompletion(ctx, s.client.GroupsClient.Client)
|
||||
}
|
||||
|
||||
}
|
||||
_, errChan := s.client.GroupsClient.Delete(resourceGroupName, cancelCh)
|
||||
err = <-errChan
|
||||
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
@@ -69,36 +63,46 @@ func (s *StepDeleteResourceGroup) deleteResourceGroup(ctx context.Context, state
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StepDeleteResourceGroup) deleteDeploymentResources(ctx context.Context, deploymentName, resourceGroupName string) error {
|
||||
func (s *StepDeleteResourceGroup) deleteDeploymentResources(deploymentName, resourceGroupName string) error {
|
||||
maxResources := int32(maxResourcesToDelete)
|
||||
|
||||
deploymentOperations, err := s.client.DeploymentOperationsClient.ListComplete(ctx, resourceGroupName, deploymentName, &maxResources)
|
||||
deploymentOperations, err := s.client.DeploymentOperationsClient.List(resourceGroupName, deploymentName, &maxResources)
|
||||
if err != nil {
|
||||
s.reportIfError(err, resourceGroupName)
|
||||
return err
|
||||
}
|
||||
|
||||
for deploymentOperations.NotDone() {
|
||||
deploymentOperation := deploymentOperations.Value()
|
||||
for _, deploymentOperation := range *deploymentOperations.Value {
|
||||
// Sometimes an empty operation is added to the list by Azure
|
||||
if deploymentOperation.Properties.TargetResource == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceName := *deploymentOperation.Properties.TargetResource.ResourceName
|
||||
resourceType := *deploymentOperation.Properties.TargetResource.ResourceType
|
||||
|
||||
s.say(fmt.Sprintf(" -> %s : '%s'",
|
||||
resourceType,
|
||||
resourceName))
|
||||
*deploymentOperation.Properties.TargetResource.ResourceType,
|
||||
*deploymentOperation.Properties.TargetResource.ResourceName))
|
||||
|
||||
err := deleteResource(ctx, s.client,
|
||||
resourceType,
|
||||
resourceName,
|
||||
resourceGroupName)
|
||||
s.reportIfError(err, resourceName)
|
||||
if err = deploymentOperations.Next(); err != nil {
|
||||
return err
|
||||
var networkDeleteFunction func(string, string, <-chan struct{}) (<-chan autorest.Response, <-chan error)
|
||||
resourceName := *deploymentOperation.Properties.TargetResource.ResourceName
|
||||
|
||||
switch *deploymentOperation.Properties.TargetResource.ResourceType {
|
||||
case "Microsoft.Compute/virtualMachines":
|
||||
_, errChan := s.client.VirtualMachinesClient.Delete(resourceGroupName, resourceName, nil)
|
||||
err := <-errChan
|
||||
s.reportIfError(err, resourceName)
|
||||
case "Microsoft.KeyVault/vaults":
|
||||
_, err := s.client.VaultClientDelete.Delete(resourceGroupName, resourceName)
|
||||
s.reportIfError(err, resourceName)
|
||||
case "Microsoft.Network/networkInterfaces":
|
||||
networkDeleteFunction = s.client.InterfacesClient.Delete
|
||||
case "Microsoft.Network/virtualNetworks":
|
||||
networkDeleteFunction = s.client.VirtualNetworksClient.Delete
|
||||
case "Microsoft.Network/publicIPAddresses":
|
||||
networkDeleteFunction = s.client.PublicIPAddressesClient.Delete
|
||||
}
|
||||
if networkDeleteFunction != nil {
|
||||
_, errChan := networkDeleteFunction(resourceGroupName, resourceName, nil)
|
||||
err := <-errChan
|
||||
s.reportIfError(err, resourceName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,23 +118,19 @@ func (s *StepDeleteResourceGroup) reportIfError(err error, resourceName string)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StepDeleteResourceGroup) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepDeleteResourceGroup) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Deleting resource group ...")
|
||||
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
|
||||
|
||||
err := s.delete(ctx, state, resourceGroupName)
|
||||
if err != nil {
|
||||
state.Put(constants.Error, err)
|
||||
s.error(err)
|
||||
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
result := common.StartInterruptibleTask(
|
||||
func() bool { return common.IsStateCancelled(state) },
|
||||
func(cancelCh <-chan struct{}) error { return s.delete(state, resourceGroupName, cancelCh) })
|
||||
stepAction := processInterruptibleResult(result, s.error, state)
|
||||
state.Put(constants.ArmIsResourceGroupCreated, false)
|
||||
|
||||
return multistep.ActionContinue
|
||||
return stepAction
|
||||
}
|
||||
|
||||
func (*StepDeleteResourceGroup) Cleanup(multistep.StateBag) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
func TestStepDeleteResourceGroupShouldFailIfDeleteFails(t *testing.T) {
|
||||
var testSubject = &StepDeleteResourceGroup{
|
||||
delete: func(context.Context, multistep.StateBag, string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
delete: func(multistep.StateBag, string, <-chan struct{}) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func TestStepDeleteResourceGroupShouldFailIfDeleteFails(t *testing.T) {
|
||||
|
||||
func TestStepDeleteResourceGroupShouldPassIfDeletePasses(t *testing.T) {
|
||||
var testSubject = &StepDeleteResourceGroup{
|
||||
delete: func(context.Context, multistep.StateBag, string) error { return nil },
|
||||
delete: func(multistep.StateBag, string, <-chan struct{}) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
@@ -49,7 +49,7 @@ func TestStepDeleteResourceGroupShouldPassIfDeletePasses(t *testing.T) {
|
||||
|
||||
func TestStepDeleteResourceGroupShouldDeleteStateBagArmResourceGroupCreated(t *testing.T) {
|
||||
var testSubject = &StepDeleteResourceGroup{
|
||||
delete: func(context.Context, multistep.StateBag, string) error {
|
||||
delete: func(s multistep.StateBag, resourceGroupName string, cancelCh <-chan struct{}) error {
|
||||
return nil
|
||||
},
|
||||
say: func(message string) {},
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/hashicorp/packer/builder/azure/common"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
@@ -14,10 +16,10 @@ import (
|
||||
|
||||
type StepDeployTemplate struct {
|
||||
client *AzureClient
|
||||
deploy func(ctx context.Context, resourceGroupName string, deploymentName string) error
|
||||
delete func(ctx context.Context, client *AzureClient, resourceType string, resourceName string, resourceGroupName string) error
|
||||
disk func(ctx context.Context, resourceGroupName string, computeName string) (string, string, error)
|
||||
deleteDisk func(ctx context.Context, imageType string, imageName string, resourceGroupName string) error
|
||||
deploy func(resourceGroupName string, deploymentName string, cancelCh <-chan struct{}) error
|
||||
delete func(resourceType string, resourceName string, resourceGroupName string) error
|
||||
disk func(resourceGroupName string, computeName string) (string, string, error)
|
||||
deleteDisk func(imageType string, imageName string, resourceGroupName string) error
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
config *Config
|
||||
@@ -36,29 +38,28 @@ func NewStepDeployTemplate(client *AzureClient, ui packer.Ui, config *Config, de
|
||||
}
|
||||
|
||||
step.deploy = step.deployTemplate
|
||||
step.delete = deleteResource
|
||||
step.delete = step.deleteOperationResource
|
||||
step.disk = step.getImageDetails
|
||||
step.deleteDisk = step.deleteImage
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepDeployTemplate) deployTemplate(ctx context.Context, resourceGroupName string, deploymentName string) error {
|
||||
func (s *StepDeployTemplate) deployTemplate(resourceGroupName string, deploymentName string, cancelCh <-chan struct{}) error {
|
||||
deployment, err := s.factory(s.config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := s.client.DeploymentsClient.CreateOrUpdate(ctx, resourceGroupName, deploymentName, *deployment)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, s.client.DeploymentsClient.Client)
|
||||
}
|
||||
_, errChan := s.client.DeploymentsClient.CreateOrUpdate(resourceGroupName, deploymentName, *deployment, cancelCh)
|
||||
|
||||
err = <-errChan
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepDeployTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepDeployTemplate) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Deploying deployment template ...")
|
||||
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
@@ -66,16 +67,21 @@ func (s *StepDeployTemplate) Run(ctx context.Context, state multistep.StateBag)
|
||||
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
|
||||
s.say(fmt.Sprintf(" -> DeploymentName : '%s'", s.name))
|
||||
|
||||
return processStepResult(
|
||||
s.deploy(ctx, resourceGroupName, s.name),
|
||||
s.error, state)
|
||||
result := common.StartInterruptibleTask(
|
||||
func() bool { return common.IsStateCancelled(state) },
|
||||
func(cancelCh <-chan struct{}) error {
|
||||
return s.deploy(resourceGroupName, s.name, cancelCh)
|
||||
},
|
||||
)
|
||||
|
||||
return processInterruptibleResult(result, s.error, state)
|
||||
}
|
||||
|
||||
func (s *StepDeployTemplate) getImageDetails(ctx context.Context, resourceGroupName string, computeName string) (string, string, error) {
|
||||
func (s *StepDeployTemplate) getImageDetails(resourceGroupName string, computeName string) (string, string, error) {
|
||||
//We can't depend on constants.ArmOSDiskVhd being set
|
||||
var imageName string
|
||||
var imageType string
|
||||
vm, err := s.client.VirtualMachinesClient.Get(ctx, resourceGroupName, computeName, "")
|
||||
vm, err := s.client.VirtualMachinesClient.Get(resourceGroupName, computeName, "")
|
||||
if err != nil {
|
||||
return imageName, imageType, err
|
||||
} else {
|
||||
@@ -90,50 +96,44 @@ func (s *StepDeployTemplate) getImageDetails(ctx context.Context, resourceGroupN
|
||||
return imageType, imageName, nil
|
||||
}
|
||||
|
||||
//TODO(paulmey): move to helpers file
|
||||
func deleteResource(ctx context.Context, client *AzureClient, resourceType string, resourceName string, resourceGroupName string) error {
|
||||
func (s *StepDeployTemplate) deleteOperationResource(resourceType string, resourceName string, resourceGroupName string) error {
|
||||
var networkDeleteFunction func(string, string, <-chan struct{}) (<-chan autorest.Response, <-chan error)
|
||||
switch resourceType {
|
||||
case "Microsoft.Compute/virtualMachines":
|
||||
f, err := client.VirtualMachinesClient.Delete(ctx, resourceGroupName, resourceName)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, client.VirtualMachinesClient.Client)
|
||||
_, errChan := s.client.VirtualMachinesClient.Delete(resourceGroupName,
|
||||
resourceName, nil)
|
||||
err := <-errChan
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
}
|
||||
return err
|
||||
case "Microsoft.KeyVault/vaults":
|
||||
// TODO(paulmey): not sure why VaultClient doesn't do cancellation
|
||||
_, err := client.VaultClientDelete.Delete(resourceGroupName, resourceName)
|
||||
_, err := s.client.VaultClientDelete.Delete(resourceGroupName, resourceName)
|
||||
return err
|
||||
case "Microsoft.Network/networkInterfaces":
|
||||
f, err := client.InterfacesClient.Delete(ctx, resourceGroupName, resourceName)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, client.InterfacesClient.Client)
|
||||
}
|
||||
return err
|
||||
networkDeleteFunction = s.client.InterfacesClient.Delete
|
||||
case "Microsoft.Network/virtualNetworks":
|
||||
f, err := client.VirtualNetworksClient.Delete(ctx, resourceGroupName, resourceName)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, client.VirtualNetworksClient.Client)
|
||||
}
|
||||
return err
|
||||
networkDeleteFunction = s.client.VirtualNetworksClient.Delete
|
||||
case "Microsoft.Network/publicIPAddresses":
|
||||
f, err := client.PublicIPAddressesClient.Delete(ctx, resourceGroupName, resourceName)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, client.PublicIPAddressesClient.Client)
|
||||
networkDeleteFunction = s.client.PublicIPAddressesClient.Delete
|
||||
}
|
||||
if networkDeleteFunction != nil {
|
||||
_, errChan := networkDeleteFunction(resourceGroupName, resourceName, nil)
|
||||
err := <-errChan
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *StepDeployTemplate) deleteImage(ctx context.Context, imageType string, imageName string, resourceGroupName string) error {
|
||||
func (s *StepDeployTemplate) deleteImage(imageType string, imageName string, resourceGroupName string) error {
|
||||
// Managed disk
|
||||
if imageType == "Microsoft.Compute/disks" {
|
||||
xs := strings.Split(imageName, "/")
|
||||
diskName := xs[len(xs)-1]
|
||||
f, err := s.client.DisksClient.Delete(ctx, resourceGroupName, diskName)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, s.client.DisksClient.Client)
|
||||
}
|
||||
_, errChan := s.client.DisksClient.Delete(resourceGroupName, diskName, nil)
|
||||
err := <-errChan
|
||||
return err
|
||||
}
|
||||
// VHD image
|
||||
@@ -167,7 +167,7 @@ func (s *StepDeployTemplate) Cleanup(state multistep.StateBag) {
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
var computeName = state.Get(constants.ArmComputeName).(string)
|
||||
var deploymentName = s.name
|
||||
imageType, imageName, err := s.disk(context.TODO(), resourceGroupName, computeName)
|
||||
imageType, imageName, err := s.disk(resourceGroupName, computeName)
|
||||
if err != nil {
|
||||
ui.Error("Could not retrieve OS Image details")
|
||||
}
|
||||
@@ -175,14 +175,13 @@ func (s *StepDeployTemplate) Cleanup(state multistep.StateBag) {
|
||||
ui.Say(" -> Deployment: " + deploymentName)
|
||||
if deploymentName != "" {
|
||||
maxResources := int32(50)
|
||||
deploymentOperations, err := s.client.DeploymentOperationsClient.ListComplete(context.TODO(), resourceGroupName, deploymentName, &maxResources)
|
||||
deploymentOperations, err := s.client.DeploymentOperationsClient.List(resourceGroupName, deploymentName, &maxResources)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error deleting resources. Please delete them manually.\n\n"+
|
||||
"Name: %s\n"+
|
||||
"Error: %s", resourceGroupName, err))
|
||||
}
|
||||
for deploymentOperations.NotDone() {
|
||||
deploymentOperation := deploymentOperations.Value()
|
||||
for _, deploymentOperation := range *deploymentOperations.Value {
|
||||
// Sometimes an empty operation is added to the list by Azure
|
||||
if deploymentOperation.Properties.TargetResource == nil {
|
||||
continue
|
||||
@@ -190,8 +189,7 @@ func (s *StepDeployTemplate) Cleanup(state multistep.StateBag) {
|
||||
ui.Say(fmt.Sprintf(" -> %s : '%s'",
|
||||
*deploymentOperation.Properties.TargetResource.ResourceType,
|
||||
*deploymentOperation.Properties.TargetResource.ResourceName))
|
||||
err = s.delete(context.TODO(), s.client,
|
||||
*deploymentOperation.Properties.TargetResource.ResourceType,
|
||||
err = s.delete(*deploymentOperation.Properties.TargetResource.ResourceType,
|
||||
*deploymentOperation.Properties.TargetResource.ResourceName,
|
||||
resourceGroupName)
|
||||
if err != nil {
|
||||
@@ -199,18 +197,12 @@ func (s *StepDeployTemplate) Cleanup(state multistep.StateBag) {
|
||||
"Name: %s\n"+
|
||||
"Error: %s", *deploymentOperation.Properties.TargetResource.ResourceName, err))
|
||||
}
|
||||
if err = deploymentOperations.Next(); err != nil {
|
||||
ui.Error(fmt.Sprintf("Error deleting resources. Please delete them manually.\n\n"+
|
||||
"Name: %s\n"+
|
||||
"Error: %s", resourceGroupName, err))
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// The disk is not defined as an operation in the template so has to be
|
||||
// deleted separately
|
||||
ui.Say(fmt.Sprintf(" -> %s : '%s'", imageType, imageName))
|
||||
err = s.deleteDisk(context.TODO(), imageType, imageName, resourceGroupName)
|
||||
err = s.deleteDisk(imageType, imageName, resourceGroupName)
|
||||
if err != nil {
|
||||
ui.Error(fmt.Sprintf("Error deleting resource. Please delete manually.\n\n"+
|
||||
"Name: %s\n"+
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
func TestStepDeployTemplateShouldFailIfDeployFails(t *testing.T) {
|
||||
var testSubject = &StepDeployTemplate{
|
||||
deploy: func(context.Context, string, string) error {
|
||||
deploy: func(string, string, <-chan struct{}) error {
|
||||
return fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
say: func(message string) {},
|
||||
@@ -32,7 +32,7 @@ func TestStepDeployTemplateShouldFailIfDeployFails(t *testing.T) {
|
||||
|
||||
func TestStepDeployTemplateShouldPassIfDeployPasses(t *testing.T) {
|
||||
var testSubject = &StepDeployTemplate{
|
||||
deploy: func(context.Context, string, string) error { return nil },
|
||||
deploy: func(string, string, <-chan struct{}) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func TestStepDeployTemplateShouldTakeStepArgumentsFromStateBag(t *testing.T) {
|
||||
var actualDeploymentName string
|
||||
|
||||
var testSubject = &StepDeployTemplate{
|
||||
deploy: func(_ context.Context, resourceGroupName string, deploymentName string) error {
|
||||
deploy: func(resourceGroupName string, deploymentName string, cancelCh <-chan struct{}) error {
|
||||
actualResourceGroupName = resourceGroupName
|
||||
actualDeploymentName = deploymentName
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestStepDeployTemplateDeleteImageShouldFailWhenImageUrlCannotBeParsed(t *te
|
||||
name: "--deployment-name--",
|
||||
}
|
||||
// Invalid URL per https://golang.org/src/net/url/url_test.go
|
||||
err := testSubject.deleteImage(context.TODO(), "image", "http://[fe80::1%en0]/", "Unit Test: ResourceGroupName")
|
||||
err := testSubject.deleteImage("image", "http://[fe80::1%en0]/", "Unit Test: ResourceGroupName")
|
||||
if err == nil {
|
||||
t.Fatal("Expected a failure because of the failed image name")
|
||||
}
|
||||
@@ -102,7 +102,7 @@ func TestStepDeployTemplateDeleteImageShouldFailWithInvalidImage(t *testing.T) {
|
||||
error: func(e error) {},
|
||||
name: "--deployment-name--",
|
||||
}
|
||||
err := testSubject.deleteImage(context.TODO(), "image", "storage.blob.core.windows.net/abc", "Unit Test: ResourceGroupName")
|
||||
err := testSubject.deleteImage("image", "storage.blob.core.windows.net/abc", "Unit Test: ResourceGroupName")
|
||||
if err == nil {
|
||||
t.Fatal("Expected a failure because of the failed image name")
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
type StepGetDataDisk struct {
|
||||
client *AzureClient
|
||||
query func(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error)
|
||||
query func(resourceGroupName string, computeName string) (compute.VirtualMachine, error)
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
}
|
||||
@@ -30,15 +30,15 @@ func NewStepGetAdditionalDisks(client *AzureClient, ui packer.Ui) *StepGetDataDi
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepGetDataDisk) queryCompute(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) {
|
||||
vm, err := s.client.VirtualMachinesClient.Get(ctx, resourceGroupName, computeName, "")
|
||||
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(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
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)
|
||||
@@ -47,7 +47,7 @@ func (s *StepGetDataDisk) Run(ctx context.Context, state multistep.StateBag) mul
|
||||
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
|
||||
s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName))
|
||||
|
||||
vm, err := s.query(ctx, resourceGroupName, computeName)
|
||||
vm, err := s.query(resourceGroupName, computeName)
|
||||
if err != nil {
|
||||
state.Put(constants.Error, err)
|
||||
s.error(err)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func TestStepGetAdditionalDiskShouldFailIfGetFails(t *testing.T) {
|
||||
var testSubject = &StepGetDataDisk{
|
||||
query: func(context.Context, string, string) (compute.VirtualMachine, error) {
|
||||
query: func(string, string) (compute.VirtualMachine, error) {
|
||||
return createVirtualMachineWithDataDisksFromUri("test.vhd"), fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
say: func(message string) {},
|
||||
@@ -35,7 +35,7 @@ func TestStepGetAdditionalDiskShouldFailIfGetFails(t *testing.T) {
|
||||
|
||||
func TestStepGetAdditionalDiskShouldPassIfGetPasses(t *testing.T) {
|
||||
var testSubject = &StepGetDataDisk{
|
||||
query: func(context.Context, string, string) (compute.VirtualMachine, error) {
|
||||
query: func(string, string) (compute.VirtualMachine, error) {
|
||||
return createVirtualMachineWithDataDisksFromUri("test.vhd"), nil
|
||||
},
|
||||
say: func(message string) {},
|
||||
@@ -59,7 +59,7 @@ func TestStepGetAdditionalDiskShouldTakeValidateArgumentsFromStateBag(t *testing
|
||||
var actualComputeName string
|
||||
|
||||
var testSubject = &StepGetDataDisk{
|
||||
query: func(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) {
|
||||
query: func(resourceGroupName string, computeName string) (compute.VirtualMachine, error) {
|
||||
actualResourceGroupName = resourceGroupName
|
||||
actualComputeName = computeName
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ var (
|
||||
type StepGetIPAddress struct {
|
||||
client *AzureClient
|
||||
endpoint EndpointType
|
||||
get func(ctx context.Context, resourceGroupName string, ipAddressName string, interfaceName string) (string, error)
|
||||
get func(resourceGroupName string, ipAddressName string, interfaceName string) (string, error)
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
}
|
||||
@@ -53,8 +53,8 @@ func NewStepGetIPAddress(client *AzureClient, ui packer.Ui, endpoint EndpointTyp
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepGetIPAddress) getPrivateIP(ctx context.Context, resourceGroupName string, ipAddressName string, interfaceName string) (string, error) {
|
||||
resp, err := s.client.InterfacesClient.Get(ctx, resourceGroupName, interfaceName, "")
|
||||
func (s *StepGetIPAddress) getPrivateIP(resourceGroupName string, ipAddressName string, interfaceName string) (string, error) {
|
||||
resp, err := s.client.InterfacesClient.Get(resourceGroupName, interfaceName, "")
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
return "", err
|
||||
@@ -63,8 +63,8 @@ func (s *StepGetIPAddress) getPrivateIP(ctx context.Context, resourceGroupName s
|
||||
return *(*resp.IPConfigurations)[0].PrivateIPAddress, nil
|
||||
}
|
||||
|
||||
func (s *StepGetIPAddress) getPublicIP(ctx context.Context, resourceGroupName string, ipAddressName string, interfaceName string) (string, error) {
|
||||
resp, err := s.client.PublicIPAddressesClient.Get(ctx, resourceGroupName, ipAddressName, "")
|
||||
func (s *StepGetIPAddress) getPublicIP(resourceGroupName string, ipAddressName string, interfaceName string) (string, error) {
|
||||
resp, err := s.client.PublicIPAddressesClient.Get(resourceGroupName, ipAddressName, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -72,12 +72,12 @@ func (s *StepGetIPAddress) getPublicIP(ctx context.Context, resourceGroupName st
|
||||
return *resp.IPAddress, nil
|
||||
}
|
||||
|
||||
func (s *StepGetIPAddress) getPublicIPInPrivateNetwork(ctx context.Context, resourceGroupName string, ipAddressName string, interfaceName string) (string, error) {
|
||||
s.getPrivateIP(ctx, resourceGroupName, ipAddressName, interfaceName)
|
||||
return s.getPublicIP(ctx, resourceGroupName, ipAddressName, interfaceName)
|
||||
func (s *StepGetIPAddress) getPublicIPInPrivateNetwork(resourceGroupName string, ipAddressName string, interfaceName string) (string, error) {
|
||||
s.getPrivateIP(resourceGroupName, ipAddressName, interfaceName)
|
||||
return s.getPublicIP(resourceGroupName, ipAddressName, interfaceName)
|
||||
}
|
||||
|
||||
func (s *StepGetIPAddress) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepGetIPAddress) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Getting the VM's IP address ...")
|
||||
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
@@ -89,7 +89,7 @@ func (s *StepGetIPAddress) Run(ctx context.Context, state multistep.StateBag) mu
|
||||
s.say(fmt.Sprintf(" -> NicName : '%s'", nicName))
|
||||
s.say(fmt.Sprintf(" -> Network Connection : '%s'", EndpointCommunicationText[s.endpoint]))
|
||||
|
||||
address, err := s.get(ctx, resourceGroupName, ipAddressName, nicName)
|
||||
address, err := s.get(resourceGroupName, ipAddressName, nicName)
|
||||
if err != nil {
|
||||
state.Put(constants.Error, err)
|
||||
s.error(err)
|
||||
|
||||
@@ -14,9 +14,7 @@ func TestStepGetIPAddressShouldFailIfGetFails(t *testing.T) {
|
||||
|
||||
for _, endpoint := range endpoints {
|
||||
var testSubject = &StepGetIPAddress{
|
||||
get: func(context.Context, string, string, string) (string, error) {
|
||||
return "", fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
get: func(string, string, string) (string, error) { return "", fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
endpoint: endpoint,
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
@@ -40,7 +38,7 @@ func TestStepGetIPAddressShouldPassIfGetPasses(t *testing.T) {
|
||||
|
||||
for _, endpoint := range endpoints {
|
||||
var testSubject = &StepGetIPAddress{
|
||||
get: func(context.Context, string, string, string) (string, error) { return "", nil },
|
||||
get: func(string, string, string) (string, error) { return "", nil },
|
||||
endpoint: endpoint,
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
@@ -67,7 +65,7 @@ func TestStepGetIPAddressShouldTakeStepArgumentsFromStateBag(t *testing.T) {
|
||||
|
||||
for _, endpoint := range endpoints {
|
||||
var testSubject = &StepGetIPAddress{
|
||||
get: func(ctx context.Context, resourceGroupName string, ipAddressName string, nicName string) (string, error) {
|
||||
get: func(resourceGroupName string, ipAddressName string, nicName string) (string, error) {
|
||||
actualResourceGroupName = resourceGroupName
|
||||
actualIPAddressName = ipAddressName
|
||||
actualNicName = nicName
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
type StepGetOSDisk struct {
|
||||
client *AzureClient
|
||||
query func(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error)
|
||||
query func(resourceGroupName string, computeName string) (compute.VirtualMachine, error)
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
}
|
||||
@@ -30,15 +30,15 @@ func NewStepGetOSDisk(client *AzureClient, ui packer.Ui) *StepGetOSDisk {
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepGetOSDisk) queryCompute(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) {
|
||||
vm, err := s.client.VirtualMachinesClient.Get(ctx, resourceGroupName, computeName, "")
|
||||
func (s *StepGetOSDisk) 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 *StepGetOSDisk) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepGetOSDisk) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Querying the machine's properties ...")
|
||||
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
@@ -47,7 +47,7 @@ func (s *StepGetOSDisk) Run(ctx context.Context, state multistep.StateBag) multi
|
||||
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
|
||||
s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName))
|
||||
|
||||
vm, err := s.query(ctx, resourceGroupName, computeName)
|
||||
vm, err := s.query(resourceGroupName, computeName)
|
||||
if err != nil {
|
||||
state.Put(constants.Error, err)
|
||||
s.error(err)
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
|
||||
func TestStepGetOSDiskShouldFailIfGetFails(t *testing.T) {
|
||||
var testSubject = &StepGetOSDisk{
|
||||
query: func(context.Context, string, string) (compute.VirtualMachine, error) {
|
||||
query: func(string, string) (compute.VirtualMachine, error) {
|
||||
return createVirtualMachineFromUri("test.vhd"), fmt.Errorf("!! Unit Test FAIL !!")
|
||||
},
|
||||
say: func(message string) {},
|
||||
@@ -35,7 +35,7 @@ func TestStepGetOSDiskShouldFailIfGetFails(t *testing.T) {
|
||||
|
||||
func TestStepGetOSDiskShouldPassIfGetPasses(t *testing.T) {
|
||||
var testSubject = &StepGetOSDisk{
|
||||
query: func(context.Context, string, string) (compute.VirtualMachine, error) {
|
||||
query: func(string, string) (compute.VirtualMachine, error) {
|
||||
return createVirtualMachineFromUri("test.vhd"), nil
|
||||
},
|
||||
say: func(message string) {},
|
||||
@@ -59,7 +59,7 @@ func TestStepGetOSDiskShouldTakeValidateArgumentsFromStateBag(t *testing.T) {
|
||||
var actualComputeName string
|
||||
|
||||
var testSubject = &StepGetOSDisk{
|
||||
query: func(ctx context.Context, resourceGroupName string, computeName string) (compute.VirtualMachine, error) {
|
||||
query: func(resourceGroupName string, computeName string) (compute.VirtualMachine, error) {
|
||||
actualResourceGroupName = resourceGroupName
|
||||
actualComputeName = computeName
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
|
||||
type StepPowerOffCompute struct {
|
||||
client *AzureClient
|
||||
powerOff func(ctx context.Context, resourceGroupName string, computeName string) error
|
||||
powerOff func(resourceGroupName string, computeName string, cancelCh <-chan struct{}) error
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
}
|
||||
@@ -27,18 +28,17 @@ func NewStepPowerOffCompute(client *AzureClient, ui packer.Ui) *StepPowerOffComp
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepPowerOffCompute) powerOffCompute(ctx context.Context, resourceGroupName string, computeName string) error {
|
||||
f, err := s.client.VirtualMachinesClient.PowerOff(ctx, resourceGroupName, computeName)
|
||||
if err == nil {
|
||||
err = f.WaitForCompletion(ctx, s.client.VirtualMachinesClient.Client)
|
||||
}
|
||||
func (s *StepPowerOffCompute) powerOffCompute(resourceGroupName string, computeName string, cancelCh <-chan struct{}) error {
|
||||
_, errChan := s.client.PowerOff(resourceGroupName, computeName, cancelCh)
|
||||
|
||||
err := <-errChan
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepPowerOffCompute) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepPowerOffCompute) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Powering off machine ...")
|
||||
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
@@ -47,9 +47,11 @@ func (s *StepPowerOffCompute) Run(ctx context.Context, state multistep.StateBag)
|
||||
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
|
||||
s.say(fmt.Sprintf(" -> ComputeName : '%s'", computeName))
|
||||
|
||||
err := s.powerOff(ctx, resourceGroupName, computeName)
|
||||
result := common.StartInterruptibleTask(
|
||||
func() bool { return common.IsStateCancelled(state) },
|
||||
func(cancelCh <-chan struct{}) error { return s.powerOff(resourceGroupName, computeName, cancelCh) })
|
||||
|
||||
return processStepResult(err, s.error, state)
|
||||
return processInterruptibleResult(result, s.error, state)
|
||||
}
|
||||
|
||||
func (*StepPowerOffCompute) Cleanup(multistep.StateBag) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
func TestStepPowerOffComputeShouldFailIfPowerOffFails(t *testing.T) {
|
||||
var testSubject = &StepPowerOffCompute{
|
||||
powerOff: func(context.Context, string, string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
powerOff: func(string, string, <-chan struct{}) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func TestStepPowerOffComputeShouldFailIfPowerOffFails(t *testing.T) {
|
||||
|
||||
func TestStepPowerOffComputeShouldPassIfPowerOffPasses(t *testing.T) {
|
||||
var testSubject = &StepPowerOffCompute{
|
||||
powerOff: func(context.Context, string, string) error { return nil },
|
||||
powerOff: func(string, string, <-chan struct{}) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func TestStepPowerOffComputeShouldTakeStepArgumentsFromStateBag(t *testing.T) {
|
||||
var actualComputeName string
|
||||
|
||||
var testSubject = &StepPowerOffCompute{
|
||||
powerOff: func(ctx context.Context, resourceGroupName string, computeName string) error {
|
||||
powerOff: func(resourceGroupName string, computeName string, cancelCh <-chan struct{}) error {
|
||||
actualResourceGroupName = resourceGroupName
|
||||
actualComputeName = computeName
|
||||
|
||||
|
||||
@@ -8,16 +8,15 @@ import (
|
||||
)
|
||||
|
||||
type StepSaveWinRMPassword struct {
|
||||
Password string
|
||||
BuildName string
|
||||
Password string
|
||||
}
|
||||
|
||||
func (s *StepSaveWinRMPassword) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
// store so that we can access this later during provisioning
|
||||
commonhelper.SetSharedState("winrm_password", s.Password, s.BuildName)
|
||||
commonhelper.SetSharedState("winrm_password", s.Password)
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepSaveWinRMPassword) Cleanup(multistep.StateBag) {
|
||||
commonhelper.RemoveSharedStateFile("winrm_password", s.BuildName)
|
||||
commonhelper.RemoveSharedStateFile("winrm_password")
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/packer/builder/azure/common"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
)
|
||||
@@ -38,3 +39,59 @@ func TestProcessStepResultShouldHaltOnError(t *testing.T) {
|
||||
t.Errorf("Expected ActionHalt(%d), but got=%d", multistep.ActionHalt, code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessStepResultShouldContinueOnSuccessfulTask(t *testing.T) {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
result := common.InterruptibleTaskResult{
|
||||
IsCancelled: false,
|
||||
Err: nil,
|
||||
}
|
||||
|
||||
code := processInterruptibleResult(result, func(error) { t.Fatal("Should not be called!") }, stateBag)
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok {
|
||||
t.Errorf("Error was nil, but was still in the state bag.")
|
||||
}
|
||||
|
||||
if code != multistep.ActionContinue {
|
||||
t.Errorf("Expected ActionContinue(%d), but got=%d", multistep.ActionContinue, code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessStepResultShouldHaltWhenTaskIsCancelled(t *testing.T) {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
result := common.InterruptibleTaskResult{
|
||||
IsCancelled: true,
|
||||
Err: nil,
|
||||
}
|
||||
|
||||
code := processInterruptibleResult(result, func(error) { t.Fatal("Should not be called!") }, stateBag)
|
||||
if _, ok := stateBag.GetOk(constants.Error); ok {
|
||||
t.Errorf("Error was nil, but was still in the state bag.")
|
||||
}
|
||||
|
||||
if code != multistep.ActionHalt {
|
||||
t.Errorf("Expected ActionHalt(%d), but got=%d", multistep.ActionHalt, code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessStepResultShouldHaltOnTaskError(t *testing.T) {
|
||||
stateBag := new(multistep.BasicStateBag)
|
||||
isSaidError := false
|
||||
result := common.InterruptibleTaskResult{
|
||||
IsCancelled: false,
|
||||
Err: fmt.Errorf("boom"),
|
||||
}
|
||||
|
||||
code := processInterruptibleResult(result, func(error) { isSaidError = true }, stateBag)
|
||||
if _, ok := stateBag.GetOk(constants.Error); !ok {
|
||||
t.Errorf("Error was *not* nil, but was not in the state bag.")
|
||||
}
|
||||
|
||||
if !isSaidError {
|
||||
t.Errorf("Expected error to be said, but it was not.")
|
||||
}
|
||||
|
||||
if code != multistep.ActionHalt {
|
||||
t.Errorf("Expected ActionHalt(%d), but got=%d", multistep.ActionHalt, code)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
type StepValidateTemplate struct {
|
||||
client *AzureClient
|
||||
validate func(ctx context.Context, resourceGroupName string, deploymentName string) error
|
||||
validate func(resourceGroupName string, deploymentName string) error
|
||||
say func(message string)
|
||||
error func(e error)
|
||||
config *Config
|
||||
@@ -31,20 +31,20 @@ func NewStepValidateTemplate(client *AzureClient, ui packer.Ui, config *Config,
|
||||
return step
|
||||
}
|
||||
|
||||
func (s *StepValidateTemplate) validateTemplate(ctx context.Context, resourceGroupName string, deploymentName string) error {
|
||||
func (s *StepValidateTemplate) validateTemplate(resourceGroupName string, deploymentName string) error {
|
||||
deployment, err := s.factory(s.config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.client.DeploymentsClient.Validate(ctx, resourceGroupName, deploymentName, *deployment)
|
||||
_, err = s.client.Validate(resourceGroupName, deploymentName, *deployment)
|
||||
if err != nil {
|
||||
s.say(s.client.LastError.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StepValidateTemplate) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
func (s *StepValidateTemplate) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
s.say("Validating deployment template ...")
|
||||
|
||||
var resourceGroupName = state.Get(constants.ArmResourceGroupName).(string)
|
||||
@@ -53,7 +53,7 @@ func (s *StepValidateTemplate) Run(ctx context.Context, state multistep.StateBag
|
||||
s.say(fmt.Sprintf(" -> ResourceGroupName : '%s'", resourceGroupName))
|
||||
s.say(fmt.Sprintf(" -> DeploymentName : '%s'", deploymentName))
|
||||
|
||||
err := s.validate(ctx, resourceGroupName, deploymentName)
|
||||
err := s.validate(resourceGroupName, deploymentName)
|
||||
return processStepResult(err, s.error, state)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
func TestStepValidateTemplateShouldFailIfValidateFails(t *testing.T) {
|
||||
var testSubject = &StepValidateTemplate{
|
||||
validate: func(context.Context, string, string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
validate: func(string, string) error { return fmt.Errorf("!! Unit Test FAIL !!") },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
@@ -30,7 +30,7 @@ func TestStepValidateTemplateShouldFailIfValidateFails(t *testing.T) {
|
||||
|
||||
func TestStepValidateTemplateShouldPassIfValidatePasses(t *testing.T) {
|
||||
var testSubject = &StepValidateTemplate{
|
||||
validate: func(context.Context, string, string) error { return nil },
|
||||
validate: func(string, string) error { return nil },
|
||||
say: func(message string) {},
|
||||
error: func(e error) {},
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func TestStepValidateTemplateShouldTakeStepArgumentsFromStateBag(t *testing.T) {
|
||||
var actualDeploymentName string
|
||||
|
||||
var testSubject = &StepValidateTemplate{
|
||||
validate: func(ctx context.Context, resourceGroupName string, deploymentName string) error {
|
||||
validate: func(resourceGroupName string, deploymentName string) error {
|
||||
actualResourceGroupName = resourceGroupName
|
||||
actualDeploymentName = deploymentName
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ package arm
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
|
||||
|
||||
"fmt"
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
}
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
}
|
||||
|
||||
+1
-1
@@ -141,7 +141,7 @@
|
||||
"image": {
|
||||
"uri": "https://localhost/custom.vhd"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@
|
||||
"image": {
|
||||
"uri": "https://localhost/custom.vhd"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@
|
||||
"image": {
|
||||
"uri": "https://localhost/custom.vhd"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
|
||||
+1
-1
@@ -142,7 +142,7 @@
|
||||
"image": {
|
||||
"uri": "https://localhost/custom.vhd"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
|
||||
+2
-2
@@ -140,11 +140,11 @@
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"createOption": "fromImage",
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -143,11 +143,11 @@
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"createOption": "fromImage",
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux"
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -121,11 +121,11 @@
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"createOption": "fromImage",
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
}
|
||||
|
||||
+2
-2
@@ -155,11 +155,11 @@
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"createOption": "fromImage",
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Standard_LRS"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2018-02-01/resources"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/resources/resources"
|
||||
"github.com/approvals/go-approval-tests"
|
||||
"github.com/hashicorp/packer/builder/azure/common/constants"
|
||||
"github.com/hashicorp/packer/builder/azure/common/template"
|
||||
|
||||
@@ -35,5 +35,4 @@ const (
|
||||
ArmManagedImageResourceGroupName string = "arm.ManagedImageResourceGroupName"
|
||||
ArmManagedImageLocation string = "arm.ManagedImageLocation"
|
||||
ArmManagedImageName string = "arm.ManagedImageName"
|
||||
ArmAsyncResourceGroupDelete string = "arm.AsyncResourceGroupDelete"
|
||||
)
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/resources/mgmt/2016-06-01/subscriptions"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/resources/subscriptions"
|
||||
"github.com/Azure/go-autorest/autorest"
|
||||
"github.com/Azure/go-autorest/autorest/adal"
|
||||
"github.com/Azure/go-autorest/autorest/azure"
|
||||
@@ -21,8 +19,7 @@ import (
|
||||
var (
|
||||
// AD app id for packer-azure driver.
|
||||
clientIDs = map[string]string{
|
||||
azure.PublicCloud.Name: "04cc58ec-51ab-4833-ac0d-ce3a7912414b",
|
||||
azure.USGovernmentCloud.Name: "a1479822-da77-46a7-abd0-6edacc8a8fac",
|
||||
azure.PublicCloud.Name: "04cc58ec-51ab-4833-ac0d-ce3a7912414b",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -41,10 +38,8 @@ var (
|
||||
|
||||
// Authenticate fetches a token from the local file cache or initiates a consent
|
||||
// flow and waits for token to be obtained.
|
||||
func Authenticate(env azure.Environment, tenantID string, say func(string), scope string) (*adal.ServicePrincipalToken, error) {
|
||||
func Authenticate(env azure.Environment, tenantID string, say func(string)) (*adal.ServicePrincipalToken, error) {
|
||||
clientID, ok := clientIDs[env.Name]
|
||||
var resourceid string
|
||||
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("packer-azure application not set up for Azure environment %q", env.Name)
|
||||
}
|
||||
@@ -56,14 +51,9 @@ func Authenticate(env azure.Environment, tenantID string, say func(string), scop
|
||||
|
||||
// for AzurePublicCloud (https://management.core.windows.net/), this old
|
||||
// Service Management scope covers both ASM and ARM.
|
||||
apiScope := env.ServiceManagementEndpoint
|
||||
|
||||
if strings.Contains(scope, "vault") {
|
||||
resourceid = "vault"
|
||||
} else {
|
||||
resourceid = "mgmt"
|
||||
}
|
||||
|
||||
tokenPath := tokenCachePath(tenantID + resourceid)
|
||||
tokenPath := tokenCachePath(tenantID)
|
||||
saveToken := mkTokenCallback(tokenPath)
|
||||
saveTokenCallback := func(t adal.Token) error {
|
||||
say("Azure token expired. Saving the refreshed token...")
|
||||
@@ -71,23 +61,46 @@ func Authenticate(env azure.Environment, tenantID string, say func(string), scop
|
||||
}
|
||||
|
||||
// Lookup the token cache file for an existing token.
|
||||
spt, err := tokenFromFile(say, *oauthCfg, tokenPath, clientID, scope, saveTokenCallback)
|
||||
spt, err := tokenFromFile(say, *oauthCfg, tokenPath, clientID, apiScope, saveTokenCallback)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if spt != nil {
|
||||
say(fmt.Sprintf("Auth token found in file: %s", tokenPath))
|
||||
return spt, nil
|
||||
|
||||
// NOTE(ahmetalpbalkan): The token file we found may contain an
|
||||
// expired access_token. In that case, the first call to Azure SDK will
|
||||
// attempt to refresh the token using refresh_token, which might have
|
||||
// expired[1], in that case we will get an error and we shall remove the
|
||||
// token file and initiate token flow again so that the user would not
|
||||
// need removing the token cache file manually.
|
||||
//
|
||||
// [1]: expiration date of refresh_token is not returned in AAD /token
|
||||
// response, we just know it is 14 days. Therefore user’s token
|
||||
// will go stale every 14 days and we will delete the token file,
|
||||
// re-initiate the device flow.
|
||||
say("Validating the token.")
|
||||
if err = validateToken(env, spt); err != nil {
|
||||
say(fmt.Sprintf("Error: %v", err))
|
||||
say("Stored Azure credentials expired. Please reauthenticate.")
|
||||
say(fmt.Sprintf("Deleting %s", tokenPath))
|
||||
if err := os.RemoveAll(tokenPath); err != nil {
|
||||
return nil, fmt.Errorf("Error deleting stale token file: %v", err)
|
||||
}
|
||||
} else {
|
||||
say("Token works.")
|
||||
return spt, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Start an OAuth 2.0 device flow
|
||||
say(fmt.Sprintf("Initiating device flow: %s", tokenPath))
|
||||
spt, err = tokenFromDeviceFlow(say, *oauthCfg, clientID, scope)
|
||||
spt, err = tokenFromDeviceFlow(say, *oauthCfg, clientID, apiScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
say("Obtained service principal token.")
|
||||
if err := saveToken(spt.Token()); err != nil {
|
||||
if err := saveToken(spt.Token); err != nil {
|
||||
say("Error occurred saving token to cache file.")
|
||||
return nil, err
|
||||
}
|
||||
@@ -168,17 +181,31 @@ func mkTokenCallback(path string) adal.TokenRefreshCallback {
|
||||
}
|
||||
}
|
||||
|
||||
// validateToken makes a call to Azure SDK with given token, essentially making
|
||||
// sure if the access_token valid, if not it uses SDK’s functionality to
|
||||
// automatically refresh the token using refresh_token (which might have
|
||||
// expired). This check is essentially to make sure refresh_token is good.
|
||||
func validateToken(env azure.Environment, token *adal.ServicePrincipalToken) error {
|
||||
c := subscriptionsClient(env.ResourceManagerEndpoint)
|
||||
c.Authorizer = autorest.NewBearerAuthorizer(token)
|
||||
_, err := c.List()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Token validity check failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindTenantID figures out the AAD tenant ID of the subscription by making an
|
||||
// unauthenticated request to the Get Subscription Details endpoint and parses
|
||||
// the value from WWW-Authenticate header.
|
||||
func FindTenantID(env azure.Environment, subscriptionID string) (string, error) {
|
||||
const hdrKey = "WWW-Authenticate"
|
||||
c := subscriptions.NewClientWithBaseURI(env.ResourceManagerEndpoint)
|
||||
c := subscriptionsClient(env.ResourceManagerEndpoint)
|
||||
|
||||
// we expect this request to fail (err != nil), but we are only interested
|
||||
// in headers, so surface the error if the Response is not present (i.e.
|
||||
// network error etc)
|
||||
subs, err := c.Get(context.TODO(), subscriptionID)
|
||||
subs, err := c.Get(subscriptionID)
|
||||
if subs.Response.Response == nil {
|
||||
return "", fmt.Errorf("Request failed: %v", err)
|
||||
}
|
||||
@@ -201,3 +228,8 @@ func FindTenantID(env azure.Environment, subscriptionID string) (string, error)
|
||||
}
|
||||
return m[1], nil
|
||||
}
|
||||
|
||||
func subscriptionsClient(baseURI string) subscriptions.GroupClient {
|
||||
client := subscriptions.NewGroupClientWithBaseURI(baseURI)
|
||||
return client
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type InterruptibleTaskResult struct {
|
||||
Err error
|
||||
IsCancelled bool
|
||||
}
|
||||
|
||||
type InterruptibleTask struct {
|
||||
IsCancelled func() bool
|
||||
Task func(cancelCh <-chan struct{}) error
|
||||
}
|
||||
|
||||
func NewInterruptibleTask(isCancelled func() bool, task func(cancelCh <-chan struct{}) error) *InterruptibleTask {
|
||||
return &InterruptibleTask{
|
||||
IsCancelled: isCancelled,
|
||||
Task: task,
|
||||
}
|
||||
}
|
||||
|
||||
func StartInterruptibleTask(isCancelled func() bool, task func(cancelCh <-chan struct{}) error) InterruptibleTaskResult {
|
||||
t := NewInterruptibleTask(isCancelled, task)
|
||||
return t.Run()
|
||||
}
|
||||
|
||||
func (s *InterruptibleTask) Run() InterruptibleTaskResult {
|
||||
completeCh := make(chan error)
|
||||
|
||||
cancelCh := make(chan struct{})
|
||||
defer close(cancelCh)
|
||||
|
||||
go func() {
|
||||
err := s.Task(cancelCh)
|
||||
completeCh <- err
|
||||
|
||||
// senders close, receivers check for close
|
||||
close(completeCh)
|
||||
}()
|
||||
|
||||
for {
|
||||
if s.IsCancelled() {
|
||||
return InterruptibleTaskResult{Err: nil, IsCancelled: true}
|
||||
}
|
||||
|
||||
select {
|
||||
case err := <-completeCh:
|
||||
return InterruptibleTaskResult{Err: err, IsCancelled: false}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestInterruptibleTaskShouldImmediatelyEndOnCancel(t *testing.T) {
|
||||
testSubject := NewInterruptibleTask(
|
||||
func() bool { return true },
|
||||
func(<-chan struct{}) error {
|
||||
for {
|
||||
time.Sleep(time.Second * 30)
|
||||
}
|
||||
})
|
||||
|
||||
result := testSubject.Run()
|
||||
if result.IsCancelled != true {
|
||||
t.Fatal("Expected the task to be cancelled, but it was not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterruptibleTaskShouldRunTaskUntilCompletion(t *testing.T) {
|
||||
var count int
|
||||
|
||||
testSubject := &InterruptibleTask{
|
||||
IsCancelled: func() bool {
|
||||
return false
|
||||
},
|
||||
Task: func(<-chan struct{}) error {
|
||||
for i := 0; i < 10; i++ {
|
||||
count += 1
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
result := testSubject.Run()
|
||||
if result.IsCancelled != false {
|
||||
t.Errorf("Expected the task to *not* be cancelled, but it was.")
|
||||
}
|
||||
|
||||
if count != 10 {
|
||||
t.Errorf("Expected the task to wait for completion, but it did not.")
|
||||
}
|
||||
|
||||
if result.Err != nil {
|
||||
t.Errorf("Expected the task to return a nil error, but got=%s", result.Err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterruptibleTaskShouldImmediatelyStopOnTaskError(t *testing.T) {
|
||||
testSubject := &InterruptibleTask{
|
||||
IsCancelled: func() bool {
|
||||
return false
|
||||
},
|
||||
Task: func(cancelCh <-chan struct{}) error {
|
||||
return fmt.Errorf("boom")
|
||||
},
|
||||
}
|
||||
|
||||
result := testSubject.Run()
|
||||
if result.IsCancelled != false {
|
||||
t.Errorf("Expected the task to *not* be cancelled, but it was.")
|
||||
}
|
||||
|
||||
if result.Err == nil {
|
||||
t.Errorf("Expected the task to return an error, but it did not.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterruptibleTaskShouldProvideLiveChannel(t *testing.T) {
|
||||
testSubject := &InterruptibleTask{
|
||||
IsCancelled: func() bool {
|
||||
return false
|
||||
},
|
||||
Task: func(cancelCh <-chan struct{}) error {
|
||||
isOpen := false
|
||||
|
||||
select {
|
||||
case _, ok := <-cancelCh:
|
||||
isOpen = !ok
|
||||
if !isOpen {
|
||||
t.Errorf("Expected the channel to open, but it was closed.")
|
||||
}
|
||||
default:
|
||||
isOpen = true
|
||||
break
|
||||
}
|
||||
|
||||
if !isOpen {
|
||||
t.Errorf("Check for openness failed.")
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
testSubject.Run()
|
||||
}
|
||||
@@ -103,7 +103,7 @@
|
||||
"storageProfile": {
|
||||
"osDisk": {
|
||||
"osType": "Linux",
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
},
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package template
|
||||
|
||||
import (
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2018-01-01/network"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/network"
|
||||
)
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/Azure/go-autorest/autorest/to"
|
||||
)
|
||||
|
||||
@@ -111,8 +111,9 @@ func (s *TemplateBuilder) SetManagedDiskUrl(managedImageId string, storageAccoun
|
||||
profile.ImageReference = &compute.ImageReference{
|
||||
ID: &managedImageId,
|
||||
}
|
||||
profile.OsDisk.Name = to.StringPtr("osdisk")
|
||||
profile.OsDisk.OsType = s.osType
|
||||
profile.OsDisk.CreateOption = compute.DiskCreateOptionTypesFromImage
|
||||
profile.OsDisk.CreateOption = compute.FromImage
|
||||
profile.OsDisk.Vhd = nil
|
||||
profile.OsDisk.ManagedDisk = &compute.ManagedDiskParameters{
|
||||
StorageAccountType: storageAccountType,
|
||||
@@ -135,8 +136,9 @@ func (s *TemplateBuilder) SetManagedMarketplaceImage(location, publisher, offer,
|
||||
Version: &version,
|
||||
//ID: &imageID,
|
||||
}
|
||||
profile.OsDisk.Name = to.StringPtr("osdisk")
|
||||
profile.OsDisk.OsType = s.osType
|
||||
profile.OsDisk.CreateOption = compute.DiskCreateOptionTypesFromImage
|
||||
profile.OsDisk.CreateOption = compute.FromImage
|
||||
profile.OsDisk.Vhd = nil
|
||||
profile.OsDisk.ManagedDisk = &compute.ManagedDiskParameters{
|
||||
StorageAccountType: storageAccountType,
|
||||
@@ -581,7 +583,7 @@ const BasicTemplate = `{
|
||||
},
|
||||
"storageProfile": {
|
||||
"osDisk": {
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
},
|
||||
|
||||
@@ -144,7 +144,7 @@
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
"image": {
|
||||
"uri": "http://azure/custom.vhd"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
"image": {
|
||||
"uri": "http://azure/custom.vhd"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Linux",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
}
|
||||
|
||||
+2
-2
@@ -179,11 +179,11 @@
|
||||
},
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"createOption": "fromImage",
|
||||
"managedDisk": {
|
||||
"storageAccountType": "Premium_LRS"
|
||||
},
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"osType": "Windows"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@
|
||||
"osDisk": {
|
||||
"caching": "ReadWrite",
|
||||
"createOption": "FromImage",
|
||||
"name": "[parameters('osDiskName')]",
|
||||
"name": "osdisk",
|
||||
"vhd": {
|
||||
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package template
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/Azure/azure-sdk-for-go/services/compute/mgmt/2018-04-01/compute"
|
||||
"github.com/Azure/azure-sdk-for-go/arm/compute"
|
||||
"github.com/approvals/go-approval-tests"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package googlecompute
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -200,8 +199,7 @@ func TestConfigPrepare(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
raw := testConfig(t)
|
||||
|
||||
if tc.Value == nil {
|
||||
delete(raw, tc.Key)
|
||||
@@ -253,8 +251,7 @@ func TestConfigPrepareAccelerator(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
raw := testConfig(t)
|
||||
|
||||
errStr := ""
|
||||
for k := range tc.Keys {
|
||||
@@ -303,8 +300,7 @@ func TestConfigPrepareServiceAccount(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
raw := testConfig(t)
|
||||
|
||||
errStr := ""
|
||||
for k := range tc.Keys {
|
||||
@@ -346,8 +342,7 @@ func TestConfigDefaults(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
raw := testConfig(t)
|
||||
|
||||
c, warns, errs := NewConfig(raw)
|
||||
testConfigOk(t, warns, errs)
|
||||
@@ -360,10 +355,7 @@ func TestConfigDefaults(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestImageName(t *testing.T) {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
c, _, _ := NewConfig(raw)
|
||||
c, _, _ := NewConfig(testConfig(t))
|
||||
if !strings.HasPrefix(c.ImageName, "packer-") {
|
||||
t.Fatalf("ImageName should have 'packer-' prefix, found %s", c.ImageName)
|
||||
}
|
||||
@@ -373,10 +365,7 @@ func TestImageName(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRegion(t *testing.T) {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
c, _, _ := NewConfig(raw)
|
||||
c, _, _ := NewConfig(testConfig(t))
|
||||
if c.Region != "us-east1" {
|
||||
t.Fatalf("Region should be 'us-east1' given Zone of 'us-east1-a', but is %s", c.Region)
|
||||
}
|
||||
@@ -384,11 +373,9 @@ func TestRegion(t *testing.T) {
|
||||
|
||||
// Helper stuff below
|
||||
|
||||
func testConfig(t *testing.T) (config map[string]interface{}, tempAccountFile string) {
|
||||
tempAccountFile = testAccountFile(t)
|
||||
|
||||
config = map[string]interface{}{
|
||||
"account_file": tempAccountFile,
|
||||
func testConfig(t *testing.T) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"account_file": testAccountFile(t),
|
||||
"project_id": "hashicorp",
|
||||
"source_image": "foo",
|
||||
"ssh_username": "root",
|
||||
@@ -402,15 +389,10 @@ func testConfig(t *testing.T) (config map[string]interface{}, tempAccountFile st
|
||||
},
|
||||
"zone": "us-east1-a",
|
||||
}
|
||||
|
||||
return config, tempAccountFile
|
||||
}
|
||||
|
||||
func testConfigStruct(t *testing.T) *Config {
|
||||
raw, tempfile := testConfig(t)
|
||||
defer os.Remove(tempfile)
|
||||
|
||||
c, warns, errs := NewConfig(raw)
|
||||
c, warns, errs := NewConfig(testConfig(t))
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", len(warns))
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
compute "google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/compute/v1"
|
||||
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/helper/useragent"
|
||||
@@ -168,7 +168,7 @@ func (d *driverGCE) DeleteDisk(zone, name string) (<-chan error, error) {
|
||||
}
|
||||
|
||||
func (d *driverGCE) GetImage(name string, fromFamily bool) (*Image, error) {
|
||||
projects := []string{d.projectId, "centos-cloud", "coreos-cloud", "cos-cloud", "debian-cloud", "google-containers", "opensuse-cloud", "rhel-cloud", "suse-cloud", "ubuntu-os-cloud", "windows-cloud", "gce-nvme", "windows-sql-cloud"}
|
||||
projects := []string{d.projectId, "centos-cloud", "coreos-cloud", "cos-cloud", "debian-cloud", "google-containers", "opensuse-cloud", "rhel-cloud", "suse-cloud", "ubuntu-os-cloud", "windows-cloud", "gce-nvme"}
|
||||
var errs error
|
||||
for _, project := range projects {
|
||||
image, err := d.GetImageFromProject(project, name, fromFamily)
|
||||
|
||||
@@ -55,7 +55,6 @@ func TestStepCreateSSHKey_debug(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
tf.Close()
|
||||
|
||||
state := testState(t)
|
||||
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
commonhelper "github.com/hashicorp/packer/helper/common"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
@@ -113,7 +112,6 @@ func (s *StepCreateWindowsPassword) Run(_ context.Context, state multistep.State
|
||||
}
|
||||
|
||||
state.Put("winrm_password", data.password)
|
||||
commonhelper.SetSharedState("winrm_password", data.password, c.PackerConfig.PackerBuildName)
|
||||
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
@@ -75,7 +75,6 @@ func TestStepCreateOrResetWindowsPassword_debug(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
defer os.Remove(tf.Name())
|
||||
tf.Close()
|
||||
|
||||
state := testState(t)
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// A driver is able to talk to HyperV and perform certain
|
||||
// operations with it. Some of the operations on here may seem overly
|
||||
// specific, but they were built specifically in mind to handle features
|
||||
@@ -70,7 +66,7 @@ type Driver interface {
|
||||
|
||||
DeleteVirtualSwitch(string) error
|
||||
|
||||
CreateVirtualMachine(string, string, string, string, int64, int64, int64, string, uint, bool, bool) error
|
||||
CreateVirtualMachine(string, string, string, string, int64, int64, int64, string, uint, bool) error
|
||||
|
||||
AddVirtualMachineHardDrive(string, string, string, int64, int64, string) error
|
||||
|
||||
@@ -86,7 +82,7 @@ type Driver interface {
|
||||
|
||||
SetVirtualMachineDynamicMemory(string, bool) error
|
||||
|
||||
SetVirtualMachineSecureBoot(string, bool, string) error
|
||||
SetVirtualMachineSecureBoot(string, bool) error
|
||||
|
||||
SetVirtualMachineVirtualizationExtensions(string, bool) error
|
||||
|
||||
@@ -113,10 +109,4 @@ type Driver interface {
|
||||
MountFloppyDrive(string, string) error
|
||||
|
||||
UnmountFloppyDrive(string) error
|
||||
|
||||
// Connect connects to a VM specified by the name given.
|
||||
Connect(string) (context.CancelFunc, error)
|
||||
|
||||
// Disconnect disconnects to a VM specified by the context cancel function.
|
||||
Disconnect(context.CancelFunc)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type DriverMock struct {
|
||||
IsRunning_Called bool
|
||||
IsRunning_VmName string
|
||||
@@ -131,7 +127,6 @@ type DriverMock struct {
|
||||
CreateVirtualMachine_SwitchName string
|
||||
CreateVirtualMachine_Generation uint
|
||||
CreateVirtualMachine_DifferentialDisk bool
|
||||
CreateVirtualMachine_FixedVHD bool
|
||||
CreateVirtualMachine_Err error
|
||||
|
||||
CloneVirtualMachine_Called bool
|
||||
@@ -165,11 +160,10 @@ type DriverMock struct {
|
||||
SetVirtualMachineDynamicMemory_Enable bool
|
||||
SetVirtualMachineDynamicMemory_Err error
|
||||
|
||||
SetVirtualMachineSecureBoot_Called bool
|
||||
SetVirtualMachineSecureBoot_VmName string
|
||||
SetVirtualMachineSecureBoot_TemplateName string
|
||||
SetVirtualMachineSecureBoot_Enable bool
|
||||
SetVirtualMachineSecureBoot_Err error
|
||||
SetVirtualMachineSecureBoot_Called bool
|
||||
SetVirtualMachineSecureBoot_VmName string
|
||||
SetVirtualMachineSecureBoot_Enable bool
|
||||
SetVirtualMachineSecureBoot_Err error
|
||||
|
||||
SetVirtualMachineVirtualizationExtensions_Called bool
|
||||
SetVirtualMachineVirtualizationExtensions_VmName string
|
||||
@@ -244,14 +238,6 @@ type DriverMock struct {
|
||||
UnmountFloppyDrive_Called bool
|
||||
UnmountFloppyDrive_VmName string
|
||||
UnmountFloppyDrive_Err error
|
||||
|
||||
Connect_Called bool
|
||||
Connect_VmName string
|
||||
Connect_Cancel context.CancelFunc
|
||||
Connect_Err error
|
||||
|
||||
Disconnect_Called bool
|
||||
Disconnect_Cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func (d *DriverMock) IsRunning(vmName string) (bool, error) {
|
||||
@@ -404,7 +390,7 @@ func (d *DriverMock) AddVirtualMachineHardDrive(vmName string, vhdFile string, v
|
||||
return d.AddVirtualMachineHardDrive_Err
|
||||
}
|
||||
|
||||
func (d *DriverMock) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool, fixedVHD bool) error {
|
||||
func (d *DriverMock) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool) error {
|
||||
d.CreateVirtualMachine_Called = true
|
||||
d.CreateVirtualMachine_VmName = vmName
|
||||
d.CreateVirtualMachine_Path = path
|
||||
@@ -460,11 +446,10 @@ func (d *DriverMock) SetVirtualMachineDynamicMemory(vmName string, enable bool)
|
||||
return d.SetVirtualMachineDynamicMemory_Err
|
||||
}
|
||||
|
||||
func (d *DriverMock) SetVirtualMachineSecureBoot(vmName string, enable bool, templateName string) error {
|
||||
func (d *DriverMock) SetVirtualMachineSecureBoot(vmName string, enable bool) error {
|
||||
d.SetVirtualMachineSecureBoot_Called = true
|
||||
d.SetVirtualMachineSecureBoot_VmName = vmName
|
||||
d.SetVirtualMachineSecureBoot_Enable = enable
|
||||
d.SetVirtualMachineSecureBoot_TemplateName = templateName
|
||||
return d.SetVirtualMachineSecureBoot_Err
|
||||
}
|
||||
|
||||
@@ -565,14 +550,3 @@ func (d *DriverMock) UnmountFloppyDrive(vmName string) error {
|
||||
d.UnmountFloppyDrive_VmName = vmName
|
||||
return d.UnmountFloppyDrive_Err
|
||||
}
|
||||
|
||||
func (d *DriverMock) Connect(vmName string) (context.CancelFunc, error) {
|
||||
d.Connect_Called = true
|
||||
d.Connect_VmName = vmName
|
||||
return d.Connect_Cancel, d.Connect_Err
|
||||
}
|
||||
|
||||
func (d *DriverMock) Disconnect(cancel context.CancelFunc) {
|
||||
d.Disconnect_Called = true
|
||||
d.Disconnect_Cancel = cancel
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"runtime"
|
||||
@@ -179,8 +178,8 @@ func (d *HypervPS4Driver) AddVirtualMachineHardDrive(vmName string, vhdFile stri
|
||||
return hyperv.AddVirtualMachineHardDiskDrive(vmName, vhdFile, vhdName, vhdSizeBytes, diskBlockSize, controllerType)
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool, fixedVHD bool) error {
|
||||
return hyperv.CreateVirtualMachine(vmName, path, harddrivePath, vhdPath, ram, diskSize, diskBlockSize, switchName, generation, diffDisks, fixedVHD)
|
||||
func (d *HypervPS4Driver) CreateVirtualMachine(vmName string, path string, harddrivePath string, vhdPath string, ram int64, diskSize int64, diskBlockSize int64, switchName string, generation uint, diffDisks bool) error {
|
||||
return hyperv.CreateVirtualMachine(vmName, path, harddrivePath, vhdPath, ram, diskSize, diskBlockSize, switchName, generation, diffDisks)
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) CloneVirtualMachine(cloneFromVmxcPath string, cloneFromVmName string, cloneFromSnapshotName string, cloneAllSnapshots bool, vmName string, path string, harddrivePath string, ram int64, switchName string) error {
|
||||
@@ -203,8 +202,8 @@ func (d *HypervPS4Driver) SetVirtualMachineDynamicMemory(vmName string, enable b
|
||||
return hyperv.SetVirtualMachineDynamicMemory(vmName, enable)
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) SetVirtualMachineSecureBoot(vmName string, enable bool, templateName string) error {
|
||||
return hyperv.SetVirtualMachineSecureBoot(vmName, enable, templateName)
|
||||
func (d *HypervPS4Driver) SetVirtualMachineSecureBoot(vmName string, enable bool) error {
|
||||
return hyperv.SetVirtualMachineSecureBoot(vmName, enable)
|
||||
}
|
||||
|
||||
func (d *HypervPS4Driver) SetVirtualMachineVirtualizationExtensions(vmName string, enable bool) error {
|
||||
@@ -348,14 +347,3 @@ func (d *HypervPS4Driver) verifyHypervPermissions() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Connect connects to a VM specified by the name given.
|
||||
func (d *HypervPS4Driver) Connect(vmName string) (context.CancelFunc, error) {
|
||||
return hyperv.ConnectVirtualMachine(vmName)
|
||||
}
|
||||
|
||||
// Disconnect disconnects to a VM specified by calling the context cancel function returned
|
||||
// from Connect.
|
||||
func (d *HypervPS4Driver) Disconnect(cancel context.CancelFunc) {
|
||||
hyperv.DisconnectVirtualMachine(cancel)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ type StepCloneVM struct {
|
||||
EnableMacSpoofing bool
|
||||
EnableDynamicMemory bool
|
||||
EnableSecureBoot bool
|
||||
SecureBootTemplate string
|
||||
EnableVirtualizationExtensions bool
|
||||
MacAddress string
|
||||
}
|
||||
@@ -100,8 +99,7 @@ func (s *StepCloneVM) Run(_ context.Context, state multistep.StateBag) multistep
|
||||
}
|
||||
|
||||
if generation == 2 {
|
||||
|
||||
err = driver.SetVirtualMachineSecureBoot(s.VMName, s.EnableSecureBoot, s.SecureBootTemplate)
|
||||
err = driver.SetVirtualMachineSecureBoot(s.VMName, s.EnableSecureBoot)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error setting secure boot: %s", err)
|
||||
state.Put("error", err)
|
||||
|
||||
@@ -27,14 +27,12 @@ type StepCreateVM struct {
|
||||
EnableMacSpoofing bool
|
||||
EnableDynamicMemory bool
|
||||
EnableSecureBoot bool
|
||||
SecureBootTemplate string
|
||||
EnableVirtualizationExtensions bool
|
||||
AdditionalDiskSize []uint
|
||||
DifferencingDisk bool
|
||||
MacAddress string
|
||||
SkipExport bool
|
||||
OutputDir string
|
||||
FixedVHD bool
|
||||
}
|
||||
|
||||
func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
@@ -69,7 +67,7 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste
|
||||
diskSize := int64(s.DiskSize * 1024 * 1024)
|
||||
diskBlockSize := int64(s.DiskBlockSize * 1024 * 1024)
|
||||
|
||||
err := driver.CreateVirtualMachine(s.VMName, path, harddrivePath, vhdPath, ramSize, diskSize, diskBlockSize, s.SwitchName, s.Generation, s.DifferencingDisk, s.FixedVHD)
|
||||
err := driver.CreateVirtualMachine(s.VMName, path, harddrivePath, vhdPath, ramSize, diskSize, diskBlockSize, s.SwitchName, s.Generation, s.DifferencingDisk)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error creating virtual machine: %s", err)
|
||||
state.Put("error", err)
|
||||
@@ -104,7 +102,7 @@ func (s *StepCreateVM) Run(_ context.Context, state multistep.StateBag) multiste
|
||||
}
|
||||
|
||||
if s.Generation == 2 {
|
||||
err = driver.SetVirtualMachineSecureBoot(s.VMName, s.EnableSecureBoot, s.SecureBootTemplate)
|
||||
err = driver.SetVirtualMachineSecureBoot(s.VMName, s.EnableSecureBoot)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error setting secure boot: %s", err)
|
||||
state.Put("error", err)
|
||||
|
||||
@@ -3,16 +3,13 @@ package common
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
)
|
||||
|
||||
type StepRun struct {
|
||||
GuiCancelFunc context.CancelFunc
|
||||
Headless bool
|
||||
vmName string
|
||||
vmName string
|
||||
}
|
||||
|
||||
func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
@@ -32,13 +29,6 @@ func (s *StepRun) Run(_ context.Context, state multistep.StateBag) multistep.Ste
|
||||
|
||||
s.vmName = vmName
|
||||
|
||||
if !s.Headless {
|
||||
ui.Say("Attempting to connect with vmconnect...")
|
||||
s.GuiCancelFunc, err = driver.Connect(vmName)
|
||||
if err != nil {
|
||||
log.Printf(fmt.Sprintf("Non-fatal error starting vmconnect: %s. continuing...", err))
|
||||
}
|
||||
}
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
@@ -50,11 +40,6 @@ func (s *StepRun) Cleanup(state multistep.StateBag) {
|
||||
driver := state.Get("driver").(Driver)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if !s.Headless && s.GuiCancelFunc != nil {
|
||||
ui.Say("Disconnecting from vmconnect...")
|
||||
s.GuiCancelFunc()
|
||||
}
|
||||
|
||||
if running, _ := driver.IsRunning(s.vmName); running {
|
||||
if err := driver.Stop(s.vmName); err != nil {
|
||||
ui.Error(fmt.Sprintf("Error shutting down VM: %s", err))
|
||||
|
||||
@@ -24,7 +24,6 @@ const (
|
||||
DefaultDiskSize = 40 * 1024 // ~40GB
|
||||
MinDiskSize = 256 // 256MB
|
||||
MaxDiskSize = 64 * 1024 * 1024 // 64TB
|
||||
MaxVHDSize = 2040 * 1024 // 2040GB
|
||||
|
||||
DefaultDiskBlockSize = 32 // 32MB
|
||||
MinDiskBlockSize = 1 // 1MB
|
||||
@@ -92,7 +91,6 @@ type Config struct {
|
||||
EnableMacSpoofing bool `mapstructure:"enable_mac_spoofing"`
|
||||
EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory"`
|
||||
EnableSecureBoot bool `mapstructure:"enable_secure_boot"`
|
||||
SecureBootTemplate string `mapstructure:"secure_boot_template"`
|
||||
EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions"`
|
||||
TempPath string `mapstructure:"temp_path"`
|
||||
|
||||
@@ -112,11 +110,6 @@ type Config struct {
|
||||
// Use differencing disk
|
||||
DifferencingDisk bool `mapstructure:"differencing_disk"`
|
||||
|
||||
// Create the VM with a Fixed VHD format disk instead of Dynamic VHDX
|
||||
FixedVHD bool `mapstructure:"use_fixed_vhd_format"`
|
||||
|
||||
Headless bool `mapstructure:"headless"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
@@ -277,21 +270,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if b.config.Generation > 1 && b.config.FixedVHD {
|
||||
err = errors.New("Fixed VHD disks are only supported on Generation 1 virtual machines.")
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
|
||||
if !b.config.SkipCompaction && b.config.FixedVHD {
|
||||
err = errors.New("Fixed VHD disks do not support compaction.")
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
|
||||
if b.config.DifferencingDisk && b.config.FixedVHD {
|
||||
err = errors.New("Fixed VHD disks are not supported with differencing disks.")
|
||||
errs = packer.MultiErrorAppend(errs, err)
|
||||
}
|
||||
|
||||
// Warnings
|
||||
|
||||
if b.config.ShutdownCommand == "" {
|
||||
@@ -395,14 +373,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
EnableMacSpoofing: b.config.EnableMacSpoofing,
|
||||
EnableDynamicMemory: b.config.EnableDynamicMemory,
|
||||
EnableSecureBoot: b.config.EnableSecureBoot,
|
||||
SecureBootTemplate: b.config.SecureBootTemplate,
|
||||
EnableVirtualizationExtensions: b.config.EnableVirtualizationExtensions,
|
||||
AdditionalDiskSize: b.config.AdditionalDiskSize,
|
||||
DifferencingDisk: b.config.DifferencingDisk,
|
||||
SkipExport: b.config.SkipExport,
|
||||
OutputDir: b.config.OutputDir,
|
||||
MacAddress: b.config.MacAddress,
|
||||
FixedVHD: b.config.FixedVHD,
|
||||
},
|
||||
&hypervcommon.StepEnableIntegrationService{},
|
||||
|
||||
@@ -429,9 +404,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
SwitchVlanId: b.config.SwitchVlanId,
|
||||
},
|
||||
|
||||
&hypervcommon.StepRun{
|
||||
Headless: b.config.Headless,
|
||||
},
|
||||
&hypervcommon.StepRun{},
|
||||
|
||||
&hypervcommon.StepTypeBootCommand{
|
||||
BootCommand: b.config.FlatBootCommand(),
|
||||
@@ -527,10 +500,8 @@ func (b *Builder) checkDiskSize() error {
|
||||
|
||||
if b.config.DiskSize < MinDiskSize {
|
||||
return fmt.Errorf("disk_size: Virtual machine requires disk space >= %v GB, but defined: %v", MinDiskSize, b.config.DiskSize/1024)
|
||||
} else if b.config.DiskSize > MaxDiskSize && !b.config.FixedVHD {
|
||||
} else if b.config.DiskSize > MaxDiskSize {
|
||||
return fmt.Errorf("disk_size: Virtual machine requires disk space <= %v GB, but defined: %v", MaxDiskSize, b.config.DiskSize/1024)
|
||||
} else if b.config.DiskSize > MaxVHDSize && b.config.FixedVHD {
|
||||
return fmt.Errorf("disk_size: Virtual machine requires disk space <= %v GB, but defined: %v", MaxVHDSize/1024, b.config.DiskSize/1024)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -139,59 +139,6 @@ func TestBuilderPrepare_DiskBlockSize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_FixedVHDFormat(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
config["use_fixed_vhd_format"] = true
|
||||
config["generation"] = 1
|
||||
config["skip_compaction"] = true
|
||||
config["differencing_disk"] = false
|
||||
|
||||
//use_fixed_vhd_format should work with generation = 1, skip_compaction = true, and differencing_disk = false
|
||||
warns, err := b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("bad err: %s", err)
|
||||
}
|
||||
|
||||
//use_fixed_vhd_format should not work with differencing_disk = true
|
||||
config["differencing_disk"] = true
|
||||
b = Builder{}
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
config["differencing_disk"] = false
|
||||
|
||||
//use_fixed_vhd_format should not work with skip_compaction = false
|
||||
config["skip_compaction"] = false
|
||||
b = Builder{}
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
config["skip_compaction"] = true
|
||||
|
||||
//use_fixed_vhd_format should not work with generation = 2
|
||||
config["generation"] = 2
|
||||
b = Builder{}
|
||||
warns, err = b.Prepare(config)
|
||||
if len(warns) > 0 {
|
||||
t.Fatalf("bad: %#v", warns)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatal("should have error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderPrepare_FloppyFiles(t *testing.T) {
|
||||
var b Builder
|
||||
config := testConfig()
|
||||
|
||||
@@ -86,11 +86,10 @@ type Config struct {
|
||||
VlanId string `mapstructure:"vlan_id"`
|
||||
Cpu uint `mapstructure:"cpu"`
|
||||
Generation uint
|
||||
EnableMacSpoofing bool `mapstructure:"enable_mac_spoofing"`
|
||||
EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory"`
|
||||
EnableSecureBoot bool `mapstructure:"enable_secure_boot"`
|
||||
SecureBootTemplate string `mapstructure:"secure_boot_template"`
|
||||
EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions"`
|
||||
EnableMacSpoofing bool `mapstructure:"enable_mac_spoofing"`
|
||||
EnableDynamicMemory bool `mapstructure:"enable_dynamic_memory"`
|
||||
EnableSecureBoot bool `mapstructure:"enable_secure_boot"`
|
||||
EnableVirtualizationExtensions bool `mapstructure:"enable_virtualization_extensions"`
|
||||
|
||||
Communicator string `mapstructure:"communicator"`
|
||||
|
||||
@@ -98,8 +97,6 @@ type Config struct {
|
||||
|
||||
SkipExport bool `mapstructure:"skip_export"`
|
||||
|
||||
Headless bool `mapstructure:"headless"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
@@ -408,7 +405,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
EnableMacSpoofing: b.config.EnableMacSpoofing,
|
||||
EnableDynamicMemory: b.config.EnableDynamicMemory,
|
||||
EnableSecureBoot: b.config.EnableSecureBoot,
|
||||
SecureBootTemplate: b.config.SecureBootTemplate,
|
||||
EnableVirtualizationExtensions: b.config.EnableVirtualizationExtensions,
|
||||
MacAddress: b.config.MacAddress,
|
||||
},
|
||||
@@ -438,9 +434,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
SwitchVlanId: b.config.SwitchVlanId,
|
||||
},
|
||||
|
||||
&hypervcommon.StepRun{
|
||||
Headless: b.config.Headless,
|
||||
},
|
||||
&hypervcommon.StepRun{},
|
||||
|
||||
&hypervcommon.StepTypeBootCommand{
|
||||
BootCommand: b.config.FlatBootCommand(),
|
||||
|
||||
@@ -52,11 +52,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
// By default, instance name is same as image name
|
||||
if b.config.InstanceName == "" {
|
||||
b.config.InstanceName = b.config.ImageName
|
||||
}
|
||||
|
||||
log.Println(common.ScrubConfig(b.config, b.config.Password))
|
||||
return nil, nil
|
||||
}
|
||||
@@ -87,7 +82,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
SSHAgentAuth: b.config.RunConfig.Comm.SSHAgentAuth,
|
||||
},
|
||||
&StepRunSourceServer{
|
||||
Name: b.config.InstanceName,
|
||||
Name: b.config.ImageName,
|
||||
SourceImage: b.config.SourceImage,
|
||||
SourceImageName: b.config.SourceImageName,
|
||||
SecurityGroups: b.config.SecurityGroups,
|
||||
|
||||
@@ -30,7 +30,6 @@ type RunConfig struct {
|
||||
Networks []string `mapstructure:"networks"`
|
||||
UserData string `mapstructure:"user_data"`
|
||||
UserDataFile string `mapstructure:"user_data_file"`
|
||||
InstanceName string `mapstructure:"instance_name"`
|
||||
InstanceMetadata map[string]string `mapstructure:"instance_metadata"`
|
||||
|
||||
ConfigDrive bool `mapstructure:"config_drive"`
|
||||
|
||||
@@ -3,12 +3,12 @@ package oci
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/oracle/oci-go-sdk/core"
|
||||
client "github.com/hashicorp/packer/builder/oracle/oci/client"
|
||||
)
|
||||
|
||||
// Artifact is an artifact implementation that contains a built Custom Image.
|
||||
type Artifact struct {
|
||||
Image core.Image
|
||||
Image client.Image
|
||||
Region string
|
||||
driver Driver
|
||||
}
|
||||
@@ -26,18 +26,13 @@ func (a *Artifact) Files() []string {
|
||||
|
||||
// Id returns the OCID of the associated Image.
|
||||
func (a *Artifact) Id() string {
|
||||
return *a.Image.Id
|
||||
return a.Image.ID
|
||||
}
|
||||
|
||||
func (a *Artifact) String() string {
|
||||
var displayName string
|
||||
if a.Image.DisplayName != nil {
|
||||
displayName = *a.Image.DisplayName
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"An image was created: '%v' (OCID: %v) in region '%v'",
|
||||
displayName, *a.Image.Id, a.Region,
|
||||
a.Image.DisplayName, a.Image.ID, a.Region,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -47,5 +42,5 @@ func (a *Artifact) State(name string) interface{} {
|
||||
|
||||
// Destroy deletes the custom image associated with the artifact.
|
||||
func (a *Artifact) Destroy() error {
|
||||
return a.driver.DeleteImage(*a.Image.Id)
|
||||
return a.driver.DeleteImage(a.Image.ID)
|
||||
}
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
"log"
|
||||
|
||||
ocommon "github.com/hashicorp/packer/builder/oracle/common"
|
||||
client "github.com/hashicorp/packer/builder/oracle/oci/client"
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/helper/communicator"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/oracle/oci-go-sdk/core"
|
||||
)
|
||||
|
||||
// BuilderId uniquely identifies the builder
|
||||
@@ -78,15 +78,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||
return nil, rawErr.(error)
|
||||
}
|
||||
|
||||
region, err := b.config.ConfigProvider.Region()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Build the artifact and return it
|
||||
artifact := &Artifact{
|
||||
Image: state.Get("image").(core.Image),
|
||||
Region: region,
|
||||
Image: state.Get("image").(client.Image),
|
||||
Region: b.config.AccessCfg.Region,
|
||||
driver: driver,
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user