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  }