github.phpd.cn/hashicorp/packer@v1.3.2/builder/cloudstack/step_prepare_config.go (about)

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