Add restart command

Signed-off-by: Ulysses Souza <ulyssessouza@gmail.com>
This commit is contained in:
Ulysses Souza 2021-03-09 18:09:45 -03:00
parent 7bb0f02d2e
commit 2fdc3bad48
15 changed files with 212 additions and 0 deletions

View File

@ -64,6 +64,10 @@ func (cs *aciComposeService) Start(ctx context.Context, project *types.Project,
return errdefs.ErrNotImplemented
}
func (cs *aciComposeService) Restart(ctx context.Context, project *types.Project, options compose.RestartOptions) error {
return errdefs.ErrNotImplemented
}
func (cs *aciComposeService) Stop(ctx context.Context, project *types.Project, options compose.StopOptions) error {
return errdefs.ErrNotImplemented
}

View File

@ -48,6 +48,10 @@ func (c *composeService) Start(ctx context.Context, project *types.Project, opti
return errdefs.ErrNotImplemented
}
func (c *composeService) Restart(ctx context.Context, project *types.Project, options compose.RestartOptions) error {
return errdefs.ErrNotImplemented
}
func (c *composeService) Stop(ctx context.Context, project *types.Project, options compose.StopOptions) error {
return errdefs.ErrNotImplemented
}

View File

@ -38,6 +38,8 @@ type Service interface {
Create(ctx context.Context, project *types.Project, opts CreateOptions) error
// Start executes the equivalent to a `compose start`
Start(ctx context.Context, project *types.Project, options StartOptions) error
// Restart restarts containers
Restart(ctx context.Context, project *types.Project, options RestartOptions) error
// Stop executes the equivalent to a `compose stop`
Stop(ctx context.Context, project *types.Project, options StopOptions) error
// Up executes the equivalent to a `compose up`
@ -106,6 +108,12 @@ type StartOptions struct {
Services []string
}
// RestartOptions group options of the Restart API
type RestartOptions struct {
// Timeout override container restart timeout
Timeout *time.Duration
}
// StopOptions group options of the Stop API
type StopOptions struct {
// Timeout override container stop timeout

View File

@ -68,6 +68,16 @@ func StartedEvent(ID string) Event {
return NewEvent(ID, Done, "Started")
}
// RestartingEvent creates a new Restarting in progress Event
func RestartingEvent(ID string) Event {
return NewEvent(ID, Working, "Restarting")
}
// RestartedEvent creates a new Restarted in progress Event
func RestartedEvent(ID string) Event {
return NewEvent(ID, Done, "Restarted")
}
// RunningEvent creates a new Running in progress Event
func RunningEvent(ID string) Event {
return NewEvent(ID, Done, "Running")

View File

@ -127,6 +127,7 @@ func Command(contextType string) *cobra.Command {
upCommand(&opts, contextType),
downCommand(&opts, contextType),
startCommand(&opts),
restartCommand(&opts),
stopCommand(&opts),
psCommand(&opts),
listCommand(contextType),

View File

@ -0,0 +1,70 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package compose
import (
"context"
"time"
"github.com/spf13/cobra"
"github.com/docker/compose-cli/api/client"
"github.com/docker/compose-cli/api/compose"
"github.com/docker/compose-cli/api/progress"
)
type restartOptions struct {
*projectOptions
timeout int
}
func restartCommand(p *projectOptions) *cobra.Command {
opts := restartOptions{
projectOptions: p,
}
restartCmd := &cobra.Command{
Use: "restart",
Short: "Restart containers",
RunE: func(cmd *cobra.Command, args []string) error {
return runRestart(cmd.Context(), opts, args)
},
}
flags := restartCmd.Flags()
flags.IntVarP(&opts.timeout, "timeout", "t", 10, "Specify a shutdown timeout in seconds")
return restartCmd
}
func runRestart(ctx context.Context, opts restartOptions, services []string) error {
c, err := client.New(ctx)
if err != nil {
return err
}
project, err := opts.toProject(services)
if err != nil {
return err
}
timeout := time.Duration(opts.timeout) * time.Second
_, err = progress.Run(ctx, func(ctx context.Context) (string, error) {
return "", c.ComposeService().Restart(ctx, project, compose.RestartOptions{
Timeout: &timeout,
})
})
return err
}

View File

View File

@ -17,6 +17,7 @@ cname:
- docker compose ps
- docker compose pull
- docker compose push
- docker compose restart
- docker compose rm
- docker compose run
- docker compose start
@ -38,6 +39,7 @@ clink:
- docker_compose_ps.yaml
- docker_compose_pull.yaml
- docker_compose_push.yaml
- docker_compose_restart.yaml
- docker_compose_rm.yaml
- docker_compose_run.yaml
- docker_compose_start.yaml

View File

@ -0,0 +1,23 @@
command: docker compose restart
short: Restart containers
long: Restart containers
usage: docker compose restart
pname: docker compose
plink: docker_compose.yaml
options:
- option: timeout
shorthand: t
value_type: int
default_value: "10"
description: Specify a shutdown timeout in seconds
deprecated: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false
deprecated: false
experimental: false
experimentalcli: false
kubernetes: false
swarm: false

View File

@ -57,6 +57,10 @@ func (e ecsLocalSimulation) Start(ctx context.Context, project *types.Project, o
return e.compose.Start(ctx, project, options)
}
func (e ecsLocalSimulation) Restart(ctx context.Context, project *types.Project, options compose.RestartOptions) error {
return e.compose.Restart(ctx, project, options)
}
func (e ecsLocalSimulation) Stop(ctx context.Context, project *types.Project, options compose.StopOptions) error {
return e.compose.Stop(ctx, project, options)
}

View File

@ -51,6 +51,10 @@ func (b *ecsAPIService) Start(ctx context.Context, project *types.Project, optio
return errdefs.ErrNotImplemented
}
func (b *ecsAPIService) Restart(ctx context.Context, project *types.Project, options compose.RestartOptions) error {
return errdefs.ErrNotImplemented
}
func (b *ecsAPIService) Stop(ctx context.Context, project *types.Project, options compose.StopOptions) error {
return errdefs.ErrNotImplemented
}

View File

@ -188,6 +188,11 @@ func (s *composeService) Start(ctx context.Context, project *types.Project, opti
return errdefs.ErrNotImplemented
}
// Restart executes the equivalent to a `compose restart`
func (s *composeService) Restart(ctx context.Context, project *types.Project, options compose.RestartOptions) error {
return errdefs.ErrNotImplemented
}
// Stop executes the equivalent to a `compose stop`
func (s *composeService) Stop(ctx context.Context, project *types.Project, options compose.StopOptions) error {
return errdefs.ErrNotImplemented

View File

@ -390,3 +390,26 @@ func (s *composeService) startService(ctx context.Context, project *types.Projec
}
return eg.Wait()
}
func (s *composeService) restartService(ctx context.Context, serviceName string, timeout *time.Duration) error {
containerState, err := GetContextContainerState(ctx)
if err != nil {
return err
}
containers := containerState.GetContainers().filter(isService(serviceName))
w := progress.ContextWriter(ctx)
eg, ctx := errgroup.WithContext(ctx)
for _, c := range containers {
container := c
eg.Go(func() error {
eventName := getContainerProgressName(container)
w.Event(progress.RestartingEvent(eventName))
err := s.apiClient.ContainerRestart(ctx, container.ID, timeout)
if err == nil {
w.Event(progress.StartedEvent(eventName))
}
return err
})
}
return eg.Wait()
}

39
local/compose/restart.go Normal file
View File

@ -0,0 +1,39 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package compose
import (
"context"
"github.com/docker/compose-cli/api/compose"
"github.com/compose-spec/compose-go/types"
)
func (s *composeService) Restart(ctx context.Context, project *types.Project, options compose.RestartOptions) error {
ctx, err := s.getUpdatedContainersStateContext(ctx, project.Name)
if err != nil {
return err
}
err = InDependencyOrder(ctx, project, func(c context.Context, service types.ServiceConfig) error {
return s.restartService(ctx, service.Name, options.Timeout)
})
if err != nil {
return err
}
return nil
}

View File

@ -20,6 +20,7 @@ import (
"context"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/pkg/errors"
)
@ -100,3 +101,17 @@ func GetContextContainerState(ctx context.Context) (ContainersState, error) {
}
return cState, nil
}
func (s composeService) getUpdatedContainersStateContext(ctx context.Context, projectName string) (context.Context, error) {
observedState, err := s.apiClient.ContainerList(ctx, types.ContainerListOptions{
Filters: filters.NewArgs(
projectFilter(projectName),
),
All: true,
})
if err != nil {
return nil, err
}
containerState := NewContainersState(observedState)
return context.WithValue(ctx, ContainersKey{}, containerState), nil
}