github.com/gophercloud/gophercloud@v1.11.0/openstack/compute/v2/extensions/schedulerhints/requests.go (about)

     1  package schedulerhints
     2  
     3  import (
     4  	"encoding/json"
     5  	"net"
     6  	"regexp"
     7  	"strings"
     8  
     9  	"github.com/gophercloud/gophercloud"
    10  	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
    11  )
    12  
    13  // SchedulerHints represents a set of scheduling hints that are passed to the
    14  // OpenStack scheduler.
    15  type SchedulerHints struct {
    16  	// Group specifies a Server Group to place the instance in.
    17  	Group string
    18  
    19  	// DifferentHost will place the instance on a compute node that does not
    20  	// host the given instances.
    21  	DifferentHost []string
    22  
    23  	// SameHost will place the instance on a compute node that hosts the given
    24  	// instances.
    25  	SameHost []string
    26  
    27  	// Query is a conditional statement that results in compute nodes able to
    28  	// host the instance.
    29  	Query []interface{}
    30  
    31  	// TargetCell specifies a cell name where the instance will be placed.
    32  	TargetCell string `json:"target_cell,omitempty"`
    33  
    34  	// DifferentCell specifies cells names where an instance should not be placed.
    35  	DifferentCell []string `json:"different_cell,omitempty"`
    36  
    37  	// BuildNearHostIP specifies a subnet of compute nodes to host the instance.
    38  	BuildNearHostIP string
    39  
    40  	// AdditionalProperies are arbitrary key/values that are not validated by nova.
    41  	AdditionalProperties map[string]interface{}
    42  }
    43  
    44  // CreateOptsBuilder builds the scheduler hints into a serializable format.
    45  type CreateOptsBuilder interface {
    46  	ToServerSchedulerHintsCreateMap() (map[string]interface{}, error)
    47  }
    48  
    49  // ToServerSchedulerHintsMap builds the scheduler hints into a serializable format.
    50  func (opts SchedulerHints) ToServerSchedulerHintsCreateMap() (map[string]interface{}, error) {
    51  	sh := make(map[string]interface{})
    52  
    53  	uuidRegex, _ := regexp.Compile("^[a-z0-9]{8}-[a-z0-9]{4}-[1-5][a-z0-9]{3}-[a-z0-9]{4}-[a-z0-9]{12}$")
    54  
    55  	if opts.Group != "" {
    56  		if !uuidRegex.MatchString(opts.Group) {
    57  			err := gophercloud.ErrInvalidInput{}
    58  			err.Argument = "schedulerhints.SchedulerHints.Group"
    59  			err.Value = opts.Group
    60  			err.Info = "Group must be a UUID"
    61  			return nil, err
    62  		}
    63  		sh["group"] = opts.Group
    64  	}
    65  
    66  	if len(opts.DifferentHost) > 0 {
    67  		for _, diffHost := range opts.DifferentHost {
    68  			if !uuidRegex.MatchString(diffHost) {
    69  				err := gophercloud.ErrInvalidInput{}
    70  				err.Argument = "schedulerhints.SchedulerHints.DifferentHost"
    71  				err.Value = opts.DifferentHost
    72  				err.Info = "The hosts must be in UUID format."
    73  				return nil, err
    74  			}
    75  		}
    76  		sh["different_host"] = opts.DifferentHost
    77  	}
    78  
    79  	if len(opts.SameHost) > 0 {
    80  		for _, sameHost := range opts.SameHost {
    81  			if !uuidRegex.MatchString(sameHost) {
    82  				err := gophercloud.ErrInvalidInput{}
    83  				err.Argument = "schedulerhints.SchedulerHints.SameHost"
    84  				err.Value = opts.SameHost
    85  				err.Info = "The hosts must be in UUID format."
    86  				return nil, err
    87  			}
    88  		}
    89  		sh["same_host"] = opts.SameHost
    90  	}
    91  
    92  	/*
    93  		Query can be something simple like:
    94  			 [">=", "$free_ram_mb", 1024]
    95  
    96  			Or more complex like:
    97  				['and',
    98  					['>=', '$free_ram_mb', 1024],
    99  					['>=', '$free_disk_mb', 200 * 1024]
   100  				]
   101  
   102  		Because of the possible complexity, just make sure the length is a minimum of 3.
   103  	*/
   104  	if len(opts.Query) > 0 {
   105  		if len(opts.Query) < 3 {
   106  			err := gophercloud.ErrInvalidInput{}
   107  			err.Argument = "schedulerhints.SchedulerHints.Query"
   108  			err.Value = opts.Query
   109  			err.Info = "Must be a conditional statement in the format of [op,variable,value]"
   110  			return nil, err
   111  		}
   112  
   113  		// The query needs to be sent as a marshalled string.
   114  		b, err := json.Marshal(opts.Query)
   115  		if err != nil {
   116  			err := gophercloud.ErrInvalidInput{}
   117  			err.Argument = "schedulerhints.SchedulerHints.Query"
   118  			err.Value = opts.Query
   119  			err.Info = "Must be a conditional statement in the format of [op,variable,value]"
   120  			return nil, err
   121  		}
   122  
   123  		sh["query"] = string(b)
   124  	}
   125  
   126  	if opts.TargetCell != "" {
   127  		sh["target_cell"] = opts.TargetCell
   128  	}
   129  
   130  	if len(opts.DifferentCell) > 0 {
   131  		sh["different_cell"] = opts.DifferentCell
   132  	}
   133  
   134  	if opts.BuildNearHostIP != "" {
   135  		if _, _, err := net.ParseCIDR(opts.BuildNearHostIP); err != nil {
   136  			err := gophercloud.ErrInvalidInput{}
   137  			err.Argument = "schedulerhints.SchedulerHints.BuildNearHostIP"
   138  			err.Value = opts.BuildNearHostIP
   139  			err.Info = "Must be a valid subnet in the form 192.168.1.1/24"
   140  			return nil, err
   141  		}
   142  		ipParts := strings.Split(opts.BuildNearHostIP, "/")
   143  		sh["build_near_host_ip"] = ipParts[0]
   144  		sh["cidr"] = "/" + ipParts[1]
   145  	}
   146  
   147  	if opts.AdditionalProperties != nil {
   148  		for k, v := range opts.AdditionalProperties {
   149  			sh[k] = v
   150  		}
   151  	}
   152  
   153  	return sh, nil
   154  }
   155  
   156  // CreateOptsExt adds a SchedulerHints option to the base CreateOpts.
   157  type CreateOptsExt struct {
   158  	servers.CreateOptsBuilder
   159  
   160  	// SchedulerHints provides a set of hints to the scheduler.
   161  	SchedulerHints CreateOptsBuilder
   162  }
   163  
   164  // ToServerCreateMap adds the SchedulerHints option to the base server creation options.
   165  func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
   166  	base, err := opts.CreateOptsBuilder.ToServerCreateMap()
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	schedulerHints, err := opts.SchedulerHints.ToServerSchedulerHintsCreateMap()
   172  	if err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	if len(schedulerHints) == 0 {
   177  		return base, nil
   178  	}
   179  
   180  	base["os:scheduler_hints"] = schedulerHints
   181  
   182  	return base, nil
   183  }