// LastLogs returns a list of the last `lines` log of the app, matching the // fields in the log instance received as an example. func (app *App) LastLogs(lines int, filterLog Applog) ([]Applog, error) { logsProvisioner, ok := Provisioner.(provision.OptionalLogsProvisioner) if ok { enabled, doc, err := logsProvisioner.LogsEnabled(app) if err != nil { return nil, err } if !enabled { return nil, stderr.New(doc) } } conn, err := db.LogConn() if err != nil { return nil, err } defer conn.Close() logs := []Applog{} q := bson.M{} if filterLog.Source != "" { q["source"] = filterLog.Source } if filterLog.Unit != "" { q["unit"] = filterLog.Unit } err = conn.Logs(app.Name).Find(q).Sort("-$natural").Limit(lines).All(&logs) if err != nil { return nil, err } l := len(logs) for i := 0; i < l/2; i++ { logs[i], logs[l-1-i] = logs[l-1-i], logs[i] } return logs, nil }
func (d *appLogDispatcher) runFlusher() { defer close(d.errCh) t := time.NewTimer(bulkMaxWaitTime) bulkBuffer := make([]interface{}, 0, 100) conn, err := db.LogConn() if err != nil { d.errCh <- err return } defer conn.Close() coll := conn.Logs(d.appName) for { var flush bool select { case <-d.done: return case msg := <-d.toFlush: bulkBuffer = append(bulkBuffer, msg) flush = len(bulkBuffer) == cap(bulkBuffer) if !flush { t.Reset(bulkMaxWaitTime) } case <-t.C: flush = len(bulkBuffer) > 0 } if flush { err := coll.Insert(bulkBuffer...) if err != nil { d.errCh <- err return } bulkBuffer = bulkBuffer[:0] } } }
func LogReceiver() (chan<- *Applog, <-chan error) { ch := make(chan *Applog) errCh := make(chan error) go func() { collMap := map[string]*storage.Collection{} messages := make([]interface{}, 1) for msg := range ch { messages[0] = msg notify(msg.AppName, messages) coll := collMap[msg.AppName] if coll == nil { conn, err := db.LogConn() if err != nil { errCh <- err break } coll = conn.Logs(msg.AppName) collMap[msg.AppName] = coll } err := coll.Insert(msg) if err != nil { errCh <- err break } } for _, coll := range collMap { coll.Close() } close(errCh) }() return ch, errCh }
// Log adds a log message to the app. Specifying a good source is good so the // user can filter where the message come from. func (app *App) Log(message, source, unit string) error { messages := strings.Split(message, "\n") logs := make([]interface{}, 0, len(messages)) for _, msg := range messages { if msg != "" { l := Applog{ Date: time.Now().In(time.UTC), Message: msg, Source: source, AppName: app.Name, Unit: unit, } logs = append(logs, l) } } if len(logs) > 0 { notify(app.Name, logs) conn, err := db.LogConn() if err != nil { return err } defer conn.Close() return conn.Logs(app.Name).Insert(logs...) } return nil }
func (s *S) SetUpTest(c *check.C) { routertest.FakeRouter.Reset() repositorytest.Reset() var err error s.conn, err = db.Conn() c.Assert(err, check.IsNil) dbtest.ClearAllCollections(s.conn.Apps().Database) s.logConn, err = db.LogConn() c.Assert(err, check.IsNil) s.createUserAndTeam(c) s.provisioner = provisiontest.NewFakeProvisioner() app.Provisioner = s.provisioner app.AuthScheme = nativeScheme p := app.Platform{Name: "zend"} s.conn.Platforms().Insert(p) s.Pool = "test1" opts := provision.AddPoolOptions{Name: "test1", Default: true} err = provision.AddPool(opts) c.Assert(err, check.IsNil) repository.Manager().CreateUser(s.user.Email) repository.Manager().CreateUser(s.adminuser.Email) factory, err := queue.Factory() c.Assert(err, check.IsNil) factory.Reset() }
func (s *LogSuite) SetUpTest(c *check.C) { repositorytest.Reset() var err error s.conn, err = db.Conn() c.Assert(err, check.IsNil) dbtest.ClearAllCollections(s.conn.Apps().Database) s.logConn, err = db.LogConn() c.Assert(err, check.IsNil) s.createUserAndTeam(c) }
func (s *LogSuite) TearDownSuite(c *check.C) { conn, err := db.Conn() c.Assert(err, check.IsNil) defer conn.Close() conn.Apps().Database.DropDatabase() logConn, err := db.LogConn() c.Assert(err, check.IsNil) defer logConn.Close() logConn.Logs("myapp").Database.DropDatabase() }
func (s *DeploySuite) SetUpSuite(c *check.C) { config.Set("database:url", "127.0.0.1:27017") config.Set("database:name", "tsuru_deploy_api_tests") config.Set("auth:hash-cost", 4) config.Set("repo-manager", "fake") var err error s.conn, err = db.Conn() c.Assert(err, check.IsNil) s.logConn, err = db.LogConn() c.Assert(err, check.IsNil) }
func (s *EventSuite) SetUpSuite(c *check.C) { err := config.ReadConfigFile("testdata/config.yaml") c.Assert(err, check.IsNil) config.Set("database:url", "127.0.0.1:27017") config.Set("database:name", "tsuru_events_api_tests") config.Set("auth:hash-cost", 4) config.Set("repo-manager", "fake") s.conn, err = db.Conn() c.Assert(err, check.IsNil) s.logConn, err = db.LogConn() c.Assert(err, check.IsNil) }
// Delete deletes an app. // // Delete an app is a process composed of three steps: // // 1. Destroy the app unit // 2. Unbind all service instances from the app // 3. Remove the app from the database func Delete(app *App) error { appName := app.Name wg := asyncDestroyAppProvisioner(app) wg.Add(1) defer wg.Done() go func() { defer ReleaseApplicationLock(appName) wg.Wait() logConn, err := db.LogConn() if err != nil { log.Errorf("Unable to delete app %s from db: %s", appName, err.Error()) } defer logConn.Close() conn, err := db.Conn() if err != nil { log.Errorf("Unable to delete app %s from db: %s", appName, err.Error()) } defer conn.Close() err = logConn.Logs(appName).DropCollection() if err != nil { log.Errorf("Ignored error dropping logs collection for app %s: %s", appName, err.Error()) } err = conn.Apps().Remove(bson.M{"name": appName}) if err != nil { log.Errorf("Error trying to destroy app %s from db: %s", appName, err.Error()) } err = markDeploysAsRemoved(appName) if err != nil { log.Errorf("Error trying to mark old deploys as removed for app %s: %s", appName, err.Error()) } }() err := repository.Manager().RemoveRepository(appName) if err != nil { log.Errorf("failed to remove app %q from repository manager: %s", appName, err) } token := app.Env["TSURU_APP_TOKEN"].Value err = AuthScheme.Logout(token) if err != nil { log.Errorf("Unable to remove app token in destroy: %s", err.Error()) } owner, err := auth.GetUserByEmail(app.Owner) if err != nil { log.Errorf("Unable to get app owner in destroy: %s", err.Error()) } else { err = auth.ReleaseApp(owner) if err != nil { log.Errorf("Unable to release app quota: %s", err.Error()) } } return nil }
func (s *DeploySuite) SetUpSuite(c *check.C) { config.Set("database:url", "127.0.0.1:27017") config.Set("database:name", "tsuru_deploy_api_tests") config.Set("aut:hash-cost", 4) config.Set("admin-team", "tsuruteam") config.Set("repo-manager", "fake") var err error s.conn, err = db.Conn() c.Assert(err, check.IsNil) s.logConn, err = db.LogConn() c.Assert(err, check.IsNil) s.provisioner = provisiontest.NewFakeProvisioner() app.Provisioner = s.provisioner }
func (s *S) SetUpSuite(c *check.C) { err := config.ReadConfigFile("testdata/config.yaml") c.Assert(err, check.IsNil) s.conn, err = db.Conn() c.Assert(err, check.IsNil) s.logConn, err = db.LogConn() c.Assert(err, check.IsNil) s.provisioner = provisiontest.NewFakeProvisioner() Provisioner = s.provisioner AuthScheme = nativeScheme data, err := json.Marshal(AppLock{}) c.Assert(err, check.IsNil) err = json.Unmarshal(data, &s.zeroLock) c.Assert(err, check.IsNil) }
func (s *S) SetUpSuite(c *check.C) { err := config.ReadConfigFile("testdata/config.yaml") c.Assert(err, check.IsNil) config.Set("queue:mongo-url", "127.0.0.1:27017") config.Set("queue:mongo-database", "queue_app_pkg_tests") config.Set("queue:mongo-polling-interval", 0.01) config.Set("docker:registry", "registry.somewhere") s.conn, err = db.Conn() c.Assert(err, check.IsNil) s.logConn, err = db.LogConn() c.Assert(err, check.IsNil) s.provisioner = provisiontest.ProvisionerInstance provision.DefaultProvisioner = "fake" AuthScheme = nativeScheme data, err := json.Marshal(AppLock{}) c.Assert(err, check.IsNil) err = json.Unmarshal(data, &s.zeroLock) c.Assert(err, check.IsNil) LogPubSubQueuePrefix = "pubsub:app-test:" }
// LogRemove removes the app log. func LogRemove(a *App) error { conn, err := db.LogConn() if err != nil { return err } defer conn.Close() if a != nil { return conn.Logs(a.Name).DropCollection() } colls, err := conn.LogsCollections() if err != nil { return err } for _, coll := range colls { err = coll.DropCollection() if err != nil { log.Errorf("Error trying to drop collection %s", coll.Name) } } return nil }
func (d *appLogDispatcher) runFlusher() { defer close(d.errCh) t := time.NewTimer(bulkMaxWaitTime) pos := 0 sz := 200 bulkBuffer := make([]interface{}, sz) for { var flush bool select { case <-d.done: return case msg := <-d.toFlush: bulkBuffer[pos] = msg pos++ flush = sz == pos if flush { t.Stop() } else { t.Reset(bulkMaxWaitTime) } case <-t.C: flush = pos > 0 } if flush { conn, err := db.LogConn() if err != nil { d.errCh <- err return } coll := conn.Logs(d.appName) err = coll.Insert(bulkBuffer[:pos]...) coll.Close() if err != nil { d.errCh <- err return } pos = 0 } } }
func (d *appLogDispatcher) runFlusher() { t := time.NewTimer(bulkMaxWaitTime) pos := 0 sz := 200 bulkBuffer := make([]interface{}, sz) for { var flush bool select { case <-d.done: return case msg := <-d.toFlush: if pos == sz { flush = true break } bulkBuffer[pos] = msg pos++ flush = sz == pos case <-t.C: flush = pos > 0 t.Reset(bulkMaxWaitTime) } if flush { conn, err := db.LogConn() if err != nil { log.Errorf("[log flusher] unable to connect to mongodb: %s", err) continue } coll := conn.Logs(d.appName) err = coll.Insert(bulkBuffer[:pos]...) coll.Close() if err != nil { log.Errorf("[log flusher] unable to insert logs: %s", err) continue } pos = 0 } } }
// LastLogs returns a list of the last `lines` log of the app, matching the // fields in the log instance received as an example. func (app *App) LastLogs(lines int, filterLog Applog) ([]Applog, error) { conn, err := db.LogConn() if err != nil { return nil, err } defer conn.Close() logs := []Applog{} q := bson.M{} if filterLog.Source != "" { q["source"] = filterLog.Source } if filterLog.Unit != "" { q["unit"] = filterLog.Unit } err = conn.Logs(app.Name).Find(q).Sort("-$natural").Limit(lines).All(&logs) if err != nil { return nil, err } l := len(logs) for i := 0; i < l/2; i++ { logs[i], logs[l-1-i] = logs[l-1-i], logs[i] } return logs, nil }
// Delete deletes an app. func Delete(app *App, w io.Writer) error { isSwapped, swappedWith, err := router.IsSwapped(app.GetName()) if err != nil { return fmt.Errorf("unable to check if app is swapped: %s", err) } if isSwapped { return fmt.Errorf("application is swapped with %q, cannot remove it", swappedWith) } appName := app.Name if w == nil { w = ioutil.Discard } fmt.Fprintf(w, "---- Removing application %q...\n", appName) var hasErrors bool defer func() { var problems string if hasErrors { problems = " Some errors occurred during removal." } fmt.Fprintf(w, "---- Done removing application.%s\n", problems) }() logErr := func(msg string, err error) { msg = fmt.Sprintf("%s: %s", msg, err) fmt.Fprintf(w, "%s\n", msg) log.Errorf("[delete-app: %s] %s", appName, msg) hasErrors = true } err = Provisioner.Destroy(app) if err != nil { logErr("Unable to destroy app in provisioner", err) } err = app.unbind() if err != nil { logErr("Unable to unbind app", err) } err = repository.Manager().RemoveRepository(appName) if err != nil { logErr("Unable to remove app from repository manager", err) } token := app.Env["TSURU_APP_TOKEN"].Value err = AuthScheme.AppLogout(token) if err != nil { logErr("Unable to remove app token in destroy", err) } owner, err := auth.GetUserByEmail(app.Owner) if err == nil { err = auth.ReleaseApp(owner) } if err != nil { logErr("Unable to release app quota", err) } logConn, err := db.LogConn() if err == nil { defer logConn.Close() err = logConn.Logs(appName).DropCollection() } if err != nil { logErr("Unable to remove logs collection", err) } conn, err := db.Conn() if err == nil { defer conn.Close() err = conn.Apps().Remove(bson.M{"name": appName}) } if err != nil { logErr("Unable to remove app from db", err) } err = markDeploysAsRemoved(appName) if err != nil { logErr("Unable to mark old deploys as removed", err) } return nil }