github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/cloudstack/step_prepare_config.go (about)

     1  package cloudstack
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"regexp"
     7  
     8  	"github.com/hashicorp/packer/packer"
     9  	"github.com/mitchellh/multistep"
    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 != "" {
    57  		if isUUID(config.PublicIPAddress) {
    58  			ip, _, err := client.Address.GetPublicIpAddressByID(config.PublicIPAddress)
    59  			if err != nil {
    60  				errs = packer.MultiErrorAppend(errs, fmt.Errorf("Failed to retrieve IP address: %s", err))
    61  			}
    62  			state.Put("ipaddress", ip.Ipaddress)
    63  		} else {
    64  			// Save the public IP address before replacing it with it's UUID.
    65  			state.Put("ipaddress", config.PublicIPAddress)
    66  
    67  			p := client.Address.NewListPublicIpAddressesParams()
    68  			p.SetIpaddress(config.PublicIPAddress)
    69  
    70  			if config.Project != "" {
    71  				p.SetProjectid(config.Project)
    72  			}
    73  
    74  			ipAddrs, err := client.Address.ListPublicIpAddresses(p)
    75  			if err != nil {
    76  				errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, err})
    77  			}
    78  			if err == nil && ipAddrs.Count != 1 {
    79  				errs = packer.MultiErrorAppend(errs, &retrieveErr{"IP address", config.PublicIPAddress, ipAddrs})
    80  			}
    81  			if err == nil && ipAddrs.Count == 1 {
    82  				config.PublicIPAddress = ipAddrs.PublicIpAddresses[0].Id
    83  			}
    84  		}
    85  	}
    86  
    87  	if !isUUID(config.Network) {
    88  		config.Network, _, err = client.Network.GetNetworkID(config.Network, cloudstack.WithProject(config.Project))
    89  		if err != nil {
    90  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"network", config.Network, err})
    91  		}
    92  	}
    93  
    94  	// Then try to get the SG's UUID's.
    95  	if len(config.SecurityGroups) > 0 {
    96  		for i := range config.SecurityGroups {
    97  			if !isUUID(config.SecurityGroups[i]) {
    98  				config.SecurityGroups[i], _, err = client.SecurityGroup.GetSecurityGroupID(config.SecurityGroups[i], cloudstack.WithProject(config.Project))
    99  				if err != nil {
   100  					errs = packer.MultiErrorAppend(errs, &retrieveErr{"network", config.SecurityGroups[i], err})
   101  				}
   102  			}
   103  		}
   104  	}
   105  
   106  	if !isUUID(config.ServiceOffering) {
   107  		config.ServiceOffering, _, err = client.ServiceOffering.GetServiceOfferingID(config.ServiceOffering)
   108  		if err != nil {
   109  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"service offering", config.ServiceOffering, err})
   110  		}
   111  	}
   112  
   113  	if config.SourceISO != "" {
   114  		if isUUID(config.SourceISO) {
   115  			state.Put("source", config.SourceISO)
   116  		} else {
   117  			isoID, _, err := client.ISO.GetIsoID(config.SourceISO, "executable", config.Zone)
   118  			if err != nil {
   119  				errs = packer.MultiErrorAppend(errs, &retrieveErr{"ISO", config.SourceISO, err})
   120  			}
   121  			state.Put("source", isoID)
   122  		}
   123  	}
   124  
   125  	if config.SourceTemplate != "" {
   126  		if isUUID(config.SourceTemplate) {
   127  			state.Put("source", config.SourceTemplate)
   128  		} else {
   129  			templateID, _, err := client.Template.GetTemplateID(config.SourceTemplate, "executable", config.Zone)
   130  			if err != nil {
   131  				errs = packer.MultiErrorAppend(errs, &retrieveErr{"template", config.SourceTemplate, err})
   132  			}
   133  			state.Put("source", templateID)
   134  		}
   135  	}
   136  
   137  	if !isUUID(config.TemplateOS) {
   138  		p := client.GuestOS.NewListOsTypesParams()
   139  		p.SetDescription(config.TemplateOS)
   140  
   141  		types, err := client.GuestOS.ListOsTypes(p)
   142  		if err != nil {
   143  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"OS type", config.TemplateOS, err})
   144  		}
   145  		if err == nil && types.Count != 1 {
   146  			errs = packer.MultiErrorAppend(errs, &retrieveErr{"OS type", config.TemplateOS, types})
   147  		}
   148  		if err == nil && types.Count == 1 {
   149  			config.TemplateOS = types.OsTypes[0].Id
   150  		}
   151  	}
   152  
   153  	// This is needed because nil is not always nil. When returning *packer.MultiError(nil)
   154  	// as an error interface, that interface will no longer be equal to nil but it will be
   155  	// an interface with type *packer.MultiError and value nil which is different then a
   156  	// nil interface.
   157  	if errs != nil && len(errs.Errors) > 0 {
   158  		state.Put("error", errs)
   159  		ui.Error(errs.Error())
   160  		return multistep.ActionHalt
   161  	}
   162  
   163  	ui.Message("Config has been prepared!")
   164  	return multistep.ActionContinue
   165  }
   166  
   167  func (s *stepPrepareConfig) Cleanup(state multistep.StateBag) {
   168  	// Nothing to cleanup for this step.
   169  }
   170  
   171  type retrieveErr struct {
   172  	name   string
   173  	value  string
   174  	result interface{}
   175  }
   176  
   177  func (e *retrieveErr) Error() string {
   178  	if err, ok := e.result.(error); ok {
   179  		e.result = err.Error()
   180  	}
   181  	return fmt.Sprintf("Error retrieving UUID of %s %s: %v", e.name, e.value, e.result)
   182  }
   183  
   184  var uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
   185  
   186  func isUUID(uuid string) bool {
   187  	return uuidRegex.MatchString(uuid)
   188  }