github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/openstack/image.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package openstack 5 6 import ( 7 "github.com/go-goose/goose/v5/nova" 8 "github.com/juju/errors" 9 10 "github.com/juju/juju/environs/imagemetadata" 11 "github.com/juju/juju/environs/instances" 12 ) 13 14 // FlavorFilter is an interface that can control which server flavors 15 // are acceptable. 16 type FlavorFilter interface { 17 // AcceptFlavor returns true iff the given flavor is acceptable. 18 AcceptFlavor(nova.FlavorDetail) bool 19 } 20 21 // FlavorFilterFunc is a function type that implements FlavorFilter. 22 type FlavorFilterFunc func(nova.FlavorDetail) bool 23 24 // AcceptFlavor is part of the FlavorFilter interface. 25 func (f FlavorFilterFunc) AcceptFlavor(d nova.FlavorDetail) bool { 26 return f(d) 27 } 28 29 // AcceptAllFlavors is a function that returns true for any input, 30 // and can be assigned to a value of type FlavorFilterFunc. 31 func AcceptAllFlavors(nova.FlavorDetail) bool { 32 return true 33 } 34 35 // findInstanceSpec returns an image and instance type satisfying the constraint. 36 // The instance type comes from querying the flavors supported by the deployment. 37 func findInstanceSpec( 38 e *Environ, 39 ic instances.InstanceConstraint, 40 imageMetadata []*imagemetadata.ImageMetadata, 41 ) (*instances.InstanceSpec, error) { 42 // First construct all available instance types from the supported flavors. 43 nova := e.nova() 44 flavors, err := nova.ListFlavorsDetail() 45 if err != nil { 46 return nil, err 47 } 48 49 if ic.Constraints.HasRootDiskSource() && *ic.Constraints.RootDiskSource == "volume" { 50 // When the root disk is a volume (i.e. cinder block volume) 51 // we don't want to match on RootDisk size. If an instance requires 52 // a very large root disk we don't want to select a larger instance type 53 // to fit a disk that won't be local to the instance. 54 ic.Constraints.RootDisk = nil 55 } 56 57 // Not all needed information is available in flavors, 58 // for e.g. architectures or virtualisation types. 59 // For these properties, we assume that all instance types support 60 // all values. 61 var allInstanceTypes []instances.InstanceType 62 for _, flavor := range flavors { 63 if !e.flavorFilter.AcceptFlavor(flavor) { 64 continue 65 } 66 instanceType := instances.InstanceType{ 67 Id: flavor.Id, 68 Name: flavor.Name, 69 Arch: ic.Arch, 70 Mem: uint64(flavor.RAM), 71 CpuCores: uint64(flavor.VCPUs), 72 RootDisk: uint64(flavor.Disk * 1024), 73 // tags not currently supported on openstack 74 } 75 if ic.Constraints.HasVirtType() { 76 // Instance Type virtual type depends on the virtual type of the selected image, i.e. 77 // picking an image with a virt type gives a machine with this virt type. 78 instanceType.VirtType = ic.Constraints.VirtType 79 } 80 allInstanceTypes = append(allInstanceTypes, instanceType) 81 } 82 83 images := instances.ImageMetadataToImages(imageMetadata) 84 spec, err := instances.FindInstanceSpec(images, &ic, allInstanceTypes) 85 if err != nil { 86 return nil, errors.Trace(err) 87 } 88 89 // If instance constraints did not have a virtualisation type, 90 // but image metadata did, we will have an instance type 91 // with virtualisation type of an image. 92 if !ic.Constraints.HasVirtType() && spec.Image.VirtType != "" { 93 spec.InstanceType.VirtType = &spec.Image.VirtType 94 } 95 return spec, nil 96 }