Skip to content

Commit

Permalink
enable managing more containers for some commands
Browse files Browse the repository at this point in the history
enable managing more containers for some commands
  • Loading branch information
xiechengsheng committed May 19, 2018
1 parent 33e585d commit 95942db
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 50 deletions.
26 changes: 18 additions & 8 deletions cli/pause.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ package main

import (
"context"
"errors"
"fmt"
"strings"

"github.com/spf13/cobra"
)

// pauseDescription is used to describe pause command in detail and auto generate command doc.
var pauseDescription = "Pause a running container object in Pouchd. " +
var pauseDescription = "Pause one or more running containers object in Pouchd. " +
"when pausing, the container will pause its running but hold all the relevant resource." +
"This is useful when you wish to pause a container for a while and to restore the running status later." +
"The container you paused will pause without being terminated."

// PauseCommand use to implement 'pause' command, it pauses a container.
// PauseCommand use to implement 'pause' command, it pauses one or more containers.
type PauseCommand struct {
baseCommand
}
Expand All @@ -22,10 +24,10 @@ type PauseCommand struct {
func (p *PauseCommand) Init(c *Cli) {
p.cli = c
p.cmd = &cobra.Command{
Use: "pause CONTAINER",
Short: "Pause a running container",
Use: "pause CONTAINER [CONTAINERS]",
Short: "Pause one or more running containers",
Long: pauseDescription,
Args: cobra.ExactArgs(1),
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return p.runPause(args)
},
Expand All @@ -44,11 +46,19 @@ func (p *PauseCommand) runPause(args []string) error {
ctx := context.Background()
apiClient := p.cli.Client()

container := args[0]
var errs []string
for _, name := range args {
if err := apiClient.ContainerPause(ctx, name); err != nil {
errs = append(errs, err.Error())
continue
}
fmt.Printf("%s\n", name)
}

if err := apiClient.ContainerPause(ctx, container); err != nil {
return fmt.Errorf("failed to pause container %s: %v", container, err)
if len(errs) > 0 {
return errors.New(strings.Join(errs, "\n"))
}

return nil
}

Expand Down
13 changes: 10 additions & 3 deletions cli/restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package main

import (
"context"
"strconv"

"errors"
"fmt"
"strconv"
"strings"

"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -46,13 +47,19 @@ func (rc *RestartCommand) runRestart(args []string) error {
ctx := context.Background()
apiClient := rc.cli.Client()

var errs []string
for _, name := range args {
if err := apiClient.ContainerRestart(ctx, name, strconv.Itoa(rc.timeout)); err != nil {
return fmt.Errorf("failed to restart container: %v", err)
errs = append(errs, err.Error())
continue
}
fmt.Printf("%s\n", name)
}

if len(errs) > 0 {
return errors.New(strings.Join(errs, "\n"))
}

return nil
}

Expand Down
16 changes: 12 additions & 4 deletions cli/rm.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ package main

import (
"context"
"errors"
"fmt"
"strings"

"github.com/alibaba/pouch/apis/types"

"github.com/spf13/cobra"
)

var rmDescription = `
Remove a container object in Pouchd.
Remove one or more container objects in Pouchd.
If a container be stopped or created, you can remove it.
If the container be running, you can also remove it with flag force.
When the container be removed, the all resource of the container will
If the container is running, you can also remove it with flag force.
When the container is removed, the all resources of the container will
be released.
`

Expand Down Expand Up @@ -58,13 +60,19 @@ func (r *RmCommand) runRm(args []string) error {
Volumes: r.removeVolumes,
}

var errs []string
for _, name := range args {
if err := apiClient.ContainerRemove(ctx, name, options); err != nil {
return fmt.Errorf("failed to remove container: %v", err)
errs = append(errs, err.Error())
continue
}
fmt.Printf("%s\n", name)
}

if len(errs) > 0 {
return errors.New(strings.Join(errs, "\n"))
}

return nil
}

Expand Down
11 changes: 10 additions & 1 deletion cli/rmi.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package main

import (
"context"
"errors"
"fmt"
"strings"

"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -43,12 +45,19 @@ func (rmi *RmiCommand) runRmi(args []string) error {
ctx := context.Background()
apiClient := rmi.cli.Client()

var errs []string
for _, name := range args {
if err := apiClient.ImageRemove(ctx, name, rmi.force); err != nil {
return fmt.Errorf("failed to remove image: %v", err)
errs = append(errs, err.Error())
continue
}
fmt.Printf("%s\n", name)
}

if len(errs) > 0 {
return errors.New("failed to remove images: " + strings.Join(errs, ""))
}

return nil
}

Expand Down
69 changes: 44 additions & 25 deletions cli/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ package main

import (
"context"
"errors"
"fmt"
"io"
"os"
"strings"

"github.com/spf13/cobra"
"golang.org/x/crypto/ssh/terminal"
)

// startDescription is used to describe start command in detail and auto generate command doc.
var startDescription = "Start a created container object in Pouchd. " +
var startDescription = "Start one or more created container objects in Pouchd. " +
"When starting, the relevant resource preserved during creating period comes into use." +
"This is useful when you wish to start a container which has been created in advance." +
"The container you started will be running if no error occurs."

// StartCommand use to implement 'start' command, it start a container.
// StartCommand use to implement 'start' command, it start one or more containers.
type StartCommand struct {
baseCommand
detachKeys string
Expand All @@ -29,9 +31,9 @@ func (s *StartCommand) Init(c *Cli) {
s.cli = c
s.cmd = &cobra.Command{
Use: "start [OPTIONS] CONTAINER",
Short: "Start a created or stopped container",
Short: "Start one or more created or stopped containers",
Long: startDescription,
Args: cobra.ExactArgs(1),
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return s.runStart(args)
},
Expand All @@ -50,14 +52,17 @@ func (s *StartCommand) addFlags() {

// runStart is the entry of start command.
func (s *StartCommand) runStart(args []string) error {
container := args[0]

// attach to io.
ctx := context.Background()
apiClient := s.cli.Client()

var wait chan struct{}
// attach to io.
if s.attach || s.stdin {
var wait chan struct{}
// We're going to attach to a container, we should make sure we only have one container.
if len(args) > 1 {
return fmt.Errorf("cannot start and attach multiple containers at once.")
}

in, out, err := setRawMode(s.stdin, false)
if err != nil {
return fmt.Errorf("failed to set raw mode")
Expand All @@ -68,6 +73,7 @@ func (s *StartCommand) runStart(args []string) error {
}
}()

container := args[0]
conn, br, err := apiClient.ContainerAttach(ctx, container, s.stdin)
if err != nil {
return fmt.Errorf("failed to attach container: %v", err)
Expand All @@ -82,28 +88,41 @@ func (s *StartCommand) runStart(args []string) error {
go func() {
io.Copy(conn, os.Stdin)
}()
}

// start container
if err := apiClient.ContainerStart(ctx, container, s.detachKeys); err != nil {
return fmt.Errorf("failed to start container %s: %v", container, err)
}
// start container
if err := apiClient.ContainerStart(ctx, container, s.detachKeys); err != nil {
return fmt.Errorf("failed to start container %s: %v", container, err)
}

// wait the io to finish.
if s.attach || s.stdin {
<-wait
}
// wait the io to finish.
if s.attach || s.stdin {
<-wait
}

info, err := apiClient.ContainerGet(ctx, container)
if err != nil {
return err
}
info, err := apiClient.ContainerGet(ctx, container)
if err != nil {
return err
}

code := info.State.ExitCode
if code != 0 {
return ExitError{Code: int(code)}
}
code := info.State.ExitCode
if code != 0 {
return ExitError{Code: int(code)}
}
} else {
// We're not going to attach to any container, so we just start as many containers as we want.
var errs []string
for _, name := range args {
if err := apiClient.ContainerStart(ctx, name, s.detachKeys); err != nil {
errs = append(errs, err.Error())
continue
}
fmt.Printf("%s\n", name)
}

if len(errs) > 0 {
return errors.New("failed to start containers: " + strings.Join(errs, ""))
}
}
return nil
}

Expand Down
26 changes: 18 additions & 8 deletions cli/unpause.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ package main

import (
"context"
"errors"
"fmt"
"strings"

"github.com/spf13/cobra"
)

// unpauseDescription is used to describe unpause command in detail and auto generate command doc.
var unpauseDescription = "Unpause a paused container in Pouchd. " +
var unpauseDescription = "Unpause one or more paused containers in Pouchd. " +
"when unpausing, the paused container will resumes the process execution within the container." +
"The container you unpaused will be running again if no error occurs."

// UnpauseCommand use to implement 'unpause' command, it unpauses a container.
// UnpauseCommand use to implement 'unpause' command, it unpauses one or more containers.
type UnpauseCommand struct {
baseCommand
}
Expand All @@ -21,10 +23,10 @@ type UnpauseCommand struct {
func (p *UnpauseCommand) Init(c *Cli) {
p.cli = c
p.cmd = &cobra.Command{
Use: "unpause CONTAINER",
Short: "Unpause a paused container",
Use: "unpause CONTAINER [CONTAINER...]",
Short: "Unpause one or more paused container",
Long: unpauseDescription,
Args: cobra.ExactArgs(1),
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return p.runUnpause(args)
},
Expand All @@ -37,11 +39,19 @@ func (p *UnpauseCommand) runUnpause(args []string) error {
ctx := context.Background()
apiClient := p.cli.Client()

container := args[0]
var errs []string
for _, name := range args {
if err := apiClient.ContainerUnpause(ctx, name); err != nil {
errs = append(errs, err.Error())
continue
}
fmt.Printf("%s\n", name)
}

if err := apiClient.ContainerUnpause(ctx, container); err != nil {
return fmt.Errorf("failed to unpause container %s: %v", container, err)
if len(errs) > 0 {
return errors.New(strings.Join(errs, "\n"))
}

return nil
}

Expand Down
21 changes: 21 additions & 0 deletions test/cli_restart_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,24 @@ func (suite *PouchRestartSuite) TestPouchRestartPausedContainer(c *check.C) {

command.PouchRun("restart", name).Assert(c, icmd.Success)
}

// TestPouchRestartMultiContainers is to verify the correctness of restarting more than one running container.
func (suite *PouchRestartSuite) TestPouchRestartMultiContainers(c *check.C) {
name1 := "TestPouchRestartMultiContainer-1"
name2 := "TestPouchRestartMultiContainer-2"

res1 := command.PouchRun("run", "-d", "--cpu-share", "20", "--name", name1, busyboxImage)
defer DelContainerForceMultyTime(c, name1)
res1.Assert(c, icmd.Success)

res2 := command.PouchRun("run", "-d", "--cpu-share", "20", "--name", name2, busyboxImage)
defer DelContainerForceMultyTime(c, name2)
res2.Assert(c, icmd.Success)

res := command.PouchRun("restart", "-t", "1", name1, name2)
res.Assert(c, icmd.Success)

if out := res.Combined(); !strings.Contains(out, name1) || !strings.Contains(out, name2) {
c.Fatalf("unexpected output: %s, expected: %s\n%s", out, name1, name2)
}
}
Loading

0 comments on commit 95942db

Please sign in to comment.