From 267716256cc67d9c410514ec6d4c55405d82f419 Mon Sep 17 00:00:00 2001 From: zeppp Date: Sat, 2 Dec 2017 17:26:19 +0800 Subject: [PATCH] feature:add pouch rename --- apis/server/container_bridge.go | 12 ++++++++ apis/server/router.go | 1 + apis/swagger.yml | 31 +++++++++++++++++++ cli/main.go | 1 + cli/rename.go | 54 +++++++++++++++++++++++++++++++++ client/container.go | 11 +++++++ daemon/mgr/container.go | 29 ++++++++++++++++++ 7 files changed, 139 insertions(+) create mode 100644 cli/rename.go diff --git a/apis/server/container_bridge.go b/apis/server/container_bridge.go index 43a8728a0..78b2011a3 100644 --- a/apis/server/container_bridge.go +++ b/apis/server/container_bridge.go @@ -20,6 +20,18 @@ func (s *Server) removeContainers(ctx context.Context, resp http.ResponseWriter, return nil } +func (s *Server) renameContainer(ctx context.Context, resp http.ResponseWriter, req *http.Request) error { + id := mux.Vars(req)["id"] + name := req.FormValue("name") + + if err := s.ContainerMgr.Rename(ctx, id, name); err != nil { + return err + } + + resp.WriteHeader(http.StatusNoContent) + return nil +} + func (s *Server) createContainerExec(ctx context.Context, resp http.ResponseWriter, req *http.Request) error { name := mux.Vars(req)["name"] diff --git a/apis/server/router.go b/apis/server/router.go index 154199780..44f891e95 100644 --- a/apis/server/router.go +++ b/apis/server/router.go @@ -33,6 +33,7 @@ func initRoute(s *Server) http.Handler { r.Path("/containers/{name:.*}").Methods(http.MethodDelete).Handler(s.filter(s.removeContainers)) r.Path("/containers/{name:.*}/exec").Methods(http.MethodPost).Handler(s.filter(s.createContainerExec)) r.Path("/exec/{name:.*}/start").Methods(http.MethodPost).Handler(s.filter(s.startContainerExec)) + r.Path("/containers/{name:.*}/rename").Methods(http.MethodPost).Handler(s.filter(s.renameContainer)) // image r.Path("/images/create").Methods(http.MethodPost).Handler(s.filter(s.pullImage)) diff --git a/apis/swagger.yml b/apis/swagger.yml index f0c11d1c7..e7557f801 100644 --- a/apis/swagger.yml +++ b/apis/swagger.yml @@ -267,6 +267,37 @@ paths: description: "Server error" schema: $ref: "#/definitions/Error" + /containers/{id}/rename: + post: + summary: "Rename a container" + operationId: "ContainerRename" + parameters: + - name: "id" + in: "path" + required: true + description: "ID or name of the container" + type: "string" + - name: "name" + in: "query" + required: true + description: "New name for the container" + type: "string" + responses: + 204: + description: "no error" + 404: + description: "no such container" + schema: + $ref: "#/definitions/Error" + 409: + description: "name already in use" + schema: + $ref: "#/definitions/Error" + 500: + description: "server error" + schema: + $ref: "#/definitions/Error" + tags: ["Container"] /volumes: get: diff --git a/cli/main.go b/cli/main.go index 2eb3d9bb9..6fd790b17 100644 --- a/cli/main.go +++ b/cli/main.go @@ -24,6 +24,7 @@ func main() { cli.AddCommand(base, &ImageCommand{}) cli.AddCommand(base, &VolumeCommand{}) cli.AddCommand(base, &InspectCommand{}) + cli.AddCommand(base, &RenameCommand{}) // add generate doc command cli.AddCommand(base, &GenDocCommand{}) diff --git a/cli/rename.go b/cli/rename.go new file mode 100644 index 000000000..f0249e60b --- /dev/null +++ b/cli/rename.go @@ -0,0 +1,54 @@ +package main + +import ( + "github.com/spf13/cobra" +) + +// renameDescription is used to describe rename command in detail and auto generate command doc. +var renameDescription = "Rename a container object in Pouchd. " + + "You can change the name of one container identified by it's name or ID. " + + "The container you renamed is ready to be used by it's new name." + +// RenameCommand uses to implement 'rename' command, it renames a container. +type RenameCommand struct { + baseCommand +} + +// Init initialize rename command. +func (rc *RenameCommand) Init(c *Cli) { + rc.cli = c + + rc.cmd = &cobra.Command{ + Use: "rename [container] [newName]", + Short: "Rename a container with newName", + Long: renameDescription, + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + return rc.runRename(args) + }, + Example: renameExample(), + } +} + +// runRename is the entry of rename command. +func (rc *RenameCommand) runRename(args []string) error { + apiClient := rc.cli.Client() + container := args[0] + newName := args[1] + + err := apiClient.ContainerRename(container, newName) + + return err +} + +// renameExample shows examples in rename command, and is used in auto-generated cli docs. +func renameExample() string { + return `$ pouch ps +Name ID Status Image +foo 71b9c1 Running docker.io/library/busybox:latest +$ pouch rename foo newName +$ pouch ps +Name ID Status Image +newName 71b9c1 Running docker.io/library/busybox:latest +` +} diff --git a/client/container.go b/client/container.go index 079bb2125..63713b13a 100644 --- a/client/container.go +++ b/client/container.go @@ -120,3 +120,14 @@ func (client *APIClient) ContainerGet(name string) (*types.ContainerJSON, error) return &container, err } + +// ContainerRename renames a container. +func (client *APIClient) ContainerRename(id string, name string) error { + q := url.Values{} + q.Add("name", name) + + resp, err := client.post("/containers/"+id+"/rename", q, nil) + ensureCloseReader(resp) + + return err +} diff --git a/daemon/mgr/container.go b/daemon/mgr/container.go index 338c8f9a4..dbb3ecca2 100644 --- a/daemon/mgr/container.go +++ b/daemon/mgr/container.go @@ -49,6 +49,9 @@ type ContainerMgr interface { // Remove removes a container, it may be running or stopped and so on. Remove(ctx context.Context, name string, option *ContainerRemoveOption) error + // Rename renames a container + Rename(ctx context.Context, id string, name string) error + // Get the detailed information of container Get(s string) (*types.ContainerInfo, error) } @@ -376,6 +379,32 @@ func (cm *ContainerManager) Get(s string) (*types.ContainerInfo, error) { return cm.containerInfo(s) } +// Rename renames a container +func (cm *ContainerManager) Rename(ctx context.Context, id string, name string) error { + var ( + ci *types.ContainerInfo + err error + ) + + if cm.NameToID.Get(name).Exist() { + return httputils.NewHTTPError(errors.New("The newName already exists"), 409) + } + + if ci, err = cm.containerInfo(id); err != nil { + return errors.Wrap(err, "failed to rename container") + } + + cm.km.Lock(ci.ID) + defer cm.km.Unlock(ci.ID) + + cm.NameToID.Remove(id) + cm.NameToID.Put(name, ci.ID) + ci.Name = name + cm.Store.Put(ci) + + return nil +} + // containerInfo returns the 'ContainerInfo' object, the parameter 's' may be container's // name, id or prefix id. func (cm *ContainerManager) containerInfo(s string) (*types.ContainerInfo, error) {