func (s *Stacker) BaseMachine(ctx context.Context, id string) (*BaseMachine, error) { if !bson.IsObjectIdHex(id) { return nil, fmt.Errorf("invalid machine id: %q", id) } m, err := modelhelper.GetMachine(id) if err == mgo.ErrNotFound { return nil, stack.NewError(stack.ErrMachineNotFound) } if err != nil { return nil, fmt.Errorf("unable to get machine: %s", err) } return s.BuildBaseMachine(ctx, m) }
func TestAddAndRemoveFromStack(t *testing.T) { db := modeltesthelper.NewMongoDB(t) defer db.Close() user, group, machine, account, clean := testFixture(t) defer clean() sd := &modelhelper.StackDetails{ UserID: user.ObjectId, GroupID: group.Id, MachineID: machine.ObjectId, UserName: user.Name, GroupSlug: group.Slug, AccountID: account.Id, BaseID: bson.ObjectIdHex("53fe557af052f8e9435a04fa"), } // Add for a first time. err := modelhelper.AddToStack(sd) if err != nil { t.Fatalf("error adding machine %q to stack: %s", machine.ObjectId.Hex(), err) } s, err := modelhelper.GetComputeStackByGroup(group.Slug, account.Id) if err != nil { t.Fatalf("error getting stack for koding, %q: %s", account.Id.Hex(), err) } if len(s.Machines) != 1 { t.Fatalf("want 1 machine, got %d", len(s.Machines)) } if s.Machines[0] != machine.ObjectId { t.Fatalf("want machine %q to be added to stack, got %q instead", machine.ObjectId.Hex(), s.Machines[0].Hex()) } m, err := modelhelper.GetMachine(machine.ObjectId.Hex()) if err != nil { t.Fatalf("error getting machine %q: %s", machine.ObjectId.Hex(), err) } if len(m.Groups) != 1 { t.Fatalf("want 1 group, got %d", len(m.Groups)) } if m.Groups[0].Id != group.Id { t.Fatalf("want group %q, got %q", group.Id.Hex(), m.Groups[0].Id.Hex()) } // Adding for a second time must be idempotent. err = modelhelper.AddToStack(sd) if err != nil { t.Fatalf("error adding machine %q to stack: %s", machine.ObjectId.Hex(), err) } s2, err := modelhelper.GetComputeStackByGroup(group.Slug, account.Id) if err != nil { t.Fatalf("error getting stack for koding, %q: %s", account.Id.Hex(), err) } if s.Id != s2.Id { t.Errorf("want jComputeStack.ObjetId %q; got %q", s.Id.Hex(), s2.Id.Hex()) } if len(s.Machines) != 1 { t.Fatalf("want 1 machine, got %d", len(s.Machines)) } if s.Machines[0] != machine.ObjectId { t.Fatalf("want machine %q to be added to stack, got %q instead", machine.ObjectId.Hex(), s.Machines[0].Hex()) } m, err = modelhelper.GetMachine(machine.ObjectId.Hex()) if err != nil { t.Fatalf("error getting machine %q: %s", machine.ObjectId.Hex(), err) } if len(m.Groups) != 1 { t.Fatalf("want 1 group, got %d", len(m.Groups)) } if m.Groups[0].Id != group.Id { t.Fatalf("want group %q, got %q", group.Id.Hex(), m.Groups[0].Id.Hex()) } // Remove from stack. err = modelhelper.RemoveFromStack(sd) if err != nil { t.Fatalf("error removing %q from stack: %s", machine.ObjectId.Hex(), err) } s3, err := modelhelper.GetComputeStackByGroup(group.Slug, account.Id) if err != nil { t.Fatalf("error getting stack for koding, %q: %s", account.Id.Hex(), err) } if len(s3.Machines) != 0 { t.Fatalf("want 0 machine, got %d", len(s.Machines)) } m, err = modelhelper.GetMachine(machine.ObjectId.Hex()) if err != nil { t.Fatalf("error getting machine %q: %s", machine.ObjectId.Hex(), err) } if len(m.Groups) != 0 { t.Fatalf("want 0 group, got %d", len(m.Groups)) } }
func (k *Kloud) authorizedKlient(r *kite.Request) (*klient.Klient, error) { if r.Args == nil { return nil, NewError(ErrNoArguments) } var args *AdminRequest if err := r.Args.One().Unmarshal(&args); err != nil { return nil, err } if args.MachineId == "" { return nil, errors.New("machineId is not passed") } if args.GroupName == "" { return nil, errors.New("groupName is not passed") } k.Log.Debug("Got arguments %+v for method: %s", args, r.Method) isAdmin, err := modelhelper.IsAdmin(r.Username, args.GroupName) if err != nil { return nil, err } if !isAdmin { return nil, fmt.Errorf("User '%s' is not an admin of group '%s'", r.Username, args.GroupName) } k.Log.Debug("User '%s' is an admin. Checking for machine permission", r.Username) machine, err := modelhelper.GetMachine(args.MachineId) if err != nil { return nil, fmt.Errorf("getMachine(%s) err: %s", args.MachineId, err) } g, err := modelhelper.GetGroup(args.GroupName) if err != nil { return nil, err } isGroupMember := false for _, group := range machine.Groups { if group.Id.Hex() == g.Id.Hex() { isGroupMember = true } } if !isGroupMember { return nil, fmt.Errorf("'%s' machine does not belong to '%s' group", args.MachineId, args.GroupName) } k.Log.Debug("Incoming user is authorized, setting up DB and Klient connection") // Now we are ready to go. ctx := request.NewContext(context.Background(), r) ctx = k.ContextCreator(ctx) sess, ok := session.FromContext(ctx) if !ok { return nil, errors.New("internal server error (err: session context is not available)") } k.Log.Debug("Calling Klient method: %s", r.Method) return klient.NewWithTimeout(sess.Kite, machine.QueryString, time.Second*10) }
// BuildMachine ensures the user and group of the spec are // inserted into db. func (spec *MachineSpec) BuildMachine(createUser bool) error { // If MachineID is not nil, ensure it exists and reuse it if it does. if spec.HasMachine() { m, err := modelhelper.GetMachine(spec.Machine.ObjectId.Hex()) if err != nil { return err } spec.Machine = *m return nil } // If no existing group is provided, create or use 'hackathon' one, // which will make VMs invisible to users until they're assigned // to proper group before the hackathon. if !spec.HasGroup() { group, err := modelhelper.GetGroup("koding") if err != nil { return err } spec.Machine.Groups = []models.MachineGroup{{Id: group.Id}} } // If no existing user is provided, create one. if !spec.HasUser() { // Try to lookup user by username first. user, err := modelhelper.GetUser(spec.Username()) if err != nil { if !createUser { return fmt.Errorf("user %q does not exist", spec.Username()) } spec.User.ObjectId = bson.NewObjectId() if spec.User.RegisteredAt.IsZero() { spec.User.RegisteredAt = time.Now() } if spec.User.LastLoginDate.IsZero() { spec.User.LastLoginDate = spec.User.RegisteredAt } if err = modelhelper.CreateUser(&spec.User); err != nil { return err } user = &spec.User } spec.User.ObjectId = user.ObjectId spec.User.Name = spec.Username() } // Ensure the user is assigned to the machine. if len(spec.Machine.Users) == 0 { spec.Machine.Users = []models.MachineUser{{ Sudo: true, Owner: true, }} } if spec.Machine.Users[0].Id == "" { spec.Machine.Users[0].Id = spec.User.ObjectId } if spec.Machine.Users[0].Username == "" { spec.Machine.Users[0].Username = spec.User.Name } // Lookup username for existing user. if spec.Machine.Users[0].Username == "" { user, err := modelhelper.GetUserById(spec.Machine.Users[0].Id.Hex()) if err != nil { return err } spec.Machine.Users[0].Username = user.Name } // Lookup group and init Uid. group, err := modelhelper.GetGroupById(spec.Machine.Groups[0].Id.Hex()) if err != nil { return err } spec.Machine.Uid = fmt.Sprintf("u%c%c%c", spec.Machine.Users[0].Username[0], group.Slug[0], spec.Machine.Provider[0], ) m, err := modelhelper.GetMachineBySlug(spec.Machine.Users[0].Id, spec.Machine.Slug) if err == mgo.ErrNotFound { return nil } if err != nil { return err } switch m.State() { case machinestate.Building, machinestate.Starting: return ErrAlreadyBuilding case machinestate.Running: return ErrAlreadyRunning case machinestate.NotInitialized: spec.Machine.ObjectId = m.ObjectId return ErrRebuild default: return fmt.Errorf("machine state is %q; needs to be deleted and build "+ "again (jMachine.ObjectId = %q)", m.State(), m.ObjectId.Hex()) } }