blob: 5713e727f436c796fbc803e43862ea08f45630c8 [file] [log] [blame]
Joe Topjian27a62432015-04-18 01:48:50 +00001package schedulerhints
2
3import (
Joe Topjian27a62432015-04-18 01:48:50 +00004 "net"
5 "regexp"
6 "strings"
7
Jon Perrittf094fef2016-03-07 01:41:59 -06008 "github.com/gophercloud/gophercloud"
Jon Perritt27249f42016-02-18 10:35:59 -06009 "github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
Joe Topjian27a62432015-04-18 01:48:50 +000010)
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.
Joe Topjian7d6989c2015-05-05 20:38:08 +000028 Query []interface{}
Joe Topjian27a62432015-04-18 01:48:50 +000029
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) {
Jon Perrittf094fef2016-03-07 01:41:59 -060050 err := gophercloud.ErrInvalidInput{}
51 err.Function = "schedulerhints.ToServerSchedulerHintsMap"
52 err.Argument = "schedulerhints.SchedulerHints.Group"
53 err.Value = opts.Group
54 err.Info = "Group must be a UUID"
55 return nil, err
Joe Topjian27a62432015-04-18 01:48:50 +000056 }
57 sh["group"] = opts.Group
58 }
59
60 if len(opts.DifferentHost) > 0 {
61 for _, diffHost := range opts.DifferentHost {
62 if !uuidRegex.MatchString(diffHost) {
Jon Perrittf094fef2016-03-07 01:41:59 -060063 err := gophercloud.ErrInvalidInput{}
64 err.Function = "schedulerhints.ToServerSchedulerHintsMap"
65 err.Argument = "schedulerhints.SchedulerHints.DifferentHost"
66 err.Value = opts.DifferentHost
67 err.Info = "The hosts must be in UUID format."
68 return nil, err
Joe Topjian27a62432015-04-18 01:48:50 +000069 }
70 }
71 sh["different_host"] = opts.DifferentHost
72 }
73
74 if len(opts.SameHost) > 0 {
75 for _, sameHost := range opts.SameHost {
76 if !uuidRegex.MatchString(sameHost) {
Jon Perrittf094fef2016-03-07 01:41:59 -060077 err := gophercloud.ErrInvalidInput{}
78 err.Function = "schedulerhints.ToServerSchedulerHintsMap"
79 err.Argument = "schedulerhints.SchedulerHints.SameHost"
80 err.Value = opts.SameHost
81 err.Info = "The hosts must be in UUID format."
82 return nil, err
Joe Topjian27a62432015-04-18 01:48:50 +000083 }
84 }
85 sh["same_host"] = opts.SameHost
86 }
87
88 /* Query can be something simple like:
89 [">=", "$free_ram_mb", 1024]
90
91 Or more complex like:
92 ['and',
93 ['>=', '$free_ram_mb', 1024],
94 ['>=', '$free_disk_mb', 200 * 1024]
95 ]
96
97 Because of the possible complexity, just make sure the length is a minimum of 3.
98 */
99 if len(opts.Query) > 0 {
100 if len(opts.Query) < 3 {
Jon Perrittf094fef2016-03-07 01:41:59 -0600101 err := gophercloud.ErrInvalidInput{}
102 err.Function = "schedulerhints.ToServerSchedulerHintsMap"
103 err.Argument = "schedulerhints.SchedulerHints.Query"
104 err.Value = opts.Query
105 err.Info = "Must be a conditional statement in the format of [op,variable,value]"
106 return nil, err
Joe Topjian27a62432015-04-18 01:48:50 +0000107 }
108 sh["query"] = opts.Query
109 }
110
111 if opts.TargetCell != "" {
112 sh["target_cell"] = opts.TargetCell
113 }
114
115 if opts.BuildNearHostIP != "" {
116 if _, _, err := net.ParseCIDR(opts.BuildNearHostIP); err != nil {
Jon Perrittf094fef2016-03-07 01:41:59 -0600117 err := gophercloud.ErrInvalidInput{}
118 err.Function = "schedulerhints.ToServerSchedulerHintsMap"
119 err.Argument = "schedulerhints.SchedulerHints.BuildNearHostIP"
120 err.Value = opts.BuildNearHostIP
121 err.Info = "Must be a valid subnet in the form 192.168.1.1/24"
122 return nil, err
Joe Topjian27a62432015-04-18 01:48:50 +0000123 }
124 ipParts := strings.Split(opts.BuildNearHostIP, "/")
125 sh["build_near_host_ip"] = ipParts[0]
126 sh["cidr"] = "/" + ipParts[1]
127 }
128
129 return sh, nil
130}
131
132// CreateOptsExt adds a SchedulerHints option to the base CreateOpts.
133type CreateOptsExt struct {
134 servers.CreateOptsBuilder
135
136 // SchedulerHints provides a set of hints to the scheduler.
137 SchedulerHints SchedulerHintsBuilder
138}
139
140// ToServerCreateMap adds the SchedulerHints option to the base server creation options.
141func (opts CreateOptsExt) ToServerCreateMap() (map[string]interface{}, error) {
142 base, err := opts.CreateOptsBuilder.ToServerCreateMap()
143 if err != nil {
144 return nil, err
145 }
146
147 schedulerHints, err := opts.SchedulerHints.ToServerSchedulerHintsMap()
148 if err != nil {
149 return nil, err
150 }
151
152 if len(schedulerHints) == 0 {
153 return base, nil
154 }
155
156 base["os:scheduler_hints"] = schedulerHints
157
158 return base, nil
159}