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 }