github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/googlecompute/step_create_instance.go (about)

     1  package googlecompute
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"time"
     8  
     9  	"github.com/hashicorp/packer/packer"
    10  	"github.com/mitchellh/multistep"
    11  )
    12  
    13  // StepCreateInstance represents a Packer build step that creates GCE instances.
    14  type StepCreateInstance struct {
    15  	Debug bool
    16  }
    17  
    18  func (c *Config) createInstanceMetadata(sourceImage *Image, sshPublicKey string) (map[string]string, error) {
    19  	instanceMetadata := make(map[string]string)
    20  	var err error
    21  
    22  	// Copy metadata from config.
    23  	for k, v := range c.Metadata {
    24  		instanceMetadata[k] = v
    25  	}
    26  
    27  	// Merge any existing ssh keys with our public key, unless there is no
    28  	// supplied public key. This is possible if a private_key_file was
    29  	// specified.
    30  	if sshPublicKey != "" {
    31  		sshMetaKey := "sshKeys"
    32  		sshKeys := fmt.Sprintf("%s:%s", c.Comm.SSHUsername, sshPublicKey)
    33  		if confSshKeys, exists := instanceMetadata[sshMetaKey]; exists {
    34  			sshKeys = fmt.Sprintf("%s\n%s", sshKeys, confSshKeys)
    35  		}
    36  		instanceMetadata[sshMetaKey] = sshKeys
    37  	}
    38  
    39  	// Wrap any startup script with our own startup script.
    40  	if c.StartupScriptFile != "" {
    41  		var content []byte
    42  		content, err = ioutil.ReadFile(c.StartupScriptFile)
    43  		instanceMetadata[StartupWrappedScriptKey] = string(content)
    44  	} else if wrappedStartupScript, exists := instanceMetadata[StartupScriptKey]; exists {
    45  		instanceMetadata[StartupWrappedScriptKey] = wrappedStartupScript
    46  	}
    47  	if sourceImage.IsWindows() {
    48  		// Windows startup script support is not yet implemented.
    49  		// Mark the startup script as done.
    50  		instanceMetadata[StartupScriptKey] = StartupScriptWindows
    51  		instanceMetadata[StartupScriptStatusKey] = StartupScriptStatusDone
    52  	} else {
    53  		instanceMetadata[StartupScriptKey] = StartupScriptLinux
    54  		instanceMetadata[StartupScriptStatusKey] = StartupScriptStatusNotDone
    55  	}
    56  
    57  	return instanceMetadata, err
    58  }
    59  
    60  func getImage(c *Config, d Driver) (*Image, error) {
    61  	name := c.SourceImageFamily
    62  	fromFamily := true
    63  	if c.SourceImage != "" {
    64  		name = c.SourceImage
    65  		fromFamily = false
    66  	}
    67  	if c.SourceImageProjectId == "" {
    68  		return d.GetImage(name, fromFamily)
    69  	} else {
    70  		return d.GetImageFromProject(c.SourceImageProjectId, name, fromFamily)
    71  	}
    72  }
    73  
    74  // Run executes the Packer build step that creates a GCE instance.
    75  func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction {
    76  	c := state.Get("config").(*Config)
    77  	d := state.Get("driver").(Driver)
    78  	sshPublicKey := state.Get("ssh_public_key").(string)
    79  	ui := state.Get("ui").(packer.Ui)
    80  
    81  	sourceImage, err := getImage(c, d)
    82  	if err != nil {
    83  		err := fmt.Errorf("Error getting source image for instance creation: %s", err)
    84  		state.Put("error", err)
    85  		ui.Error(err.Error())
    86  		return multistep.ActionHalt
    87  	}
    88  
    89  	ui.Say(fmt.Sprintf("Using image: %s", sourceImage.Name))
    90  
    91  	if sourceImage.IsWindows() && c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" {
    92  		state.Put("create_windows_password", true)
    93  	}
    94  
    95  	ui.Say("Creating instance...")
    96  	name := c.InstanceName
    97  
    98  	var errCh <-chan error
    99  	var metadata map[string]string
   100  	metadata, err = c.createInstanceMetadata(sourceImage, sshPublicKey)
   101  	errCh, err = d.RunInstance(&InstanceConfig{
   102  		AcceleratorType:   c.AcceleratorType,
   103  		AcceleratorCount:  c.AcceleratorCount,
   104  		Address:           c.Address,
   105  		Description:       "New instance created by Packer",
   106  		DiskSizeGb:        c.DiskSizeGb,
   107  		DiskType:          c.DiskType,
   108  		Image:             sourceImage,
   109  		Labels:            c.Labels,
   110  		MachineType:       c.MachineType,
   111  		Metadata:          metadata,
   112  		Name:              name,
   113  		Network:           c.Network,
   114  		NetworkProjectId:  c.NetworkProjectId,
   115  		OmitExternalIP:    c.OmitExternalIP,
   116  		OnHostMaintenance: c.OnHostMaintenance,
   117  		Preemptible:       c.Preemptible,
   118  		Region:            c.Region,
   119  		Scopes:            c.Scopes,
   120  		Subnetwork:        c.Subnetwork,
   121  		Tags:              c.Tags,
   122  		Zone:              c.Zone,
   123  	})
   124  
   125  	if err == nil {
   126  		ui.Message("Waiting for creation operation to complete...")
   127  		select {
   128  		case err = <-errCh:
   129  		case <-time.After(c.stateTimeout):
   130  			err = errors.New("time out while waiting for instance to create")
   131  		}
   132  	}
   133  
   134  	if err != nil {
   135  		err := fmt.Errorf("Error creating instance: %s", err)
   136  		state.Put("error", err)
   137  		ui.Error(err.Error())
   138  		return multistep.ActionHalt
   139  	}
   140  
   141  	ui.Message("Instance has been created!")
   142  
   143  	if s.Debug {
   144  		if name != "" {
   145  			ui.Message(fmt.Sprintf("Instance: %s started in %s", name, c.Zone))
   146  		}
   147  	}
   148  
   149  	// Things succeeded, store the name so we can remove it later
   150  	state.Put("instance_name", name)
   151  
   152  	return multistep.ActionContinue
   153  }
   154  
   155  // Cleanup destroys the GCE instance created during the image creation process.
   156  func (s *StepCreateInstance) Cleanup(state multistep.StateBag) {
   157  	nameRaw, ok := state.GetOk("instance_name")
   158  	if !ok {
   159  		return
   160  	}
   161  	name := nameRaw.(string)
   162  	if name == "" {
   163  		return
   164  	}
   165  
   166  	config := state.Get("config").(*Config)
   167  	driver := state.Get("driver").(Driver)
   168  	ui := state.Get("ui").(packer.Ui)
   169  
   170  	ui.Say("Deleting instance...")
   171  	errCh, err := driver.DeleteInstance(config.Zone, name)
   172  	if err == nil {
   173  		select {
   174  		case err = <-errCh:
   175  		case <-time.After(config.stateTimeout):
   176  			err = errors.New("time out while waiting for instance to delete")
   177  		}
   178  	}
   179  
   180  	if err != nil {
   181  		ui.Error(fmt.Sprintf(
   182  			"Error deleting instance. Please delete it manually.\n\n"+
   183  				"Name: %s\n"+
   184  				"Error: %s", name, err))
   185  	}
   186  
   187  	ui.Message("Instance has been deleted!")
   188  	state.Put("instance_name", "")
   189  
   190  	// Deleting the instance does not remove the boot disk. This cleanup removes
   191  	// the disk.
   192  	ui.Say("Deleting disk...")
   193  	errCh, err = driver.DeleteDisk(config.Zone, config.DiskName)
   194  	if err == nil {
   195  		select {
   196  		case err = <-errCh:
   197  		case <-time.After(config.stateTimeout):
   198  			err = errors.New("time out while waiting for disk to delete")
   199  		}
   200  	}
   201  
   202  	if err != nil {
   203  		ui.Error(fmt.Sprintf(
   204  			"Error deleting disk. Please delete it manually.\n\n"+
   205  				"Name: %s\n"+
   206  				"Error: %s", config.InstanceName, err))
   207  	}
   208  
   209  	ui.Message("Disk has been deleted!")
   210  
   211  	return
   212  }