Merge lp:~axwalk/juju-core/lp1239550-check-jenv-consistency into lp:~go-bot/juju-core/trunk

Proposed by Andrew Wilkins
Status: Work in progress
Proposed branch: lp:~axwalk/juju-core/lp1239550-check-jenv-consistency
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 97 lines (+36/-4)
1 file modified
environs/open.go (+36/-4)
To merge this branch: bzr merge lp:~axwalk/juju-core/lp1239550-check-jenv-consistency
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+191748@code.launchpad.net

Description of the change

environs: warn if .jenv/env.yaml are inconsistent

Changes in environments.yaml do not take effect
for an environment that has already been prepared.
In some cases, it might not be obvious to a user
that the environment is prepared, and that changes
will not take effect. e.g.:
 - User called sync-tools, then modified env.yaml,
   then bootstrapped.
 - User bootstrapped, bootstrap failed, then modified
   env.yaml and tried again. We could remove the
   .jenv file on failure, but we can't guarantee
   juju won't die before doing so.
 - User is bootstrapping the null provider; since
   destroy-environment is not implemented, the user
   must remove the .jenv file manually. It's easy to
   forget to do that.

We now log a warning if any values have been
changed in environments.yaml after preparing,
and provide some direction on what to do.

Also: don't call Prepare for config retrieved from
the config store (i.e. already prepared config).

Fixes #1239550

https://codereview.appspot.com/14880043/

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

Reviewers: mp+191748_code.launchpad.net,

Message:
Please take a look.

Description:
environs: warn if .jenv/env.yaml are inconsistent

Changes in environments.yaml do not take effect
for an environment that has already been prepared.
In some cases, it might not be obvious to a user
that the environment is prepared, and that changes
will not take effect. e.g.:
  - User called sync-tools, then modified env.yaml,
    then bootstrapped.
  - User bootstrapped, bootstrap failed, then modified
    env.yaml and tried again. We could remove the
    .jenv file on failure, but we can't guarantee
    juju won't die before doing so.
  - User is bootstrapping the null provider; since
    destroy-environment is not implemented, the user
    must remove the .jenv file manually. It's easy to
    forget to do that.

We now log a warning if any values have been
changed in environments.yaml after preparing,
and provide some direction on what to do.

Also: don't call Prepare for config retrieved from
the config store (i.e. already prepared config).

Fixes #1239550

https://code.launchpad.net/~axwalk/juju-core/lp1239550-check-jenv-consistency/+merge/191748

(do not edit description out of merge proposal)

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

Affected files (+38, -4 lines):
   [revision details]
   environs/open.go

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: tarmac-20131017053700-k2l0flmzzs7feuv2
+New revision: <email address hidden>

Index: environs/open.go
=== modified file 'environs/open.go'
--- environs/open.go 2013-10-04 12:18:17 +0000
+++ environs/open.go 2013-10-18 03:39:49 +0000
@@ -6,6 +6,7 @@
  import (
   "fmt"
   "io/ioutil"
+ "reflect"
   "strings"
   "time"

@@ -44,6 +45,28 @@
   ConfigFromEnvirons
  )

+// checkBootstrapConfigConsistency checks that the bootstrap configuration
+// in the store (.jenv) is consistent with the configuration in
+// environments.yaml, logging warnings for each changed value.
+func checkBootstrapConfigConsistency(infoConfig, environsConfig
*config.Config) {
+ if infoConfig == nil || environsConfig == nil {
+ return
+ }
+ environsConfigAttrs := environsConfig.AllAttrs()
+ var changed bool
+ for k, v := range infoConfig.AllAttrs() {
+ if v2, ok := environsConfigAttrs[k]; ok {
+ if !reflect.DeepEqual(v, v2) {
+ logger.Warningf("config %q was changed in environments.yaml from %q
to %q", k, v, v2)
+ changed = true
+ }
+ }
+ }
+ if changed {
+ logger.Warningf(`changes in environments.yaml will not take effect after
bootstrapping. Update %s.jenv, revert environments.yaml, or
destroy-environment and re-bootstrap`, infoConfig.Name())
+ }
+}
+
  // ConfigForName returns the configuration for the environment with the
  // given name from the default environments file. If the name is blank,
  // the default environment will be used. If the configuration is not
@@ -62,6 +85,7 @@
   if name == "" {
    name = envs.Default
   }
+ environsCfg, err := envs.Config(name)
   // TODO(rog) 2013-10-04 https://bu...

Read more...

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

There's some issues with this, for example logging config is changed after Prepare. Will need to revisit.

Unmerged revisions

1995. By Andrew Wilkins

environs: warn if .jenv/env.yaml are inconsistent

Changes in environments.yaml do not take effect
for an environment that has already been prepared.
In some cases, it might not be obvious to a user
that the environment is prepared, and that changes
will not take effect. e.g.:
 - User called sync-tools, then modified env.yaml,
   then bootstrapped.
 - User bootstrapped, bootstrap failed, then modified
   env.yaml and tried again. We could remove the
   .jenv file on failure, but we can't guarantee
   juju won't die before doing so.
 - User is bootstrapping the null provider; since
   destroy-environment is not implemented, the user
   must remove the .jenv file manually. It's easy to
   forget to do that.

We now log a warning if any values have been
changed in environments.yaml after preparing,
and provide some direction on what to do.

Also: don't call Prepare for config retrieved from
the config store (i.e. already prepared config).

Fixes #1239550

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'environs/open.go'
2--- environs/open.go 2013-10-04 12:18:17 +0000
3+++ environs/open.go 2013-10-18 04:03:27 +0000
4@@ -6,6 +6,7 @@
5 import (
6 "fmt"
7 "io/ioutil"
8+ "reflect"
9 "strings"
10 "time"
11
12@@ -44,6 +45,28 @@
13 ConfigFromEnvirons
14 )
15
16+// checkBootstrapConfigConsistency checks that the bootstrap configuration
17+// in the store (.jenv) is consistent with the configuration in
18+// environments.yaml, logging warnings for each changed value.
19+func checkBootstrapConfigConsistency(infoConfig, environsConfig *config.Config) {
20+ if infoConfig == nil || environsConfig == nil {
21+ return
22+ }
23+ environsConfigAttrs := environsConfig.AllAttrs()
24+ var changed bool
25+ for k, v := range infoConfig.AllAttrs() {
26+ if v2, ok := environsConfigAttrs[k]; ok {
27+ if !reflect.DeepEqual(v, v2) {
28+ logger.Warningf("config %q was changed in environments.yaml from %q to %q", k, v, v2)
29+ changed = true
30+ }
31+ }
32+ }
33+ if changed {
34+ logger.Warningf(`changes in environments.yaml will not take effect after bootstrapping. Update %s.jenv, revert environments.yaml, or destroy-environment and re-bootstrap`, infoConfig.Name())
35+ }
36+}
37+
38 // ConfigForName returns the configuration for the environment with the
39 // given name from the default environments file. If the name is blank,
40 // the default environment will be used. If the configuration is not
41@@ -62,6 +85,7 @@
42 if name == "" {
43 name = envs.Default
44 }
45+ environsCfg, err := envs.Config(name)
46 // TODO(rog) 2013-10-04 https://bugs.launchpad.net/juju-core/+bug/1235217
47 // Don't fall back to reading from environments.yaml
48 // when we can be sure that everyone has a
49@@ -74,14 +98,17 @@
50 }
51 logger.Debugf("ConfigForName found bootstrap config %#v", info.BootstrapConfig())
52 cfg, err := config.New(config.NoDefaults, info.BootstrapConfig())
53- return cfg, ConfigFromInfo, err
54+ if err != nil {
55+ return nil, ConfigFromInfo, err
56+ }
57+ checkBootstrapConfigConsistency(cfg, environsCfg)
58+ return cfg, ConfigFromInfo, nil
59 }
60 if err != nil && !errors.IsNotFoundError(err) {
61 return nil, ConfigFromInfo, fmt.Errorf("cannot read environment info for %q: %v", name, err)
62 }
63 }
64- cfg, err := envs.Config(name)
65- return cfg, ConfigFromEnvirons, err
66+ return environsCfg, ConfigFromEnvirons, err
67 }
68
69 // NewFromName opens the environment with the given
70@@ -117,10 +144,13 @@
71 // given store. If the environment is already prepared,
72 // it behaves like NewFromName.
73 func PrepareFromName(name string, store configstore.Storage) (Environ, error) {
74- cfg, _, err := ConfigForName(name, store)
75+ cfg, source, err := ConfigForName(name, store)
76 if err != nil {
77 return nil, err
78 }
79+ if source == ConfigFromInfo {
80+ return New(cfg)
81+ }
82 return Prepare(cfg, store)
83 }
84
85@@ -164,10 +194,12 @@
86 if len(info.BootstrapConfig()) == 0 {
87 return nil, fmt.Errorf("found environment info but no bootstrap config")
88 }
89+ environsCfg := cfg
90 cfg, err = config.New(config.NoDefaults, info.BootstrapConfig())
91 if err != nil {
92 return nil, fmt.Errorf("cannot parse bootstrap config: %v", err)
93 }
94+ checkBootstrapConfigConsistency(cfg, environsCfg)
95 return New(cfg)
96 }
97 if err != nil {

Subscribers

People subscribed via source and target branches

to status/vote changes: