// NewWatcher returns a new Watcher. func NewWatcher(base *mgo.Collection, envTag names.EnvironTag) *Watcher { w := &Watcher{ envUUID: envTag.Id(), base: base, pings: pingsC(base), beings: beingsC(base), beingKey: make(map[int64]string), beingSeq: make(map[string]int64), watches: make(map[string][]chan<- Change), request: make(chan interface{}), } go func() { err := w.loop() cause := errors.Cause(err) // tomb expects ErrDying or ErrStillAlive as // exact values, so we need to log and unwrap // the error first. if err != nil && cause != tomb.ErrDying { logger.Infof("watcher loop failed: %v", err) } w.tomb.Kill(cause) w.tomb.Done() }() return w }
func open(tag names.EnvironTag, info *mongo.MongoInfo, opts mongo.DialOpts, policy Policy) (*State, error) { logger.Infof("opening state, mongo addresses: %q; entity %v", info.Addrs, info.Tag) logger.Debugf("dialing mongo") session, err := mongo.DialWithInfo(info.Info, opts) if err != nil { return nil, maybeUnauthorized(err, "cannot connect to mongodb") } logger.Debugf("connection established") // In rare circumstances, we may be upgrading from pre-1.23, and not have the // environment UUID available. In that case we need to infer what it might be; // we depend on the assumption that this is the only circumstance in which // the the UUID might not be known. if tag.Id() == "" { logger.Warningf("creating state without environment tag; inferring bootstrap environment") ssInfo, err := readRawStateServerInfo(session) if err != nil { return nil, errors.Trace(err) } tag = ssInfo.EnvironmentTag } st, err := newState(tag, session, info, policy) if err != nil { session.Close() return nil, errors.Trace(err) } return st, nil }
// newState creates an incomplete *State, with a configured watcher but no // pwatcher, leadershipManager, or serverTag. You must start() the returned // *State before it will function correctly. func newState(environTag names.EnvironTag, session *mgo.Session, mongoInfo *mongo.MongoInfo, policy Policy) (_ *State, resultErr error) { admin := session.DB("admin") if mongoInfo.Tag != nil { if err := admin.Login(mongoInfo.Tag.String(), mongoInfo.Password); err != nil { return nil, maybeUnauthorized(err, fmt.Sprintf("cannot log in to admin database as %q", mongoInfo.Tag)) } } else if mongoInfo.Password != "" { if err := admin.Login(mongo.AdminUser, mongoInfo.Password); err != nil { return nil, maybeUnauthorized(err, "cannot log in to admin database") } } // Set up database. rawDB := session.DB(jujuDB) database, err := allCollections().Load(rawDB, environTag.Id()) if err != nil { return nil, errors.Trace(err) } if err := InitDbLogs(session); err != nil { return nil, errors.Trace(err) } // Create State. st := &State{ environTag: environTag, mongoInfo: mongoInfo, session: session, database: database, policy: policy, watcher: watcher.New(rawDB.C(txnLogC)), } st.LeasePersistor = NewLeasePersistor(leaseC, st.run, st.getCollection) return st, nil }
// NewPinger returns a new Pinger to report that key is alive. // It starts reporting after Start is called. func NewPinger(base *mgo.Collection, envTag names.EnvironTag, key string) *Pinger { return &Pinger{ base: base, pings: pingsC(base), beingKey: key, envUUID: envTag.Id(), } }
func (m *envWorkerManager) envIsDead(envTag names.EnvironTag) error { uuid := envTag.Id() err := m.runner.StopWorker(uuid) if err != nil { return errors.Trace(err) } return nil }
func (m *envWorkerManager) isEnvAlive(tag names.EnvironTag) (bool, error) { env, err := m.st.GetEnvironment(tag) if errors.IsNotFound(err) { return false, nil } else if err != nil { return false, errors.Annotatef(err, "error loading environment %s", tag.Id()) } return env.Life() == state.Alive, nil }
// GetEnvironment looks for the environment identified by the uuid passed in. func (st *State) GetEnvironment(tag names.EnvironTag) (*Environment, error) { environments, closer := st.getCollection(environmentsC) defer closer() env := &Environment{st: st} if err := env.refresh(environments.FindId(tag.Id())); err != nil { return nil, errors.Trace(err) } return env, nil }
// envNotFound stops all workers for that environment. func (m *envWorkerManager) envNotFound(envTag names.EnvironTag) error { uuid := envTag.Id() if err := m.runner.StopWorker(uuid); err != nil { return errors.Trace(err) } if err := m.runner.StopWorker(dyingEnvWorkerId(uuid)); err != nil { return errors.Trace(err) } return nil }
// apiPath returns the given API endpoint path relative // to the given environment tag. The caller is responsible // for ensuring that the environment tag is valid and // that the path is slash-prefixed. func apiPath(envTag names.EnvironTag, path string) string { if !strings.HasPrefix(path, "/") { panic(fmt.Sprintf("apiPath called with non-slash-prefixed path %q", path)) } if envTag.Id() == "" { panic("apiPath called with empty environment tag") } if envUUID := envTag.Id(); envUUID != "" { return "/environment/" + envUUID + path } return path }
// ResourceTags returns tags to set on an infrastructure resource // for the specified Juju environment. func ResourceTags(e names.EnvironTag, taggers ...ResourceTagger) map[string]string { allTags := make(map[string]string) for _, tagger := range taggers { tags, ok := tagger.ResourceTags() if !ok { continue } for k, v := range tags { allTags[k] = v } } allTags[JujuEnv] = e.Id() return allTags }
func (s *loginSuite) assertRemoteEnvironment(c *gc.C, st api.Connection, expected names.EnvironTag) { // Look at what the api thinks it has. tag, err := st.EnvironTag() c.Assert(err, jc.ErrorIsNil) c.Assert(tag, gc.Equals, expected) // Look at what the api Client thinks it has. client := st.Client() // EnvironmentUUID looks at the env tag on the api state connection. c.Assert(client.EnvironmentUUID(), gc.Equals, expected.Id()) // EnvironmentInfo calls a remote method that looks up the environment. info, err := client.EnvironmentInfo() c.Assert(err, jc.ErrorIsNil) c.Assert(info.UUID, gc.Equals, expected.Id()) }
// Open connects to the server described by the given // info, waits for it to be initialized, and returns a new State // representing the environment connected to. // // A policy may be provided, which will be used to validate and // modify behaviour of certain operations in state. A nil policy // may be provided. // // Open returns unauthorizedError if access is unauthorized. func Open(tag names.EnvironTag, info *mongo.MongoInfo, opts mongo.DialOpts, policy Policy) (*State, error) { st, err := open(tag, info, opts, policy) if err != nil { return nil, errors.Trace(err) } if _, err := st.Environment(); err != nil { if err := st.Close(); err != nil { logger.Errorf("error closing state for unreadable environment %s: %v", tag.Id(), err) } return nil, errors.Annotatef(err, "cannot read environment %s", tag.Id()) } // State should only be Opened on behalf of a state server environ; all // other *States should be created via ForEnviron. if err := st.start(tag); err != nil { return nil, errors.Trace(err) } return st, nil }
// newState creates an incomplete *State, with a configured watcher but no // pwatcher, leadershipManager, or controllerTag. You must start() the returned // *State before it will function correctly. func newState(environTag names.EnvironTag, session *mgo.Session, mongoInfo *mongo.MongoInfo, policy Policy) (_ *State, resultErr error) { // Set up database. rawDB := session.DB(jujuDB) database, err := allCollections().Load(rawDB, environTag.Id()) if err != nil { return nil, errors.Trace(err) } if err := InitDbLogs(session); err != nil { return nil, errors.Trace(err) } // Create State. return &State{ environTag: environTag, mongoInfo: mongoInfo, session: session, database: database, policy: policy, watcher: watcher.New(rawDB.C(txnLogC)), }, nil }
func (m *envWorkerManager) envIsDying(envTag names.EnvironTag) error { id := dyingEnvWorkerId(envTag.Id()) return m.runner.StartWorker(id, func() (worker.Worker, error) { st, err := m.st.ForEnviron(envTag) if err != nil { return nil, errors.Annotatef(err, "failed to open state for environment %s", envTag.Id()) } closeState := func() { err := st.Close() if err != nil { logger.Errorf("error closing state for env %s: %v", envTag.Id(), err) } } dyingRunner, err := m.dyingEnvWorker(m.st, st) if err != nil { closeState() return nil, errors.Trace(err) } // Close State when the runner for the environment is done. go func() { dyingRunner.Wait() closeState() }() return dyingRunner, nil }) }
func (c *dumpLogsCommand) dumpLogsForEnv(ctx *cmd.Context, st0 *state.State, tag names.EnvironTag) error { st, err := st0.ForEnviron(tag) if err != nil { return errors.Annotate(err, "failed open environment") } defer st.Close() logName := ctx.AbsPath(filepath.Join(c.outDir, fmt.Sprintf("%s.log", tag.Id()))) ctx.Infof("writing to %s", logName) file, err := os.Create(logName) if err != nil { return errors.Annotate(err, "failed to open output file") } defer file.Close() writer := bufio.NewWriter(file) defer writer.Flush() tailer := state.NewLogTailer(st, &state.LogTailerParams{NoTail: true}) logs := tailer.Logs() for { rec, ok := <-logs if !ok { break } writer.WriteString(c.format( rec.Time, rec.Level, rec.Entity, rec.Module, rec.Message, ) + "\n") } return nil }
func (m *envWorkerManager) envIsDead(envTag names.EnvironTag) error { err := m.runner.StopWorker(envTag.Id()) return errors.Trace(err) }