github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 25 func newConstraints(args ConstraintsArgs) *constraints { 26 // If the ConstraintsArgs are all empty, then we return 27 // nil to indicate that there are no constraints. 28 if args.empty() { 29 return nil 30 } 31 32 tags := make([]string, len(args.Tags)) 33 copy(tags, args.Tags) 34 spaces := make([]string, len(args.Spaces)) 35 copy(spaces, args.Spaces) 36 return &constraints{ 37 Version: 1, 38 Architecture_: args.Architecture, 39 Container_: args.Container, 40 CpuCores_: args.CpuCores, 41 CpuPower_: args.CpuPower, 42 InstanceType_: args.InstanceType, 43 Memory_: args.Memory, 44 RootDisk_: args.RootDisk, 45 Spaces_: spaces, 46 Tags_: tags, 47 } 48 } 49 50 type constraints struct { 51 Version int `yaml:"version"` 52 53 Architecture_ string `yaml:"architecture,omitempty"` 54 Container_ string `yaml:"container,omitempty"` 55 CpuCores_ uint64 `yaml:"cpu-cores,omitempty"` 56 CpuPower_ uint64 `yaml:"cpu-power,omitempty"` 57 InstanceType_ string `yaml:"instance-type,omitempty"` 58 Memory_ uint64 `yaml:"memory,omitempty"` 59 RootDisk_ uint64 `yaml:"root-disk,omitempty"` 60 61 Spaces_ []string `yaml:"spaces,omitempty"` 62 Tags_ []string `yaml:"tags,omitempty"` 63 } 64 65 // Architecture implements Constraints. 66 func (c *constraints) Architecture() string { 67 return c.Architecture_ 68 } 69 70 // Container implements Constraints. 71 func (c *constraints) Container() string { 72 return c.Container_ 73 } 74 75 // CpuCores implements Constraints. 76 func (c *constraints) CpuCores() uint64 { 77 return c.CpuCores_ 78 } 79 80 // CpuPower implements Constraints. 81 func (c *constraints) CpuPower() uint64 { 82 return c.CpuPower_ 83 } 84 85 // InstanceType implements Constraints. 86 func (c *constraints) InstanceType() string { 87 return c.InstanceType_ 88 } 89 90 // Memory implements Constraints. 91 func (c *constraints) Memory() uint64 { 92 return c.Memory_ 93 } 94 95 // RootDisk implements Constraints. 96 func (c *constraints) RootDisk() uint64 { 97 return c.RootDisk_ 98 } 99 100 // Spaces implements Constraints. 101 func (c *constraints) Spaces() []string { 102 var spaces []string 103 if count := len(c.Spaces_); count > 0 { 104 spaces = make([]string, count) 105 copy(spaces, c.Spaces_) 106 } 107 return spaces 108 } 109 110 // Tags implements Constraints. 111 func (c *constraints) Tags() []string { 112 var tags []string 113 if count := len(c.Tags_); count > 0 { 114 tags = make([]string, count) 115 copy(tags, c.Tags_) 116 } 117 return tags 118 } 119 120 func importConstraints(source map[string]interface{}) (*constraints, error) { 121 version, err := getVersion(source) 122 if err != nil { 123 return nil, errors.Annotate(err, "constraints version schema check failed") 124 } 125 126 importFunc, ok := constraintsDeserializationFuncs[version] 127 if !ok { 128 return nil, errors.NotValidf("version %d", version) 129 } 130 131 return importFunc(source) 132 } 133 134 type constraintsDeserializationFunc func(map[string]interface{}) (*constraints, error) 135 136 var constraintsDeserializationFuncs = map[int]constraintsDeserializationFunc{ 137 1: importConstraintsV1, 138 } 139 140 func importConstraintsV1(source map[string]interface{}) (*constraints, error) { 141 fields := schema.Fields{ 142 "architecture": schema.String(), 143 "container": schema.String(), 144 "cpu-cores": schema.Uint(), 145 "cpu-power": schema.Uint(), 146 "instance-type": schema.String(), 147 "memory": schema.Uint(), 148 "root-disk": schema.Uint(), 149 150 "spaces": schema.List(schema.String()), 151 "tags": schema.List(schema.String()), 152 } 153 // Some values don't have to be there. 154 defaults := schema.Defaults{ 155 "architecture": "", 156 "container": "", 157 "cpu-cores": uint64(0), 158 "cpu-power": uint64(0), 159 "instance-type": "", 160 "memory": uint64(0), 161 "root-disk": uint64(0), 162 163 "spaces": schema.Omit, 164 "tags": schema.Omit, 165 } 166 checker := schema.FieldMap(fields, defaults) 167 168 coerced, err := checker.Coerce(source, nil) 169 if err != nil { 170 return nil, errors.Annotatef(err, "constraints v1 schema check failed") 171 } 172 valid := coerced.(map[string]interface{}) 173 // From here we know that the map returned from the schema coercion 174 // contains fields of the right type. 175 176 return &constraints{ 177 Version: 1, 178 Architecture_: valid["architecture"].(string), 179 Container_: valid["container"].(string), 180 CpuCores_: valid["cpu-cores"].(uint64), 181 CpuPower_: valid["cpu-power"].(uint64), 182 InstanceType_: valid["instance-type"].(string), 183 Memory_: valid["memory"].(uint64), 184 RootDisk_: valid["root-disk"].(uint64), 185 186 Spaces_: convertToStringSlice(valid["spaces"]), 187 Tags_: convertToStringSlice(valid["tags"]), 188 }, nil 189 } 190 191 func addConstraintsSchema(fields schema.Fields, defaults schema.Defaults) { 192 fields["constraints"] = schema.StringMap(schema.Any()) 193 defaults["constraints"] = schema.Omit 194 } 195 196 func (c ConstraintsArgs) empty() bool { 197 return c.Architecture == "" && 198 c.Container == "" && 199 c.CpuCores == 0 && 200 c.CpuPower == 0 && 201 c.InstanceType == "" && 202 c.Memory == 0 && 203 c.RootDisk == 0 && 204 c.Spaces == nil && 205 c.Tags == nil 206 }