Joe Topjian | 27a6243 | 2015-04-18 01:48:50 +0000 | [diff] [blame^] | 1 | package schedulerhints |
| 2 | |
| 3 | import ( |
| 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 |
| 14 | type 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. |
| 38 | type SchedulerHintsBuilder interface { |
| 39 | ToServerSchedulerHintsMap() (map[string]interface{}, error) |
| 40 | } |
| 41 | |
| 42 | // ToServerSchedulerHintsMap builds the scheduler hints into a serializable format. |
| 43 | func (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. |
| 108 | type 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. |
| 116 | func (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 | } |