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 }