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 }