Skip to content

Commit

Permalink
fix: support tasks with no stack changes
Browse files Browse the repository at this point in the history
  • Loading branch information
jvmakine committed Nov 28, 2024
1 parent 528e6db commit fdf2c47
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 12 deletions.
2 changes: 1 addition & 1 deletion cmd/ftl-provisioner-cloudformation/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func PostgresPostUpdate(ctx context.Context, secrets *secretsmanager.Client, byN
return fmt.Errorf("failed to create database: %w", err)
}
}
if _, err := db.ExecContext(ctx, fmt.Sprintf("GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA %s TO ftluser;", resourceID)); err != nil {
if _, err := db.ExecContext(ctx, "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO ftluser;"); err != nil {
return fmt.Errorf("failed to grant FTL user privileges: %w", err)
}
}
Expand Down
4 changes: 4 additions & 0 deletions cmd/ftl-provisioner-cloudformation/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1beta1/provisioner"
"github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1beta1/provisioner/provisionerconnect"
"github.com/TBD54566975/ftl/common/plugin"
"github.com/TBD54566975/ftl/internal/log"
)

const (
Expand Down Expand Up @@ -71,6 +72,8 @@ func (c *CloudformationProvisioner) Ping(context.Context, *connect.Request[ftlv1
}

func (c *CloudformationProvisioner) Provision(ctx context.Context, req *connect.Request[provisioner.ProvisionRequest]) (*connect.Response[provisioner.ProvisionResponse], error) {
logger := log.FromContext(ctx)

res, updated, err := c.createChangeSet(ctx, req.Msg)
if err != nil {
return nil, err
Expand All @@ -90,6 +93,7 @@ func (c *CloudformationProvisioner) Provision(ctx context.Context, req *connect.
if _, ok := c.running.LoadOrStore(token, task); ok {
return nil, fmt.Errorf("provisioner already running: %s", token)
}
logger.Debugf("Starting task for module %s: %s (%s)", req.Msg.Module, token, changeSetID)
task.Start(ctx, c.client, c.secrets, changeSetID)
return connect.NewResponse(&provisioner.ProvisionResponse{
Status: provisioner.ProvisionResponse_SUBMITTED,
Expand Down
5 changes: 4 additions & 1 deletion cmd/ftl-provisioner-cloudformation/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ func (c *CloudformationProvisioner) Status(ctx context.Context, req *connect.Req
token := req.Msg.ProvisioningToken
// if the task is not in the map, it means that the provisioner has crashed since starting the task
// in that case, we start a new task to query the existing stack
task, _ := c.running.LoadOrStore(token, &task{stackID: token})
task, loaded := c.running.LoadOrStore(token, &task{stackID: token})
if !loaded {
task.Start(ctx, c.client, c.secrets, "")
}

if task.err.Load() != nil {
c.running.Delete(token)
Expand Down
31 changes: 21 additions & 10 deletions cmd/ftl-provisioner-cloudformation/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"time"

"github.com/TBD54566975/ftl/internal/log"
"github.com/alecthomas/atomic"
"github.com/aws/aws-sdk-go-v2/service/cloudformation"
"github.com/aws/aws-sdk-go-v2/service/cloudformation/types"
Expand All @@ -20,15 +21,7 @@ type task struct {
outputs atomic.Value[[]types.Output]
}

func (t *task) updateStack(ctx context.Context, client *cloudformation.Client, changeSetID string) ([]types.Output, error) {
_, err := client.ExecuteChangeSet(ctx, &cloudformation.ExecuteChangeSetInput{
ChangeSetName: &changeSetID,
StackName: &t.stackID,
})
if err != nil {
return nil, fmt.Errorf("failed to execute change-set: %w", err)
}

func (t *task) waitForStackReady(ctx context.Context, client *cloudformation.Client) ([]types.Output, error) {
retry := backoff.Backoff{
Min: 100 * time.Millisecond,
Max: 5 * time.Second,
Expand Down Expand Up @@ -101,16 +94,34 @@ func (t *task) postUpdate(ctx context.Context, secrets *secretsmanager.Client, o

func (t *task) Start(oldCtx context.Context, client *cloudformation.Client, secrets *secretsmanager.Client, changeSetID string) {
ctx := context.WithoutCancel(oldCtx)
logger := log.FromContext(ctx)
go func() {
outputs, err := t.updateStack(ctx, client, changeSetID)
if changeSetID != "" {
logger.Debugf("Executing change-set: %s", changeSetID)
_, err := client.ExecuteChangeSet(ctx, &cloudformation.ExecuteChangeSetInput{
ChangeSetName: &changeSetID,
StackName: &t.stackID,
})
if err != nil {
logger.Errorf(err, "failed to execute change-set")
t.err.Store(fmt.Errorf("failed to execute change-set: %w", err))
return
}
}
logger.Debugf("Waiting for stack to be ready: %s", t.stackID)
outputs, err := t.waitForStackReady(ctx, client)
if err != nil {
logger.Errorf(err, "failed to wait for stack to be ready")
t.err.Store(err)
return
}
logger.Debugf("Stack ready: %s", t.stackID)
if err := t.postUpdate(ctx, secrets, outputs); err != nil {
logger.Errorf(err, "failed to post-update")
t.err.Store(err)
return
}
logger.Debugf("Post-update complete: %s", t.stackID)
t.outputs.Store(outputs)
}()
}
Expand Down

0 comments on commit fdf2c47

Please sign in to comment.