github.phpd.cn/hashicorp/packer@v1.3.2/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  
    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, string(c.Comm.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  		MinCpuPlatform:               c.MinCpuPlatform,
   115  		Name:                         name,
   116  		Network:                      c.Network,
   117  		NetworkProjectId:             c.NetworkProjectId,
   118  		OmitExternalIP:               c.OmitExternalIP,
   119  		OnHostMaintenance:            c.OnHostMaintenance,
   120  		Preemptible:                  c.Preemptible,
   121  		Region:                       c.Region,
   122  		ServiceAccountEmail:          c.ServiceAccountEmail,
   123  		Scopes:                       c.Scopes,
   124  		Subnetwork:                   c.Subnetwork,
   125  		Tags:                         c.Tags,
   126  		Zone:                         c.Zone,
   127  	})
   128  
   129  	if err == nil {
   130  		ui.Message("Waiting for creation operation to complete...")
   131  		select {
   132  		case err = <-errCh:
   133  		case <-time.After(c.stateTimeout):
   134  			err = errors.New("time out while waiting for instance to create")
   135  		}
   136  	}
   137  
   138  	if err != nil {
   139  		err := fmt.Errorf("Error creating instance: %s", err)
   140  		state.Put("error", err)
   141  		ui.Error(err.Error())
   142  		return multistep.ActionHalt
   143  	}
   144  
   145  	ui.Message("Instance has been created!")
   146  
   147  	if s.Debug {
   148  		if name != "" {
   149  			ui.Message(fmt.Sprintf("Instance: %s started in %s", name, c.Zone))
   150  		}
   151  	}
   152  
   153  	// Things succeeded, store the name so we can remove it later
   154  	state.Put("instance_name", name)
   155  
   156  	return multistep.ActionContinue
   157  }
   158  
   159  // Cleanup destroys the GCE instance created during the image creation process.
   160  func (s *StepCreateInstance) Cleanup(state multistep.StateBag) {
   161  	nameRaw, ok := state.GetOk("instance_name")
   162  	if !ok {
   163  		return
   164  	}
   165  	name := nameRaw.(string)
   166  	if name == "" {
   167  		return
   168  	}
   169  
   170  	config := state.Get("config").(*Config)
   171  	driver := state.Get("driver").(Driver)
   172  	ui := state.Get("ui").(packer.Ui)
   173  
   174  	ui.Say("Deleting instance...")
   175  	errCh, err := driver.DeleteInstance(config.Zone, name)
   176  	if err == nil {
   177  		select {
   178  		case err = <-errCh:
   179  		case <-time.After(config.stateTimeout):
   180  			err = errors.New("time out while waiting for instance to delete")
   181  		}
   182  	}
   183  
   184  	if err != nil {
   185  		ui.Error(fmt.Sprintf(
   186  			"Error deleting instance. Please delete it manually.\n\n"+
   187  				"Name: %s\n"+
   188  				"Error: %s", name, err))
   189  	}
   190  
   191  	ui.Message("Instance has been deleted!")
   192  	state.Put("instance_name", "")
   193  
   194  	// Deleting the instance does not remove the boot disk. This cleanup removes
   195  	// the disk.
   196  	ui.Say("Deleting disk...")
   197  	errCh, err = driver.DeleteDisk(config.Zone, config.DiskName)
   198  	if err == nil {
   199  		select {
   200  		case err = <-errCh:
   201  		case <-time.After(config.stateTimeout):
   202  			err = errors.New("time out while waiting for disk to delete")
   203  		}
   204  	}
   205  
   206  	if err != nil {
   207  		ui.Error(fmt.Sprintf(
   208  			"Error deleting disk. Please delete it manually.\n\n"+
   209  				"Name: %s\n"+
   210  				"Error: %s", config.InstanceName, err))
   211  	}
   212  
   213  	ui.Message("Disk has been deleted!")
   214  
   215  	return
   216  }