Exemple #1
0
func (bs *BaseStack) destroyAsync(ctx context.Context, req *stack.ApplyRequest) error {
	if rt, ok := stack.RequestTraceFromContext(ctx); ok {
		defer rt.Send()
	}

	bs.Eventer.Push(&eventer.Event{
		Message:    "Fetching and validating credentials",
		Percentage: 30,
		Status:     machinestate.Terminating,
	})

	credIDs := FlattenValues(bs.Builder.Stack.Credentials)

	bs.Log.Debug("Fetching '%d' credentials from user '%s'", len(credIDs), bs.Req.Username)

	if err := bs.Builder.BuildCredentials(bs.Req.Method, bs.Req.Username, req.GroupName, credIDs); err != nil {
		return err
	}

	bs.Log.Debug("Fetched terraform data: koding=%+v, template=%+v", bs.Builder.Koding, bs.Builder.Template)

	if bs.Builder.Stack.Stack.State() != stackstate.NotInitialized {
		bs.Log.Debug("Connection to Terraformer")

		tfKite, err := terraformer.Connect(bs.Session.Terraformer)
		if err != nil {
			return err
		}
		defer tfKite.Close()

		tfReq := &tf.TerraformRequest{
			ContentID: req.GroupName + "-" + req.StackID,
			TraceID:   bs.TraceID,
		}

		bs.Log.Debug("Calling terraform.destroy method with context: %+v", tfReq)

		_, err = tfKite.Destroy(tfReq)
		if err != nil {
			return err
		}
	}

	return bs.Builder.Database.Destroy()
}
Exemple #2
0
// HandleApply builds and expands compute stack template for the given ID and
// sends an apply request to terraformer.
//
// When destroy=false, building and expanding the stack prior to
// terraformer request is done asynchronously, and the result of
// that operation is communicated back with eventer.
//
// When destroy=true, fetching machines from DB is done synchronously, as
// as soon as Apply method returns, allowed user list for each machine
// is zeroed, which could make the destroy oepration to fail - we
// first build machines and rest of the destroy is perfomed asynchronously.
func (bs *BaseStack) HandleApply(ctx context.Context) (interface{}, error) {
	arg, ok := ctx.Value(stack.ApplyRequestKey).(*stack.ApplyRequest)
	if !ok {
		arg = &stack.ApplyRequest{}

		if err := bs.Req.Args.One().Unmarshal(arg); err != nil {
			return nil, err
		}
	}

	if err := arg.Valid(); err != nil {
		return nil, err
	}

	err := bs.Builder.BuildStack(arg.StackID, arg.Credentials)

	if err != nil && !(arg.Destroy && models.IsNotFound(err, "jStackTemplate")) {
		return nil, err
	}

	if state := bs.Builder.Stack.Stack.State(); state.InProgress() {
		return nil, fmt.Errorf("State is currently %s. Please try again later", state)
	}

	if rt, ok := stack.RequestTraceFromContext(ctx); ok {
		rt.Hijack()
	}

	bs.Arg = arg

	if arg.Destroy {
		err = bs.destroy(ctx, arg)
	} else {
		err = bs.apply(ctx, arg)
	}

	if err != nil {
		return nil, err
	}

	return &stack.ControlResult{
		EventId: bs.Eventer.ID(),
	}, nil
}
Exemple #3
0
func (bs *BaseStack) applyAsync(ctx context.Context, req *stack.ApplyRequest) error {
	if rt, ok := stack.RequestTraceFromContext(ctx); ok {
		defer rt.Send()
	}

	bs.Eventer.Push(&eventer.Event{
		Message:    "Fetching and validating machines",
		Percentage: 20,
		Status:     machinestate.Building,
	})

	if err := bs.Builder.BuildMachines(ctx); err != nil {
		return err
	}

	bs.Eventer.Push(&eventer.Event{
		Message:    "Fetching and validating credentials",
		Percentage: 30,
		Status:     machinestate.Building,
	})

	credIDs := FlattenValues(bs.Builder.Stack.Credentials)

	bs.Log.Debug("Fetching '%d' credentials from user '%s'", len(credIDs), bs.Req.Username)

	if err := bs.Builder.BuildCredentials(bs.Req.Method, bs.Req.Username, req.GroupName, credIDs); err != nil {
		return err
	}

	cred, err := bs.Builder.CredentialByProvider(bs.Provider.Name)
	if err != nil {
		return err
	}

	bs.Log.Debug("Fetched terraform data: koding=%+v, template=%+v", bs.Builder.Koding, bs.Builder.Template)

	tfKite, err := terraformer.Connect(bs.Session.Terraformer)
	if err != nil {
		return err
	}
	defer tfKite.Close()

	defaultContentID := req.GroupName + "-" + req.StackID
	bs.Log.Debug("Building template: %s", defaultContentID)

	if err := bs.Builder.BuildTemplate(bs.Builder.Stack.Template, defaultContentID); err != nil {
		return err
	}

	if len(req.Variables) != 0 {
		if err := bs.Builder.Template.InjectVariables("", req.Variables); err != nil {
			return err
		}
	}

	bs.Log.Debug("Stack template before injecting Koding data: %s", bs.Builder.Template)

	t, err := bs.stack.ApplyTemplate(cred)
	if err != nil {
		return err
	}

	if t.Key == "" {
		t.Key = defaultContentID
	}

	bs.Log.Debug("Stack template after injecting Koding data: %s", t)

	bs.Builder.Stack.Template = t.Content

	done := make(chan struct{})

	// because apply can last long, we are going to increment the eventer's
	// percentage as long as we build automatically.
	go func() {
		start := 45
		ticker := time.NewTicker(time.Second * 5)
		defer ticker.Stop()

		for {
			select {
			case <-done:
				return
			case <-ticker.C:
				if start < 70 {
					start += 5
				}

				bs.Eventer.Push(&eventer.Event{
					Message:    "Building stack resources",
					Percentage: start,
					Status:     machinestate.Building,
				})
			}
		}
	}()

	tfReq := &tf.TerraformRequest{
		Content:   bs.Builder.Stack.Template,
		ContentID: t.Key,
		TraceID:   bs.TraceID,
	}

	bs.Log.Debug("Final stack template. Calling terraform.apply method:")
	bs.Log.Debug("%+v", tfReq)

	state, err := tfKite.Apply(tfReq)

	close(done)

	if err != nil {
		return err
	}

	bs.Eventer.Push(&eventer.Event{
		Message:    "Checking VM connections",
		Percentage: 70,
		Status:     machinestate.Building,
	})

	if bs.Klients, err = bs.Planner.DialKlients(ctx, bs.KlientIDs); err != nil {
		return err
	}

	bs.Eventer.Push(&eventer.Event{
		Message:    "Updating machine settings",
		Percentage: 90,
		Status:     machinestate.Building,
	})

	err = bs.UpdateResources(state)

	if e := bs.Builder.UpdateStack(); e != nil && err == nil {
		err = e
	}

	return err
}