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  }