diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/swagger/swagger.go | 18 | ||||
-rw-r--r-- | pkg/api/handlers/types.go | 9 | ||||
-rw-r--r-- | pkg/api/server/register_images.go | 2 | ||||
-rw-r--r-- | pkg/bindings/images/build.go | 44 | ||||
-rw-r--r-- | pkg/bindings/images/build_unix.go | 16 | ||||
-rw-r--r-- | pkg/bindings/images/build_windows.go | 9 | ||||
-rw-r--r-- | pkg/cgroups/cgroups.go | 106 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_libpod.go | 1 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 13 |
10 files changed, 175 insertions, 45 deletions
diff --git a/pkg/api/handlers/swagger/swagger.go b/pkg/api/handlers/swagger/swagger.go index ef3d12df8..83ff5914e 100644 --- a/pkg/api/handlers/swagger/swagger.go +++ b/pkg/api/handlers/swagger/swagger.go @@ -8,6 +8,15 @@ import ( "github.com/docker/docker/api/types" ) +// Tree response +// swagger:response TreeResponse +type swagTree struct { + // in:body + Body struct { + entities.ImageTreeReport + } +} + // History response // swagger:response DocsHistory type swagHistory struct { @@ -183,12 +192,3 @@ type swagInspectVolumeResponse struct { define.InspectVolumeData } } - -// Image tree response -// swagger:response LibpodImageTreeResponse -type swagImageTreeResponse struct { - // in:body - Body struct { - handlers.ImageTreeResponse - } -} diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go index 2ffd9b0cb..f94c9a1f5 100644 --- a/pkg/api/handlers/types.go +++ b/pkg/api/handlers/types.go @@ -148,15 +148,6 @@ type HistoryResponse struct { Comment string } -type ImageLayer struct{} - -type ImageTreeResponse struct { - ID string `json:"id"` - Tags []string `json:"tags"` - Size string `json:"size"` - Layers []ImageLayer `json:"layers"` -} - type ExecCreateConfig struct { docker.ExecConfig } diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index b32c0df20..9634bd83b 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -747,7 +747,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // - application/json // responses: // 200: - // $ref: '#/responses/LibpodImageTreeResponse' + // $ref: "#/responses/TreeResponse" // 404: // $ref: '#/responses/NoSuchImage' // 500: diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index f5e7c0c98..346d55c47 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -28,6 +28,11 @@ import ( "github.com/sirupsen/logrus" ) +type devino struct { + Dev uint64 + Ino uint64 +} + var ( iidRegex = regexp.MustCompile(`^[0-9a-f]{12}`) ) @@ -402,7 +407,7 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) { defer pw.Close() defer gw.Close() defer tw.Close() - + seen := make(map[devino]string) for _, src := range sources { s, err := filepath.Abs(src) if err != nil { @@ -431,25 +436,40 @@ func nTar(excludes []string, sources ...string) (io.ReadCloser, error) { } if info.Mode().IsRegular() { // add file item - f, lerr := os.Open(path) - if lerr != nil { - return lerr + di, isHardLink := checkHardLink(info) + if err != nil { + return err } - hdr, lerr := tar.FileInfoHeader(info, name) - if lerr != nil { - f.Close() - return lerr + hdr, err := tar.FileInfoHeader(info, "") + if err != nil { + return err + } + orig, ok := seen[di] + if ok { + hdr.Typeflag = tar.TypeLink + hdr.Linkname = orig + hdr.Size = 0 + hdr.Name = name + return tw.WriteHeader(hdr) + } + f, err := os.Open(path) + if err != nil { + return err } + hdr.Name = name - if lerr := tw.WriteHeader(hdr); lerr != nil { + if err := tw.WriteHeader(hdr); err != nil { f.Close() - return lerr + return err } - _, cerr := io.Copy(tw, f) + _, err = io.Copy(tw, f) f.Close() - return cerr + if err == nil && isHardLink { + seen[di] = name + } + return err } else if info.Mode().IsDir() { // add folders hdr, lerr := tar.FileInfoHeader(info, name) if lerr != nil { diff --git a/pkg/bindings/images/build_unix.go b/pkg/bindings/images/build_unix.go new file mode 100644 index 000000000..0afb1deb6 --- /dev/null +++ b/pkg/bindings/images/build_unix.go @@ -0,0 +1,16 @@ +// +build !windows + +package images + +import ( + "os" + "syscall" +) + +func checkHardLink(fi os.FileInfo) (devino, bool) { + st := fi.Sys().(*syscall.Stat_t) + return devino{ + Dev: uint64(st.Dev), + Ino: uint64(st.Ino), + }, st.Nlink > 1 +} diff --git a/pkg/bindings/images/build_windows.go b/pkg/bindings/images/build_windows.go new file mode 100644 index 000000000..bd71d1bf0 --- /dev/null +++ b/pkg/bindings/images/build_windows.go @@ -0,0 +1,9 @@ +package images + +import ( + "os" +) + +func checkHardLink(fi os.FileInfo) (devino, bool) { + return devino{}, false +} diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go index aefb5183b..911edeb5b 100644 --- a/pkg/cgroups/cgroups.go +++ b/pkg/cgroups/cgroups.go @@ -128,28 +128,118 @@ func init() { // getAvailableControllers get the available controllers func getAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool) ([]controller, error) { if cgroup2 { - return nil, fmt.Errorf("getAvailableControllers not implemented yet for cgroup v2") + controllers := []controller{} + subtreeControl := cgroupRoot + "/cgroup.subtree_control" + // rootless cgroupv2: check available controllers for current user ,systemd or servicescope will inherit + if rootless.IsRootless() { + userSlice, err := getCgroupPathForCurrentProcess() + if err != nil { + return controllers, err + } + //userSlice already contains '/' so not adding here + basePath := cgroupRoot + userSlice + subtreeControl = fmt.Sprintf("%s/cgroup.subtree_control", basePath) + } + subtreeControlBytes, err := ioutil.ReadFile(subtreeControl) + if err != nil { + return nil, errors.Wrapf(err, "failed while reading controllers for cgroup v2 from %q", subtreeControl) + } + for _, controllerName := range strings.Fields(string(subtreeControlBytes)) { + c := controller{ + name: controllerName, + symlink: false, + } + controllers = append(controllers, c) + } + return controllers, nil } - infos, err := ioutil.ReadDir(cgroupRoot) - if err != nil { - return nil, err - } + subsystems, _ := cgroupV1GetAllSubsystems() controllers := []controller{} - for _, i := range infos { - name := i.Name() + // cgroupv1 and rootless: No subsystem is available: delegation is unsafe. + if rootless.IsRootless() { + return controllers, nil + } + + for _, name := range subsystems { if _, found := exclude[name]; found { continue } + isSymLink := false + fileInfo, err := os.Stat(cgroupRoot + "/" + name) + if err != nil { + isSymLink = !fileInfo.IsDir() + } c := controller{ name: name, - symlink: !i.IsDir(), + symlink: isSymLink, } controllers = append(controllers, c) } + return controllers, nil } +// GetAvailableControllers get string:bool map of all the available controllers +func GetAvailableControllers(exclude map[string]controllerHandler, cgroup2 bool) ([]string, error) { + availableControllers, err := getAvailableControllers(exclude, cgroup2) + if err != nil { + return nil, err + } + controllerList := []string{} + for _, controller := range availableControllers { + controllerList = append(controllerList, controller.name) + } + + return controllerList, nil +} + +func cgroupV1GetAllSubsystems() ([]string, error) { + f, err := os.Open("/proc/cgroups") + if err != nil { + return nil, err + } + defer f.Close() + + subsystems := []string{} + + s := bufio.NewScanner(f) + for s.Scan() { + text := s.Text() + if text[0] != '#' { + parts := strings.Fields(text) + if len(parts) >= 4 && parts[3] != "0" { + subsystems = append(subsystems, parts[0]) + } + } + } + if err := s.Err(); err != nil { + return nil, err + } + return subsystems, nil +} + +func getCgroupPathForCurrentProcess() (string, error) { + path := fmt.Sprintf("/proc/%d/cgroup", os.Getpid()) + f, err := os.Open(path) + if err != nil { + return "", err + } + defer f.Close() + + cgroupPath := "" + s := bufio.NewScanner(f) + for s.Scan() { + text := s.Text() + procEntries := strings.SplitN(text, "::", 2) + cgroupPath = procEntries[1] + } + if err := s.Err(); err != nil { + return cgroupPath, err + } + return cgroupPath, nil +} + // getCgroupv1Path is a helper function to get the cgroup v1 path func (c *CgroupControl) getCgroupv1Path(name string) string { return filepath.Join(cgroupRoot, name, c.path) diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index d0a2b1bae..237a43441 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -275,7 +275,7 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, case nil: // remove container names that we successfully deleted reports = append(reports, &report) - case define.ErrNoSuchCtr: + case define.ErrNoSuchCtr, define.ErrCtrExists: // There is still a potential this is a libpod container tmpNames = append(tmpNames, ctr) default: diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go index a98c9168a..5cbee2e76 100644 --- a/pkg/domain/infra/runtime_libpod.go +++ b/pkg/domain/infra/runtime_libpod.go @@ -129,6 +129,7 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo if fs.Changed("root") { storageSet = true storageOpts.GraphRoot = cfg.Engine.StaticDir + storageOpts.GraphDriverOptions = []string{} } if fs.Changed("runroot") { storageSet = true diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index 3830835cc..74ced300a 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -21,6 +21,7 @@ import ( "github.com/containers/podman/v3/pkg/errorhandling" "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/util" + "github.com/containers/storage/types" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -580,7 +581,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri if err := containers.Remove(ic.ClientCtx, ctr.ID, removeOptions); err != nil { if errorhandling.Contains(err, define.ErrNoSuchCtr) || errorhandling.Contains(err, define.ErrCtrRemoved) { - logrus.Warnf("Container %s does not exist: %v", ctr.ID, err) + logrus.Debugf("Container %s does not exist: %v", ctr.ID, err) } else { logrus.Errorf("Error removing container %s: %v", ctr.ID, err) } @@ -613,8 +614,9 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri rmOptions := new(containers.RemoveOptions).WithForce(false).WithVolumes(true) if err := containers.Remove(ic.ClientCtx, ctr.ID, rmOptions); err != nil { if errorhandling.Contains(err, define.ErrNoSuchCtr) || - errorhandling.Contains(err, define.ErrCtrRemoved) { - logrus.Warnf("Container %s does not exist: %v", ctr.ID, err) + errorhandling.Contains(err, define.ErrCtrRemoved) || + errorhandling.Contains(err, types.ErrLayerUnknown) { + logrus.Debugf("Container %s does not exist: %v", ctr.ID, err) } else { logrus.Errorf("Error removing container %s: %v", ctr.ID, err) } @@ -691,8 +693,9 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta if !shouldRestart { if err := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true)); err != nil { if errorhandling.Contains(err, define.ErrNoSuchCtr) || - errorhandling.Contains(err, define.ErrCtrRemoved) { - logrus.Warnf("Container %s does not exist: %v", con.ID, err) + errorhandling.Contains(err, define.ErrCtrRemoved) || + errorhandling.Contains(err, types.ErrLayerUnknown) { + logrus.Debugf("Container %s does not exist: %v", con.ID, err) } else { logrus.Errorf("Error removing container %s: %v", con.ID, err) } |