// 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) 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 }
func (a *Amazon) Start(ctx context.Context) (*ec2.Instance, error) { if a.Id() == "" { return nil, ErrInstanceEmptyID } // if we have eventer, use it ev, withPush := eventer.FromContext(ctx) if withPush { ev.Push(&eventer.Event{ Message: "Starting machine", Status: machinestate.Starting, Percentage: 25, }) } a.Log.Debug("amazon start eventer: %t", withPush) _, err := a.Client.StartInstance(a.Id()) if err != nil { return nil, err } var instance *ec2.Instance stateFunc := func(currentPercentage int) (machinestate.State, error) { if withPush { ev.Push(&eventer.Event{ Message: "Starting machine", Status: machinestate.Starting, Percentage: currentPercentage, }) } instance, err = a.Instance() if err != nil { return 0, err } return StatusToState(aws.StringValue(instance.State.Name)), nil } ws := waitstate.WaitState{ StateFunc: stateFunc, DesiredState: machinestate.Running, Start: 45, Finish: 60, } if err := ws.Wait(); err != nil { return nil, err } return instance, nil }
// Start stops Google compute instance. func (m *Machine) Stop(ctx context.Context) (interface{}, error) { ev, withPush := eventer.FromContext(ctx) if withPush { ev.Push(&eventer.Event{ Message: "Stopping machine", Status: machinestate.Stopping, Percentage: 25, }) } project, zone, name := m.Location() _, err := m.InstancesService.Stop(project, zone, name).Do() // Ignore http.StatusNotModified status. if err != nil && googleapi.IsNotModified(err) { if withPush { ev.Push(&eventer.Event{ Message: "Machine stopped", Status: machinestate.Stopped, Percentage: 60, }) } return nil, nil } if err != nil { return nil, err } stateFunc := func(currentPercentage int) (machinestate.State, error) { if withPush { ev.Push(&eventer.Event{ Message: "Stopping machine", Status: machinestate.Stopping, Percentage: currentPercentage, }) } state, _, err := m.Info(nil) if err != nil { return machinestate.Unknown, err } return state, err } ws := waitstate.WaitState{ StateFunc: stateFunc, DesiredState: machinestate.Stopped, Start: 45, Finish: 60, } return nil, ws.Wait() }
func (a *Amazon) CheckBuild(ctx context.Context, instanceId string, start, finish int) (*ec2.Instance, error) { ev, withPush := eventer.FromContext(ctx) if withPush { ev.Push(&eventer.Event{ Message: "Building machine", Status: machinestate.Building, Percentage: start, }) } var instance *ec2.Instance var err error stateFunc := func(currentPercentage int) (machinestate.State, error) { if withPush { ev.Push(&eventer.Event{ Message: "Building machine", Status: machinestate.Building, Percentage: currentPercentage, }) } instance, err = a.Client.InstanceByID(instanceId) if err != nil { return 0, err } currentStatus := StatusToState(aws.StringValue(instance.State.Name)) // happens when there is no volume limit. The instance will be not // build and it returns terminated from AWS if currentStatus.In(machinestate.Terminated, machinestate.Terminating) { return 0, ErrInstanceTerminated } return currentStatus, nil } ws := waitstate.WaitState{ Timeout: 15 * time.Minute, StateFunc: stateFunc, DesiredState: machinestate.Running, Start: start, Finish: finish, } if err := ws.Wait(); err != nil { return nil, err } return instance, nil }
// Stop the remote Softlayer instance. func (m *Machine) Stop(ctx context.Context) (interface{}, error) { ev, withPush := eventer.FromContext(ctx) if withPush { ev.Push(&eventer.Event{ Message: "Stopping machine", Status: machinestate.Stopping, Percentage: 25, }) } metadata := m.BaseMachine.Metadata.(*Metadata) service, err := m.Client.GetSoftLayer_Virtual_Guest_Service() if err != nil { return nil, err } _, err = service.PowerOffSoft(metadata.Id) if err != nil { return nil, err } stateFunc := func(currentPercentage int) (machinestate.State, error) { if withPush { ev.Push(&eventer.Event{ Message: "Stopping machine", Status: machinestate.Stopping, Percentage: currentPercentage, }) } state, _, err := m.Info(nil) if err != nil { return machinestate.Unknown, err } return state, err } ws := waitstate.WaitState{ StateFunc: stateFunc, DesiredState: machinestate.Stopped, Start: 45, Finish: 60, } return nil, ws.Wait() }
func (a *Amazon) Destroy(ctx context.Context, start, finish int) error { if a.Id() == "" { return ErrInstanceEmptyID } ev, withPush := eventer.FromContext(ctx) if withPush { ev.Push(&eventer.Event{ Message: "Terminating machine", Status: machinestate.Terminating, Percentage: start, }) } _, err := a.Client.TerminateInstance(a.Id()) if err != nil { return err } stateFunc := func(currentPercentage int) (machinestate.State, error) { if withPush { ev.Push(&eventer.Event{ Message: "Terminating machine", Status: machinestate.Terminating, Percentage: currentPercentage, }) } instance, err := a.Instance() if err != nil { return 0, err } return StatusToState(aws.StringValue(instance.State.Name)), nil } ws := waitstate.WaitState{ StateFunc: stateFunc, DesiredState: machinestate.Terminated, Start: start, Finish: finish, } return ws.Wait() }
func (a *Amazon) Restart(ctx context.Context) error { if a.Id() == "" { return ErrInstanceEmptyID } ev, withPush := eventer.FromContext(ctx) if withPush { ev.Push(&eventer.Event{ Message: "Restarting machine", Status: machinestate.Rebooting, Percentage: 10, }) } err := a.Client.RebootInstance(a.Id()) if err != nil { return err } stateFunc := func(currentPercentage int) (machinestate.State, error) { if withPush { ev.Push(&eventer.Event{ Message: "Restarting machine", Status: machinestate.Rebooting, Percentage: currentPercentage, }) } instance, err := a.Instance() if err != nil { return 0, err } return StatusToState(aws.StringValue(instance.State.Name)), nil } ws := waitstate.WaitState{ StateFunc: stateFunc, DesiredState: machinestate.Running, Start: 25, Finish: 60, } return ws.Wait() }
func (a *Amazon) Stop(ctx context.Context) error { if a.Id() == "" { return ErrInstanceEmptyID } ev, withPush := eventer.FromContext(ctx) if withPush { ev.Push(&eventer.Event{ Message: "Stopping machine", Status: machinestate.Stopping, Percentage: 25, }) } a.Log.Debug("amazon stop eventer: %t", withPush) var ( // needs to be declared so we can call it recursively tryStop func() error tried int = 0 lastError error ) // we try to stop if there is an error in the stop instance call. For // example if it's a timeout we shouldn't return and try again. tryStop = func() error { if tried == 2 { return fmt.Errorf("Tried to stop three times without any success. Last error is:'%s'", lastError) } _, err := a.Client.StopInstance(a.Id()) if err != nil { lastError = err tried++ return tryStop() } return nil } if err := tryStop(); err != nil { return err } stateFunc := func(currentPercentage int) (machinestate.State, error) { if withPush { ev.Push(&eventer.Event{ Message: "Stopping machine", Status: machinestate.Stopping, Percentage: currentPercentage, }) } instance, err := a.Instance() if err != nil { return 0, err } return StatusToState(aws.StringValue(instance.State.Name)), nil } ws := waitstate.WaitState{ StateFunc: stateFunc, DesiredState: machinestate.Stopped, Start: 45, Finish: 60, } return ws.Wait() }