Beispiel #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
}
Beispiel #2
0
func (s *Stacker) BuildBaseMachine(ctx context.Context, m *models.Machine) (*BaseMachine, error) {
	req, ok := request.FromContext(ctx)
	if !ok {
		return nil, errors.New("request context is not available")
	}

	bm := &BaseMachine{
		Machine: m,
		Session: &session.Session{
			DB:       s.DB,
			Kite:     s.Kite,
			Userdata: s.Userdata,
			Log:      s.Log.New(m.ObjectId.Hex()),
		},
		Credential: s.Provider.newCredential(),
		Bootstrap:  s.Provider.newBootstrap(),
		Metadata:   s.Provider.newMetadata(nil),
		Req:        req,
		Provider:   s.Provider.Name,
		Debug:      s.Debug,
	}

	// NOTE(rjeczalik): "internal" method is used by (*Queue).CheckAWS
	if req.Method != "internal" {
		// get user model which contains user ssh keys or the list of users that
		// are allowed to use this machine
		if len(m.Users) == 0 {
			return nil, errors.New("permitted users list is empty")
		}

		// get the user from the permitted list. If the list contains more than one
		// allowed person, fetch the one that is the same as requesterName, if
		// not pick up the first one.
		var err error
		bm.User, err = modelhelper.GetPermittedUser(req.Username, bm.Users)
		if err != nil {
			return nil, err
		}

		if err := s.ValidateUser(bm.User, bm.Users, req); err != nil {
			return nil, err
		}
	}

	if traceID, ok := stack.TraceFromContext(ctx); ok {
		bm.Log = logging.NewCustom("kloud-"+s.Provider.Name, true).New(m.ObjectId.Hex()).New(traceID)
		bm.Debug = true
		bm.TraceID = traceID
	}

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

	s.Log.Debug("BaseMachine: %+v", bm)

	return bm, nil
}
Beispiel #3
0
func (k *Kloud) traceRequest(ctx context.Context, tags []string) context.Context {
	if r, ok := request.FromContext(ctx); ok {
		tags = append(tags, "action:"+r.Method)
	}

	if traceID, ok := ctx.Value(TraceKey).(string); ok {
		tags = append(tags, "trace:"+traceID)
	}

	return context.WithValue(ctx, RequestTraceKey, &RequestTrace{
		start:    time.Now(),
		tags:     tags,
		histFunc: k.Metrics.Histogram,
		log:      k.Log,
	})
}
Beispiel #4
0
// BuildMachines fetches machines that belongs to existing b.Stack.
//
// It validates whether user is allowed to perform apply operation.
// When nil error is returned, the  b.Machines field is non-nil.
func (b *Builder) BuildMachines(ctx context.Context) error {
	ids := b.Stack.Machines

	sess, ok := session.FromContext(ctx)
	if !ok {
		return errors.New("session context is not passed")
	}

	req, ok := request.FromContext(ctx)
	if !ok {
		return errors.New("request context is not passed")
	}

	mongodbIds := make([]bson.ObjectId, len(ids))
	for i, id := range ids {
		mongodbIds[i] = bson.ObjectIdHex(id)
	}

	b.Log.Debug("Building machines with IDs: %+v", ids)

	machines := make([]*models.Machine, 0)
	if err := sess.DB.Run("jMachines", func(c *mgo.Collection) error {
		return c.Find(bson.M{"_id": bson.M{"$in": mongodbIds}}).All(&machines)
	}); err != nil {
		return err
	}

	b.Log.Debug("Fetched machines: %+v", machines)

	validUsers := make(map[string]models.MachineUser, 0)
	validMachines := make(map[string]*models.Machine, 0)

	for _, machine := range machines {
		// machines with empty users are supposed to allowed by default
		// (gokmen)
		if len(machine.Users) == 0 {
			validMachines[machine.ObjectId.Hex()] = machine
			continue
		}

		// for others we need to be sure they are valid
		// TODO(arslan): add custom type with custom methods for type
		// []*Machineuser
		for _, user := range machine.Users {
			// we only going to select users that are allowed:
			//
			//   - team member that owns vm (sudo + owner)
			//   - team admin that owns all vms (owner + !permanent)
			//
			// A shared user is (owner + permanent).
			if (user.Sudo || !user.Permanent) && user.Owner {
				validUsers[user.Id.Hex()] = user
			}
		}
	}

	allowedIds := make([]bson.ObjectId, 0)
	for _, user := range validUsers {
		allowedIds = append(allowedIds, user.Id)
	}

	b.Log.Debug("Building users with allowed IDs: %+v", allowedIds)

	users, err := modelhelper.GetUsersById(allowedIds...)
	if err != nil {
		return models.ResError(err, "jUser")
	}

	// find whether requested user is among allowed ones
	var reqUser *models.User
	for _, u := range users {
		if u.Name == req.Username {
			reqUser = u
			break
		}
	}

	b.Log.Debug("Found requester: %v (requester username: %s)", reqUser, req.Username)

	if reqUser != nil {
		// now check if the requested user is inside the allowed users list
		for _, m := range machines {
			for _, user := range m.Users {
				if user.Id.Hex() == reqUser.ObjectId.Hex() {
					validMachines[m.ObjectId.Hex()] = m
					break
				}
			}
		}
	}

	if len(validMachines) == 0 {
		return fmt.Errorf("no valid machines found for the user: %s", req.Username)
	}

	b.Machines = make(map[string]*models.Machine, len(validMachines))

	for _, m := range validMachines {
		label := m.Label
		if s, ok := m.Meta["assignedLabel"].(string); ok {
			label = s
		}

		b.Machines[label] = m
	}

	b.Log.Debug("Machines built: %+v", b.Machines)

	return nil
}