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 *S) TestCreateRepositoryBackward(c *check.C) { app := App{Name: "someapp"} err := repository.Manager().CreateRepository(app.Name, nil) c.Assert(err, check.IsNil) ctx := action.BWContext{FWResult: &app, Params: []interface{}{app}} createRepository.Backward(ctx) _, err = repository.Manager().GetRepository(app.Name) c.Assert(err, check.NotNil) c.Assert(err.Error(), check.Equals, "repository not found") }
func (s *S) TestRemoveKeyRemovesAKeyFromTheUser(c *check.C) { key := repository.Key{Body: "my-key", Name: "the-key"} u := &User{Email: "*****@*****.**"} err := u.Create() c.Assert(err, check.IsNil) defer u.Delete() err = repository.Manager().(repository.KeyRepositoryManager).AddKey(u.Email, key) c.Assert(err, check.IsNil) err = u.RemoveKey(repository.Key{Name: "the-key"}) c.Assert(err, check.IsNil) keys, err := repository.Manager().(repository.KeyRepositoryManager).ListKeys(u.Email) c.Assert(err, check.IsNil) c.Assert(keys, check.HasLen, 0) }
func (u *User) createOnRepositoryManager() error { err := repository.Manager().CreateUser(u.Email) if err != nil { return err } return nil }
// removeUser removes the user from the database and from repository server // // If the user is the only one in a team an error will be returned. func removeUser(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } email := r.URL.Query().Get("user") if email != "" { if !permission.Check(t, permission.PermUserDelete) { return permission.ErrUnauthorized } u, err = auth.GetUserByEmail(email) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } } appNames, err := deployableApps(u) if err != nil { return err } manager := repository.Manager() for _, name := range appNames { manager.RevokeAccess(name, u.Email) } rec.Log(u.Email, "remove-user") if err := manager.RemoveUser(u.Email); err != nil { log.Errorf("Failed to remove user from repository manager: %s", err) } return app.AuthScheme.Remove(u) }
func (s *S) TestRemovePermissionsFromRoleSyncGitRepository(c *check.C) { r, err := permission.NewRole("test", "team") c.Assert(err, check.IsNil) defer permission.DestroyRole(r.Name) err = r.AddPermissions("app.deploy") c.Assert(err, check.IsNil) user := &auth.User{Email: "*****@*****.**", Password: "******"} _, err = nativeScheme.Create(user) c.Assert(err, check.IsNil) err = user.AddRole("test", s.team.Name) c.Assert(err, check.IsNil) a := app.App{Name: "myapp", TeamOwner: s.team.Name} err = app.CreateApp(&a, s.user) err = repository.Manager().GrantAccess(a.Name, user.Email) c.Assert(err, check.IsNil) rec := httptest.NewRecorder() req, err := http.NewRequest("DELETE", "/roles/test/permissions/app.deploy", nil) c.Assert(err, check.IsNil) token := userWithPermission(c, permission.Permission{ Scheme: permission.PermRoleUpdate, Context: permission.Context(permission.CtxGlobal, ""), }) req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Authorization", "bearer "+token.GetValue()) server := RunServer(true) server.ServeHTTP(rec, req) c.Assert(rec.Code, check.Equals, http.StatusOK) r, err = permission.FindRole("test") c.Assert(err, check.IsNil) c.Assert(r.SchemeNames, check.DeepEquals, []string{}) users, err := repositorytest.Granted(a.Name) c.Assert(err, check.IsNil) c.Assert(users, check.DeepEquals, []string{s.user.Email}) }
// gitDeployCmds returns the list of commands that are used when the // provisioner deploys a unit using the Git repository method. func gitDeployCmds(app provision.App, version string) ([]string, error) { repo, err := repository.Manager().GetRepository(app.GetName()) if err != nil { return nil, err } return deployCmds(app, "git", repo.ReadOnlyURL, version) }
func (s *S) SetUpTest(c *check.C) { config.Set("docker:api-timeout", 2) iaas.ResetAll() repositorytest.Reset() queue.ResetQueue() repository.Manager().CreateUser(s.user.Email) s.p = &dockerProvisioner{storage: &cluster.MapStorage{}} err := s.p.Initialize() c.Assert(err, check.IsNil) queue.ResetQueue() s.server, err = dtesting.NewServer("127.0.0.1:0", nil, nil) c.Assert(err, check.IsNil) s.p.cluster, err = cluster.New(nil, s.p.storage, cluster.Node{Address: s.server.URL(), Metadata: map[string]string{"pool": "test-default"}}, ) c.Assert(err, check.IsNil) mainDockerProvisioner = s.p err = dbtest.ClearAllCollectionsExcept(s.storage.Apps().Database, []string{"users", "tokens", "teams"}) c.Assert(err, check.IsNil) err = clearClusterStorage(s.clusterSess) c.Assert(err, check.IsNil) routertest.FakeRouter.Reset() opts := provision.AddPoolOptions{Name: "test-default", Default: true} err = provision.AddPool(opts) c.Assert(err, check.IsNil) s.storage.Tokens().Remove(bson.M{"appname": bson.M{"$ne": ""}}) s.logBuf = safe.NewBuffer(nil) log.SetLogger(log.NewWriterLogger(s.logBuf, true)) s.token = createTokenForUser(s.user, "*", string(permission.CtxGlobal), "", c) }
func removeUserFromTeamInRepository(u *auth.User, team *auth.Team) error { teamApps, err := team.AllowedApps() if err != nil { return err } userApps, err := u.AllowedApps() if err != nil { return err } appsToRemove := make([]string, 0, len(teamApps)) for _, teamApp := range teamApps { found := false for _, userApp := range userApps { if userApp == teamApp { found = true break } } if !found { appsToRemove = append(appsToRemove, teamApp) } } manager := repository.Manager() for _, app := range appsToRemove { manager.RevokeAccess(app, u.Email) } return nil }
func (s *S) TestListKeysShouldGetKeysFromTheRepositoryManager(c *check.C) { u := User{ Email: "*****@*****.**", Password: "******", } newKeys := []repository.Key{{Name: "key1", Body: "superkey"}, {Name: "key2", Body: "hiperkey"}} err := u.Create() c.Assert(err, check.IsNil) defer u.Delete() repository.Manager().(repository.KeyRepositoryManager).AddKey(u.Email, newKeys[0]) repository.Manager().(repository.KeyRepositoryManager).AddKey(u.Email, newKeys[1]) keys, err := u.ListKeys() c.Assert(err, check.IsNil) expected := map[string]string{"key1": "superkey", "key2": "hiperkey"} c.Assert(keys, check.DeepEquals, expected) }
// Revoke removes the access from a team. It returns an error if the team do // not have access to the app. func (app *App) Revoke(team *auth.Team) error { if len(app.Teams) == 1 { return ErrCannotOrphanApp } index, found := app.findTeam(team) if !found { return ErrNoAccess } last := len(app.Teams) - 1 app.Teams[index] = app.Teams[last] app.Teams = app.Teams[:last] conn, err := db.Conn() if err != nil { return err } defer conn.Close() err = conn.Apps().Update(bson.M{"name": app.Name}, bson.M{"$pull": bson.M{"teams": team.Name}}) if err != nil { return err } for _, user := range app.usersToRevoke(team) { err = repository.Manager().RevokeAccess(app.Name, user) if err != nil { conn.Apps().Update(bson.M{"name": app.Name}, bson.M{"$addToSet": bson.M{"teams": team.Name}}) return err } } return nil }
// Grant allows a team to have access to an app. It returns an error if the // team already have access to the app. func (app *App) Grant(team *auth.Team) error { if _, found := app.findTeam(team); found { return ErrAlreadyHaveAccess } app.Teams = append(app.Teams, team.Name) conn, err := db.Conn() if err != nil { return err } defer conn.Close() err = conn.Apps().Update(bson.M{"name": app.Name}, bson.M{"$addToSet": bson.M{"teams": team.Name}}) if err != nil { return err } users, err := auth.ListUsersWithPermissions(permission.Permission{ Scheme: permission.PermAppDeploy, Context: permission.Context(permission.CtxTeam, team.Name), }) if err != nil { conn.Apps().Update(bson.M{"name": app.Name}, bson.M{"$pull": bson.M{"teams": team.Name}}) return err } for _, user := range users { err = repository.Manager().GrantAccess(app.Name, user.Email) if err != nil { conn.Apps().Update(bson.M{"name": app.Name}, bson.M{"$pull": bson.M{"teams": team.Name}}) return err } } return nil }
func (s *S) SetUpTest(c *check.C) { s.provisioner.Reset() repositorytest.Reset() dbtest.ClearAllCollections(s.conn.Apps().Database) s.createUserAndTeam(c) platform := Platform{Name: "python"} s.conn.Platforms().Insert(platform) s.defaultPlan = Plan{ Name: "default-plan", Memory: 1024, Swap: 1024, CpuShare: 100, Default: true, } err := s.conn.Plans().Insert(s.defaultPlan) c.Assert(err, check.IsNil) s.Pool = "pool1" opts := provision.AddPoolOptions{Name: s.Pool} err = provision.AddPool(opts) c.Assert(err, check.IsNil) repository.Manager().CreateUser(s.user.Email) factory, err := queue.Factory() c.Assert(err, check.IsNil) factory.Reset() }
func (s *S) TestGetDiffInDeploysNoGit(c *check.C) { s.conn.Deploys().RemoveAll(nil) myDeploy := DeployData{ App: "g1", Timestamp: time.Now().Add(-3600 * time.Second), Commit: "545b1904af34458704e2aa06ff1aaffad5289f8g", Origin: "app-deploy", } deploys := []DeployData{ {App: "ge", Timestamp: time.Now(), Commit: "hwed834hf8y34h8fhn8rnr823nr238runh23x", Origin: "git"}, {App: "g1", Timestamp: time.Now().Add(-3600 * time.Second * 2), Commit: "545b1904af34458704e2aa06ff1aaffad5289f8f", Origin: "git"}, myDeploy, {App: "g1", Timestamp: time.Now(), Commit: "1b970b076bbb30d708e262b402d4e31910e1dc10", Origin: "git"}, } for _, d := range deploys { s.conn.Deploys().Insert(d) } defer s.conn.Deploys().RemoveAll(nil) err := s.conn.Deploys().Find(bson.M{"commit": myDeploy.Commit}).One(&myDeploy) c.Assert(err, check.IsNil) repository.Manager().CreateRepository("g1", nil) diffOutput, err := GetDiffInDeploys(&myDeploy) c.Assert(err, check.IsNil) c.Assert(diffOutput, check.Equals, "Cannot have diffs between git based and app-deploy based deployments") }
func syncRepositoryApps(user *auth.User, beforeApps []string, roleCache map[string]*permission.Role) error { err := user.Reload() if err != nil { return err } afterApps, err := deployableApps(user, roleCache) if err != nil { return err } afterMap := map[string]struct{}{} for _, a := range afterApps { afterMap[a] = struct{}{} } manager := repository.Manager() for _, a := range beforeApps { var err error if _, ok := afterMap[a]; !ok { err = manager.RevokeAccess(a, user.Email) } if err != nil { log.Errorf("error revoking gandalf access for app %s, user %s: %s", a, user.Email, err) } } for _, a := range afterApps { err := manager.GrantAccess(a, user.Email) if err != nil { log.Errorf("error granting gandalf access for app %s, user %s: %s", a, user.Email, err) } } return nil }
func (u *User) AddKey(key repository.Key) error { if mngr, ok := repository.Manager().(repository.KeyRepositoryManager); ok { if key.Name == "" { return ErrInvalidKey } return mngr.AddKey(u.Email, key) } return ErrKeyDisabled }
func (Suite) TestRegistration(c *check.C) { if old, err := config.Get("repo-manager"); err == nil { defer config.Set("repo-manager", old) } else { defer config.Unset("repo-manager") } config.Set("repo-manager", "fake") c.Check(repository.Manager().(*fakeManager), check.Equals, &manager) }
// removeUser removes the user from the database and from repository server // // If the user is the only one in a team an error will be returned. func removeUser(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } email := r.URL.Query().Get("user") if email != "" && u.IsAdmin() { u, err = auth.GetUserByEmail(email) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } } else if u.IsAdmin() { return &errors.HTTP{Code: http.StatusBadRequest, Message: "please specify the user you want to remove"} } else if email != "" { return &errors.HTTP{Code: http.StatusForbidden, Message: "you're not allowed to remove this user"} } alwdApps, err := u.AllowedApps() if err != nil { return err } manager := repository.Manager() for _, app := range alwdApps { manager.RevokeAccess(app, u.Email) } teams, err := u.Teams() if err != nil { return err } conn, err := db.Conn() if err != nil { return err } defer conn.Close() for _, team := range teams { if len(team.Users) < 2 { msg := fmt.Sprintf(`This user is the last member of the team "%s", so it cannot be removed. Please remove the team, then remove the user.`, team.Name) return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } err = team.RemoveUser(u) if err != nil { return err } // this can be done without the loop err = conn.Teams().Update(bson.M{"_id": team.Name}, team) if err != nil { return err } } rec.Log(u.Email, "remove-user") if err := manager.RemoveUser(u.Email); err != nil { log.Errorf("Failed to remove user from repository manager: %s", err) } return app.AuthScheme.Remove(u) }
func createApp(w http.ResponseWriter, r *http.Request, t auth.Token) error { var a app.App defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } if err = json.Unmarshal(body, &a); err != nil { return err } u, err := t.User() if err != nil { return err } rec.Log(u.Email, "create-app", "app="+a.Name, "platform="+a.Platform, "plan="+a.Plan.Name) err = app.CreateApp(&a, u) if err != nil { log.Errorf("Got error while creating app: %s", err) if e, ok := err.(*errors.ValidationError); ok { return &errors.HTTP{Code: http.StatusBadRequest, Message: e.Message} } if _, ok := err.(app.NoTeamsError); ok { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "In order to create an app, you should be member of at least one team", } } if e, ok := err.(*app.AppCreationError); ok { if e.Err == app.ErrAppAlreadyExists { return &errors.HTTP{Code: http.StatusConflict, Message: e.Error()} } if _, ok := e.Err.(*quota.QuotaExceededError); ok { return &errors.HTTP{ Code: http.StatusForbidden, Message: "Quota exceeded", } } } if e, ok := err.(app.InvalidPlatformError); ok { return &errors.HTTP{Code: http.StatusNotFound, Message: e.Error()} } return err } repo, _ := repository.Manager().GetRepository(a.Name) msg := map[string]string{ "status": "success", "repository_url": repo.ReadWriteURL, "ip": a.Ip, } jsonMsg, err := json.Marshal(msg) if err != nil { return err } fmt.Fprintf(w, "%s", jsonMsg) return nil }
func (s *S) TestAddDuplicatedKey(c *check.C) { u := &User{Email: "*****@*****.**"} err := u.Create() c.Assert(err, check.IsNil) defer u.Delete() key := repository.Key{Name: "my-key", Body: "other-key"} repository.Manager().(repository.KeyRepositoryManager).AddKey(u.Email, key) err = u.AddKey(key) c.Assert(err, check.Equals, repository.ErrKeyAlreadyExists) }
func (s *S) TestListKeysRepositoryManagerFailure(c *check.C) { u := User{Email: "*****@*****.**", Password: "******"} err := u.Create() c.Assert(err, check.IsNil) defer u.Delete() err = repository.Manager().RemoveUser(u.Email) c.Assert(err, check.IsNil) keys, err := u.ListKeys() c.Assert(keys, check.HasLen, 0) c.Assert(err.Error(), check.Equals, "user not found") }
func (s *S) TestCreateRepositoryForwardAppPointer(c *check.C) { app := App{Name: "someapp", Teams: []string{s.team.Name}} ctx := action.FWContext{Params: []interface{}{&app}} result, err := createRepository.Forward(ctx) a, ok := result.(*App) c.Assert(ok, check.Equals, true) c.Assert(a.Name, check.Equals, app.Name) c.Assert(err, check.IsNil) _, err = repository.Manager().GetRepository(app.Name) c.Assert(err, check.IsNil) }
func (s *DeploySuite) SetUpTest(c *check.C) { repositorytest.Reset() err := dbtest.ClearAllCollections(s.conn.Apps().Database) c.Assert(err, check.IsNil) s.createUserAndTeam(c) s.conn.Platforms().Insert(app.Platform{Name: "python"}) err = provision.AddPool("pool1", false) c.Assert(err, check.IsNil) user, err := s.token.User() c.Assert(err, check.IsNil) repository.Manager().CreateUser(user.Email) }
func (s *S) TestAddKeyAddsAKeyToTheUser(c *check.C) { u := &User{Email: "*****@*****.**"} err := u.Create() c.Assert(err, check.IsNil) defer u.Delete() key := repository.Key{Name: "some-key", Body: "my-key"} err = u.AddKey(key, false) c.Assert(err, check.IsNil) keys, err := repository.Manager().(repository.KeyRepositoryManager).ListKeys(u.Email) c.Assert(err, check.IsNil) c.Assert(keys, check.DeepEquals, []repository.Key{key}) }
func (u *User) AddKey(key repository.Key, force bool) error { if mngr, ok := repository.Manager().(repository.KeyRepositoryManager); ok { if key.Name == "" { return ErrInvalidKey } err := mngr.AddKey(u.Email, key) if err == repository.ErrKeyAlreadyExists && force { return mngr.UpdateKey(u.Email, key) } return err } return ErrKeyDisabled }
// 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 }
// Revoke removes the access from a team. It returns an error if the team do // not have access to the app. func (app *App) Revoke(team *auth.Team) error { if len(app.Teams) == 1 { return ErrCannotOrphanApp } index, found := app.findTeam(team) if !found { return ErrNoAccess } last := len(app.Teams) - 1 app.Teams[index] = app.Teams[last] app.Teams = app.Teams[:last] conn, err := db.Conn() if err != nil { return err } defer conn.Close() err = conn.Apps().Update(bson.M{"name": app.Name}, bson.M{"$pull": bson.M{"teams": team.Name}}) if err != nil { return err } users, err := auth.ListUsersWithPermissions(permission.Permission{ Scheme: permission.PermAppDeploy, Context: permission.Context(permission.CtxTeam, team.Name), }) if err != nil { conn.Apps().Update(bson.M{"name": app.Name}, bson.M{"$addToSet": bson.M{"teams": team.Name}}) return err } for _, user := range users { perms, err := user.Permissions() if err != nil { conn.Apps().Update(bson.M{"name": app.Name}, bson.M{"$addToSet": bson.M{"teams": team.Name}}) return err } canDeploy := permission.CheckFromPermList(perms, permission.PermAppDeploy, append(permission.Contexts(permission.CtxTeam, app.Teams), permission.Context(permission.CtxApp, app.Name), permission.Context(permission.CtxPool, app.Pool), )..., ) if canDeploy { continue } err = repository.Manager().RevokeAccess(app.Name, user.Email) if err != nil { conn.Apps().Update(bson.M{"name": app.Name}, bson.M{"$addToSet": bson.M{"teams": team.Name}}) return err } } return nil }
func (u *User) ListKeys() (map[string]string, error) { if mngr, ok := repository.Manager().(repository.KeyRepositoryManager); ok { keys, err := mngr.ListKeys(u.Email) if err != nil { return nil, err } keysMap := make(map[string]string, len(keys)) for _, key := range keys { keysMap[key.Name] = key.Body } return keysMap, nil } return nil, ErrKeyDisabled }
func addUserToTeamInRepository(user *auth.User, t *auth.Team) error { alwdApps, err := t.AllowedApps() if err != nil { return fmt.Errorf("Failed to obtain allowed apps to grant: %s", err) } manager := repository.Manager() for _, app := range alwdApps { err = manager.GrantAccess(app, user.Email) if err != nil { return err } } return nil }
func (u *User) Delete() error { conn, err := db.Conn() if err != nil { return err } defer conn.Close() err = conn.Users().Remove(bson.M{"email": u.Email}) if err != nil { log.Errorf("failed to remove user %q from the database: %s", u.Email, err) } err = repository.Manager().RemoveUser(u.Email) if err != nil { log.Errorf("failed to remove user %q from the repository manager: %s", u.Email, err) } return nil }