github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/builder/googlecompute/step_create_instance.go (about)

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