Example #1
0
// BaseStack builds new base stack for the given context value.
func (s *Stacker) BaseStack(ctx context.Context) (*BaseStack, error) {
	bs := &BaseStack{
		Planner: &Planner{
			Provider:     s.Provider.Name,
			ResourceType: s.Provider.resourceName(),
			Log:          s.Log,
		},
		Provider:  s.Provider,
		KlientIDs: make(stack.KiteMap),
		Klients:   make(map[string]*DialState),
		TunnelURL: s.TunnelURL,
		Keys:      s.SSHKey,
	}

	var ok bool
	if bs.Req, ok = request.FromContext(ctx); !ok {
		return nil, errors.New("request not available in context")
	}

	req, ok := stack.TeamRequestFromContext(ctx)
	if !ok {
		return nil, errors.New("team request not available in context")
	}

	if bs.Session, ok = session.FromContext(ctx); !ok {
		return nil, errors.New("session not available in context")
	}

	bs.Log = s.Log.New(req.GroupName)

	if traceID, ok := stack.TraceFromContext(ctx); ok {
		bs.Log = logging.NewCustom("kloud-"+req.Provider, true).New(traceID)
		bs.TraceID = traceID
	}

	if keys, ok := publickeys.FromContext(ctx); ok {
		bs.Keys = keys
	}

	if ev, ok := eventer.FromContext(ctx); ok {
		bs.Eventer = ev
	}

	builderOpts := &BuilderOptions{
		Log:       s.Log.New("stackplan"),
		CredStore: s.CredStore,
	}

	bs.Builder = NewBuilder(builderOpts)

	if err := bs.Builder.BuildTeam(req.GroupName); err != nil {
		return nil, err
	}

	if !bs.Builder.Team.IsSubActive() {
		return nil, stack.NewError(stack.ErrTeamSubIsNotActive)
	}

	return bs, nil
}
Example #2
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 #3
0
func (s *Stacker) Lock(id string) error {
	err := s.DB.Run("jMachines", func(c *mgo.Collection) error {
		// we use findAndModify() to get a unique lock from the DB. That means only
		// one instance should be responsible for this action. We will update the
		// assignee if none else is doing stuff with it.
		change := mgo.Change{
			Update: bson.M{
				"$set": bson.M{
					"assignee.inProgress": true,
					"assignee.assignedAt": time.Now().UTC(),
				},
			},
			ReturnNew: true,
		}

		// if Find() is successful the Update() above will be applied (which
		// set's us as assignee by marking the inProgress to true). If not, it
		// means someone else is working on this document and we should return
		// with an error. The whole process is atomic and a single transaction.
		_, err := c.Find(
			bson.M{
				"_id": bson.ObjectIdHex(id),
				"assignee.inProgress": bson.M{"$ne": true},
			},
		).Apply(change, &models.Machine{}) // machine is used just used for prevent nil unmarshalling
		return err
	})

	// query didn't matched, means it's assigned to some other Kloud
	// instances and an ongoing event is in process.
	if err == mgo.ErrNotFound {
		return stack.ErrLockAcquired
	}

	// some other error, this shouldn't be happed
	if err != nil {
		s.Log.Error("Storage get error: %s", err)

		return stack.NewError(stack.ErrBadState)
	}

	return nil
}
Example #4
0
func (s *Stacker) ValidateUser(user *models.User, users []models.MachineUser, r *kite.Request) error {
	// give access to kloudctl immediately
	if stack.IsKloudctlAuth(r, s.KloudSecretKey) {
		return nil
	}

	if r.Username != user.Name {
		return errors.New("username is not permitted to make any action")
	}

	// check for user permissions
	if err := checkUser(user.ObjectId, users); err != nil {
		return err
	}

	if user.Status != "confirmed" {
		return stack.NewError(stack.ErrUserNotConfirmed)
	}

	return nil
}