Compare commits

..

1 Commits

Author SHA1 Message Date
Matthew Hooker e5f6958803 update ssh library 2018-04-22 19:47:37 -07:00
1024 changed files with 26539 additions and 102197 deletions
+2 -4
View File
@@ -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
View File
@@ -23,5 +23,4 @@ packer-test*.log
.idea/
*.iml
Thumbs.db
/packer.exe
.project
/packer.exe
-1
View File
@@ -10,7 +10,6 @@ go:
- 1.9.x
- 1.x
install:
- make deps
+5 -111
View File
@@ -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)
-3
View File
@@ -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()
+3 -4
View File
@@ -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
+2 -4
View File
@@ -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)
+4 -10
View File
@@ -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 {
+13 -33
View File
@@ -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
}
+8 -51
View File
@@ -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()
+5 -6
View File
@@ -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},
})
+3 -5
View File
@@ -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,
+1 -11
View File
@@ -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
+3 -5
View File
@@ -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,
+3 -5
View File
@@ -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,
+3 -5
View File
@@ -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,
+11 -33
View File
@@ -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')]"
+14 -14
View File
@@ -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)
}
}
+8 -8
View File
@@ -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
}
+24 -87
View File
@@ -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)
}
-280
View File
@@ -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"
}]
}
`
-1
View File
@@ -25,7 +25,6 @@ func TestStateBagShouldBePopulatedExpectedValues(t *testing.T) {
constants.ArmStorageAccountName,
constants.ArmVirtualMachineCaptureParameters,
constants.ArmPublicIPAddressName,
constants.ArmAsyncResourceGroupDelete,
}
for _, v := range expectedStateBagKeys {
+11 -11
View File
@@ -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))
}
+37 -69
View File
@@ -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 {
+11 -21
View File
@@ -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
}
+10
View File
@@ -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 {
+36 -32
View File
@@ -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) {
+4 -4
View File
@@ -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
+17 -25
View File
@@ -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)
+6 -8
View File
@@ -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)
+41 -41
View File
@@ -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) {},
+48 -56
View File
@@ -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
+10 -10
View File
@@ -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
+6 -6
View File
@@ -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)
+4 -4
View File
@@ -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
+11 -9
View File
@@ -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")
}
+57
View File
@@ -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)
}
}
+5 -5
View File
@@ -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
+2 -2
View File
@@ -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')]"
}
@@ -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": "https://localhost/custom.vhd"
},
"name": "[parameters('osDiskName')]",
"name": "osdisk",
"osType": "Linux",
"vhd": {
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
@@ -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')]"
@@ -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')]"
@@ -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')]"
@@ -140,11 +140,11 @@
},
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"createOption": "fromImage",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"name": "[parameters('osDiskName')]",
"name": "osdisk",
"osType": "Linux"
}
}
@@ -143,11 +143,11 @@
},
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"createOption": "fromImage",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"name": "[parameters('osDiskName')]",
"name": "osdisk",
"osType": "Linux"
}
}
@@ -121,11 +121,11 @@
},
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"createOption": "fromImage",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"name": "[parameters('osDiskName')]",
"name": "osdisk",
"osType": "Linux"
}
}
@@ -156,7 +156,7 @@
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"name": "[parameters('osDiskName')]",
"name": "osdisk",
"vhd": {
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
}
@@ -155,11 +155,11 @@
},
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"createOption": "fromImage",
"managedDisk": {
"storageAccountType": "Standard_LRS"
},
"name": "[parameters('osDiskName')]",
"name": "osdisk",
"osType": "Linux"
}
}
+1 -1
View File
@@ -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"
)
+53 -21
View File
@@ -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 users 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 SDKs 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')]"
},
+2 -2
View File
@@ -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')]"
@@ -158,7 +158,7 @@
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"name": "[parameters('osDiskName')]",
"name": "osdisk",
"vhd": {
"uri": "[concat(parameters('storageAccountBlobEndpoint'),variables('vmStorageAccountContainerName'),'/', parameters('osDiskName'),'.vhd')]"
}
@@ -179,11 +179,11 @@
},
"osDisk": {
"caching": "ReadWrite",
"createOption": "FromImage",
"createOption": "fromImage",
"managedDisk": {
"storageAccountType": "Premium_LRS"
},
"name": "[parameters('osDiskName')]",
"name": "osdisk",
"osType": "Windows"
}
}
@@ -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"
)
+10 -28
View File
@@ -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))
}
+2 -2
View File
@@ -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)
+2 -12
View File
@@ -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)
}
+6 -32
View File
@@ -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
}
+4 -16
View File
@@ -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)
}
+1 -3
View File
@@ -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)
+2 -4
View File
@@ -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)
+1 -16
View File
@@ -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))
+2 -31
View File
@@ -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
-53
View File
@@ -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()
+5 -11
View File
@@ -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(),
+1 -6
View File
@@ -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,
-1
View File
@@ -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"`
+5 -10
View File
@@ -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)
}
+3 -8
View File
@@ -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