Merge lp:~waigani/juju-core/get-oldConfig-from-state into lp:~go-bot/juju-core/trunk

Proposed by Jesse Meek
Status: Merged
Approved by: Jesse Meek
Approved revision: no longer in the source branch.
Merged at revision: 2433
Proposed branch: lp:~waigani/juju-core/get-oldConfig-from-state
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 1846 lines (+475/-413)
46 files modified
cmd/juju/authorisedkeys_test.go (+1/-2)
cmd/juju/environment.go (+2/-20)
cmd/juju/environment_test.go (+2/-1)
cmd/juju/upgradejuju_test.go (+7/-14)
cmd/jujud/machine_test.go (+3/-8)
environs/config.go (+5/-5)
environs/config/config.go (+9/-0)
environs/statepolicy.go (+10/-0)
environs/testing/tools.go (+1/-7)
juju/conn.go (+3/-7)
juju/conn_test.go (+4/-10)
juju/testing/conn.go (+5/-1)
juju/testing/repo.go (+2/-5)
juju/testing/utils.go (+0/-14)
state/api/common/testing/environwatcher.go (+16/-7)
state/api/firewaller/state_test.go (+4/-7)
state/api/keymanager/client_test.go (+1/-2)
state/api/keyupdater/authorisedkeys_test.go (+1/-1)
state/api/logger/logger_test.go (+1/-1)
state/apiserver/client/client.go (+15/-30)
state/apiserver/client/client_test.go (+3/-12)
state/apiserver/keymanager/keymanager.go (+21/-21)
state/apiserver/keymanager/keymanager_test.go (+1/-2)
state/apiserver/keyupdater/authorisedkeys_test.go (+1/-1)
state/apiserver/logger/logger_test.go (+1/-1)
state/apiserver/provisioner/provisioner_test.go (+3/-6)
state/apiserver/rsyslog/rsyslog.go (+2/-10)
state/configvalidator_test.go (+114/-0)
state/conn_test.go (+9/-1)
state/initialize_test.go (+5/-5)
state/machine_test.go (+2/-3)
state/policy.go (+28/-0)
state/state.go (+48/-10)
state/state_test.go (+50/-19)
state/testing/agent.go (+1/-1)
state/testing/config.go (+0/-22)
upgrades/deprecatedattributes.go (+8/-21)
upgrades/deprecatedattributes_test.go (+3/-6)
upgrades/rsyslogport.go (+2/-9)
worker/authenticationworker/worker_test.go (+1/-2)
worker/environ_test.go (+17/-13)
worker/firewaller/firewaller_test.go (+17/-38)
worker/instancepoller/observer_test.go (+12/-15)
worker/machineenvironmentworker/machineenvironmentworker_test.go (+8/-8)
worker/provisioner/provisioner_test.go (+23/-39)
worker/uniter/uniter_test.go (+3/-6)
To merge this branch: bzr merge lp:~waigani/juju-core/get-oldConfig-from-state
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+209569@code.launchpad.net

Commit message

Update and Validate Environ Config in State

The main business logic happens in state/state.go. The bulk of the other
changes are mechanical i.e. updating method calls. There are a few things going on:

-Explicitly add/update or remove attributes with state.UpdateEnvironConf, which
replaces state.SetEnvironConf.
- Add ConfigValidator to state.Policy interface.
- Validate environment configuration within state.
    - build new config from UpdateEnvironConf args, get old config from state.
    - pass both configs to st.validate which use the environ policy
 ConfigValidator to get the correct validation method.
    - use the validated config to make the actual updates in state.
- Update or delete tests that rely on an invalid configuration being set, as
    this is now not possible.

Description of the change

Update and Validate Environ Config in State

The main business logic happens in state/state.go. The bulk of the other
changes are mechanical i.e. updating method calls. There are a few things going on:

-Explicitly add/update or remove attributes with state.UpdateEnvironConf, which
replaces state.SetEnvironConf.
- Add ConfigValidator to state.Policy interface.
- Validate environment configuration within state.
    - build new config from UpdateEnvironConf args, get old config from state.
    - pass both configs to st.validate which use the environ policy
 ConfigValidator to get the correct validation method.
    - use the validated config to make the actual updates in state.
- Update or delete tests that rely on an invalid configuration being set, as
    this is now not possible.

A follow up branch will use txn and a retry loop to address a race condition in
updating state config to ensure that concurrent updates to state config do not corrupt one
another.

https://codereview.appspot.com/70190050/

To post a comment you must log in.
Revision history for this message
Andrew Wilkins (axwalk) wrote :

Some preliminary comments. I've only really looked at state.go.

https://codereview.appspot.com/70190050/diff/1/state/state.go
File state/state.go (left):

https://codereview.appspot.com/70190050/diff/1/state/state.go#oldcode282
state/state.go:282: _, err = settings.Write()
Write isn't really good enough here; this does not address the deleted
TODO. The update to settings should assert that there has been no change
to settings since st.EnvironConfig() was called; otherwise the
validation is not complete.

https://codereview.appspot.com/70190050/diff/1/state/state.go
File state/state.go (right):

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode259
state/state.go:259: func (st *State)
VaidateUpdateEnvironConfig(updateAttrs map[string]interface{},
removeAttrs []string, oldConfig *config.Config) error {
s/Vaidate/Validate/
also, doesn't need to be exported does it?

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode264
state/state.go:264: // Build new config with attributes to add/update
You can get rid of the comments, if statement, forward declared
newConfig/err vars, and just replace with:

     newConfig, err := oldConfig.Apply(updateAttrs)
     if err != nil {
         return err
     }

Apply doesn't care if updateAttrs is nil or empty.

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode274
state/state.go:274: if len(removeAttrs) != 0 {
And then since newConfig exists unconditionally:

     newConfig, err = newConfig.Remove(removeAttrs)
     if err != nil {
         return err
     }

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode304
state/state.go:304: func (st *State) SetEnvironConfig(attrs
map[string]interface{}) error {
Why do we still need SetEnvironConfig? This still has the old race
conditions. *If* it's needed, then SetEnvironConfig and
UpdateEnvironConfig should use a common method that takes a
*state.Settings as input and does the no-concurrent-change check on
that.

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode327
state/state.go:327: oldConfig, err := st.EnvironConfig()
This does a readSettings, so you're reading settings twice. I think it'd
be preferable to just do a readSettings and use its Map() to create a
config.

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode333
state/state.go:333: err = st.VaidateUpdateEnvironConfig(updateAttrs,
removeAttrs, oldConfig)
Since ValidateUpdateEnvironConfig updates the config with attributes to
validate, I wonder if it's worthwhile even having a separate method.
You're duplicating work here by updating settings.

I think it would be simpler to just:
    1. get settings, and create a config from them
    2. apply changes to get a new config, check validity
    3. do something *like* replaceSettingsOp (see settings.go), but
passing in the *state.Settings

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode351
state/state.go:351: // Add/Update attributes.
These comments aren't really useful, the code speaks for itself.

https://codereview.appspot.com/70190050/

Revision history for this message
Jesse Meek (waigani) wrote :
Download full text (5.6 KiB)

Reviewers: mp+209569_code.launchpad.net, axw,

https://codereview.appspot.com/70190050/diff/1/state/state.go
File state/state.go (left):

https://codereview.appspot.com/70190050/diff/1/state/state.go#oldcode282
state/state.go:282: _, err = settings.Write()
On 2014/03/06 04:19:17, axw wrote:
> Write isn't really good enough here; this does not address the deleted
TODO. The
> update to settings should assert that there has been no change to
settings since
> st.EnvironConfig() was called; otherwise the validation is not
complete.

fwereade wanted a txn retry loop, ensuring the underlying settings had
not been changed, in client.EnvironmentSet
(https://codereview.appspot.com/63790045/diff/40001/state/apiserver/client/client.go#newcode791).
As this is a WIP, I have not done it yet. I can make a TODO in
client.EnvironmentSet and write the txn retry loop in a follow up
branch?

https://codereview.appspot.com/70190050/diff/1/state/state.go
File state/state.go (right):

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode259
state/state.go:259: func (st *State)
VaidateUpdateEnvironConfig(updateAttrs map[string]interface{},
removeAttrs []string, oldConfig *config.Config) error {
On 2014/03/06 04:19:17, axw wrote:
> s/Vaidate/Validate/
> also, doesn't need to be exported does it?

Good catch!

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode264
state/state.go:264: // Build new config with attributes to add/update
On 2014/03/06 04:19:17, axw wrote:
> You can get rid of the comments, if statement, forward declared
newConfig/err
> vars, and just replace with:

> newConfig, err := oldConfig.Apply(updateAttrs)
> if err != nil {
> return err
> }

> Apply doesn't care if updateAttrs is nil or empty.

Done.

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode274
state/state.go:274: if len(removeAttrs) != 0 {
On 2014/03/06 04:19:17, axw wrote:
> And then since newConfig exists unconditionally:

> newConfig, err = newConfig.Remove(removeAttrs)
> if err != nil {
> return err
> }

Done.

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode304
state/state.go:304: func (st *State) SetEnvironConfig(attrs
map[string]interface{}) error {
On 2014/03/06 04:19:17, axw wrote:
> Why do we still need SetEnvironConfig? This still has the old race
conditions.
> *If* it's needed, then SetEnvironConfig and UpdateEnvironConfig should
use a
> common method that takes a *state.Settings as input and does the
> no-concurrent-change check on that.

It was needed by testing.ChangeEnvironConfig. ChangeEnvironConfig is
only used in two places, but it is actually easier to use
UpdateEnvironConfig directly instead. So I would be in favour of
deleting SetEnvironConfig and ChangeEnvironConfig.

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode327
state/state.go:327: oldConfig, err := st.EnvironConfig()
On 2014/03/06 04:19:17, axw wrote:
> This does a readSettings, so you're reading settings twice. I think
it'd be
> preferable to just do a readSettings and use its Map() to create a
config.

Done.

https://codereview.appspot.com/70190050/diff/1/state/stat...

Read more...

Revision history for this message
Andrew Wilkins (axwalk) wrote :
Download full text (3.5 KiB)

https://codereview.appspot.com/70190050/diff/1/state/state.go
File state/state.go (left):

https://codereview.appspot.com/70190050/diff/1/state/state.go#oldcode282
state/state.go:282: _, err = settings.Write()
On 2014/03/06 08:17:48, waigani wrote:
> On 2014/03/06 04:19:17, axw wrote:
> > Write isn't really good enough here; this does not address the
deleted TODO.
> The
> > update to settings should assert that there has been no change to
settings
> since
> > st.EnvironConfig() was called; otherwise the validation is not
complete.

> fwereade wanted a txn retry loop, ensuring the underlying settings had
not been
> changed, in client.EnvironmentSet

(https://codereview.appspot.com/63790045/diff/40001/state/apiserver/client/client.go#newcode791).
> As this is a WIP, I have not done it yet. I can make a TODO in
> client.EnvironmentSet and write the txn retry loop in a follow up
branch?

The assertion is a prerequisite of the looping. The assertion is what
ensures that the settings haven't been changed concurrently. If the
settings are changed underfoot, then the transaction fails with
txn.ErrAborted.

The assertion must happen here, whereas looping may happen here or in
the caller. There's basically no point in making any of these changes
unless that assertion is in place.

https://codereview.appspot.com/70190050/diff/1/state/state.go
File state/state.go (right):

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode304
state/state.go:304: func (st *State) SetEnvironConfig(attrs
map[string]interface{}) error {
On 2014/03/06 08:17:48, waigani wrote:
> On 2014/03/06 04:19:17, axw wrote:
> > Why do we still need SetEnvironConfig? This still has the old race
conditions.
> > *If* it's needed, then SetEnvironConfig and UpdateEnvironConfig
should use a
> > common method that takes a *state.Settings as input and does the
> > no-concurrent-change check on that.

> It was needed by testing.ChangeEnvironConfig. ChangeEnvironConfig is
only used
> in two places, but it is actually easier to use UpdateEnvironConfig
directly
> instead. So I would be in favour of deleting SetEnvironConfig and
> ChangeEnvironConfig.

ChangeEnvironConfig can be modified to compute a delta and pass it into
UpdateEnvironConfig. I know it's a bit arse about, but I don't think we
should be exposing ourselves to bugs just to simplify a test. If you can
just get rid of ChangeEnvironConfig, though, that may be better.

https://codereview.appspot.com/70190050/diff/1/state/state.go#newcode333
state/state.go:333: err = st.VaidateUpdateEnvironConfig(updateAttrs,
removeAttrs, oldConfig)
On 2014/03/06 08:17:48, waigani wrote:
> On 2014/03/06 04:19:17, axw wrote:
> > Since ValidateUpdateEnvironConfig updates the config with attributes
to
> > validate, I wonder if it's worthwhile even having a separate method.
You're
> > duplicating work here by updating settings.
> >
> > I think it would be simpler to just:
> > 1. get settings, and create a config from them
> > 2. apply changes to get a new config, check validity
> > 3. do something *like* replaceSettingsOp (see settings.go), but
passing in
> > the *state.Settings

> Do you think something *like* replaceSettingsOp s...

Read more...

Revision history for this message
Jesse Meek (waigani) wrote :
Revision history for this message
Jesse Meek (waigani) wrote :
Revision history for this message
Jesse Meek (waigani) wrote :
Revision history for this message
Andrew Wilkins (axwalk) wrote :
Download full text (7.6 KiB)

I haven't reviewed everything, this should keep you going for a while
though.

In general: we should not be dropping any tests that are not
*guaranteed* to never work. Since UpdateEnvironConfig is not completely
fixed yet, the tests should remain. This may involve hacking around
validation with a nil policy.

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

https://codereview.appspot.com/70190050/diff/60001/cmd/juju/environment.go#newcode166
cmd/juju/environment.go:166: return
conn.State.UpdateEnvironConfig(c.values, []string{})
Just nil is fine.

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

https://codereview.appspot.com/70190050/diff/60001/cmd/juju/environment_test.go#newcode173
cmd/juju/environment_test.go:173: c.Check(err, gc.ErrorMatches, `no
registered provider for "foo"`)
This has nothing to do with attribute mutability, so doesn't belong
here. Why not just change the value in the map to a real provider type?
You will need to make sure the provider is registered by importing its
package.

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

https://codereview.appspot.com/70190050/diff/60001/environs/config.go#newcode138
environs/config.go:138: func Provider(providerType string)
(EnvironProvider, error) {
Making cosmetic changes is fine, but it's best not to mix cosmetic
changes (or refactoring) with functional changes. Otherwise I'm
scrutinising everything to make sure there's no functional change, and
the review takes longer than necessary.

https://codereview.appspot.com/70190050/diff/60001/environs/testing/tools.go
File environs/testing/tools.go (right):

https://codereview.appspot.com/70190050/diff/60001/environs/testing/tools.go#newcode447
environs/testing/tools.go:447: err = st.UpdateEnvironConfig(attrs,
[]string{})
Just pass in the one attribute in a new map. FYI, you can make maps with
map literals like so:
   map[string]interface{}{"ssl-hostname-verification":
SSLHostnameVerification}

https://codereview.appspot.com/70190050/diff/60001/juju/conn.go
File juju/conn.go (right):

https://codereview.appspot.com/70190050/diff/60001/juju/conn.go#newcode155
juju/conn.go:155: return c.State.UpdateEnvironConfig(attrs, []string{})
Just pass secrets here, and don't bother updating attrs in the loop.

https://codereview.appspot.com/70190050/diff/60001/juju/conn_test.go
File juju/conn_test.go (right):

https://codereview.appspot.com/70190050/diff/60001/juju/conn_test.go#newcode152
juju/conn_test.go:152: // Removing the secret from state should not be
possible, as
Well, that's only true for the dummy provider. Real providers don't have
defaults for secrets. For a real provider you'd have a different
problem: validation would fail because a config without the secrets is
invalid.

In this test it makes sense to disable validation while you're removing
the attribute.

https://codereview.appspot.com/70190050/diff/60001/state/api/firewaller/state_test.go
File state/api/firewaller/state_test.go (right):

https://codereview.appspot.com/70190050/diff/60001/...

Read more...

Revision history for this message
Jesse Meek (waigani) wrote :
Download full text (7.9 KiB)

Please take a look.

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

https://codereview.appspot.com/70190050/diff/60001/cmd/juju/environment.go#newcode166
cmd/juju/environment.go:166: return
conn.State.UpdateEnvironConfig(c.values, []string{})
On 2014/03/10 03:41:54, axw wrote:
> Just nil is fine.

Done.

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

https://codereview.appspot.com/70190050/diff/60001/cmd/juju/environment_test.go#newcode173
cmd/juju/environment_test.go:173: c.Check(err, gc.ErrorMatches, `no
registered provider for "foo"`)
On 2014/03/10 03:41:54, axw wrote:
> This has nothing to do with attribute mutability, so doesn't belong
here. Why
> not just change the value in the map to a real provider type? You will
need to
> make sure the provider is registered by importing its package.

Done.

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

https://codereview.appspot.com/70190050/diff/60001/environs/config.go#newcode138
environs/config.go:138: func Provider(providerType string)
(EnvironProvider, error) {
On 2014/03/10 03:41:54, axw wrote:
> Making cosmetic changes is fine, but it's best not to mix cosmetic
changes (or
> refactoring) with functional changes. Otherwise I'm scrutinising
everything to
> make sure there's no functional change, and the review takes longer
than
> necessary.

Sorry about that. This branch is actually three squashed together. These
changes are in response to William's review of one of those branches.

https://codereview.appspot.com/70190050/diff/60001/juju/conn.go
File juju/conn.go (right):

https://codereview.appspot.com/70190050/diff/60001/juju/conn.go#newcode155
juju/conn.go:155: return c.State.UpdateEnvironConfig(attrs, []string{})
On 2014/03/10 03:41:54, axw wrote:
> Just pass secrets here, and don't bother updating attrs in the loop.

Done. I couldn't cast or assert secrets (which is map[string]string) to
map[string]interface{}, so I created a new var secretAttrs with that
type instead.

https://codereview.appspot.com/70190050/diff/60001/state/api/firewaller/state_test.go
File state/api/firewaller/state_test.go (right):

https://codereview.appspot.com/70190050/diff/60001/state/api/firewaller/state_test.go#newcode94
state/api/firewaller/state_test.go:94: // TODO [waigani] test removing
an attribute.
On 2014/03/10 03:41:54, axw wrote:
> I don't think deferral is warranted here. Not sure it's really
necessary to add
> the test either, though: firewaller doesn't care about attributes
being removed.

Done. TODO removed.

https://codereview.appspot.com/70190050/diff/60001/state/api/firewaller/state_test.go#newcode94
state/api/firewaller/state_test.go:94: // TODO [waigani] test removing
an attribute.
On 2014/03/10 03:41:54, axw wrote:
> I don't think deferral is warranted here. Not sure it's really
necessary to add
> the test either, though: firewaller doesn't care about attributes
being removed.

https://codereview.appspot.com/70190050/diff/60001/state/apiserver/client/client.go
File state/apiserver/client/client...

Read more...

Revision history for this message
Jesse Meek (waigani) wrote :

Yikes. I really dug a hole for myself with such a big branch. I've
finally merged in trunk, all tests pass and review comments addressed.
Let me know if I've missed anything.

https://codereview.appspot.com/70190050/

Revision history for this message
Andrew Wilkins (axwalk) wrote :
Download full text (7.9 KiB)

Getting there.

https://codereview.appspot.com/70190050/diff/60001/state/apiserver/keymanager/keymanager.go
File state/apiserver/keymanager/keymanager.go (left):

https://codereview.appspot.com/70190050/diff/60001/state/apiserver/keymanager/keymanager.go#oldcode311
state/apiserver/keymanager/keymanager.go:311: // For now, authorised
keys are global, common to all users.
On 2014/03/13 01:02:03, waigani wrote:
> On 2014/03/10 03:41:54, axw wrote:
> > This comment didn't need to be deleted

> I'm confused. The comment is still there on line 312?

Huh, I must've been on crack. Never mind.

https://codereview.appspot.com/70190050/diff/60001/worker/environ_test.go
File worker/environ_test.go (left):

https://codereview.appspot.com/70190050/diff/60001/worker/environ_test.go#oldcode49
worker/environ_test.go:49: // Create an invalid config by taking the
current config and
On 2014/03/13 01:02:03, waigani wrote:
> On 2014/03/10 03:41:54, axw wrote:
> > This shouldn't go until UpdateEnvironConfig is completely fixed.

> I see that TestInvalidConfig is no longer in trunk, so I assume to is
fine to
> leave this deleted?

I just pulled trunk and it is still there. Not sure what you're looking
at...
http://bazaar.launchpad.net/~go-bot/juju-core/trunk/view/head:/worker/environ_test.go#L48

https://codereview.appspot.com/70190050/diff/60001/worker/machineenvironmentworker/machineenvironmentworker_test.go
File worker/machineenvironmentworker/machineenvironmentworker_test.go
(right):

https://codereview.appspot.com/70190050/diff/60001/worker/machineenvironmentworker/machineenvironmentworker_test.go#newcode128
worker/machineenvironmentworker/machineenvironmentworker_test.go:128:
attrs := map[string]interface{}{}
On 2014/03/13 01:02:03, waigani wrote:
> On 2014/03/10 03:41:54, axw wrote:
> > The conventional way to write this is
> > attrs := make(map[string]interface{})

> Ah. There are a lot of map[string]interface{}{} around (from my code
and
> others). Shall I put off changing these to another day/branch?

No problems, just leave them.

https://codereview.appspot.com/70190050/diff/80001/cmd/juju/environment_test.go
File cmd/juju/environment_test.go (right):

https://codereview.appspot.com/70190050/diff/80001/cmd/juju/environment_test.go#newcode14
cmd/juju/environment_test.go:14: _
"launchpad.net/juju-core/provider/dummy"
dummy will already be imported by the base test suite, but you should
import local here.

https://codereview.appspot.com/70190050/diff/80001/environs/statepolicy.go
File environs/statepolicy.go (right):

https://codereview.appspot.com/70190050/diff/80001/environs/statepolicy.go#newcode43
environs/statepolicy.go:43: if p, ok :=
provider.(state.ConfigValidator); ok {
No need for the assertion here, this is always going to be true for
Provider. Just go ahead and "return p, nil".

https://codereview.appspot.com/70190050/diff/80001/juju/conn.go
File juju/conn.go (right):

https://codereview.appspot.com/70190050/diff/80001/juju/conn.go#newcode146
juju/conn.go:146: var secretAttrs map[string]interface{}
You need to initialise the map, like so:
     secretAttrs := make(map[string]interface{})

https://codereview.appspot.com/70190050/diff/80001/juju...

Read more...

Revision history for this message
Jesse Meek (waigani) wrote :
Download full text (7.1 KiB)

Please take a look.

https://codereview.appspot.com/70190050/diff/60001/worker/environ_test.go
File worker/environ_test.go (left):

https://codereview.appspot.com/70190050/diff/60001/worker/environ_test.go#oldcode49
worker/environ_test.go:49: // Create an invalid config by taking the
current config and
On 2014/03/13 03:07:14, axw wrote:
> On 2014/03/13 01:02:03, waigani wrote:
> > On 2014/03/10 03:41:54, axw wrote:
> > > This shouldn't go until UpdateEnvironConfig is completely fixed.
> >
> > I see that TestInvalidConfig is no longer in trunk, so I assume to
is fine to
> > leave this deleted?

> I just pulled trunk and it is still there. Not sure what you're
looking at...

http://bazaar.launchpad.net/~go-bot/juju-core/trunk/view/head:/worker/environ_test.go#L48

Done. I confused my working branch with trunk - facepalm.

https://codereview.appspot.com/70190050/diff/80001/cmd/juju/environment_test.go
File cmd/juju/environment_test.go (right):

https://codereview.appspot.com/70190050/diff/80001/cmd/juju/environment_test.go#newcode14
cmd/juju/environment_test.go:14: _
"launchpad.net/juju-core/provider/dummy"
On 2014/03/13 03:07:14, axw wrote:
> dummy will already be imported by the base test suite, but you should
import
> local here.

Done. Yeah, like in the line above - second facepalm.

https://codereview.appspot.com/70190050/diff/80001/juju/conn.go
File juju/conn.go (right):

https://codereview.appspot.com/70190050/diff/80001/juju/conn.go#newcode146
juju/conn.go:146: var secretAttrs map[string]interface{}
On 2014/03/13 03:07:14, axw wrote:
> You need to initialise the map, like so:
> secretAttrs := make(map[string]interface{})

Done.

https://codereview.appspot.com/70190050/diff/80001/juju/conn.go#newcode153
juju/conn.go:153: secretAttrs[k] = v
On 2014/03/13 03:07:14, axw wrote:
> This will panic, since you didn't initialise the map. I guess you
didn't run the
> tests after this change?

Done. Strange, I guess not. Passes now.

https://codereview.appspot.com/70190050/diff/80001/juju/conn_test.go
File juju/conn_test.go (right):

https://codereview.appspot.com/70190050/diff/80001/juju/conn_test.go#newcode153
juju/conn_test.go:153: // UpdateEnvironConfig vaidates the config and
resets the "secret"
On 2014/03/13 03:07:14, axw wrote:
> s/vaidates/validates/

Done.

https://codereview.appspot.com/70190050/diff/80001/juju/conn_test.go#newcode154
juju/conn_test.go:154: // setting.
On 2014/03/13 03:07:14, axw wrote:
> In normal circumstances it shouldn't be possible, but this is
specifically for a
> test. Not removing it completely misses the point of the test: that if
the
> attributes *aren't* in state, they will be added. This is testing
compatibility
> with legacy code.

> Please put this back to how it was, using a nil policy to override the
removal
> prevention.

Done.

https://codereview.appspot.com/70190050/diff/80001/state/api/common/testing/environwatcher.go
File state/api/common/testing/environwatcher.go (right):

https://codereview.appspot.com/70190050/diff/80001/state/api/common/testing/environwatcher.go#newcode91
state/api/common/testing/environwatcher.go:91: // TODO [waigani] test
removing an attribute.
On 2014/03/13 03:07:14, axw w...

Read more...

Revision history for this message
Jesse Meek (waigani) wrote :
Revision history for this message
Andrew Wilkins (axwalk) wrote :
Download full text (3.6 KiB)

A few minor things, then it should be good to land.

https://codereview.appspot.com/70190050/diff/100001/environs/statepolicy.go
File environs/statepolicy.go (right):

https://codereview.appspot.com/70190050/diff/100001/environs/statepolicy.go#newcode43
environs/statepolicy.go:43: return provider.(state.ConfigValidator), nil
No need to type assert, since EnvironProvider implements
state.ConfigValidator. Just "return provider, nil".

https://codereview.appspot.com/70190050/diff/100001/environs/statepolicy.go#newcode44
environs/statepolicy.go:44: return nil,
errors.NewNotImplementedError("ConfigValidator")
Lose the second return

https://codereview.appspot.com/70190050/diff/100001/juju/conn_test.go
File juju/conn_test.go (right):

https://codereview.appspot.com/70190050/diff/100001/juju/conn_test.go#newcode143
juju/conn_test.go:143: //Use a state without a nil policy, which will
allow us to set an invalid config
Please leave a space after //, preferably end sentence with a .

https://codereview.appspot.com/70190050/diff/100001/state/api/common/testing/environwatcher.go
File state/api/common/testing/environwatcher.go (right):

https://codereview.appspot.com/70190050/diff/100001/state/api/common/testing/environwatcher.go#newcode92
state/api/common/testing/environwatcher.go:92: err =
s.st.UpdateEnvironConfig(map[string]interface{}{}, []string{"foo"}, nil)
check error

https://codereview.appspot.com/70190050/diff/100001/state/api/common/testing/environwatcher.go#newcode94
state/api/common/testing/environwatcher.go:94: c.Logf("!!!!! %#v",
cf.AllAttrs()["logging-config"])
leftover logging

https://codereview.appspot.com/70190050/diff/100001/state/state.go
File state/state.go (right):

https://codereview.appspot.com/70190050/diff/100001/state/state.go#newcode279
state/state.go:279: type ValidateFn func(updateAttrs
map[string]interface{}, removeAttrs []string, oldConfig *config.Config)
error
This could do with a better name. Out of context (e.g. in godoc), it
wouldn't really be meaningful. I suggest ValidateConfigFunc (Func,
rather than Fn, to be consistent with function types in Go's standard
library).

https://codereview.appspot.com/70190050/diff/100001/state/state.go#newcode316
state/state.go:316: //use validCfg to update settings
Just drop this comment

https://codereview.appspot.com/70190050/diff/100001/state/state_test.go
File state/state_test.go (right):

https://codereview.appspot.com/70190050/diff/100001/state/state_test.go#newcode1689
state/state_test.go:1689: if v, found := updateAttrs["agent-version"];
found {
All we really care about is: did the callback get called with the
appropriate arguments, and does its result have the appropriate effect?

So there's some missing coverage there: there's no validation of the
input, and there's no test for a non-nil validator with a nil result
(i.e. has no effect on normal operation).

https://codereview.appspot.com/70190050/diff/100001/state/state_test.go#newcode1818
state/state_test.go:1818: err = settings.Update(nil, bson.D{{"$set",
bson.D{{"name", "foo"}}}})
What is this doing here? Is this because UpdateEnvironConfig won't
change the "name" attribute? If it's needed, you should probably be
using ...

Read more...

Revision history for this message
Jesse Meek (waigani) wrote :
Download full text (4.2 KiB)

Please take a look.

https://codereview.appspot.com/70190050/diff/100001/environs/statepolicy.go
File environs/statepolicy.go (right):

https://codereview.appspot.com/70190050/diff/100001/environs/statepolicy.go#newcode43
environs/statepolicy.go:43: return provider.(state.ConfigValidator), nil
On 2014/03/17 12:15:56, axw wrote:
> No need to type assert, since EnvironProvider implements
state.ConfigValidator.
> Just "return provider, nil".

Done.

https://codereview.appspot.com/70190050/diff/100001/environs/statepolicy.go#newcode44
environs/statepolicy.go:44: return nil,
errors.NewNotImplementedError("ConfigValidator")
On 2014/03/17 12:15:56, axw wrote:
> Lose the second return

Done.

https://codereview.appspot.com/70190050/diff/100001/juju/conn_test.go
File juju/conn_test.go (right):

https://codereview.appspot.com/70190050/diff/100001/juju/conn_test.go#newcode143
juju/conn_test.go:143: //Use a state without a nil policy, which will
allow us to set an invalid config
On 2014/03/17 12:15:56, axw wrote:
> Please leave a space after //, preferably end sentence with a .

Done.

https://codereview.appspot.com/70190050/diff/100001/state/api/common/testing/environwatcher.go
File state/api/common/testing/environwatcher.go (right):

https://codereview.appspot.com/70190050/diff/100001/state/api/common/testing/environwatcher.go#newcode92
state/api/common/testing/environwatcher.go:92: err =
s.st.UpdateEnvironConfig(map[string]interface{}{}, []string{"foo"}, nil)
On 2014/03/17 12:15:56, axw wrote:
> check error

Done.

https://codereview.appspot.com/70190050/diff/100001/state/api/common/testing/environwatcher.go#newcode94
state/api/common/testing/environwatcher.go:94: c.Logf("!!!!! %#v",
cf.AllAttrs()["logging-config"])
On 2014/03/17 12:15:56, axw wrote:
> leftover logging

Done.

https://codereview.appspot.com/70190050/diff/100001/state/state.go
File state/state.go (right):

https://codereview.appspot.com/70190050/diff/100001/state/state.go#newcode279
state/state.go:279: type ValidateFn func(updateAttrs
map[string]interface{}, removeAttrs []string, oldConfig *config.Config)
error
On 2014/03/17 12:15:56, axw wrote:
> This could do with a better name. Out of context (e.g. in godoc), it
wouldn't
> really be meaningful. I suggest ValidateConfigFunc (Func, rather than
Fn, to be
> consistent with function types in Go's standard library).

Done.

https://codereview.appspot.com/70190050/diff/100001/state/state.go#newcode316
state/state.go:316: //use validCfg to update settings
On 2014/03/17 12:15:56, axw wrote:
> Just drop this comment

Done.

https://codereview.appspot.com/70190050/diff/100001/state/state_test.go
File state/state_test.go (right):

https://codereview.appspot.com/70190050/diff/100001/state/state_test.go#newcode1689
state/state_test.go:1689: if v, found := updateAttrs["agent-version"];
found {
On 2014/03/17 12:15:56, axw wrote:
> All we really care about is: did the callback get called with the
appropriate
> arguments, and does its result have the appropriate effect?

> So there's some missing coverage there: there's no validation of the
input, and
> there's no test for a non-nil validator with a nil result (i.e. has no
effect on
> normal operati...

Read more...

Revision history for this message
Jesse Meek (waigani) wrote :
Revision history for this message
Andrew Wilkins (axwalk) wrote :

On 2014/03/17 22:48:37, waigani wrote:

LGTM. Thanks for slogging through it.

https://codereview.appspot.com/70190050/

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'cmd/juju/authorisedkeys_test.go'
--- cmd/juju/authorisedkeys_test.go 2014-01-22 22:48:54 +0000
+++ cmd/juju/authorisedkeys_test.go 2014-03-18 02:38:23 +0000
@@ -13,7 +13,6 @@
13 jujutesting "launchpad.net/juju-core/juju/testing"13 jujutesting "launchpad.net/juju-core/juju/testing"
14 keymanagerserver "launchpad.net/juju-core/state/apiserver/keymanager"14 keymanagerserver "launchpad.net/juju-core/state/apiserver/keymanager"
15 keymanagertesting "launchpad.net/juju-core/state/apiserver/keymanager/testing"15 keymanagertesting "launchpad.net/juju-core/state/apiserver/keymanager/testing"
16 statetesting "launchpad.net/juju-core/state/testing"
17 coretesting "launchpad.net/juju-core/testing"16 coretesting "launchpad.net/juju-core/testing"
18 "launchpad.net/juju-core/testing/testbase"17 "launchpad.net/juju-core/testing/testbase"
19 sshtesting "launchpad.net/juju-core/utils/ssh/testing"18 sshtesting "launchpad.net/juju-core/utils/ssh/testing"
@@ -103,7 +102,7 @@
103102
104func (s *keySuiteBase) setAuthorisedKeys(c *gc.C, keys ...string) {103func (s *keySuiteBase) setAuthorisedKeys(c *gc.C, keys ...string) {
105 keyString := strings.Join(keys, "\n")104 keyString := strings.Join(keys, "\n")
106 err := statetesting.UpdateConfig(s.State, map[string]interface{}{"authorized-keys": keyString})105 err := s.State.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": keyString}, nil, nil)
107 c.Assert(err, gc.IsNil)106 c.Assert(err, gc.IsNil)
108 envConfig, err := s.State.EnvironConfig()107 envConfig, err := s.State.EnvironConfig()
109 c.Assert(err, gc.IsNil)108 c.Assert(err, gc.IsNil)
110109
=== modified file 'cmd/juju/environment.go'
--- cmd/juju/environment.go 2013-12-17 18:21:26 +0000
+++ cmd/juju/environment.go 2014-03-18 02:38:23 +0000
@@ -162,26 +162,8 @@
162 }162 }
163 defer conn.Close()163 defer conn.Close()
164164
165 // Here is the magic around setting the attributes:165 // Update state config with new values
166 // TODO(thumper): get this magic under test somewhere, and update other call-sites to use it.166 return conn.State.UpdateEnvironConfig(c.values, nil, nil)
167 // Get the existing environment config from the state.
168 oldConfig, err := conn.State.EnvironConfig()
169 if err != nil {
170 return err
171 }
172 // Apply the attributes specified for the command to the state config.
173 newConfig, err := oldConfig.Apply(c.values)
174 if err != nil {
175 return err
176 }
177 // Now validate this new config against the existing config via the provider.
178 provider := conn.Environ.Provider()
179 newProviderConfig, err := provider.Validate(newConfig, oldConfig)
180 if err != nil {
181 return err
182 }
183 // Now try to apply the new validated config.
184 return conn.State.SetEnvironConfig(newProviderConfig, oldConfig)
185}167}
186168
187func (c *SetEnvironmentCommand) Run(ctx *cmd.Context) error {169func (c *SetEnvironmentCommand) Run(ctx *cmd.Context) error {
188170
=== modified file 'cmd/juju/environment_test.go'
--- cmd/juju/environment_test.go 2014-02-27 04:43:37 +0000
+++ cmd/juju/environment_test.go 2014-03-18 02:38:23 +0000
@@ -11,6 +11,7 @@
1111
12 jujutesting "launchpad.net/juju-core/juju/testing"12 jujutesting "launchpad.net/juju-core/juju/testing"
13 "launchpad.net/juju-core/provider/dummy"13 "launchpad.net/juju-core/provider/dummy"
14 _ "launchpad.net/juju-core/provider/local"
14 "launchpad.net/juju-core/testing"15 "launchpad.net/juju-core/testing"
15)16)
1617
@@ -163,7 +164,7 @@
163164
164var immutableConfigTests = map[string]string{165var immutableConfigTests = map[string]string{
165 "name": "foo",166 "name": "foo",
166 "type": "foo",167 "type": "local",
167 "firewall-mode": "global",168 "firewall-mode": "global",
168 "state-port": "1",169 "state-port": "1",
169 "api-port": "666",170 "api-port": "666",
170171
=== modified file 'cmd/juju/upgradejuju_test.go'
--- cmd/juju/upgradejuju_test.go 2014-03-13 23:30:56 +0000
+++ cmd/juju/upgradejuju_test.go 2014-03-18 02:38:23 +0000
@@ -322,20 +322,16 @@
322 }322 }
323323
324 // Set up state and environ, and run the command.324 // Set up state and environ, and run the command.
325 oldcfg, err := s.State.EnvironConfig()
326 c.Assert(err, gc.IsNil)
327 toolsDir := c.MkDir()325 toolsDir := c.MkDir()
328 cfg, err := oldcfg.Apply(map[string]interface{}{326 updateAttrs := map[string]interface{}{
329 "agent-version": test.agentVersion,327 "agent-version": test.agentVersion,
330 "tools-metadata-url": "file://" + toolsDir,328 "tools-metadata-url": "file://" + toolsDir,
331 })329 }
332 c.Assert(err, gc.IsNil)330 err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil)
333 err = s.State.SetEnvironConfig(cfg, oldcfg)
334 c.Assert(err, gc.IsNil)331 c.Assert(err, gc.IsNil)
335 versions := make([]version.Binary, len(test.tools))332 versions := make([]version.Binary, len(test.tools))
336 for i, v := range test.tools {333 for i, v := range test.tools {
337 versions[i] = version.MustParseBinary(v)334 versions[i] = version.MustParseBinary(v)
338
339 }335 }
340 if len(versions) > 0 {336 if len(versions) > 0 {
341 envtesting.MustUploadFakeToolsVersions(s.Conn.Environ.Storage(), versions...)337 envtesting.MustUploadFakeToolsVersions(s.Conn.Environ.Storage(), versions...)
@@ -353,7 +349,7 @@
353 }349 }
354350
355 // Check expected changes to environ/state.351 // Check expected changes to environ/state.
356 cfg, err = s.State.EnvironConfig()352 cfg, err := s.State.EnvironConfig()
357 c.Check(err, gc.IsNil)353 c.Check(err, gc.IsNil)
358 agentVersion, ok := cfg.AgentVersion()354 agentVersion, ok := cfg.AgentVersion()
359 c.Check(ok, gc.Equals, true)355 c.Check(ok, gc.Equals, true)
@@ -408,14 +404,11 @@
408func (s *UpgradeJujuSuite) Reset(c *gc.C) {404func (s *UpgradeJujuSuite) Reset(c *gc.C) {
409 s.JujuConnSuite.Reset(c)405 s.JujuConnSuite.Reset(c)
410 envtesting.RemoveTools(c, s.Conn.Environ.Storage())406 envtesting.RemoveTools(c, s.Conn.Environ.Storage())
411 oldcfg, err := s.State.EnvironConfig()407 updateAttrs := map[string]interface{}{
412 c.Assert(err, gc.IsNil)
413 cfg, err := oldcfg.Apply(map[string]interface{}{
414 "default-series": "raring",408 "default-series": "raring",
415 "agent-version": "1.2.3",409 "agent-version": "1.2.3",
416 })410 }
417 c.Assert(err, gc.IsNil)411 err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil)
418 err = s.State.SetEnvironConfig(cfg, oldcfg)
419 c.Assert(err, gc.IsNil)412 c.Assert(err, gc.IsNil)
420 s.toolsDir = c.MkDir()413 s.toolsDir = c.MkDir()
421}414}
422415
=== modified file 'cmd/jujud/machine_test.go'
--- cmd/jujud/machine_test.go 2014-03-13 07:54:56 +0000
+++ cmd/jujud/machine_test.go 2014-03-18 02:38:23 +0000
@@ -32,7 +32,6 @@
32 "launchpad.net/juju-core/state/api/params"32 "launchpad.net/juju-core/state/api/params"
33 apirsyslog "launchpad.net/juju-core/state/api/rsyslog"33 apirsyslog "launchpad.net/juju-core/state/api/rsyslog"
34 charmtesting "launchpad.net/juju-core/state/apiserver/charmrevisionupdater/testing"34 charmtesting "launchpad.net/juju-core/state/apiserver/charmrevisionupdater/testing"
35 statetesting "launchpad.net/juju-core/state/testing"
36 "launchpad.net/juju-core/state/watcher"35 "launchpad.net/juju-core/state/watcher"
37 "launchpad.net/juju-core/testing"36 "launchpad.net/juju-core/testing"
38 coretesting "launchpad.net/juju-core/testing"37 coretesting "launchpad.net/juju-core/testing"
@@ -635,7 +634,7 @@
635634
636 // Update the keys in the environment.635 // Update the keys in the environment.
637 sshKey := sshtesting.ValidKeyOne.Key + " user@host"636 sshKey := sshtesting.ValidKeyOne.Key + " user@host"
638 err := statetesting.UpdateConfig(s.BackingState, map[string]interface{}{"authorized-keys": sshKey})637 err := s.BackingState.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": sshKey}, nil, nil)
639 c.Assert(err, gc.IsNil)638 c.Assert(err, gc.IsNil)
640639
641 // Wait for ssh keys file to be updated.640 // Wait for ssh keys file to be updated.
@@ -723,19 +722,15 @@
723722
724 s.primeAgent(c, version.Current, state.JobHostUnits)723 s.primeAgent(c, version.Current, state.JobHostUnits)
725 // Make sure there are some proxy settings to write.724 // Make sure there are some proxy settings to write.
726 oldConfig, err := s.State.EnvironConfig()
727 c.Assert(err, gc.IsNil)
728
729 proxySettings := osenv.ProxySettings{725 proxySettings := osenv.ProxySettings{
730 Http: "http proxy",726 Http: "http proxy",
731 Https: "https proxy",727 Https: "https proxy",
732 Ftp: "ftp proxy",728 Ftp: "ftp proxy",
733 }729 }
734730
735 envConfig, err := oldConfig.Apply(config.ProxyConfigMap(proxySettings))731 updateAttrs := config.ProxyConfigMap(proxySettings)
736 c.Assert(err, gc.IsNil)
737732
738 err = s.State.SetEnvironConfig(envConfig, oldConfig)733 err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil)
739 c.Assert(err, gc.IsNil)734 c.Assert(err, gc.IsNil)
740735
741 s.assertJobWithAPI(c, state.JobHostUnits, func(conf agent.Config, st *api.State) {736 s.assertJobWithAPI(c, state.JobHostUnits, func(conf agent.Config, st *api.State) {
742737
=== modified file 'environs/config.go'
--- environs/config.go 2014-03-05 19:41:34 +0000
+++ environs/config.go 2014-03-18 02:38:23 +0000
@@ -135,13 +135,13 @@
135}135}
136136
137// Provider returns the previously registered provider with the given type.137// Provider returns the previously registered provider with the given type.
138func Provider(typ string) (EnvironProvider, error) {138func Provider(providerType string) (EnvironProvider, error) {
139 if alias, ok := providerAliases[typ]; ok {139 if alias, ok := providerAliases[providerType]; ok {
140 typ = alias140 providerType = alias
141 }141 }
142 p, ok := providers[typ]142 p, ok := providers[providerType]
143 if !ok {143 if !ok {
144 return nil, fmt.Errorf("no registered provider for %q", typ)144 return nil, fmt.Errorf("no registered provider for %q", providerType)
145 }145 }
146 return p, nil146 return p, nil
147}147}
148148
=== modified file 'environs/config/config.go'
--- environs/config/config.go 2014-03-14 03:44:08 +0000
+++ environs/config/config.go 2014-03-18 02:38:23 +0000
@@ -662,6 +662,15 @@
662 return allAttrs662 return allAttrs
663}663}
664664
665// Remove returns a new configuration that has the attributes of c minus attrs.
666func (c *Config) Remove(attrs []string) (*Config, error) {
667 defined := c.AllAttrs()
668 for _, k := range attrs {
669 delete(defined, k)
670 }
671 return New(NoDefaults, defined)
672}
673
665// Apply returns a new configuration that has the attributes of c plus attrs.674// Apply returns a new configuration that has the attributes of c plus attrs.
666func (c *Config) Apply(attrs map[string]interface{}) (*Config, error) {675func (c *Config) Apply(attrs map[string]interface{}) (*Config, error) {
667 defined := c.AllAttrs()676 defined := c.AllAttrs()
668677
=== modified file 'environs/statepolicy.go'
--- environs/statepolicy.go 2014-02-19 06:31:52 +0000
+++ environs/statepolicy.go 2014-03-18 02:38:23 +0000
@@ -27,8 +27,18 @@
27 if err != nil {27 if err != nil {
28 return nil, err28 return nil, err
29 }29 }
30
30 if p, ok := env.(state.Prechecker); ok {31 if p, ok := env.(state.Prechecker); ok {
31 return p, nil32 return p, nil
32 }33 }
33 return nil, errors.NewNotImplementedError("Prechecker")34 return nil, errors.NewNotImplementedError("Prechecker")
34}35}
36
37func (environStatePolicy) ConfigValidator(providerType string) (state.ConfigValidator, error) {
38 provider, err := Provider(providerType)
39 if err != nil {
40 return nil, err
41 }
42
43 return provider, nil
44}
3545
=== modified file 'environs/testing/tools.go'
--- environs/testing/tools.go 2014-03-13 22:47:05 +0000
+++ environs/testing/tools.go 2014-03-18 02:38:23 +0000
@@ -442,12 +442,6 @@
442 }}442 }}
443443
444func SetSSLHostnameVerification(c *gc.C, st *state.State, SSLHostnameVerification bool) {444func SetSSLHostnameVerification(c *gc.C, st *state.State, SSLHostnameVerification bool) {
445 envConfig, err := st.EnvironConfig()445 err := st.UpdateEnvironConfig(map[string]interface{}{"ssl-hostname-verification": SSLHostnameVerification}, nil, nil)
446 c.Assert(err, gc.IsNil)
447 attrs := envConfig.AllAttrs()
448 attrs["ssl-hostname-verification"] = SSLHostnameVerification
449 newConfig, err := config.New(config.NoDefaults, attrs)
450 c.Assert(err, gc.IsNil)
451 err = st.SetEnvironConfig(newConfig, envConfig)
452 c.Assert(err, gc.IsNil)446 c.Assert(err, gc.IsNil)
453}447}
454448
=== modified file 'juju/conn.go'
--- juju/conn.go 2014-03-07 14:15:28 +0000
+++ juju/conn.go 2014-03-18 02:38:23 +0000
@@ -13,7 +13,6 @@
1313
14 "launchpad.net/juju-core/charm"14 "launchpad.net/juju-core/charm"
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/configstore"16 "launchpad.net/juju-core/environs/configstore"
18 "launchpad.net/juju-core/errors"17 "launchpad.net/juju-core/errors"
19 "launchpad.net/juju-core/juju/osenv"18 "launchpad.net/juju-core/juju/osenv"
@@ -144,20 +143,17 @@
144 if err != nil {143 if err != nil {
145 return err144 return err
146 }145 }
146 secretAttrs := make(map[string]interface{})
147 attrs := cfg.AllAttrs()147 attrs := cfg.AllAttrs()
148 for k, v := range secrets {148 for k, v := range secrets {
149 if _, exists := attrs[k]; exists {149 if _, exists := attrs[k]; exists {
150 // Environment already has secrets. Won't send again.150 // Environment already has secrets. Won't send again.
151 return nil151 return nil
152 } else {152 } else {
153 attrs[k] = v153 secretAttrs[k] = v
154 }154 }
155 }155 }
156 newcfg, err := config.New(config.NoDefaults, attrs)156 return c.State.UpdateEnvironConfig(secretAttrs, nil, nil)
157 if err != nil {
158 return err
159 }
160 return c.State.SetEnvironConfig(newcfg, cfg)
161}157}
162158
163// PutCharm uploads the given charm to provider storage, and adds a159// PutCharm uploads the given charm to provider storage, and adds a
164160
=== modified file 'juju/conn_test.go'
--- juju/conn_test.go 2014-03-13 07:54:56 +0000
+++ juju/conn_test.go 2014-03-18 02:38:23 +0000
@@ -140,7 +140,8 @@
140 info, _, err := env.StateInfo()140 info, _, err := env.StateInfo()
141 c.Assert(err, gc.IsNil)141 c.Assert(err, gc.IsNil)
142 info.Password = utils.UserPasswordHash("side-effect secret", utils.CompatSalt)142 info.Password = utils.UserPasswordHash("side-effect secret", utils.CompatSalt)
143 st, err := state.Open(info, state.DefaultDialOpts(), environs.NewStatePolicy())143 // Use a state without a nil policy, which will allow us to set an invalid config.
144 st, err := state.Open(info, state.DefaultDialOpts(), state.Policy(nil))
144 c.Assert(err, gc.IsNil)145 c.Assert(err, gc.IsNil)
145 defer assertClose(c, st)146 defer assertClose(c, st)
146147
@@ -151,15 +152,8 @@
151152
152 // Remove the secret from state, and then make sure it gets153 // Remove the secret from state, and then make sure it gets
153 // pushed back again.154 // pushed back again.
154 attrs = statecfg.AllAttrs()155 err = st.UpdateEnvironConfig(map[string]interface{}{}, []string{"secret"}, nil)
155 delete(attrs, "secret")156 c.Assert(err, gc.IsNil)
156 newcfg, err := config.New(config.NoDefaults, attrs)
157 c.Assert(err, gc.IsNil)
158 err = st.SetEnvironConfig(newcfg, statecfg)
159 c.Assert(err, gc.IsNil)
160 statecfg, err = st.EnvironConfig()
161 c.Assert(err, gc.IsNil)
162 c.Assert(statecfg.UnknownAttrs()["secret"], gc.IsNil)
163157
164 // Make a new Conn, which will push the secrets.158 // Make a new Conn, which will push the secrets.
165 conn, err := juju.NewConn(env)159 conn, err := juju.NewConn(env)
166160
=== modified file 'juju/testing/conn.go'
--- juju/testing/conn.go 2014-02-21 03:57:49 +0000
+++ juju/testing/conn.go 2014-03-18 02:38:23 +0000
@@ -62,6 +62,7 @@
62 oldHome string62 oldHome string
63 oldJujuHome string63 oldJujuHome string
64 environ environs.Environ64 environ environs.Environ
65 DummyConfig testing.Attrs
65}66}
6667
67const AdminSecret = "dummy-secret"68const AdminSecret = "dummy-secret"
@@ -220,7 +221,10 @@
220}221}
221222
222func (s *JujuConnSuite) writeSampleConfig(c *gc.C, path string) {223func (s *JujuConnSuite) writeSampleConfig(c *gc.C, path string) {
223 attrs := dummy.SampleConfig().Merge(testing.Attrs{224 if s.DummyConfig == nil {
225 s.DummyConfig = dummy.SampleConfig()
226 }
227 attrs := s.DummyConfig.Merge(testing.Attrs{
224 "admin-secret": AdminSecret,228 "admin-secret": AdminSecret,
225 "agent-version": version.Current.Number.String(),229 "agent-version": version.Current.Number.String(),
226 }).Delete("name")230 }).Delete("name")
227231
=== modified file 'juju/testing/repo.go'
--- juju/testing/repo.go 2014-01-28 17:07:55 +0000
+++ juju/testing/repo.go 2014-03-18 02:38:23 +0000
@@ -25,11 +25,8 @@
25 s.JujuConnSuite.SetUpTest(c)25 s.JujuConnSuite.SetUpTest(c)
26 // Change the environ's config to ensure we're using the one in state,26 // Change the environ's config to ensure we're using the one in state,
27 // not the one in the local environments.yaml27 // not the one in the local environments.yaml
28 oldcfg, err := s.State.EnvironConfig()28 updateAttrs := map[string]interface{}{"default-series": "precise"}
29 c.Assert(err, gc.IsNil)29 err := s.State.UpdateEnvironConfig(updateAttrs, nil, nil)
30 cfg, err := oldcfg.Apply(map[string]interface{}{"default-series": "precise"})
31 c.Assert(err, gc.IsNil)
32 err = s.State.SetEnvironConfig(cfg, oldcfg)
33 c.Assert(err, gc.IsNil)30 c.Assert(err, gc.IsNil)
34 s.RepoPath = os.Getenv("JUJU_REPOSITORY")31 s.RepoPath = os.Getenv("JUJU_REPOSITORY")
35 repoPath := c.MkDir()32 repoPath := c.MkDir()
3633
=== modified file 'juju/testing/utils.go'
--- juju/testing/utils.go 2014-01-22 19:28:08 +0000
+++ juju/testing/utils.go 2014-03-18 02:38:23 +0000
@@ -6,24 +6,10 @@
6import (6import (
7 gc "launchpad.net/gocheck"7 gc "launchpad.net/gocheck"
88
9 "launchpad.net/juju-core/environs/config"
10 "launchpad.net/juju-core/instance"9 "launchpad.net/juju-core/instance"
11 "launchpad.net/juju-core/state"10 "launchpad.net/juju-core/state"
12 coretesting "launchpad.net/juju-core/testing"
13)11)
1412
15// ChangeEnvironConfig applies the given change function
16// to the attributes from st.EnvironConfig and
17// sets the state's environment configuration to the result.
18func ChangeEnvironConfig(c *gc.C, st *state.State, change func(coretesting.Attrs) coretesting.Attrs) {
19 cfg, err := st.EnvironConfig()
20 c.Assert(err, gc.IsNil)
21 newCfg, err := config.New(config.NoDefaults, change(cfg.AllAttrs()))
22 c.Assert(err, gc.IsNil)
23 err = st.SetEnvironConfig(newCfg, cfg)
24 c.Assert(err, gc.IsNil)
25}
26
27// AddStateServerMachine adds a "state server" machine to the state so13// AddStateServerMachine adds a "state server" machine to the state so
28// that State.Addresses and State.APIAddresses will work. It returns the14// that State.Addresses and State.APIAddresses will work. It returns the
29// added machine. The addresses that those methods will return bear no15// added machine. The addresses that those methods will return bear no
3016
=== modified file 'state/api/common/testing/environwatcher.go'
--- state/api/common/testing/environwatcher.go 2014-03-13 07:54:56 +0000
+++ state/api/common/testing/environwatcher.go 2014-03-18 02:38:23 +0000
@@ -76,17 +76,26 @@
76 // Initial event.76 // Initial event.
77 wc.AssertOneChange()77 wc.AssertOneChange()
7878
79 // Change the environment configuration, check it's detected.79 // Change the environment configuration by updating an existing attribute, check it's detected.
80 attrs := envConfig.AllAttrs()80 newAttrs := map[string]interface{}{"logging-config": "juju=ERROR"}
81 attrs["type"] = "blah"81 err = s.st.UpdateEnvironConfig(newAttrs, nil, nil)
82 newConfig, err := config.New(config.NoDefaults, attrs)82 c.Assert(err, gc.IsNil)
83 c.Assert(err, gc.IsNil)83 wc.AssertOneChange()
84 err = s.st.SetEnvironConfig(newConfig, envConfig)84
85 // Change the environment configuration by adding a new attribute, check it's detected.
86 newAttrs = map[string]interface{}{"foo": "bar"}
87 err = s.st.UpdateEnvironConfig(newAttrs, nil, nil)
88 c.Assert(err, gc.IsNil)
89 wc.AssertOneChange()
90
91 // Change the environment configuration by removing an attribute, check it's detected.
92 err = s.st.UpdateEnvironConfig(map[string]interface{}{}, []string{"foo"}, nil)
85 c.Assert(err, gc.IsNil)93 c.Assert(err, gc.IsNil)
86 wc.AssertOneChange()94 wc.AssertOneChange()
8795
88 // Change it back to the original config.96 // Change it back to the original config.
89 err = s.st.SetEnvironConfig(envConfig, newConfig)97 oldAttrs := map[string]interface{}{"logging-config": envConfig.AllAttrs()["logging-config"]}
98 err = s.st.UpdateEnvironConfig(oldAttrs, nil, nil)
90 c.Assert(err, gc.IsNil)99 c.Assert(err, gc.IsNil)
91 wc.AssertOneChange()100 wc.AssertOneChange()
92101
93102
=== modified file 'state/api/firewaller/state_test.go'
--- state/api/firewaller/state_test.go 2014-03-13 07:54:56 +0000
+++ state/api/firewaller/state_test.go 2014-03-18 02:38:23 +0000
@@ -7,7 +7,6 @@
7 jc "github.com/juju/testing/checkers"7 jc "github.com/juju/testing/checkers"
8 gc "launchpad.net/gocheck"8 gc "launchpad.net/gocheck"
99
10 "launchpad.net/juju-core/environs/config"
11 "launchpad.net/juju-core/instance"10 "launchpad.net/juju-core/instance"
12 "launchpad.net/juju-core/state"11 "launchpad.net/juju-core/state"
13 statetesting "launchpad.net/juju-core/state/testing"12 statetesting "launchpad.net/juju-core/state/testing"
@@ -81,16 +80,14 @@
81 wc.AssertOneChange()80 wc.AssertOneChange()
8281
83 // Change the environment configuration, check it's detected.82 // Change the environment configuration, check it's detected.
84 attrs := envConfig.AllAttrs()83 newAttrs := map[string]interface{}{"logging-config": "juju=ERROR"}
85 attrs["type"] = "blah"84 err = s.State.UpdateEnvironConfig(newAttrs, nil, nil)
86 newConfig, err := config.New(config.NoDefaults, attrs)
87 c.Assert(err, gc.IsNil)
88 err = s.State.SetEnvironConfig(newConfig, envConfig)
89 c.Assert(err, gc.IsNil)85 c.Assert(err, gc.IsNil)
90 wc.AssertOneChange()86 wc.AssertOneChange()
9187
92 // Change it back to the original config.88 // Change it back to the original config.
93 err = s.State.SetEnvironConfig(envConfig, newConfig)89 oldAttrs := map[string]interface{}{"logging-config": envConfig.AllAttrs()["logging-config"]}
90 err = s.State.UpdateEnvironConfig(oldAttrs, nil, nil)
94 c.Assert(err, gc.IsNil)91 c.Assert(err, gc.IsNil)
95 wc.AssertOneChange()92 wc.AssertOneChange()
9693
9794
=== modified file 'state/api/keymanager/client_test.go'
--- state/api/keymanager/client_test.go 2014-03-10 13:13:43 +0000
+++ state/api/keymanager/client_test.go 2014-03-18 02:38:23 +0000
@@ -14,7 +14,6 @@
14 "launchpad.net/juju-core/state/api/params"14 "launchpad.net/juju-core/state/api/params"
15 keymanagerserver "launchpad.net/juju-core/state/apiserver/keymanager"15 keymanagerserver "launchpad.net/juju-core/state/apiserver/keymanager"
16 keymanagertesting "launchpad.net/juju-core/state/apiserver/keymanager/testing"16 keymanagertesting "launchpad.net/juju-core/state/apiserver/keymanager/testing"
17 "launchpad.net/juju-core/state/testing"
18 "launchpad.net/juju-core/utils/ssh"17 "launchpad.net/juju-core/utils/ssh"
19 sshtesting "launchpad.net/juju-core/utils/ssh/testing"18 sshtesting "launchpad.net/juju-core/utils/ssh/testing"
20)19)
@@ -35,7 +34,7 @@
35}34}
3635
37func (s *keymanagerSuite) setAuthorisedKeys(c *gc.C, keys string) {36func (s *keymanagerSuite) setAuthorisedKeys(c *gc.C, keys string) {
38 err := testing.UpdateConfig(s.BackingState, map[string]interface{}{"authorized-keys": keys})37 err := s.BackingState.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": keys}, nil, nil)
39 c.Assert(err, gc.IsNil)38 c.Assert(err, gc.IsNil)
40}39}
4140
4241
=== modified file 'state/api/keyupdater/authorisedkeys_test.go'
--- state/api/keyupdater/authorisedkeys_test.go 2014-01-24 12:39:48 +0000
+++ state/api/keyupdater/authorisedkeys_test.go 2014-03-18 02:38:23 +0000
@@ -54,7 +54,7 @@
54}54}
5555
56func (s *keyupdaterSuite) setAuthorisedKeys(c *gc.C, keys string) {56func (s *keyupdaterSuite) setAuthorisedKeys(c *gc.C, keys string) {
57 err := testing.UpdateConfig(s.BackingState, map[string]interface{}{"authorized-keys": keys})57 err := s.BackingState.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": keys}, nil, nil)
58 c.Assert(err, gc.IsNil)58 c.Assert(err, gc.IsNil)
59}59}
6060
6161
=== modified file 'state/api/logger/logger_test.go'
--- state/api/logger/logger_test.go 2013-09-17 03:12:12 +0000
+++ state/api/logger/logger_test.go 2014-03-18 02:38:23 +0000
@@ -50,7 +50,7 @@
50}50}
5151
52func (s *loggerSuite) setLoggingConfig(c *gc.C, loggingConfig string) {52func (s *loggerSuite) setLoggingConfig(c *gc.C, loggingConfig string) {
53 err := testing.UpdateConfig(s.BackingState, map[string]interface{}{"logging-config": loggingConfig})53 err := s.BackingState.UpdateEnvironConfig(map[string]interface{}{"logging-config": loggingConfig}, nil, nil)
54 c.Assert(err, gc.IsNil)54 c.Assert(err, gc.IsNil)
55}55}
5656
5757
=== modified file 'state/apiserver/client/client.go'
--- state/apiserver/client/client.go 2014-03-14 10:28:40 +0000
+++ state/apiserver/client/client.go 2014-03-18 02:38:23 +0000
@@ -761,38 +761,23 @@
761// EnvironmentSet implements the server-side part of the761// EnvironmentSet implements the server-side part of the
762// set-environment CLI command.762// set-environment CLI command.
763func (c *Client) EnvironmentSet(args params.EnvironmentSet) error {763func (c *Client) EnvironmentSet(args params.EnvironmentSet) error {
764 // TODO(dimitern,thumper): 2013-11-06 bug #1167616
765 // SetEnvironConfig should take both new and old configs.
766
767 // Get the existing environment config from the state.
768 oldConfig, err := c.api.state.EnvironConfig()
769 if err != nil {
770 return err
771 }
772 // Make sure we don't allow changing agent-version.764 // Make sure we don't allow changing agent-version.
773 if v, found := args.Config["agent-version"]; found {765 checkAgentVersion := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error {
774 oldVersion, _ := oldConfig.AgentVersion()766 if v, found := updateAttrs["agent-version"]; found {
775 if v != oldVersion.String() {767 oldVersion, _ := oldConfig.AgentVersion()
776 return fmt.Errorf("agent-version cannot be changed")768 if v != oldVersion.String() {
769 return fmt.Errorf("agent-version cannot be changed")
770 }
777 }771 }
778 }772 return nil
779 // Apply the attributes specified for the command to the state config.773 }
780 newConfig, err := oldConfig.Apply(args.Config)774
781 if err != nil {775 // TODO(waigani) 2014-3-11 #1167616
782 return err776 // Add a txn retry loop to ensure that the settings on disk have not
783 }777 // changed underneath us.
784 env, err := environs.New(oldConfig)778
785 if err != nil {779 return c.api.state.UpdateEnvironConfig(args.Config, nil, checkAgentVersion)
786 return err780
787 }
788 // Now validate this new config against the existing config via the provider.
789 provider := env.Provider()
790 newProviderConfig, err := provider.Validate(newConfig, oldConfig)
791 if err != nil {
792 return err
793 }
794 // Now try to apply the new validated config.
795 return c.api.state.SetEnvironConfig(newProviderConfig, oldConfig)
796}781}
797782
798// SetEnvironAgentVersion sets the environment agent version.783// SetEnvironAgentVersion sets the environment agent version.
799784
=== modified file 'state/apiserver/client/client_test.go'
--- state/apiserver/client/client_test.go 2014-03-14 10:28:40 +0000
+++ state/apiserver/client/client_test.go 2014-03-18 02:38:23 +0000
@@ -1741,18 +1741,9 @@
1741 store, restore := makeMockCharmStore()1741 store, restore := makeMockCharmStore()
1742 defer restore()1742 defer restore()
17431743
1744 oldConfig, err := s.State.EnvironConfig()1744 attrs := map[string]interface{}{"charm-store-auth": "token=value",
1745 c.Assert(err, gc.IsNil)1745 "test-mode": true}
17461746 err := s.State.UpdateEnvironConfig(attrs, nil, nil)
1747 attrs := coretesting.Attrs(oldConfig.AllAttrs())
1748 attrs = attrs.Merge(coretesting.Attrs{
1749 "charm-store-auth": "token=value",
1750 "test-mode": true})
1751
1752 cfg, err := config.New(config.NoDefaults, attrs)
1753 c.Assert(err, gc.IsNil)
1754
1755 err = s.State.SetEnvironConfig(cfg, oldConfig)
1756 c.Assert(err, gc.IsNil)1747 c.Assert(err, gc.IsNil)
17571748
1758 curl, _ := addCharm(c, store, "dummy")1749 curl, _ := addCharm(c, store, "dummy")
17591750
=== modified file 'state/apiserver/keymanager/keymanager.go'
--- state/apiserver/keymanager/keymanager.go 2014-03-05 19:41:34 +0000
+++ state/apiserver/keymanager/keymanager.go 2014-03-18 02:38:23 +0000
@@ -144,14 +144,14 @@
144 return keyInfo144 return keyInfo
145}145}
146146
147func (api *KeyManagerAPI) writeSSHKeys(currentConfig *config.Config, sshKeys []string) error {147func (api *KeyManagerAPI) writeSSHKeys(sshKeys []string) error {
148 // Write out the new keys.148 // Write out the new keys.
149 keyStr := strings.Join(sshKeys, "\n")149 keyStr := strings.Join(sshKeys, "\n")
150 newConfig, err := currentConfig.Apply(map[string]interface{}{config.AuthKeysConfig: keyStr})150 attrs := map[string]interface{}{config.AuthKeysConfig: keyStr}
151 if err != nil {151 // TODO(waigani) 2014-03-17 bug #1293324
152 return fmt.Errorf("creating new environ config: %v", err)152 // Pass in validation to ensure SSH keys
153 }153 // have not changed underfoot
154 err = api.state.SetEnvironConfig(newConfig, currentConfig)154 err := api.state.UpdateEnvironConfig(attrs, nil, nil)
155 if err != nil {155 if err != nil {
156 return fmt.Errorf("writing environ config: %v", err)156 return fmt.Errorf("writing environ config: %v", err)
157 }157 }
@@ -159,12 +159,12 @@
159}159}
160160
161// currentKeyDataForAdd gathers data used when adding ssh keys.161// currentKeyDataForAdd gathers data used when adding ssh keys.
162func (api *KeyManagerAPI) currentKeyDataForAdd() (keys []string, fingerprints *set.Strings, cfg *config.Config, err error) {162func (api *KeyManagerAPI) currentKeyDataForAdd() (keys []string, fingerprints *set.Strings, err error) {
163 fp := set.NewStrings()163 fp := set.NewStrings()
164 fingerprints = &fp164 fingerprints = &fp
165 cfg, err = api.state.EnvironConfig()165 cfg, err := api.state.EnvironConfig()
166 if err != nil {166 if err != nil {
167 return nil, nil, nil, err167 return nil, nil, fmt.Errorf("reading current key data: %v", err)
168 }168 }
169 keys = ssh.SplitAuthorisedKeys(cfg.AuthorizedKeys())169 keys = ssh.SplitAuthorisedKeys(cfg.AuthorizedKeys())
170 for _, key := range keys {170 for _, key := range keys {
@@ -174,7 +174,7 @@
174 }174 }
175 fingerprints.Add(fingerprint)175 fingerprints.Add(fingerprint)
176 }176 }
177 return keys, fingerprints, cfg, nil177 return keys, fingerprints, nil
178}178}
179179
180// AddKeys adds new authorised ssh keys for the specified user.180// AddKeys adds new authorised ssh keys for the specified user.
@@ -195,7 +195,7 @@
195 }195 }
196196
197 // For now, authorised keys are global, common to all users.197 // For now, authorised keys are global, common to all users.
198 sshKeys, currentFingerprints, currentConfig, err := api.currentKeyDataForAdd()198 sshKeys, currentFingerprints, err := api.currentKeyDataForAdd()
199 if err != nil {199 if err != nil {
200 return params.ErrorResults{}, common.ServerError(fmt.Errorf("reading current key data: %v", err))200 return params.ErrorResults{}, common.ServerError(fmt.Errorf("reading current key data: %v", err))
201 }201 }
@@ -214,7 +214,7 @@
214 }214 }
215 sshKeys = append(sshKeys, key)215 sshKeys = append(sshKeys, key)
216 }216 }
217 err = api.writeSSHKeys(currentConfig, sshKeys)217 err = api.writeSSHKeys(sshKeys)
218 if err != nil {218 if err != nil {
219 return params.ErrorResults{}, common.ServerError(err)219 return params.ErrorResults{}, common.ServerError(err)
220 }220 }
@@ -278,7 +278,7 @@
278 }278 }
279279
280 // For now, authorised keys are global, common to all users.280 // For now, authorised keys are global, common to all users.
281 sshKeys, currentFingerprints, currentConfig, err := api.currentKeyDataForAdd()281 sshKeys, currentFingerprints, err := api.currentKeyDataForAdd()
282 if err != nil {282 if err != nil {
283 return params.ErrorResults{}, common.ServerError(fmt.Errorf("reading current key data: %v", err))283 return params.ErrorResults{}, common.ServerError(fmt.Errorf("reading current key data: %v", err))
284 }284 }
@@ -297,7 +297,7 @@
297 }297 }
298 sshKeys = append(sshKeys, keyInfo.key)298 sshKeys = append(sshKeys, keyInfo.key)
299 }299 }
300 err = api.writeSSHKeys(currentConfig, sshKeys)300 err = api.writeSSHKeys(sshKeys)
301 if err != nil {301 if err != nil {
302 return params.ErrorResults{}, common.ServerError(err)302 return params.ErrorResults{}, common.ServerError(err)
303 }303 }
@@ -306,13 +306,13 @@
306306
307// currentKeyDataForAdd gathers data used when deleting ssh keys.307// currentKeyDataForAdd gathers data used when deleting ssh keys.
308func (api *KeyManagerAPI) currentKeyDataForDelete() (308func (api *KeyManagerAPI) currentKeyDataForDelete() (
309 keys map[string]string, invalidKeys []string, comments map[string]string, cfg *config.Config, err error) {309 keys map[string]string, invalidKeys []string, comments map[string]string, err error) {
310310
311 // For now, authorised keys are global, common to all users.311 cfg, err := api.state.EnvironConfig()
312 cfg, err = api.state.EnvironConfig()
313 if err != nil {312 if err != nil {
314 return nil, nil, nil, nil, fmt.Errorf("reading current key data: %v", err)313 return nil, nil, nil, fmt.Errorf("reading current key data: %v", err)
315 }314 }
315 // For now, authorised keys are global, common to all users.
316 existingSSHKeys := ssh.SplitAuthorisedKeys(cfg.AuthorizedKeys())316 existingSSHKeys := ssh.SplitAuthorisedKeys(cfg.AuthorizedKeys())
317317
318 // Build up a map of keys indexed by fingerprint, and fingerprints indexed by comment318 // Build up a map of keys indexed by fingerprint, and fingerprints indexed by comment
@@ -332,7 +332,7 @@
332 comments[comment] = fingerprint332 comments[comment] = fingerprint
333 }333 }
334 }334 }
335 return keys, invalidKeys, comments, cfg, nil335 return keys, invalidKeys, comments, nil
336}336}
337337
338// DeleteKeys deletes the authorised ssh keys for the specified user.338// DeleteKeys deletes the authorised ssh keys for the specified user.
@@ -352,7 +352,7 @@
352 return params.ErrorResults{}, common.ServerError(common.ErrPerm)352 return params.ErrorResults{}, common.ServerError(common.ErrPerm)
353 }353 }
354354
355 sshKeys, invalidKeys, keyComments, currentConfig, err := api.currentKeyDataForDelete()355 sshKeys, invalidKeys, keyComments, err := api.currentKeyDataForDelete()
356 if err != nil {356 if err != nil {
357 return params.ErrorResults{}, common.ServerError(fmt.Errorf("reading current key data: %v", err))357 return params.ErrorResults{}, common.ServerError(fmt.Errorf("reading current key data: %v", err))
358 }358 }
@@ -382,7 +382,7 @@
382 return params.ErrorResults{}, common.ServerError(stderrors.New("cannot delete all keys"))382 return params.ErrorResults{}, common.ServerError(stderrors.New("cannot delete all keys"))
383 }383 }
384384
385 err = api.writeSSHKeys(currentConfig, keysToWrite)385 err = api.writeSSHKeys(keysToWrite)
386 if err != nil {386 if err != nil {
387 return params.ErrorResults{}, common.ServerError(err)387 return params.ErrorResults{}, common.ServerError(err)
388 }388 }
389389
=== modified file 'state/apiserver/keymanager/keymanager_test.go'
--- state/apiserver/keymanager/keymanager_test.go 2014-03-10 13:13:43 +0000
+++ state/apiserver/keymanager/keymanager_test.go 2014-03-18 02:38:23 +0000
@@ -16,7 +16,6 @@
16 "launchpad.net/juju-core/state/apiserver/keymanager"16 "launchpad.net/juju-core/state/apiserver/keymanager"
17 keymanagertesting "launchpad.net/juju-core/state/apiserver/keymanager/testing"17 keymanagertesting "launchpad.net/juju-core/state/apiserver/keymanager/testing"
18 apiservertesting "launchpad.net/juju-core/state/apiserver/testing"18 apiservertesting "launchpad.net/juju-core/state/apiserver/testing"
19 statetesting "launchpad.net/juju-core/state/testing"
20 "launchpad.net/juju-core/utils/ssh"19 "launchpad.net/juju-core/utils/ssh"
21 sshtesting "launchpad.net/juju-core/utils/ssh/testing"20 sshtesting "launchpad.net/juju-core/utils/ssh/testing"
22)21)
@@ -78,7 +77,7 @@
78}77}
7978
80func (s *keyManagerSuite) setAuthorisedKeys(c *gc.C, keys string) {79func (s *keyManagerSuite) setAuthorisedKeys(c *gc.C, keys string) {
81 err := statetesting.UpdateConfig(s.State, map[string]interface{}{"authorized-keys": keys})80 err := s.State.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": keys}, nil, nil)
82 c.Assert(err, gc.IsNil)81 c.Assert(err, gc.IsNil)
83 envConfig, err := s.State.EnvironConfig()82 envConfig, err := s.State.EnvironConfig()
84 c.Assert(err, gc.IsNil)83 c.Assert(err, gc.IsNil)
8584
=== modified file 'state/apiserver/keyupdater/authorisedkeys_test.go'
--- state/apiserver/keyupdater/authorisedkeys_test.go 2013-12-12 05:12:49 +0000
+++ state/apiserver/keyupdater/authorisedkeys_test.go 2014-03-18 02:38:23 +0000
@@ -73,7 +73,7 @@
73}73}
7474
75func (s *authorisedKeysSuite) setAuthorizedKeys(c *gc.C, keys string) {75func (s *authorisedKeysSuite) setAuthorizedKeys(c *gc.C, keys string) {
76 err := statetesting.UpdateConfig(s.State, map[string]interface{}{"authorized-keys": keys})76 err := s.State.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": keys}, nil, nil)
77 c.Assert(err, gc.IsNil)77 c.Assert(err, gc.IsNil)
78 envConfig, err := s.State.EnvironConfig()78 envConfig, err := s.State.EnvironConfig()
79 c.Assert(err, gc.IsNil)79 c.Assert(err, gc.IsNil)
8080
=== modified file 'state/apiserver/logger/logger_test.go'
--- state/apiserver/logger/logger_test.go 2014-01-22 02:08:33 +0000
+++ state/apiserver/logger/logger_test.go 2014-03-18 02:38:23 +0000
@@ -74,7 +74,7 @@
74}74}
7575
76func (s *loggerSuite) setLoggingConfig(c *gc.C, loggingConfig string) {76func (s *loggerSuite) setLoggingConfig(c *gc.C, loggingConfig string) {
77 err := statetesting.UpdateConfig(s.State, map[string]interface{}{"logging-config": loggingConfig})77 err := s.State.UpdateEnvironConfig(map[string]interface{}{"logging-config": loggingConfig}, nil, nil)
78 c.Assert(err, gc.IsNil)78 c.Assert(err, gc.IsNil)
79 envConfig, err := s.State.EnvironConfig()79 envConfig, err := s.State.EnvironConfig()
80 c.Assert(err, gc.IsNil)80 c.Assert(err, gc.IsNil)
8181
=== modified file 'state/apiserver/provisioner/provisioner_test.go'
--- state/apiserver/provisioner/provisioner_test.go 2014-03-17 13:22:55 +0000
+++ state/apiserver/provisioner/provisioner_test.go 2014-03-18 02:38:23 +0000
@@ -683,13 +683,10 @@
683}683}
684684
685func (s *withoutStateServerSuite) TestContainerConfig(c *gc.C) {685func (s *withoutStateServerSuite) TestContainerConfig(c *gc.C) {
686 cfg, err := s.State.EnvironConfig()686 attrs := map[string]interface{}{
687 c.Assert(err, gc.IsNil)
688 newCfg, err := cfg.Apply(map[string]interface{}{
689 "http-proxy": "http://proxy.example.com:9000",687 "http-proxy": "http://proxy.example.com:9000",
690 })688 }
691 c.Assert(err, gc.IsNil)689 err := s.State.UpdateEnvironConfig(attrs, nil, nil)
692 err = s.State.SetEnvironConfig(newCfg, cfg)
693 c.Assert(err, gc.IsNil)690 c.Assert(err, gc.IsNil)
694 expectedProxy := osenv.ProxySettings{691 expectedProxy := osenv.ProxySettings{
695 Http: "http://proxy.example.com:9000",692 Http: "http://proxy.example.com:9000",
696693
=== modified file 'state/apiserver/rsyslog/rsyslog.go'
--- state/apiserver/rsyslog/rsyslog.go 2014-02-27 03:46:35 +0000
+++ state/apiserver/rsyslog/rsyslog.go 2014-03-18 02:38:23 +0000
@@ -40,17 +40,9 @@
40 result.Error = common.ServerError(err)40 result.Error = common.ServerError(err)
41 return result, nil41 return result, nil
42 }42 }
43 old, err := api.st.EnvironConfig()43 attrs := map[string]interface{}{"rsyslog-ca-cert": string(args.CACert)}
44 if err != nil {44 if err := api.st.UpdateEnvironConfig(attrs, nil, nil); err != nil {
45 return params.ErrorResult{}, err
46 }
47 cfg, err := old.Apply(map[string]interface{}{"rsyslog-ca-cert": string(args.CACert)})
48 if err != nil {
49 result.Error = common.ServerError(err)45 result.Error = common.ServerError(err)
50 } else {
51 if err := api.st.SetEnvironConfig(cfg, old); err != nil {
52 result.Error = common.ServerError(err)
53 }
54 }46 }
55 return result, nil47 return result, nil
56}48}
5749
=== added file 'state/configvalidator_test.go'
--- state/configvalidator_test.go 1970-01-01 00:00:00 +0000
+++ state/configvalidator_test.go 2014-03-18 02:38:23 +0000
@@ -0,0 +1,114 @@
1// Copyright 2014 Canonical Ltd.
2// Licensed under the AGPLv3, see LICENCE file for details.
3
4package state_test
5
6import (
7 gc "launchpad.net/gocheck"
8 "launchpad.net/juju-core/environs/config"
9 "launchpad.net/juju-core/errors"
10 "launchpad.net/juju-core/state"
11 coretesting "launchpad.net/juju-core/testing"
12)
13
14type ConfigValidatorSuite struct {
15 ConnSuite
16 configValidator mockConfigValidator
17}
18
19var _ = gc.Suite(&ConfigValidatorSuite{})
20
21type mockConfigValidator struct {
22 validateError error
23 validateCfg *config.Config
24 validateOld *config.Config
25 validateValid *config.Config
26}
27
28// To test UpdateEnvironConfig updates state, Validate returns a config
29// different to both input configs
30func mockValidCfg() (valid *config.Config, err error) {
31 cfg, err := config.New(config.UseDefaults, coretesting.FakeConfig())
32 if err != nil {
33 return nil, err
34 }
35 valid, err = cfg.Apply(map[string]interface{}{
36 "arbitrary-key": "cptn-marvel",
37 })
38 if err != nil {
39 return nil, err
40 }
41 return valid, nil
42}
43
44func (p *mockConfigValidator) Validate(cfg, old *config.Config) (valid *config.Config, err error) {
45 p.validateCfg = cfg
46 p.validateOld = old
47 p.validateValid, p.validateError = mockValidCfg()
48 return p.validateValid, p.validateError
49}
50
51func (s *ConfigValidatorSuite) SetUpTest(c *gc.C) {
52 s.ConnSuite.SetUpTest(c)
53 s.configValidator = mockConfigValidator{}
54 s.policy.getConfigValidator = func(string) (state.ConfigValidator, error) {
55 return &s.configValidator, nil
56 }
57}
58
59func (s *ConfigValidatorSuite) updateEnvironConfig(c *gc.C) error {
60 updateAttrs := map[string]interface{}{
61 "authorized-keys": "different-keys",
62 "arbitrary-key": "shazam!",
63 }
64 return s.State.UpdateEnvironConfig(updateAttrs, nil, nil)
65}
66
67func (s *ConfigValidatorSuite) TestConfigValidate(c *gc.C) {
68 err := s.updateEnvironConfig(c)
69 c.Assert(err, gc.IsNil)
70}
71
72func (s *ConfigValidatorSuite) TestUpdateEnvironConfigFailsOnConfigValidateError(c *gc.C) {
73 var configValidatorErr error
74 s.policy.getConfigValidator = func(string) (state.ConfigValidator, error) {
75 configValidatorErr = errors.NotFoundf("")
76 return &s.configValidator, configValidatorErr
77 }
78
79 err := s.updateEnvironConfig(c)
80 c.Assert(err, gc.ErrorMatches, " not found")
81}
82
83func (s *ConfigValidatorSuite) TestUpdateEnvironConfigUpdatesState(c *gc.C) {
84 s.updateEnvironConfig(c)
85 stateCfg, err := s.State.EnvironConfig()
86 c.Assert(err, gc.IsNil)
87 newValidCfg, err := mockValidCfg()
88 c.Assert(err, gc.IsNil)
89 c.Assert(stateCfg.AllAttrs()["arbitrary-key"], gc.Equals, newValidCfg.AllAttrs()["arbitrary-key"])
90}
91
92func (s *ConfigValidatorSuite) TestConfigValidateUnimplemented(c *gc.C) {
93 var configValidatorErr error
94 s.policy.getConfigValidator = func(string) (state.ConfigValidator, error) {
95 return nil, configValidatorErr
96 }
97
98 err := s.updateEnvironConfig(c)
99 c.Assert(err, gc.ErrorMatches, "policy returned nil configValidator without an error")
100 configValidatorErr = errors.NewNotImplementedError("Validator")
101 err = s.updateEnvironConfig(c)
102 c.Assert(err, gc.IsNil)
103}
104
105func (s *ConfigValidatorSuite) TestConfigValidateNoPolicy(c *gc.C) {
106 s.policy.getConfigValidator = func(providerType string) (state.ConfigValidator, error) {
107 c.Errorf("should not have been invoked")
108 return nil, nil
109 }
110
111 state.SetPolicy(s.State, nil)
112 err := s.updateEnvironConfig(c)
113 c.Assert(err, gc.IsNil)
114}
0115
=== modified file 'state/conn_test.go'
--- state/conn_test.go 2014-03-13 13:42:50 +0000
+++ state/conn_test.go 2014-03-18 02:38:23 +0000
@@ -97,7 +97,8 @@
97}97}
9898
99type mockPolicy struct {99type mockPolicy struct {
100 getPrechecker func(*config.Config) (state.Prechecker, error)100 getPrechecker func(*config.Config) (state.Prechecker, error)
101 getConfigValidator func(string) (state.ConfigValidator, error)
101}102}
102103
103func (p *mockPolicy) Prechecker(cfg *config.Config) (state.Prechecker, error) {104func (p *mockPolicy) Prechecker(cfg *config.Config) (state.Prechecker, error) {
@@ -106,3 +107,10 @@
106 }107 }
107 return nil, errors.NewNotImplementedError("Prechecker")108 return nil, errors.NewNotImplementedError("Prechecker")
108}109}
110
111func (p *mockPolicy) ConfigValidator(providerType string) (state.ConfigValidator, error) {
112 if p.getConfigValidator != nil {
113 return p.getConfigValidator(providerType)
114 }
115 return nil, errors.NewNotImplementedError("ConfigValidator")
116}
109117
=== modified file 'state/initialize_test.go'
--- state/initialize_test.go 2014-03-17 16:12:00 +0000
+++ state/initialize_test.go 2014-03-18 02:38:23 +0000
@@ -110,17 +110,18 @@
110func (s *InitializeSuite) TestEnvironConfigWithAdminSecret(c *gc.C) {110func (s *InitializeSuite) TestEnvironConfigWithAdminSecret(c *gc.C) {
111 // admin-secret blocks Initialize.111 // admin-secret blocks Initialize.
112 good := testing.EnvironConfig(c)112 good := testing.EnvironConfig(c)
113 bad, err := good.Apply(map[string]interface{}{"admin-secret": "foo"})113 badUpdateAttrs := map[string]interface{}{"admin-secret": "foo"}
114 bad, err := good.Apply(badUpdateAttrs)
114115
115 _, err = state.Initialize(state.TestingStateInfo(), bad, state.TestingDialOpts(), state.Policy(nil))116 _, err = state.Initialize(state.TestingStateInfo(), bad, state.TestingDialOpts(), state.Policy(nil))
116 c.Assert(err, gc.ErrorMatches, "admin-secret should never be written to the state")117 c.Assert(err, gc.ErrorMatches, "admin-secret should never be written to the state")
117118
118 // admin-secret blocks SetEnvironConfig.119 // admin-secret blocks UpdateEnvironConfig.
119 st := state.TestingInitialize(c, good, state.Policy(nil))120 st := state.TestingInitialize(c, good, state.Policy(nil))
120 st.Close()121 st.Close()
121122
122 s.openState(c)123 s.openState(c)
123 err = s.State.SetEnvironConfig(bad, good)124 err = s.State.UpdateEnvironConfig(badUpdateAttrs, nil, nil)
124 c.Assert(err, gc.ErrorMatches, "admin-secret should never be written to the state")125 c.Assert(err, gc.ErrorMatches, "admin-secret should never be written to the state")
125126
126 // EnvironConfig remains inviolate.127 // EnvironConfig remains inviolate.
@@ -140,12 +141,11 @@
140 _, err = state.Initialize(state.TestingStateInfo(), bad, state.TestingDialOpts(), state.Policy(nil))141 _, err = state.Initialize(state.TestingStateInfo(), bad, state.TestingDialOpts(), state.Policy(nil))
141 c.Assert(err, gc.ErrorMatches, "agent-version must always be set in state")142 c.Assert(err, gc.ErrorMatches, "agent-version must always be set in state")
142143
143 // Bad agent-version blocks SetEnvironConfig.
144 st := state.TestingInitialize(c, good, state.Policy(nil))144 st := state.TestingInitialize(c, good, state.Policy(nil))
145 st.Close()145 st.Close()
146146
147 s.openState(c)147 s.openState(c)
148 err = s.State.SetEnvironConfig(bad, good)148 err = s.State.UpdateEnvironConfig(map[string]interface{}{}, []string{"agent-version"}, nil)
149 c.Assert(err, gc.ErrorMatches, "agent-version must always be set in state")149 c.Assert(err, gc.ErrorMatches, "agent-version must always be set in state")
150150
151 // EnvironConfig remains inviolate.151 // EnvironConfig remains inviolate.
152152
=== modified file 'state/machine_test.go'
--- state/machine_test.go 2014-03-13 07:54:56 +0000
+++ state/machine_test.go 2014-03-18 02:38:23 +0000
@@ -79,9 +79,8 @@
79 manual, err := s.machine0.IsManual()79 manual, err := s.machine0.IsManual()
80 c.Assert(err, gc.IsNil)80 c.Assert(err, gc.IsNil)
81 c.Assert(manual, jc.IsFalse)81 c.Assert(manual, jc.IsFalse)
82 newcfg, err := cfg.Apply(map[string]interface{}{"type": "null"})82 attrs := map[string]interface{}{"type": "null"}
83 c.Assert(err, gc.IsNil)83 err = s.State.UpdateEnvironConfig(attrs, nil, nil)
84 err = s.State.SetEnvironConfig(newcfg, cfg)
85 c.Assert(err, gc.IsNil)84 c.Assert(err, gc.IsNil)
86 manual, err = s.machine0.IsManual()85 manual, err = s.machine0.IsManual()
87 c.Assert(err, gc.IsNil)86 c.Assert(err, gc.IsNil)
8887
=== modified file 'state/policy.go'
--- state/policy.go 2014-02-20 08:11:19 +0000
+++ state/policy.go 2014-03-18 02:38:23 +0000
@@ -24,6 +24,10 @@
24 // Prechecker takes a *config.Config and returns24 // Prechecker takes a *config.Config and returns
25 // a (possibly nil) Prechecker or an error.25 // a (possibly nil) Prechecker or an error.
26 Prechecker(*config.Config) (Prechecker, error)26 Prechecker(*config.Config) (Prechecker, error)
27
28 // ConfigValidator takes a string (environ type) and returns
29 // a (possibly nil) ConfigValidator or an error.
30 ConfigValidator(string) (ConfigValidator, error)
27}31}
2832
29// Prechecker is a policy interface that is provided to State33// Prechecker is a policy interface that is provided to State
@@ -40,6 +44,12 @@
40 PrecheckInstance(series string, cons constraints.Value) error44 PrecheckInstance(series string, cons constraints.Value) error
41}45}
4246
47// ConfigValidator is a policy interface that is provided to State
48// to check validity of new configuration attributes before applying them to state.
49type ConfigValidator interface {
50 Validate(cfg, old *config.Config) (valid *config.Config, err error)
51}
52
43// precheckInstance calls the state's assigned policy, if non-nil, to obtain53// precheckInstance calls the state's assigned policy, if non-nil, to obtain
44// a Prechecker, and calls PrecheckInstance if a non-nil Prechecker is returned.54// a Prechecker, and calls PrecheckInstance if a non-nil Prechecker is returned.
45func (st *State) precheckInstance(series string, cons constraints.Value) error {55func (st *State) precheckInstance(series string, cons constraints.Value) error {
@@ -61,3 +71,21 @@
61 }71 }
62 return prechecker.PrecheckInstance(series, cons)72 return prechecker.PrecheckInstance(series, cons)
63}73}
74
75// validate calls the state's assigned policy, if non-nil, to obtain
76// a Validator, and calls validate if a non-nil Validator is returned.
77func (st *State) validate(cfg, old *config.Config) (valid *config.Config, err error) {
78 if st.policy == nil {
79 return cfg, nil
80 }
81 configValidator, err := st.policy.ConfigValidator(cfg.Type())
82 if errors.IsNotImplementedError(err) {
83 return cfg, nil
84 } else if err != nil {
85 return nil, err
86 }
87 if configValidator == nil {
88 return nil, fmt.Errorf("policy returned nil configValidator without an error")
89 }
90 return configValidator.Validate(cfg, old)
91}
6492
=== modified file 'state/state.go'
--- state/state.go 2014-03-13 13:42:50 +0000
+++ state/state.go 2014-03-18 02:38:23 +0000
@@ -259,12 +259,33 @@
259 return ErrExcessiveContention259 return ErrExcessiveContention
260}260}
261261
262// SetEnvironConfig replaces the current configuration of the262func (st *State) buildAndValidateEnvironConfig(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) (validCfg *config.Config, err error) {
263// environment with the provided configuration.263 newConfig, err := oldConfig.Apply(updateAttrs)
264func (st *State) SetEnvironConfig(cfg, old *config.Config) error {264 if err != nil {
265 if err := checkEnvironConfig(cfg); err != nil {265 return nil, err
266 return err266 }
267 }267 if len(removeAttrs) != 0 {
268 newConfig, err = newConfig.Remove(removeAttrs)
269 if err != nil {
270 return nil, err
271 }
272 }
273 if err := checkEnvironConfig(newConfig); err != nil {
274 return nil, err
275 }
276 return st.validate(newConfig, oldConfig)
277}
278
279type ValidateConfigFunc func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error
280
281// UpateEnvironConfig adds, updates or removes attributes in the current
282// configuration of the environment with the provided updateAttrs and
283// removeAttrs.
284func (st *State) UpdateEnvironConfig(updateAttrs map[string]interface{}, removeAttrs []string, additionalValidation ValidateConfigFunc) error {
285 if len(updateAttrs)+len(removeAttrs) == 0 {
286 return nil
287 }
288
268 // TODO(axw) 2013-12-6 #1167616289 // TODO(axw) 2013-12-6 #1167616
269 // Ensure that the settings on disk have not changed290 // Ensure that the settings on disk have not changed
270 // underneath us. The settings changes are actually291 // underneath us. The settings changes are actually
@@ -275,13 +296,30 @@
275 if err != nil {296 if err != nil {
276 return err297 return err
277 }298 }
278 newattrs := cfg.AllAttrs()299
279 for k, _ := range old.AllAttrs() {300 // Get the existing environment config from state.
280 if _, ok := newattrs[k]; !ok {301 oldConfig, err := config.New(config.NoDefaults, settings.Map())
302 if err != nil {
303 return err
304 }
305 if additionalValidation != nil {
306 err = additionalValidation(updateAttrs, removeAttrs, oldConfig)
307 if err != nil {
308 return err
309 }
310 }
311 validCfg, err := st.buildAndValidateEnvironConfig(updateAttrs, removeAttrs, oldConfig)
312 if err != nil {
313 return err
314 }
315
316 validAttrs := validCfg.AllAttrs()
317 for k, _ := range oldConfig.AllAttrs() {
318 if _, ok := validAttrs[k]; !ok {
281 settings.Delete(k)319 settings.Delete(k)
282 }320 }
283 }321 }
284 settings.Update(newattrs)322 settings.Update(validAttrs)
285 _, err = settings.Write()323 _, err = settings.Write()
286 return err324 return err
287}325}
288326
=== modified file 'state/state_test.go'
--- state/state_test.go 2014-03-17 16:39:43 +0000
+++ state/state_test.go 2014-03-18 02:38:23 +0000
@@ -1250,18 +1250,20 @@
1250}1250}
12511251
1252func (s *StateSuite) TestEnvironConfig(c *gc.C) {1252func (s *StateSuite) TestEnvironConfig(c *gc.C) {
1253 cfg, err := s.State.EnvironConfig()1253 attrs := map[string]interface{}{
1254 c.Assert(err, gc.IsNil)
1255 change, err := cfg.Apply(map[string]interface{}{
1256 "authorized-keys": "different-keys",1254 "authorized-keys": "different-keys",
1257 "arbitrary-key": "shazam!",1255 "arbitrary-key": "shazam!",
1258 })1256 }
1259 c.Assert(err, gc.IsNil)1257 cfg, err := s.State.EnvironConfig()
1260 err = s.State.SetEnvironConfig(change, cfg)1258 c.Assert(err, gc.IsNil)
1261 c.Assert(err, gc.IsNil)1259 err = s.State.UpdateEnvironConfig(attrs, nil, nil)
1262 cfg, err = s.State.EnvironConfig()1260 c.Assert(err, gc.IsNil)
1263 c.Assert(err, gc.IsNil)1261 cfg, err = cfg.Apply(attrs)
1264 c.Assert(cfg.AllAttrs(), gc.DeepEquals, change.AllAttrs())1262 c.Assert(err, gc.IsNil)
1263 oldCfg, err := s.State.EnvironConfig()
1264 c.Assert(err, gc.IsNil)
1265
1266 c.Assert(oldCfg, gc.DeepEquals, cfg)
1265}1267}
12661268
1267func (s *StateSuite) TestEnvironConstraints(c *gc.C) {1269func (s *StateSuite) TestEnvironConstraints(c *gc.C) {
@@ -1681,6 +1683,37 @@
1681 })1683 })
1682}1684}
16831685
1686func (s *StateSuite) TestAdditionalValidation(c *gc.C) {
1687 updateAttrs := map[string]interface{}{"logging-config": "juju=ERROR"}
1688 configValidator1 := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error {
1689 c.Assert(updateAttrs, gc.DeepEquals, map[string]interface{}{"logging-config": "juju=ERROR"})
1690 if _, found := updateAttrs["logging-config"]; found {
1691 return fmt.Errorf("cannot change logging-config")
1692 }
1693 return nil
1694 }
1695 removeAttrs := []string{"logging-config"}
1696 configValidator2 := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error {
1697 c.Assert(removeAttrs, gc.DeepEquals, []string{"logging-config"})
1698 for _, i := range removeAttrs {
1699 if i == "logging-config" {
1700 return fmt.Errorf("cannot remove logging-config")
1701 }
1702 }
1703 return nil
1704 }
1705 configValidator3 := func(updateAttrs map[string]interface{}, removeAttrs []string, oldConfig *config.Config) error {
1706 return nil
1707 }
1708
1709 err := s.State.UpdateEnvironConfig(updateAttrs, nil, configValidator1)
1710 c.Assert(err, gc.ErrorMatches, "cannot change logging-config")
1711 err = s.State.UpdateEnvironConfig(nil, removeAttrs, configValidator2)
1712 c.Assert(err, gc.ErrorMatches, "cannot remove logging-config")
1713 err = s.State.UpdateEnvironConfig(updateAttrs, nil, configValidator3)
1714 c.Assert(err, gc.IsNil)
1715}
1716
1684type attrs map[string]interface{}1717type attrs map[string]interface{}
16851718
1686func (s *StateSuite) TestWatchEnvironConfig(c *gc.C) {1719func (s *StateSuite) TestWatchEnvironConfig(c *gc.C) {
@@ -1699,11 +1732,10 @@
1699 assertChange := func(change attrs) {1732 assertChange := func(change attrs) {
1700 cfg, err := s.State.EnvironConfig()1733 cfg, err := s.State.EnvironConfig()
1701 c.Assert(err, gc.IsNil)1734 c.Assert(err, gc.IsNil)
1735 cfg, err = cfg.Apply(change)
1736 c.Assert(err, gc.IsNil)
1702 if change != nil {1737 if change != nil {
1703 oldcfg := cfg1738 err = s.State.UpdateEnvironConfig(change, nil, nil)
1704 cfg, err = cfg.Apply(change)
1705 c.Assert(err, gc.IsNil)
1706 err = s.State.SetEnvironConfig(cfg, oldcfg)
1707 c.Assert(err, gc.IsNil)1739 c.Assert(err, gc.IsNil)
1708 }1740 }
1709 s.State.StartSync()1741 s.State.StartSync()
@@ -1761,7 +1793,6 @@
1761func (s *StateSuite) TestWatchEnvironConfigCorruptConfig(c *gc.C) {1793func (s *StateSuite) TestWatchEnvironConfigCorruptConfig(c *gc.C) {
1762 cfg, err := s.State.EnvironConfig()1794 cfg, err := s.State.EnvironConfig()
1763 c.Assert(err, gc.IsNil)1795 c.Assert(err, gc.IsNil)
1764 oldcfg := cfg
17651796
1766 // Corrupt the environment configuration.1797 // Corrupt the environment configuration.
1767 settings := s.Session.DB("juju").C("settings")1798 settings := s.Session.DB("juju").C("settings")
@@ -1797,9 +1828,11 @@
1797 }1828 }
17981829
1799 // Fix the configuration.1830 // Fix the configuration.
1800 err = s.State.SetEnvironConfig(cfg, oldcfg)1831 err = settings.UpdateId("e", bson.D{{"$set", bson.D{{"name", "foo"}}}})
1801 c.Assert(err, gc.IsNil)1832 c.Assert(err, gc.IsNil)
1802 fixed := cfg.AllAttrs()1833 fixed := cfg.AllAttrs()
1834 err = s.State.UpdateEnvironConfig(fixed, nil, nil)
1835 c.Assert(err, gc.IsNil)
18031836
1804 s.State.StartSync()1837 s.State.StartSync()
1805 select {1838 select {
@@ -2559,9 +2592,7 @@
2559func (s *StateSuite) changeEnviron(c *gc.C, envConfig *config.Config, name string, value interface{}) {2592func (s *StateSuite) changeEnviron(c *gc.C, envConfig *config.Config, name string, value interface{}) {
2560 attrs := envConfig.AllAttrs()2593 attrs := envConfig.AllAttrs()
2561 attrs[name] = value2594 attrs[name] = value
2562 newConfig, err := config.New(config.NoDefaults, attrs)2595 c.Assert(s.State.UpdateEnvironConfig(attrs, nil, nil), gc.IsNil)
2563 c.Assert(err, gc.IsNil)
2564 c.Assert(s.State.SetEnvironConfig(newConfig, envConfig), gc.IsNil)
2565}2596}
25662597
2567func (s *StateSuite) assertAgentVersion(c *gc.C, envConfig *config.Config, vers string) {2598func (s *StateSuite) assertAgentVersion(c *gc.C, envConfig *config.Config, vers string) {
25682599
=== modified file 'state/testing/agent.go'
--- state/testing/agent.go 2013-09-11 03:48:05 +0000
+++ state/testing/agent.go 2014-03-18 02:38:23 +0000
@@ -11,5 +11,5 @@
11// SetAgentVersion sets the current agent version in the state's11// SetAgentVersion sets the current agent version in the state's
12// environment configuration.12// environment configuration.
13func SetAgentVersion(st *state.State, vers version.Number) error {13func SetAgentVersion(st *state.State, vers version.Number) error {
14 return UpdateConfig(st, map[string]interface{}{"agent-version": vers.String()})14 return st.UpdateEnvironConfig(map[string]interface{}{"agent-version": vers.String()}, nil, nil)
15}15}
1616
=== removed file 'state/testing/config.go'
--- state/testing/config.go 2013-12-06 04:47:45 +0000
+++ state/testing/config.go 1970-01-01 00:00:00 +0000
@@ -1,22 +0,0 @@
1// Copyright 2013 Canonical Ltd.
2// Licensed under the AGPLv3, see LICENCE file for details.
3
4package testing
5
6import (
7 "launchpad.net/juju-core/state"
8)
9
10// UpdateConfig sets the current agent version in the state's
11// environment configuration.
12func UpdateConfig(st *state.State, newValues map[string]interface{}) error {
13 cfg, err := st.EnvironConfig()
14 if err != nil {
15 return err
16 }
17 newcfg, err := cfg.Apply(newValues)
18 if err != nil {
19 return err
20 }
21 return st.SetEnvironConfig(newcfg, cfg)
22}
230
=== modified file 'upgrades/deprecatedattributes.go'
--- upgrades/deprecatedattributes.go 2014-03-07 02:48:20 +0000
+++ upgrades/deprecatedattributes.go 2014-03-18 02:38:23 +0000
@@ -3,29 +3,16 @@
33
4package upgrades4package upgrades
55
6import (
7 "fmt"
8
9 "launchpad.net/juju-core/environs/config"
10)
11
12func processDeprecatedAttributes(context Context) error {6func processDeprecatedAttributes(context Context) error {
13 st := context.State()7 st := context.State()
14 cfg, err := st.EnvironConfig()8 removeAttrs := []string{
15 if err != nil {9 "public-bucket",
16 return fmt.Errorf("failed to read current config: %v", err)10 "public-bucket-region",
11 "public-bucket-url",
12 "default-image-id",
13 "default-instance-type",
14 "shared-storage-port",
17 }15 }
18 newAttrs := cfg.AllAttrs()
19 delete(newAttrs, "public-bucket")
20 delete(newAttrs, "public-bucket-region")
21 delete(newAttrs, "public-bucket-url")
22 delete(newAttrs, "default-image-id")
23 delete(newAttrs, "default-instance-type")
24 delete(newAttrs, "shared-storage-port")
25 // TODO (wallyworld) - delete tools-url in 1.2016 // TODO (wallyworld) - delete tools-url in 1.20
26 newCfg, err := config.New(config.NoDefaults, newAttrs)17 return st.UpdateEnvironConfig(map[string]interface{}{}, removeAttrs, nil)
27 if err != nil {
28 return fmt.Errorf("failed to create new config: %v", err)
29 }
30 return st.SetEnvironConfig(newCfg, cfg)
31}18}
3219
=== modified file 'upgrades/deprecatedattributes_test.go'
--- upgrades/deprecatedattributes_test.go 2014-03-13 07:54:56 +0000
+++ upgrades/deprecatedattributes_test.go 2014-03-18 02:38:23 +0000
@@ -27,19 +27,16 @@
27 apiState: apiState,27 apiState: apiState,
28 state: s.State,28 state: s.State,
29 }29 }
30 cfg, err := s.State.EnvironConfig()
31 c.Assert(err, gc.IsNil)
32 // Add in old attributes.30 // Add in old attributes.
33 newCfg, err := cfg.Apply(map[string]interface{}{31 newCfg := map[string]interface{}{
34 "public-bucket": "foo",32 "public-bucket": "foo",
35 "public-bucket-region": "bar",33 "public-bucket-region": "bar",
36 "public-bucket-url": "shazbot",34 "public-bucket-url": "shazbot",
37 "default-instance-type": "vulch",35 "default-instance-type": "vulch",
38 "default-image-id": "1234",36 "default-image-id": "1234",
39 "shared-storage-port": 1234,37 "shared-storage-port": 1234,
40 })38 }
41 c.Assert(err, gc.IsNil)39 err := s.State.UpdateEnvironConfig(newCfg, nil, nil)
42 err = s.State.SetEnvironConfig(newCfg, cfg)
43 c.Assert(err, gc.IsNil)40 c.Assert(err, gc.IsNil)
44}41}
4542
4643
=== modified file 'upgrades/rsyslogport.go'
--- upgrades/rsyslogport.go 2014-02-28 05:44:03 +0000
+++ upgrades/rsyslogport.go 2014-03-18 02:38:23 +0000
@@ -9,15 +9,8 @@
99
10func updateRsyslogPort(context Context) error {10func updateRsyslogPort(context Context) error {
11 st := context.State()11 st := context.State()
12 old, err := st.EnvironConfig()12 attrs := map[string]interface{}{
13 if err != nil {
14 return err
15 }
16 cfg, err := old.Apply(map[string]interface{}{
17 "syslog-port": config.DefaultSyslogPort,13 "syslog-port": config.DefaultSyslogPort,
18 })
19 if err != nil {
20 return err
21 }14 }
22 return st.SetEnvironConfig(cfg, old)15 return st.UpdateEnvironConfig(attrs, nil, nil)
23}16}
2417
=== modified file 'worker/authenticationworker/worker_test.go'
--- worker/authenticationworker/worker_test.go 2013-12-23 05:18:58 +0000
+++ worker/authenticationworker/worker_test.go 2014-03-18 02:38:23 +0000
@@ -15,7 +15,6 @@
15 "launchpad.net/juju-core/state"15 "launchpad.net/juju-core/state"
16 "launchpad.net/juju-core/state/api"16 "launchpad.net/juju-core/state/api"
17 "launchpad.net/juju-core/state/api/keyupdater"17 "launchpad.net/juju-core/state/api/keyupdater"
18 "launchpad.net/juju-core/state/testing"
19 coretesting "launchpad.net/juju-core/testing"18 coretesting "launchpad.net/juju-core/testing"
20 "launchpad.net/juju-core/utils/ssh"19 "launchpad.net/juju-core/utils/ssh"
21 sshtesting "launchpad.net/juju-core/utils/ssh/testing"20 sshtesting "launchpad.net/juju-core/utils/ssh/testing"
@@ -90,7 +89,7 @@
9089
91func (s *workerSuite) setAuthorisedKeys(c *gc.C, keys ...string) {90func (s *workerSuite) setAuthorisedKeys(c *gc.C, keys ...string) {
92 keyStr := strings.Join(keys, "\n")91 keyStr := strings.Join(keys, "\n")
93 err := testing.UpdateConfig(s.BackingState, map[string]interface{}{"authorized-keys": keyStr})92 err := s.BackingState.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": keyStr}, nil, nil)
94 c.Assert(err, gc.IsNil)93 c.Assert(err, gc.IsNil)
95 s.BackingState.StartSync()94 s.BackingState.StartSync()
96}95}
9796
=== modified file 'worker/environ_test.go'
--- worker/environ_test.go 2013-12-05 03:42:25 +0000
+++ worker/environ_test.go 2014-03-18 02:38:23 +0000
@@ -46,30 +46,34 @@
46}46}
4747
48func (s *waitForEnvironSuite) TestInvalidConfig(c *gc.C) {48func (s *waitForEnvironSuite) TestInvalidConfig(c *gc.C) {
49 var oldType string
50 oldType = s.Conn.Environ.Config().AllAttrs()["type"].(string)
51
49 // Create an invalid config by taking the current config and52 // Create an invalid config by taking the current config and
50 // tweaking the provider type.53 // tweaking the provider type.
51 var oldType string54 info := s.StateInfo(c)
52 testing.ChangeEnvironConfig(c, s.State, func(attrs coretesting.Attrs) coretesting.Attrs {55 opts := state.DefaultDialOpts()
53 oldType = attrs["type"].(string)56 st2, err := state.Open(info, opts, state.Policy(nil))
54 return attrs.Merge(coretesting.Attrs{"type": "unknown"})57 c.Assert(err, gc.IsNil)
55 })58 defer st2.Close()
56 w := s.State.WatchForEnvironConfigChanges()59 err = st2.UpdateEnvironConfig(map[string]interface{}{"type": "unknown"}, nil, nil)
60 c.Assert(err, gc.IsNil)
61
62 w := st2.WatchForEnvironConfigChanges()
57 defer stopWatcher(c, w)63 defer stopWatcher(c, w)
58 done := make(chan environs.Environ)64 done := make(chan environs.Environ)
59 go func() {65 go func() {
60 env, err := worker.WaitForEnviron(w, s.State, nil)66 env, err := worker.WaitForEnviron(w, st2, nil)
61 c.Check(err, gc.IsNil)67 c.Check(err, gc.IsNil)
62 done <- env68 done <- env
63 }()69 }()
64 // Wait for the loop to process the invalid configuratrion70 // Wait for the loop to process the invalid configuratrion
65 <-worker.LoadedInvalid71 <-worker.LoadedInvalid
6672
67 testing.ChangeEnvironConfig(c, s.State, func(attrs coretesting.Attrs) coretesting.Attrs {73 st2.UpdateEnvironConfig(map[string]interface{}{
68 return attrs.Merge(coretesting.Attrs{74 "type": oldType,
69 "type": oldType,75 "secret": "environ_test",
70 "secret": "environ_test",76 }, nil, nil)
71 })
72 })
7377
74 env := <-done78 env := <-done
75 c.Assert(env, gc.NotNil)79 c.Assert(env, gc.NotNil)
7680
=== modified file 'worker/firewaller/firewaller_test.go'
--- worker/firewaller/firewaller_test.go 2014-01-22 15:40:18 +0000
+++ worker/firewaller/firewaller_test.go 2014-03-18 02:38:23 +0000
@@ -4,13 +4,13 @@
4package firewaller_test4package firewaller_test
55
6import (6import (
7 "launchpad.net/juju-core/environs/config"
7 "reflect"8 "reflect"
8 stdtesting "testing"9 stdtesting "testing"
9 "time"10 "time"
1011
11 gc "launchpad.net/gocheck"12 gc "launchpad.net/gocheck"
1213
13 "launchpad.net/juju-core/environs/config"
14 "launchpad.net/juju-core/instance"14 "launchpad.net/juju-core/instance"
15 "launchpad.net/juju-core/juju"15 "launchpad.net/juju-core/juju"
16 "launchpad.net/juju-core/juju/testing"16 "launchpad.net/juju-core/juju/testing"
@@ -37,6 +37,10 @@
37 firewaller *apifirewaller.State37 firewaller *apifirewaller.State
38}38}
3939
40type FirewallerGlobalModeSuite struct {
41 FirewallerSuite
42}
43
40var _ worker.Worker = (*firewaller.Firewaller)(nil)44var _ worker.Worker = (*firewaller.Firewaller)(nil)
4145
42// assertPorts retrieves the open ports of the instance and compares them46// assertPorts retrieves the open ports of the instance and compares them
@@ -91,6 +95,13 @@
9195
92var _ = gc.Suite(&FirewallerSuite{})96var _ = gc.Suite(&FirewallerSuite{})
9397
98func (s FirewallerGlobalModeSuite) SetUpTest(c *gc.C) {
99 add := map[string]interface{}{"firewall-mode": config.FwGlobal}
100 s.DummyConfig = dummy.SampleConfig().Merge(add).Delete("admin-secret", "ca-private-key")
101
102 s.FirewallerSuite.SetUpTest(c)
103}
104
94func (s *FirewallerSuite) SetUpTest(c *gc.C) {105func (s *FirewallerSuite) SetUpTest(c *gc.C) {
95 s.JujuConnSuite.SetUpTest(c)106 s.JujuConnSuite.SetUpTest(c)
96 s.charm = s.AddTestingCharm(c, "dummy")107 s.charm = s.AddTestingCharm(c, "dummy")
@@ -129,23 +140,6 @@
129 return u, m140 return u, m
130}141}
131142
132func (s *FirewallerSuite) setGlobalMode(c *gc.C) {
133 // TODO(rog) This should not be possible - you shouldn't
134 // be able to set the firewalling mode after an environment
135 // has bootstrapped.
136 oldConfig := s.Conn.Environ.Config()
137 attrs := oldConfig.AllAttrs()
138 delete(attrs, "admin-secret")
139 delete(attrs, "ca-private-key")
140 attrs["firewall-mode"] = config.FwGlobal
141 newConfig, err := config.New(config.NoDefaults, attrs)
142 c.Assert(err, gc.IsNil)
143 err = s.State.SetEnvironConfig(newConfig, oldConfig)
144 c.Assert(err, gc.IsNil)
145 err = s.Conn.Environ.SetConfig(newConfig)
146 c.Assert(err, gc.IsNil)
147}
148
149// startInstance starts a new instance for the given machine.143// startInstance starts a new instance for the given machine.
150func (s *FirewallerSuite) startInstance(c *gc.C, m *state.Machine) instance.Instance {144func (s *FirewallerSuite) startInstance(c *gc.C, m *state.Machine) instance.Instance {
151 inst, hc := testing.AssertStartInstance(c, s.Conn.Environ, m.Id())145 inst, hc := testing.AssertStartInstance(c, s.Conn.Environ, m.Id())
@@ -573,10 +567,7 @@
573 c.Assert(err, gc.IsNil)567 c.Assert(err, gc.IsNil)
574}568}
575569
576func (s *FirewallerSuite) TestGlobalMode(c *gc.C) {570func (s *FirewallerGlobalModeSuite) TestGlobalMode(c *gc.C) {
577 // Change configuration.
578 s.setGlobalMode(c)
579
580 // Start firewaller and open ports.571 // Start firewaller and open ports.
581 fw, err := firewaller.NewFirewaller(s.firewaller)572 fw, err := firewaller.NewFirewaller(s.firewaller)
582 c.Assert(err, gc.IsNil)573 c.Assert(err, gc.IsNil)
@@ -621,10 +612,7 @@
621 s.assertEnvironPorts(c, nil)612 s.assertEnvironPorts(c, nil)
622}613}
623614
624func (s *FirewallerSuite) TestGlobalModeStartWithUnexposedService(c *gc.C) {615func (s *FirewallerGlobalModeSuite) TestGlobalModeStartWithUnexposedService(c *gc.C) {
625 // Change configuration.
626 s.setGlobalMode(c)
627
628 m, err := s.State.AddMachine("quantal", state.JobHostUnits)616 m, err := s.State.AddMachine("quantal", state.JobHostUnits)
629 c.Assert(err, gc.IsNil)617 c.Assert(err, gc.IsNil)
630 s.startInstance(c, m)618 s.startInstance(c, m)
@@ -650,10 +638,7 @@
650 s.assertEnvironPorts(c, []instance.Port{{"tcp", 80}})638 s.assertEnvironPorts(c, []instance.Port{{"tcp", 80}})
651}639}
652640
653func (s *FirewallerSuite) TestGlobalModeRestart(c *gc.C) {641func (s *FirewallerGlobalModeSuite) TestGlobalModeRestart(c *gc.C) {
654 // Change configuration.
655 s.setGlobalMode(c)
656
657 // Start firewaller and open ports.642 // Start firewaller and open ports.
658 fw, err := firewaller.NewFirewaller(s.firewaller)643 fw, err := firewaller.NewFirewaller(s.firewaller)
659 c.Assert(err, gc.IsNil)644 c.Assert(err, gc.IsNil)
@@ -688,10 +673,7 @@
688 s.assertEnvironPorts(c, []instance.Port{{"tcp", 80}, {"tcp", 8888}})673 s.assertEnvironPorts(c, []instance.Port{{"tcp", 80}, {"tcp", 8888}})
689}674}
690675
691func (s *FirewallerSuite) TestGlobalModeRestartUnexposedService(c *gc.C) {676func (s *FirewallerGlobalModeSuite) TestGlobalModeRestartUnexposedService(c *gc.C) {
692 // Change configuration.
693 s.setGlobalMode(c)
694
695 // Start firewaller and open ports.677 // Start firewaller and open ports.
696 fw, err := firewaller.NewFirewaller(s.firewaller)678 fw, err := firewaller.NewFirewaller(s.firewaller)
697 c.Assert(err, gc.IsNil)679 c.Assert(err, gc.IsNil)
@@ -724,10 +706,7 @@
724 s.assertEnvironPorts(c, nil)706 s.assertEnvironPorts(c, nil)
725}707}
726708
727func (s *FirewallerSuite) TestGlobalModeRestartPortCount(c *gc.C) {709func (s *FirewallerGlobalModeSuite) TestGlobalModeRestartPortCount(c *gc.C) {
728 // Change configuration.
729 s.setGlobalMode(c)
730
731 // Start firewaller and open ports.710 // Start firewaller and open ports.
732 fw, err := firewaller.NewFirewaller(s.firewaller)711 fw, err := firewaller.NewFirewaller(s.firewaller)
733 c.Assert(err, gc.IsNil)712 c.Assert(err, gc.IsNil)
734713
=== modified file 'worker/instancepoller/observer_test.go'
--- worker/instancepoller/observer_test.go 2014-03-05 19:41:34 +0000
+++ worker/instancepoller/observer_test.go 2014-03-18 02:38:23 +0000
@@ -12,6 +12,7 @@
12 gc "launchpad.net/gocheck"12 gc "launchpad.net/gocheck"
1313
14 "launchpad.net/juju-core/juju/testing"14 "launchpad.net/juju-core/juju/testing"
15 "launchpad.net/juju-core/state"
15 coretesting "launchpad.net/juju-core/testing"16 coretesting "launchpad.net/juju-core/testing"
16)17)
1718
@@ -43,17 +44,18 @@
4344
44 env := obs.Environ()45 env := obs.Environ()
45 c.Assert(env.Config().AllAttrs(), gc.DeepEquals, originalConfig.AllAttrs())46 c.Assert(env.Config().AllAttrs(), gc.DeepEquals, originalConfig.AllAttrs())
46
47 var oldType string47 var oldType string
48 oldType = env.Config().AllAttrs()["type"].(string)
49
50 info := s.StateInfo(c)
51 opts := state.DefaultDialOpts()
52 st2, err := state.Open(info, opts, state.Policy(nil))
53 defer st2.Close()
54
48 // Change to an invalid configuration and check55 // Change to an invalid configuration and check
49 // that the observer's environment remains the same.56 // that the observer's environment remains the same.
50 testing.ChangeEnvironConfig(c, s.State, func(attrs coretesting.Attrs) coretesting.Attrs {57 st2.UpdateEnvironConfig(map[string]interface{}{"type": "invalid"}, nil, nil)
51 oldType = attrs["type"].(string)58 st2.StartSync()
52 return attrs.Merge(coretesting.Attrs{
53 "type": "invalid",
54 })
55 })
56 s.State.StartSync()
5759
58 // Wait for the observer to register the invalid environment60 // Wait for the observer to register the invalid environment
59 timeout := time.After(coretesting.LongWait)61 timeout := time.After(coretesting.LongWait)
@@ -74,13 +76,8 @@
7476
75 // Change the environment back to a valid configuration77 // Change the environment back to a valid configuration
76 // with a different name and check that we see it.78 // with a different name and check that we see it.
77 testing.ChangeEnvironConfig(c, s.State, func(attrs coretesting.Attrs) coretesting.Attrs {79 st2.UpdateEnvironConfig(map[string]interface{}{"type": oldType, "name": "a-new-name"}, nil, nil)
78 return attrs.Merge(coretesting.Attrs{80 st2.StartSync()
79 "type": oldType,
80 "name": "a-new-name",
81 })
82 })
83 s.State.StartSync()
8481
85 for a := coretesting.LongAttempt.Start(); a.Next(); {82 for a := coretesting.LongAttempt.Start(); a.Next(); {
86 env := obs.Environ()83 env := obs.Environ()
8784
=== modified file 'worker/machineenvironmentworker/machineenvironmentworker_test.go'
--- worker/machineenvironmentworker/machineenvironmentworker_test.go 2014-03-13 07:54:56 +0000
+++ worker/machineenvironmentworker/machineenvironmentworker_test.go 2014-03-18 02:38:23 +0000
@@ -119,8 +119,6 @@
119}119}
120120
121func (s *MachineEnvironmentWatcherSuite) updateConfig(c *gc.C) (osenv.ProxySettings, osenv.ProxySettings) {121func (s *MachineEnvironmentWatcherSuite) updateConfig(c *gc.C) (osenv.ProxySettings, osenv.ProxySettings) {
122 oldConfig, err := s.State.EnvironConfig()
123 c.Assert(err, gc.IsNil)
124122
125 proxySettings := osenv.ProxySettings{123 proxySettings := osenv.ProxySettings{
126 Http: "http proxy",124 Http: "http proxy",
@@ -128,9 +126,10 @@
128 Ftp: "ftp proxy",126 Ftp: "ftp proxy",
129 NoProxy: "no proxy",127 NoProxy: "no proxy",
130 }128 }
131129 attrs := map[string]interface{}{}
132 envConfig, err := oldConfig.Apply(config.ProxyConfigMap(proxySettings))130 for k, v := range config.ProxyConfigMap(proxySettings) {
133 c.Assert(err, gc.IsNil)131 attrs[k] = v
132 }
134133
135 // We explicitly set apt proxy settings as well to show that it is the apt134 // We explicitly set apt proxy settings as well to show that it is the apt
136 // settings that are used for the apt config, and not just the normal135 // settings that are used for the apt config, and not just the normal
@@ -141,10 +140,11 @@
141 Https: "apt https proxy",140 Https: "apt https proxy",
142 Ftp: "apt ftp proxy",141 Ftp: "apt ftp proxy",
143 }142 }
144 envConfig, err = envConfig.Apply(config.AptProxyConfigMap(aptProxySettings))143 for k, v := range config.AptProxyConfigMap(aptProxySettings) {
145 c.Assert(err, gc.IsNil)144 attrs[k] = v
145 }
146146
147 err = s.State.SetEnvironConfig(envConfig, oldConfig)147 err := s.State.UpdateEnvironConfig(attrs, nil, nil)
148 c.Assert(err, gc.IsNil)148 c.Assert(err, gc.IsNil)
149149
150 return proxySettings, aptProxySettings150 return proxySettings, aptProxySettings
151151
=== modified file 'worker/provisioner/provisioner_test.go'
--- worker/provisioner/provisioner_test.go 2014-03-13 07:54:56 +0000
+++ worker/provisioner/provisioner_test.go 2014-03-18 02:38:23 +0000
@@ -96,11 +96,8 @@
96// that causes the given environMethod of the dummy provider to return96// that causes the given environMethod of the dummy provider to return
97// an error, which is also returned as a message to be checked.97// an error, which is also returned as a message to be checked.
98func breakDummyProvider(c *gc.C, st *state.State, environMethod string) string {98func breakDummyProvider(c *gc.C, st *state.State, environMethod string) string {
99 oldCfg, err := st.EnvironConfig()99 attrs := map[string]interface{}{"broken": environMethod}
100 c.Assert(err, gc.IsNil)100 err := st.UpdateEnvironConfig(attrs, nil, nil)
101 cfg, err := oldCfg.Apply(map[string]interface{}{"broken": environMethod})
102 c.Assert(err, gc.IsNil)
103 err = st.SetEnvironConfig(cfg, oldCfg)
104 c.Assert(err, gc.IsNil)101 c.Assert(err, gc.IsNil)
105 return fmt.Sprintf("dummy.%s is broken", environMethod)102 return fmt.Sprintf("dummy.%s is broken", environMethod)
106}103}
@@ -121,21 +118,21 @@
121// so the Settings returned from the watcher will not pass118// so the Settings returned from the watcher will not pass
122// validation.119// validation.
123func (s *CommonProvisionerSuite) invalidateEnvironment(c *gc.C) {120func (s *CommonProvisionerSuite) invalidateEnvironment(c *gc.C) {
124 attrs := s.cfg.AllAttrs()121 st, err := state.Open(s.StateInfo(c), state.DefaultDialOpts(), state.Policy(nil))
125 attrs["type"] = "unknown"
126 invalidCfg, err := config.New(config.NoDefaults, attrs)
127 c.Assert(err, gc.IsNil)122 c.Assert(err, gc.IsNil)
128 err = s.State.SetEnvironConfig(invalidCfg, s.cfg)123 defer st.Close()
124 attrs := map[string]interface{}{"type": "unknown"}
125 err = st.UpdateEnvironConfig(attrs, nil, nil)
129 c.Assert(err, gc.IsNil)126 c.Assert(err, gc.IsNil)
130}127}
131128
132// fixEnvironment undoes the work of invalidateEnvironment.129// fixEnvironment undoes the work of invalidateEnvironment.
133func (s *CommonProvisionerSuite) fixEnvironment() error {130func (s *CommonProvisionerSuite) fixEnvironment(c *gc.C) error {
134 cfg, err := s.State.EnvironConfig()131 st, err := state.Open(s.StateInfo(c), state.DefaultDialOpts(), state.Policy(nil))
135 if err != nil {132 c.Assert(err, gc.IsNil)
136 return err133 defer st.Close()
137 }134 attrs := map[string]interface{}{"type": s.cfg.AllAttrs()["type"]}
138 return s.State.SetEnvironConfig(s.cfg, cfg)135 return st.UpdateEnvironConfig(attrs, nil, nil)
139}136}
140137
141// stopper is stoppable.138// stopper is stoppable.
@@ -415,7 +412,7 @@
415 }412 }
416413
417 // Unbreak the environ config.414 // Unbreak the environ config.
418 err = s.fixEnvironment()415 err = s.fixEnvironment(c)
419 c.Assert(err, gc.IsNil)416 c.Assert(err, gc.IsNil)
420417
421 // Restart the PA to make sure the machine is skipped again.418 // Restart the PA to make sure the machine is skipped again.
@@ -480,7 +477,7 @@
480 // the PA should not create it477 // the PA should not create it
481 s.checkNoOperations(c)478 s.checkNoOperations(c)
482479
483 err = s.fixEnvironment()480 err = s.fixEnvironment(c)
484 c.Assert(err, gc.IsNil)481 c.Assert(err, gc.IsNil)
485482
486 s.checkStartInstance(c, m)483 s.checkStartInstance(c, m)
@@ -611,20 +608,15 @@
611 // the PA should create it using the old environment608 // the PA should create it using the old environment
612 s.checkStartInstance(c, m)609 s.checkStartInstance(c, m)
613610
614 err = s.fixEnvironment()611 err = s.fixEnvironment(c)
615 c.Assert(err, gc.IsNil)612 c.Assert(err, gc.IsNil)
616613
617 // insert our observer614 // insert our observer
618 cfgObserver := make(chan *config.Config, 1)615 cfgObserver := make(chan *config.Config, 1)
619 provisioner.SetObserver(p, cfgObserver)616 provisioner.SetObserver(p, cfgObserver)
620617
621 oldcfg, err := s.State.EnvironConfig()618 err = s.State.UpdateEnvironConfig(map[string]interface{}{"secret": "beef"}, nil, nil)
622 c.Assert(err, gc.IsNil)619 c.Assert(err, gc.IsNil)
623 attrs := oldcfg.AllAttrs()
624 attrs["secret"] = "beef"
625 cfg, err := config.New(config.NoDefaults, attrs)
626 c.Assert(err, gc.IsNil)
627 err = s.State.SetEnvironConfig(cfg, oldcfg)
628620
629 s.BackingState.StartSync()621 s.BackingState.StartSync()
630622
@@ -666,13 +658,9 @@
666 c.Assert(m1.Remove(), gc.IsNil)658 c.Assert(m1.Remove(), gc.IsNil)
667659
668 // turn on safe mode660 // turn on safe mode
669 oldcfg, err := s.State.EnvironConfig()661 attrs := map[string]interface{}{"provisioner-safe-mode": true}
670 c.Assert(err, gc.IsNil)662 err = s.State.UpdateEnvironConfig(attrs, nil, nil)
671 attrs := oldcfg.AllAttrs()663 c.Assert(err, gc.IsNil)
672 attrs["provisioner-safe-mode"] = true
673 cfg, err := config.New(config.NoDefaults, attrs)
674 c.Assert(err, gc.IsNil)
675 err = s.State.SetEnvironConfig(cfg, oldcfg)
676664
677 // start a new provisioner to shut down only the machine still in state.665 // start a new provisioner to shut down only the machine still in state.
678 p = s.newEnvironProvisioner(c)666 p = s.newEnvironProvisioner(c)
@@ -712,13 +700,9 @@
712 provisioner.SetObserver(p, cfgObserver)700 provisioner.SetObserver(p, cfgObserver)
713701
714 // turn on safe mode702 // turn on safe mode
715 oldcfg, err := s.State.EnvironConfig()703 attrs := map[string]interface{}{"provisioner-safe-mode": true}
716 c.Assert(err, gc.IsNil)704 err = s.State.UpdateEnvironConfig(attrs, nil, nil)
717 attrs := oldcfg.AllAttrs()705 c.Assert(err, gc.IsNil)
718 attrs["provisioner-safe-mode"] = true
719 cfg, err := config.New(config.NoDefaults, attrs)
720 c.Assert(err, gc.IsNil)
721 err = s.State.SetEnvironConfig(cfg, oldcfg)
722706
723 s.BackingState.StartSync()707 s.BackingState.StartSync()
724708
725709
=== modified file 'worker/uniter/uniter_test.go'
--- worker/uniter/uniter_test.go 2014-03-17 13:45:26 +0000
+++ worker/uniter/uniter_test.go 2014-03-18 02:38:23 +0000
@@ -1959,16 +1959,13 @@
1959type setProxySettings osenv.ProxySettings1959type setProxySettings osenv.ProxySettings
19601960
1961func (s setProxySettings) step(c *gc.C, ctx *context) {1961func (s setProxySettings) step(c *gc.C, ctx *context) {
1962 old, err := ctx.st.EnvironConfig()1962 attrs := map[string]interface{}{
1963 c.Assert(err, gc.IsNil)
1964 cfg, err := old.Apply(map[string]interface{}{
1965 "http-proxy": s.Http,1963 "http-proxy": s.Http,
1966 "https-proxy": s.Https,1964 "https-proxy": s.Https,
1967 "ftp-proxy": s.Ftp,1965 "ftp-proxy": s.Ftp,
1968 "no-proxy": s.NoProxy,1966 "no-proxy": s.NoProxy,
1969 })1967 }
1970 c.Assert(err, gc.IsNil)1968 err := ctx.st.UpdateEnvironConfig(attrs, nil, nil)
1971 err = ctx.st.SetEnvironConfig(cfg, old)
1972 c.Assert(err, gc.IsNil)1969 c.Assert(err, gc.IsNil)
1973 // wait for the new values...1970 // wait for the new values...
1974 expected := (osenv.ProxySettings)(s)1971 expected := (osenv.ProxySettings)(s)

Subscribers

People subscribed via source and target branches

to status/vote changes: