コード例 #1
0
ファイル: stacker.go プロジェクト: koding/koding
// 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
}
コード例 #2
0
ファイル: stacker.go プロジェクト: koding/koding
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
}
コード例 #3
0
ファイル: state.go プロジェクト: koding/koding
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
}
コード例 #4
0
ファイル: machine.go プロジェクト: koding/koding
// 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()
}
コード例 #5
0
ファイル: instance.go プロジェクト: koding/koding
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
}
コード例 #6
0
ファイル: machine.go プロジェクト: koding/koding
// 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()
}
コード例 #7
0
ファイル: state.go プロジェクト: koding/koding
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()
}
コード例 #8
0
ファイル: state.go プロジェクト: koding/koding
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()
}
コード例 #9
0
ファイル: state.go プロジェクト: koding/koding
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()
}