Merge lp:~wallyworld/juju-core/fix-instance-type-matching into lp:~go-bot/juju-core/trunk
- fix-instance-type-matching
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Ian Booth |
Approved revision: | no longer in the source branch. |
Merged at revision: | 2323 |
Proposed branch: | lp:~wallyworld/juju-core/fix-instance-type-matching |
Merge into: | lp:~go-bot/juju-core/trunk |
Diff against target: |
231 lines (+94/-55) 4 files modified
environs/instances/instancetype.go (+38/-40) environs/instances/instancetype_test.go (+53/-12) provider/ec2/image_test.go (+1/-1) provider/openstack/local_test.go (+2/-2) |
To merge this branch: | bzr merge lp:~wallyworld/juju-core/fix-instance-type-matching |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju Engineering | Pending | ||
Review via email: mp+204159@code.launchpad.net |
Commit message
Fix instance type selection
Instance type selection will, by default, choose
an instance with enough memory for mong (1024M).
That is unless the user has specified a memory
constraint. If no matching instances are found,
an error is returned. Previously, instead of
an error an arbitary instance with 1024M would
be chosen.
It's perhaps easiest to see the behaviour by
looking at the tests in instancetype_test. With
the old code, several of the tests fail, especially
the memory ones where other constraints are used also.
Description of the change
Fix instance type selection
Instance type selection will, by default, choose
an instance with enough memory for mong (1024M).
That is unless the user has specified a memory
constraint. If no matching instances are found,
an error is returned. Previously, instead of
an error an arbitary instance with 1024M would
be chosen.
It's perhaps easiest to see the behaviour by
looking at the tests in instancetype_test. With
the old code, several of the tests fail, especially
the memory ones where other constraints are used also.
BTW - I tested on Canonistack and EC2. On Canonistack, the default instance
selection was m1.tiny (512MB) but this branch fixes that so that now
cpu1-ram1-
cpu-cores=9000 results in an error.
Ian Booth (wallyworld) wrote : | # |
Ian Booth (wallyworld) wrote : | # |
Please take a look.
Ian Booth (wallyworld) wrote : | # |
Please take a look.
Dimiter Naydenov (dimitern) wrote : | # |
LGTM with some suggestions.
https:/
File environs/
https:/
environs/
with largest available memory was returned even if it didn't
I don't think we need to explain how it was previously.
https:/
environs/
Why not just:
cons.Mem = uint64(
?
https:/
File environs/
https:/
environs/
specified, use that even though less than needed for mongodb",
I think if the user overrode our minimum memory heuristic, we should at
least print out a warning, saying bootstrap might fail due to
insufficient memory for mongo.
Ian Booth (wallyworld) wrote : | # |
Please take a look.
https:/
File environs/
https:/
environs/
with largest available memory was returned even if it didn't
On 2014/02/10 08:27:13, dimitern wrote:
> I don't think we need to explain how it was previously.
Done.
https:/
environs/
with largest available memory was returned even if it didn't
On 2014/02/10 08:27:13, dimitern wrote:
> I don't think we need to explain how it was previously.
Done.
https:/
environs/
On 2014/02/10 08:27:13, dimitern wrote:
> Why not just:
> cons.Mem = uint64(
> ?
Yeah, i refactored some stuff and left it in a bad state. Fixed. It does
need to be a pointer but there's no need for the intermediate object.
https:/
File environs/
https:/
environs/
specified, use that even though less than needed for mongodb",
On 2014/02/10 08:27:13, dimitern wrote:
> I think if the user overrode our minimum memory heuristic, we should
at least
> print out a warning, saying bootstrap might fail due to insufficient
memory for
> mongo.
Not sure about that. The user could also specify poorly speced systems
for charms and we don't emit anything there. This behaviour, allowing
the user to specify small memory, is not new - the tests are just being
improved. We have never in the past emitted a warning AFAIK.
Dimiter Naydenov (dimitern) wrote : | # |
https:/
File environs/
https:/
environs/
specified, use that even though less than needed for mongodb",
On 2014/02/11 00:39:04, wallyworld wrote:
> On 2014/02/10 08:27:13, dimitern wrote:
> > I think if the user overrode our minimum memory heuristic, we should
at least
> > print out a warning, saying bootstrap might fail due to insufficient
memory
> for
> > mongo.
> Not sure about that. The user could also specify poorly speced systems
for
> charms and we don't emit anything there. This behaviour, allowing the
user to
> specify small memory, is not new - the tests are just being improved.
We have
> never in the past emitted a warning AFAIK.
It's true we never said anything, but it's the UX improvement an
important goal? An overly conservative user might pick 256M so it's
cheap, but then will get frustrated why he can't bootstrap (perhaps
without a nice error in the log).
William Reade (fwereade) wrote : | # |
LGTM, but an explicit tie-breaker would be really nice.
https:/
File environs/
https:/
environs/
specified, use that even though less than needed for mongodb",
On 2014/02/11 09:59:57, dimitern wrote:
> On 2014/02/11 00:39:04, wallyworld wrote:
> > On 2014/02/10 08:27:13, dimitern wrote:
> > > I think if the user overrode our minimum memory heuristic, we
should at
> least
> > > print out a warning, saying bootstrap might fail due to
insufficient memory
> > for
> > > mongo.
> >
> > Not sure about that. The user could also specify poorly speced
systems for
> > charms and we don't emit anything there. This behaviour, allowing
the user to
> > specify small memory, is not new - the tests are just being
improved. We have
> > never in the past emitted a warning AFAIK.
> It's true we never said anything, but it's the UX improvement an
important goal?
> An overly conservative user might pick 256M so it's cheap, but then
will get
> frustrated why he can't bootstrap (perhaps without a nice error in the
log).
We *might* want to do this on a state server (although really we should
just take what we *know* we need in that case) but this isn't the right
layer IMO. They asked explicitly, and they got it ;).
https:/
File environs/
https:/
environs/
constraint specified, try again and return any matching instance
"any": would be nice to tie-break equal-greatest-
Ian Booth (wallyworld) wrote : | # |
I added a cost based tie breaker
https:/
File environs/
https:/
environs/
constraint specified, try again and return any matching instance
On 2014/02/13 15:19:21, fwereade wrote:
> "any": would be nice to tie-break equal-greatest-
cost
Done.
Go Bot (go-bot) wrote : | # |
The attempt to merge lp:~wallyworld/juju-core/fix-instance-type-matching into lp:juju-core failed. Below is the output from the failed tests.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
? launchpad.
? launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
? launchpad.
ok launchpad.
ok launchpad.
ok launchpad.
Preview Diff
1 | === modified file 'environs/instances/instancetype.go' | |||
2 | --- environs/instances/instancetype.go 2013-09-27 18:08:05 +0000 | |||
3 | +++ environs/instances/instancetype.go 2014-02-14 01:03:32 +0000 | |||
4 | @@ -74,52 +74,44 @@ | |||
5 | 74 | // minMemoryHeuristic is the assumed minimum amount of memory (in MB) we prefer in order to run a server (1GB) | 74 | // minMemoryHeuristic is the assumed minimum amount of memory (in MB) we prefer in order to run a server (1GB) |
6 | 75 | const minMemoryHeuristic = 1024 | 75 | const minMemoryHeuristic = 1024 |
7 | 76 | 76 | ||
8 | 77 | // matchingTypesForConstraint returns instance types from allTypes which match cons. | ||
9 | 78 | func matchingTypesForConstraint(allTypes []InstanceType, cons constraints.Value) []InstanceType { | ||
10 | 79 | var matchingTypes []InstanceType | ||
11 | 80 | for _, itype := range allTypes { | ||
12 | 81 | itype, ok := itype.match(cons) | ||
13 | 82 | if !ok { | ||
14 | 83 | continue | ||
15 | 84 | } | ||
16 | 85 | matchingTypes = append(matchingTypes, itype) | ||
17 | 86 | } | ||
18 | 87 | return matchingTypes | ||
19 | 88 | } | ||
20 | 89 | |||
21 | 77 | // getMatchingInstanceTypes returns all instance types matching ic.Constraints and available | 90 | // getMatchingInstanceTypes returns all instance types matching ic.Constraints and available |
22 | 78 | // in ic.Region, sorted by increasing region-specific cost (if known). | 91 | // in ic.Region, sorted by increasing region-specific cost (if known). |
23 | 79 | func getMatchingInstanceTypes(ic *InstanceConstraint, allInstanceTypes []InstanceType) ([]InstanceType, error) { | 92 | func getMatchingInstanceTypes(ic *InstanceConstraint, allInstanceTypes []InstanceType) ([]InstanceType, error) { |
24 | 80 | cons := ic.Constraints | ||
25 | 81 | region := ic.Region | 93 | region := ic.Region |
26 | 82 | var itypes []InstanceType | 94 | var itypes []InstanceType |
27 | 83 | 95 | ||
35 | 84 | // Iterate over allInstanceTypes, finding matching ones. | 96 | // Rules used to select instance types: |
36 | 85 | for _, itype := range allInstanceTypes { | 97 | // - non memory constraints like cpu-cores etc are always honoured |
37 | 86 | itype, ok := itype.match(cons) | 98 | // - if no mem constraint specified, try opinionated default with enough mem to run a server. |
38 | 87 | if !ok { | 99 | // - if no matches and no mem constraint specified, try again and return any matching instance |
39 | 88 | continue | 100 | // with the largest memory |
40 | 89 | } | 101 | cons := ic.Constraints |
41 | 90 | itypes = append(itypes, itype) | 102 | if ic.Constraints.Mem == nil { |
42 | 103 | minMem := uint64(minMemoryHeuristic) | ||
43 | 104 | cons.Mem = &minMem | ||
44 | 91 | } | 105 | } |
45 | 106 | itypes = matchingTypesForConstraint(allInstanceTypes, cons) | ||
46 | 92 | 107 | ||
77 | 93 | if len(itypes) == 0 { | 108 | // No matches using opinionated default, so if no mem constraint specified, |
78 | 94 | // No matching instance types were found, so the fallback is to: | 109 | // look for matching instance with largest memory. |
79 | 95 | // 1. Sort by memory and find the smallest matching both the required architecture | 110 | if len(itypes) == 0 && ic.Constraints.Mem == nil { |
80 | 96 | // and our own heuristic: minimum amount of memory required to run a realistic server, or | 111 | itypes = matchingTypesForConstraint(allInstanceTypes, ic.Constraints) |
81 | 97 | // 2. Sort by memory in reverse order and return the largest one, which will hopefully work, | 112 | if len(itypes) > 0 { |
82 | 98 | // albeit not the best match | 113 | sort.Sort(byMemory(itypes)) |
83 | 99 | archCons := constraints.Value{Arch: ic.Constraints.Arch} | 114 | itypes = []InstanceType{itypes[len(itypes)-1]} |
54 | 100 | for _, itype := range allInstanceTypes { | ||
55 | 101 | itype, ok := itype.match(archCons) | ||
56 | 102 | if !ok { | ||
57 | 103 | continue | ||
58 | 104 | } | ||
59 | 105 | itypes = append(itypes, itype) | ||
60 | 106 | } | ||
61 | 107 | sort.Sort(byMemory(itypes)) | ||
62 | 108 | var fallbackType *InstanceType | ||
63 | 109 | // 1. check for smallest instance type that can realistically run a server | ||
64 | 110 | for _, itype := range itypes { | ||
65 | 111 | if itype.Mem >= minMemoryHeuristic { | ||
66 | 112 | itcopy := itype | ||
67 | 113 | fallbackType = &itcopy | ||
68 | 114 | break | ||
69 | 115 | } | ||
70 | 116 | } | ||
71 | 117 | if fallbackType == nil && len(itypes) > 0 { | ||
72 | 118 | // 2. just get the one with the largest memory | ||
73 | 119 | fallbackType = &itypes[len(itypes)-1] | ||
74 | 120 | } | ||
75 | 121 | if fallbackType != nil { | ||
76 | 122 | itypes = []InstanceType{*fallbackType} | ||
84 | 123 | } | 115 | } |
85 | 124 | } | 116 | } |
86 | 125 | // If we have matching instance types, we can return those, sorted by cost. | 117 | // If we have matching instance types, we can return those, sorted by cost. |
87 | @@ -129,7 +121,7 @@ | |||
88 | 129 | } | 121 | } |
89 | 130 | 122 | ||
90 | 131 | // No luck, so report the error. | 123 | // No luck, so report the error. |
92 | 132 | return nil, fmt.Errorf("no instance types in %s matching constraints %q", region, cons) | 124 | return nil, fmt.Errorf("no instance types in %s matching constraints %q", region, ic.Constraints) |
93 | 133 | } | 125 | } |
94 | 134 | 126 | ||
95 | 135 | // tagsMatch returns if the tags in wanted all exist in have. | 127 | // tagsMatch returns if the tags in wanted all exist in have. |
96 | @@ -185,5 +177,11 @@ | |||
97 | 185 | func (s byMemory) Len() int { return len(s) } | 177 | func (s byMemory) Len() int { return len(s) } |
98 | 186 | func (s byMemory) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | 178 | func (s byMemory) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
99 | 187 | func (s byMemory) Less(i, j int) bool { | 179 | func (s byMemory) Less(i, j int) bool { |
101 | 188 | return s[i].Mem < s[j].Mem | 180 | inst0, inst1 := &s[i], &s[j] |
102 | 181 | if inst0.Mem != inst1.Mem { | ||
103 | 182 | return s[i].Mem < s[j].Mem | ||
104 | 183 | } | ||
105 | 184 | // Memory is equal, so use cost as a tie breaker. | ||
106 | 185 | // Result is in descending order of cost so instance with lowest cost is used. | ||
107 | 186 | return inst0.Cost > inst1.Cost | ||
108 | 189 | } | 187 | } |
109 | 190 | 188 | ||
110 | === modified file 'environs/instances/instancetype_test.go' | |||
111 | --- environs/instances/instancetype_test.go 2013-09-20 02:53:59 +0000 | |||
112 | +++ environs/instances/instancetype_test.go 2014-02-14 01:03:32 +0000 | |||
113 | @@ -140,24 +140,59 @@ | |||
114 | 140 | arches: []string{"arm"}, | 140 | arches: []string{"arm"}, |
115 | 141 | }, | 141 | }, |
116 | 142 | { | 142 | { |
120 | 143 | about: "fallback instance type, enough memory for mongodb", | 143 | about: "enough memory for mongodb if mem not specified", |
121 | 144 | cons: "mem=8G", | 144 | cons: "cpu-cores=4", |
122 | 145 | itypesToUse: []InstanceType{ | 145 | itypesToUse: []InstanceType{ |
123 | 146 | {Id: "5", Name: "it-5", Arches: []string{"amd64"}, Mem: 1024, CpuCores: 2}, | ||
124 | 147 | {Id: "4", Name: "it-4", Arches: []string{"amd64"}, Mem: 2048, CpuCores: 4}, | ||
125 | 148 | {Id: "3", Name: "it-3", Arches: []string{"amd64"}, Mem: 1024, CpuCores: 4}, | ||
126 | 149 | {Id: "2", Name: "it-2", Arches: []string{"amd64"}, Mem: 256, CpuCores: 4}, | ||
127 | 150 | {Id: "1", Name: "it-1", Arches: []string{"amd64"}, Mem: 512, CpuCores: 4}, | ||
128 | 151 | }, | ||
129 | 152 | expectedItypes: []string{"it-3", "it-4"}, | ||
130 | 153 | }, | ||
131 | 154 | { | ||
132 | 155 | about: "small mem specified, use that even though less than needed for mongodb", | ||
133 | 156 | cons: "mem=300M", | ||
134 | 157 | itypesToUse: []InstanceType{ | ||
135 | 158 | {Id: "3", Name: "it-3", Arches: []string{"amd64"}, Mem: 2048}, | ||
136 | 159 | {Id: "2", Name: "it-2", Arches: []string{"amd64"}, Mem: 256}, | ||
137 | 160 | {Id: "1", Name: "it-1", Arches: []string{"amd64"}, Mem: 512}, | ||
138 | 161 | }, | ||
139 | 162 | expectedItypes: []string{"it-1", "it-3"}, | ||
140 | 163 | }, | ||
141 | 164 | { | ||
142 | 165 | about: "mem specified and match found", | ||
143 | 166 | cons: "mem=4G arch=amd64", | ||
144 | 167 | itypesToUse: []InstanceType{ | ||
145 | 168 | {Id: "4", Name: "it-4", Arches: []string{"arm"}, Mem: 8096}, | ||
146 | 146 | {Id: "3", Name: "it-3", Arches: []string{"amd64"}, Mem: 4096}, | 169 | {Id: "3", Name: "it-3", Arches: []string{"amd64"}, Mem: 4096}, |
147 | 147 | {Id: "2", Name: "it-2", Arches: []string{"amd64"}, Mem: 2048}, | 170 | {Id: "2", Name: "it-2", Arches: []string{"amd64"}, Mem: 2048}, |
148 | 148 | {Id: "1", Name: "it-1", Arches: []string{"amd64"}, Mem: 512}, | 171 | {Id: "1", Name: "it-1", Arches: []string{"amd64"}, Mem: 512}, |
149 | 149 | }, | 172 | }, |
150 | 173 | expectedItypes: []string{"it-3"}, | ||
151 | 174 | }, | ||
152 | 175 | { | ||
153 | 176 | about: "largest mem available matching other constraints if mem not specified", | ||
154 | 177 | cons: "cpu-cores=4", | ||
155 | 178 | itypesToUse: []InstanceType{ | ||
156 | 179 | {Id: "3", Name: "it-3", Arches: []string{"amd64"}, Mem: 1024, CpuCores: 2}, | ||
157 | 180 | {Id: "2", Name: "it-2", Arches: []string{"amd64"}, Mem: 256, CpuCores: 4}, | ||
158 | 181 | {Id: "1", Name: "it-1", Arches: []string{"amd64"}, Mem: 512, CpuCores: 4}, | ||
159 | 182 | }, | ||
160 | 183 | expectedItypes: []string{"it-1"}, | ||
161 | 184 | }, | ||
162 | 185 | { | ||
163 | 186 | about: "largest mem available matching other constraints if mem not specified, cost is tie breaker", | ||
164 | 187 | cons: "cpu-cores=4", | ||
165 | 188 | itypesToUse: []InstanceType{ | ||
166 | 189 | {Id: "4", Name: "it-4", Arches: []string{"amd64"}, Mem: 1024, CpuCores: 2}, | ||
167 | 190 | {Id: "3", Name: "it-3", Arches: []string{"amd64"}, Mem: 256, CpuCores: 4}, | ||
168 | 191 | {Id: "2", Name: "it-2", Arches: []string{"amd64"}, Mem: 512, CpuCores: 4, Cost: 50}, | ||
169 | 192 | {Id: "1", Name: "it-1", Arches: []string{"amd64"}, Mem: 512, CpuCores: 4, Cost: 100}, | ||
170 | 193 | }, | ||
171 | 150 | expectedItypes: []string{"it-2"}, | 194 | expectedItypes: []string{"it-2"}, |
172 | 151 | }, | 195 | }, |
173 | 152 | { | ||
174 | 153 | about: "fallback instance type, not enough memory for mongodb", | ||
175 | 154 | cons: "mem=4G", | ||
176 | 155 | itypesToUse: []InstanceType{ | ||
177 | 156 | {Id: "2", Name: "it-2", Arches: []string{"amd64"}, Mem: 256}, | ||
178 | 157 | {Id: "1", Name: "it-1", Arches: []string{"amd64"}, Mem: 512}, | ||
179 | 158 | }, | ||
180 | 159 | expectedItypes: []string{"it-1"}, | ||
181 | 160 | }, | ||
182 | 161 | } | 196 | } |
183 | 162 | 197 | ||
184 | 163 | func constraint(region, cons string) *InstanceConstraint { | 198 | func constraint(region, cons string) *InstanceConstraint { |
185 | @@ -195,6 +230,12 @@ | |||
186 | 195 | 230 | ||
187 | 196 | _, err = getMatchingInstanceTypes(constraint("test", "arch=i386 mem=8G"), instanceTypes) | 231 | _, err = getMatchingInstanceTypes(constraint("test", "arch=i386 mem=8G"), instanceTypes) |
188 | 197 | c.Check(err, gc.ErrorMatches, `no instance types in test matching constraints "arch=i386 mem=8192M"`) | 232 | c.Check(err, gc.ErrorMatches, `no instance types in test matching constraints "arch=i386 mem=8192M"`) |
189 | 233 | |||
190 | 234 | _, err = getMatchingInstanceTypes(constraint("test", "cpu-cores=9000"), instanceTypes) | ||
191 | 235 | c.Check(err, gc.ErrorMatches, `no instance types in test matching constraints "cpu-cores=9000"`) | ||
192 | 236 | |||
193 | 237 | _, err = getMatchingInstanceTypes(constraint("test", "mem=90000M"), instanceTypes) | ||
194 | 238 | c.Check(err, gc.ErrorMatches, `no instance types in test matching constraints "mem=90000M"`) | ||
195 | 198 | } | 239 | } |
196 | 199 | 240 | ||
197 | 200 | var instanceTypeMatchTests = []struct { | 241 | var instanceTypeMatchTests = []struct { |
198 | 201 | 242 | ||
199 | === modified file 'provider/ec2/image_test.go' | |||
200 | --- provider/ec2/image_test.go 2014-01-29 00:14:51 +0000 | |||
201 | +++ provider/ec2/image_test.go 2014-02-14 01:03:32 +0000 | |||
202 | @@ -94,7 +94,7 @@ | |||
203 | 94 | series: "precise", | 94 | series: "precise", |
204 | 95 | arches: both, | 95 | arches: both, |
205 | 96 | cons: "cpu-power=", | 96 | cons: "cpu-power=", |
207 | 97 | itype: "t1.micro", | 97 | itype: "m1.small", |
208 | 98 | image: "ami-00000033", | 98 | image: "ami-00000033", |
209 | 99 | }, { | 99 | }, { |
210 | 100 | series: "precise", | 100 | series: "precise", |
211 | 101 | 101 | ||
212 | === modified file 'provider/openstack/local_test.go' | |||
213 | --- provider/openstack/local_test.go 2014-01-29 06:45:16 +0000 | |||
214 | +++ provider/openstack/local_test.go 2014-02-14 01:03:32 +0000 | |||
215 | @@ -530,7 +530,7 @@ | |||
216 | 530 | c.Assert(err, gc.IsNil) | 530 | c.Assert(err, gc.IsNil) |
217 | 531 | c.Assert(stateData.StateInstances, gc.HasLen, 1) | 531 | c.Assert(stateData.StateInstances, gc.HasLen, 1) |
218 | 532 | 532 | ||
220 | 533 | expectedHardware := instance.MustParseHardware("arch=amd64 cpu-cores=1 mem=512M") | 533 | expectedHardware := instance.MustParseHardware("arch=amd64 cpu-cores=1 mem=2G") |
221 | 534 | insts, err := env.AllInstances() | 534 | insts, err := env.AllInstances() |
222 | 535 | c.Assert(err, gc.IsNil) | 535 | c.Assert(err, gc.IsNil) |
223 | 536 | c.Assert(insts, gc.HasLen, 1) | 536 | c.Assert(insts, gc.HasLen, 1) |
224 | @@ -609,7 +609,7 @@ | |||
225 | 609 | env := s.Open(c) | 609 | env := s.Open(c) |
226 | 610 | 610 | ||
227 | 611 | // An error occurs if no suitable image is found. | 611 | // An error occurs if no suitable image is found. |
229 | 612 | _, err := openstack.FindInstanceSpec(env, "saucy", "amd64", "mem=8G") | 612 | _, err := openstack.FindInstanceSpec(env, "saucy", "amd64", "mem=1G") |
230 | 613 | c.Assert(err, gc.ErrorMatches, `no "saucy" images in some-region with arches \[amd64\]`) | 613 | c.Assert(err, gc.ErrorMatches, `no "saucy" images in some-region with arches \[amd64\]`) |
231 | 614 | } | 614 | } |
232 | 615 | 615 |
Reviewers: mp+204159_ code.launchpad. net,
Message:
Please take a look.
Description:
Fix instance type selection
Instance type selection will, by default, choose
an instance with enough memory for mong (1024M).
That is unless the user has specified a memory
constraint. If no matching instances are found,
an error is returned. Previously, instead of
an error an arbitary instance with 1024M would
be chosen.
It's perhaps easiest to see the behaviour by
looking at the tests in instancetype_test. With
the old code, several of the tests fail, especially
the memory ones where other constraints are used also.
https:/ /code.launchpad .net/~wallyworl d/juju- core/fix- instance- type-matching/ +merge/ 204159
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/58950043/
Affected files (+86, -40 lines): instances/ instancetype. go instances/ instancetype_ test.go
A [revision details]
M environs/
M environs/