@@ -17,8 +17,10 @@ limitations under the License.
1717package hetzner
1818
1919import (
20+ "context"
2021 "fmt"
2122 "math/rand"
23+ "strings"
2224 "sync"
2325 "time"
2426
@@ -380,13 +382,23 @@ func instanceTypeArch(manager *hetznerManager, instanceType string) (string, err
380382}
381383
382384func createServer (n * hetznerNodeGroup ) error {
385+ serverType , err := n .manager .cachedServerType .getServerType (n .instanceType )
386+ if err != nil {
387+ return err
388+ }
389+
390+ image , err := findImage (n , serverType )
391+ if err != nil {
392+ return err
393+ }
394+
383395 StartAfterCreate := true
384396 opts := hcloud.ServerCreateOpts {
385397 Name : newNodeName (n ),
386398 UserData : n .manager .cloudInit ,
387399 Location : & hcloud.Location {Name : n .region },
388- ServerType : & hcloud. ServerType { Name : n . instanceType } ,
389- Image : n . manager . image ,
400+ ServerType : serverType ,
401+ Image : image ,
390402 StartAfterCreate : & StartAfterCreate ,
391403 Labels : map [string ]string {
392404 nodeGroupLabel : n .id ,
@@ -423,6 +435,44 @@ func createServer(n *hetznerNodeGroup) error {
423435 return nil
424436}
425437
438+ // findImage searches for an image ID corresponding to the supplied
439+ // HCLOUD_IMAGE env variable. This value can either be an image ID itself (an
440+ // int), a name (e.g. "ubuntu-20.04"), or a label selector associated with an
441+ // image snapshot. In the latter case it will use the most recent snapshot.
442+ // It also verifies that the returned image has a compatible architecture with
443+ // server.
444+ func findImage (n * hetznerNodeGroup , serverType * hcloud.ServerType ) (* hcloud.Image , error ) {
445+ // Select correct image based on server type architecture
446+ image , _ , err := n .manager .client .Image .GetForArchitecture (context .TODO (), n .manager .image , serverType .Architecture )
447+ if err != nil {
448+ // Keep looking for label if image was not found by id or name
449+ if ! strings .HasPrefix (err .Error (), "image not found" ) {
450+ return nil , err
451+ }
452+ }
453+
454+ if image != nil {
455+ return image , nil
456+ }
457+
458+ // Look for snapshot with label
459+ images , err := n .manager .client .Image .AllWithOpts (context .TODO (), hcloud.ImageListOpts {
460+ Type : []hcloud.ImageType {hcloud .ImageTypeSnapshot },
461+ Status : []hcloud.ImageStatus {hcloud .ImageStatusAvailable },
462+ Sort : []string {"created:desc" },
463+ Architecture : []hcloud.Architecture {serverType .Architecture },
464+ ListOpts : hcloud.ListOpts {
465+ LabelSelector : n .manager .image ,
466+ },
467+ })
468+
469+ if err != nil || len (images ) == 0 {
470+ return nil , fmt .Errorf ("unable to find image %s with architecture %s: %v" , n .manager .image , serverType .Architecture , err )
471+ }
472+
473+ return images [0 ], nil
474+ }
475+
426476func waitForServerAction (m * hetznerManager , serverName string , action * hcloud.Action ) error {
427477 // The implementation of the Hetzner Cloud action client's WatchProgress
428478 // method may be a little puzzling. The following comment thus explains how
0 commit comments