func (s *ELBSuite) TestELBInstanceHealerInstallingUnit(c *gocheck.C) { lb := "elbtest" instance := s.server.NewInstance() defer s.server.RemoveInstance(instance) s.server.NewLoadBalancer(lb) defer s.server.RemoveLoadBalancer(lb) s.server.RegisterInstance(instance, lb) defer s.server.DeregisterInstance(instance, lb) a := app.App{ Name: "elbtest", Units: []app.Unit{{InstanceId: instance, State: "installing", Name: "elbtest/0"}}, } storage, err := db.Conn() c.Assert(err, gocheck.IsNil) err = storage.Apps().Insert(a) c.Assert(err, gocheck.IsNil) defer storage.Apps().Remove(bson.M{"name": a.Name}) s.provisioner.Provision(&a) defer s.provisioner.Destroy(&a) state := elb.InstanceState{ Description: "Instance has failed at least the UnhealthyThreshold number of health checks consecutively.", State: "OutOfService", ReasonCode: "Instance", InstanceId: instance, } s.server.ChangeInstanceState(lb, state) healer := elbInstanceHealer{} err = healer.Heal() c.Assert(err, gocheck.IsNil) err = a.Get() c.Assert(err, gocheck.IsNil) c.Assert(a.Units, gocheck.HasLen, 1) c.Assert(a.Units[0].InstanceId, gocheck.Equals, instance) }
func (s segregatedScheduler) Schedule(opts dcli.CreateContainerOptions, cfg *docker.Config) (string, *docker.Container, error) { conn, err := db.Conn() if err != nil { return "", nil, err } defer conn.Close() var cont container coll := collection() defer coll.Close() err = coll.Find(bson.M{"name": opts.Name}).One(&cont) if err != nil { return "", nil, err } app := app.App{Name: cont.AppName} err = app.Get() if err != nil { return s.fallback(opts, cfg) } var nodes []node query := bson.M{"teams": bson.M{"$in": app.Teams}} err = conn.Collection(schedulerCollection).Find(query).All(&nodes) if err != nil || len(nodes) < 1 { return s.fallback(opts, cfg) } return s.handle(opts, cfg, nodes) }
func (s *S) TestSaveUnitsForwardShouldMaintainData(c *gocheck.C) { a := app.App{ Name: "otherapp", Platform: "zend", Deploys: 10, } conn, err := db.Conn() c.Assert(err, gocheck.IsNil) defer conn.Close() err = conn.Apps().Insert(a) c.Assert(err, gocheck.IsNil) a.Deploys = 0 defer conn.Apps().Remove(bson.M{"name": a.Name}) container := container{ ID: "id", Type: "python", HostAddr: "", AppName: a.Name, } coll := collection() c.Assert(err, gocheck.IsNil) coll.Insert(&container) context := action.FWContext{Params: []interface{}{&a}} _, err = saveUnits.Forward(context) c.Assert(err, gocheck.IsNil) app, err := app.GetByName(a.Name) c.Assert(err, gocheck.IsNil) c.Assert(app.Units[0].Name, gocheck.Equals, "id") c.Assert(int(app.Deploys), gocheck.Equals, 10) }
func (s segregatedScheduler) Schedule(cfg *docker.Config) (string, *docker.Container, error) { image := cfg.Image namespace, err := config.GetString("docker:repository-namespace") if err != nil { return "", nil, err } conn, err := db.Conn() if err != nil { return "", nil, err } defer conn.Close() appname := strings.Replace(image, namespace+"/", "", -1) app := app.App{Name: appname} err = app.Get() if err != nil { return s.fallback(cfg) } if len(app.Teams) == 1 { var nodes []node err = conn.Collection(schedulerCollection).Find(bson.M{"team": app.Teams[0]}).All(&nodes) if err != nil || len(nodes) < 1 { return s.fallback(cfg) } return s.handle(cfg, nodes) } return s.fallback(cfg) }
func (s *S) TestSaveUnitsForward(c *gocheck.C) { app := app.App{ Name: "otherapp", Platform: "zend", } conn, err := db.Conn() c.Assert(err, gocheck.IsNil) defer conn.Close() err = conn.Apps().Insert(app) c.Assert(err, gocheck.IsNil) defer conn.Apps().Remove(bson.M{"name": app.Name}) container := container{ ID: "id", Type: "python", HostAddr: "", AppName: app.Name, } coll := collection() c.Assert(err, gocheck.IsNil) coll.Insert(&container) context := action.FWContext{Params: []interface{}{&app}} _, err = saveUnits.Forward(context) c.Assert(err, gocheck.IsNil) err = app.Get() c.Assert(err, gocheck.IsNil) c.Assert(app.Units[0].Name, gocheck.Equals, "id") }
func addLog(w http.ResponseWriter, r *http.Request, t *auth.Token) error { queryValues := r.URL.Query() app := app.App{Name: queryValues.Get(":app")} err := app.Get() if err != nil { return err } defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } var logs []string err = json.Unmarshal(body, &logs) source := queryValues.Get("source") if len(source) == 0 { source = "app" } for _, log := range logs { err := app.Log(log, source) if err != nil { return err } } w.WriteHeader(http.StatusOK) return nil }
func generateAppToken(w http.ResponseWriter, r *http.Request, t *auth.Token) error { var body jToken defer r.Body.Close() err := json.NewDecoder(r.Body).Decode(&body) if err != nil { return err } if body.Client == "" { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "Missing client name in JSON body", } } token, err := auth.CreateApplicationToken(body.Client) if err != nil { return err } if body.Export { a := app.App{Name: body.Client} if err := a.Get(); err == nil { envs := []bind.EnvVar{ { Name: "TSURU_APP_TOKEN", Value: token.Token, Public: false, }, } a.SetEnvs(envs, false) } } return json.NewEncoder(w).Encode(token) }
func createAppHelper(instance *app.App, u *auth.User, units uint) ([]byte, error) { teams, err := u.Teams() if err != nil { return nil, err } if len(teams) < 1 { msg := "In order to create an app, you should be member of at least one team" return nil, &errors.Http{Code: http.StatusForbidden, Message: msg} } instance.SetTeams(teams) err = app.CreateApp(instance, units) if err != nil { log.Printf("Got error while creating app: %s", err) if e, ok := err.(*app.ValidationError); ok { return nil, &errors.Http{Code: http.StatusPreconditionFailed, Message: e.Message} } if strings.Contains(err.Error(), "key error") { msg := fmt.Sprintf(`There is already an app named "%s".`, instance.Name) return nil, &errors.Http{Code: http.StatusConflict, Message: msg} } return nil, err } msg := map[string]string{ "status": "success", "repository_url": repository.GetUrl(instance.Name), } return json.Marshal(msg) }
func (s *S) TestUnbindRemovesEnvironmentVariableFromApp(c *gocheck.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{ Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}, Apps: []string{"painkiller"}, } err = instance.Create() c.Assert(err, gocheck.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"_id": "my-mysql"}) a := app.App{ Name: "painkiller", Teams: []string{s.team.Name}, Env: map[string]bind.EnvVar{ "DATABASE_HOST": { Name: "DATABASE_HOST", Value: "arrea", Public: false, InstanceName: instance.Name, }, "MY_VAR": { Name: "MY_VAR", Value: "123", }, }, Units: []app.Unit{ { Ip: "10.10.10.10", }, }, } err = s.conn.Apps().Insert(&a) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = instance.UnbindApp(&a) c.Assert(err, gocheck.IsNil) newApp := app.App{Name: a.Name} err = newApp.Get() c.Assert(err, gocheck.IsNil) expected := map[string]bind.EnvVar{ "MY_VAR": { Name: "MY_VAR", Value: "123", }, } c.Assert(a.Env, gocheck.DeepEquals, expected) }
func getAppOrError(name string, u *auth.User) (app.App, error) { app := app.App{Name: name} err := app.Get() if err != nil { return app, &errors.Http{Code: http.StatusNotFound, Message: fmt.Sprintf("App %s not found.", name)} } if !auth.CheckUserAccess(app.Teams, u) { return app, &errors.Http{Code: http.StatusForbidden, Message: "User does not have access to this app"} } return app, nil }
// AppIsAvaliableHandler verify if the app.Unit().State() is // started. If is started it returns 200 else returns 500 for // status code. func AppIsAvaliableHandler(w http.ResponseWriter, r *http.Request) error { app := app.App{Name: r.URL.Query().Get(":name")} err := app.Get() if err != nil { return err } if app.State != "started" { return fmt.Errorf("App must be started to receive pushs, but it is %q.", app.State) } w.WriteHeader(http.StatusOK) return nil }
func appIsAvailable(w http.ResponseWriter, r *http.Request, t *auth.Token) error { app := app.App{Name: r.URL.Query().Get(":appname")} err := app.Get() if err != nil { return err } if !app.Available() { return fmt.Errorf("App must be available to receive pushs.") } w.WriteHeader(http.StatusOK) return nil }
func createApp(w http.ResponseWriter, r *http.Request, t *auth.Token) error { var a app.App var japp jsonApp defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } if err = json.Unmarshal(body, &japp); err != nil { return err } a.Name = japp.Name a.Platform = japp.Platform if japp.Units == 0 { japp.Units = 1 } u, err := t.User() if err != nil { return err } rec.Log(u.Email, "create-app", "name="+japp.Name, "platform="+japp.Platform, fmt.Sprintf("units=%d", japp.Units)) teams, err := u.Teams() if err != nil { return err } if len(teams) < 1 { msg := "In order to create an app, you should be member of at least one team" return &errors.Http{Code: http.StatusForbidden, Message: msg} } err = app.CreateApp(&a, japp.Units, teams) if err != nil { log.Printf("Got error while creating app: %s", err) if e, ok := err.(*errors.ValidationError); ok { return &errors.Http{Code: http.StatusBadRequest, Message: e.Message} } if strings.Contains(err.Error(), "key error") { msg := fmt.Sprintf(`There is already an app named "%s".`, a.Name) return &errors.Http{Code: http.StatusConflict, Message: msg} } return err } msg := map[string]string{ "status": "success", "repository_url": repository.GetUrl(a.Name), } jsonMsg, err := json.Marshal(msg) if err != nil { return err } fmt.Fprintf(w, "%s", jsonMsg) return nil }
func (s *S) TestDeployRemoveContainersEvenWhenTheyreNotInTheAppsCollection(c *gocheck.C) { h := &tsrTesting.TestHandler{} gandalfServer := tsrTesting.StartGandalfTestServer(h) defer gandalfServer.Close() go s.stopContainers(3) err := newImage("tsuru/python", s.server.URL()) c.Assert(err, gocheck.IsNil) cont1, err := s.newContainer(nil) c.Assert(err, gocheck.IsNil) _, err = s.newContainer(nil) c.Assert(err, gocheck.IsNil) defer rtesting.FakeRouter.RemoveBackend(cont1.AppName) var p dockerProvisioner a := app.App{ Name: "otherapp", Platform: "python", Units: []app.Unit{{Name: "i-0800", State: "started"}}, } conn, err := db.Conn() defer conn.Close() err = conn.Apps().Insert(a) c.Assert(err, gocheck.IsNil) defer conn.Apps().Remove(bson.M{"name": a.Name}) p.Provision(&a) defer p.Destroy(&a) fexec := &etesting.FakeExecutor{} setExecut(fexec) defer setExecut(nil) var w bytes.Buffer err = app.DeployApp(&a, "master", &w) c.Assert(err, gocheck.IsNil) time.Sleep(1e9) defer p.Destroy(&a) q, err := getQueue() c.Assert(err, gocheck.IsNil) for _, u := range a.ProvisionedUnits() { message, err := q.Get(1e6) c.Assert(err, gocheck.IsNil) defer message.Delete() c.Assert(err, gocheck.IsNil) c.Assert(message.Action, gocheck.Equals, app.BindService) c.Assert(message.Args[0], gocheck.Equals, a.GetName()) c.Assert(message.Args[1], gocheck.Equals, u.GetName()) } coll := collection() defer coll.Close() n, err := coll.Find(bson.M{"appname": cont1.AppName}).Count() c.Assert(err, gocheck.IsNil) c.Assert(n, gocheck.Equals, 2) }
func (s *LogSuite) TestLogRemoveAll(c *gocheck.C) { a := app.App{Name: "words"} request, err := http.NewRequest("DELETE", "/logs", nil) c.Assert(err, gocheck.IsNil) recorder := httptest.NewRecorder() err = s.conn.Apps().Insert(a) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = a.Log("last log msg", "tsuru") c.Assert(err, gocheck.IsNil) err = logRemove(recorder, request, s.token) c.Assert(err, gocheck.IsNil) count, err := s.conn.Logs().Find(nil).Count() c.Assert(err, gocheck.IsNil) c.Assert(count, gocheck.Equals, 0) }
func (s *S) TestUpdateWithMultipleApps(c *gocheck.C) { appDicts := []map[string]string{ { "name": "andrewzito3", "ip": "10.10.10.163", }, { "name": "flaviapp", "ip": "10.10.10.208", }, { "name": "mysqlapi", "ip": "10.10.10.131", }, { "name": "teste_api_semantica", "ip": "10.10.10.189", }, { "name": "xikin", "ip": "10.10.10.168", }, } apps := make([]app.App, len(appDicts)) units := make([]provision.Unit, len(appDicts)) for i, appDict := range appDicts { a := app.App{Name: appDict["name"]} err := s.conn.Apps().Insert(&a) c.Assert(err, gocheck.IsNil) apps[i] = a units[i] = provision.Unit{ Name: "i-00000", AppName: appDict["name"], Machine: i + 1, Type: "python", Ip: appDict["ip"], Status: provision.StatusInstalling, } } update(units) for _, appDict := range appDicts { a := app.App{Name: appDict["name"]} err := a.Get() c.Assert(err, gocheck.IsNil) c.Assert(a.Units[0].Ip, gocheck.Equals, appDict["ip"]) } }
func (s *S) TestUpdateWithDownMachine(c *gocheck.C) { a := app.App{Name: "barduscoapp"} err := s.conn.Apps().Insert(&a) c.Assert(err, gocheck.IsNil) units := []provision.Unit{ { Name: "i-00000zz8", AppName: "barduscoapp", Type: "python", Machine: 2, Ip: "", Status: provision.StatusPending, }, } update(units) err = a.Get() c.Assert(err, gocheck.IsNil) }
func (s *S) TestUpdateWithDownMachine(c *C) { a := app.App{Name: "barduscoapp"} err := db.Session.Apps().Insert(&a) c.Assert(err, IsNil) units := []provision.Unit{ { Name: "i-00000zz8", AppName: "barduscoapp", Type: "python", Machine: 2, Ip: "", Status: provision.StatusPending, }, } update(units) err = a.Get() c.Assert(err, IsNil) c.Assert(a.State, Equals, string(provision.StatusPending)) }
func (s *S) TestDeploy(c *gocheck.C) { h := &tsrTesting.TestHandler{} gandalfServer := tsrTesting.StartGandalfTestServer(h) defer gandalfServer.Close() go s.stopContainers(1) err := newImage("tsuru/python", s.server.URL()) c.Assert(err, gocheck.IsNil) fexec := &etesting.FakeExecutor{} setExecut(fexec) defer setExecut(nil) p := dockerProvisioner{} app.Provisioner = &p a := app.App{ Name: "otherapp", Platform: "python", Units: []app.Unit{{Name: "i-0800", State: "started"}}, } conn, err := db.Conn() defer conn.Close() err = conn.Apps().Insert(a) c.Assert(err, gocheck.IsNil) defer conn.Apps().Remove(bson.M{"name": a.Name}) p.Provision(&a) defer p.Destroy(&a) w := writer{b: make([]byte, 2048)} err = app.DeployApp(&a, "master", &w) c.Assert(err, gocheck.IsNil) w.b = nil defer p.Destroy(&a) time.Sleep(6e9) q, err := getQueue() for _, u := range a.ProvisionedUnits() { message, err := q.Get(1e6) c.Assert(err, gocheck.IsNil) defer message.Delete() c.Assert(err, gocheck.IsNil) c.Assert(message.Action, gocheck.Equals, app.BindService) c.Assert(message.Args[0], gocheck.Equals, a.GetName()) c.Assert(message.Args[1], gocheck.Equals, u.GetName()) } }
func (s *S) TestBindCallTheServiceAPIAndSetsEnvironmentVariableReturnedFromTheCall(c *gocheck.C) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(`{"DATABASE_USER":"******","DATABASE_PASSWORD":"******"}`)) })) defer ts.Close() srvc := service.Service{Name: "mysql", Endpoint: map[string]string{"production": ts.URL}} err := srvc.Create() c.Assert(err, gocheck.IsNil) defer s.conn.Services().Remove(bson.M{"_id": "mysql"}) instance := service.ServiceInstance{ Name: "my-mysql", ServiceName: "mysql", Teams: []string{s.team.Name}, } err = instance.Create() c.Assert(err, gocheck.IsNil) defer s.conn.ServiceInstances().Remove(bson.M{"_id": "my-mysql"}) a, err := createTestApp(s.conn, "painkiller", "", []string{s.team.Name}, []app.Unit{{Ip: "127.0.0.1"}}) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = instance.BindApp(&a) c.Assert(err, gocheck.IsNil) newApp := app.App{Name: a.Name} err = newApp.Get() c.Assert(err, gocheck.IsNil) expectedEnv := map[string]bind.EnvVar{ "DATABASE_USER": { Name: "DATABASE_USER", Value: "root", Public: false, InstanceName: instance.Name, }, "DATABASE_PASSWORD": { Name: "DATABASE_PASSWORD", Value: "s3cr3t", Public: false, InstanceName: instance.Name, }, } c.Assert(a.Env, gocheck.DeepEquals, expectedEnv) }
func (s *LogSuite) TestLogRemoveByApp(c *gocheck.C) { a := app.App{ Name: "words", Teams: []string{s.team.Name}, } err := s.conn.Apps().Insert(a) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a.Name}) err = a.Log("last log msg", "tsuru") c.Assert(err, gocheck.IsNil) a2 := app.App{Name: "words2"} err = s.conn.Apps().Insert(a2) c.Assert(err, gocheck.IsNil) defer s.conn.Apps().Remove(bson.M{"name": a2.Name}) err = a2.Log("last log msg2", "tsuru") c.Assert(err, gocheck.IsNil) url := fmt.Sprintf("/logs?app=%s", a.Name) request, err := http.NewRequest("DELETE", url, nil) c.Assert(err, gocheck.IsNil) recorder := httptest.NewRecorder() err = logRemove(recorder, request, s.token) c.Assert(err, gocheck.IsNil) count, err := s.conn.Logs().Find(nil).Count() c.Assert(err, gocheck.IsNil) c.Assert(count, gocheck.Equals, 1) }
func AddLogHandler(w http.ResponseWriter, r *http.Request) error { app := app.App{Name: r.URL.Query().Get(":name")} err := app.Get() if err != nil { return err } defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } var logs []string err = json.Unmarshal(body, &logs) for _, log := range logs { err := app.Log(log, "app") if err != nil { return err } } w.WriteHeader(http.StatusOK) return nil }
func (h *MessageHandler) ensureAppIsStarted(msg queue.Message) (app.App, error) { a := app.App{Name: msg.Args[0]} err := a.Get() if err != nil { return a, fmt.Errorf("Error handling %q: app %q does not exist.", msg.Action, a.Name) } units := h.getUnits(&a, msg.Args[1:]) if a.State != "started" || !units.Started() { format := "Error handling %q for the app %q:" switch a.State { case "error": format += " the app is in %q state." case "down": format += " the app is %s." default: format += ` The status of the app and all units should be "started" (the app is %q).` time.Sleep(time.Duration(msg.Visits+1) * time.Second) h.server.PutBack(msg) } return a, fmt.Errorf(format, msg.Action, a.Name, a.State) } return a, nil }
func CreateAppHandler(w http.ResponseWriter, r *http.Request, u *auth.User) error { var app app.App var japp jsonApp defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } if err = json.Unmarshal(body, &japp); err != nil { return err } app.Name = japp.Name app.Framework = japp.Framework if japp.Units == 0 { japp.Units = 1 } jsonMsg, err := createAppHelper(&app, u, japp.Units) if err != nil { return err } fmt.Fprint(w, string(jsonMsg)) return nil }
func ensureAppIsStarted(msg *queue.Message) (app.App, error) { a := app.App{Name: msg.Args[0]} err := a.Get() if err != nil { return a, fmt.Errorf("Error handling %q: app %q does not exist.", msg.Action, a.Name) } units := getUnits(&a, msg.Args[1:]) if a.State != "started" || !units.Started() { format := "Error handling %q for the app %q:" switch a.State { case "error": format += " the app is in %q state." queue.Delete(msg) case "down": format += " the app is %s." queue.Delete(msg) default: format += ` The status of the app and all units should be "started" (the app is %q).` } return a, fmt.Errorf(format, msg.Action, a.Name, a.State) } return a, nil }
func getEmailsForRevoking(app *app.App, t *auth.Team) []string { var i int teams := app.GetTeams() users := make([]string, len(t.Users)) for _, email := range t.Users { found := false for _, team := range teams { for _, user := range team.Users { if user == email { found = true break } } } if !found { users[i] = email i++ } } return users[:i] }
func CloneRepositoryHandler(w http.ResponseWriter, r *http.Request) error { w.Header().Set("Content-Type", "text") instance := app.App{Name: r.URL.Query().Get(":name")} err := instance.Get() logWriter := LogWriter{&instance, w} if err != nil { return &errors.Http{Code: http.StatusNotFound, Message: fmt.Sprintf("App %s not found.", instance.Name)} } err = write(&logWriter, []byte("\n ---> Tsuru receiving push\n")) if err != nil { return err } err = write(&logWriter, []byte("\n ---> Replicating the application repository across units\n")) if err != nil { return err } out, err := repository.CloneOrPull(&instance) // should iterate over the machines if err != nil { return &errors.Http{Code: http.StatusInternalServerError, Message: string(out)} } err = write(&logWriter, out) if err != nil { return err } err = write(&logWriter, []byte("\n ---> Installing dependencies\n")) if err != nil { return err } err = instance.InstallDeps(&logWriter) if err != nil { return err } err = instance.Restart(&logWriter) if err != nil { return err } return write(&logWriter, []byte("\n ---> Deploy done!\n\n")) }