github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/core/description/constraints.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package description 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/schema" 9 ) 10 11 // ConstraintsArgs is an argument struct to construct Constraints. 12 type ConstraintsArgs struct { 13 Architecture string 14 Container string 15 CpuCores uint64 16 CpuPower uint64 17 InstanceType string 18 Memory uint64 19 RootDisk uint64 20 21 Spaces []string 22 Tags []string 23 24 VirtType string 25 } 26 27 func newConstraints(args ConstraintsArgs) *constraints { 28 // If the ConstraintsArgs are all empty, then we return 29 // nil to indicate that there are no constraints. 30 if args.empty() { 31 return nil 32 } 33 34 tags := make([]string, len(args.Tags)) 35 copy(tags, args.Tags) 36 spaces := make([]string, len(args.Spaces)) 37 copy(spaces, args.Spaces) 38 return &constraints{ 39 Version: 1, 40 Architecture_: args.Architecture, 41 Container_: args.Container, 42 CpuCores_: args.CpuCores, 43 CpuPower_: args.CpuPower, 44 InstanceType_: args.InstanceType, 45 Memory_: args.Memory, 46 RootDisk_: args.RootDisk, 47 Spaces_: spaces, 48 Tags_: tags, 49 VirtType_: args.VirtType, 50 } 51 } 52 53 type constraints struct { 54 Version int `yaml:"version"` 55 56 Architecture_ string `yaml:"architecture,omitempty"` 57 Container_ string `yaml:"container,omitempty"` 58 CpuCores_ uint64 `yaml:"cores,omitempty"` 59 CpuPower_ uint64 `yaml:"cpu-power,omitempty"` 60 InstanceType_ string `yaml:"instance-type,omitempty"` 61 Memory_ uint64 `yaml:"memory,omitempty"` 62 RootDisk_ uint64 `yaml:"root-disk,omitempty"` 63 64 Spaces_ []string `yaml:"spaces,omitempty"` 65 Tags_ []string `yaml:"tags,omitempty"` 66 67 VirtType_ string `yaml:"virt-type,omitempty"` 68 } 69 70 // Architecture implements Constraints. 71 func (c *constraints) Architecture() string { 72 return c.Architecture_ 73 } 74 75 // Container implements Constraints. 76 func (c *constraints) Container() string { 77 return c.Container_ 78 } 79 80 // CpuCores implements Constraints. 81 func (c *constraints) CpuCores() uint64 { 82 return c.CpuCores_ 83 } 84 85 // CpuPower implements Constraints. 86 func (c *constraints) CpuPower() uint64 { 87 return c.CpuPower_ 88 } 89 90 // InstanceType implements Constraints. 91 func (c *constraints) InstanceType() string { 92 return c.InstanceType_ 93 } 94 95 // Memory implements Constraints. 96 func (c *constraints) Memory() uint64 { 97 return c.Memory_ 98 } 99 100 // RootDisk implements Constraints. 101 func (c *constraints) RootDisk() uint64 { 102 return c.RootDisk_ 103 } 104 105 // Spaces implements Constraints. 106 func (c *constraints) Spaces() []string { 107 var spaces []string 108 if count := len(c.Spaces_); count > 0 { 109 spaces = make([]string, count) 110 copy(spaces, c.Spaces_) 111 } 112 return spaces 113 } 114 115 // Tags implements Constraints. 116 func (c *constraints) Tags() []string { 117 var tags []string 118 if count := len(c.Tags_); count > 0 { 119 tags = make([]string, count) 120 copy(tags, c.Tags_) 121 } 122 return tags 123 } 124 125 // VirtType implements Constraints. 126 func (c *constraints) VirtType() string { 127 return c.VirtType_ 128 } 129 130 func importConstraints(source map[string]interface{}) (*constraints, error) { 131 version, err := getVersion(source) 132 if err != nil { 133 return nil, errors.Annotate(err, "constraints version schema check failed") 134 } 135 136 importFunc, ok := constraintsDeserializationFuncs[version] 137 if !ok { 138 return nil, errors.NotValidf("version %d", version) 139 } 140 141 return importFunc(source) 142 } 143 144 type constraintsDeserializationFunc func(map[string]interface{}) (*constraints, error) 145 146 var constraintsDeserializationFuncs = map[int]constraintsDeserializationFunc{ 147 1: importConstraintsV1, 148 } 149 150 func importConstraintsV1(source map[string]interface{}) (*constraints, error) { 151 fields := schema.Fields{ 152 "architecture": schema.String(), 153 "container": schema.String(), 154 "cpu-cores": schema.ForceUint(), 155 "cores": schema.ForceUint(), 156 "cpu-power": schema.ForceUint(), 157 "instance-type": schema.String(), 158 "memory": schema.ForceUint(), 159 "root-disk": schema.ForceUint(), 160 161 "spaces": schema.List(schema.String()), 162 "tags": schema.List(schema.String()), 163 164 "virt-type": schema.String(), 165 } 166 // Some values don't have to be there. 167 defaults := schema.Defaults{ 168 "architecture": "", 169 "container": "", 170 "cpu-cores": schema.Omit, 171 "cores": schema.Omit, 172 "cpu-power": uint64(0), 173 "instance-type": "", 174 "memory": uint64(0), 175 "root-disk": uint64(0), 176 177 "spaces": schema.Omit, 178 "tags": schema.Omit, 179 180 "virt-type": "", 181 } 182 checker := schema.FieldMap(fields, defaults) 183 184 coerced, err := checker.Coerce(source, nil) 185 if err != nil { 186 return nil, errors.Annotatef(err, "constraints v1 schema check failed") 187 } 188 189 valid := coerced.(map[string]interface{}) 190 _, hasCPU := valid["cpu-cores"] 191 _, hasCores := valid["cores"] 192 if hasCPU && hasCores { 193 return nil, errors.Errorf("can not specify both cores and cores constraints") 194 } 195 196 var cores uint64 197 if hasCPU { 198 cores = valid["cpu-cores"].(uint64) 199 } 200 if hasCores { 201 cores = valid["cores"].(uint64) 202 } 203 204 // From here we know that the map returned from the schema coercion 205 // contains fields of the right type. 206 207 return &constraints{ 208 Version: 1, 209 Architecture_: valid["architecture"].(string), 210 Container_: valid["container"].(string), 211 CpuCores_: cores, 212 CpuPower_: valid["cpu-power"].(uint64), 213 InstanceType_: valid["instance-type"].(string), 214 Memory_: valid["memory"].(uint64), 215 RootDisk_: valid["root-disk"].(uint64), 216 217 Spaces_: convertToStringSlice(valid["spaces"]), 218 Tags_: convertToStringSlice(valid["tags"]), 219 220 VirtType_: valid["virt-type"].(string), 221 }, nil 222 } 223 224 func addConstraintsSchema(fields schema.Fields, defaults schema.Defaults) { 225 fields["constraints"] = schema.StringMap(schema.Any()) 226 defaults["constraints"] = schema.Omit 227 } 228 229 func (c ConstraintsArgs) empty() bool { 230 return c.Architecture == "" && 231 c.Container == "" && 232 c.CpuCores == 0 && 233 c.CpuPower == 0 && 234 c.InstanceType == "" && 235 c.Memory == 0 && 236 c.RootDisk == 0 && 237 c.Spaces == nil && 238 c.Tags == nil && 239 c.VirtType == "" 240 }