github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/provider/maas/constraints.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package maas
     5  
     6  import (
     7  	"net/url"
     8  	"strings"
     9  
    10  	"github.com/juju/collections/set"
    11  	"github.com/juju/gomaasapi/v2"
    12  
    13  	"github.com/juju/juju/core/arch"
    14  	"github.com/juju/juju/core/constraints"
    15  	"github.com/juju/juju/environs/context"
    16  )
    17  
    18  var unsupportedConstraints = []string{
    19  	constraints.CpuPower,
    20  	constraints.InstanceType,
    21  	constraints.VirtType,
    22  	constraints.AllocatePublicIP,
    23  }
    24  
    25  // ConstraintsValidator is defined on the Environs interface.
    26  func (env *maasEnviron) ConstraintsValidator(ctx context.ProviderCallContext) (constraints.Validator, error) {
    27  	validator := constraints.NewValidator()
    28  	validator.RegisterUnsupported(unsupportedConstraints)
    29  	supportedArches, err := env.getSupportedArchitectures(ctx)
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  
    34  	// Only consume supported juju architectures for this release. This will
    35  	// also remove any duplicate architectures.
    36  	maasArches := set.NewStrings(supportedArches...)
    37  	supported := set.NewStrings(arch.AllSupportedArches...).Intersection(maasArches)
    38  
    39  	validator.RegisterVocabulary(constraints.Arch, supported.SortedValues())
    40  
    41  	return validator, nil
    42  }
    43  
    44  // convertConstraints converts the given constraints into a
    45  // gomaasapi.AllocateMachineArgs for passing to MAAS.
    46  func convertConstraints(cons constraints.Value) gomaasapi.AllocateMachineArgs {
    47  	params := gomaasapi.AllocateMachineArgs{}
    48  	if cons.Arch != nil {
    49  		params.Architecture = *cons.Arch
    50  	}
    51  	if cons.CpuCores != nil {
    52  		params.MinCPUCount = int(*cons.CpuCores)
    53  	}
    54  	if cons.Mem != nil {
    55  		params.MinMemory = int(*cons.Mem)
    56  	}
    57  	if cons.Tags != nil {
    58  		positives, negatives := parseDelimitedValues(*cons.Tags)
    59  		if len(positives) > 0 {
    60  			params.Tags = positives
    61  		}
    62  		if len(negatives) > 0 {
    63  			params.NotTags = negatives
    64  		}
    65  	}
    66  	if cons.CpuPower != nil {
    67  		logger.Warningf("ignoring unsupported constraint 'cpu-power'")
    68  	}
    69  	return params
    70  }
    71  
    72  // convertTagsToParams converts a list of positive/negative tags from
    73  // constraints into two comma-delimited lists of values, which can then be
    74  // passed to MAAS using the "tags" and "not_tags" arguments to acquire. If
    75  // either list of tags is empty, the respective argument is not added to params.
    76  func convertTagsToParams(params url.Values, tags *[]string) {
    77  	if tags == nil || len(*tags) == 0 {
    78  		return
    79  	}
    80  	positives, negatives := parseDelimitedValues(*tags)
    81  	if len(positives) > 0 {
    82  		params.Add("tags", strings.Join(positives, ","))
    83  	}
    84  	if len(negatives) > 0 {
    85  		params.Add("not_tags", strings.Join(negatives, ","))
    86  	}
    87  }
    88  
    89  // convertSpacesFromConstraints extracts spaces from constraints and converts
    90  // them to two lists of positive and negative spaces.
    91  func convertSpacesFromConstraints(spaces *[]string) ([]string, []string) {
    92  	if spaces == nil || len(*spaces) == 0 {
    93  		return nil, nil
    94  	}
    95  	return parseDelimitedValues(*spaces)
    96  }
    97  
    98  // parseDelimitedValues parses a slice of raw values coming from constraints
    99  // (Tags or Spaces). The result is split into two slices - positives and
   100  // negatives (prefixed with "^"). Empty values are ignored.
   101  func parseDelimitedValues(rawValues []string) (positives, negatives []string) {
   102  	for _, value := range rawValues {
   103  		if value == "" || value == "^" {
   104  			// Neither of these cases should happen in practise, as constraints
   105  			// are validated before setting them and empty names for spaces or
   106  			// tags are not allowed.
   107  			continue
   108  		}
   109  		if strings.HasPrefix(value, "^") {
   110  			negatives = append(negatives, strings.TrimPrefix(value, "^"))
   111  		} else {
   112  			positives = append(positives, value)
   113  		}
   114  	}
   115  	return positives, negatives
   116  }
   117  
   118  func addInterfaces(params *gomaasapi.AllocateMachineArgs, positiveSpaceIDs, negativeSpaceIDs set.Strings) {
   119  	if len(positiveSpaceIDs) > 0 {
   120  		for _, providerSpaceID := range positiveSpaceIDs.SortedValues() {
   121  			// NOTE(achilleasa): use the provider ID as the label for the
   122  			// iface. Using the space name might seem to be more
   123  			// user-friendly but space names can change after the machine
   124  			// gets provisioned so they should not be used for labeling things.
   125  			params.Interfaces = append(
   126  				params.Interfaces,
   127  				gomaasapi.InterfaceSpec{
   128  					Label: providerSpaceID,
   129  					Space: providerSpaceID,
   130  				},
   131  			)
   132  		}
   133  	}
   134  
   135  	if len(negativeSpaceIDs) != 0 {
   136  		params.NotSpace = negativeSpaceIDs.SortedValues()
   137  	}
   138  }
   139  
   140  // addStorage adds volume information onto a gomaasapi.AllocateMachineArgs
   141  // object suitable to pass to MAAS 2 when acquiring a node.
   142  func addStorage(params *gomaasapi.AllocateMachineArgs, volumes []volumeInfo) {
   143  	if len(volumes) == 0 {
   144  		return
   145  	}
   146  	var volParams []gomaasapi.StorageSpec
   147  	for _, v := range volumes {
   148  		volSpec := gomaasapi.StorageSpec{
   149  			Label: v.name,
   150  			Size:  int(v.sizeInGB),
   151  			Tags:  v.tags,
   152  		}
   153  		volParams = append(volParams, volSpec)
   154  	}
   155  	params.Storage = volParams
   156  }