From 8ff99bf3122429fa3c44e702e8d1c92866d02867 Mon Sep 17 00:00:00 2001 From: Allen Sun Date: Thu, 10 May 2018 16:24:44 +0800 Subject: [PATCH] refactor: reorder function sequence to make it more reasonable Signed-off-by: Allen Sun --- apis/server/container_bridge.go | 336 +++++++++++--------------- apis/server/exec_bridge.go | 83 +++++++ apis/server/image_bridge.go | 22 +- apis/server/network_bridge.go | 26 +- apis/server/volume_bridge.go | 20 +- daemon/mgr/container.go | 404 ++++++++++++-------------------- daemon/mgr/container_exec.go | 131 +++++++++++ daemon/mgr/image.go | 154 ++++++------ daemon/mgr/network.go | 142 +++++------ daemon/mgr/volume.go | 54 ++--- 10 files changed, 706 insertions(+), 666 deletions(-) create mode 100644 apis/server/exec_bridge.go create mode 100644 daemon/mgr/container_exec.go diff --git a/apis/server/container_bridge.go b/apis/server/container_bridge.go index 067520dbe..9386591dc 100644 --- a/apis/server/container_bridge.go +++ b/apis/server/container_bridge.go @@ -20,169 +20,155 @@ import ( "github.com/sirupsen/logrus" ) -func (s *Server) removeContainers(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - name := mux.Vars(req)["name"] - - option := &types.ContainerRemoveOptions{ - Force: httputils.BoolValue(req, "force"), - Volumes: httputils.BoolValue(req, "v"), - // TODO: Link will be supported in the future. - Link: httputils.BoolValue(req, "link"), +func (s *Server) createContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + config := &types.ContainerCreateConfig{} + reader := req.Body + var ex error + if s.ContainerPlugin != nil { + logrus.Infof("invoke container pre-create hook in plugin") + if reader, ex = s.ContainerPlugin.PreCreate(req.Body); ex != nil { + return errors.Wrapf(ex, "pre-create plugin point execute failed") + } } - - if err := s.ContainerMgr.Remove(ctx, name, option); err != nil { - return err + // decode request body + if err := json.NewDecoder(reader).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) } - rw.WriteHeader(http.StatusNoContent) - return nil -} + name := req.FormValue("name") -func (s *Server) renameContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - oldName := mux.Vars(req)["name"] - newName := req.FormValue("name") + // to do compensation to potential nil pointer after validation + if config.HostConfig == nil { + config.HostConfig = &types.HostConfig{} + } + if config.NetworkingConfig == nil { + config.NetworkingConfig = &types.NetworkingConfig{} + } - if err := s.ContainerMgr.Rename(ctx, oldName, newName); err != nil { + container, err := s.ContainerMgr.Create(ctx, name, config) + if err != nil { return err } - rw.WriteHeader(http.StatusNoContent) - return nil + return EncodeResponse(rw, http.StatusCreated, container) } -func (s *Server) restartContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - var ( - t int - err error - ) - - if v := req.FormValue("t"); v != "" { - if t, err = strconv.Atoi(v); err != nil { - return httputils.NewHTTPError(err, http.StatusBadRequest) - } - } - +func (s *Server) getContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { name := mux.Vars(req)["name"] - if err = s.ContainerMgr.Restart(ctx, name, int64(t)); err != nil { + meta, err := s.ContainerMgr.Get(ctx, name) + if err != nil { return err } - rw.WriteHeader(http.StatusNoContent) - return nil -} - -func (s *Server) createContainerExec(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - config := &types.ExecCreateConfig{} - // 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) + container := types.ContainerJSON{ + ID: meta.ID, + Name: meta.Name, + Image: meta.Config.Image, + Created: meta.Created, + State: meta.State, + Config: meta.Config, + HostConfig: meta.HostConfig, + Snapshotter: meta.Snapshotter, + GraphDriver: &types.GraphDriverData{ + Name: meta.Snapshotter.Name, + Data: meta.Snapshotter.Data, + }, } - name := mux.Vars(req)["name"] - - id, err := s.ContainerMgr.CreateExec(ctx, name, config) - if err != nil { - return err + if meta.NetworkSettings != nil { + container.NetworkSettings = &types.NetworkSettings{ + Networks: meta.NetworkSettings.Networks, + } } - execCreateResp := &types.ExecCreateResp{ - ID: id, + container.Mounts = []types.MountPoint{} + for _, mp := range meta.Mounts { + container.Mounts = append(container.Mounts, *mp) } - return EncodeResponse(rw, http.StatusCreated, execCreateResp) + return EncodeResponse(rw, http.StatusOK, container) } -func (s *Server) startContainerExec(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - config := &types.ExecStartConfig{} - // decode request body - if err := json.NewDecoder(req.Body).Decode(config); err != nil { - return httputils.NewHTTPError(err, http.StatusBadRequest) +func (s *Server) getContainers(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + option := &mgr.ContainerListOption{ + All: httputils.BoolValue(req, "all"), } - // validate request body - if err := config.Validate(strfmt.NewFormats()); err != nil { - return httputils.NewHTTPError(err, http.StatusBadRequest) + + metas, err := s.ContainerMgr.List(ctx, func(meta *mgr.ContainerMeta) bool { + return true + }, option) + if err != nil { + return err } - name := mux.Vars(req)["name"] - _, upgrade := req.Header["Upgrade"] + containerList := make([]types.Container, 0, len(metas)) - var attach *mgr.AttachConfig + for _, m := range metas { + status, err := m.FormatStatus() + if err != nil { + return err + } - if !config.Detach { - hijacker, ok := rw.(http.Hijacker) - if !ok { - return fmt.Errorf("not a hijack connection, container: %s", name) + t, err := time.Parse(utils.TimeLayout, m.Created) + if err != nil { + return err } - attach = &mgr.AttachConfig{ - Hijack: hijacker, - Stdin: config.Tty, - Stdout: true, - Stderr: true, - Upgrade: upgrade, + container := types.Container{ + ID: m.ID, + Names: []string{m.Name}, + Image: m.Config.Image, + Command: strings.Join(m.Config.Cmd, " "), + Status: status, + Created: t.UnixNano(), + Labels: m.Config.Labels, + HostConfig: m.HostConfig, } - } - return s.ContainerMgr.StartExec(ctx, name, config, attach) -} + if m.NetworkSettings != nil { + container.NetworkSettings = &types.ContainerNetworkSettings{ + Networks: m.NetworkSettings.Networks, + } + } -func (s *Server) getExecInfo(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - name := mux.Vars(req)["name"] - execInfo, err := s.ContainerMgr.InspectExec(ctx, name) - if err != nil { - return err + containerList = append(containerList, container) } - return EncodeResponse(rw, http.StatusOK, execInfo) + return EncodeResponse(rw, http.StatusOK, containerList) } -func (s *Server) createContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - config := &types.ContainerCreateConfig{} - reader := req.Body - var ex error - if s.ContainerPlugin != nil { - logrus.Infof("invoke container pre-create hook in plugin") - if reader, ex = s.ContainerPlugin.PreCreate(req.Body); ex != nil { - return errors.Wrapf(ex, "pre-create plugin point execute failed") - } - } - // decode request body - if err := json.NewDecoder(reader).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 := req.FormValue("name") +func (s *Server) startContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + name := mux.Vars(req)["name"] - // to do compensation to potential nil pointer after validation - if config.HostConfig == nil { - config.HostConfig = &types.HostConfig{} - } - if config.NetworkingConfig == nil { - config.NetworkingConfig = &types.NetworkingConfig{} - } + detachKeys := req.FormValue("detachKeys") - container, err := s.ContainerMgr.Create(ctx, name, config) - if err != nil { + if err := s.ContainerMgr.Start(ctx, name, detachKeys); err != nil { return err } - return EncodeResponse(rw, http.StatusCreated, container) + rw.WriteHeader(http.StatusNoContent) + return nil } -func (s *Server) startContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - name := mux.Vars(req)["name"] +func (s *Server) restartContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + var ( + t int + err error + ) - detachKeys := req.FormValue("detachKeys") + if v := req.FormValue("t"); v != "" { + if t, err = strconv.Atoi(v); err != nil { + return httputils.NewHTTPError(err, http.StatusBadRequest) + } + } - if err := s.ContainerMgr.Start(ctx, name, detachKeys); err != nil { + name := mux.Vars(req)["name"] + + if err = s.ContainerMgr.Restart(ctx, name, int64(t)); err != nil { return err } @@ -234,6 +220,18 @@ func (s *Server) unpauseContainer(ctx context.Context, rw http.ResponseWriter, r return nil } +func (s *Server) renameContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + oldName := mux.Vars(req)["name"] + newName := req.FormValue("name") + + if err := s.ContainerMgr.Rename(ctx, oldName, newName); err != nil { + return err + } + + rw.WriteHeader(http.StatusNoContent) + return nil +} + func (s *Server) attachContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { name := mux.Vars(req)["name"] @@ -259,90 +257,6 @@ func (s *Server) attachContainer(ctx context.Context, rw http.ResponseWriter, re return nil } -func (s *Server) getContainers(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - option := &mgr.ContainerListOption{ - All: httputils.BoolValue(req, "all"), - } - - metas, err := s.ContainerMgr.List(ctx, func(meta *mgr.ContainerMeta) bool { - return true - }, option) - if err != nil { - return err - } - - containerList := make([]types.Container, 0, len(metas)) - - for _, m := range metas { - status, err := m.FormatStatus() - if err != nil { - return err - } - - t, err := time.Parse(utils.TimeLayout, m.Created) - if err != nil { - return err - } - - container := types.Container{ - ID: m.ID, - Names: []string{m.Name}, - Image: m.Config.Image, - Command: strings.Join(m.Config.Cmd, " "), - Status: status, - Created: t.UnixNano(), - Labels: m.Config.Labels, - HostConfig: m.HostConfig, - } - - if m.NetworkSettings != nil { - container.NetworkSettings = &types.ContainerNetworkSettings{ - Networks: m.NetworkSettings.Networks, - } - } - - containerList = append(containerList, container) - } - return EncodeResponse(rw, http.StatusOK, containerList) -} - -func (s *Server) getContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - name := mux.Vars(req)["name"] - - meta, err := s.ContainerMgr.Get(ctx, name) - if err != nil { - return err - } - - container := types.ContainerJSON{ - ID: meta.ID, - Name: meta.Name, - Image: meta.Config.Image, - Created: meta.Created, - State: meta.State, - Config: meta.Config, - HostConfig: meta.HostConfig, - Snapshotter: meta.Snapshotter, - GraphDriver: &types.GraphDriverData{ - Name: meta.Snapshotter.Name, - Data: meta.Snapshotter.Data, - }, - } - - if meta.NetworkSettings != nil { - container.NetworkSettings = &types.NetworkSettings{ - Networks: meta.NetworkSettings.Networks, - } - } - - container.Mounts = []types.MountPoint{} - for _, mp := range meta.Mounts { - container.Mounts = append(container.Mounts, *mp) - } - - return EncodeResponse(rw, http.StatusOK, container) -} - func (s *Server) updateContainer(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { config := &types.UpdateConfig{} // decode request body @@ -428,3 +342,21 @@ func (s *Server) resizeContainer(ctx context.Context, rw http.ResponseWriter, re rw.WriteHeader(http.StatusOK) return nil } + +func (s *Server) removeContainers(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + name := mux.Vars(req)["name"] + + option := &types.ContainerRemoveOptions{ + Force: httputils.BoolValue(req, "force"), + Volumes: httputils.BoolValue(req, "v"), + // TODO: Link will be supported in the future. + Link: httputils.BoolValue(req, "link"), + } + + if err := s.ContainerMgr.Remove(ctx, name, option); err != nil { + return err + } + + rw.WriteHeader(http.StatusNoContent) + return nil +} diff --git a/apis/server/exec_bridge.go b/apis/server/exec_bridge.go new file mode 100644 index 000000000..87f418fa5 --- /dev/null +++ b/apis/server/exec_bridge.go @@ -0,0 +1,83 @@ +package server + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/alibaba/pouch/apis/types" + "github.com/alibaba/pouch/daemon/mgr" + "github.com/alibaba/pouch/pkg/httputils" + + "github.com/go-openapi/strfmt" + "github.com/gorilla/mux" +) + +func (s *Server) createContainerExec(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + config := &types.ExecCreateConfig{} + // 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"] + + id, err := s.ContainerMgr.CreateExec(ctx, name, config) + if err != nil { + return err + } + + execCreateResp := &types.ExecCreateResp{ + ID: id, + } + + return EncodeResponse(rw, http.StatusCreated, execCreateResp) +} + +func (s *Server) startContainerExec(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + config := &types.ExecStartConfig{} + // 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"] + _, upgrade := req.Header["Upgrade"] + + var attach *mgr.AttachConfig + + if !config.Detach { + hijacker, ok := rw.(http.Hijacker) + if !ok { + return fmt.Errorf("not a hijack connection, container: %s", name) + } + + attach = &mgr.AttachConfig{ + Hijack: hijacker, + Stdin: config.Tty, + Stdout: true, + Stderr: true, + Upgrade: upgrade, + } + } + + return s.ContainerMgr.StartExec(ctx, name, config, attach) +} + +func (s *Server) getExecInfo(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + name := mux.Vars(req)["name"] + execInfo, err := s.ContainerMgr.InspectExec(ctx, name) + if err != nil { + return err + } + return EncodeResponse(rw, http.StatusOK, execInfo) +} diff --git a/apis/server/image_bridge.go b/apis/server/image_bridge.go index 8aace658c..b32ee6b72 100644 --- a/apis/server/image_bridge.go +++ b/apis/server/image_bridge.go @@ -54,17 +54,6 @@ func (s *Server) pullImage(ctx context.Context, rw http.ResponseWriter, req *htt return nil } -func (s *Server) listImages(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - filters := req.FormValue("filters") - - imageList, err := s.ImageMgr.ListImages(ctx, filters) - if err != nil { - logrus.Errorf("failed to list images: %v", err) - return err - } - return EncodeResponse(rw, http.StatusOK, imageList) -} - func (s *Server) getImage(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { idOrRef := mux.Vars(req)["name"] @@ -77,6 +66,17 @@ func (s *Server) getImage(ctx context.Context, rw http.ResponseWriter, req *http return EncodeResponse(rw, http.StatusOK, imageInfo) } +func (s *Server) listImages(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + filters := req.FormValue("filters") + + imageList, err := s.ImageMgr.ListImages(ctx, filters) + if err != nil { + logrus.Errorf("failed to list images: %v", err) + return err + } + return EncodeResponse(rw, http.StatusOK, imageList) +} + func (s *Server) searchImages(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { searchPattern := req.FormValue("term") registry := req.FormValue("registry") diff --git a/apis/server/network_bridge.go b/apis/server/network_bridge.go index d9352e408..9cd211a84 100644 --- a/apis/server/network_bridge.go +++ b/apis/server/network_bridge.go @@ -37,6 +37,19 @@ func (s *Server) createNetwork(ctx context.Context, rw http.ResponseWriter, req return EncodeResponse(rw, http.StatusCreated, networkCreateResp) } +func (s *Server) getNetwork(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + id := mux.Vars(req)["id"] + + network, err := s.NetworkMgr.Get(ctx, id) + if err != nil { + return err + } + + networkResp := buildNetworkInspectResp(network) + + return EncodeResponse(rw, http.StatusOK, networkResp) +} + func (s *Server) listNetwork(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { networks, err := s.NetworkMgr.List(ctx, map[string]string{}) if err != nil { @@ -54,19 +67,6 @@ func (s *Server) listNetwork(ctx context.Context, rw http.ResponseWriter, req *h return EncodeResponse(rw, http.StatusOK, respNetworks) } -func (s *Server) getNetwork(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - id := mux.Vars(req)["id"] - - network, err := s.NetworkMgr.Get(ctx, id) - if err != nil { - return err - } - - networkResp := buildNetworkInspectResp(network) - - return EncodeResponse(rw, http.StatusOK, networkResp) -} - func (s *Server) deleteNetwork(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { id := mux.Vars(req)["id"] diff --git a/apis/server/volume_bridge.go b/apis/server/volume_bridge.go index cf86cc1a0..16b17f133 100644 --- a/apis/server/volume_bridge.go +++ b/apis/server/volume_bridge.go @@ -97,16 +97,6 @@ func (s *Server) getVolume(ctx context.Context, rw http.ResponseWriter, req *htt return EncodeResponse(rw, http.StatusOK, respVolume) } -func (s *Server) removeVolume(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { - name := mux.Vars(req)["name"] - - if err := s.VolumeMgr.Remove(ctx, name); err != nil { - return err - } - rw.WriteHeader(http.StatusNoContent) - return nil -} - func (s *Server) listVolume(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { volumes, err := s.VolumeMgr.List(ctx, map[string]string{}) if err != nil { @@ -138,3 +128,13 @@ func (s *Server) listVolume(ctx context.Context, rw http.ResponseWriter, req *ht } return EncodeResponse(rw, http.StatusOK, respVolumes) } + +func (s *Server) removeVolume(ctx context.Context, rw http.ResponseWriter, req *http.Request) error { + name := mux.Vars(req)["name"] + + if err := s.VolumeMgr.Remove(ctx, name); err != nil { + return err + } + rw.WriteHeader(http.StatusNoContent) + return nil +} diff --git a/daemon/mgr/container.go b/daemon/mgr/container.go index c7fe50843..4235b2616 100644 --- a/daemon/mgr/container.go +++ b/daemon/mgr/container.go @@ -37,22 +37,36 @@ import ( "github.com/magiconair/properties" digest "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) // ContainerMgr as an interface defines all operations against container. +// ContainerMgr's functionality could be divided into three parts: +// 1. regular container management; +// 2. container exec management; +// 3. container network management. type ContainerMgr interface { + // 1. the following functions are related to regular container management + // Create a new container. Create(ctx context.Context, name string, config *types.ContainerCreateConfig) (*types.ContainerCreateResp, error) + // Get the detailed information of container. + Get(ctx context.Context, name string) (*ContainerMeta, error) + + // List returns the list of containers. + List(ctx context.Context, filter ContainerFilter, option *ContainerListOption) ([]*ContainerMeta, error) + // Start a container. Start(ctx context.Context, id, detachKeys string) error // Stop a container. Stop(ctx context.Context, name string, timeout int64) error + // Restart restart a running container. + Restart(ctx context.Context, name string, timeout int64) error + // Pause a container. Pause(ctx context.Context, name string) error @@ -62,30 +76,9 @@ type ContainerMgr interface { // Attach a container. Attach(ctx context.Context, name string, attach *AttachConfig) error - // List returns the list of containers. - List(ctx context.Context, filter ContainerFilter, option *ContainerListOption) ([]*ContainerMeta, error) - - // CreateExec creates exec process's environment. - CreateExec(ctx context.Context, name string, config *types.ExecCreateConfig) (string, error) - - // StartExec executes a new process in container. - StartExec(ctx context.Context, execid string, config *types.ExecStartConfig, attach *AttachConfig) error - - // InspectExec returns low-level information about exec command. - InspectExec(ctx context.Context, execid string) (*types.ContainerExecInspect, error) - - // GetExecConfig returns execonfig of a exec process inside container. - GetExecConfig(ctx context.Context, execid string) (*ContainerExecConfig, error) - - // Remove removes a container, it may be running or stopped and so on. - Remove(ctx context.Context, name string, option *types.ContainerRemoveOptions) error - // Rename renames a container. Rename(ctx context.Context, oldName string, newName string) error - // Get the detailed information of container. - Get(ctx context.Context, name string) (*ContainerMeta, error) - // Update updates the configurations of a container. Update(ctx context.Context, name string, config *types.UpdateConfig) error @@ -98,8 +91,26 @@ type ContainerMgr interface { // Resize resizes the size of container tty. Resize(ctx context.Context, name string, opts types.ResizeOptions) error - // Restart restart a running container. - Restart(ctx context.Context, name string, timeout int64) error + // Remove removes a container, it may be running or stopped and so on. + Remove(ctx context.Context, name string, option *types.ContainerRemoveOptions) error + + // 2. The following five functions is related to containr exec. + + // CreateExec creates exec process's environment. + CreateExec(ctx context.Context, name string, config *types.ExecCreateConfig) (string, error) + + // StartExec executes a new process in container. + StartExec(ctx context.Context, execid string, config *types.ExecStartConfig, attach *AttachConfig) error + + // InspectExec returns low-level information about exec command. + InspectExec(ctx context.Context, execid string) (*types.ContainerExecInspect, error) + + // GetExecConfig returns execonfig of a exec process inside container. + GetExecConfig(ctx context.Context, execid string) (*ContainerExecConfig, error) + + // 3. The following two function is related to network management. + // TODO: inconsistency, Connect/Disconnect operation is in newtork_bridge.go in upper API layer. + // Here we encapsualted them in container manager, inconsistency exists. // Connect is used to connect a container to a network. Connect(ctx context.Context, name string, networkIDOrName string, epConfig *types.EndpointSettings) error @@ -210,170 +221,6 @@ func (mgr *ContainerManager) Restore(ctx context.Context) error { return mgr.Store.ForEach(fn) } -// Remove removes a container, it may be running or stopped and so on. -func (mgr *ContainerManager) Remove(ctx context.Context, name string, options *types.ContainerRemoveOptions) error { - c, err := mgr.container(name) - if err != nil { - return err - } - c.Lock() - defer c.Unlock() - - if !c.IsStopped() && !c.IsExited() && !c.IsCreated() && !options.Force { - return fmt.Errorf("container: %s is not stopped, can't remove it without flag force", c.ID()) - } - - // if the container is running, force to stop it. - if c.IsRunning() && options.Force { - msg, err := mgr.Client.DestroyContainer(ctx, c.ID(), c.StopTimeout()) - if err != nil && !errtypes.IsNotfound(err) { - return errors.Wrapf(err, "failed to destroy container: %s", c.ID()) - } - if err := mgr.markStoppedAndRelease(c, msg); err != nil { - return errors.Wrapf(err, "failed to mark container: %s stop status", c.ID()) - } - } - - if err := mgr.detachVolumes(ctx, c.meta, options.Volumes); err != nil { - logrus.Errorf("failed to detach volume: %v", err) - } - - // remove name - mgr.NameToID.Remove(c.Name()) - - // remove meta data - if err := mgr.Store.Remove(c.meta.Key()); err != nil { - logrus.Errorf("failed to remove container: %s meta store, %v", c.ID(), err) - } - - // remove container cache - mgr.cache.Remove(c.ID()) - - // remove snapshot - if err := mgr.Client.RemoveSnapshot(ctx, c.ID()); err != nil { - logrus.Errorf("failed to remove container: %s snapshot, %v", c.ID(), err) - } - - return nil -} - -// CreateExec creates exec process's meta data. -func (mgr *ContainerManager) CreateExec(ctx context.Context, name string, config *types.ExecCreateConfig) (string, error) { - c, err := mgr.container(name) - if err != nil { - return "", err - } - - if !c.IsRunning() { - return "", fmt.Errorf("container %s is not running", c.ID()) - } - - execid := randomid.Generate() - execConfig := &ContainerExecConfig{ - ExecID: execid, - ExecCreateConfig: *config, - ContainerID: c.ID(), - } - - mgr.ExecProcesses.Put(execid, execConfig) - - return execid, nil -} - -// StartExec executes a new process in container. -func (mgr *ContainerManager) StartExec(ctx context.Context, execid string, config *types.ExecStartConfig, attach *AttachConfig) error { - v, ok := mgr.ExecProcesses.Get(execid).Result() - if !ok { - return errors.Wrap(errtypes.ErrNotfound, "to be exec process: "+execid) - } - execConfig, ok := v.(*ContainerExecConfig) - if !ok { - return fmt.Errorf("invalid exec config type") - } - - if attach != nil { - attach.Stdin = execConfig.AttachStdin - } - - io, err := mgr.openExecIO(execid, attach) - if err != nil { - return err - } - - c, err := mgr.container(execConfig.ContainerID) - if err != nil { - return err - } - - process := &specs.Process{ - Args: execConfig.Cmd, - Terminal: execConfig.Tty, - Cwd: "/", - Env: c.Config().Env, - } - - if execConfig.User != "" { - c.meta.Config.User = execConfig.User - } - - if err = setupUser(ctx, c.meta, &specs.Spec{Process: process}); err != nil { - return err - } - - // set exec process ulimit - if err := setupRlimits(ctx, c.meta.HostConfig, &specs.Spec{Process: process}); err != nil { - return err - } - - execConfig.Running = true - defer func() { - if err != nil { - execConfig.Running = false - exitCode := 126 - execConfig.ExitCode = int64(exitCode) - } - mgr.ExecProcesses.Put(execid, execConfig) - }() - - err = mgr.Client.ExecContainer(ctx, &ctrd.Process{ - ContainerID: execConfig.ContainerID, - ExecID: execid, - IO: io, - P: process, - }) - - return err -} - -// InspectExec returns low-level information about exec command. -func (mgr *ContainerManager) InspectExec(ctx context.Context, execid string) (*types.ContainerExecInspect, error) { - execConfig, err := mgr.GetExecConfig(ctx, execid) - if err != nil { - return nil, err - } - - return &types.ContainerExecInspect{ - ID: execConfig.ExecID, - // FIXME: try to use the correct running status of exec - Running: execConfig.Running, - ExitCode: execConfig.ExitCode, - ContainerID: execConfig.ContainerID, - }, nil -} - -// GetExecConfig returns execonfig of a exec process inside container. -func (mgr *ContainerManager) GetExecConfig(ctx context.Context, execid string) (*ContainerExecConfig, error) { - v, ok := mgr.ExecProcesses.Get(execid).Result() - if !ok { - return nil, errors.Wrap(errtypes.ErrNotfound, "exec process "+execid) - } - execConfig, ok := v.(*ContainerExecConfig) - if !ok { - return nil, fmt.Errorf("invalid exec config type") - } - return execConfig, nil -} - // Create checks passed in parameters and create a Container object whose status is set at Created. func (mgr *ContainerManager) Create(ctx context.Context, name string, config *types.ContainerCreateConfig) (*types.ContainerCreateResp, error) { imgID, _, primaryRef, err := mgr.ImageMgr.CheckReference(ctx, config.Image) @@ -528,6 +375,45 @@ func (mgr *ContainerManager) Create(ctx context.Context, name string, config *ty }, nil } +// Get the detailed information of container. +func (mgr *ContainerManager) Get(ctx context.Context, name string) (*ContainerMeta, error) { + c, err := mgr.container(name) + if err != nil { + return nil, err + } + + c.Lock() + defer c.Unlock() + + return c.meta, nil +} + +// List returns the container's list. +func (mgr *ContainerManager) List(ctx context.Context, filter ContainerFilter, option *ContainerListOption) ([]*ContainerMeta, error) { + metas := []*ContainerMeta{} + + list, err := mgr.Store.List() + if err != nil { + return nil, err + } + + for _, obj := range list { + m, ok := obj.(*ContainerMeta) + if !ok { + return nil, fmt.Errorf("failed to get container list, invalid meta type") + } + if filter != nil && filter(m) { + if option.All { + metas = append(metas, m) + } else if m.State.Status == types.StatusRunning || m.State.Status == types.StatusPaused { + metas = append(metas, m) + } + } + } + + return metas, nil +} + // Start a pre created Container. func (mgr *ContainerManager) Start(ctx context.Context, id, detachKeys string) (err error) { if id == "" { @@ -694,6 +580,33 @@ func (mgr *ContainerManager) stop(ctx context.Context, c *Container, timeout int return mgr.markStoppedAndRelease(c, msg) } +// Restart restarts a running container. +func (mgr *ContainerManager) Restart(ctx context.Context, name string, timeout int64) error { + c, err := mgr.container(name) + if err != nil { + return err + } + + c.Lock() + defer c.Unlock() + + if timeout == 0 { + timeout = c.StopTimeout() + } + + if c.IsRunning() || c.IsPaused() { + // stop container if it is running or paused. + if err := mgr.stop(ctx, c, timeout); err != nil { + logrus.Errorf("failed to stop container %s when restarting: %v", c.ID(), err) + return errors.Wrapf(err, fmt.Sprintf("failed to stop container %s", c.ID())) + } + } + + logrus.Debugf("start container %s when restarting", c.ID()) + // start container + return mgr.start(ctx, c, "") +} + // Pause pauses a running container. func (mgr *ContainerManager) Pause(ctx context.Context, name string) error { var ( @@ -781,46 +694,7 @@ func (mgr *ContainerManager) Attach(ctx context.Context, name string, attach *At return nil } -// List returns the container's list. -func (mgr *ContainerManager) List(ctx context.Context, filter ContainerFilter, option *ContainerListOption) ([]*ContainerMeta, error) { - metas := []*ContainerMeta{} - - list, err := mgr.Store.List() - if err != nil { - return nil, err - } - - for _, obj := range list { - m, ok := obj.(*ContainerMeta) - if !ok { - return nil, fmt.Errorf("failed to get container list, invalid meta type") - } - if filter != nil && filter(m) { - if option.All { - metas = append(metas, m) - } else if m.State.Status == types.StatusRunning || m.State.Status == types.StatusPaused { - metas = append(metas, m) - } - } - } - - return metas, nil -} - -// Get the detailed information of container. -func (mgr *ContainerManager) Get(ctx context.Context, name string) (*ContainerMeta, error) { - c, err := mgr.container(name) - if err != nil { - return nil, err - } - - c.Lock() - defer c.Unlock() - - return c.meta, nil -} - -// Rename renames a container +// Rename renames a container. func (mgr *ContainerManager) Rename(ctx context.Context, oldName, newName string) error { var ( c *Container @@ -941,6 +815,53 @@ func (mgr *ContainerManager) Update(ctx context.Context, name string, config *ty return updateErr } +// Remove removes a container, it may be running or stopped and so on. +func (mgr *ContainerManager) Remove(ctx context.Context, name string, options *types.ContainerRemoveOptions) error { + c, err := mgr.container(name) + if err != nil { + return err + } + c.Lock() + defer c.Unlock() + + if !c.IsStopped() && !c.IsExited() && !c.IsCreated() && !options.Force { + return fmt.Errorf("container: %s is not stopped, can't remove it without flag force", c.ID()) + } + + // if the container is running, force to stop it. + if c.IsRunning() && options.Force { + msg, err := mgr.Client.DestroyContainer(ctx, c.ID(), c.StopTimeout()) + if err != nil && !errtypes.IsNotfound(err) { + return errors.Wrapf(err, "failed to destroy container: %s", c.ID()) + } + if err := mgr.markStoppedAndRelease(c, msg); err != nil { + return errors.Wrapf(err, "failed to mark container: %s stop status", c.ID()) + } + } + + if err := mgr.detachVolumes(ctx, c.meta, options.Volumes); err != nil { + logrus.Errorf("failed to detach volume: %v", err) + } + + // remove name + mgr.NameToID.Remove(c.Name()) + + // remove meta data + if err := mgr.Store.Remove(c.meta.Key()); err != nil { + logrus.Errorf("failed to remove container: %s meta store, %v", c.ID(), err) + } + + // remove container cache + mgr.cache.Remove(c.ID()) + + // remove snapshot + if err := mgr.Client.RemoveSnapshot(ctx, c.ID()); err != nil { + logrus.Errorf("failed to remove container: %s snapshot, %v", c.ID(), err) + } + + return nil +} + func (mgr *ContainerManager) updateContainerDiskQuota(ctx context.Context, c *ContainerMeta, diskQuota string) error { if diskQuota == "" { return nil @@ -1340,33 +1261,6 @@ func (mgr *ContainerManager) Resize(ctx context.Context, name string, opts types return mgr.Client.ResizeContainer(ctx, c.ID(), opts) } -// Restart restarts a running container. -func (mgr *ContainerManager) Restart(ctx context.Context, name string, timeout int64) error { - c, err := mgr.container(name) - if err != nil { - return err - } - - c.Lock() - defer c.Unlock() - - if timeout == 0 { - timeout = c.StopTimeout() - } - - if c.IsRunning() || c.IsPaused() { - // stop container if it is running or paused. - if err := mgr.stop(ctx, c, timeout); err != nil { - logrus.Errorf("failed to stop container %s when restarting: %v", c.ID(), err) - return errors.Wrapf(err, fmt.Sprintf("failed to stop container %s", c.ID())) - } - } - - logrus.Debugf("start container %s when restarting", c.ID()) - // start container - return mgr.start(ctx, c, "") -} - // Connect is used to connect a container to a network. func (mgr *ContainerManager) Connect(ctx context.Context, name string, networkIDOrName string, epConfig *types.EndpointSettings) error { c, err := mgr.container(name) diff --git a/daemon/mgr/container_exec.go b/daemon/mgr/container_exec.go new file mode 100644 index 000000000..4cf9aeaab --- /dev/null +++ b/daemon/mgr/container_exec.go @@ -0,0 +1,131 @@ +package mgr + +import ( + "context" + "fmt" + + "github.com/alibaba/pouch/apis/types" + "github.com/alibaba/pouch/ctrd" + "github.com/alibaba/pouch/pkg/errtypes" + "github.com/alibaba/pouch/pkg/randomid" + + specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/pkg/errors" +) + +// CreateExec creates exec process's meta data. +func (mgr *ContainerManager) CreateExec(ctx context.Context, name string, config *types.ExecCreateConfig) (string, error) { + c, err := mgr.container(name) + if err != nil { + return "", err + } + + if !c.IsRunning() { + return "", fmt.Errorf("container %s is not running", c.ID()) + } + + execid := randomid.Generate() + execConfig := &ContainerExecConfig{ + ExecID: execid, + ExecCreateConfig: *config, + ContainerID: c.ID(), + } + + mgr.ExecProcesses.Put(execid, execConfig) + + return execid, nil +} + +// StartExec executes a new process in container. +func (mgr *ContainerManager) StartExec(ctx context.Context, execid string, config *types.ExecStartConfig, attach *AttachConfig) error { + v, ok := mgr.ExecProcesses.Get(execid).Result() + if !ok { + return errors.Wrap(errtypes.ErrNotfound, "to be exec process: "+execid) + } + execConfig, ok := v.(*ContainerExecConfig) + if !ok { + return fmt.Errorf("invalid exec config type") + } + + if attach != nil { + attach.Stdin = execConfig.AttachStdin + } + + io, err := mgr.openExecIO(execid, attach) + if err != nil { + return err + } + + c, err := mgr.container(execConfig.ContainerID) + if err != nil { + return err + } + + process := &specs.Process{ + Args: execConfig.Cmd, + Terminal: execConfig.Tty, + Cwd: "/", + Env: c.Config().Env, + } + + if execConfig.User != "" { + c.meta.Config.User = execConfig.User + } + + if err = setupUser(ctx, c.meta, &specs.Spec{Process: process}); err != nil { + return err + } + + // set exec process ulimit + if err := setupRlimits(ctx, c.meta.HostConfig, &specs.Spec{Process: process}); err != nil { + return err + } + + execConfig.Running = true + defer func() { + if err != nil { + execConfig.Running = false + exitCode := 126 + execConfig.ExitCode = int64(exitCode) + } + mgr.ExecProcesses.Put(execid, execConfig) + }() + + err = mgr.Client.ExecContainer(ctx, &ctrd.Process{ + ContainerID: execConfig.ContainerID, + ExecID: execid, + IO: io, + P: process, + }) + + return err +} + +// InspectExec returns low-level information about exec command. +func (mgr *ContainerManager) InspectExec(ctx context.Context, execid string) (*types.ContainerExecInspect, error) { + execConfig, err := mgr.GetExecConfig(ctx, execid) + if err != nil { + return nil, err + } + + return &types.ContainerExecInspect{ + ID: execConfig.ExecID, + // FIXME: try to use the correct running status of exec + Running: execConfig.Running, + ExitCode: execConfig.ExitCode, + ContainerID: execConfig.ContainerID, + }, nil +} + +// GetExecConfig returns execonfig of a exec process inside container. +func (mgr *ContainerManager) GetExecConfig(ctx context.Context, execid string) (*ContainerExecConfig, error) { + v, ok := mgr.ExecProcesses.Get(execid).Result() + if !ok { + return nil, errors.Wrap(errtypes.ErrNotfound, "exec process "+execid) + } + execConfig, ok := v.(*ContainerExecConfig) + if !ok { + return nil, fmt.Errorf("invalid exec config type") + } + return execConfig, nil +} diff --git a/daemon/mgr/image.go b/daemon/mgr/image.go index 876b6fbd7..2549dfe77 100644 --- a/daemon/mgr/image.go +++ b/daemon/mgr/image.go @@ -26,15 +26,15 @@ type ImageMgr interface { // PullImage pulls images from specified registry. PullImage(ctx context.Context, ref string, authConfig *types.AuthConfig, out io.Writer) error + // GetImage returns imageInfo by reference or id. + GetImage(ctx context.Context, idOrRef string) (*types.ImageInfo, error) + // ListImages lists images stored by containerd. ListImages(ctx context.Context, filter ...string) ([]types.ImageInfo, error) // Search Images from specified registry. SearchImages(ctx context.Context, name string, registry string) ([]types.SearchResultItem, error) - // GetImage returns imageInfo by reference or id. - GetImage(ctx context.Context, idOrRef string) (*types.ImageInfo, error) - // RemoveImage deletes an image by reference. RemoveImage(ctx context.Context, idOrRef string, force bool) error @@ -81,80 +81,6 @@ func NewImageManager(cfg *config.Config, client ctrd.APIClient) (*ImageManager, return mgr, nil } -// CheckReference returns image ID and actual reference. -func (mgr *ImageManager) CheckReference(ctx context.Context, idOrRef string) (actualID digest.Digest, actualRef reference.Named, primaryRef reference.Named, err error) { - var namedRef reference.Named - - namedRef, err = reference.Parse(idOrRef) - if err != nil { - return - } - - // NOTE: we cannot add default registry for the idOrRef directly - // because the idOrRef maybe short ID or ID. we should run search - // without addDefaultRegistryIfMissing at first round. - actualID, actualRef, err = mgr.localStore.Search(namedRef) - if err != nil { - if !errtypes.IsNotfound(err) { - return - } - - newIDOrRef := addDefaultRegistryIfMissing(idOrRef, mgr.DefaultRegistry, mgr.DefaultNamespace) - if newIDOrRef == idOrRef { - return - } - - // ideally, the err should be nil - namedRef, err = reference.Parse(newIDOrRef) - if err != nil { - return - } - - actualID, actualRef, err = mgr.localStore.Search(namedRef) - if err != nil { - return - } - } - - // NOTE: if the actualRef is short ID or ID, the primaryRef is first one of - // primary reference - if reference.IsNamedOnly(actualRef) { - refs := mgr.localStore.GetPrimaryReferences(actualID) - if len(refs) == 0 { - err = errtypes.ErrNotfound - logrus.Errorf("one Image ID must have the primary references, but got nothing") - return - } - - primaryRef = refs[0] - } else { - primaryRef, err = mgr.localStore.GetPrimaryReference(actualRef) - if err != nil { - return - } - } - return -} - -// GetImage returns imageInfo by reference. -func (mgr *ImageManager) GetImage(ctx context.Context, idOrRef string) (*types.ImageInfo, error) { - _, _, ref, err := mgr.CheckReference(ctx, idOrRef) - if err != nil { - return nil, err - } - - img, err := mgr.client.GetImage(ctx, ref.String()) - if err != nil { - return nil, err - } - - imgInfo, err := mgr.containerdImageToImageInfo(ctx, img) - if err != nil { - return nil, err - } - return &imgInfo, nil -} - // PullImage pulls images from specified registry. func (mgr *ImageManager) PullImage(ctx context.Context, ref string, authConfig *types.AuthConfig, out io.Writer) error { newRef := addDefaultRegistryIfMissing(ref, mgr.DefaultRegistry, mgr.DefaultNamespace) @@ -185,6 +111,25 @@ func (mgr *ImageManager) PullImage(ctx context.Context, ref string, authConfig * return mgr.storeImageReference(ctx, img) } +// GetImage returns imageInfo by reference. +func (mgr *ImageManager) GetImage(ctx context.Context, idOrRef string) (*types.ImageInfo, error) { + _, _, ref, err := mgr.CheckReference(ctx, idOrRef) + if err != nil { + return nil, err + } + + img, err := mgr.client.GetImage(ctx, ref.String()) + if err != nil { + return nil, err + } + + imgInfo, err := mgr.containerdImageToImageInfo(ctx, img) + if err != nil { + return nil, err + } + return &imgInfo, nil +} + // ListImages lists images stored by containerd. func (mgr *ImageManager) ListImages(ctx context.Context, filter ...string) ([]types.ImageInfo, error) { imgs, err := mgr.client.ListImages(ctx, filter...) @@ -277,6 +222,61 @@ func (mgr *ImageManager) RemoveImage(ctx context.Context, idOrRef string, force return mgr.localStore.RemoveReference(id, namedRef) } +// CheckReference returns image ID and actual reference. +func (mgr *ImageManager) CheckReference(ctx context.Context, idOrRef string) (actualID digest.Digest, actualRef reference.Named, primaryRef reference.Named, err error) { + var namedRef reference.Named + + namedRef, err = reference.Parse(idOrRef) + if err != nil { + return + } + + // NOTE: we cannot add default registry for the idOrRef directly + // because the idOrRef maybe short ID or ID. we should run search + // without addDefaultRegistryIfMissing at first round. + actualID, actualRef, err = mgr.localStore.Search(namedRef) + if err != nil { + if !errtypes.IsNotfound(err) { + return + } + + newIDOrRef := addDefaultRegistryIfMissing(idOrRef, mgr.DefaultRegistry, mgr.DefaultNamespace) + if newIDOrRef == idOrRef { + return + } + + // ideally, the err should be nil + namedRef, err = reference.Parse(newIDOrRef) + if err != nil { + return + } + + actualID, actualRef, err = mgr.localStore.Search(namedRef) + if err != nil { + return + } + } + + // NOTE: if the actualRef is short ID or ID, the primaryRef is first one of + // primary reference + if reference.IsNamedOnly(actualRef) { + refs := mgr.localStore.GetPrimaryReferences(actualID) + if len(refs) == 0 { + err = errtypes.ErrNotfound + logrus.Errorf("one Image ID must have the primary references, but got nothing") + return + } + + primaryRef = refs[0] + } else { + primaryRef, err = mgr.localStore.GetPrimaryReference(actualRef) + if err != nil { + return + } + } + return +} + // updateLocalStore updates the local store. func (mgr *ImageManager) updateLocalStore() error { ctx, cancel := context.WithTimeout(context.Background(), deadlineLoadImagesAtBootup) diff --git a/daemon/mgr/network.go b/daemon/mgr/network.go index 0ff450802..9c174cedf 100644 --- a/daemon/mgr/network.go +++ b/daemon/mgr/network.go @@ -32,26 +32,26 @@ type NetworkMgr interface { // Create is used to create network. Create(ctx context.Context, create apitypes.NetworkCreateConfig) (*types.Network, error) - // NetworkRemove is used to delete an existing network. - Remove(ctx context.Context, name string) error + // Get returns the information of network that specified name/id. + Get(ctx context.Context, name string) (*types.Network, error) // List returns all networks on this host. List(ctx context.Context, labels map[string]string) ([]*types.Network, error) - // Get returns the information of network that specified name/id. - Get(ctx context.Context, name string) (*types.Network, error) + // NetworkRemove is used to delete an existing network. + Remove(ctx context.Context, name string) error // EndpointCreate is used to create network endpoint. EndpointCreate(ctx context.Context, endpoint *types.Endpoint) (string, error) - // EndpointRemove is used to remove network endpoint. - EndpointRemove(ctx context.Context, endpoint *types.Endpoint) error + // EndpointInfo returns the information of endpoint that specified name/id. + EndpointInfo(ctx context.Context, name string) (*types.Endpoint, error) // EndpointList returns all endpoints. EndpointList(ctx context.Context) ([]*types.Endpoint, error) - // EndpointInfo returns the information of endpoint that specified name/id. - EndpointInfo(ctx context.Context, name string) (*types.Endpoint, error) + // EndpointRemove is used to remove network endpoint. + EndpointRemove(ctx context.Context, endpoint *types.Endpoint) error // Controller returns the network controller. Controller() libnetwork.NetworkController @@ -119,20 +119,24 @@ func (nm *NetworkManager) Create(ctx context.Context, create apitypes.NetworkCre return &network, nil } -// Remove is used to delete an existing network. -func (nm *NetworkManager) Remove(ctx context.Context, name string) error { - nw, err := nm.controller.NetworkByName(name) - if err != nil { - if err == libnetwork.ErrNoSuchNetwork(name) { - return errors.Wrap(errtypes.ErrNotfound, err.Error()) - } - return err +// Get returns the information of network for specified string that represent network name or ID. +// If network name is given, the network with same name is returned. +// If prefix of network ID is given, the network with same prefix is returned. +func (nm *NetworkManager) Get(ctx context.Context, idName string) (*types.Network, error) { + n, err := nm.GetNetworkByName(idName) + if err != nil && !isNoSuchNetworkError(err) { + return nil, err } - if nw == nil { - return nil + + if n != nil { + return n, nil } - return nw.Delete() + n, err = nm.GetNetworkByPartialID(idName) + if err != nil { + return nil, err + } + return n, err } // List returns all networks on this host. @@ -151,6 +155,22 @@ func (nm *NetworkManager) List(ctx context.Context, labels map[string]string) ([ return net, nil } +// Remove is used to delete an existing network. +func (nm *NetworkManager) Remove(ctx context.Context, name string) error { + nw, err := nm.controller.NetworkByName(name) + if err != nil { + if err == libnetwork.ErrNoSuchNetwork(name) { + return errors.Wrap(errtypes.ErrNotfound, err.Error()) + } + return err + } + if nw == nil { + return nil + } + + return nw.Delete() +} + // GetNetworkByName returns the information of network that specified name. func (nm *NetworkManager) GetNetworkByName(name string) (*types.Network, error) { n, err := nm.controller.NetworkByName(name) @@ -165,26 +185,6 @@ func (nm *NetworkManager) GetNetworkByName(name string) (*types.Network, error) }, nil } -// GetNetworksByPartialID returns a list of networks that ID starts with the given prefix. -func (nm *NetworkManager) GetNetworksByPartialID(partialID string) []*types.Network { - var matchedNetworks []*types.Network - - walker := func(nw libnetwork.Network) bool { - if strings.HasPrefix(nw.ID(), partialID) { - matchedNetwork := &types.Network{ - Name: nw.Name(), - ID: nw.ID(), - Type: nw.Type(), - Network: nw, - } - matchedNetworks = append(matchedNetworks, matchedNetwork) - } - return false - } - nm.controller.WalkNetworks(walker) - return matchedNetworks -} - // GetNetworkByPartialID returns the information of network that ID starts with the given prefix. // If there are not matching networks, it fails with ErrNotfound. // If there are multiple matching networks, it fails with ErrTooMany. @@ -211,32 +211,32 @@ func (nm *NetworkManager) GetNetworkByPartialID(partialID string) (*types.Networ return matchedNetworks[0], nil } +// GetNetworksByPartialID returns a list of networks that ID starts with the given prefix. +func (nm *NetworkManager) GetNetworksByPartialID(partialID string) []*types.Network { + var matchedNetworks []*types.Network + + walker := func(nw libnetwork.Network) bool { + if strings.HasPrefix(nw.ID(), partialID) { + matchedNetwork := &types.Network{ + Name: nw.Name(), + ID: nw.ID(), + Type: nw.Type(), + Network: nw, + } + matchedNetworks = append(matchedNetworks, matchedNetwork) + } + return false + } + nm.controller.WalkNetworks(walker) + return matchedNetworks +} + // isNoSuchNetworkError looks up the error type and returns a bool if it is ErrNoSuchNetwork or not. func isNoSuchNetworkError(err error) bool { _, ok := err.(libnetwork.ErrNoSuchNetwork) return ok } -// Get returns the information of network for specified string that represent network name or ID. -// If network name is given, the network with same name is returned. -// If prefix of network ID is given, the network with same prefix is returned. -func (nm *NetworkManager) Get(ctx context.Context, idName string) (*types.Network, error) { - n, err := nm.GetNetworkByName(idName) - if err != nil && !isNoSuchNetworkError(err) { - return nil, err - } - - if n != nil { - return n, nil - } - - n, err = nm.GetNetworkByPartialID(idName) - if err != nil { - return nil, err - } - return n, err -} - // EndpointCreate is used to create network endpoint. func (nm *NetworkManager) EndpointCreate(ctx context.Context, endpoint *types.Endpoint) (string, error) { containerID := endpoint.Owner @@ -330,6 +330,18 @@ func (nm *NetworkManager) EndpointCreate(ctx context.Context, endpoint *types.En return endpointName, nil } +// EndpointInfo returns the information of endpoint that specified name/id. +func (nm *NetworkManager) EndpointInfo(ctx context.Context, name string) (*types.Endpoint, error) { + // TODO + return nil, nil +} + +// EndpointList returns all endpoints. +func (nm *NetworkManager) EndpointList(ctx context.Context) ([]*types.Endpoint, error) { + // TODO + return nil, nil +} + // EndpointRemove is used to remove network endpoint. func (nm *NetworkManager) EndpointRemove(ctx context.Context, endpoint *types.Endpoint) error { sid := endpoint.NetworkConfig.SandboxID @@ -358,18 +370,6 @@ func (nm *NetworkManager) EndpointRemove(ctx context.Context, endpoint *types.En return nil } -// EndpointList returns all endpoints. -func (nm *NetworkManager) EndpointList(ctx context.Context) ([]*types.Endpoint, error) { - // TODO - return nil, nil -} - -// EndpointInfo returns the information of endpoint that specified name/id. -func (nm *NetworkManager) EndpointInfo(ctx context.Context, name string) (*types.Endpoint, error) { - // TODO - return nil, nil -} - // Controller returns the network controller. func (nm *NetworkManager) Controller() libnetwork.NetworkController { return nm.controller diff --git a/daemon/mgr/volume.go b/daemon/mgr/volume.go index 6861ffd37..bc5fd6d51 100644 --- a/daemon/mgr/volume.go +++ b/daemon/mgr/volume.go @@ -18,14 +18,14 @@ type VolumeMgr interface { // Create is used to create volume. Create(ctx context.Context, name, driver string, options, labels map[string]string) error - // Remove is used to delete an existing volume. - Remove(ctx context.Context, name string) error + // Get returns the information of volume that specified name/id. + Get(ctx context.Context, name string) (*types.Volume, error) // List returns all volumes on this host. List(ctx context.Context, labels map[string]string) ([]*types.Volume, error) - // Get returns the information of volume that specified name/id. - Get(ctx context.Context, name string) (*types.Volume, error) + // Remove is used to delete an existing volume. + Remove(ctx context.Context, name string) error // Path returns the mount path of volume. Path(ctx context.Context, name string) (string, error) @@ -91,28 +91,19 @@ func (vm *VolumeManager) Create(ctx context.Context, name, driver string, option return vm.core.CreateVolume(id) } -// Remove is used to delete an existing volume. -func (vm *VolumeManager) Remove(ctx context.Context, name string) error { - vol, err := vm.Get(ctx, name) - if err != nil { - return errors.Wrapf(err, "failed to get volume: %s", name) - } - - ref := vol.Option(types.OptionRef) - if ref != "" { - return errors.Wrapf(errtypes.ErrUsingbyContainers, "failed to remove volume: %s", name) - } - +// Get returns the information of volume that specified name/id. +func (vm *VolumeManager) Get(ctx context.Context, name string) (*types.Volume, error) { id := types.VolumeID{ Name: name, } - if err := vm.core.RemoveVolume(id); err != nil { + vol, err := vm.core.GetVolume(id) + if err != nil { if strings.Contains(err.Error(), "not found") { - return errors.Wrap(errtypes.ErrNotfound, err.Error()) + return nil, errors.Wrap(errtypes.ErrNotfound, err.Error()) } + return nil, err } - - return nil + return vol, nil } // List returns all volumes on this host. @@ -129,19 +120,28 @@ func (vm *VolumeManager) List(ctx context.Context, labels map[string]string) ([] return vm.core.ListVolumes(labels) } -// Get returns the information of volume that specified name/id. -func (vm *VolumeManager) Get(ctx context.Context, name string) (*types.Volume, error) { +// Remove is used to delete an existing volume. +func (vm *VolumeManager) Remove(ctx context.Context, name string) error { + vol, err := vm.Get(ctx, name) + if err != nil { + return errors.Wrapf(err, "failed to get volume: %s", name) + } + + ref := vol.Option(types.OptionRef) + if ref != "" { + return errors.Wrapf(errtypes.ErrUsingbyContainers, "failed to remove volume: %s", name) + } + id := types.VolumeID{ Name: name, } - vol, err := vm.core.GetVolume(id) - if err != nil { + if err := vm.core.RemoveVolume(id); err != nil { if strings.Contains(err.Error(), "not found") { - return nil, errors.Wrap(errtypes.ErrNotfound, err.Error()) + return errors.Wrap(errtypes.ErrNotfound, err.Error()) } - return nil, err } - return vol, nil + + return nil } // Path returns the mount path of volume.