github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/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/mitchellh/multistep"
    10  	"github.com/mitchellh/packer/packer"
    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  	if c.SourceImageProjectId == "" {
    62  		return d.GetImage(c.SourceImage)
    63  	} else {
    64  		return d.GetImageFromProject(c.SourceImageProjectId, c.SourceImage)
    65  	}
    66  }
    67  
    68  // Run executes the Packer build step that creates a GCE instance.
    69  func (s *StepCreateInstance) Run(state multistep.StateBag) multistep.StepAction {
    70  	c := state.Get("config").(*Config)
    71  	d := state.Get("driver").(Driver)
    72  	sshPublicKey := state.Get("ssh_public_key").(string)
    73  	ui := state.Get("ui").(packer.Ui)
    74  
    75  	sourceImage, err := getImage(c, d)
    76  	if err != nil {
    77  		err := fmt.Errorf("Error getting source image for instance creation: %s", err)
    78  		state.Put("error", err)
    79  		ui.Error(err.Error())
    80  		return multistep.ActionHalt
    81  	}
    82  
    83  	if sourceImage.IsWindows() && c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" {
    84  		state.Put("create_windows_password", true)
    85  	}
    86  
    87  	ui.Say("Creating instance...")
    88  	name := c.InstanceName
    89  
    90  	var errCh <-chan error
    91  	var metadata map[string]string
    92  	metadata, err = c.createInstanceMetadata(sourceImage, sshPublicKey)
    93  	errCh, err = d.RunInstance(&InstanceConfig{
    94  		Address:             c.Address,
    95  		Description:         "New instance created by Packer",
    96  		DiskSizeGb:          c.DiskSizeGb,
    97  		DiskType:            c.DiskType,
    98  		Image:               sourceImage,
    99  		MachineType:         c.MachineType,
   100  		Metadata:            metadata,
   101  		Name:                name,
   102  		Network:             c.Network,
   103  		OmitExternalIP:      c.OmitExternalIP,
   104  		Preemptible:         c.Preemptible,
   105  		Region:              c.Region,
   106  		ServiceAccountEmail: c.Account.ClientEmail,
   107  		Scopes:              c.Scopes,
   108  		Subnetwork:          c.Subnetwork,
   109  		Tags:                c.Tags,
   110  		Zone:                c.Zone,
   111  	})
   112  
   113  	if err == nil {
   114  		ui.Message("Waiting for creation operation to complete...")
   115  		select {
   116  		case err = <-errCh:
   117  		case <-time.After(c.stateTimeout):
   118  			err = errors.New("time out while waiting for instance to create")
   119  		}
   120  	}
   121  
   122  	if err != nil {
   123  		err := fmt.Errorf("Error creating instance: %s", err)
   124  		state.Put("error", err)
   125  		ui.Error(err.Error())
   126  		return multistep.ActionHalt
   127  	}
   128  
   129  	ui.Message("Instance has been created!")
   130  
   131  	if s.Debug {
   132  		if name != "" {
   133  			ui.Message(fmt.Sprintf("Instance: %s started in %s", name, c.Zone))
   134  		}
   135  	}
   136  
   137  	// Things succeeded, store the name so we can remove it later
   138  	state.Put("instance_name", name)
   139  
   140  	return multistep.ActionContinue
   141  }
   142  
   143  // Cleanup destroys the GCE instance created during the image creation process.
   144  func (s *StepCreateInstance) Cleanup(state multistep.StateBag) {
   145  	nameRaw, ok := state.GetOk("instance_name")
   146  	if !ok {
   147  		return
   148  	}
   149  	name := nameRaw.(string)
   150  	if name == "" {
   151  		return
   152  	}
   153  
   154  	config := state.Get("config").(*Config)
   155  	driver := state.Get("driver").(Driver)
   156  	ui := state.Get("ui").(packer.Ui)
   157  
   158  	ui.Say("Deleting instance...")
   159  	errCh, err := driver.DeleteInstance(config.Zone, name)
   160  	if err == nil {
   161  		select {
   162  		case err = <-errCh:
   163  		case <-time.After(config.stateTimeout):
   164  			err = errors.New("time out while waiting for instance to delete")
   165  		}
   166  	}
   167  
   168  	if err != nil {
   169  		ui.Error(fmt.Sprintf(
   170  			"Error deleting instance. Please delete it manually.\n\n"+
   171  				"Name: %s\n"+
   172  				"Error: %s", name, err))
   173  	}
   174  
   175  	ui.Message("Instance has been deleted!")
   176  	state.Put("instance_name", "")
   177  
   178  	// Deleting the instance does not remove the boot disk. This cleanup removes
   179  	// the disk.
   180  	ui.Say("Deleting disk...")
   181  	errCh, err = driver.DeleteDisk(config.Zone, config.DiskName)
   182  	if err == nil {
   183  		select {
   184  		case err = <-errCh:
   185  		case <-time.After(config.stateTimeout):
   186  			err = errors.New("time out while waiting for disk to delete")
   187  		}
   188  	}
   189  
   190  	if err != nil {
   191  		ui.Error(fmt.Sprintf(
   192  			"Error deleting disk. Please delete it manually.\n\n"+
   193  				"Name: %s\n"+
   194  				"Error: %s", config.InstanceName, err))
   195  	}
   196  
   197  	ui.Message("Disk has been deleted!")
   198  
   199  	return
   200  }