Skip to content

Commit d5c96bb

Browse files
committed
feat: add restart command
fixes #48
1 parent 140043e commit d5c96bb

File tree

6 files changed

+104
-15
lines changed

6 files changed

+104
-15
lines changed

src/cmd/cli/main.go

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ var composeCmd = &cobra.Command{
377377
Use: "compose",
378378
Aliases: []string{"stack"},
379379
Args: cobra.NoArgs,
380-
Short: "Work with local docker-compose.yml files",
380+
Short: "Work with local Compose files",
381381
}
382382

383383
func printEndpoints(serviceInfos []*defangv1.ServiceInfo) {
@@ -399,7 +399,7 @@ func printEndpoints(serviceInfos []*defangv1.ServiceInfo) {
399399
var composeUpCmd = &cobra.Command{
400400
Use: "up",
401401
Annotations: authNeededAnnotation,
402-
Args: cobra.NoArgs,
402+
Args: cobra.NoArgs, // TODO: takes optional list of service names
403403
Short: "Like 'start' but immediately tracks the progress of the deployment",
404404
RunE: func(cmd *cobra.Command, args []string) error {
405405
var filePath, _ = cmd.InheritedFlags().GetString("file")
@@ -428,8 +428,8 @@ var composeStartCmd = &cobra.Command{
428428
Use: "start",
429429
Aliases: []string{"deploy"},
430430
Annotations: authNeededAnnotation,
431-
Args: cobra.NoArgs,
432-
Short: "Reads a docker-compose.yml file and deploys services to the cluster",
431+
Args: cobra.NoArgs, // TODO: takes optional list of service names
432+
Short: "Reads a Compose file and deploys services to the cluster",
433433
RunE: func(cmd *cobra.Command, args []string) error {
434434
var filePath, _ = cmd.InheritedFlags().GetString("file")
435435
var force, _ = cmd.Flags().GetBool("force")
@@ -450,12 +450,28 @@ var composeStartCmd = &cobra.Command{
450450
},
451451
}
452452

453+
var composeRestartCmd = &cobra.Command{
454+
Use: "restart",
455+
Annotations: authNeededAnnotation,
456+
Args: cobra.NoArgs, // TODO: takes optional list of service names
457+
Short: "Reads a Compose file and restarts its services",
458+
RunE: func(cmd *cobra.Command, args []string) error {
459+
var filePath, _ = cmd.InheritedFlags().GetString("file")
460+
461+
_, err := cli.ComposeRestart(cmd.Context(), client, filePath, string(tenantId))
462+
if err != nil {
463+
return err
464+
}
465+
return nil
466+
},
467+
}
468+
453469
var composeDownCmd = &cobra.Command{
454470
Use: "down",
455471
Aliases: []string{"stop", "rm"},
456472
Annotations: authNeededAnnotation,
457-
Args: cobra.NoArgs,
458-
Short: "Reads a docker-compose.yml file and deletes services from the cluster",
473+
Args: cobra.NoArgs, // TODO: takes optional list of service names
474+
Short: "Reads a Compose file and deletes services from the cluster",
459475
RunE: func(cmd *cobra.Command, args []string) error {
460476
var filePath, _ = cmd.InheritedFlags().GetString("file")
461477
var tail, _ = cmd.Flags().GetBool("tail")
@@ -485,8 +501,8 @@ var composeDownCmd = &cobra.Command{
485501

486502
var composeConfigCmd = &cobra.Command{
487503
Use: "config",
488-
Args: cobra.NoArgs,
489-
Short: "Reads a docker-compose.yml file and shows the generated config",
504+
Args: cobra.NoArgs, // TODO: takes optional list of service names
505+
Short: "Reads a Compose file and shows the generated config",
490506
RunE: func(cmd *cobra.Command, args []string) error {
491507
var filePath, _ = cmd.InheritedFlags().GetString("file")
492508

@@ -529,6 +545,20 @@ var deleteCmd = &cobra.Command{
529545
},
530546
}
531547

548+
var restartCmd = &cobra.Command{
549+
Use: "restart",
550+
Annotations: authNeededAnnotation,
551+
Args: cobra.MinimumNArgs(1),
552+
Short: "Restart one or more services",
553+
RunE: func(cmd *cobra.Command, args []string) error {
554+
_, err := cli.Restart(cmd.Context(), client, args...)
555+
if err != nil {
556+
return err
557+
}
558+
return nil
559+
},
560+
}
561+
532562
var sendCmd = &cobra.Command{
533563
Use: "send",
534564
Hidden: true, // not available in private beta
@@ -624,6 +654,7 @@ func main() {
624654
secretsCmd.AddCommand(secretsListCmd)
625655

626656
rootCmd.AddCommand(secretsCmd)
657+
rootCmd.AddCommand(restartCmd)
627658

628659
// Compose Command
629660
composeCmd.PersistentFlags().StringP("file", "f", "*compose.y*ml", `Compose file path`)
@@ -643,6 +674,7 @@ func main() {
643674
composeStartCmd.Flags().Bool("force", false, "Force a build of the image even if nothing has changed")
644675
composeCmd.AddCommand(composeStartCmd)
645676
rootCmd.AddCommand(composeCmd)
677+
composeCmd.AddCommand(composeRestartCmd)
646678

647679
// Tail Command
648680
tailCmd.Flags().StringP("name", "n", "", "Name of the service")

src/pkg/cli/composeDown.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func ComposeDown(ctx context.Context, client defangv1connect.FabricControllerCli
1414

1515
names := make([]string, 0, len(project.Services))
1616
for _, service := range project.Services {
17-
names = append(names, service.Name)
17+
names = append(names, NormalizeServiceName(service.Name))
1818
}
1919

2020
return Delete(ctx, client, names...)

src/pkg/cli/composeRestart.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
6+
pb "github.com/defang-io/defang/src/protos/io/defang/v1"
7+
"github.com/defang-io/defang/src/protos/io/defang/v1/defangv1connect"
8+
)
9+
10+
func ComposeRestart(ctx context.Context, client defangv1connect.FabricControllerClient, filePath, projectName string) ([]*pb.ServiceInfo, error) {
11+
project, err := loadDockerCompose(filePath, projectName)
12+
if err != nil {
13+
return nil, err
14+
}
15+
16+
names := make([]string, 0, len(project.Services))
17+
for _, service := range project.Services {
18+
names = append(names, NormalizeServiceName(service.Name))
19+
}
20+
21+
return Restart(ctx, client, names...)
22+
}

src/pkg/cli/composeStart.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ func ComposeStart(ctx context.Context, client defangv1connect.FabricControllerCl
243243
var deploy *pb.Deploy
244244
if svccfg.Deploy != nil {
245245
deploy = &pb.Deploy{}
246+
deploy.Replicas = 1 // default to one replica per service
246247
if svccfg.Deploy.Replicas != nil {
247248
deploy.Replicas = uint32(*svccfg.Deploy.Replicas)
248249
}

src/pkg/cli/delete.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,14 @@ import (
88
"github.com/defang-io/defang/src/protos/io/defang/v1/defangv1connect"
99
)
1010

11-
func Delete(ctx context.Context, client defangv1connect.FabricControllerClient, name ...string) (string, error) {
12-
Debug(" - Deleting service", name)
11+
func Delete(ctx context.Context, client defangv1connect.FabricControllerClient, names ...string) (string, error) {
12+
Debug(" - Deleting service", names)
1313

1414
if DoDryRun {
1515
return "", nil
1616
}
1717

18-
for i, n := range name {
19-
name[i] = NormalizeServiceName(n)
20-
}
21-
resp, err := client.Delete(ctx, connect.NewRequest(&pb.DeleteRequest{Names: name}))
18+
resp, err := client.Delete(ctx, connect.NewRequest(&pb.DeleteRequest{Names: names}))
2219
if err != nil {
2320
return "", err
2421
}

src/pkg/cli/restart.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
6+
"github.com/bufbuild/connect-go"
7+
pb "github.com/defang-io/defang/src/protos/io/defang/v1"
8+
"github.com/defang-io/defang/src/protos/io/defang/v1/defangv1connect"
9+
)
10+
11+
func Restart(ctx context.Context, client defangv1connect.FabricControllerClient, names ...string) ([]*pb.ServiceInfo, error) {
12+
Debug(" - Restarting service", names)
13+
if DoDryRun {
14+
return nil, nil
15+
}
16+
17+
serviceInfos := make([]*pb.ServiceInfo, 0, len(names))
18+
for _, name := range names {
19+
Info(" * Restarting service", name)
20+
serviceInfo, err := client.Get(ctx, connect.NewRequest(&pb.ServiceID{Name: name}))
21+
if err != nil {
22+
Warn(" ! Failed to get service", name, err)
23+
continue
24+
}
25+
serviceInfo, err = client.Update(ctx, connect.NewRequest(serviceInfo.Msg.Service))
26+
if err != nil {
27+
// Abort all? TODO: restart should probably be atomic, all or nothing
28+
if len(serviceInfos) == 0 {
29+
return nil, err
30+
}
31+
Warn(" ! Failed to restart service", name, err)
32+
continue
33+
}
34+
serviceInfos = append(serviceInfos, serviceInfo.Msg)
35+
}
36+
return serviceInfos, nil
37+
}

0 commit comments

Comments
 (0)