github.com/rahart/packer@v0.12.2-0.20161229105310-282bb6ad370f/builder/cloudstack/step_prepare_config.go (about)

     1  package cloudstack
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"regexp"
     7  
     8  	"github.com/mitchellh/multistep"
     9  	"github.com/mitchellh/packer/packer"
    10  	"github.com/xanzy/go-cloudstack/cloudstack"
    11  )
    12  
    13  type stepPrepareConfig struct{}
    14  
    15  func (s *stepPrepareConfig) Run(state multistep.StateBag) multistep.StepAction {
    16  	client := state.Get("client").(*cloudstack.CloudStackClient)
    17  	config := state.Get("config").(*Config)
    18  	ui := state.Get("ui").(packer.Ui)
    19  
    20  	ui.Say("Preparing config...")
    21  
    22  	var err error
    23  	var errs *packer.MultiError
    24  
    25  	// First get the project and zone UUID's so we can use them in other calls when needed.
    26  	if config.Project != "" && !isUUID(config.Project) {
    27  		config.Project, _, err = client.Project.GetProjectID(config.Project)
    28  		if err != nil {
    29  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"project", config.Project, err})
    30  		}
    31  	}
    32  
    33  	if config.UserDataFile != "" {
    34  		userdata, err := ioutil.ReadFile(config.UserDataFile)
    35  		if err != nil {
    36  			errs = packer.MultiErrorAppend(errs, fmt.Errorf("problem reading user data file: %s", err))
    37  		}
    38  		config.UserData = string(userdata)
    39  	}
    40  
    41  	if !isUUID(config.Zone) {
    42  		config.Zone, _, err = client.Zone.GetZoneID(config.Zone)
    43  		if err != nil {
    44  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"zone", config.Zone, err})
    45  		}
    46  	}
    47  
    48  	// Then try to get the remaining UUID's.
    49  	if config.DiskOffering != "" && !isUUID(config.DiskOffering) {
    50  		config.DiskOffering, _, err = client.DiskOffering.GetDiskOfferingID(config.DiskOffering)
    51  		if err != nil {
    52  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"disk offering", config.DiskOffering, err})
    53  		}
    54  	}
    55  
    56  	if config.PublicIPAddress != "" && !isUUID(config.PublicIPAddress) {
    57  		// Save the public IP address before replacing it with it's UUID.
    58  		config.hostAddress = config.PublicIPAddress
    59  
    60  		p := client.Address.NewListPublicIpAddressesParams()
    61  		p.SetIpaddress(config.PublicIPAddress)
    62  
    63  		if config.Project != "" {
    64  			p.SetProjectid(config.Project)
    65  		}
    66  
    67  		ipAddrs, err := client.Address.ListPublicIpAddresses(p)
    68  		if err != nil {
    69  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, err})
    70  		}
    71  		if err == nil && ipAddrs.Count != 1 {
    72  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, ipAddrs})
    73  		}
    74  		if err == nil && ipAddrs.Count == 1 {
    75  			config.PublicIPAddress = ipAddrs.PublicIpAddresses[0].Id
    76  		}
    77  	}
    78  
    79  	if !isUUID(config.Network) {
    80  		config.Network, _, err = client.Network.GetNetworkID(config.Network, cloudstack.WithProject(config.Project))
    81  		if err != nil {
    82  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"network", config.Network, err})
    83  		}
    84  	}
    85  
    86  	if !isUUID(config.ServiceOffering) {
    87  		config.ServiceOffering, _, err = client.ServiceOffering.GetServiceOfferingID(config.ServiceOffering)
    88  		if err != nil {
    89  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"service offering", config.ServiceOffering, err})
    90  		}
    91  	}
    92  
    93  	if config.SourceISO != "" {
    94  		if isUUID(config.SourceISO) {
    95  			config.instanceSource = config.SourceISO
    96  		} else {
    97  			config.instanceSource, _, err = client.ISO.GetIsoID(config.SourceISO, "executable", config.Zone)
    98  			if err != nil {
    99  				errs = packer.MultiErrorAppend(errs, &retrieveErr{"ISO", config.SourceISO, err})
   100  			}
   101  		}
   102  	}
   103  
   104  	if config.SourceTemplate != "" {
   105  		if isUUID(config.SourceTemplate) {
   106  			config.instanceSource = config.SourceTemplate
   107  		} else {
   108  			config.instanceSource, _, err = client.Template.GetTemplateID(config.SourceTemplate, "executable", config.Zone)
   109  			if err != nil {
   110  				errs = packer.MultiErrorAppend(errs, &retrieveErr{"template", config.SourceTemplate, err})
   111  			}
   112  		}
   113  	}
   114  
   115  	if !isUUID(config.TemplateOS) {
   116  		p := client.GuestOS.NewListOsTypesParams()
   117  		p.SetDescription(config.TemplateOS)
   118  
   119  		types, err := client.GuestOS.ListOsTypes(p)
   120  		if err != nil {
   121  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"OS type", config.TemplateOS, err})
   122  		}
   123  		if err == nil && types.Count != 1 {
   124  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"OS type", config.TemplateOS, types})
   125  		}
   126  		if err == nil && types.Count == 1 {
   127  			config.TemplateOS = types.OsTypes[0].Id
   128  		}
   129  	}
   130  
   131  	// This is needed because nil is not always nil. When returning *packer.MultiError(nil)
   132  	// as an error interface, that interface will no longer be equal to nil but it will be
   133  	// an interface with type *packer.MultiError and value nil which is different then a
   134  	// nil interface.
   135  	if errs != nil && len(errs.Errors) > 0 {
   136  		ui.Error(errs.Error())
   137  		return multistep.ActionHalt
   138  	}
   139  
   140  	ui.Message("Config has been prepared!")
   141  
   142  	return multistep.ActionContinue
   143  }
   144  
   145  func (s *stepPrepareConfig) Cleanup(state multistep.StateBag) {
   146  	// Nothing to cleanup for this step.
   147  }
   148  
   149  type retrieveErr struct {
   150  	name   string
   151  	value  string
   152  	result interface{}
   153  }
   154  
   155  func (e *retrieveErr) Error() string {
   156  	if err, ok := e.result.(error); ok {
   157  		e.result = err.Error()
   158  	}
   159  	return fmt.Sprintf("Error retrieving UUID of %s %s: %v", e.name, e.value, e.result)
   160  }
   161  
   162  var uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
   163  
   164  func isUUID(uuid string) bool {
   165  	return uuidRegex.MatchString(uuid)
   166  }