From 5de6fa83c04dae321c7b04d8ef02595582b3e4d4 Mon Sep 17 00:00:00 2001 From: Michael Wan Date: Tue, 20 Mar 2018 10:11:44 -0400 Subject: [PATCH] feature: finish resize interface Signed-off-by: Michael Wan --- apis/server/container_bridge.go | 15 +++++--- client/container.go | 7 ++-- client/interface.go | 2 +- ctrd/container.go | 16 ++++++++ daemon/mgr/container.go | 15 +++++++- test/api_container_resize.go | 65 ++++++++++++++++++++++++++++++++- 6 files changed, 107 insertions(+), 13 deletions(-) diff --git a/apis/server/container_bridge.go b/apis/server/container_bridge.go index 04766e56d..c15208f3e 100644 --- a/apis/server/container_bridge.go +++ b/apis/server/container_bridge.go @@ -367,16 +367,21 @@ func (s *Server) logsContainer(ctx context.Context, rw http.ResponseWriter, req } func (s *Server) resizeContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - opts := types.ResizeOptions{} - // decode request body - if err := json.NewDecoder(req.Body).Decode(opts); err != nil { + height, err := strconv.Atoi(req.FormValue("h")) + if err != nil { return httputils.NewHTTPError(err, http.StatusBadRequest) } - // validate request body - if err := opts.Validate(strfmt.NewFormats()); err != nil { + + width, err := strconv.Atoi(req.FormValue("w")) + if err != nil { return httputils.NewHTTPError(err, http.StatusBadRequest) } + opts := types.ResizeOptions{ + Height: int64(height), + Width: int64(width), + } + name := mux.Vars(req)["name"] if err := s.ContainerMgr.Resize(ctx, name, opts); err != nil { diff --git a/client/container.go b/client/container.go index fe33047c2..e2ff214de 100644 --- a/client/container.go +++ b/client/container.go @@ -6,7 +6,6 @@ import ( "io" "net" "net/url" - "strconv" "strings" "github.com/alibaba/pouch/apis/types" @@ -256,10 +255,10 @@ func (client *APIClient) ContainerLogs(ctx context.Context, name string, options } // ContainerResize resizes the size of container tty. -func (client *APIClient) ContainerResize(ctx context.Context, name string, opts types.ResizeOptions) error { +func (client *APIClient) ContainerResize(ctx context.Context, name, height, width string) error { query := url.Values{} - query.Set("h", strconv.Itoa(int(opts.Height))) - query.Set("w", strconv.Itoa(int(opts.Width))) + query.Set("h", height) + query.Set("w", width) resp, err := client.post(ctx, "/containers/"+name+"/resize", query, nil, nil) ensureCloseReader(resp) diff --git a/client/interface.go b/client/interface.go index 9fa8c07e1..f247f97f1 100644 --- a/client/interface.go +++ b/client/interface.go @@ -37,7 +37,7 @@ type ContainerAPIClient interface { ContainerUpgrade(ctx context.Context, name string, config types.ContainerConfig, hostConfig *types.HostConfig) error ContainerTop(ctx context.Context, name string, arguments []string) (types.ContainerProcessList, error) ContainerLogs(ctx context.Context, name string, options types.ContainerLogsOptions) (io.ReadCloser, error) - ContainerResize(ctx context.Context, name string, options types.ResizeOptions) error + ContainerResize(ctx context.Context, name, height, width string) error } // ImageAPIClient defines methods of Image client. diff --git a/ctrd/container.go b/ctrd/container.go index 1efe82ed7..9535718f3 100644 --- a/ctrd/container.go +++ b/ctrd/container.go @@ -469,3 +469,19 @@ func (c *Client) GetPidsForContainer(ctx context.Context, id string) ([]int, err } return pids, nil } + +// ResizeContainer changes the size of the TTY of the init process running +// in the container to the given height and width. +func (c *Client) ResizeContainer(ctx context.Context, id string, opts types.ResizeOptions) error { + if !c.lock.Trylock(id) { + return errtypes.ErrLockfailed + } + defer c.lock.Unlock(id) + + pack, err := c.watch.get(id) + if err != nil { + return err + } + + return pack.task.Resize(ctx, uint32(opts.Height), uint32(opts.Width)) +} diff --git a/daemon/mgr/container.go b/daemon/mgr/container.go index 97011cf0b..d1090b15f 100644 --- a/daemon/mgr/container.go +++ b/daemon/mgr/container.go @@ -867,8 +867,19 @@ func (mgr *ContainerManager) Top(ctx context.Context, name string, psArgs string // Resize resizes the size of a container tty. func (mgr *ContainerManager) Resize(ctx context.Context, name string, opts types.ResizeOptions) error { - // TODO - return nil + c, err := mgr.container(name) + if err != nil { + return err + } + + c.Lock() + defer c.Unlock() + + if !c.IsRunning() && !c.IsPaused() { + return fmt.Errorf("failed to resize container %s: container is not running", c.ID()) + } + + return mgr.Client.ResizeContainer(ctx, c.ID(), opts) } func (mgr *ContainerManager) openContainerIO(id string, attach *AttachConfig) (*containerio.IO, error) { diff --git a/test/api_container_resize.go b/test/api_container_resize.go index 2699f0593..96f782ca8 100644 --- a/test/api_container_resize.go +++ b/test/api_container_resize.go @@ -1,7 +1,10 @@ package main import ( + "net/url" + "github.com/alibaba/pouch/test/environment" + "github.com/alibaba/pouch/test/request" "github.com/go-check/check" ) @@ -19,4 +22,64 @@ func (suite *APIContainerResizeSuite) SetUpTest(c *check.C) { } -// TODO add test case. +// TestContainerResizeOk is to verify resize container. +func (suite *APIContainerResizeSuite) TestContainerResizeOk(c *check.C) { + cname := "TestContainerResizeOk" + + CreateBusyboxContainerOk(c, cname) + + resp, err := request.Post("/containers/" + cname + "/start") + c.Assert(err, check.IsNil) + CheckRespStatus(c, resp, 204) + + q := url.Values{} + q.Add("h", "10") + q.Add("w", "10") + query := request.WithQuery(q) + + resp, err = request.Post("/containers/"+cname+"/resize", query) + c.Assert(err, check.IsNil) + CheckRespStatus(c, resp, 200) + + DelContainerForceOk(c, cname) +} + +// TestContainerResizeWithInvalidSize is to verify resize container with invalid size. +func (suite *APIContainerResizeSuite) TestContainerResizeWithInvalidSize(c *check.C) { + cname := "TestContainerResizeWithInvalidSize" + + CreateBusyboxContainerOk(c, cname) + + resp, err := request.Post("/containers/" + cname + "/start") + c.Assert(err, check.IsNil) + CheckRespStatus(c, resp, 204) + + q := url.Values{} + q.Add("h", "hi") + q.Add("w", "wo") + query := request.WithQuery(q) + + resp, err = request.Post("/containers/"+cname+"/resize", query) + c.Assert(err, check.IsNil) + CheckRespStatus(c, resp, 400) + + DelContainerForceOk(c, cname) +} + +// TestResizeStoppedContainer is to verify resize a stopped container. +func (suite *APIContainerResizeSuite) TestResizeStoppedContainer(c *check.C) { + cname := "TestResizeStoppedContainer" + + CreateBusyboxContainerOk(c, cname) + + q := url.Values{} + q.Add("h", "10") + q.Add("w", "10") + query := request.WithQuery(q) + + resp, err := request.Post("/containers/"+cname+"/resize", query) + c.Assert(err, check.IsNil) + CheckRespStatus(c, resp, 500) + + DelContainerForceOk(c, cname) +}