// 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 }
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 (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 }
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 }