Merge lp:~cmars/juju-core/resolve-cs-series into lp:~go-bot/juju-core/trunk

Proposed by Casey Marshall
Status: Merged
Approved by: Casey Marshall
Approved revision: no longer in the source branch.
Merged at revision: 2559
Proposed branch: lp:~cmars/juju-core/resolve-cs-series
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 1614 lines (+447/-151)
40 files modified
charm/charm.go (+5/-5)
charm/charm_test.go (+4/-4)
charm/url.go (+17/-2)
charm/url_test.go (+20/-1)
cmd/juju/addmachine.go (+2/-1)
cmd/juju/bootstrap_test.go (+33/-20)
cmd/juju/common.go (+39/-0)
cmd/juju/deploy.go (+14/-11)
cmd/juju/environment_test.go (+14/-4)
cmd/juju/publish.go (+1/-1)
cmd/juju/upgradecharm.go (+6/-11)
cmd/juju/upgradejuju_test.go (+10/-6)
cmd/plugins/juju-metadata/imagemetadata.go (+2/-2)
cmd/plugins/juju-metadata/imagemetadata_test.go (+4/-2)
environs/bootstrap/bootstrap_test.go (+16/-9)
environs/bootstrap/synctools.go (+8/-3)
environs/config/config.go (+59/-8)
environs/config/config_test.go (+7/-6)
environs/jujutest/livetests.go (+2/-2)
environs/testing/tools.go (+9/-8)
juju/apiconn_test.go (+1/-1)
juju/testing/conn.go (+15/-2)
juju/testing/instance.go (+2/-1)
provider/azure/environ_test.go (+1/-1)
provider/common/bootstrap.go (+1/-1)
provider/dummy/environs.go (+1/-1)
provider/ec2/ec2.go (+1/-1)
provider/ec2/live_test.go (+1/-1)
provider/ec2/local_test.go (+1/-1)
provider/joyent/environ.go (+1/-1)
provider/openstack/provider.go (+1/-1)
state/api/client.go (+18/-0)
state/api/params/params.go (+16/-0)
state/apiserver/client/client.go (+40/-13)
state/apiserver/client/client_test.go (+60/-5)
testing/environ.go (+3/-1)
worker/provisioner/container_initialisation_test.go (+4/-4)
worker/provisioner/kvm-broker_test.go (+3/-4)
worker/provisioner/lxc-broker_test.go (+3/-4)
worker/provisioner/provisioner_test.go (+2/-2)
To merge this branch: bzr merge lp:~cmars/juju-core/resolve-cs-series
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+212755@code.launchpad.net

Commit message

Resolve series with charm store in juju client.

For the deploy and upgradecharm commands, when a series is not provided, and a
default-series is not set in the environment config, the client will resolve
the series with the charm store, through the state server. If the client is
working with a 1.16 state server, it will resolve the series directly with the
charm store.

Existing environments will have a default-series, so they should have no
change in series selection.

New environments will continue to support the default-series config setting,
but it can be omitted, and is not set by default.

https://codereview.appspot.com/80280043/

Description of the change

Resolve series with charm store in juju client.

For the deploy and upgradecharm commands, when a series is not provided, and a
default-series is not set in the environment config, the client will resolve
the series with the charm store, through the state server. If the client is
working with a 1.16 state server, it will resolve the series directly with the
charm store.

Existing environments will have a default-series, so they should have no
change in series selection.

New environments will continue to support the default-series config setting,
but it can be omitted, and is not set by default.

https://codereview.appspot.com/80280043/

To post a comment you must log in.
Revision history for this message
Casey Marshall (cmars) wrote :

Reviewers: mp+212755_code.launchpad.net,

Message:
Please take a look.

Description:
Resolve series with charm store in juju client.

For the deploy and upgradecharm commands, when a series is not provided,
and a
default-series is not set in the environment config, the client will
resolve
the series with the charm store, through the state server. If the
client is
working with a 1.16 state server, it will resolve the series directly
with the
charm store.

Existing environments will have a default-series, so they should have no
change in series selection.

New environments will continue to support the default-series config
setting,
but it can be omitted, and is not set by default.

https://code.launchpad.net/~cmars/juju-core/resolve-cs-series/+merge/212755

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/80280043/

Affected files (+189, -32 lines):
   A [revision details]
   M charm/charm.go
   M charm/charm_test.go
   M cmd/juju/deploy.go
   M cmd/juju/publish.go
   M cmd/juju/upgradecharm.go
   M environs/bootstrap/synctools.go
   M environs/config/config.go
   M juju/testing/conn.go
   M state/api/client.go
   M state/apiserver/client/client.go
   M state/apiserver/client/client_test.go

Revision history for this message
Casey Marshall (cmars) wrote :

This is the client-side to support the LTS transition to trusty (LP:
#1290824). It can't land until the charm store update (LP: #1290828) is
deployed into production (expected tomorrow).

In the meantime, I'd much appreciate your feedback & review.

Thanks,
Casey

https://codereview.appspot.com/80280043/

Revision history for this message
John A Meinel (jameinel) wrote :

I think we have some common code that should be factored out, and I
think we need to consider how the code will operate with older Juju
server versions, but otherwise I think this looks pretty good.

https://codereview.appspot.com/80280043/diff/1/cmd/juju/deploy.go
File cmd/juju/deploy.go (right):

https://codereview.appspot.com/80280043/diff/1/cmd/juju/deploy.go#newcode155
cmd/juju/deploy.go:155: repo, err := charm.InferRepository(ref,
ctx.AbsPath(c.RepoPath))
This feels like stuff that definitely needs to be done, but shouldn't be
done in "cmd/juju/deploy.go" which is a "main" sort of function.
Is there a reason this can't be part of more "library" code and tested
as such?

Specifically it feels like it should be a function that takes the
command line parameter (CharmName) a client and a conf, and returns a
fully qualified charm.URL (or error).

Especially given that you essentially implemented it 2 times in this
file. (at least the code you added below this looks a lot like the code
you added above this).

https://codereview.appspot.com/80280043/diff/1/cmd/juju/upgradecharm.go
File cmd/juju/upgradecharm.go (left):

https://codereview.appspot.com/80280043/diff/1/cmd/juju/upgradecharm.go#oldcode208
cmd/juju/upgradecharm.go:208: }
And here, though this one seems to have a new SpecializeCharmRepo step
that I didn't see before.

https://codereview.appspot.com/80280043/diff/1/cmd/juju/upgradecharm.go
File cmd/juju/upgradecharm.go (right):

https://codereview.appspot.com/80280043/diff/1/cmd/juju/upgradecharm.go#newcode148
cmd/juju/upgradecharm.go:148: }
And implemented again here?

https://codereview.appspot.com/80280043/diff/1/state/api/client.go
File state/api/client.go (right):

https://codereview.appspot.com/80280043/diff/1/state/api/client.go#newcode573
state/api/client.go:573:
We need to also add code to handle the fallback case. What do we do if
you are using juju 1.18 to deploy against a 1.16 server that doesn't
have the ResolveCharm API.

I'm guessing the answer is to print an error of:
  "You must supply a series in your charm URL for juju < 1.18".

Either that, or we see that the ResolveCharm isn't available, and just
issue a warning with something like "server version is too old to
support ResolveCharm (juju <1.18) falling back to default series of
"precise""

To be clear, that compatibility code probably shouldn't be here. But
probably could be in the common helper I was outlining earlier.

https://codereview.appspot.com/80280043/

Revision history for this message
Casey Marshall (cmars) wrote :

PTAL. If everything looks ok, I'd still like to run a few more tests
against the deployed charm store update tomorrow, before landing.

Thanks,
Casey

https://codereview.appspot.com/80280043/diff/1/cmd/juju/deploy.go
File cmd/juju/deploy.go (right):

https://codereview.appspot.com/80280043/diff/1/cmd/juju/deploy.go#newcode155
cmd/juju/deploy.go:155: repo, err := charm.InferRepository(ref,
ctx.AbsPath(c.RepoPath))
On 2014/03/26 07:11:17, jameinel wrote:
> This feels like stuff that definitely needs to be done, but shouldn't
be done in
> "cmd/juju/deploy.go" which is a "main" sort of function.
> Is there a reason this can't be part of more "library" code and tested
as such?

> Specifically it feels like it should be a function that takes the
command line
> parameter (CharmName) a client and a conf, and returns a fully
qualified
> charm.URL (or error).

> Especially given that you essentially implemented it 2 times in this
file. (at
> least the code you added below this looks a lot like the code you
added above
> this).

Good call, I've refactored functions to cmd/common.go, shared among
deploy and upgradecharm.

https://codereview.appspot.com/80280043/diff/1/cmd/juju/upgradecharm.go
File cmd/juju/upgradecharm.go (left):

https://codereview.appspot.com/80280043/diff/1/cmd/juju/upgradecharm.go#oldcode208
cmd/juju/upgradecharm.go:208: }
On 2014/03/26 07:11:17, jameinel wrote:
> And here, though this one seems to have a new SpecializeCharmRepo step
that I
> didn't see before.

Done.

https://codereview.appspot.com/80280043/diff/1/cmd/juju/upgradecharm.go
File cmd/juju/upgradecharm.go (right):

https://codereview.appspot.com/80280043/diff/1/cmd/juju/upgradecharm.go#newcode148
cmd/juju/upgradecharm.go:148: }
On 2014/03/26 07:11:17, jameinel wrote:
> And implemented again here?

Done.

https://codereview.appspot.com/80280043/diff/1/state/api/client.go
File state/api/client.go (right):

https://codereview.appspot.com/80280043/diff/1/state/api/client.go#newcode573
state/api/client.go:573:
On 2014/03/26 07:11:17, jameinel wrote:
> We need to also add code to handle the fallback case. What do we do if
you are
> using juju 1.18 to deploy against a 1.16 server that doesn't have the
> ResolveCharm API.

> I'm guessing the answer is to print an error of:
> "You must supply a series in your charm URL for juju < 1.18".

> Either that, or we see that the ResolveCharm isn't available, and just
issue a
> warning with something like "server version is too old to support
ResolveCharm
> (juju <1.18) falling back to default series of "precise""

> To be clear, that compatibility code probably shouldn't be here. But
probably
> could be in the common helper I was outlining earlier.

I decided to warn and fall back on "precise" for <1.18 state servers.
These existing environments will almost certainly already have a
default-series set by their bootstrapping.

I had originally intended to resolve the series directly with the charm
store for that case (since 1.16 hits the charm store directly for other
things), but it seems unlikely that such an environment would benefit
from it.

https://codereview.appspot.com/80280043/

Revision history for this message
Casey Marshall (cmars) wrote :
Revision history for this message
Casey Marshall (cmars) wrote :

The necessary charm store updates to support this change have been
deployed to store.juju.ubuntu.com.

It is safe to land this branch now, waiting for your review.

https://codereview.appspot.com/80280043/

Revision history for this message
William Reade (fwereade) wrote :
Download full text (3.6 KiB)

A few issues -- don't think any of them should be too much hassle to
resolve, the DefaultSeries return value and the API bulk call thing
should both be pretty mechanical.

https://codereview.appspot.com/80280043/diff/20001/cmd/juju/common.go
File cmd/juju/common.go (right):

https://codereview.appspot.com/80280043/diff/20001/cmd/juju/common.go#newcode82
cmd/juju/common.go:82: logger.Warningf(`ResolveCharm not supported by
the API server, falling back to default series "precise".`)
We should in fact be guaranteed a value given a 1.16 state server, but I
heartily endorse this behaviour all the same.

https://codereview.appspot.com/80280043/diff/20001/environs/config/config.go
File environs/config/config.go (left):

https://codereview.appspot.com/80280043/diff/20001/environs/config/config.go#oldcode411
environs/config/config.go:411: func (c *Config) DefaultSeries() string {
In-band errors squick me out... now that it's possible to have no
default-series, please add a ,ok return value. And I guess return false
if it *is* set, but is set to "".

https://codereview.appspot.com/80280043/diff/20001/state/api/client.go
File state/api/client.go (right):

https://codereview.appspot.com/80280043/diff/20001/state/api/client.go#newcode614
state/api/client.go:614: args := params.CharmURL{URL: ref.String()}
mmmmm I don't quite like that... can we make this a separate type?
params.CharmURL now means something different (although I'm surprised, a
little... I could have sworn that charm url fields marshalled to strings
without any hassle at all [0], and so I'd expect us to be using actual
*charm.URLs, and to have to add a new type for a reference anyway.)

[0] yeah, they should do, they have MarshalJSON and UnmarshalJSON.
Wonder why wedon't make use of it...

https://codereview.appspot.com/80280043/diff/20001/state/api/client.go#newcode616
state/api/client.go:616: if err := c.st.Call("Client", "",
"ResolveCharm", args, result); err != nil {
Bulk calls please, they don't have to be exposed in api.Client but it's
reasonable to expect to be able to resolve a few urls in one go, and we
should accommodate that in the interface.

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client.go
File state/apiserver/client/client.go (right):

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client.go#newcode959
state/apiserver/client/client.go:959: ref, series, err :=
charm.ParseReference(args.URL)
yeah, calling it URL is jarring -- new type OK?

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client_test.go
File state/apiserver/client/client_test.go (right):

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client_test.go#newcode1977
state/apiserver/client/client_test.go:1977: store.DefaultSeries =
t.defaultSeries
set this outside loop?

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client_test.go#newcode1979
state/apiserver/client/client_test.go:1979: comment :=
gc.Commentf("defaultSeries:%s charmName:%s", t.defaultSeries,
t.charmName)
for i, test := range tests {
     c.Logf("test %d: %#v", i, test)

...is a reasonably compact way to make the t...

Read more...

Revision history for this message
Casey Marshall (cmars) wrote :
Revision history for this message
Casey Marshall (cmars) wrote :
Download full text (3.6 KiB)

https://codereview.appspot.com/80280043/diff/20001/environs/config/config.go
File environs/config/config.go (left):

https://codereview.appspot.com/80280043/diff/20001/environs/config/config.go#oldcode411
environs/config/config.go:411: func (c *Config) DefaultSeries() string {
On 2014/03/28 10:43:11, fwereade wrote:
> In-band errors squick me out... now that it's possible to have no
> default-series, please add a ,ok return value. And I guess return
false if it
> *is* set, but is set to "".

Done.

https://codereview.appspot.com/80280043/diff/20001/state/api/client.go
File state/api/client.go (right):

https://codereview.appspot.com/80280043/diff/20001/state/api/client.go#newcode614
state/api/client.go:614: args := params.CharmURL{URL: ref.String()}
On 2014/03/28 10:43:11, fwereade wrote:
> mmmmm I don't quite like that... can we make this a separate type?
> params.CharmURL now means something different (although I'm surprised,
a
> little... I could have sworn that charm url fields marshalled to
strings without
> any hassle at all [0], and so I'd expect us to be using actual
*charm.URLs, and
> to have to add a new type for a reference anyway.)

> [0] yeah, they should do, they have MarshalJSON and UnmarshalJSON.
Wonder why
> wedon't make use of it...

Done.

https://codereview.appspot.com/80280043/diff/20001/state/api/client.go#newcode616
state/api/client.go:616: if err := c.st.Call("Client", "",
"ResolveCharm", args, result); err != nil {
On 2014/03/28 10:43:11, fwereade wrote:
> Bulk calls please, they don't have to be exposed in api.Client but
it's
> reasonable to expect to be able to resolve a few urls in one go, and
we should
> accommodate that in the interface.

Done.

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client.go
File state/apiserver/client/client.go (right):

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client.go#newcode959
state/apiserver/client/client.go:959: ref, series, err :=
charm.ParseReference(args.URL)
On 2014/03/28 10:43:11, fwereade wrote:
> yeah, calling it URL is jarring -- new type OK?

Done.

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client_test.go
File state/apiserver/client/client_test.go (right):

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client_test.go#newcode1977
state/apiserver/client/client_test.go:1977: store.DefaultSeries =
t.defaultSeries
On 2014/03/28 10:43:11, fwereade wrote:
> set this outside loop?

Varying the default series in the mock charm store among the test
conditions helps ensure the value isn't being hard-coded anywhere in the
apiserver, and it's useful for simulating a failure to resolve.

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client_test.go#newcode1979
state/apiserver/client/client_test.go:1979: comment :=
gc.Commentf("defaultSeries:%s charmName:%s", t.defaultSeries,
t.charmName)
On 2014/03/28 10:43:11, fwereade wrote:
> for i, test := range tests {
> c.Logf("test %d: %#v", i, test)

> ...is a reasonably compact way to make the test logs somewhat useful.

> I do really like calling it "test", not "t", though :).

Done.

https...

Read more...

Revision history for this message
Casey Marshall (cmars) wrote :
Revision history for this message
William Reade (fwereade) wrote :
Download full text (4.1 KiB)

Nearly there -- a quibble with the location of the PreferredSeries code,
and a bit of work on the API.

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client_test.go
File state/apiserver/client/client_test.go (right):

https://codereview.appspot.com/80280043/diff/20001/state/apiserver/client/client_test.go#newcode1977
state/apiserver/client/client_test.go:1977: store.DefaultSeries =
t.defaultSeries
On 2014/03/31 19:57:07, cmars wrote:
> On 2014/03/28 10:43:11, fwereade wrote:
> > set this outside loop?

> Varying the default series in the mock charm store among the test
conditions
> helps ensure the value isn't being hard-coded anywhere in the
apiserver, and
> it's useful for simulating a failure to resolve.

Ofc, thanks. I think my eye slipped over the `t.` -- but it's much
harder to miss the `test.`. Thanks :).

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/addmachine.go
File cmd/juju/addmachine.go (right):

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/addmachine.go#newcode129
cmd/juju/addmachine.go:129: series = conf.PreferredSeries()
mm, I rather liked the PreferredSeries(conf) spelling, especially if it
were using an interface with just the DefaultSeries method. This doesn't
feel fundamental to a config -- does that seem sane?

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/common.go
File cmd/juju/common.go (right):

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/common.go#newcode82
cmd/juju/common.go:82: logger.Warningf(`ResolveCharm not supported by
the API server, falling back to default series "precise".`)
PreferredSeries should surely be guaranteed to return non-""?

https://codereview.appspot.com/80280043/diff/60001/environs/config/config.go
File environs/config/config.go (right):

https://codereview.appspot.com/80280043/diff/60001/environs/config/config.go#newcode230
environs/config/config.go:230: return DefaultSeries
How do we determine the value of this? I'm feeling like it really ought
to actually *be* the latest LTS, rather than just some global var set by
who-knows-who.

https://codereview.appspot.com/80280043/diff/60001/state/api/params/params.go
File state/api/params/params.go (right):

https://codereview.appspot.com/80280043/diff/60001/state/api/params/params.go#newcode338
state/api/params/params.go:338: URLs []charm.URL
I think we need an error per-result here, don't we?

https://codereview.appspot.com/80280043/diff/60001/state/apiserver/client/client.go
File state/apiserver/client/client.go (right):

https://codereview.appspot.com/80280043/diff/60001/state/apiserver/client/client.go#newcode963
state/apiserver/client/client.go:963: return
params.ResolveCharmResults{}, err
sorry for the hassle, but we should always return one result per
request, and that result should contain either the answer or the error.

Client is a dog's dinner in this regard, and can only gradually and
incrementally improve, but the internal APIs are generally written as I
want them, and should be used as a model. The core idea is that bulk
APIs can be used for single calls, but single APIs can't be used in
bulk; as humans we are bad at predicting the future, and I'd r...

Read more...

Revision history for this message
Casey Marshall (cmars) wrote :

Thanks for reviewing. Couple of questions:

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/addmachine.go
File cmd/juju/addmachine.go (right):

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/addmachine.go#newcode129
cmd/juju/addmachine.go:129: series = conf.PreferredSeries()
On 2014/04/01 07:10:07, fwereade wrote:
> mm, I rather liked the PreferredSeries(conf) spelling, especially if
it were
> using an interface with just the DefaultSeries method. This doesn't
feel
> fundamental to a config -- does that seem sane?

Will do. Should this live in environs/config or a different package?

https://codereview.appspot.com/80280043/diff/60001/environs/config/config.go
File environs/config/config.go (right):

https://codereview.appspot.com/80280043/diff/60001/environs/config/config.go#newcode230
environs/config/config.go:230: return DefaultSeries
On 2014/04/01 07:10:07, fwereade wrote:
> How do we determine the value of this? I'm feeling like it really
ought to
> actually *be* the latest LTS, rather than just some global var set by
> who-knows-who.

I can try to get this from 'distro-info --lts'. If that fails to exec,
I'll use a hard-coded fallback (named as such). What do you think?

https://codereview.appspot.com/80280043/

Revision history for this message
Casey Marshall (cmars) wrote :
Revision history for this message
Casey Marshall (cmars) wrote :
Download full text (4.7 KiB)

I've addressed most of the feedback, but there is a problem lurking.
When config.LatestLtsSeries() == "trusty", some of the tests are failing
due to tools availability. I was able to resolve some of them, but not
all. Could really use some advice.

To reproduce the failures, this will simulate a post-trusty release
scenario in the proposed branch:

go test -ldflags "-X
launchpad.net/juju-core/environs/config.latestLtsSeries trusty" ./...

These are the failures:

FAIL: bootstrap_test.go:506:
BootstrapSuite.TestAutoUploadAfterFailedSync
FAIL: bootstrap_test.go:555:
BootstrapSuite.TestMissingToolsUploadFailedError
FAIL: upgradejuju_test.go:301: UpgradeJujuSuite.TestUpgradeJuju
FAIL: imagemetadata_test.go:141:
ImageMetadataSuite.TestImageMetadataFilesDefaultSeries

Everything passes when the latest LTS is precise.

Please advise,
Casey

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/addmachine.go
File cmd/juju/addmachine.go (right):

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/addmachine.go#newcode129
cmd/juju/addmachine.go:129: series = conf.PreferredSeries()
On 2014/04/01 07:10:07, fwereade wrote:
> mm, I rather liked the PreferredSeries(conf) spelling, especially if
it were
> using an interface with just the DefaultSeries method. This doesn't
feel
> fundamental to a config -- does that seem sane?

Done.

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/common.go
File cmd/juju/common.go (right):

https://codereview.appspot.com/80280043/diff/60001/cmd/juju/common.go#newcode82
cmd/juju/common.go:82: logger.Warningf(`ResolveCharm not supported by
the API server, falling back to default series "precise".`)
On 2014/04/01 07:10:07, fwereade wrote:
> PreferredSeries should surely be guaranteed to return non-""?

Done.

https://codereview.appspot.com/80280043/diff/60001/environs/config/config.go
File environs/config/config.go (right):

https://codereview.appspot.com/80280043/diff/60001/environs/config/config.go#newcode230
environs/config/config.go:230: return DefaultSeries
On 2014/04/01 15:05:12, cmars wrote:
> On 2014/04/01 07:10:07, fwereade wrote:
> > How do we determine the value of this? I'm feeling like it really
ought to
> > actually *be* the latest LTS, rather than just some global var set
by
> > who-knows-who.

> I can try to get this from 'distro-info --lts'. If that fails to exec,
I'll use
> a hard-coded fallback (named as such). What do you think?

Done.

https://codereview.appspot.com/80280043/diff/60001/state/api/params/params.go
File state/api/params/params.go (right):

https://codereview.appspot.com/80280043/diff/60001/state/api/params/params.go#newcode338
state/api/params/params.go:338: URLs []charm.URL
On 2014/04/01 07:10:07, fwereade wrote:
> I think we need an error per-result here, don't we?

Done.

https://codereview.appspot.com/80280043/diff/60001/state/apiserver/client/client.go
File state/apiserver/client/client.go (right):

https://codereview.appspot.com/80280043/diff/60001/state/apiserver/client/client.go#newcode963
state/apiserver/client/client.go:963: return
params.ResolveCharmResults{}, err
On 2014/04/01 07:10:07, fwereade wrote:
> sorry for the hassle, but we should always return ...

Read more...

Revision history for this message
Casey Marshall (cmars) wrote :
Revision history for this message
Casey Marshall (cmars) wrote :

Tests affected by the LTS change wrt uploading tools are now all passing
when the latest LTS series is "trusty". To run the tests as if trusty
were already released, run with:

go test -ldflags "-X
launchpad.net/juju-core/environs/config.latestLtsSeries trusty"

(This var is normally initialized when not set, from `distro-info
--lts`)

Added wallyworld. I could use a review from a tools distribution
perspective, as this is an area I am only superficially familiar with.
They were affected by the LTS series change so I've tried to make fixes
where test cases and setup had "precise" hardcoded, did not anticipate
having to upload tools other than a DefaultSeries, etc.

Thanks!
-Casey

https://codereview.appspot.com/80280043/

Revision history for this message
Casey Marshall (cmars) wrote :
Revision history for this message
Ian Booth (wallyworld) wrote :

I think the tools changes are ok. What I like is that when we start
running the tests on a trusty host, the test set up will, where
relevant, continue to correctly use a series matching the host of which
the tests are running, hence replicating the current test behaviour.
Having said that, I still fear our test coverage of the various
permutations in this area is not complete, but that's outside the scope
of this branch. There's still the possibility of perhaps a subtle bug
being introduced with regard to series handling, as has been seen before
when this sort of this was tweaked, but it's hard to know for sure.

https://codereview.appspot.com/80280043/

Revision history for this message
William Reade (fwereade) wrote :
Download full text (4.5 KiB)

Looks good, would appreciate at least a short chat before landing -- in
particular, I'm not quite clear on the forces that lead us to use
FakeDefaultSeries sometimes, and LatestLts at others.

https://codereview.appspot.com/80280043/diff/120001/cmd/juju/bootstrap_test.go
File cmd/juju/bootstrap_test.go (right):

https://codereview.appspot.com/80280043/diff/120001/cmd/juju/bootstrap_test.go#newcode123
cmd/juju/bootstrap_test.go:123: useVersion :=
strings.Replace(test.version, "%LTS%", config.LatestLtsSeries(), 1)
not quite sure that config is the right package for these -- but I'm not
sure I can think of a better one. Unless you want to create a tiny,
hyper-focused, series package somewhere? I'm sure it'll grow excitingly
as we deal with other OSs...

https://codereview.appspot.com/80280043/diff/120001/cmd/juju/upgradecharm.go
File cmd/juju/upgradecharm.go (right):

https://codereview.appspot.com/80280043/diff/120001/cmd/juju/upgradecharm.go#newcode209
cmd/juju/upgradecharm.go:209: repo, err :=
charm.InferRepository(newURL.Reference, c.RepoPath)
We still need ctx.AbsPath, I think. Would you change the relevant test
to use a path relative to the working dir so we check this properly
please?

https://codereview.appspot.com/80280043/diff/120001/environs/config/config.go
File environs/config/config.go (right):

https://codereview.appspot.com/80280043/diff/120001/environs/config/config.go#newcode106
environs/config/config.go:106:
yeah, this feels a bit tacked-on here. Let's give it its own package if
we don't think of anywhere better.

https://codereview.appspot.com/80280043/diff/120001/environs/config/config.go#newcode456
environs/config/config.go:456: series := s.(string)
this is guaranteed to be a string if it's got this far, right?

https://codereview.appspot.com/80280043/diff/120001/provider/common/bootstrap.go
File provider/common/bootstrap.go (right):

https://codereview.appspot.com/80280043/diff/120001/provider/common/bootstrap.go#newcode45
provider/common/bootstrap.go:45: selectedTools, err :=
EnsureBootstrapTools(ctx, env, config.PreferredSeries(env.Config()),
cons.Arch)
quibble quibble, we should probably allow bootstrap on any series we can
find tools for. Out of scope today, but maybe worth a bug?

https://codereview.appspot.com/80280043/diff/120001/provider/ec2/ec2.go
File provider/ec2/ec2.go (right):

https://codereview.appspot.com/80280043/diff/120001/provider/ec2/ec2.go#newcode367
provider/ec2/ec2.go:367: Series:
config.PreferredSeries(e.ecfg()),
this seems a bit weird, but so did the original. let it stand.

https://codereview.appspot.com/80280043/diff/120001/provider/ec2/live_test.go
File provider/ec2/live_test.go (right):

https://codereview.appspot.com/80280043/diff/120001/provider/ec2/live_test.go#newcode104
provider/ec2/live_test.go:104: Series: coretesting.FakeDefaultSeries,
wondering if this should be LatestLts? I presume you have a good reason
it isn't, but it's not immediately clear ;)

https://codereview.appspot.com/80280043/diff/120001/state/api/client.go
File state/api/client.go (right):

https://codereview.appspot.com/80280043/diff/120001/state/api/client.go#newcode613
state/api/client.go:613: func (c *Client) Resolv...

Read more...

Revision history for this message
Casey Marshall (cmars) wrote :
Download full text (5.1 KiB)

PTAL

https://codereview.appspot.com/80280043/diff/120001/cmd/juju/bootstrap_test.go
File cmd/juju/bootstrap_test.go (right):

https://codereview.appspot.com/80280043/diff/120001/cmd/juju/bootstrap_test.go#newcode123
cmd/juju/bootstrap_test.go:123: useVersion :=
strings.Replace(test.version, "%LTS%", config.LatestLtsSeries(), 1)
On 2014/04/03 13:34:15, fwereade wrote:
> not quite sure that config is the right package for these -- but I'm
not sure I
> can think of a better one. Unless you want to create a tiny,
hyper-focused,
> series package somewhere? I'm sure it'll grow excitingly as we deal
with other
> OSs...

LP: #1301999

https://codereview.appspot.com/80280043/diff/120001/cmd/juju/upgradecharm.go
File cmd/juju/upgradecharm.go (right):

https://codereview.appspot.com/80280043/diff/120001/cmd/juju/upgradecharm.go#newcode209
cmd/juju/upgradecharm.go:209: repo, err :=
charm.InferRepository(newURL.Reference, c.RepoPath)
On 2014/04/03 13:34:15, fwereade wrote:
> We still need ctx.AbsPath, I think. Would you change the relevant test
to use a
> path relative to the working dir so we check this properly please?

Ah, must have botched this in a prior merge. Restored it.

https://codereview.appspot.com/80280043/diff/120001/environs/config/config.go
File environs/config/config.go (right):

https://codereview.appspot.com/80280043/diff/120001/environs/config/config.go#newcode106
environs/config/config.go:106:
On 2014/04/03 13:34:15, fwereade wrote:
> yeah, this feels a bit tacked-on here. Let's give it its own package
if we don't
> think of anywhere better.

LP: #1301999

https://codereview.appspot.com/80280043/diff/120001/environs/config/config.go#newcode456
environs/config/config.go:456: series := s.(string)
On 2014/04/03 13:34:15, fwereade wrote:
> this is guaranteed to be a string if it's got this far, right?

Non-string values that make their way in here will be ignored with a
warning.

https://codereview.appspot.com/80280043/diff/120001/provider/common/bootstrap.go
File provider/common/bootstrap.go (right):

https://codereview.appspot.com/80280043/diff/120001/provider/common/bootstrap.go#newcode45
provider/common/bootstrap.go:45: selectedTools, err :=
EnsureBootstrapTools(ctx, env, config.PreferredSeries(env.Config()),
cons.Arch)
On 2014/04/03 13:34:15, fwereade wrote:
> quibble quibble, we should probably allow bootstrap on any series we
can find
> tools for. Out of scope today, but maybe worth a bug?

LP: #1302005

https://codereview.appspot.com/80280043/diff/120001/provider/ec2/live_test.go
File provider/ec2/live_test.go (right):

https://codereview.appspot.com/80280043/diff/120001/provider/ec2/live_test.go#newcode104
provider/ec2/live_test.go:104: Series: coretesting.FakeDefaultSeries,
On 2014/04/03 13:34:15, fwereade wrote:
> wondering if this should be LatestLts? I presume you have a good
reason it
> isn't, but it's not immediately clear ;)

It's to separate what is used for default-series: in tests from the
preferred series selection. This allows us to test scenarios against
different configured series vs. what will be preferred.

Most of what's affected atm is the tools setup & bootstrapping for some
tests. There are still some areas ...

Read more...

Revision history for this message
William Reade (fwereade) wrote :

LGTM with one trivial. Thanks for this, it's a monster diff -- let's
throw it at CI and see what we've missed ;).

https://codereview.appspot.com/80280043/diff/140001/charm/url_test.go
File charm/url_test.go (right):

https://codereview.appspot.com/80280043/diff/140001/charm/url_test.go#newcode292
charm/url_test.go:292: c.Check(parsed, gc.DeepEquals, ref)
add one for unmarshalling gibberish, just for safety's sake

https://codereview.appspot.com/80280043/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charm/charm.go'
--- charm/charm.go 2014-03-17 18:46:17 +0000
+++ charm/charm.go 2014-04-03 17:37:27 +0000
@@ -30,10 +30,10 @@
30 return ReadBundle(path)30 return ReadBundle(path)
31}31}
3232
33// InferRepository returns a charm repository inferred from33// InferRepository returns a charm repository inferred from the provided charm
34// the provided URL. Local URLs will use the provided path.34// reference. Local references will use the provided path.
35func InferRepository(curl *URL, localRepoPath string) (repo Repository, err error) {35func InferRepository(ref Reference, localRepoPath string) (repo Repository, err error) {
36 switch curl.Schema {36 switch ref.Schema {
37 case "cs":37 case "cs":
38 repo = Store38 repo = Store
39 case "local":39 case "local":
@@ -42,7 +42,7 @@
42 }42 }
43 repo = &LocalRepository{Path: localRepoPath}43 repo = &LocalRepository{Path: localRepoPath}
44 default:44 default:
45 return nil, fmt.Errorf("unknown schema for charm URL %q", curl)45 return nil, fmt.Errorf("unknown schema for charm reference %q", ref)
46 }46 }
47 return47 return
48}48}
4949
=== modified file 'charm/charm_test.go'
--- charm/charm_test.go 2014-03-18 05:08:25 +0000
+++ charm/charm_test.go 2014-04-03 17:37:27 +0000
@@ -48,7 +48,7 @@
48 c.Logf("test %d", i)48 c.Logf("test %d", i)
49 curl, err := charm.InferURL(t.url, "precise")49 curl, err := charm.InferURL(t.url, "precise")
50 c.Assert(err, gc.IsNil)50 c.Assert(err, gc.IsNil)
51 repo, err := charm.InferRepository(curl, "/some/path")51 repo, err := charm.InferRepository(curl.Reference, "/some/path")
52 c.Assert(err, gc.IsNil)52 c.Assert(err, gc.IsNil)
53 switch repo := repo.(type) {53 switch repo := repo.(type) {
54 case *charm.LocalRepository:54 case *charm.LocalRepository:
@@ -59,11 +59,11 @@
59 }59 }
60 curl, err := charm.InferURL("local:whatever", "precise")60 curl, err := charm.InferURL("local:whatever", "precise")
61 c.Assert(err, gc.IsNil)61 c.Assert(err, gc.IsNil)
62 _, err = charm.InferRepository(curl, "")62 _, err = charm.InferRepository(curl.Reference, "")
63 c.Assert(err, gc.ErrorMatches, "path to local repository not specified")63 c.Assert(err, gc.ErrorMatches, "path to local repository not specified")
64 curl.Schema = "foo"64 curl.Schema = "foo"
65 _, err = charm.InferRepository(curl, "")65 _, err = charm.InferRepository(curl.Reference, "")
66 c.Assert(err, gc.ErrorMatches, "unknown schema for charm URL.*")66 c.Assert(err, gc.ErrorMatches, "unknown schema for charm reference.*")
67}67}
6868
69func checkDummy(c *gc.C, f charm.Charm, path string) {69func checkDummy(c *gc.C, f charm.Charm, path string) {
7070
=== modified file 'charm/url.go'
--- charm/url.go 2014-03-24 15:35:41 +0000
+++ charm/url.go 2014-04-03 17:37:27 +0000
@@ -284,8 +284,6 @@
284 return nil284 return nil
285}285}
286286
287var jsonNull = []byte("null")
288
289func (u *URL) MarshalJSON() ([]byte, error) {287func (u *URL) MarshalJSON() ([]byte, error) {
290 if u == nil {288 if u == nil {
291 panic("cannot marshal nil *charm.URL")289 panic("cannot marshal nil *charm.URL")
@@ -306,6 +304,23 @@
306 return nil304 return nil
307}305}
308306
307func (r *Reference) MarshalJSON() ([]byte, error) {
308 return json.Marshal(r.String())
309}
310
311func (r *Reference) UnmarshalJSON(b []byte) error {
312 var s string
313 if err := json.Unmarshal(b, &s); err != nil {
314 return err
315 }
316 ref, _, err := ParseReference(s)
317 if err != nil {
318 return err
319 }
320 *r = ref
321 return nil
322}
323
309// Quote translates a charm url string into one which can be safely used324// Quote translates a charm url string into one which can be safely used
310// in a file path. ASCII letters, ASCII digits, dot and dash stay the325// in a file path. ASCII letters, ASCII digits, dot and dash stay the
311// same; other characters are translated to their hex representation326// same; other characters are translated to their hex representation
312327
=== modified file 'charm/url_test.go'
--- charm/url_test.go 2014-03-24 15:35:41 +0000
+++ charm/url_test.go 2014-04-03 17:37:27 +0000
@@ -258,7 +258,7 @@
258 Unmarshal: json.Unmarshal,258 Unmarshal: json.Unmarshal,
259}}259}}
260260
261func (s *URLSuite) TestCodecs(c *gc.C) {261func (s *URLSuite) TestURLCodecs(c *gc.C) {
262 for i, codec := range codecs {262 for i, codec := range codecs {
263 c.Logf("codec %d", i)263 c.Logf("codec %d", i)
264 type doc struct {264 type doc struct {
@@ -279,6 +279,25 @@
279 }279 }
280}280}
281281
282func (s *URLSuite) TestReferenceJSON(c *gc.C) {
283 ref, _, err := charm.ParseReference("cs:series/name")
284 c.Assert(err, gc.IsNil)
285 data, err := json.Marshal(&ref)
286 c.Assert(err, gc.IsNil)
287 c.Check(string(data), gc.Equals, `"cs:name"`)
288
289 var parsed charm.Reference
290 err = json.Unmarshal(data, &parsed)
291 c.Assert(err, gc.IsNil)
292 c.Check(parsed, gc.DeepEquals, ref)
293
294 // unmarshalling json gibberish and invalid charm reference strings
295 for _, value := range []string{":{", `"cs:{}+<"`, `"cs:~_~/f00^^&^/baaaar$%-?"`} {
296 err = json.Unmarshal([]byte(value), &parsed)
297 c.Check(err, gc.NotNil)
298 }
299}
300
282type QuoteSuite struct{}301type QuoteSuite struct{}
283302
284var _ = gc.Suite(&QuoteSuite{})303var _ = gc.Suite(&QuoteSuite{})
285304
=== modified file 'cmd/juju/addmachine.go'
--- cmd/juju/addmachine.go 2014-04-01 04:53:43 +0000
+++ cmd/juju/addmachine.go 2014-04-03 17:37:27 +0000
@@ -12,6 +12,7 @@
12 "launchpad.net/juju-core/cmd"12 "launchpad.net/juju-core/cmd"
13 "launchpad.net/juju-core/cmd/envcmd"13 "launchpad.net/juju-core/cmd/envcmd"
14 "launchpad.net/juju-core/constraints"14 "launchpad.net/juju-core/constraints"
15 "launchpad.net/juju-core/environs/config"
15 "launchpad.net/juju-core/environs/manual"16 "launchpad.net/juju-core/environs/manual"
16 "launchpad.net/juju-core/instance"17 "launchpad.net/juju-core/instance"
17 "launchpad.net/juju-core/juju"18 "launchpad.net/juju-core/juju"
@@ -131,7 +132,7 @@
131 if err != nil {132 if err != nil {
132 return "", err133 return "", err
133 }134 }
134 series = conf.DefaultSeries()135 series = config.PreferredSeries(conf)
135 }136 }
136 template := state.MachineTemplate{137 template := state.MachineTemplate{
137 Series: series,138 Series: series,
138139
=== modified file 'cmd/juju/bootstrap_test.go'
--- cmd/juju/bootstrap_test.go 2014-04-01 03:11:16 +0000
+++ cmd/juju/bootstrap_test.go 2014-04-03 17:37:27 +0000
@@ -15,6 +15,7 @@
15 "launchpad.net/juju-core/cmd"15 "launchpad.net/juju-core/cmd"
16 "launchpad.net/juju-core/constraints"16 "launchpad.net/juju-core/constraints"
17 "launchpad.net/juju-core/environs"17 "launchpad.net/juju-core/environs"
18 "launchpad.net/juju-core/environs/config"
18 "launchpad.net/juju-core/environs/configstore"19 "launchpad.net/juju-core/environs/configstore"
19 "launchpad.net/juju-core/environs/filestorage"20 "launchpad.net/juju-core/environs/filestorage"
20 "launchpad.net/juju-core/environs/imagemetadata"21 "launchpad.net/juju-core/environs/imagemetadata"
@@ -119,7 +120,8 @@
119func (s *BootstrapSuite) runAllowRetriesTest(c *gc.C, test bootstrapRetryTest) {120func (s *BootstrapSuite) runAllowRetriesTest(c *gc.C, test bootstrapRetryTest) {
120 toolsVersions := envtesting.VAll121 toolsVersions := envtesting.VAll
121 if test.version != "" {122 if test.version != "" {
122 testVersion := version.MustParseBinary(test.version)123 useVersion := strings.Replace(test.version, "%LTS%", config.LatestLtsSeries(), 1)
124 testVersion := version.MustParseBinary(useVersion)
123 s.PatchValue(&version.Current, testVersion)125 s.PatchValue(&version.Current, testVersion)
124 if test.addVersionToSource {126 if test.addVersionToSource {
125 toolsVersions = append([]version.Binary{}, toolsVersions...)127 toolsVersions = append([]version.Binary{}, toolsVersions...)
@@ -201,8 +203,9 @@
201 defer fake.Restore()203 defer fake.Restore()
202204
203 if test.version != "" {205 if test.version != "" {
206 useVersion := strings.Replace(test.version, "%LTS%", config.LatestLtsSeries(), 1)
204 origVersion := version.Current207 origVersion := version.Current
205 version.Current = version.MustParseBinary(test.version)208 version.Current = version.MustParseBinary(useVersion)
206 defer func() { version.Current = origVersion }()209 defer func() { version.Current = origVersion }()
207 }210 }
208211
@@ -217,7 +220,7 @@
217 uploadCount := len(test.uploads)220 uploadCount := len(test.uploads)
218 if uploadCount == 0 {221 if uploadCount == 0 {
219 usefulVersion := version.Current222 usefulVersion := version.Current
220 usefulVersion.Series = env.Config().DefaultSeries()223 usefulVersion.Series = config.PreferredSeries(env.Config())
221 envtesting.AssertUploadFakeToolsVersions(c, env.Storage(), usefulVersion)224 envtesting.AssertUploadFakeToolsVersions(c, env.Storage(), usefulVersion)
222 }225 }
223226
@@ -245,6 +248,7 @@
245 urls := list.URLs()248 urls := list.URLs()
246 c.Check(urls, gc.HasLen, len(test.uploads))249 c.Check(urls, gc.HasLen, len(test.uploads))
247 for _, v := range test.uploads {250 for _, v := range test.uploads {
251 v := strings.Replace(v, "%LTS%", config.LatestLtsSeries(), 1)
248 c.Logf("seeking: " + v)252 c.Logf("seeking: " + v)
249 vers := version.MustParseBinary(v)253 vers := version.MustParseBinary(v)
250 _, found := urls[vers]254 _, found := urls[vers]
@@ -299,10 +303,9 @@
299 args: []string{"--series", "fine"},303 args: []string{"--series", "fine"},
300 err: `--series requires --upload-tools`,304 err: `--series requires --upload-tools`,
301}, {305}, {
302 info: "bad environment",306 info: "bad environment",
303 version: "1.2.3-precise-amd64",307 args: []string{"-e", "brokenenv"},
304 args: []string{"-e", "brokenenv"},308 err: `dummy.Bootstrap is broken`,
305 err: `dummy.Bootstrap is broken`,
306}, {309}, {
307 info: "constraints",310 info: "constraints",
308 args: []string{"--constraints", "mem=4G cpu-cores=4"},311 args: []string{"--constraints", "mem=4G cpu-cores=4"},
@@ -312,9 +315,9 @@
312 version: "1.2.3-saucy-amd64",315 version: "1.2.3-saucy-amd64",
313 args: []string{"--upload-tools"},316 args: []string{"--upload-tools"},
314 uploads: []string{317 uploads: []string{
315 "1.2.3.1-saucy-amd64", // from version.Current318 "1.2.3.1-saucy-amd64", // from version.Current
316 "1.2.3.1-raring-amd64", // from env.Config().DefaultSeries()319 "1.2.3.1-raring-amd64", // from env.Config().DefaultSeries()
317 "1.2.3.1-precise-amd64", // from environs/config.DefaultSeries320 "1.2.3.1-%LTS%-amd64", // from environs/config.DefaultSeries
318 },321 },
319}, {322}, {
320 info: "--upload-tools uses arch from constraint if it matches current version",323 info: "--upload-tools uses arch from constraint if it matches current version",
@@ -322,18 +325,18 @@
322 hostArch: "ppc64",325 hostArch: "ppc64",
323 args: []string{"--upload-tools", "--constraints", "arch=ppc64"},326 args: []string{"--upload-tools", "--constraints", "arch=ppc64"},
324 uploads: []string{327 uploads: []string{
325 "1.3.3.1-saucy-ppc64", // from version.Current328 "1.3.3.1-saucy-ppc64", // from version.Current
326 "1.3.3.1-raring-ppc64", // from env.Config().DefaultSeries()329 "1.3.3.1-raring-ppc64", // from env.Config().DefaultSeries()
327 "1.3.3.1-precise-ppc64", // from environs/config.DefaultSeries330 "1.3.3.1-%LTS%-ppc64", // from environs/config.DefaultSeries
328 },331 },
329 constraints: constraints.MustParse("arch=ppc64"),332 constraints: constraints.MustParse("arch=ppc64"),
330}, {333}, {
331 info: "--upload-tools only uploads each file once",334 info: "--upload-tools only uploads each file once",
332 version: "1.2.3-precise-amd64",335 version: "1.2.3-%LTS%-amd64",
333 args: []string{"--upload-tools"},336 args: []string{"--upload-tools"},
334 uploads: []string{337 uploads: []string{
335 "1.2.3.1-raring-amd64",338 "1.2.3.1-raring-amd64",
336 "1.2.3.1-precise-amd64",339 "1.2.3.1-%LTS%-amd64",
337 },340 },
338}, {341}, {
339 info: "--upload-tools rejects invalid series",342 info: "--upload-tools rejects invalid series",
@@ -357,7 +360,7 @@
357 args: []string{"--upload-tools"},360 args: []string{"--upload-tools"},
358 uploads: []string{361 uploads: []string{
359 "1.2.3.5-raring-amd64",362 "1.2.3.5-raring-amd64",
360 "1.2.3.5-precise-amd64",363 "1.2.3.5-%LTS%-amd64",
361 },364 },
362}}365}}
363366
@@ -365,7 +368,7 @@
365 env, fake := makeEmptyFakeHome(c)368 env, fake := makeEmptyFakeHome(c)
366 defer fake.Restore()369 defer fake.Restore()
367 defaultSeriesVersion := version.Current370 defaultSeriesVersion := version.Current
368 defaultSeriesVersion.Series = env.Config().DefaultSeries()371 defaultSeriesVersion.Series = config.PreferredSeries(env.Config())
369372
370 ctx := coretesting.Context(c)373 ctx := coretesting.Context(c)
371 code := cmd.Main(&BootstrapCommand{}, ctx, nil)374 code := cmd.Main(&BootstrapCommand{}, ctx, nil)
@@ -383,7 +386,7 @@
383 env, fake := makeEmptyFakeHome(c)386 env, fake := makeEmptyFakeHome(c)
384 defer fake.Restore()387 defer fake.Restore()
385 defaultSeriesVersion := version.Current388 defaultSeriesVersion := version.Current
386 defaultSeriesVersion.Series = env.Config().DefaultSeries()389 defaultSeriesVersion.Series = config.PreferredSeries(env.Config())
387390
388 store, err := configstore.Default()391 store, err := configstore.Default()
389 c.Assert(err, gc.IsNil)392 c.Assert(err, gc.IsNil)
@@ -515,7 +518,13 @@
515 c.Assert(err, gc.IsNil)518 c.Assert(err, gc.IsNil)
516 c.Logf("found: " + list.String())519 c.Logf("found: " + list.String())
517 urls := list.URLs()520 urls := list.URLs()
518 c.Assert(urls, gc.HasLen, 2)521 expectedUrlCount := 2
522
523 // There will be distinct tools for each of these if they are different
524 if config.LatestLtsSeries() != coretesting.FakeDefaultSeries {
525 expectedUrlCount++
526 }
527 c.Assert(urls, gc.HasLen, expectedUrlCount)
519 expectedVers := []version.Binary{528 expectedVers := []version.Binary{
520 version.MustParseBinary(fmt.Sprintf("1.7.3.1-%s-%s", otherSeries, version.Current.Arch)),529 version.MustParseBinary(fmt.Sprintf("1.7.3.1-%s-%s", otherSeries, version.Current.Arch)),
521 version.MustParseBinary(fmt.Sprintf("1.7.3.1-%s-%s", version.Current.Series, version.Current.Arch)),530 version.MustParseBinary(fmt.Sprintf("1.7.3.1-%s-%s", version.Current.Series, version.Current.Arch)),
@@ -556,7 +565,11 @@
556 code := cmd.Main(&BootstrapCommand{}, context, nil)565 code := cmd.Main(&BootstrapCommand{}, context, nil)
557 c.Assert(code, gc.Equals, 1)566 c.Assert(code, gc.Equals, 1)
558 errText := context.Stderr.(*bytes.Buffer).String()567 errText := context.Stderr.(*bytes.Buffer).String()
559 expectedErrText := "uploading tools for series \\[precise raring\\]\n"568 expectedErrText := "uploading tools for series \\[precise "
569 if config.LatestLtsSeries() != coretesting.FakeDefaultSeries {
570 expectedErrText += config.LatestLtsSeries() + " "
571 }
572 expectedErrText += "raring\\]\n"
560 expectedErrText += "error: cannot upload bootstrap tools: an error\n"573 expectedErrText += "error: cannot upload bootstrap tools: an error\n"
561 c.Assert(errText, gc.Matches, expectedErrText)574 c.Assert(errText, gc.Matches, expectedErrText)
562}575}
563576
=== modified file 'cmd/juju/common.go'
--- cmd/juju/common.go 2014-03-26 04:36:17 +0000
+++ cmd/juju/common.go 2014-04-03 17:37:27 +0000
@@ -4,10 +4,13 @@
4package main4package main
55
6import (6import (
7 "launchpad.net/juju-core/charm"
7 "launchpad.net/juju-core/cmd"8 "launchpad.net/juju-core/cmd"
8 "launchpad.net/juju-core/environs"9 "launchpad.net/juju-core/environs"
10 "launchpad.net/juju-core/environs/config"
9 "launchpad.net/juju-core/environs/configstore"11 "launchpad.net/juju-core/environs/configstore"
10 "launchpad.net/juju-core/errors"12 "launchpad.net/juju-core/errors"
13 "launchpad.net/juju-core/state/api"
11)14)
1215
13// destroyPreparedEnviron destroys the environment and logs an error if it fails.16// destroyPreparedEnviron destroys the environment and logs an error if it fails.
@@ -45,3 +48,39 @@
45 }48 }
46 return environ, cleanup, nil49 return environ, cleanup, nil
47}50}
51
52// resolveCharmURL returns a resolved charm URL, given a charm location string.
53// If the series is not resolved, the environment default-series is used, or if
54// not set, the series is resolved with the state server.
55func resolveCharmURL(url string, client *api.Client, conf *config.Config) (*charm.URL, error) {
56 ref, series, err := charm.ParseReference(url)
57 if err != nil {
58 return nil, err
59 }
60 // If series is not set, use configured default series
61 if series == "" {
62 if defaultSeries, ok := conf.DefaultSeries(); ok {
63 series = defaultSeries
64 }
65 }
66 // Otherwise, look up the best supported series for this charm
67 if series == "" {
68 return client.ResolveCharm(ref)
69 }
70 return &charm.URL{Reference: ref, Series: series}, nil
71}
72
73// resolveCharmURL1dot16 returns a resolved charm URL for older state servers
74// that do not support ResolveCharm. The default series "precise" is
75// appropriate for these environments.
76func resolveCharmURL1dot16(url string, conf *config.Config) (*charm.URL, error) {
77 ref, series, err := charm.ParseReference(url)
78 if err != nil {
79 return nil, err
80 }
81
82 if series == "" {
83 series = config.PreferredSeries(conf)
84 }
85 return &charm.URL{Reference: ref, Series: series}, err
86}
4887
=== modified file 'cmd/juju/deploy.go'
--- cmd/juju/deploy.go 2014-04-01 14:55:36 +0000
+++ cmd/juju/deploy.go 2014-04-03 17:37:27 +0000
@@ -154,11 +154,13 @@
154 if err != nil {154 if err != nil {
155 return err155 return err
156 }156 }
157 curl, err := charm.InferURL(c.CharmName, conf.DefaultSeries())157
158 curl, err := resolveCharmURL(c.CharmName, client, conf)
158 if err != nil {159 if err != nil {
159 return err160 return err
160 }161 }
161 repo, err := charm.InferRepository(curl, ctx.AbsPath(c.RepoPath))162
163 repo, err := charm.InferRepository(curl.Reference, ctx.AbsPath(c.RepoPath))
162 if err != nil {164 if err != nil {
163 return err165 return err
164 }166 }
@@ -260,15 +262,16 @@
260 if err != nil {262 if err != nil {
261 return err263 return err
262 }264 }
263 curl, err := charm.InferURL(c.CharmName, conf.DefaultSeries())265
264 if err != nil {266 curl, err := resolveCharmURL1dot16(c.CharmName, conf)
265 return err267 if err != nil {
266 }268 return err
267 repo, err := charm.InferRepository(curl, ctx.AbsPath(c.RepoPath))269 }
268 if err != nil {270
269 return err271 repo, err := charm.InferRepository(curl.Reference, c.RepoPath)
270 }272 if err != nil {
271273 return err
274 }
272 repo = config.SpecializeCharmRepo(repo, conf)275 repo = config.SpecializeCharmRepo(repo, conf)
273276
274 // TODO(fwereade) it's annoying to roundtrip the bytes through the client277 // TODO(fwereade) it's annoying to roundtrip the bytes through the client
275278
=== modified file 'cmd/juju/environment_test.go'
--- cmd/juju/environment_test.go 2014-03-26 05:44:41 +0000
+++ cmd/juju/environment_test.go 2014-04-03 17:37:27 +0000
@@ -124,12 +124,22 @@
124}124}
125125
126func (s *SetEnvironmentSuite) TestChangeDefaultSeries(c *gc.C) {126func (s *SetEnvironmentSuite) TestChangeDefaultSeries(c *gc.C) {
127 _, err := testing.RunCommand(c, &SetEnvironmentCommand{}, []string{"default-series=raring"})127 // default-series not set
128 c.Assert(err, gc.IsNil)
129
130 stateConfig, err := s.State.EnvironConfig()128 stateConfig, err := s.State.EnvironConfig()
131 c.Assert(err, gc.IsNil)129 c.Assert(err, gc.IsNil)
132 c.Assert(stateConfig.DefaultSeries(), gc.Equals, "raring")130 series, ok := stateConfig.DefaultSeries()
131 c.Assert(ok, gc.Equals, true)
132 c.Assert(series, gc.Equals, "precise") // default-series set in RepoSuite.SetUpTest
133
134 _, err = testing.RunCommand(c, &SetEnvironmentCommand{}, []string{"default-series=raring"})
135 c.Assert(err, gc.IsNil)
136
137 stateConfig, err = s.State.EnvironConfig()
138 c.Assert(err, gc.IsNil)
139 series, ok = stateConfig.DefaultSeries()
140 c.Assert(ok, gc.Equals, true)
141 c.Assert(series, gc.Equals, "raring")
142 c.Assert(config.PreferredSeries(stateConfig), gc.Equals, "raring")
133}143}
134144
135func (s *SetEnvironmentSuite) TestChangeBooleanAttribute(c *gc.C) {145func (s *SetEnvironmentSuite) TestChangeBooleanAttribute(c *gc.C) {
136146
=== modified file 'cmd/juju/publish.go'
--- cmd/juju/publish.go 2014-04-01 04:53:43 +0000
+++ cmd/juju/publish.go 2014-04-03 17:37:27 +0000
@@ -115,7 +115,7 @@
115 pushLocation = c.changePushLocation(pushLocation)115 pushLocation = c.changePushLocation(pushLocation)
116 }116 }
117117
118 repo, err := charm.InferRepository(curl, "/not/important")118 repo, err := charm.InferRepository(curl.Reference, "/not/important")
119 if err != nil {119 if err != nil {
120 return err120 return err
121 }121 }
122122
=== modified file 'cmd/juju/upgradecharm.go'
--- cmd/juju/upgradecharm.go 2014-04-01 04:53:43 +0000
+++ cmd/juju/upgradecharm.go 2014-04-03 17:37:27 +0000
@@ -134,8 +134,7 @@
134134
135 var newURL *charm.URL135 var newURL *charm.URL
136 if c.SwitchURL != "" {136 if c.SwitchURL != "" {
137 // A new charm URL was explicitly specified.137 newURL, err = resolveCharmURL(c.SwitchURL, client, conf)
138 newURL, err = charm.InferURL(c.SwitchURL, conf.DefaultSeries())
139 if err != nil {138 if err != nil {
140 return err139 return err
141 }140 }
@@ -143,11 +142,11 @@
143 // No new URL specified, but revision might have been.142 // No new URL specified, but revision might have been.
144 newURL = oldURL.WithRevision(c.Revision)143 newURL = oldURL.WithRevision(c.Revision)
145 }144 }
146 repo, err := charm.InferRepository(newURL, ctx.AbsPath(c.RepoPath))145
146 repo, err := charm.InferRepository(newURL.Reference, ctx.AbsPath(c.RepoPath))
147 if err != nil {147 if err != nil {
148 return err148 return err
149 }149 }
150
151 repo = config.SpecializeCharmRepo(repo, conf)150 repo = config.SpecializeCharmRepo(repo, conf)
152151
153 // If no explicit revision was set with either SwitchURL152 // If no explicit revision was set with either SwitchURL
@@ -203,11 +202,7 @@
203 var newURL *charm.URL202 var newURL *charm.URL
204 if c.SwitchURL != "" {203 if c.SwitchURL != "" {
205 // A new charm URL was explicitly specified.204 // A new charm URL was explicitly specified.
206 conf, err := conn.State.EnvironConfig()205 newURL, err = resolveCharmURL1dot16(c.SwitchURL, conf)
207 if err != nil {
208 return err
209 }
210 newURL, err = charm.InferURL(c.SwitchURL, conf.DefaultSeries())
211 if err != nil {206 if err != nil {
212 return err207 return err
213 }208 }
@@ -215,11 +210,11 @@
215 // No new URL specified, but revision might have been.210 // No new URL specified, but revision might have been.
216 newURL = oldURL.WithRevision(c.Revision)211 newURL = oldURL.WithRevision(c.Revision)
217 }212 }
218 repo, err := charm.InferRepository(newURL, ctx.AbsPath(c.RepoPath))213
214 repo, err := charm.InferRepository(newURL.Reference, ctx.AbsPath(c.RepoPath))
219 if err != nil {215 if err != nil {
220 return err216 return err
221 }217 }
222
223 repo = config.SpecializeCharmRepo(repo, conf)218 repo = config.SpecializeCharmRepo(repo, conf)
224219
225 // If no explicit revision was set with either SwitchURL220 // If no explicit revision was set with either SwitchURL
226221
=== modified file 'cmd/juju/upgradejuju_test.go'
--- cmd/juju/upgradejuju_test.go 2014-03-17 06:05:54 +0000
+++ cmd/juju/upgradejuju_test.go 2014-04-03 17:37:27 +0000
@@ -14,6 +14,7 @@
14 jc "github.com/juju/testing/checkers"14 jc "github.com/juju/testing/checkers"
15 gc "launchpad.net/gocheck"15 gc "launchpad.net/gocheck"
1616
17 "launchpad.net/juju-core/environs/config"
17 "launchpad.net/juju-core/environs/filestorage"18 "launchpad.net/juju-core/environs/filestorage"
18 "launchpad.net/juju-core/environs/storage"19 "launchpad.net/juju-core/environs/storage"
19 "launchpad.net/juju-core/environs/sync"20 "launchpad.net/juju-core/environs/sync"
@@ -225,14 +226,14 @@
225 agentVersion: "2.0.0",226 agentVersion: "2.0.0",
226 args: []string{"--upload-tools"},227 args: []string{"--upload-tools"},
227 expectVersion: "2.2.0.1",228 expectVersion: "2.2.0.1",
228 expectUploaded: []string{"2.2.0.1-quantal-amd64", "2.2.0.1-precise-amd64", "2.2.0.1-raring-amd64"},229 expectUploaded: []string{"2.2.0.1-quantal-amd64", "2.2.0.1-%LTS%-amd64", "2.2.0.1-raring-amd64"},
229}, {230}, {
230 about: "upload with explicit version",231 about: "upload with explicit version",
231 currentVersion: "2.2.0-quantal-amd64",232 currentVersion: "2.2.0-quantal-amd64",
232 agentVersion: "2.0.0",233 agentVersion: "2.0.0",
233 args: []string{"--upload-tools", "--version", "2.7.3"},234 args: []string{"--upload-tools", "--version", "2.7.3"},
234 expectVersion: "2.7.3.1",235 expectVersion: "2.7.3.1",
235 expectUploaded: []string{"2.7.3.1-quantal-amd64", "2.7.3.1-precise-amd64", "2.7.3.1-raring-amd64"},236 expectUploaded: []string{"2.7.3.1-quantal-amd64", "2.7.3.1-%LTS%-amd64", "2.7.3.1-raring-amd64"},
236}, {237}, {
237 about: "upload with explicit series",238 about: "upload with explicit series",
238 currentVersion: "2.2.0-quantal-amd64",239 currentVersion: "2.2.0-quantal-amd64",
@@ -246,7 +247,7 @@
246 agentVersion: "2.0.0",247 agentVersion: "2.0.0",
247 args: []string{"--upload-tools"},248 args: []string{"--upload-tools"},
248 expectVersion: "2.1.0.1",249 expectVersion: "2.1.0.1",
249 expectUploaded: []string{"2.1.0.1-quantal-amd64", "2.1.0.1-precise-amd64", "2.1.0.1-raring-amd64"},250 expectUploaded: []string{"2.1.0.1-quantal-amd64", "2.1.0.1-%LTS%-amd64", "2.1.0.1-raring-amd64"},
250}, {251}, {
251 about: "upload bumps version when necessary",252 about: "upload bumps version when necessary",
252 tools: []string{"2.4.6-quantal-amd64", "2.4.8-quantal-amd64"},253 tools: []string{"2.4.6-quantal-amd64", "2.4.8-quantal-amd64"},
@@ -254,7 +255,7 @@
254 agentVersion: "2.4.0",255 agentVersion: "2.4.0",
255 args: []string{"--upload-tools"},256 args: []string{"--upload-tools"},
256 expectVersion: "2.4.6.1",257 expectVersion: "2.4.6.1",
257 expectUploaded: []string{"2.4.6.1-quantal-amd64", "2.4.6.1-precise-amd64", "2.4.6.1-raring-amd64"},258 expectUploaded: []string{"2.4.6.1-quantal-amd64", "2.4.6.1-%LTS%-amd64", "2.4.6.1-raring-amd64"},
258}, {259}, {
259 about: "upload re-bumps version when necessary",260 about: "upload re-bumps version when necessary",
260 tools: []string{"2.4.6-quantal-amd64", "2.4.6.2-saucy-i386", "2.4.8-quantal-amd64"},261 tools: []string{"2.4.6-quantal-amd64", "2.4.6.2-saucy-i386", "2.4.8-quantal-amd64"},
@@ -262,7 +263,7 @@
262 agentVersion: "2.4.6.2",263 agentVersion: "2.4.6.2",
263 args: []string{"--upload-tools"},264 args: []string{"--upload-tools"},
264 expectVersion: "2.4.6.3",265 expectVersion: "2.4.6.3",
265 expectUploaded: []string{"2.4.6.3-quantal-amd64", "2.4.6.3-precise-amd64", "2.4.6.3-raring-amd64"},266 expectUploaded: []string{"2.4.6.3-quantal-amd64", "2.4.6.3-%LTS%-amd64", "2.4.6.3-raring-amd64"},
266}, {267}, {
267 about: "upload with explicit version bumps when necessary",268 about: "upload with explicit version bumps when necessary",
268 currentVersion: "2.2.0-quantal-amd64",269 currentVersion: "2.2.0-quantal-amd64",
@@ -270,7 +271,7 @@
270 agentVersion: "2.0.0",271 agentVersion: "2.0.0",
271 args: []string{"--upload-tools", "--version", "2.7.3"},272 args: []string{"--upload-tools", "--version", "2.7.3"},
272 expectVersion: "2.7.3.2",273 expectVersion: "2.7.3.2",
273 expectUploaded: []string{"2.7.3.2-quantal-amd64", "2.7.3.2-precise-amd64", "2.7.3.2-raring-amd64"},274 expectUploaded: []string{"2.7.3.2-quantal-amd64", "2.7.3.2-%LTS%-amd64", "2.7.3.2-raring-amd64"},
274}}275}}
275276
276// getMockBuildTools returns a sync.BuildToolsTarballFunc implementation which generates277// getMockBuildTools returns a sync.BuildToolsTarballFunc implementation which generates
@@ -356,6 +357,9 @@
356 c.Check(agentVersion, gc.Equals, version.MustParse(test.expectVersion))357 c.Check(agentVersion, gc.Equals, version.MustParse(test.expectVersion))
357358
358 for _, uploaded := range test.expectUploaded {359 for _, uploaded := range test.expectUploaded {
360 // Substitute latest LTS for placeholder in expected series for uploaded tools
361 uploaded = strings.Replace(uploaded, "%LTS%", config.LatestLtsSeries(), 1)
362
359 vers := version.MustParseBinary(uploaded)363 vers := version.MustParseBinary(uploaded)
360 r, err := storage.Get(s.Conn.Environ.Storage(), envtools.StorageName(vers))364 r, err := storage.Get(s.Conn.Environ.Storage(), envtools.StorageName(vers))
361 if !c.Check(err, gc.IsNil) {365 if !c.Check(err, gc.IsNil) {
362366
=== modified file 'cmd/plugins/juju-metadata/imagemetadata.go'
--- cmd/plugins/juju-metadata/imagemetadata.go 2014-03-28 12:28:30 +0000
+++ cmd/plugins/juju-metadata/imagemetadata.go 2014-04-03 17:37:27 +0000
@@ -97,7 +97,7 @@
97 }97 }
98 cfg := environ.Config()98 cfg := environ.Config()
99 if c.Series == "" {99 if c.Series == "" {
100 c.Series = cfg.DefaultSeries()100 c.Series = config.PreferredSeries(cfg)
101 }101 }
102 if v, ok := cfg.AllAttrs()["control-bucket"]; ok {102 if v, ok := cfg.AllAttrs()["control-bucket"]; ok {
103 c.privateStorage = v.(string)103 c.privateStorage = v.(string)
@@ -110,7 +110,7 @@
110 logger.Infof("no environment found, creating image metadata using user supplied data")110 logger.Infof("no environment found, creating image metadata using user supplied data")
111 }111 }
112 if c.Series == "" {112 if c.Series == "" {
113 c.Series = config.DefaultSeries113 c.Series = config.LatestLtsSeries()
114 }114 }
115 if c.ImageId == "" {115 if c.ImageId == "" {
116 return fmt.Errorf("image id must be specified")116 return fmt.Errorf("image id must be specified")
117117
=== modified file 'cmd/plugins/juju-metadata/imagemetadata_test.go'
--- cmd/plugins/juju-metadata/imagemetadata_test.go 2014-03-13 07:54:56 +0000
+++ cmd/plugins/juju-metadata/imagemetadata_test.go 2014-04-03 17:37:27 +0000
@@ -15,6 +15,7 @@
15 gc "launchpad.net/gocheck"15 gc "launchpad.net/gocheck"
1616
17 "launchpad.net/juju-core/cmd"17 "launchpad.net/juju-core/cmd"
18 "launchpad.net/juju-core/environs/config"
18 "launchpad.net/juju-core/testing"19 "launchpad.net/juju-core/testing"
19 "launchpad.net/juju-core/testing/testbase"20 "launchpad.net/juju-core/testing/testbase"
20)21)
@@ -61,6 +62,7 @@
61var seriesVersions map[string]string = map[string]string{62var seriesVersions map[string]string = map[string]string{
62 "precise": "12.04",63 "precise": "12.04",
63 "raring": "13.04",64 "raring": "13.04",
65 "trusty": "14.04",
64}66}
6567
66type expectedMetadata struct {68type expectedMetadata struct {
@@ -138,7 +140,7 @@
138 s.assertCommandOutput(c, expected, out, defaultIndexFileName, defaultImageFileName)140 s.assertCommandOutput(c, expected, out, defaultIndexFileName, defaultImageFileName)
139}141}
140142
141func (s *ImageMetadataSuite) TestImageMetadataFilesDefaultSeries(c *gc.C) {143func (s *ImageMetadataSuite) TestImageMetadataFilesLatestLts(c *gc.C) {
142 ctx := testing.Context(c)144 ctx := testing.Context(c)
143 code := cmd.Main(145 code := cmd.Main(
144 &ImageMetadataCommand{}, ctx, []string{146 &ImageMetadataCommand{}, ctx, []string{
@@ -146,7 +148,7 @@
146 c.Assert(code, gc.Equals, 0)148 c.Assert(code, gc.Equals, 0)
147 out := testing.Stdout(ctx)149 out := testing.Stdout(ctx)
148 expected := expectedMetadata{150 expected := expectedMetadata{
149 series: "precise",151 series: config.LatestLtsSeries(),
150 arch: "arch",152 arch: "arch",
151 }153 }
152 s.assertCommandOutput(c, expected, out, defaultIndexFileName, defaultImageFileName)154 s.assertCommandOutput(c, expected, out, defaultIndexFileName, defaultImageFileName)
153155
=== modified file 'environs/bootstrap/bootstrap_test.go'
--- environs/bootstrap/bootstrap_test.go 2014-03-28 13:27:45 +0000
+++ environs/bootstrap/bootstrap_test.go 2014-04-03 17:37:27 +0000
@@ -88,7 +88,7 @@
8888
89func uploadTools(c *gc.C, env environs.Environ) {89func uploadTools(c *gc.C, env environs.Environ) {
90 usefulVersion := version.Current90 usefulVersion := version.Current
91 usefulVersion.Series = env.Config().DefaultSeries()91 usefulVersion.Series = config.PreferredSeries(env.Config())
92 envtesting.AssertUploadFakeToolsVersions(c, env.Storage(), usefulVersion)92 envtesting.AssertUploadFakeToolsVersions(c, env.Storage(), usefulVersion)
93}93}
9494
@@ -217,7 +217,7 @@
217 s.setDummyStorage(c, env)217 s.setDummyStorage(c, env)
218 envtesting.RemoveFakeTools(c, env.Storage())218 envtesting.RemoveFakeTools(c, env.Storage())
219 arch := "ppc64"219 arch := "ppc64"
220 _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), &arch)220 _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, config.PreferredSeries(env.Config()), &arch)
221 c.Assert(err, gc.NotNil)221 c.Assert(err, gc.NotNil)
222 stripped := strings.Replace(err.Error(), "\n", "", -1)222 stripped := strings.Replace(err.Error(), "\n", "", -1)
223 c.Assert(stripped,223 c.Assert(stripped,
@@ -233,7 +233,7 @@
233 env := newEnviron("foo", useDefaultKeys, nil)233 env := newEnviron("foo", useDefaultKeys, nil)
234 s.setDummyStorage(c, env)234 s.setDummyStorage(c, env)
235 envtesting.RemoveFakeTools(c, env.Storage())235 envtesting.RemoveFakeTools(c, env.Storage())
236 _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), nil)236 _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, config.PreferredSeries(env.Config()), nil)
237 c.Assert(err, gc.NotNil)237 c.Assert(err, gc.NotNil)
238 stripped := strings.Replace(err.Error(), "\n", "", -1)238 stripped := strings.Replace(err.Error(), "\n", "", -1)
239 c.Assert(stripped,239 c.Assert(stripped,
@@ -246,7 +246,7 @@
246 env := newEnviron("foo", useDefaultKeys, map[string]interface{}{"agent-version": "1.16.0"})246 env := newEnviron("foo", useDefaultKeys, map[string]interface{}{"agent-version": "1.16.0"})
247 s.setDummyStorage(c, env)247 s.setDummyStorage(c, env)
248 envtesting.RemoveFakeTools(c, env.Storage())248 envtesting.RemoveFakeTools(c, env.Storage())
249 _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), nil)249 _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, config.PreferredSeries(env.Config()), nil)
250 c.Assert(err, gc.NotNil)250 c.Assert(err, gc.NotNil)
251 stripped := strings.Replace(err.Error(), "\n", "", -1)251 stripped := strings.Replace(err.Error(), "\n", "", -1)
252 c.Assert(stripped,252 c.Assert(stripped,
@@ -260,7 +260,7 @@
260 env := newEnviron("foo", useDefaultKeys, nil)260 env := newEnviron("foo", useDefaultKeys, nil)
261 s.setDummyStorage(c, env)261 s.setDummyStorage(c, env)
262 envtesting.RemoveFakeTools(c, env.Storage())262 envtesting.RemoveFakeTools(c, env.Storage())
263 _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), nil)263 _, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, config.PreferredSeries(env.Config()), nil)
264 c.Assert(err, gc.NotNil)264 c.Assert(err, gc.NotNil)
265 stripped := strings.Replace(err.Error(), "\n", "", -1)265 stripped := strings.Replace(err.Error(), "\n", "", -1)
266 c.Assert(stripped,266 c.Assert(stripped,
@@ -310,12 +310,12 @@
310 return "arm64"310 return "arm64"
311 })311 })
312 arch := "arm64"312 arch := "arm64"
313 agentTools, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, env.Config().DefaultSeries(), &arch)313 agentTools, err := bootstrap.EnsureToolsAvailability(coretesting.Context(c), env, config.PreferredSeries(env.Config()), &arch)
314 c.Assert(err, gc.IsNil)314 c.Assert(err, gc.IsNil)
315 c.Assert(agentTools, gc.HasLen, 1)315 c.Assert(agentTools, gc.HasLen, 1)
316 expectedVers := version.Current316 expectedVers := version.Current
317 expectedVers.Number.Build++317 expectedVers.Number.Build++
318 expectedVers.Series = env.Config().DefaultSeries()318 expectedVers.Series = config.PreferredSeries(env.Config())
319 c.Assert(agentTools[0].Version, gc.DeepEquals, expectedVers)319 c.Assert(agentTools[0].Version, gc.DeepEquals, expectedVers)
320}320}
321321
@@ -325,11 +325,18 @@
325 s.PatchValue(&version.Current, vers)325 s.PatchValue(&version.Current, vers)
326 env := newEnviron("foo", useDefaultKeys, nil)326 env := newEnviron("foo", useDefaultKeys, nil)
327 cfg := env.Config()327 cfg := env.Config()
328 c.Assert(bootstrap.SeriesToUpload(cfg, nil), jc.SameContents, []string{"quantal", "precise"})328
329 prefSeries := config.PreferredSeries(cfg)
330 expect := []string{"quantal", prefSeries}
331 if prefSeries != config.LatestLtsSeries() {
332 expect = append(expect, config.LatestLtsSeries())
333 }
334 c.Assert(bootstrap.SeriesToUpload(cfg, nil), jc.SameContents, expect)
335
329 c.Assert(bootstrap.SeriesToUpload(cfg, []string{"quantal"}), jc.SameContents, []string{"quantal"})336 c.Assert(bootstrap.SeriesToUpload(cfg, []string{"quantal"}), jc.SameContents, []string{"quantal"})
330 env = newEnviron("foo", useDefaultKeys, map[string]interface{}{"default-series": "lucid"})337 env = newEnviron("foo", useDefaultKeys, map[string]interface{}{"default-series": "lucid"})
331 cfg = env.Config()338 cfg = env.Config()
332 c.Assert(bootstrap.SeriesToUpload(cfg, nil), jc.SameContents, []string{"quantal", "precise", "lucid"})339 c.Assert(bootstrap.SeriesToUpload(cfg, nil), jc.SameContents, []string{"quantal", config.LatestLtsSeries(), "lucid"})
333}340}
334341
335func (s *bootstrapSuite) assertUploadTools(c *gc.C, vers version.Binary, allowRelease bool,342func (s *bootstrapSuite) assertUploadTools(c *gc.C, vers version.Binary, allowRelease bool,
336343
=== modified file 'environs/bootstrap/synctools.go'
--- environs/bootstrap/synctools.go 2014-03-26 03:30:35 +0000
+++ environs/bootstrap/synctools.go 2014-04-03 17:37:27 +0000
@@ -100,8 +100,10 @@
100 unique := set.NewStrings(series...)100 unique := set.NewStrings(series...)
101 if unique.IsEmpty() {101 if unique.IsEmpty() {
102 unique.Add(version.Current.Series)102 unique.Add(version.Current.Series)
103 unique.Add(config.DefaultSeries)103 unique.Add(config.LatestLtsSeries())
104 unique.Add(cfg.DefaultSeries())104 if series, ok := cfg.DefaultSeries(); ok {
105 unique.Add(series)
106 }
105 }107 }
106 return unique.Values()108 return unique.Values()
107}109}
@@ -175,7 +177,10 @@
175 // No tools available so our only hope is to build locally and upload.177 // No tools available so our only hope is to build locally and upload.
176 logger.Warningf("no prepackaged tools available")178 logger.Warningf("no prepackaged tools available")
177 uploadSeries := SeriesToUpload(cfg, nil)179 uploadSeries := SeriesToUpload(cfg, nil)
178 if err := UploadTools(ctx, env, toolsArch, false, append(uploadSeries, series)...); err != nil {180 if series != "" {
181 uploadSeries = append(uploadSeries, series)
182 }
183 if err := UploadTools(ctx, env, toolsArch, false, uploadSeries...); err != nil {
179 logger.Errorf("%s", noToolsMessage)184 logger.Errorf("%s", noToolsMessage)
180 return nil, fmt.Errorf("cannot upload bootstrap tools: %v", err)185 return nil, fmt.Errorf("cannot upload bootstrap tools: %v", err)
181 }186 }
182187
=== modified file 'environs/config/config.go'
--- environs/config/config.go 2014-04-02 06:15:57 +0000
+++ environs/config/config.go 2014-04-03 17:37:27 +0000
@@ -7,6 +7,7 @@
7 "fmt"7 "fmt"
8 "io/ioutil"8 "io/ioutil"
9 "os"9 "os"
10 "os/exec"
10 "path/filepath"11 "path/filepath"
11 "regexp"12 "regexp"
12 "strings"13 "strings"
@@ -34,9 +35,6 @@
34 // port opened.35 // port opened.
35 FwGlobal = "global"36 FwGlobal = "global"
3637
37 // DefaultSeries returns the most recent Ubuntu LTS release name.
38 DefaultSeries string = "precise"
39
40 // DefaultStatePort is the default port the state server is listening on.38 // DefaultStatePort is the default port the state server is listening on.
41 DefaultStatePort int = 3701739 DefaultStatePort int = 37017
4240
@@ -59,8 +57,53 @@
59 // refreshing the addresses, in seconds. Not too frequent, as we57 // refreshing the addresses, in seconds. Not too frequent, as we
60 // refresh addresses from the provider each time.58 // refresh addresses from the provider each time.
61 DefaultBootstrapSSHAddressesDelay int = 1059 DefaultBootstrapSSHAddressesDelay int = 10
60
61 // fallbackLtsSeries is the latest LTS series we'll use, if we fail to
62 // obtain this information from the system.
63 fallbackLtsSeries string = "precise"
62)64)
6365
66var latestLtsSeries string
67
68type HasDefaultSeries interface {
69 DefaultSeries() (string, bool)
70}
71
72// PreferredSeries returns the preferred series to use when a charm does not
73// explicitly specify a series.
74func PreferredSeries(cfg HasDefaultSeries) string {
75 if series, ok := cfg.DefaultSeries(); ok {
76 return series
77 }
78 return LatestLtsSeries()
79}
80
81func LatestLtsSeries() string {
82 if latestLtsSeries == "" {
83 series, err := distroLtsSeries()
84 if err != nil {
85 latestLtsSeries = fallbackLtsSeries
86 } else {
87 latestLtsSeries = series
88 }
89 }
90 return latestLtsSeries
91}
92
93// distroLtsSeries returns the latest LTS series, if this information is
94// available on this system.
95func distroLtsSeries() (string, error) {
96 out, err := exec.Command("distro-info", "--lts").Output()
97 if err != nil {
98 return "", err
99 }
100 series := strings.TrimSpace(string(out))
101 if !charm.IsValidSeries(series) {
102 return "", fmt.Errorf("not a valid LTS series: %q", series)
103 }
104 return series, nil
105}
106
64// Config holds an immutable environment configuration.107// Config holds an immutable environment configuration.
65type Config struct {108type Config struct {
66 // defined holds the attributes that are defined for Config.109 // defined holds the attributes that are defined for Config.
@@ -162,7 +205,6 @@
162 // For backward compatibility purposes, we treat as unset string205 // For backward compatibility purposes, we treat as unset string
163 // valued attributes that are set to the empty string, and fill206 // valued attributes that are set to the empty string, and fill
164 // out their defaults accordingly.207 // out their defaults accordingly.
165 c.fillInStringDefault("default-series")
166 c.fillInStringDefault("firewall-mode")208 c.fillInStringDefault("firewall-mode")
167209
168 // Load authorized-keys-path into authorized-keys if necessary.210 // Load authorized-keys-path into authorized-keys if necessary.
@@ -407,9 +449,17 @@
407 return c.mustString("name")449 return c.mustString("name")
408}450}
409451
410// DefaultSeries returns the default Ubuntu series for the environment.452// DefaultSeries returns the configured default Ubuntu series for the environment,
411func (c *Config) DefaultSeries() string {453// and whether the default series was explicitly configured on the environment.
412 return c.mustString("default-series")454func (c *Config) DefaultSeries() (string, bool) {
455 if s, ok := c.defined["default-series"]; ok {
456 if series, ok := s.(string); ok && series != "" {
457 return series, true
458 } else if !ok {
459 logger.Warningf("invalid default-series: %q", s)
460 }
461 }
462 return "", false
413}463}
414464
415// StatePort returns the state server port for the environment.465// StatePort returns the state server port for the environment.
@@ -771,6 +821,8 @@
771 "image-metadata-url": "", // TODO(rog) omit821 "image-metadata-url": "", // TODO(rog) omit
772 "tools-metadata-url": "", // TODO(rog) omit822 "tools-metadata-url": "", // TODO(rog) omit
773823
824 "default-series": "",
825
774 // For backward compatibility only - default ports were826 // For backward compatibility only - default ports were
775 // not filled out in previous versions of the configuration.827 // not filled out in previous versions of the configuration.
776 "state-port": DefaultStatePort,828 "state-port": DefaultStatePort,
@@ -795,7 +847,6 @@
795// UseDefaults.847// UseDefaults.
796func allDefaults() schema.Defaults {848func allDefaults() schema.Defaults {
797 d := schema.Defaults{849 d := schema.Defaults{
798 "default-series": DefaultSeries,
799 "firewall-mode": FwInstance,850 "firewall-mode": FwInstance,
800 "development": false,851 "development": false,
801 "ssl-hostname-verification": true,852 "ssl-hostname-verification": true,
802853
=== modified file 'environs/config/config_test.go'
--- environs/config/config_test.go 2014-03-26 08:14:32 +0000
+++ environs/config/config_test.go 2014-04-03 17:37:27 +0000
@@ -652,7 +652,6 @@
652 authTokenConfigTest("token=value, =z", false),652 authTokenConfigTest("token=value, =z", false),
653 authTokenConfigTest("token=value =z", false),653 authTokenConfigTest("token=value =z", false),
654 authTokenConfigTest("\t", false),654 authTokenConfigTest("\t", false),
655 missingAttributeNoDefault("default-series"),
656 missingAttributeNoDefault("firewall-mode"),655 missingAttributeNoDefault("firewall-mode"),
657 missingAttributeNoDefault("development"),656 missingAttributeNoDefault("development"),
658 missingAttributeNoDefault("ssl-hostname-verification"),657 missingAttributeNoDefault("ssl-hostname-verification"),
@@ -861,11 +860,14 @@
861 testmode, _ := test.attrs["test-mode"].(bool)860 testmode, _ := test.attrs["test-mode"].(bool)
862 c.Assert(cfg.TestMode(), gc.Equals, testmode)861 c.Assert(cfg.TestMode(), gc.Equals, testmode)
863862
864 if series, _ := test.attrs["default-series"].(string); series != "" {863 series, _ := test.attrs["default-series"].(string)
865 c.Assert(cfg.DefaultSeries(), gc.Equals, series)864 if defaultSeries, ok := cfg.DefaultSeries(); ok {
865 c.Assert(defaultSeries, gc.Equals, series)
866 } else {866 } else {
867 c.Assert(cfg.DefaultSeries(), gc.Equals, config.DefaultSeries)867 c.Assert(series, gc.Equals, "")
868 c.Assert(defaultSeries, gc.Equals, "")
868 }869 }
870
869 if m, _ := test.attrs["firewall-mode"].(string); m != "" {871 if m, _ := test.attrs["firewall-mode"].(string); m != "" {
870 c.Assert(cfg.FirewallMode(), gc.Equals, m)872 c.Assert(cfg.FirewallMode(), gc.Equals, m)
871 }873 }
@@ -1010,7 +1012,7 @@
1010 "bootstrap-timeout": 3600,1012 "bootstrap-timeout": 3600,
1011 "bootstrap-retry-delay": 30,1013 "bootstrap-retry-delay": 30,
1012 "bootstrap-addresses-delay": 10,1014 "bootstrap-addresses-delay": 10,
1013 "default-series": "precise",1015 "default-series": testing.FakeDefaultSeries,
1014 "charm-store-auth": "token=auth",1016 "charm-store-auth": "token=auth",
1015 "test-mode": false,1017 "test-mode": false,
1016 }1018 }
@@ -1019,7 +1021,6 @@
10191021
1020 // These attributes are added if not set.1022 // These attributes are added if not set.
1021 attrs["development"] = false1023 attrs["development"] = false
1022 attrs["default-series"] = config.DefaultSeries
1023 attrs["logging-config"] = "<root>=WARNING;unit=DEBUG"1024 attrs["logging-config"] = "<root>=WARNING;unit=DEBUG"
1024 attrs["ca-private-key"] = ""1025 attrs["ca-private-key"] = ""
1025 attrs["image-metadata-url"] = ""1026 attrs["image-metadata-url"] = ""
10261027
=== modified file 'environs/jujutest/livetests.go'
--- environs/jujutest/livetests.go 2014-04-03 02:57:11 +0000
+++ environs/jujutest/livetests.go 2014-04-03 17:37:27 +0000
@@ -133,7 +133,7 @@
133 // we could connect to (actual live tests, rather than local-only)133 // we could connect to (actual live tests, rather than local-only)
134 cons := constraints.MustParse("mem=2G")134 cons := constraints.MustParse("mem=2G")
135 if t.CanOpenState {135 if t.CanOpenState {
136 _, err := sync.Upload(t.Env.Storage(), nil, config.DefaultSeries)136 _, err := sync.Upload(t.Env.Storage(), nil, coretesting.FakeDefaultSeries)
137 c.Assert(err, gc.IsNil)137 c.Assert(err, gc.IsNil)
138 }138 }
139 envtesting.UploadFakeTools(c, t.Env.Storage())139 envtesting.UploadFakeTools(c, t.Env.Storage())
@@ -442,7 +442,7 @@
442442
443 // If the series has not been specified, we expect the most recent Ubuntu LTS release to be used.443 // If the series has not been specified, we expect the most recent Ubuntu LTS release to be used.
444 expectedVersion := version.Current444 expectedVersion := version.Current
445 expectedVersion.Series = config.DefaultSeries445 expectedVersion.Series = config.LatestLtsSeries()
446446
447 mtools0 := waitAgentTools(c, mw0, expectedVersion)447 mtools0 := waitAgentTools(c, mw0, expectedVersion)
448448
449449
=== modified file 'environs/testing/tools.go'
--- environs/testing/tools.go 2014-03-27 00:42:27 +0000
+++ environs/testing/tools.go 2014-04-03 17:37:27 +0000
@@ -13,7 +13,6 @@
1313
14 agenttools "launchpad.net/juju-core/agent/tools"14 agenttools "launchpad.net/juju-core/agent/tools"
15 "launchpad.net/juju-core/environs"15 "launchpad.net/juju-core/environs"
16 "launchpad.net/juju-core/environs/config"
17 "launchpad.net/juju-core/environs/simplestreams"16 "launchpad.net/juju-core/environs/simplestreams"
18 "launchpad.net/juju-core/environs/storage"17 "launchpad.net/juju-core/environs/storage"
19 envtools "launchpad.net/juju-core/environs/tools"18 envtools "launchpad.net/juju-core/environs/tools"
@@ -163,8 +162,9 @@
163func uploadFakeTools(stor storage.Storage) error {162func uploadFakeTools(stor storage.Storage) error {
164 versions := []version.Binary{version.Current}163 versions := []version.Binary{version.Current}
165 toolsVersion := version.Current164 toolsVersion := version.Current
166 if toolsVersion.Series != config.DefaultSeries {165 latestLts := coretesting.FakeDefaultSeries
167 toolsVersion.Series = config.DefaultSeries166 if toolsVersion.Series != latestLts {
167 toolsVersion.Series = latestLts
168 versions = append(versions, toolsVersion)168 versions = append(versions, toolsVersion)
169 }169 }
170 if _, err := UploadFakeToolsVersions(stor, versions...); err != nil {170 if _, err := UploadFakeToolsVersions(stor, versions...); err != nil {
@@ -175,9 +175,9 @@
175175
176// UploadFakeTools puts fake tools into the supplied storage with a binary176// UploadFakeTools puts fake tools into the supplied storage with a binary
177// version matching version.Current; if version.Current's series is different177// version matching version.Current; if version.Current's series is different
178// to config.DefaultSeries, matching fake tools will be uploaded for that series.178// to coretesting.FakeDefaultSeries, matching fake tools will be uploaded for that
179// This is useful for tests that are kinda casual about specifying their179// series. This is useful for tests that are kinda casual about specifying
180// environment.180// their environment.
181func UploadFakeTools(c *gc.C, stor storage.Storage) {181func UploadFakeTools(c *gc.C, stor storage.Storage) {
182 c.Assert(uploadFakeTools(stor), gc.IsNil)182 c.Assert(uploadFakeTools(stor), gc.IsNil)
183}183}
@@ -196,8 +196,9 @@
196 name := envtools.StorageName(toolsVersion)196 name := envtools.StorageName(toolsVersion)
197 err := stor.Remove(name)197 err := stor.Remove(name)
198 c.Check(err, gc.IsNil)198 c.Check(err, gc.IsNil)
199 if version.Current.Series != config.DefaultSeries {199 defaultSeries := coretesting.FakeDefaultSeries
200 toolsVersion.Series = config.DefaultSeries200 if version.Current.Series != defaultSeries {
201 toolsVersion.Series = defaultSeries
201 name := envtools.StorageName(toolsVersion)202 name := envtools.StorageName(toolsVersion)
202 err := stor.Remove(name)203 err := stor.Remove(name)
203 c.Check(err, gc.IsNil)204 c.Check(err, gc.IsNil)
204205
=== modified file 'juju/apiconn_test.go'
--- juju/apiconn_test.go 2014-04-02 00:18:34 +0000
+++ juju/apiconn_test.go 2014-04-03 17:37:27 +0000
@@ -175,7 +175,7 @@
175 "name": "myenv",175 "name": "myenv",
176 "state-server": true,176 "state-server": true,
177 "authorized-keys": "i-am-a-key",177 "authorized-keys": "i-am-a-key",
178 "default-series": config.DefaultSeries,178 "default-series": config.LatestLtsSeries(),
179 "firewall-mode": config.FwInstance,179 "firewall-mode": config.FwInstance,
180 "development": false,180 "development": false,
181 "ssl-hostname-verification": true,181 "ssl-hostname-verification": true,
182182
=== modified file 'juju/testing/conn.go'
--- juju/testing/conn.go 2014-03-25 15:06:31 +0000
+++ juju/testing/conn.go 2014-04-03 17:37:27 +0000
@@ -17,6 +17,7 @@
17 "launchpad.net/juju-core/constraints"17 "launchpad.net/juju-core/constraints"
18 "launchpad.net/juju-core/environs"18 "launchpad.net/juju-core/environs"
19 "launchpad.net/juju-core/environs/bootstrap"19 "launchpad.net/juju-core/environs/bootstrap"
20 "launchpad.net/juju-core/environs/config"
20 "launchpad.net/juju-core/environs/configstore"21 "launchpad.net/juju-core/environs/configstore"
21 envtesting "launchpad.net/juju-core/environs/testing"22 envtesting "launchpad.net/juju-core/environs/testing"
22 "launchpad.net/juju-core/juju"23 "launchpad.net/juju-core/juju"
@@ -164,6 +165,14 @@
164 return s.openAPIAs(c, machine.Tag(), password, "fake_nonce"), machine165 return s.openAPIAs(c, machine.Tag(), password, "fake_nonce"), machine
165}166}
166167
168func PreferredDefaultVersions(conf *config.Config, template version.Binary) []version.Binary {
169 prefVersion := template
170 prefVersion.Series = config.PreferredSeries(conf)
171 defaultVersion := template
172 defaultVersion.Series = testing.FakeDefaultSeries
173 return []version.Binary{prefVersion, defaultVersion}
174}
175
167func (s *JujuConnSuite) setUpConn(c *gc.C) {176func (s *JujuConnSuite) setUpConn(c *gc.C) {
168 if s.RootDir != "" {177 if s.RootDir != "" {
169 panic("JujuConnSuite.setUpConn without teardown")178 panic("JujuConnSuite.setUpConn without teardown")
@@ -203,7 +212,11 @@
203 c.Assert(environ.Name(), gc.Equals, "dummyenv")212 c.Assert(environ.Name(), gc.Equals, "dummyenv")
204 s.PatchValue(&dummy.DataDir, s.DataDir())213 s.PatchValue(&dummy.DataDir, s.DataDir())
205214
206 envtesting.MustUploadFakeTools(environ.Storage())215 versions := PreferredDefaultVersions(environ.Config(), version.Current)
216 versions = append(versions, version.Current)
217
218 // Upload tools for both preferred and fake default series
219 envtesting.MustUploadFakeToolsVersions(environ.Storage(), versions...)
207 c.Assert(bootstrap.Bootstrap(ctx, environ, constraints.Value{}), gc.IsNil)220 c.Assert(bootstrap.Bootstrap(ctx, environ, constraints.Value{}), gc.IsNil)
208221
209 s.BackingState = environ.(GetStater).GetStateInAPIServer()222 s.BackingState = environ.(GetStater).GetStateInAPIServer()
@@ -285,7 +298,7 @@
285 ch := testing.Charms.Dir(name)298 ch := testing.Charms.Dir(name)
286 ident := fmt.Sprintf("%s-%d", ch.Meta().Name, ch.Revision())299 ident := fmt.Sprintf("%s-%d", ch.Meta().Name, ch.Revision())
287 curl := charm.MustParseURL("local:quantal/" + ident)300 curl := charm.MustParseURL("local:quantal/" + ident)
288 repo, err := charm.InferRepository(curl, testing.Charms.Path())301 repo, err := charm.InferRepository(curl.Reference, testing.Charms.Path())
289 c.Assert(err, gc.IsNil)302 c.Assert(err, gc.IsNil)
290 sch, err := s.Conn.PutCharm(curl, repo, false)303 sch, err := s.Conn.PutCharm(curl, repo, false)
291 c.Assert(err, gc.IsNil)304 c.Assert(err, gc.IsNil)
292305
=== modified file 'juju/testing/instance.go'
--- juju/testing/instance.go 2014-04-01 16:27:22 +0000
+++ juju/testing/instance.go 2014-04-03 17:37:27 +0000
@@ -10,6 +10,7 @@
1010
11 "launchpad.net/juju-core/constraints"11 "launchpad.net/juju-core/constraints"
12 "launchpad.net/juju-core/environs"12 "launchpad.net/juju-core/environs"
13 "launchpad.net/juju-core/environs/config"
13 "launchpad.net/juju-core/environs/tools"14 "launchpad.net/juju-core/environs/tools"
14 "launchpad.net/juju-core/instance"15 "launchpad.net/juju-core/instance"
15 "launchpad.net/juju-core/names"16 "launchpad.net/juju-core/names"
@@ -112,7 +113,7 @@
112) (113) (
113 instance.Instance, *instance.HardwareCharacteristics, error,114 instance.Instance, *instance.HardwareCharacteristics, error,
114) {115) {
115 series := env.Config().DefaultSeries()116 series := config.PreferredSeries(env.Config())
116 agentVersion, ok := env.Config().AgentVersion()117 agentVersion, ok := env.Config().AgentVersion()
117 if !ok {118 if !ok {
118 return nil, nil, fmt.Errorf("missing agent version in environment config")119 return nil, nil, fmt.Errorf("missing agent version in environment config")
119120
=== modified file 'provider/azure/environ_test.go'
--- provider/azure/environ_test.go 2014-04-03 09:07:57 +0000
+++ provider/azure/environ_test.go 2014-04-03 17:37:27 +0000
@@ -448,7 +448,7 @@
448 err = env.SetConfig(cfg)448 err = env.SetConfig(cfg)
449 c.Assert(err, gc.IsNil)449 c.Assert(err, gc.IsNil)
450450
451 c.Check(env.ecfg.Config.DefaultSeries(), gc.Equals, "feisty")451 c.Check(config.PreferredSeries(env.ecfg.Config), gc.Equals, "feisty")
452}452}
453453
454func (*environSuite) TestSetConfigLocksEnviron(c *gc.C) {454func (*environSuite) TestSetConfigLocksEnviron(c *gc.C) {
455455
=== modified file 'provider/common/bootstrap.go'
--- provider/common/bootstrap.go 2014-03-28 22:31:08 +0000
+++ provider/common/bootstrap.go 2014-04-03 17:37:27 +0000
@@ -42,7 +42,7 @@
42 defer func() { handleBootstrapError(err, ctx, inst, env) }()42 defer func() { handleBootstrapError(err, ctx, inst, env) }()
4343
44 // First thing, ensure we have tools otherwise there's no point.44 // First thing, ensure we have tools otherwise there's no point.
45 selectedTools, err := EnsureBootstrapTools(ctx, env, env.Config().DefaultSeries(), cons.Arch)45 selectedTools, err := EnsureBootstrapTools(ctx, env, config.PreferredSeries(env.Config()), cons.Arch)
46 if err != nil {46 if err != nil {
47 return err47 return err
48 }48 }
4949
=== modified file 'provider/dummy/environs.go'
--- provider/dummy/environs.go 2014-04-03 03:37:45 +0000
+++ provider/dummy/environs.go 2014-04-03 17:37:27 +0000
@@ -545,7 +545,7 @@
545}545}
546546
547func (e *environ) Bootstrap(ctx environs.BootstrapContext, cons constraints.Value) error {547func (e *environ) Bootstrap(ctx environs.BootstrapContext, cons constraints.Value) error {
548 selectedTools, err := common.EnsureBootstrapTools(ctx, e, e.Config().DefaultSeries(), cons.Arch)548 selectedTools, err := common.EnsureBootstrapTools(ctx, e, config.PreferredSeries(e.Config()), cons.Arch)
549 if err != nil {549 if err != nil {
550 return err550 return err
551 }551 }
552552
=== modified file 'provider/ec2/ec2.go'
--- provider/ec2/ec2.go 2014-04-03 03:37:45 +0000
+++ provider/ec2/ec2.go 2014-04-03 17:37:27 +0000
@@ -367,7 +367,7 @@
367 return nil, err367 return nil, err
368 }368 }
369 return &simplestreams.MetadataLookupParams{369 return &simplestreams.MetadataLookupParams{
370 Series: e.ecfg().DefaultSeries(),370 Series: config.PreferredSeries(e.ecfg()),
371 Region: cloudSpec.Region,371 Region: cloudSpec.Region,
372 Endpoint: cloudSpec.Endpoint,372 Endpoint: cloudSpec.Endpoint,
373 Architectures: arch.AllSupportedArches,373 Architectures: arch.AllSupportedArches,
374374
=== modified file 'provider/ec2/live_test.go'
--- provider/ec2/live_test.go 2014-03-20 03:06:57 +0000
+++ provider/ec2/live_test.go 2014-04-03 17:37:27 +0000
@@ -101,7 +101,7 @@
101 t.LiveTests.SetUpTest(c)101 t.LiveTests.SetUpTest(c)
102 t.PatchValue(&version.Current, version.Binary{102 t.PatchValue(&version.Current, version.Binary{
103 Number: version.Current.Number,103 Number: version.Current.Number,
104 Series: config.DefaultSeries,104 Series: coretesting.FakeDefaultSeries,
105 Arch: arch.AMD64,105 Arch: arch.AMD64,
106 })106 })
107107
108108
=== modified file 'provider/ec2/local_test.go'
--- provider/ec2/local_test.go 2014-04-02 11:35:49 +0000
+++ provider/ec2/local_test.go 2014-04-03 17:37:27 +0000
@@ -205,7 +205,7 @@
205 t.Tests.SetUpTest(c)205 t.Tests.SetUpTest(c)
206 t.PatchValue(&version.Current, version.Binary{206 t.PatchValue(&version.Current, version.Binary{
207 Number: version.Current.Number,207 Number: version.Current.Number,
208 Series: config.DefaultSeries,208 Series: coretesting.FakeDefaultSeries,
209 Arch: arch.AMD64,209 Arch: arch.AMD64,
210 })210 })
211}211}
212212
=== modified file 'provider/joyent/environ.go'
--- provider/joyent/environ.go 2014-04-03 03:37:45 +0000
+++ provider/joyent/environ.go 2014-04-03 17:37:27 +0000
@@ -154,7 +154,7 @@
154 region = env.Ecfg().Region()154 region = env.Ecfg().Region()
155 }155 }
156 return &simplestreams.MetadataLookupParams{156 return &simplestreams.MetadataLookupParams{
157 Series: env.Ecfg().DefaultSeries(),157 Series: config.PreferredSeries(env.Ecfg()),
158 Region: region,158 Region: region,
159 Endpoint: env.Ecfg().sdcUrl(),159 Endpoint: env.Ecfg().sdcUrl(),
160 Architectures: []string{"amd64", "arm"},160 Architectures: []string{"amd64", "arm"},
161161
=== modified file 'provider/openstack/provider.go'
--- provider/openstack/provider.go 2014-04-03 03:37:45 +0000
+++ provider/openstack/provider.go 2014-04-03 17:37:27 +0000
@@ -1236,7 +1236,7 @@
1236 return nil, err1236 return nil, err
1237 }1237 }
1238 return &simplestreams.MetadataLookupParams{1238 return &simplestreams.MetadataLookupParams{
1239 Series: e.ecfg().DefaultSeries(),1239 Series: config.PreferredSeries(e.ecfg()),
1240 Region: cloudSpec.Region,1240 Region: cloudSpec.Region,
1241 Endpoint: cloudSpec.Endpoint,1241 Endpoint: cloudSpec.Endpoint,
1242 Architectures: arch.AllSupportedArches,1242 Architectures: arch.AllSupportedArches,
12431243
=== modified file 'state/api/client.go'
--- state/api/client.go 2014-03-28 13:31:26 +0000
+++ state/api/client.go 2014-04-03 17:37:27 +0000
@@ -608,6 +608,24 @@
608 return c.call("AddCharm", args, nil)608 return c.call("AddCharm", args, nil)
609}609}
610610
611// ResolveCharms resolves the best available charm URLs with series, for charm
612// locations without a series specified.
613func (c *Client) ResolveCharm(ref charm.Reference) (*charm.URL, error) {
614 args := params.ResolveCharms{References: []charm.Reference{ref}}
615 result := new(params.ResolveCharmResults)
616 if err := c.st.Call("Client", "", "ResolveCharms", args, result); err != nil {
617 return nil, err
618 }
619 if len(result.URLs) == 0 {
620 return nil, fmt.Errorf("unexpected empty response")
621 }
622 urlInfo := result.URLs[0]
623 if urlInfo.Error != "" {
624 return nil, fmt.Errorf("%v", urlInfo.Error)
625 }
626 return urlInfo.URL, nil
627}
628
611func (c *Client) UploadTools(629func (c *Client) UploadTools(
612 toolsFilename string, vers version.Binary, fakeSeries ...string,630 toolsFilename string, vers version.Binary, fakeSeries ...string,
613) (631) (
614632
=== modified file 'state/api/params/params.go'
--- state/api/params/params.go 2014-04-03 02:57:11 +0000
+++ state/api/params/params.go 2014-04-03 17:37:27 +0000
@@ -330,6 +330,22 @@
330 CharmURL string330 CharmURL string
331}331}
332332
333// ResolveCharms stores charm references for a ResolveCharms call.
334type ResolveCharms struct {
335 References []charm.Reference
336}
337
338// ResolveCharmResult holds the result of resolving a charm reference to a URL, or any error that occurred.
339type ResolveCharmResult struct {
340 URL *charm.URL `json:",omitempty"`
341 Error string `json:",omitempty"`
342}
343
344// ResolveCharmResults holds results of the ResolveCharms call.
345type ResolveCharmResults struct {
346 URLs []ResolveCharmResult
347}
348
333// AllWatcherId holds the id of an AllWatcher.349// AllWatcherId holds the id of an AllWatcher.
334type AllWatcherId struct {350type AllWatcherId struct {
335 AllWatcherId string351 AllWatcherId string
336352
=== modified file 'state/apiserver/client/client.go'
--- state/apiserver/client/client.go 2014-03-28 13:31:26 +0000
+++ state/apiserver/client/client.go 2014-04-03 17:37:27 +0000
@@ -567,16 +567,8 @@
567 results := params.AddMachinesResults{567 results := params.AddMachinesResults{
568 Machines: make([]params.AddMachinesResult, len(args.MachineParams)),568 Machines: make([]params.AddMachinesResult, len(args.MachineParams)),
569 }569 }
570
571 var defaultSeries string
572 conf, err := c.api.state.EnvironConfig()
573 if err != nil {
574 return results, err
575 }
576 defaultSeries = conf.DefaultSeries()
577
578 for i, p := range args.MachineParams {570 for i, p := range args.MachineParams {
579 m, err := c.addOneMachine(p, defaultSeries)571 m, err := c.addOneMachine(p)
580 results.Machines[i].Error = common.ServerError(err)572 results.Machines[i].Error = common.ServerError(err)
581 if err == nil {573 if err == nil {
582 results.Machines[i].Machine = m.Id()574 results.Machines[i].Machine = m.Id()
@@ -590,9 +582,13 @@
590 return c.AddMachines(args)582 return c.AddMachines(args)
591}583}
592584
593func (c *Client) addOneMachine(p params.AddMachineParams, defaultSeries string) (*state.Machine, error) {585func (c *Client) addOneMachine(p params.AddMachineParams) (*state.Machine, error) {
594 if p.Series == "" {586 if p.Series == "" {
595 p.Series = defaultSeries587 conf, err := c.api.state.EnvironConfig()
588 if err != nil {
589 return nil, err
590 }
591 p.Series = config.PreferredSeries(conf)
596 }592 }
597 if p.ContainerType != "" {593 if p.ContainerType != "" {
598 // Guard against dubious client by making sure that594 // Guard against dubious client by making sure that
@@ -709,7 +705,7 @@
709 }705 }
710706
711 info := api.EnvironmentInfo{707 info := api.EnvironmentInfo{
712 DefaultSeries: conf.DefaultSeries(),708 DefaultSeries: config.PreferredSeries(conf),
713 ProviderType: conf.Type(),709 ProviderType: conf.Type(),
714 Name: conf.Name(),710 Name: conf.Name(),
715 UUID: env.UUID(),711 UUID: env.UUID(),
@@ -955,6 +951,37 @@
955 return err951 return err
956}952}
957953
954func (c *Client) ResolveCharms(args params.ResolveCharms) (params.ResolveCharmResults, error) {
955 var results params.ResolveCharmResults
956
957 envConfig, err := c.api.state.EnvironConfig()
958 if err != nil {
959 return params.ResolveCharmResults{}, err
960 }
961 repo := config.SpecializeCharmRepo(CharmStore, envConfig)
962
963 for _, ref := range args.References {
964 result := params.ResolveCharmResult{}
965 curl, err := c.resolveCharm(ref, repo)
966 if err != nil {
967 result.Error = err.Error()
968 } else {
969 result.URL = curl
970 }
971 results.URLs = append(results.URLs, result)
972 }
973 return results, nil
974}
975
976func (c *Client) resolveCharm(ref charm.Reference, repo charm.Repository) (*charm.URL, error) {
977 if ref.Schema != "cs" {
978 return nil, fmt.Errorf("only charm store charm references are supported, with cs: schema")
979 }
980
981 // Resolve the charm location with the repository.
982 return repo.Resolve(ref)
983}
984
958// CharmArchiveName returns a string that is suitable as a file name985// CharmArchiveName returns a string that is suitable as a file name
959// in a storage URL. It is constructed from the charm name, revision986// in a storage URL. It is constructed from the charm name, revision
960// and a random UUID string.987// and a random UUID string.
@@ -993,7 +1020,7 @@
993 if err != nil {1020 if err != nil {
994 return err1021 return err
995 }1022 }
996 series = cfg.DefaultSeries()1023 series = config.PreferredSeries(cfg)
997 }1024 }
998 return c.api.state.EnsureAvailability(args.NumStateServers, args.Constraints, series)1025 return c.api.state.EnsureAvailability(args.NumStateServers, args.Constraints, series)
999}1026}
10001027
=== modified file 'state/apiserver/client/client_test.go'
--- state/apiserver/client/client_test.go 2014-04-01 03:37:13 +0000
+++ state/apiserver/client/client_test.go 2014-04-03 17:37:27 +0000
@@ -261,7 +261,7 @@
261 c.Assert(err, gc.IsNil)261 c.Assert(err, gc.IsNil)
262 env, err := s.State.Environment()262 env, err := s.State.Environment()
263 c.Assert(err, gc.IsNil)263 c.Assert(err, gc.IsNil)
264 c.Assert(info.DefaultSeries, gc.Equals, conf.DefaultSeries())264 c.Assert(info.DefaultSeries, gc.Equals, config.PreferredSeries(conf))
265 c.Assert(info.ProviderType, gc.Equals, conf.Type())265 c.Assert(info.ProviderType, gc.Equals, conf.Type())
266 c.Assert(info.Name, gc.Equals, conf.Name())266 c.Assert(info.Name, gc.Equals, conf.Name())
267 c.Assert(info.UUID, gc.Equals, env.UUID())267 c.Assert(info.UUID, gc.Equals, env.UUID())
@@ -1119,8 +1119,12 @@
1119}1119}
11201120
1121func addCharm(c *gc.C, store *coretesting.MockCharmStore, name string) (*charm.URL, charm.Charm) {1121func addCharm(c *gc.C, store *coretesting.MockCharmStore, name string) (*charm.URL, charm.Charm) {
1122 return addSeriesCharm(c, store, "precise", name)
1123}
1124
1125func addSeriesCharm(c *gc.C, store *coretesting.MockCharmStore, series, name string) (*charm.URL, charm.Charm) {
1122 bundle := coretesting.Charms.Bundle(c.MkDir(), name)1126 bundle := coretesting.Charms.Bundle(c.MkDir(), name)
1123 scurl := fmt.Sprintf("cs:precise/%s-%d", name, bundle.Revision())1127 scurl := fmt.Sprintf("cs:%s/%s-%d", series, name, bundle.Revision())
1124 curl := charm.MustParseURL(scurl)1128 curl := charm.MustParseURL(scurl)
1125 err := store.SetCharm(curl, bundle)1129 err := store.SetCharm(curl, bundle)
1126 c.Assert(err, gc.IsNil)1130 c.Assert(err, gc.IsNil)
@@ -1634,7 +1638,7 @@
1634 c.Assert(len(machines), gc.Equals, 3)1638 c.Assert(len(machines), gc.Equals, 3)
1635 for i, machineResult := range machines {1639 for i, machineResult := range machines {
1636 c.Assert(machineResult.Machine, gc.DeepEquals, strconv.Itoa(i))1640 c.Assert(machineResult.Machine, gc.DeepEquals, strconv.Itoa(i))
1637 s.checkMachine(c, machineResult.Machine, config.DefaultSeries, apiParams[i].Constraints.String())1641 s.checkMachine(c, machineResult.Machine, coretesting.FakeDefaultSeries, apiParams[i].Constraints.String())
1638 }1642 }
1639}1643}
16401644
@@ -1684,7 +1688,7 @@
1684 c.Assert(len(machines), gc.Equals, 3)1688 c.Assert(len(machines), gc.Equals, 3)
1685 for i, machineResult := range machines {1689 for i, machineResult := range machines {
1686 c.Assert(machineResult.Machine, gc.DeepEquals, strconv.Itoa(i))1690 c.Assert(machineResult.Machine, gc.DeepEquals, strconv.Itoa(i))
1687 s.checkMachine(c, machineResult.Machine, config.DefaultSeries, apiParams[i].Constraints.String())1691 s.checkMachine(c, machineResult.Machine, coretesting.FakeDefaultSeries, apiParams[i].Constraints.String())
1688 }1692 }
1689}1693}
16901694
@@ -1755,7 +1759,7 @@
1755 c.Assert(machineResult.Error, gc.ErrorMatches, "cannot add a new machine: cannot add a machine with an instance id and no nonce")1759 c.Assert(machineResult.Error, gc.ErrorMatches, "cannot add a new machine: cannot add a machine with an instance id and no nonce")
1756 } else {1760 } else {
1757 c.Assert(machineResult.Machine, gc.DeepEquals, strconv.Itoa(i))1761 c.Assert(machineResult.Machine, gc.DeepEquals, strconv.Itoa(i))
1758 s.checkMachine(c, machineResult.Machine, config.DefaultSeries, apiParams[i].Constraints.String())1762 s.checkMachine(c, machineResult.Machine, coretesting.FakeDefaultSeries, apiParams[i].Constraints.String())
1759 instanceId := fmt.Sprintf("1234-%d", i)1763 instanceId := fmt.Sprintf("1234-%d", i)
1760 s.checkInstance(c, machineResult.Machine, instanceId, "foo", hc, addrs)1764 s.checkInstance(c, machineResult.Machine, instanceId, "foo", hc, addrs)
1761 }1765 }
@@ -1943,6 +1947,57 @@
1943 s.assertUploaded(c, storage, sch.BundleURL(), sch.BundleSha256())1947 s.assertUploaded(c, storage, sch.BundleURL(), sch.BundleSha256())
1944}1948}
19451949
1950var resolveCharmCases = []struct {
1951 schema, defaultSeries, charmName string
1952 parseErr string
1953 resolveErr string
1954}{
1955 {"cs", "precise", "wordpress", "", ""},
1956 {"cs", "trusty", "wordpress", "", ""},
1957 {"cs", "", "wordpress", "", `missing default series, cannot resolve charm url: "cs:wordpress"`},
1958 {"cs", "trusty", "", `charm URL has invalid charm name: "cs:"`, ""},
1959 {"local", "trusty", "wordpress", "", `only charm store charm references are supported, with cs: schema`},
1960 {"cs", "precise", "hl3", "", ""},
1961 {"cs", "trusty", "hl3", "", ""},
1962 {"cs", "", "hl3", "", `missing default series, cannot resolve charm url: \"cs:hl3\"`},
1963}
1964
1965func (s *clientSuite) TestResolveCharm(c *gc.C) {
1966 store, restore := makeMockCharmStore()
1967 defer restore()
1968
1969 for i, test := range resolveCharmCases {
1970 c.Logf("test %d: %#v", i, test)
1971 // Mock charm store will use this to resolve a charm reference.
1972 store.DefaultSeries = test.defaultSeries
1973
1974 client := s.APIState.Client()
1975 ref, series, err := charm.ParseReference(fmt.Sprintf("%s:%s", test.schema, test.charmName))
1976 if test.parseErr == "" {
1977 if !c.Check(err, gc.IsNil) {
1978 continue
1979 }
1980 } else {
1981 c.Assert(err, gc.NotNil)
1982 c.Check(err, gc.ErrorMatches, test.parseErr)
1983 continue
1984 }
1985 c.Check(series, gc.Equals, "")
1986 c.Check(ref.String(), gc.Equals, fmt.Sprintf("%s:%s", test.schema, test.charmName))
1987
1988 curl, err := client.ResolveCharm(ref)
1989 if err == nil {
1990 c.Assert(curl, gc.NotNil)
1991 // Only cs: schema should make it through here
1992 c.Check(curl.String(), gc.Equals, fmt.Sprintf("cs:%s/%s", test.defaultSeries, test.charmName))
1993 c.Check(test.resolveErr, gc.Equals, "")
1994 } else {
1995 c.Check(curl, gc.IsNil)
1996 c.Check(err, gc.ErrorMatches, test.resolveErr)
1997 }
1998 }
1999}
2000
1946func (s *clientSuite) TestAddCharmConcurrently(c *gc.C) {2001func (s *clientSuite) TestAddCharmConcurrently(c *gc.C) {
1947 store, restore := makeMockCharmStore()2002 store, restore := makeMockCharmStore()
1948 defer restore()2003 defer restore()
19492004
=== modified file 'testing/environ.go'
--- testing/environ.go 2014-04-01 08:20:44 +0000
+++ testing/environ.go 2014-04-03 17:37:27 +0000
@@ -28,6 +28,8 @@
28 }28 }
29}29}
3030
31const FakeDefaultSeries = "precise"
32
31// FakeConfig() returns an environment configuration for a33// FakeConfig() returns an environment configuration for a
32// fake provider with all required attributes set.34// fake provider with all required attributes set.
33func FakeConfig() Attrs {35func FakeConfig() Attrs {
@@ -43,7 +45,7 @@
43 "development": false,45 "development": false,
44 "state-port": 19034,46 "state-port": 19034,
45 "api-port": 17777,47 "api-port": 17777,
46 "default-series": config.DefaultSeries,48 "default-series": FakeDefaultSeries,
47 }49 }
48}50}
4951
5052
=== modified file 'worker/provisioner/container_initialisation_test.go'
--- worker/provisioner/container_initialisation_test.go 2014-03-19 03:48:12 +0000
+++ worker/provisioner/container_initialisation_test.go 2014-04-03 17:37:27 +0000
@@ -12,10 +12,10 @@
1212
13 "launchpad.net/juju-core/agent"13 "launchpad.net/juju-core/agent"
14 "launchpad.net/juju-core/environs"14 "launchpad.net/juju-core/environs"
15 "launchpad.net/juju-core/environs/config"
16 "launchpad.net/juju-core/instance"15 "launchpad.net/juju-core/instance"
17 "launchpad.net/juju-core/state"16 "launchpad.net/juju-core/state"
18 apiprovisioner "launchpad.net/juju-core/state/api/provisioner"17 apiprovisioner "launchpad.net/juju-core/state/api/provisioner"
18 coretesting "launchpad.net/juju-core/testing"
19 "launchpad.net/juju-core/utils"19 "launchpad.net/juju-core/utils"
20 "launchpad.net/juju-core/version"20 "launchpad.net/juju-core/version"
21 "launchpad.net/juju-core/worker"21 "launchpad.net/juju-core/worker"
@@ -88,7 +88,7 @@
8888
89 // make a container on the host machine89 // make a container on the host machine
90 template := state.MachineTemplate{90 template := state.MachineTemplate{
91 Series: config.DefaultSeries,91 Series: coretesting.FakeDefaultSeries,
92 Jobs: []state.MachineJob{state.JobHostUnits},92 Jobs: []state.MachineJob{state.JobHostUnits},
93 }93 }
94 container, err := s.State.AddMachineInsideMachine(template, host.Id(), ctype)94 container, err := s.State.AddMachineInsideMachine(template, host.Id(), ctype)
@@ -131,7 +131,7 @@
131 for _, ctype := range instance.ContainerTypes {131 for _, ctype := range instance.ContainerTypes {
132 // create a machine to host the container.132 // create a machine to host the container.
133 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{133 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
134 Series: config.DefaultSeries,134 Series: coretesting.FakeDefaultSeries,
135 Jobs: []state.MachineJob{state.JobHostUnits},135 Jobs: []state.MachineJob{state.JobHostUnits},
136 Constraints: s.defaultConstraints,136 Constraints: s.defaultConstraints,
137 })137 })
@@ -154,7 +154,7 @@
154154
155 // create a machine to host the container.155 // create a machine to host the container.
156 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{156 m, err := s.BackingState.AddOneMachine(state.MachineTemplate{
157 Series: config.DefaultSeries,157 Series: coretesting.FakeDefaultSeries,
158 Jobs: []state.MachineJob{state.JobHostUnits},158 Jobs: []state.MachineJob{state.JobHostUnits},
159 Constraints: s.defaultConstraints,159 Constraints: s.defaultConstraints,
160 })160 })
161161
=== modified file 'worker/provisioner/kvm-broker_test.go'
--- worker/provisioner/kvm-broker_test.go 2014-04-02 11:35:49 +0000
+++ worker/provisioner/kvm-broker_test.go 2014-04-03 17:37:27 +0000
@@ -16,7 +16,6 @@
16 "launchpad.net/juju-core/container/kvm/mock"16 "launchpad.net/juju-core/container/kvm/mock"
17 kvmtesting "launchpad.net/juju-core/container/kvm/testing"17 kvmtesting "launchpad.net/juju-core/container/kvm/testing"
18 "launchpad.net/juju-core/environs"18 "launchpad.net/juju-core/environs"
19 "launchpad.net/juju-core/environs/config"
20 "launchpad.net/juju-core/errors"19 "launchpad.net/juju-core/errors"
21 "launchpad.net/juju-core/instance"20 "launchpad.net/juju-core/instance"
22 instancetest "launchpad.net/juju-core/instance/testing"21 instancetest "launchpad.net/juju-core/instance/testing"
@@ -162,7 +161,7 @@
162161
163 // The kvm provisioner actually needs the machine it is being created on162 // The kvm provisioner actually needs the machine it is being created on
164 // to be in state, in order to get the watcher.163 // to be in state, in order to get the watcher.
165 m, err := s.State.AddMachine(config.DefaultSeries, state.JobHostUnits, state.JobManageEnviron)164 m, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits, state.JobManageEnviron)
166 c.Assert(err, gc.IsNil)165 c.Assert(err, gc.IsNil)
167 err = m.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))166 err = m.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
168 c.Assert(err, gc.IsNil)167 c.Assert(err, gc.IsNil)
@@ -227,7 +226,7 @@
227 defer stop(c, p)226 defer stop(c, p)
228227
229 // Check that an instance is not provisioned when the machine is created.228 // Check that an instance is not provisioned when the machine is created.
230 _, err := s.State.AddMachine(config.DefaultSeries, state.JobHostUnits)229 _, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits)
231 c.Assert(err, gc.IsNil)230 c.Assert(err, gc.IsNil)
232231
233 s.expectNoEvents(c)232 s.expectNoEvents(c)
@@ -244,7 +243,7 @@
244243
245func (s *kvmProvisionerSuite) addContainer(c *gc.C) *state.Machine {244func (s *kvmProvisionerSuite) addContainer(c *gc.C) *state.Machine {
246 template := state.MachineTemplate{245 template := state.MachineTemplate{
247 Series: config.DefaultSeries,246 Series: coretesting.FakeDefaultSeries,
248 Jobs: []state.MachineJob{state.JobHostUnits},247 Jobs: []state.MachineJob{state.JobHostUnits},
249 }248 }
250 container, err := s.State.AddMachineInsideMachine(template, s.machineId, instance.KVM)249 container, err := s.State.AddMachineInsideMachine(template, s.machineId, instance.KVM)
251250
=== modified file 'worker/provisioner/lxc-broker_test.go'
--- worker/provisioner/lxc-broker_test.go 2014-04-02 11:35:49 +0000
+++ worker/provisioner/lxc-broker_test.go 2014-04-03 17:37:27 +0000
@@ -17,7 +17,6 @@
17 "launchpad.net/juju-core/container/lxc/mock"17 "launchpad.net/juju-core/container/lxc/mock"
18 lxctesting "launchpad.net/juju-core/container/lxc/testing"18 lxctesting "launchpad.net/juju-core/container/lxc/testing"
19 "launchpad.net/juju-core/environs"19 "launchpad.net/juju-core/environs"
20 "launchpad.net/juju-core/environs/config"
21 "launchpad.net/juju-core/errors"20 "launchpad.net/juju-core/errors"
22 "launchpad.net/juju-core/instance"21 "launchpad.net/juju-core/instance"
23 instancetest "launchpad.net/juju-core/instance/testing"22 instancetest "launchpad.net/juju-core/instance/testing"
@@ -191,7 +190,7 @@
191190
192 // The lxc provisioner actually needs the machine it is being created on191 // The lxc provisioner actually needs the machine it is being created on
193 // to be in state, in order to get the watcher.192 // to be in state, in order to get the watcher.
194 m, err := s.State.AddMachine(config.DefaultSeries, state.JobHostUnits, state.JobManageEnviron)193 m, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits, state.JobManageEnviron)
195 c.Assert(err, gc.IsNil)194 c.Assert(err, gc.IsNil)
196 err = m.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))195 err = m.SetAddresses(instance.NewAddress("0.1.2.3", instance.NetworkUnknown))
197 c.Assert(err, gc.IsNil)196 c.Assert(err, gc.IsNil)
@@ -260,7 +259,7 @@
260 defer stop(c, p)259 defer stop(c, p)
261260
262 // Check that an instance is not provisioned when the machine is created.261 // Check that an instance is not provisioned when the machine is created.
263 _, err := s.State.AddMachine(config.DefaultSeries, state.JobHostUnits)262 _, err := s.State.AddMachine(coretesting.FakeDefaultSeries, state.JobHostUnits)
264 c.Assert(err, gc.IsNil)263 c.Assert(err, gc.IsNil)
265264
266 s.expectNoEvents(c)265 s.expectNoEvents(c)
@@ -277,7 +276,7 @@
277276
278func (s *lxcProvisionerSuite) addContainer(c *gc.C) *state.Machine {277func (s *lxcProvisionerSuite) addContainer(c *gc.C) *state.Machine {
279 template := state.MachineTemplate{278 template := state.MachineTemplate{
280 Series: config.DefaultSeries,279 Series: coretesting.FakeDefaultSeries,
281 Jobs: []state.MachineJob{state.JobHostUnits},280 Jobs: []state.MachineJob{state.JobHostUnits},
282 }281 }
283 container, err := s.State.AddMachineInsideMachine(template, s.parentMachineId, instance.LXC)282 container, err := s.State.AddMachineInsideMachine(template, s.parentMachineId, instance.LXC)
284283
=== modified file 'worker/provisioner/provisioner_test.go'
--- worker/provisioner/provisioner_test.go 2014-04-02 07:50:15 +0000
+++ worker/provisioner/provisioner_test.go 2014-04-03 17:37:27 +0000
@@ -349,7 +349,7 @@
349349
350func (s *CommonProvisionerSuite) addMachineWithNetworks(includeNetworks, excludeNetworks []string) (*state.Machine, error) {350func (s *CommonProvisionerSuite) addMachineWithNetworks(includeNetworks, excludeNetworks []string) (*state.Machine, error) {
351 return s.BackingState.AddOneMachine(state.MachineTemplate{351 return s.BackingState.AddOneMachine(state.MachineTemplate{
352 Series: config.DefaultSeries,352 Series: coretesting.FakeDefaultSeries,
353 Jobs: []state.MachineJob{state.JobHostUnits},353 Jobs: []state.MachineJob{state.JobHostUnits},
354 Constraints: s.defaultConstraints,354 Constraints: s.defaultConstraints,
355 IncludeNetworks: includeNetworks,355 IncludeNetworks: includeNetworks,
@@ -442,7 +442,7 @@
442442
443 // make a container on the machine we just created443 // make a container on the machine we just created
444 template := state.MachineTemplate{444 template := state.MachineTemplate{
445 Series: config.DefaultSeries,445 Series: coretesting.FakeDefaultSeries,
446 Jobs: []state.MachineJob{state.JobHostUnits},446 Jobs: []state.MachineJob{state.JobHostUnits},
447 }447 }
448 container, err := s.State.AddMachineInsideMachine(template, m.Id(), instance.LXC)448 container, err := s.State.AddMachineInsideMachine(template, m.Id(), instance.LXC)

Subscribers

People subscribed via source and target branches

to status/vote changes: