feat(builder/hcloud): allow selecting image based on filters
This commit is contained in:
parent
d832cd6f67
commit
cb1e30ef69
|
@ -25,10 +25,11 @@ type Config struct {
|
|||
Endpoint string `mapstructure:"endpoint"`
|
||||
PollInterval time.Duration `mapstructure:"poll_interval"`
|
||||
|
||||
ServerName string `mapstructure:"server_name"`
|
||||
Location string `mapstructure:"location"`
|
||||
ServerType string `mapstructure:"server_type"`
|
||||
Image string `mapstructure:"image"`
|
||||
ServerName string `mapstructure:"server_name"`
|
||||
Location string `mapstructure:"location"`
|
||||
ServerType string `mapstructure:"server_type"`
|
||||
Image string `mapstructure:"image"`
|
||||
ImageFilter *imageFilter `mapstructure:"image_filter"`
|
||||
|
||||
SnapshotName string `mapstructure:"snapshot_name"`
|
||||
SnapshotLabels map[string]string `mapstructure:"snapshot_labels"`
|
||||
|
@ -41,6 +42,11 @@ type Config struct {
|
|||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
type imageFilter struct {
|
||||
WithSelector []string `mapstructure:"with_selector"`
|
||||
MostRecent bool `mapstructure:"most_recent"`
|
||||
}
|
||||
|
||||
func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
||||
c := new(Config)
|
||||
|
||||
|
@ -108,9 +114,18 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) {
|
|||
errs, errors.New("server type is required"))
|
||||
}
|
||||
|
||||
if c.Image == "" {
|
||||
if c.Image == "" && c.ImageFilter == nil {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("image is required"))
|
||||
errs, errors.New("image or image_filter is required"))
|
||||
}
|
||||
if c.ImageFilter != nil {
|
||||
if len(c.ImageFilter.WithSelector) == 0 {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("image_filter.with_selector is required when specifying filter"))
|
||||
} else if c.Image != "" {
|
||||
errs = packer.MultiErrorAppend(
|
||||
errs, errors.New("only one of image or image_filter can be specified"))
|
||||
}
|
||||
}
|
||||
|
||||
if c.UserData != "" && c.UserDataFile != "" {
|
||||
|
|
|
@ -3,8 +3,9 @@ package hcloud
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
|
@ -50,10 +51,24 @@ func (s *stepCreateServer) Run(ctx context.Context, state multistep.StateBag) mu
|
|||
sshKeys = append(sshKeys, sshKey)
|
||||
}
|
||||
|
||||
var image *hcloud.Image
|
||||
if c.Image != "" {
|
||||
image = &hcloud.Image{Name: c.Image}
|
||||
} else {
|
||||
var err error
|
||||
image, err = getImageWithSelectors(ctx, client, c)
|
||||
if err != nil {
|
||||
ui.Error(err.Error())
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
ui.Message(fmt.Sprintf("Using image %s with ID %d", image.Description, image.ID))
|
||||
}
|
||||
|
||||
serverCreateResult, _, err := client.Server.Create(ctx, hcloud.ServerCreateOpts{
|
||||
Name: c.ServerName,
|
||||
ServerType: &hcloud.ServerType{Name: c.ServerType},
|
||||
Image: &hcloud.Image{Name: c.Image},
|
||||
Image: image,
|
||||
SSHKeys: sshKeys,
|
||||
Location: &hcloud.Location{Name: c.Location},
|
||||
UserData: userData,
|
||||
|
@ -185,3 +200,32 @@ func waitForAction(ctx context.Context, client *hcloud.Client, action *hcloud.Ac
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getImageWithSelectors(ctx context.Context, client *hcloud.Client, c *Config) (*hcloud.Image, error) {
|
||||
var allImages []*hcloud.Image
|
||||
|
||||
var selector = strings.Join(c.ImageFilter.WithSelector, ",")
|
||||
opts := hcloud.ImageListOpts{
|
||||
ListOpts: hcloud.ListOpts{LabelSelector: selector},
|
||||
Status: []hcloud.ImageStatus{hcloud.ImageStatusAvailable},
|
||||
}
|
||||
|
||||
allImages, err := client.Image.AllWithOpts(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(allImages) == 0 {
|
||||
return nil, fmt.Errorf("no image found for selector %q", selector)
|
||||
}
|
||||
if len(allImages) > 1 {
|
||||
if !c.ImageFilter.MostRecent {
|
||||
return nil, fmt.Errorf("more than one image found for selector %q", selector)
|
||||
}
|
||||
|
||||
sort.Slice(allImages, func(i, j int) bool {
|
||||
return allImages[i].Created.After(allImages[j].Created)
|
||||
})
|
||||
}
|
||||
|
||||
return allImages[0], nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue