// handleBootstrapError cleans up after a failed bootstrap. func handleBootstrapError(err error, ctx environs.BootstrapContext, inst instance.Instance, env environs.Environ) { if err == nil { return } logger.Errorf("bootstrap failed: %v", err) ch := make(chan os.Signal, 1) ctx.InterruptNotify(ch) defer ctx.StopInterruptNotify(ch) defer close(ch) go func() { for _ = range ch { fmt.Fprintln(ctx.GetStderr(), "Cleaning up failed bootstrap") } }() if inst != nil { fmt.Fprintln(ctx.GetStderr(), "Stopping instance...") if stoperr := env.StopInstances(inst.Id()); stoperr != nil { logger.Errorf("cannot stop failed bootstrap instance %q: %v", inst.Id(), stoperr) } else { // set to nil so we know we can safely delete the state file inst = nil } } // We only delete the bootstrap state file if either we didn't // start an instance, or we managed to cleanly stop it. if inst == nil { if rmerr := bootstrap.DeleteStateFile(env.Storage()); rmerr != nil { logger.Errorf("cannot delete bootstrap state file: %v", rmerr) } } }
// Destroy is a common implementation of the Destroy method defined on // environs.Environ; we strongly recommend that this implementation be // used when writing a new provider. func Destroy(env environs.Environ) error { logger.Infof("destroying environment %q", env.Name()) instances, err := env.AllInstances() switch err { case nil: ids := make([]instance.Id, len(instances)) for i, inst := range instances { ids[i] = inst.Id() } if err := env.StopInstances(ids...); err != nil { return err } fallthrough case environs.ErrNoInstances: return env.Storage().RemoveAll() } return err }