Example #1
0
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)
}
Example #2
0
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))
	}
}
Example #3
0
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)
}
Example #4
0
// 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())
	}
}