blob: c8b8da0a928c445c00e06f42943179e2b626a6e9 [file] [log] [blame]
Joe Topjian27a62432015-04-18 01:48:50 +00001package schedulerhints
2
3import (
4 "fmt"
5 "net"
6 "regexp"
7 "strings"
8
9 "github.com/rackspace/gophercloud/openstack/compute/v2/servers"
10)
11
12// SchedulerHints represents a set of scheduling hints that are passed to the
13// OpenStack scheduler
14type SchedulerHints struct {
15 // Group specifies a Server Group to place the instance in.
16 Group string
17
18 // DifferentHost will place the instance on a compute node that does not
19 // host the given instances.
20 DifferentHost []string
21
22 // SameHost will place the instance on a compute node that hosts the given
23 // instances.
24 SameHost []string
25
26 // Query is a conditional statement that results in compute nodes able to
27 // host the instance.
28 Query []string
29
30 // TargetCell specifies a cell name where the instance will be placed.
31 TargetCell string
32
33 // BuildNearHostIP specifies a subnet of compute nodes to host the instance.
34 BuildNearHostIP string
35}
36
37// SchedulerHintsBuilder builds the scheduler hints into a serializable format.
38type SchedulerHintsBuilder interface {
39 ToServerSchedulerHintsMap() (map[string]interface{}, error)
40}
41
42// ToServerSchedulerHintsMap builds the scheduler hints into a serializable format.
43func (opts SchedulerHints) ToServerSchedulerHintsMap() (map[string]interface{}, error) {
44 sh := make(map[string]interface{})
45
46 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}$")
47
48 if opts.Group != "" {
49 if !uuidRegex.MatchString(opts.Group) {
50 return nil, fmt.Errorf("Group must be a UUID")
51 }
52 sh["group"] = opts.Group
53 }
54
55 if len(opts.DifferentHost) > 0 {
56 for _, diffHost := range opts.DifferentHost {
57 if !uuidRegex.MatchString(diffHost) {
58 return nil, fmt.Errorf("The hosts in DifferentHost must be in UUID format.")
59 }
60 }
61 sh["different_host"] = opts.DifferentHost
62 }
63
64 if len(opts.SameHost) > 0 {
65 for _, sameHost := range opts.SameHost {
66 if !uuidRegex.MatchString(sameHost) {
67 return nil, fmt.Errorf("The hosts in SameHost must be in UUID format.")
68 }
69 }
70 sh["same_host"] = opts.SameHost
71 }
72
73 /* Query can be something simple like:
74 [">=", "$free_ram_mb", 1024]
75
76 Or more complex like:
77 ['and',
78 ['>=', '$free_ram_mb', 1024],
79 ['>=', '$free_disk_mb', 200 * 1024]
80 ]
81
82 Because of the possible complexity, just make sure the length is a minimum of 3.
83 */
84 if len(opts.Query) > 0 {
85 if len(opts.Query) < 3 {
86 return nil, fmt.Errorf("Query must be a conditional statement in the format of [op,variable,value]")
87 }
88 sh["query"] = opts.Query
89 }
90
91 if opts.TargetCell != "" {
92 sh["target_cell"] = opts.TargetCell
93 }
94
95 if opts.BuildNearHostIP != "" {
96 if _, _, err := net.ParseCIDR(opts.BuildNearHostIP); err != nil {
97 return nil, fmt.Errorf("BuildNearHostIP must be a valid subnet in the form 192.168.1.1/24")
98 }
99 ipParts := strings.Split(opts.BuildNearHostIP, "/")
100 sh["build_near_host_ip"] = ipParts[0]
101 sh["cidr"] = "/" + ipParts[1]
102 }
103
104 return sh, nil
105}
106
107// CreateOptsExt adds a SchedulerHints option to the base CreateOpts.
108type CreateOptsExt struct {
109 servers.CreateOptsBuilder
110
111 // SchedulerHints provides a set of hints to the scheduler.
112 SchedulerHints SchedulerHintsBuilder
113}
114
115// ToServerCreateMap adds the SchedulerHints option to the base server creation options.
116func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
117 base, err := opts.CreateOptsBuilder.ToServerCreateMap()
118 if err != nil {
119 return nil, err
120 }
121
122 schedulerHints, err := opts.SchedulerHints.ToServerSchedulerHintsMap()
123 if err != nil {
124 return nil, err
125 }
126
127 if len(schedulerHints) == 0 {
128 return base, nil
129 }
130
131 base["os:scheduler_hints"] = schedulerHints
132
133 return base, nil
134}