github.com/raghuse92/packer@v1.3.2/builder/openstack/run_config.go (about)

     1  package openstack
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
     8  	"github.com/hashicorp/packer/common/uuid"
     9  	"github.com/hashicorp/packer/helper/communicator"
    10  	"github.com/hashicorp/packer/template/interpolate"
    11  )
    12  
    13  // RunConfig contains configuration for running an instance from a source
    14  // image and details on how to access that launched image.
    15  type RunConfig struct {
    16  	Comm communicator.Config `mapstructure:",squash"`
    17  
    18  	SourceImage        string            `mapstructure:"source_image"`
    19  	SourceImageName    string            `mapstructure:"source_image_name"`
    20  	SourceImageFilters ImageFilter       `mapstructure:"source_image_filter"`
    21  	Flavor             string            `mapstructure:"flavor"`
    22  	AvailabilityZone   string            `mapstructure:"availability_zone"`
    23  	RackconnectWait    bool              `mapstructure:"rackconnect_wait"`
    24  	FloatingIPNetwork  string            `mapstructure:"floating_ip_network"`
    25  	FloatingIP         string            `mapstructure:"floating_ip"`
    26  	ReuseIPs           bool              `mapstructure:"reuse_ips"`
    27  	SecurityGroups     []string          `mapstructure:"security_groups"`
    28  	Networks           []string          `mapstructure:"networks"`
    29  	Ports              []string          `mapstructure:"ports"`
    30  	UserData           string            `mapstructure:"user_data"`
    31  	UserDataFile       string            `mapstructure:"user_data_file"`
    32  	InstanceName       string            `mapstructure:"instance_name"`
    33  	InstanceMetadata   map[string]string `mapstructure:"instance_metadata"`
    34  
    35  	ConfigDrive bool `mapstructure:"config_drive"`
    36  
    37  	// Used for BC, value will be passed to the "floating_ip_network"
    38  	FloatingIPPool string `mapstructure:"floating_ip_pool"`
    39  
    40  	UseBlockStorageVolume  bool   `mapstructure:"use_blockstorage_volume"`
    41  	VolumeName             string `mapstructure:"volume_name"`
    42  	VolumeType             string `mapstructure:"volume_type"`
    43  	VolumeAvailabilityZone string `mapstructure:"volume_availability_zone"`
    44  
    45  	// Not really used, but here for BC
    46  	OpenstackProvider string `mapstructure:"openstack_provider"`
    47  	UseFloatingIp     bool   `mapstructure:"use_floating_ip"`
    48  
    49  	sourceImageOpts images.ListOpts
    50  }
    51  
    52  type ImageFilter struct {
    53  	Filters    ImageFilterOptions `mapstructure:"filters"`
    54  	MostRecent bool               `mapstructure:"most_recent"`
    55  }
    56  
    57  type ImageFilterOptions struct {
    58  	Name       string   `mapstructure:"name"`
    59  	Owner      string   `mapstructure:"owner"`
    60  	Tags       []string `mapstructure:"tags"`
    61  	Visibility string   `mapstructure:"visibility"`
    62  }
    63  
    64  func (f *ImageFilterOptions) Empty() bool {
    65  	return f.Name == "" && f.Owner == "" && len(f.Tags) == 0 && f.Visibility == ""
    66  }
    67  
    68  func (f *ImageFilterOptions) Build() (*images.ListOpts, error) {
    69  	opts := images.ListOpts{}
    70  	// Set defaults for status, member_status, and sort
    71  	opts.Status = images.ImageStatusActive
    72  	opts.MemberStatus = images.ImageMemberStatusAccepted
    73  	opts.Sort = "created_at:desc"
    74  
    75  	var err error
    76  
    77  	if f.Name != "" {
    78  		opts.Name = f.Name
    79  	}
    80  	if f.Owner != "" {
    81  		opts.Owner = f.Owner
    82  	}
    83  	if len(f.Tags) > 0 {
    84  		opts.Tags = f.Tags
    85  	}
    86  	if f.Visibility != "" {
    87  		v, err := getImageVisibility(f.Visibility)
    88  		if err == nil {
    89  			opts.Visibility = *v
    90  		}
    91  	}
    92  
    93  	return &opts, err
    94  }
    95  
    96  func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
    97  	// If we are not given an explicit ssh_keypair_name or
    98  	// ssh_private_key_file, then create a temporary one, but only if the
    99  	// temporary_key_pair_name has not been provided and we are not using
   100  	// ssh_password.
   101  	if c.Comm.SSHKeyPairName == "" && c.Comm.SSHTemporaryKeyPairName == "" &&
   102  		c.Comm.SSHPrivateKeyFile == "" && c.Comm.SSHPassword == "" {
   103  
   104  		c.Comm.SSHTemporaryKeyPairName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
   105  	}
   106  
   107  	if c.FloatingIPPool != "" && c.FloatingIPNetwork == "" {
   108  		c.FloatingIPNetwork = c.FloatingIPPool
   109  	}
   110  
   111  	// Validation
   112  	errs := c.Comm.Prepare(ctx)
   113  
   114  	if c.Comm.SSHKeyPairName != "" {
   115  		if c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" && c.Comm.SSHPrivateKeyFile == "" {
   116  			errs = append(errs, errors.New("A ssh_private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name."))
   117  		} else if c.Comm.SSHPrivateKeyFile == "" && !c.Comm.SSHAgentAuth {
   118  			errs = append(errs, errors.New("A ssh_private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified."))
   119  		}
   120  	}
   121  
   122  	if c.SourceImage == "" && c.SourceImageName == "" && c.SourceImageFilters.Filters.Empty() {
   123  		errs = append(errs, errors.New("Either a source_image, a source_image_name, or source_image_filter must be specified"))
   124  	} else if len(c.SourceImage) > 0 && len(c.SourceImageName) > 0 {
   125  		errs = append(errs, errors.New("Only a source_image or a source_image_name can be specified, not both."))
   126  	}
   127  
   128  	if c.Flavor == "" {
   129  		errs = append(errs, errors.New("A flavor must be specified"))
   130  	}
   131  
   132  	if c.Comm.SSHIPVersion != "" && c.Comm.SSHIPVersion != "4" && c.Comm.SSHIPVersion != "6" {
   133  		errs = append(errs, errors.New("SSH IP version must be either 4 or 6"))
   134  	}
   135  
   136  	for key, value := range c.InstanceMetadata {
   137  		if len(key) > 255 {
   138  			errs = append(errs, fmt.Errorf("Instance metadata key too long (max 255 bytes): %s", key))
   139  		}
   140  		if len(value) > 255 {
   141  			errs = append(errs, fmt.Errorf("Instance metadata value too long (max 255 bytes): %s", value))
   142  		}
   143  	}
   144  
   145  	if c.UseBlockStorageVolume {
   146  		// Use Compute instance availability zone for the Block Storage volume if
   147  		// it's not provided.
   148  		if c.VolumeAvailabilityZone == "" {
   149  			c.VolumeAvailabilityZone = c.AvailabilityZone
   150  		}
   151  
   152  		// Use random name for the Block Storage volume if it's not provided.
   153  		if c.VolumeName == "" {
   154  			c.VolumeName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID())
   155  		}
   156  	}
   157  
   158  	// if neither ID or image name is provided outside the filter, build the filter
   159  	if len(c.SourceImage) == 0 && len(c.SourceImageName) == 0 {
   160  
   161  		listOpts, filterErr := c.SourceImageFilters.Filters.Build()
   162  
   163  		if filterErr != nil {
   164  			errs = append(errs, filterErr)
   165  		}
   166  		c.sourceImageOpts = *listOpts
   167  	}
   168  
   169  	return errs
   170  }
   171  
   172  // Retrieve the specific ImageVisibility using the exported const from images
   173  func getImageVisibility(visibility string) (*images.ImageVisibility, error) {
   174  	visibilities := [...]images.ImageVisibility{
   175  		images.ImageVisibilityPublic,
   176  		images.ImageVisibilityPrivate,
   177  		images.ImageVisibilityCommunity,
   178  		images.ImageVisibilityShared,
   179  	}
   180  
   181  	for _, v := range visibilities {
   182  		if string(v) == visibility {
   183  			return &v, nil
   184  		}
   185  	}
   186  
   187  	return nil, fmt.Errorf("Not a valid visibility: %s", visibility)
   188  }