func deleteWorkspaces(res interface{}) error { ws := res.(*models.Workspace) _, err := helper.GetMachineByUid(ws.MachineUID) if err == mgo.ErrNotFound { fmt.Printf("deleting WS with UID (corresponding machine does not exist) %q\n", ws.ObjectId.Hex()) if !*flagDry { return helper.RemoveWorkspace(ws.ObjectId) } } if !getAccountByID(ws.OriginId.Hex()) { fmt.Printf("deleting WS with owner (corresponding acc does not exist) %q\n", ws.ObjectId.Hex()) if !*flagDry { return helper.RemoveWorkspace(ws.ObjectId) } } return nil }
func TestUnshareMachine(t *testing.T) { db := modeltesthelper.NewMongoDB(t) defer db.Close() m := createMachine(t) defer modelhelper.DeleteMachine(m.ObjectId) if err := modelhelper.UnshareMachineByUid(m.Uid); err != nil { t.Error(err) } m2, err := modelhelper.GetMachineByUid(m.Uid) if err != nil { t.Error(err.Error()) } if len(m2.Users) != 1 { t.Errorf("user count should be 1, got: %d", len(m2.Users)) } if !(m2.Users[0].Sudo && m2.Users[0].Owner) { t.Errorf("only owner should have sudo and owner priv.") } }
func (c *Controller) findToBeRemovedUsers(ping *models.Ping) ([]bson.ObjectId, error) { ws, err := modelhelper.GetWorkspaceByChannelId( strconv.FormatInt(ping.ChannelId, 10), ) if err != nil { return nil, filterErr(err) } machine, err := modelhelper.GetMachineByUid(ws.MachineUID) if err != nil { return nil, filterErr(err) } ownerMachineUser := machine.Owner() if ownerMachineUser == nil { c.log.Critical("owner couldnt found %+v", ping) return nil, nil // if we cant find the owner, we cant process the users } ownerAccount, err := modelhelper.GetAccountByUserId(ownerMachineUser.Id) if err != nil { return nil, filterErr(err) } // get workspaces of the owner ownersWorkspaces, err := modelhelper.GetWorkspaces(ownerAccount.Id) if err != nil { return nil, filterErr(err) } users := partitionUsers(ownerAccount, ownersWorkspaces, ws) var toBeRemovedUsers []bson.ObjectId for accountID, count := range users { // if we count the user more than once, that means user is in another // workspace too if count > 1 { continue } u, err := modelhelper.GetUserByAccountId(accountID) if err != nil { return nil, err } toBeRemovedUsers = append(toBeRemovedUsers, u.ObjectId) } var filteredUsers []bson.ObjectId permanentUsers := make(map[string]struct{}) for _, user := range machine.Users { if user.Permanent { permanentUsers[user.Id.Hex()] = struct{}{} } } for _, toBeRemovedUser := range toBeRemovedUsers { if _, ok := permanentUsers[toBeRemovedUser.Hex()]; !ok { filteredUsers = append(filteredUsers, toBeRemovedUser) } } return filteredUsers, nil }
func TestCollaborationOperationsUnshareVM(t *testing.T) { r := runner.New("collaboration-UnshareVM-tests") err := r.Init() if err != nil { panic(err) } defer r.Close() appConfig := config.MustRead(r.Conf.Path) modelhelper.Initialize(appConfig.Mongo) defer modelhelper.Close() // init with defaults mongoCache := cache.NewMongoCacheWithTTL(modelhelper.Mongo.Session) defer mongoCache.StopGC() handler := New(r.Log, mongoCache, appConfig, r.Kite) Convey("while testing UnshareVM", t, func() { Convey("should be able to create the channel and workspace first", func() { Convey("should be able to UnshareVM", func() { creator, err := socialapimodels.CreateAccountInBothDbs() // init account So(err, ShouldBeNil) participant1, err := socialapimodels.CreateAccountInBothDbs() So(err, ShouldBeNil) participant2, err := socialapimodels.CreateAccountInBothDbs() So(err, ShouldBeNil) m1, m1ws1 := prepareSingleWorkspace(creator, participant1, participant2) channelId, err := strconv.ParseInt(m1ws1.ChannelId, 10, 64) So(err, ShouldBeNil) req1 := &models.Ping{ AccountId: creator.Id, FileId: fmt.Sprintf("%d", rand.Int63()), ChannelId: channelId, } toBeRemovedUsers, err := handler.findToBeRemovedUsers(req1) So(err, ShouldBeNil) So(toBeRemovedUsers, ShouldNotBeNil) err = handler.UnshareVM(req1, toBeRemovedUsers) So(err, ShouldBeNil) err = handler.EndPrivateMessage(req1) So(err, ShouldBeNil) Convey("remove users should not be in the machine", func() { mm1, err := modelhelper.GetMachineByUid(m1.Uid) So(err, ShouldBeNil) So(mm1, ShouldNotBeNil) So(len(mm1.Users), ShouldEqual, 1) ownerUser, err := modelhelper.GetUserByAccountId(creator.OldId) So(err, ShouldBeNil) So(mm1.Users[0].Id.Hex(), ShouldEqual, ownerUser.ObjectId.Hex()) }) }) Convey("if participant and owner shares multiple workspaces", func() { creator, err := socialapimodels.CreateAccountInBothDbs() // init account So(err, ShouldBeNil) participant1, err := socialapimodels.CreateAccountInBothDbs() So(err, ShouldBeNil) participant2, err := socialapimodels.CreateAccountInBothDbs() So(err, ShouldBeNil) participant3, err := socialapimodels.CreateAccountInBothDbs() So(err, ShouldBeNil) _, _, m2, m2ws1, m2ws2 := prepareWorkspace(creator, participant1, participant2, participant3) Convey("remove from first workspace", func() { channelId, err := strconv.ParseInt(m2ws1.ChannelId, 10, 64) So(err, ShouldBeNil) req := &models.Ping{ AccountId: creator.Id, FileId: fmt.Sprintf("%d", rand.Int63()), ChannelId: channelId, } toBeRemovedUsers, err := handler.findToBeRemovedUsers(req) So(err, ShouldBeNil) So(toBeRemovedUsers, ShouldNotBeNil) err = handler.UnshareVM(req, toBeRemovedUsers) So(err, ShouldBeNil) err = handler.EndPrivateMessage(req) So(err, ShouldBeNil) Convey("participants should still be in the second machine", func() { mm2, err := modelhelper.GetMachineByUid(m2.Uid) So(err, ShouldBeNil) So(mm2, ShouldNotBeNil) So(len(mm2.Users), ShouldEqual, 3) // participant1 is not in the second WS, so it should be removed from the machine ownerUser, err := modelhelper.GetUserByAccountId(creator.OldId) So(err, ShouldBeNil) So(mm2.Users[0].Id.Hex(), ShouldEqual, ownerUser.ObjectId.Hex()) participant2User, err := modelhelper.GetUserByAccountId(participant2.OldId) So(err, ShouldBeNil) So(mm2.Users[1].Id.Hex(), ShouldEqual, participant2User.ObjectId.Hex()) participant3User, err := modelhelper.GetUserByAccountId(participant3.OldId) So(err, ShouldBeNil) So(mm2.Users[2].Id.Hex(), ShouldEqual, participant3User.ObjectId.Hex()) Convey("after removing from second WS", func() { // remove from second WS too channelId, err := strconv.ParseInt(m2ws2.ChannelId, 10, 64) So(err, ShouldBeNil) req := &models.Ping{ AccountId: creator.Id, FileId: fmt.Sprintf("%d", rand.Int63()), ChannelId: channelId, } toBeRemovedUsers, err := handler.findToBeRemovedUsers(req) So(err, ShouldBeNil) So(toBeRemovedUsers, ShouldNotBeNil) err = handler.UnshareVM(req, toBeRemovedUsers) So(err, ShouldBeNil) err = handler.EndPrivateMessage(req) So(err, ShouldBeNil) Convey("owner and permanent should still stay", func() { mm2, err := modelhelper.GetMachineByUid(m2.Uid) So(err, ShouldBeNil) So(mm2, ShouldNotBeNil) So(len(mm2.Users), ShouldEqual, 2) ownerUser, err := modelhelper.GetUserByAccountId(creator.OldId) So(err, ShouldBeNil) So(mm2.Users[0].Id.Hex(), ShouldEqual, ownerUser.ObjectId.Hex()) participant1User, err := modelhelper.GetUserByAccountId(participant3.OldId) So(err, ShouldBeNil) So(mm2.Users[1].Id.Hex(), ShouldEqual, participant1User.ObjectId.Hex()) }) }) }) }) }) }) }) }
// RemoveUsersFromMachine removes the collaboraters from the host machine func (c *Controller) RemoveUsersFromMachine(ping *models.Ping, toBeRemovedUsers []bson.ObjectId) error { // if channel id is nil, there is nothing to do if ping.ChannelId == 0 { return nil } ws, err := modelhelper.GetWorkspaceByChannelId(strconv.FormatInt(ping.ChannelId, 10)) if err != nil { return filterErr(err) } m, err := modelhelper.GetMachineByUid(ws.MachineUID) if err != nil { return filterErr(err) } // Get the klient. klientRef, err := klient.ConnectTimeout(c.kite, m.QueryString, time.Second*10) if err != nil { if err == klient.ErrDialingFailed || err == kite.ErrNoKitesAvailable { c.log.Error( "[%s] Klient is not registered to Kontrol. Err: %s", m.QueryString, err, ) return nil // if the machine is not open, we cant do anything } return err } defer klientRef.Close() type args struct { Username string // we are not gonna use this propery here, just for reference // Permanent bool } var iterErr error for _, toBeDeletedUser := range toBeRemovedUsers { // fetch user for its username u, err := modelhelper.GetUserById(toBeDeletedUser.Hex()) if err != nil { c.log.Error("couldnt get user", err.Error()) // if we cant find the regarding user, do not do anything if err == mgo.ErrNotFound { continue } iterErr = err continue // do not stop iterating, unshare from others } param := args{ Username: u.Name, } _, err = klientRef.Client.Tell("klient.unshare", param) if err != nil { c.log.Error("couldnt unshare %+v", err.Error()) // those are so error prone, force klient side not to change the API // or make them exported to some other package? if strings.Contains(err.Error(), "user is permanent") { continue } if strings.Contains(err.Error(), "user is not in the shared list") { continue } if strings.Contains(err.Error(), "User not found") { continue } iterErr = err continue // do not stop iterating, unshare from others } } res, err := klientRef.Client.Tell("klient.shared", nil) if err == nil { c.log.Info("other users in the machine: %+v", res.MustString()) } // iterErr will be nil if we dont encounter to any error in iter return iterErr }