Description:
Make a common verification function for bootstrap
All the providers did the same pre-bootstrap verification
(or should have in the case of maas). As discussed in Oakland,
I pulled the common code out into a shared function.
Affected files:
A [revision details]
M environs/bootstrap.go
M environs/dummy/environs.go
M environs/ec2/ec2.go
M environs/maas/environ.go
M environs/openstack/provider.go
// Bootstrap bootstraps the given environment. The supplied constraints are
@@ -33,3 +35,32 @@
}
return environ.Bootstrap(cons)
}
+
+// VerifyBootstrapInit does the common initial check inside bootstrap to
+// confirm that the environment isn't already running, and that the storage
+// works.
+func VerifyBootstrapInit(env Environ, shortAttempt utils.AttemptStrategy)
error {
+ var err error
+
+ // If the state file exists, it might actually have just been
+ // removed by Destroy, and eventual consistency has not caught
+ // up yet, so we retry to verify if that is happening.
+ for a := shortAttempt.Start(); a.Next(); {
+ _, err = LoadProviderState(env.Storage())
+ if err != nil {
+ break
+ }
+ }
+ if err == nil {
+ return fmt.Errorf("environment is already bootstrapped")
+ }
+ if !errors.IsNotFoundError(err) {
+ return fmt.Errorf("cannot query old bootstrap state: %v", err)
+ }
+
+ err = VerifyStorage(env.Storage())
+ if err != nil {
+ return err
+ }
+ return nil
+}
+// A request may fail to due "eventual consistency" semantics, which
+// should resolve fairly quickly. A request may also fail due to a slow
+// state transition (for instance an instance taking a while to release
+// a security group after termination). The former failure mode is
+// dealt with by shortAttempt, the latter by longAttempt.
+var shortAttempt = utils.AttemptStrategy{
+ Total: 5 * time.Second,
+ Delay: 200 * time.Millisecond,
+}
+
var longAttempt = utils.AttemptStrategy{
Total: 3 * time.Minute,
Delay: 1 * time.Second,
@@ -100,10 +110,9 @@
// Bootstrap is specified in the Environ interface.
func (env *maasEnviron) Bootstrap(cons constraints.Value) error {
- // TODO(fwereade): this should check for an existing environment before
- // starting a new one -- even given raciness, it's better than nothing.
- if err := environs.VerifyStorage(env.Storage()); err != nil {
- return fmt.Errorf("provider storage is not writeable")
+
+ if err := environs.VerifyBootstrapInit(env, shortAttempt); err != nil {
+ return err
}
func (e *environ) Bootstrap(cons constraints.Value) error {
log.Infof("environs/openstack: bootstrapping environment %q", e.name)
- // If the state file exists, it might actually have just been
- // removed by Destroy, and eventual consistency has not caught
- // up yet, so we retry to verify if that is happening.
- var err error
- for a := shortAttempt.Start(); a.Next(); {
- _, err = environs.LoadProviderState(e.Storage())
- if err != nil {
- break
- }
- }
- if err == nil {
- return fmt.Errorf("environment is already bootstrapped")
- }
- if !coreerrors.IsNotFoundError(err) {
- return fmt.Errorf("cannot query old bootstrap state: %v", err)
- }
- err = environs.VerifyStorage(e.Storage())
- if err != nil {
+
+ if err := environs.VerifyBootstrapInit(e, shortAttempt); err != nil {
return err
}
Reviewers: mp+172715_ code.launchpad. net,
Message:
Please take a look.
Description:
Make a common verification function for bootstrap
All the providers did the same pre-bootstrap verification
(or should have in the case of maas). As discussed in Oakland,
I pulled the common code out into a shared function.
https:/ /code.launchpad .net/~thumper/ juju-core/ consolidate- bootstrap- initial- check/+ merge/172715
Requires: /code.launchpad .net/~thumper/ juju-core/ consolidate- bootstrap- state/+ merge/172701
https:/
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/10888044/
Affected files: bootstrap. go dummy/environs. go maas/environ. go openstack/ provider. go
A [revision details]
M environs/
M environs/
M environs/ec2/ec2.go
M environs/
M environs/
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: <email address hidden>
+New revision: <email address hidden>
Index: environs/ bootstrap. go bootstrap. go' bootstrap. go 2013-07-02 23:28:43 +0000 bootstrap. go 2013-07-03 01:16:51 +0000
=== modified file 'environs/
--- environs/
+++ environs/
@@ -7,6 +7,8 @@
"fmt"
"launchpad. net/juju- core/constraint s" net/juju- core/errors" net/juju- core/utils"
+ "launchpad.
+ "launchpad.
)
// Bootstrap bootstraps the given environment. The supplied constraints are Bootstrap( cons) Init(env Environ, shortAttempt utils.AttemptSt rategy) Start() ; a.Next(); { te(env. Storage( )) "environment is already bootstrapped") IsNotFoundError (err) { env.Storage( ))
@@ -33,3 +35,32 @@
}
return environ.
}
+
+// VerifyBootstrapInit does the common initial check inside bootstrap to
+// confirm that the environment isn't already running, and that the storage
+// works.
+func VerifyBootstrap
error {
+ var err error
+
+ // If the state file exists, it might actually have just been
+ // removed by Destroy, and eventual consistency has not caught
+ // up yet, so we retry to verify if that is happening.
+ for a := shortAttempt.
+ _, err = LoadProviderSta
+ if err != nil {
+ break
+ }
+ }
+ if err == nil {
+ return fmt.Errorf(
+ }
+ if !errors.
+ return fmt.Errorf("cannot query old bootstrap state: %v", err)
+ }
+
+ err = VerifyStorage(
+ if err != nil {
+ return err
+ }
+ return nil
+}
Index: environs/ dummy/environs. go dummy/environs. go' dummy/environs. go 2013-06-30 23:37:23 +0000 dummy/environs. go 2013-07-03 01:23:46 +0000 ).CACert( ); !ok { VerifyStorage( e.Storage( )); err != nil { rategy{ VerifyBootstrap Init(e, shortAttempt); err != nil {
=== modified file 'environs/
--- environs/
+++ environs/
@@ -433,7 +433,12 @@
if _, ok := e.Config(
return fmt.Errorf("no CA certificate in environment configuration")
}
- if err := environs.
+
+ var shortAttempt = utils.AttemptSt
+ Total: 200 * time.Millisecond,
+ Delay: 10 * time.Millisecond,
+ }
+ if err := environs.
return err
}
Index: environs/ec2/ec2.go ec2/ec2. go' net/juju- core/environs/ imagemetadata" net/juju- core/environs/ instances" net/juju- core/environs/ tools" net/juju- core/errors" net/juju- core/instance" net/juju- core/log" net/juju- core/state" Start() ; a.Next(); { LoadProviderSta te(e.Storage( )) "environment is already bootstrapped") IsNotFoundError (err) { VerifyStorage( e.Storage( )) VerifyBootstrap Init(e, shortAttempt); err != nil { FindBootstrapTo ols(e, cons)
=== modified file 'environs/
--- environs/ec2/ec2.go 2013-07-02 23:15:14 +0000
+++ environs/ec2/ec2.go 2013-07-03 01:16:51 +0000
@@ -16,7 +16,6 @@
"launchpad.
"launchpad.
"launchpad.
- "launchpad.
"launchpad.
"launchpad.
"launchpad.
@@ -255,25 +254,9 @@
// If the state file exists, it might actually have just been
// removed by Destroy, and eventual consistency has not caught
// up yet, so we retry to verify if that is happening.
- var err error
- for a := shortAttempt.
- _, err = environs.
- if err != nil {
- break
- }
- }
- if err == nil {
- return fmt.Errorf(
- }
- if !errors.
- return fmt.Errorf("cannot query old bootstrap state: %v", err)
- }
-
- err = environs.
- if err != nil {
+ if err := environs.
return err
}
-
possibleTools, err := environs.
if err != nil {
return err
Index: environs/ maas/environ. go maas/environ. go' maas/environ. go 2013-07-02 23:15:14 +0000 maas/environ. go 2013-07-03 01:16:51 +0000
=== modified file 'environs/
--- environs/
+++ environs/
@@ -28,6 +28,16 @@
apiVersion = "1.0"
)
+// A request may fail to due "eventual consistency" semantics, which rategy{ rategy{
+// should resolve fairly quickly. A request may also fail due to a slow
+// state transition (for instance an instance taking a while to release
+// a security group after termination). The former failure mode is
+// dealt with by shortAttempt, the latter by longAttempt.
+var shortAttempt = utils.AttemptSt
+ Total: 5 * time.Second,
+ Delay: 200 * time.Millisecond,
+}
+
var longAttempt = utils.AttemptSt
Total: 3 * time.Minute,
Delay: 1 * time.Second,
@@ -100,10 +110,9 @@
// Bootstrap is specified in the Environ interface. VerifyStorage( env.Storage( )); err != nil { "provider storage is not writeable") VerifyBootstrap Init(env, shortAttempt); err != nil {
func (env *maasEnviron) Bootstrap(cons constraints.Value) error {
- // TODO(fwereade): this should check for an existing environment before
- // starting a new one -- even given raciness, it's better than nothing.
- if err := environs.
- return fmt.Errorf(
+
+ if err := environs.
+ return err
}
inst, err := env.startBootst rapNode( cons)
Index: environs/ openstack/ provider. go openstack/ provider. go' openstack/ provider. go 2013-07-02 23:15:14 +0000 openstack/ provider. go 2013-07-03 01:16:51 +0000 net/juju- core/environs/ imagemetadata" net/juju- core/environs/ instances" net/juju- core/environs/ tools" net/juju- core/errors" net/juju- core/instance" net/juju- core/log" net/juju- core/state"
=== modified file 'environs/
--- environs/
+++ environs/
@@ -22,7 +22,6 @@
"launchpad.
"launchpad.
"launchpad.
- coreerrors "launchpad.
"launchpad.
"launchpad.
"launchpad.
@@ -481,24 +480,8 @@
func (e *environ) Bootstrap(cons constraints.Value) error { Infof(" environs/ openstack: bootstrapping environment %q", e.name) Start() ; a.Next(); { LoadProviderSta te(e.Storage( )) "environment is already bootstrapped") IsNotFoundError (err) { VerifyStorage( e.Storage( )) VerifyBootstrap Init(e, shortAttempt); err != nil {
log.
- // If the state file exists, it might actually have just been
- // removed by Destroy, and eventual consistency has not caught
- // up yet, so we retry to verify if that is happening.
- var err error
- for a := shortAttempt.
- _, err = environs.
- if err != nil {
- break
- }
- }
- if err == nil {
- return fmt.Errorf(
- }
- if !coreerrors.
- return fmt.Errorf("cannot query old bootstrap state: %v", err)
- }
- err = environs.
- if err != nil {
+
+ if err := environs.
return err
}