github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/openstack/step_run_source_server.go (about) 1 package openstack 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 8 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs" 9 "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" 10 "github.com/hashicorp/packer/packer" 11 "github.com/mitchellh/multistep" 12 ) 13 14 type StepRunSourceServer struct { 15 Name string 16 SourceImage string 17 SourceImageName string 18 SecurityGroups []string 19 Networks []string 20 AvailabilityZone string 21 UserData string 22 UserDataFile string 23 ConfigDrive bool 24 InstanceMetadata map[string]string 25 server *servers.Server 26 } 27 28 func (s *StepRunSourceServer) Run(state multistep.StateBag) multistep.StepAction { 29 config := state.Get("config").(Config) 30 flavor := state.Get("flavor_id").(string) 31 ui := state.Get("ui").(packer.Ui) 32 33 // We need the v2 compute client 34 computeClient, err := config.computeV2Client() 35 if err != nil { 36 err = fmt.Errorf("Error initializing compute client: %s", err) 37 state.Put("error", err) 38 return multistep.ActionHalt 39 } 40 41 networks := make([]servers.Network, len(s.Networks)) 42 for i, networkUuid := range s.Networks { 43 networks[i].UUID = networkUuid 44 } 45 46 userData := []byte(s.UserData) 47 if s.UserDataFile != "" { 48 userData, err = ioutil.ReadFile(s.UserDataFile) 49 if err != nil { 50 err = fmt.Errorf("Error reading user data file: %s", err) 51 state.Put("error", err) 52 return multistep.ActionHalt 53 } 54 } 55 56 ui.Say("Launching server...") 57 58 serverOpts := servers.CreateOpts{ 59 Name: s.Name, 60 ImageRef: s.SourceImage, 61 ImageName: s.SourceImageName, 62 FlavorRef: flavor, 63 SecurityGroups: s.SecurityGroups, 64 Networks: networks, 65 AvailabilityZone: s.AvailabilityZone, 66 UserData: userData, 67 ConfigDrive: &s.ConfigDrive, 68 ServiceClient: computeClient, 69 Metadata: s.InstanceMetadata, 70 } 71 72 var serverOptsExt servers.CreateOptsBuilder 73 keyName, hasKey := state.GetOk("keyPair") 74 if hasKey { 75 serverOptsExt = keypairs.CreateOptsExt{ 76 CreateOptsBuilder: serverOpts, 77 KeyName: keyName.(string), 78 } 79 } else { 80 serverOptsExt = serverOpts 81 } 82 83 s.server, err = servers.Create(computeClient, serverOptsExt).Extract() 84 if err != nil { 85 err := fmt.Errorf("Error launching source server: %s", err) 86 state.Put("error", err) 87 ui.Error(err.Error()) 88 return multistep.ActionHalt 89 } 90 91 ui.Message(fmt.Sprintf("Server ID: %s", s.server.ID)) 92 log.Printf("server id: %s", s.server.ID) 93 94 ui.Say("Waiting for server to become ready...") 95 stateChange := StateChangeConf{ 96 Pending: []string{"BUILD"}, 97 Target: []string{"ACTIVE"}, 98 Refresh: ServerStateRefreshFunc(computeClient, s.server), 99 StepState: state, 100 } 101 latestServer, err := WaitForState(&stateChange) 102 if err != nil { 103 err := fmt.Errorf("Error waiting for server (%s) to become ready: %s", s.server.ID, err) 104 state.Put("error", err) 105 ui.Error(err.Error()) 106 return multistep.ActionHalt 107 } 108 109 s.server = latestServer.(*servers.Server) 110 state.Put("server", s.server) 111 112 return multistep.ActionContinue 113 } 114 115 func (s *StepRunSourceServer) Cleanup(state multistep.StateBag) { 116 if s.server == nil { 117 return 118 } 119 120 config := state.Get("config").(Config) 121 ui := state.Get("ui").(packer.Ui) 122 123 // We need the v2 compute client 124 computeClient, err := config.computeV2Client() 125 if err != nil { 126 ui.Error(fmt.Sprintf("Error terminating server, may still be around: %s", err)) 127 return 128 } 129 130 ui.Say(fmt.Sprintf("Terminating the source server: %s ...", s.server.ID)) 131 if err := servers.Delete(computeClient, s.server.ID).ExtractErr(); err != nil { 132 ui.Error(fmt.Sprintf("Error terminating server, may still be around: %s", err)) 133 return 134 } 135 136 stateChange := StateChangeConf{ 137 Pending: []string{"ACTIVE", "BUILD", "REBUILD", "SUSPENDED", "SHUTOFF", "STOPPED"}, 138 Refresh: ServerStateRefreshFunc(computeClient, s.server), 139 Target: []string{"DELETED"}, 140 } 141 142 WaitForState(&stateChange) 143 }