Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: skeleton of upgrade interface #852

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions apis/server/container_bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,24 @@ func (s *Server) updateContainer(ctx context.Context, rw http.ResponseWriter, re
rw.WriteHeader(http.StatusOK)
return nil
}

func (s *Server) upgradeContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error {
config := &types.ContainerUpgradeConfig{}
// decode request body
if err := json.NewDecoder(req.Body).Decode(config); err != nil {
return httputils.NewHTTPError(err, http.StatusBadRequest)
}
// validate request body
if err := config.Validate(strfmt.NewFormats()); err != nil {
return httputils.NewHTTPError(err, http.StatusBadRequest)
}

name := mux.Vars(req)["name"]

if err := s.ContainerMgr.Upgrade(ctx, name, config); err != nil {
return err
}

rw.WriteHeader(http.StatusOK)
return nil
}
1 change: 1 addition & 0 deletions apis/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func initRoute(s *Server) http.Handler {
r.Path(versionMatcher + "/containers/{name:.*}/pause").Methods(http.MethodPost).Handler(s.filter(s.pauseContainer))
r.Path(versionMatcher + "/containers/{name:.*}/unpause").Methods(http.MethodPost).Handler(s.filter(s.unpauseContainer))
r.Path(versionMatcher + "/containers/{name:.*}/update").Methods(http.MethodPost).Handler(s.filter(s.updateContainer))
r.Path(versionMatcher + "/containers/{name:.*}/upgrade").Methods(http.MethodPost).Handler(s.filter(s.upgradeContainer))

// image
r.Path(versionMatcher + "/images/create").Methods(http.MethodPost).Handler(s.filter(s.pullImage))
Expand Down
34 changes: 34 additions & 0 deletions apis/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,28 @@ paths:
500:
$ref: "#/responses/500ErrorResponse"
tags: ["Container"]
/containers/{id}/upgrade:
post:
summary: "Upgrade a container with new image and args"
operationId: "ContainerUpgrade"
parameters:
- $ref: "#/parameters/id"
- name: "upgradeConfig"
in: "body"
schema:
$ref: "#/definitions/ContainerUpgradeConfig"
responses:
200:
description: "no error"
400:
description: "bad parameter"
schema:
$ref: "#/definitions/Error"
404:
$ref: "#/responses/404ErrorResponse"
500:
$ref: "#/responses/500ErrorResponse"
tags: ["Container"]

/volumes:
get:
Expand Down Expand Up @@ -1365,6 +1387,18 @@ definitions:
additionalProperties:
type: "string"

ContainerUpgradeConfig:
description: |
ContainerUpgradeConfig is used for API "POST /containers/upgrade".
It wraps all kinds of config used in container upgrade.
It can be used to encode client params in client and unmarshal request body in daemon side.
allOf:
- $ref: "#/definitions/ContainerConfig"
- type: "object"
properties:
HostConfig:
$ref: "#/definitions/HostConfig"

Resources:
description: "A container's resources (cgroups config, ulimits, etc)"
type: "object"
Expand Down
104 changes: 104 additions & 0 deletions apis/types/container_upgrade_config.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func main() {
cli.AddCommand(base, &LoginCommand{})
cli.AddCommand(base, &UpdateCommand{})
cli.AddCommand(base, &LogoutCommand{})
cli.AddCommand(base, &UpgradeCommand{})

// add generate doc command
cli.AddCommand(base, &GenDocCommand{})
Expand Down
70 changes: 70 additions & 0 deletions cli/upgrade.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package main

import (
"context"
"fmt"

"github.com/spf13/cobra"
)

// upgradeDescription is used to describe upgrade command in detail and auto generate command doc.
var upgradeDescription = ""

// UpgradeCommand use to implement 'upgrade' command, it is used to upgrade a container.
type UpgradeCommand struct {
baseCommand
*container
}

// Init initialize upgrade command.
func (ug *UpgradeCommand) Init(c *Cli) {
ug.cli = c
ug.cmd = &cobra.Command{
Use: "upgrade [OPTIONS] IMAGE [COMMAND] [ARG...]",
Short: "Upgrade a container with new image and args",
Long: upgradeDescription,
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
return ug.runUpgrade(args)
},
Example: upgradeExample(),
}
ug.addFlags()
}

// addFlags adds flags for specific command.
func (ug *UpgradeCommand) addFlags() {
flagSet := ug.cmd.Flags()
flagSet.SetInterspersed(false)

c := addCommonFlags(flagSet)
ug.container = c
}

// runUpgrade is the entry of UpgradeCommand command.
func (ug *UpgradeCommand) runUpgrade(args []string) error {
config, err := ug.config()
if err != nil {
return fmt.Errorf("failed to upgrade container: %v", err)
}

config.Image = args[0]
if len(args) > 1 {
config.Cmd = args[1:]
}
containerName := ug.name
if containerName == "" {
return fmt.Errorf("failed to upgrade container: must specify container name")
}

ctx := context.Background()
apiClient := ug.cli.Client()

// TODO if error is image not found, we can pull image, and retry upgrade
return apiClient.ContainerUpgrade(ctx, containerName, config.ContainerConfig, config.HostConfig)
}

//upgradeExample shows examples in exec command, and is used in auto-generated cli docs.
func upgradeExample() string {
return ""
}
5 changes: 5 additions & 0 deletions client/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,8 @@ func (client *APIClient) ContainerUpdate(ctx context.Context, name string, confi
return err

}

// ContainerUpgrade upgrade a container with new image and args.
func (client *APIClient) ContainerUpgrade(ctx context.Context, name string, config types.ContainerConfig, hostConfig *types.HostConfig) error {
return nil
}
1 change: 1 addition & 0 deletions client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type ContainerAPIClient interface {
ContainerPause(ctx context.Context, name string) error
ContainerUnpause(ctx context.Context, name string) error
ContainerUpdate(ctx context.Context, name string, config *types.UpdateConfig) error
ContainerUpgrade(ctx context.Context, name string, config types.ContainerConfig, hostConfig *types.HostConfig) error
}

// ImageAPIClient defines methods of Image client.
Expand Down
9 changes: 9 additions & 0 deletions daemon/mgr/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ type ContainerMgr interface {

// Update updates the configurations of a container.
Update(ctx context.Context, name string, config *types.UpdateConfig) error

// Upgrade upgrades a container with new image and args.
Upgrade(ctx context.Context, name string, config *types.ContainerUpgradeConfig) error
}

// ContainerManager is the default implement of interface ContainerMgr.
Expand Down Expand Up @@ -788,6 +791,12 @@ func (mgr *ContainerManager) Update(ctx context.Context, name string, config *ty
return nil
}

// Upgrade upgrades a container with new image and args.
func (mgr *ContainerManager) Upgrade(ctx context.Context, name string, config *types.ContainerUpgradeConfig) error {
// TODO
return nil
}

func (mgr *ContainerManager) openContainerIO(id string, attach *AttachConfig) (*containerio.IO, error) {
return mgr.openIO(id, attach, false)
}
Expand Down
19 changes: 19 additions & 0 deletions test/api_container_upgrade_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package main

import (
"github.com/alibaba/pouch/test/environment"

"github.com/go-check/check"
)

// APIContainerUpgradeSuite is the test suite for container upgrade API.
type APIContainerUpgradeSuite struct{}

func init() {
check.Suite(&APIContainerUpgradeSuite{})
}

// SetUpTest does common setup in the beginning of each test.
func (suite *APIContainerUpgradeSuite) SetUpTest(c *check.C) {
SkipIfFalse(c, environment.IsLinux)
}
31 changes: 31 additions & 0 deletions test/cli_upgrade_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
//"github.com/alibaba/pouch/apis/types"
"github.com/alibaba/pouch/test/command"
"github.com/alibaba/pouch/test/environment"

"github.com/go-check/check"
"github.com/gotestyourself/gotestyourself/icmd"
)

// PouchUpgradeSuite is the test suite for upgrade CLI.
type PouchUpgradeSuite struct{}

func init() {
check.Suite(&PouchUpgradeSuite{})
}

// SetUpSuite does common setup in the beginning of each test suite.
func (suite *PouchUpgradeSuite) SetUpSuite(c *check.C) {
SkipIfFalse(c, environment.IsLinux)

environment.PruneAllContainers(apiClient)

command.PouchRun("pull", busyboxImage).Assert(c, icmd.Success)
}

// TearDownTest does cleanup work in the end of each test.
func (suite *PouchUpgradeSuite) TeadDownTest(c *check.C) {
// TODO
}