func (s *StateSuite) TestEnvironConfigWithAdminSecret(c *C) { attrs := map[string]interface{}{ "name": "test", "type": "test", "authorized-keys": "i-am-a-key", "default-series": "precise", "development": true, "admin-secret": "foo", "ca-cert": testing.CACert, "ca-private-key": "", } cfg, err := config.New(attrs) c.Assert(err, IsNil) _, err = state.Initialize(state.TestingStateInfo(), cfg) c.Assert(err, ErrorMatches, "admin-secret should never be written to the state") delete(attrs, "admin-secret") cfg, err = config.New(attrs) st, err := state.Initialize(state.TestingStateInfo(), cfg) c.Assert(err, IsNil) st.Close() cfg, err = cfg.Apply(map[string]interface{}{"admin-secret": "foo"}) err = s.State.SetEnvironConfig(cfg) c.Assert(err, ErrorMatches, "admin-secret should never be written to the state") }
// Run initializes state for an environment. func (c *BootstrapCommand) Run(_ *cmd.Context) error { if err := c.Conf.read("bootstrap"); err != nil { return err } cfg, err := config.New(c.EnvConfig) if err != nil { return err } // There is no entity that's created at init time. c.Conf.StateInfo.EntityName = "" st, err := state.Initialize(c.Conf.StateInfo, cfg) if err != nil { return err } defer st.Close() m, err := st.InjectMachine(state.InstanceId(c.InstanceId), state.JobManageEnviron) if err != nil { return err } if c.Conf.OldPassword != "" { if err := m.SetMongoPassword(c.Conf.OldPassword); err != nil { return err } if err := st.SetAdminMongoPassword(c.Conf.OldPassword); err != nil { return err } } return nil }
func (s *InitializeSuite) TestInitialize(c *C) { _, err := s.State.EnvironConfig() c.Assert(err, checkers.Satisfies, errors.IsNotFoundError) _, err = s.State.Annotator("environment-foo") c.Assert(err, checkers.Satisfies, errors.IsNotFoundError) _, err = s.State.EnvironConstraints() c.Assert(err, checkers.Satisfies, errors.IsNotFoundError) cfg := testing.EnvironConfig(c) initial := cfg.AllAttrs() st, err := state.Initialize(state.TestingStateInfo(), cfg, state.TestingDialOpts()) c.Assert(err, IsNil) c.Assert(st, NotNil) err = st.Close() c.Assert(err, IsNil) cfg, err = s.State.EnvironConfig() c.Assert(err, IsNil) c.Assert(cfg.AllAttrs(), DeepEquals, initial) env, err := s.State.Annotator("environment-" + cfg.Name()) c.Assert(err, IsNil) annotations, err := env.Annotations() c.Assert(err, IsNil) c.Assert(annotations, HasLen, 0) cons, err := s.State.EnvironConstraints() c.Assert(err, IsNil) c.Assert(cons, DeepEquals, constraints.Value{}) }
func (s *StateSuite) TestWatchEnvironConfig(c *C) { watcher := s.State.WatchEnvironConfig() defer func() { c.Assert(watcher.Stop(), IsNil) }() for i, test := range watchEnvironConfigTests { c.Logf("test %d", i) change, err := config.New(test) c.Assert(err, IsNil) if i == 0 { st, err := state.Initialize(state.TestingStateInfo(), change) c.Assert(err, IsNil) st.Close() } else { err = s.State.SetEnvironConfig(change) c.Assert(err, IsNil) } c.Assert(err, IsNil) s.State.StartSync() select { case got, ok := <-watcher.Changes(): c.Assert(ok, Equals, true) c.Assert(got.AllAttrs(), DeepEquals, change.AllAttrs()) case <-time.After(500 * time.Millisecond): c.Fatalf("did not get change: %#v", test) } } select { case got := <-watcher.Changes(): c.Fatalf("got unexpected change: %#v", got) case <-time.After(50 * time.Millisecond): } }
func (s *StateSuite) TestEnvironConfig(c *C) { initial := map[string]interface{}{ "name": "test", "type": "test", "authorized-keys": "i-am-a-key", "default-series": "precise", "development": true, "firewall-mode": "", "admin-secret": "", "ca-cert": testing.CACert, "ca-private-key": "", "ssl-hostname-verification": true, } cfg, err := config.New(initial) c.Assert(err, IsNil) st, err := state.Initialize(state.TestingStateInfo(), cfg) c.Assert(err, IsNil) st.Close() c.Assert(err, IsNil) cfg, err = s.State.EnvironConfig() c.Assert(err, IsNil) current := cfg.AllAttrs() c.Assert(current, DeepEquals, initial) current["authorized-keys"] = "i-am-a-new-key" cfg, err = config.New(current) c.Assert(err, IsNil) err = s.State.SetEnvironConfig(cfg) c.Assert(err, IsNil) cfg, err = s.State.EnvironConfig() c.Assert(err, IsNil) final := cfg.AllAttrs() c.Assert(final, DeepEquals, current) }
func (s *StateSuite) TestDoubleInitialize(c *C) { m := map[string]interface{}{ "type": "dummy", "name": "lisboa", "authorized-keys": "i-am-a-key", "default-series": "precise", "development": true, "firewall-mode": "", "admin-secret": "", "ca-cert": testing.CACert, "ca-private-key": "", "ssl-hostname-verification": true, } cfg, err := config.New(m) c.Assert(err, IsNil) st, err := state.Initialize(state.TestingStateInfo(), cfg) c.Assert(err, IsNil) c.Assert(st, NotNil) env1, err := st.EnvironConfig() st.Close() // initialize again, there should be no error and the // environ config should not change. m = map[string]interface{}{ "type": "dummy", "name": "sydney", "authorized-keys": "i-am-not-an-animal", "default-series": "xanadu", "development": false, "firewall-mode": "", "admin-secret": "", "ca-cert": testing.CACert, "ca-private-key": "", "ssl-hostname-verification": false, } cfg, err = config.New(m) c.Assert(err, IsNil) st, err = state.Initialize(state.TestingStateInfo(), cfg) c.Assert(err, IsNil) c.Assert(st, NotNil) env2, err := st.EnvironConfig() st.Close() c.Assert(env1.AllAttrs(), DeepEquals, env2.AllAttrs()) }
func (e *environ) Bootstrap(cons constraints.Value) error { defer delay() if err := e.checkBroken("Bootstrap"); err != nil { return err } password := e.Config().AdminSecret() if password == "" { return fmt.Errorf("admin-secret is required for bootstrap") } if _, ok := e.Config().CACert(); !ok { return fmt.Errorf("no CA certificate in environment configuration") } possibleTools, err := environs.FindBootstrapTools(e, cons) if err != nil { return err } log.Infof("environs/dummy: would pick tools from %s", possibleTools) cfg, err := environs.BootstrapConfig(e.Config()) if err != nil { return fmt.Errorf("cannot make bootstrap config: %v", err) } e.state.mu.Lock() defer e.state.mu.Unlock() if e.state.bootstrapped { return fmt.Errorf("environment is already bootstrapped") } if e.ecfg().stateServer() { // TODO(rog) factor out relevant code from cmd/jujud/bootstrap.go // so that we can call it here. info := stateInfo() st, err := state.Initialize(info, cfg, state.DefaultDialOpts()) if err != nil { panic(err) } if err := st.SetEnvironConstraints(cons); err != nil { panic(err) } if err := st.SetAdminMongoPassword(utils.PasswordHash(password)); err != nil { panic(err) } _, err = st.AddUser("admin", password) if err != nil { panic(err) } e.state.apiServer, err = apiserver.NewServer(st, "localhost:0", []byte(testing.ServerCert), []byte(testing.ServerKey)) if err != nil { panic(err) } e.state.apiState = st } e.state.bootstrapped = true e.state.ops <- OpBootstrap{Env: e.state.name, Constraints: cons} return nil }
// Run initializes state for an environment. func (c *BootstrapCommand) Run(_ *cmd.Context) error { if err := c.Conf.read("bootstrap"); err != nil { return err } cfg, err := config.New(c.EnvConfig) if err != nil { return err } // There is no entity that's created at init time. c.Conf.StateInfo.Tag = "" st, err := state.Initialize(c.Conf.StateInfo, cfg, state.DefaultDialOpts()) if err != nil { return err } defer st.Close() if err := environs.BootstrapUsers(st, cfg, c.Conf.OldPassword); err != nil { return err } // TODO(fwereade): we need to be able to customize machine jobs, // not just hardcode these values; in particular, JobHostUnits // on a machine, like this one, that is running JobManageEnviron // (not to mention the actual state server itself...) will allow // a malicious or compromised unit to trivially access to the // user's environment credentials. However, given that this point // is currently moot (see Upgrader in this package), the pseudo- // local provider mode (in which everything is deployed with // `--to 0`) offers enough value to enough people that // JobHostUnits is currently always enabled. This will one day // have to change, but it's strictly less important than fixing // Upgrader, and it's a capability we'll always want to have // available for the aforementioned use case. jobs := []state.MachineJob{ state.JobManageEnviron, state.JobManageState, state.JobHostUnits, } data, err := ioutil.ReadFile(providerStateURLFile) if err != nil { return fmt.Errorf("cannot read provider-state-url file: %v", err) } stateInfoURL := strings.Split(string(data), "\n")[0] bsState, err := environs.LoadStateFromURL(stateInfoURL) if err != nil { return fmt.Errorf("cannot load state from URL %q (read from %q): %v", stateInfoURL, providerStateURLFile, err) } instId := bsState.StateInstances[0] var characteristics instance.HardwareCharacteristics if len(bsState.Characteristics) > 0 { characteristics = bsState.Characteristics[0] } return environs.ConfigureBootstrapMachine(st, c.Constraints, c.Conf.DataDir, jobs, instance.Id(instId), characteristics) }
func (e *environ) Bootstrap(uploadTools bool, cert, key []byte) error { defer delay() if err := e.checkBroken("Bootstrap"); err != nil { return err } password := e.Config().AdminSecret() if password == "" { return fmt.Errorf("admin-secret is required for bootstrap") } if _, ok := e.Config().CACert(); !ok { return fmt.Errorf("no CA certificate in environment configuration") } var tools *state.Tools var err error if uploadTools { tools, err = environs.PutTools(e.Storage(), nil) if err != nil { return err } } else { flags := environs.HighestVersion | environs.CompatVersion tools, err = environs.FindTools(e, version.Current, flags) if err != nil { return err } } e.state.mu.Lock() defer e.state.mu.Unlock() e.state.ops <- OpBootstrap{Env: e.state.name} if e.state.bootstrapped { return fmt.Errorf("environment is already bootstrapped") } if e.ecfg().stateServer() { info := stateInfo() cfg, err := environs.BootstrapConfig(&providerInstance, e.ecfg().Config, tools) if err != nil { return fmt.Errorf("cannot make bootstrap config: %v", err) } st, err := state.Initialize(info, cfg) if err != nil { panic(err) } if err := st.SetAdminMongoPassword(trivial.PasswordHash(password)); err != nil { return err } if err := st.Close(); err != nil { panic(err) } } e.state.bootstrapped = true return nil }
func (s *StateSuite) TestWatchEnvironConfigAfterCreation(c *C) { cfg, err := config.New(watchEnvironConfigTests[0]) c.Assert(err, IsNil) st, err := state.Initialize(state.TestingStateInfo(), cfg) c.Assert(err, IsNil) st.Close() s.State.Sync() watcher := s.State.WatchEnvironConfig() defer watcher.Stop() select { case got, ok := <-watcher.Changes(): c.Assert(ok, Equals, true) c.Assert(got.AllAttrs(), DeepEquals, cfg.AllAttrs()) case <-time.After(500 * time.Millisecond): c.Fatalf("did not get change") } }
func (s *InitializeSuite) TestEnvironConfigWithAdminSecret(c *C) { // admin-secret blocks Initialize. good := testing.EnvironConfig(c) bad, err := good.Apply(map[string]interface{}{"admin-secret": "foo"}) _, err = state.Initialize(state.TestingStateInfo(), bad, state.TestingDialOpts()) c.Assert(err, ErrorMatches, "admin-secret should never be written to the state") // admin-secret blocks SetEnvironConfig. st := state.TestingInitialize(c, good) st.Close() err = s.State.SetEnvironConfig(bad) c.Assert(err, ErrorMatches, "admin-secret should never be written to the state") // EnvironConfig remains inviolate. cfg, err := s.State.EnvironConfig() c.Assert(err, IsNil) c.Assert(cfg.AllAttrs(), DeepEquals, good.AllAttrs()) }
func (s *InitializeSuite) TestDoubleInitializeConfig(c *C) { cfg := testing.EnvironConfig(c) initial := cfg.AllAttrs() st := state.TestingInitialize(c, cfg) st.Close() // A second initialize returns an open *State, but ignores its params. // TODO(fwereade) I think this is crazy, but it's what we were testing // for originally... cfg, err := cfg.Apply(map[string]interface{}{"authorized-keys": "something-else"}) c.Assert(err, IsNil) st, err = state.Initialize(state.TestingStateInfo(), cfg, state.TestingDialOpts()) c.Assert(err, IsNil) c.Assert(st, NotNil) st.Close() cfg, err = s.State.EnvironConfig() c.Assert(err, IsNil) c.Assert(cfg.AllAttrs(), DeepEquals, initial) }
func (s *InitializeSuite) TestEnvironConfigWithoutAgentVersion(c *C) { // admin-secret blocks Initialize. good := testing.EnvironConfig(c) attrs := good.AllAttrs() delete(attrs, "agent-version") bad, err := config.New(attrs) c.Assert(err, IsNil) _, err = state.Initialize(state.TestingStateInfo(), bad, state.TestingDialOpts()) c.Assert(err, ErrorMatches, "agent-version must always be set in state") // Bad agent-version blocks SetEnvironConfig. st := state.TestingInitialize(c, good) st.Close() err = s.State.SetEnvironConfig(bad) c.Assert(err, ErrorMatches, "agent-version must always be set in state") // EnvironConfig remains inviolate. cfg, err := s.State.EnvironConfig() c.Assert(err, IsNil) c.Assert(cfg.AllAttrs(), DeepEquals, good.AllAttrs()) }
func (s *StateSuite) TestInitialize(c *C) { m := map[string]interface{}{ "type": "dummy", "name": "lisboa", "authorized-keys": "i-am-a-key", "default-series": "precise", "development": true, "firewall-mode": "", "admin-secret": "", "ca-cert": testing.CACert, "ca-private-key": "", "ssl-hostname-verification": true, } cfg, err := config.New(m) c.Assert(err, IsNil) st, err := state.Initialize(state.TestingStateInfo(), cfg) c.Assert(err, IsNil) c.Assert(st, NotNil) defer st.Close() env, err := st.EnvironConfig() c.Assert(env.AllAttrs(), DeepEquals, m) }
func (env *localEnviron) initialStateConfiguration(addr string, cons constraints.Value) (*state.State, error) { // We don't check the existance of the CACert here as if it wasn't set, we // wouldn't get this far. cfg := env.config.Config caCert, _ := cfg.CACert() addr = fmt.Sprintf("%s:%d", addr, cfg.StatePort()) info := &state.Info{ Addrs: []string{addr}, CACert: caCert, } timeout := state.DialOpts{60 * time.Second} bootstrap, err := environs.BootstrapConfig(cfg) if err != nil { return nil, err } st, err := state.Initialize(info, bootstrap, timeout) if err != nil { logger.Errorf("failed to initialize state: %v", err) return nil, err } logger.Debugf("state initialized") passwordHash := utils.PasswordHash(cfg.AdminSecret()) if err := environs.BootstrapUsers(st, cfg, passwordHash); err != nil { st.Close() return nil, err } jobs := []state.MachineJob{state.JobManageEnviron, state.JobManageState} if err := environs.ConfigureBootstrapMachine( st, cons, env.config.rootDir(), jobs, instance.Id(boostrapInstanceId), instance.HardwareCharacteristics{}); err != nil { st.Close() return nil, err } // Return an open state reference. return st, nil }
func (s *StateSuite) TestWatchEnvironConfigInvalidConfig(c *C) { m := map[string]interface{}{ "type": "dummy", "name": "lisboa", "authorized-keys": "i-am-a-key", "ca-cert": testing.CACert, "ca-private-key": "", } cfg1, err := config.New(m) c.Assert(err, IsNil) st, err := state.Initialize(state.TestingStateInfo(), cfg1) c.Assert(err, IsNil) st.Close() // Corrupt the environment configuration. settings := s.Session.DB("juju").C("settings") err = settings.UpdateId("e", bson.D{{"$unset", bson.D{{"name", 1}}}}) c.Assert(err, IsNil) s.State.Sync() // Start watching the configuration. watcher := s.State.WatchEnvironConfig() defer watcher.Stop() done := make(chan *config.Config) go func() { select { case cfg, ok := <-watcher.Changes(): if !ok { c.Errorf("watcher channel closed") } else { done <- cfg } case <-time.After(5 * time.Second): c.Fatalf("no environment configuration observed") } }() s.State.Sync() // The invalid configuration must not have been generated. select { case <-done: c.Fatalf("configuration returned too soon") case <-time.After(100 * time.Millisecond): } // Fix the configuration. cfg2, err := config.New(map[string]interface{}{ "type": "dummy", "name": "lisboa", "authorized-keys": "new-key", "ca-cert": testing.CACert, "ca-private-key": "", }) c.Assert(err, IsNil) err = s.State.SetEnvironConfig(cfg2) c.Assert(err, IsNil) s.State.StartSync() select { case cfg3 := <-done: c.Assert(cfg3.AllAttrs(), DeepEquals, cfg2.AllAttrs()) case <-time.After(5 * time.Second): c.Fatalf("no environment configuration observed") } }