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 }