github.com/raghuse92/packer@v1.3.2/builder/openstack/step_run_source_server.go (about) 1 package openstack 2 3 import ( 4 "context" 5 "fmt" 6 "io/ioutil" 7 "log" 8 9 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/bootfromvolume" 10 "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs" 11 "github.com/gophercloud/gophercloud/openstack/compute/v2/servers" 12 "github.com/hashicorp/packer/helper/multistep" 13 "github.com/hashicorp/packer/packer" 14 ) 15 16 type StepRunSourceServer struct { 17 Name string 18 SecurityGroups []string 19 Networks []string 20 Ports []string 21 AvailabilityZone string 22 UserData string 23 UserDataFile string 24 ConfigDrive bool 25 InstanceMetadata map[string]string 26 UseBlockStorageVolume bool 27 server *servers.Server 28 } 29 30 func (s *StepRunSourceServer) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { 31 config := state.Get("config").(*Config) 32 flavor := state.Get("flavor_id").(string) 33 sourceImage := state.Get("source_image").(string) 34 ui := state.Get("ui").(packer.Ui) 35 36 // We need the v2 compute client 37 computeClient, err := config.computeV2Client() 38 if err != nil { 39 err = fmt.Errorf("Error initializing compute client: %s", err) 40 state.Put("error", err) 41 return multistep.ActionHalt 42 } 43 44 networks := make([]servers.Network, len(s.Networks)+len(s.Ports)) 45 i := 0 46 for ; i < len(s.Ports); i++ { 47 networks[i].Port = s.Ports[i] 48 } 49 for ; i < len(networks); i++ { 50 networks[i].UUID = s.Networks[i] 51 } 52 53 userData := []byte(s.UserData) 54 if s.UserDataFile != "" { 55 userData, err = ioutil.ReadFile(s.UserDataFile) 56 if err != nil { 57 err = fmt.Errorf("Error reading user data file: %s", err) 58 state.Put("error", err) 59 return multistep.ActionHalt 60 } 61 } 62 63 ui.Say("Launching server...") 64 65 serverOpts := servers.CreateOpts{ 66 Name: s.Name, 67 ImageRef: sourceImage, 68 FlavorRef: flavor, 69 SecurityGroups: s.SecurityGroups, 70 Networks: networks, 71 AvailabilityZone: s.AvailabilityZone, 72 UserData: userData, 73 ConfigDrive: &s.ConfigDrive, 74 ServiceClient: computeClient, 75 Metadata: s.InstanceMetadata, 76 } 77 78 var serverOptsExt servers.CreateOptsBuilder 79 80 // Create root volume in the Block Storage service if required. 81 // Add block device mapping v2 to the server create options if required. 82 if s.UseBlockStorageVolume { 83 volume := state.Get("volume_id").(string) 84 blockDeviceMappingV2 := []bootfromvolume.BlockDevice{ 85 { 86 BootIndex: 0, 87 DestinationType: bootfromvolume.DestinationVolume, 88 SourceType: bootfromvolume.SourceVolume, 89 UUID: volume, 90 }, 91 } 92 // ImageRef and block device mapping is an invalid options combination. 93 serverOpts.ImageRef = "" 94 serverOptsExt = bootfromvolume.CreateOptsExt{ 95 CreateOptsBuilder: serverOpts, 96 BlockDevice: blockDeviceMappingV2, 97 } 98 } else { 99 serverOptsExt = serverOpts 100 } 101 102 // Add keypair to the server create options. 103 keyName := config.Comm.SSHKeyPairName 104 if keyName != "" { 105 serverOptsExt = keypairs.CreateOptsExt{ 106 CreateOptsBuilder: serverOptsExt, 107 KeyName: keyName, 108 } 109 } 110 111 ui.Say("Launching server...") 112 s.server, err = servers.Create(computeClient, serverOptsExt).Extract() 113 if err != nil { 114 err := fmt.Errorf("Error launching source server: %s", err) 115 state.Put("error", err) 116 ui.Error(err.Error()) 117 return multistep.ActionHalt 118 } 119 120 ui.Message(fmt.Sprintf("Server ID: %s", s.server.ID)) 121 log.Printf("server id: %s", s.server.ID) 122 123 ui.Say("Waiting for server to become ready...") 124 stateChange := StateChangeConf{ 125 Pending: []string{"BUILD"}, 126 Target: []string{"ACTIVE"}, 127 Refresh: ServerStateRefreshFunc(computeClient, s.server), 128 StepState: state, 129 } 130 latestServer, err := WaitForState(&stateChange) 131 if err != nil { 132 err := fmt.Errorf("Error waiting for server (%s) to become ready: %s", s.server.ID, err) 133 state.Put("error", err) 134 ui.Error(err.Error()) 135 return multistep.ActionHalt 136 } 137 138 s.server = latestServer.(*servers.Server) 139 state.Put("server", s.server) 140 141 return multistep.ActionContinue 142 } 143 144 func (s *StepRunSourceServer) Cleanup(state multistep.StateBag) { 145 if s.server == nil { 146 return 147 } 148 149 config := state.Get("config").(*Config) 150 ui := state.Get("ui").(packer.Ui) 151 152 // We need the v2 compute client 153 computeClient, err := config.computeV2Client() 154 if err != nil { 155 ui.Error(fmt.Sprintf("Error terminating server, may still be around: %s", err)) 156 return 157 } 158 159 ui.Say(fmt.Sprintf("Terminating the source server: %s ...", s.server.ID)) 160 if err := servers.Delete(computeClient, s.server.ID).ExtractErr(); err != nil { 161 ui.Error(fmt.Sprintf("Error terminating server, may still be around: %s", err)) 162 return 163 } 164 165 stateChange := StateChangeConf{ 166 Pending: []string{"ACTIVE", "BUILD", "REBUILD", "SUSPENDED", "SHUTOFF", "STOPPED"}, 167 Refresh: ServerStateRefreshFunc(computeClient, s.server), 168 Target: []string{"DELETED"}, 169 } 170 171 WaitForState(&stateChange) 172 }