Skip to content

Commit

Permalink
add preview mode
Browse files Browse the repository at this point in the history
  • Loading branch information
lionello committed Jul 2, 2024
1 parent 4c4f5aa commit 529f321
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 41 deletions.
53 changes: 36 additions & 17 deletions src/cmd/cli/command/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,15 @@ func SetupCommands(version string) {

// Bootstrap command
RootCmd.AddCommand(bootstrapCmd)
bootstrapCmd.AddCommand(bootstrapDestroyCmd)
bootstrapCmd.AddCommand(bootstrapDownCmd)
bootstrapCmd.AddCommand(bootstrapRefreshCmd)
bootstrapTearDownCmd.Flags().Bool("force", false, "force the teardown of the CD stack")
bootstrapCmd.AddCommand(bootstrapTearDownCmd)
bootstrapListCmd.Flags().Bool("remote", false, "invoke the command on the remote cluster")
bootstrapCmd.AddCommand(bootstrapListCmd)
bootstrapCmd.AddCommand(bootstrapCancelCmd)
bootstrapCmd.AddCommand(cdDestroyCmd)
bootstrapCmd.AddCommand(cdDownCmd)
bootstrapCmd.AddCommand(cdRefreshCmd)
cdTearDownCmd.Flags().Bool("force", false, "force the teardown of the CD stack")
bootstrapCmd.AddCommand(cdTearDownCmd)
cdListCmd.Flags().Bool("remote", false, "invoke the command on the remote cluster")
bootstrapCmd.AddCommand(cdListCmd)
bootstrapCmd.AddCommand(cdCancelCmd)
bootstrapCmd.AddCommand(cdPreviewCmd)

// Eula command
tosCmd.Flags().Bool("agree-tos", false, "agree to the Defang terms of service")
Expand Down Expand Up @@ -806,9 +807,13 @@ var composeUpCmd = &cobra.Command{
var force, _ = cmd.Flags().GetBool("force")
var detach, _ = cmd.Flags().GetBool("detach")

buildContext := compose.BuildContextDigest
if force {
buildContext = compose.BuildContextForce
}
since := time.Now()
ctx := cmd.Context()
deploy, err := cli.ComposeStart(ctx, client, force)
deploy, err := cli.ComposeStart(ctx, client, buildContext)
if err != nil {
return err
}
Expand Down Expand Up @@ -863,7 +868,11 @@ var composeStartCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
var force, _ = cmd.Flags().GetBool("force")

deploy, err := cli.ComposeStart(cmd.Context(), client, force)
buildContext := compose.BuildContextDigest
if force {
buildContext = compose.BuildContextForce
}
deploy, err := cli.ComposeStart(cmd.Context(), client, buildContext)
if err != nil {
return err
}
Expand Down Expand Up @@ -968,7 +977,7 @@ var composeConfigCmd = &cobra.Command{
RunE: func(cmd *cobra.Command, args []string) error {
cli.DoDryRun = true // config is like start in a dry run
// force=false to calculate the digest
if _, err := cli.ComposeStart(cmd.Context(), client, false); !errors.Is(err, cli.ErrDryRun) {
if _, err := cli.ComposeStart(cmd.Context(), client, compose.BuildContextIgnore); !errors.Is(err, cli.ErrDryRun) {
return err
}
return nil
Expand Down Expand Up @@ -1081,7 +1090,7 @@ var bootstrapCmd = &cobra.Command{
Short: "Manually run a command with the CD task (for BYOC only)",
}

var bootstrapDestroyCmd = &cobra.Command{
var cdDestroyCmd = &cobra.Command{
Use: "destroy",
Args: cobra.NoArgs, // TODO: set MaximumNArgs(1),
Short: "Destroy the service stack",
Expand All @@ -1090,7 +1099,7 @@ var bootstrapDestroyCmd = &cobra.Command{
},
}

var bootstrapDownCmd = &cobra.Command{
var cdDownCmd = &cobra.Command{
Use: "down",
Args: cobra.NoArgs, // TODO: set MaximumNArgs(1),
Short: "Refresh and then destroy the service stack",
Expand All @@ -1099,7 +1108,7 @@ var bootstrapDownCmd = &cobra.Command{
},
}

var bootstrapRefreshCmd = &cobra.Command{
var cdRefreshCmd = &cobra.Command{
Use: "refresh",
Args: cobra.NoArgs, // TODO: set MaximumNArgs(1),
Short: "Refresh the service stack",
Expand All @@ -1108,7 +1117,7 @@ var bootstrapRefreshCmd = &cobra.Command{
},
}

var bootstrapCancelCmd = &cobra.Command{
var cdCancelCmd = &cobra.Command{
Use: "cancel",
Args: cobra.NoArgs, // TODO: set MaximumNArgs(1),
Short: "Cancel the current CD operation",
Expand All @@ -1117,7 +1126,7 @@ var bootstrapCancelCmd = &cobra.Command{
},
}

var bootstrapTearDownCmd = &cobra.Command{
var cdTearDownCmd = &cobra.Command{
Use: "teardown",
Args: cobra.NoArgs,
Short: "Destroy the CD cluster without destroying the services",
Expand All @@ -1128,7 +1137,7 @@ var bootstrapTearDownCmd = &cobra.Command{
},
}

var bootstrapListCmd = &cobra.Command{
var cdListCmd = &cobra.Command{
Use: "ls",
Args: cobra.NoArgs,
Aliases: []string{"list"},
Expand All @@ -1143,6 +1152,16 @@ var bootstrapListCmd = &cobra.Command{
},
}

var cdPreviewCmd = &cobra.Command{
Use: "preview",
Args: cobra.NoArgs,
Short: "Preview the changes that will be made by the CD task",
RunE: func(cmd *cobra.Command, args []string) error {
_, err := cli.ComposeStart(cmd.Context(), client, compose.BuildContextPreview)
return err
},
}

var tosCmd = &cobra.Command{
Use: "terms",
Aliases: []string{"tos", "eula", "tac", "tou"},
Expand Down
11 changes: 9 additions & 2 deletions src/pkg/cli/client/byoc/aws/byoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ func (b *ByocAws) setUp(ctx context.Context) error {
}

func (b *ByocAws) Deploy(ctx context.Context, req *defangv1.DeployRequest) (*defangv1.DeployResponse, error) {
return b.deploy(ctx, req, "up")
}

func (b *ByocAws) Preview(ctx context.Context, req *defangv1.DeployRequest) (*defangv1.DeployResponse, error) {
return b.deploy(ctx, req, "preview")
}

func (b *ByocAws) deploy(ctx context.Context, req *defangv1.DeployRequest, cmd string) (*defangv1.DeployResponse, error) {
if err := b.setUp(ctx); err != nil {
return nil, err
}
Expand Down Expand Up @@ -169,15 +177,14 @@ func (b *ByocAws) Deploy(ctx context.Context, req *defangv1.DeployRequest) (*def
return nil, fmt.Errorf("unexpected status code during upload: %s", resp.Status)
}
payloadString = http.RemoveQueryParam(url)
// FIXME: this code path didn't work
}

if b.ShouldDelegateSubdomain {
if _, err := b.delegateSubdomain(ctx); err != nil {
return nil, err
}
}
taskArn, err := b.runCdCommand(ctx, "up", payloadString)
taskArn, err := b.runCdCommand(ctx, cmd, payloadString)
if err != nil {
return nil, err
}
Expand Down
5 changes: 5 additions & 0 deletions src/pkg/cli/client/byoc/do/byoc.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package do
import (
"bytes"
"context"
"errors"
"fmt"
"os"
"strings"
Expand Down Expand Up @@ -47,6 +48,10 @@ func NewByoc(ctx context.Context, grpcClient client.GrpcClient, tenantId types.T
return b
}

func (b *ByocDo) Preview(ctx context.Context, req *defangv1.DeployRequest) (*defangv1.DeployResponse, error) {
return nil, errors.ErrUnsupported
}

func (b *ByocDo) Deploy(ctx context.Context, req *defangv1.DeployRequest) (*defangv1.DeployResponse, error) {
if err := b.setUp(ctx); err != nil {
return nil, err
Expand Down
1 change: 1 addition & 0 deletions src/pkg/cli/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type Client interface {
GetService(context.Context, *defangv1.ServiceID) (*defangv1.ServiceInfo, error)
GetServices(context.Context) (*defangv1.ListServicesResponse, error)
ListConfig(context.Context) (*defangv1.Secrets, error)
Preview(context.Context, *defangv1.DeployRequest) (*defangv1.DeployResponse, error)
PutConfig(context.Context, *defangv1.SecretValue) error
Restart(context.Context, ...string) (types.ETag, error)
ServiceDNS(name string) string
Expand Down
6 changes: 5 additions & 1 deletion src/pkg/cli/client/playground.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ func (g PlaygroundClient) Deploy(ctx context.Context, req *defangv1.DeployReques
return getMsg(g.client.Deploy(ctx, connect.NewRequest(req)))
}

func (g PlaygroundClient) Preview(ctx context.Context, req *defangv1.DeployRequest) (*defangv1.DeployResponse, error) {
return nil, errors.New("the preview command is not valid for the Defang playground; did you forget --provider?")
}

func (g PlaygroundClient) GetService(ctx context.Context, req *defangv1.ServiceID) (*defangv1.ServiceInfo, error) {
return getMsg(g.client.Get(ctx, connect.NewRequest(req)))
}
Expand Down Expand Up @@ -64,7 +68,7 @@ func (g *PlaygroundClient) Tail(ctx context.Context, req *defangv1.TailRequest)
}

func (g *PlaygroundClient) BootstrapCommand(ctx context.Context, command string) (types.ETag, error) {
return "", errors.New("the bootstrap command is not valid for the Defang playground; did you forget --provider?")
return "", errors.New("the CD command is not valid for the Defang playground; did you forget --provider?")
}
func (g *PlaygroundClient) Destroy(ctx context.Context) (types.ETag, error) {
// Get all the services in the project and delete them all at once
Expand Down
9 changes: 5 additions & 4 deletions src/pkg/cli/compose/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ import (
type BuildContext int

const (
BuildContextDigest BuildContext = iota // the default: calculate the digest of the tarball so we can skip building the same image twice
BuildContextForce // force: always upload the tarball, even if it's the same as a previous one
BuildContextIgnore // dry-run: don't upload the tarball, just return the path
BuildContextDigest BuildContext = iota // the default: calculate the digest of the tarball so we can skip building the same image twice
BuildContextForce // force: always upload the tarball, even if it's the same as a previous one
BuildContextIgnore // dry-run: don't upload the tarball, just return the path
BuildContextPreview // preview:, like dry-run but also don't deploy
)

const (
Expand Down Expand Up @@ -77,7 +78,7 @@ func getRemoteBuildContext(ctx context.Context, client client.Client, name strin
term.Debug("Digest:", digest)
}

if force == BuildContextIgnore {
if force == BuildContextIgnore || force == BuildContextPreview {
return root, nil
}

Expand Down
25 changes: 9 additions & 16 deletions src/pkg/cli/composeStart.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,8 @@ func (e ComposeError) Unwrap() error {
return e.error
}

func buildContext(force bool) compose.BuildContext {
if DoDryRun {
return compose.BuildContextIgnore
}
if force {
return compose.BuildContextForce
}
return compose.BuildContextDigest
}

// ComposeStart validates a compose project and uploads the services using the client
func ComposeStart(ctx context.Context, c client.Client, force bool) (*defangv1.DeployResponse, error) {
func ComposeStart(ctx context.Context, c client.Client, force compose.BuildContext) (*defangv1.DeployResponse, error) {
project, err := c.LoadProject(ctx)
if err != nil {
return nil, err
Expand All @@ -39,7 +29,7 @@ func ComposeStart(ctx context.Context, c client.Client, force bool) (*defangv1.D
return nil, &ComposeError{err}
}

services, err := compose.ConvertServices(ctx, c, project.Services, buildContext(force))
services, err := compose.ConvertServices(ctx, c, project.Services, force)
if err != nil {
return nil, err
}
Expand All @@ -48,7 +38,7 @@ func ComposeStart(ctx context.Context, c client.Client, force bool) (*defangv1.D
return nil, &ComposeError{fmt.Errorf("no services found")}
}

if DoDryRun {
if force == compose.BuildContextIgnore {
for _, service := range services {
PrintObject(service.Name, service)
}
Expand All @@ -59,9 +49,12 @@ func ComposeStart(ctx context.Context, c client.Client, force bool) (*defangv1.D
term.Info("Deploying service", service.Name)
}

resp, err := c.Deploy(ctx, &defangv1.DeployRequest{
Services: services,
})
var resp *defangv1.DeployResponse
if force == compose.BuildContextPreview {
resp, err = c.Preview(ctx, &defangv1.DeployRequest{Services: services})
} else {
resp, err = c.Deploy(ctx, &defangv1.DeployRequest{Services: services})
}
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion src/pkg/cli/composeStart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestComposeStart(t *testing.T) {
}))
defer server.Close()

_, err = ComposeStart(context.Background(), client.MockClient{UploadUrl: server.URL + "/", Project: proj}, false)
_, err = ComposeStart(context.Background(), client.MockClient{UploadUrl: server.URL + "/", Project: proj}, compose.BuildContextDigest)
if !errors.Is(err, ErrDryRun) {
t.Fatalf("ComposeStart() failed: %v", err)
}
Expand Down

0 comments on commit 529f321

Please sign in to comment.