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