Merge pull request #1309 from Random-Liu/update-containerd
Update containerd to a6a0c8b6e3
.
This commit is contained in:
commit
815f3e727d
@ -17,13 +17,11 @@ limitations under the License.
|
||||
package integration
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd"
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"golang.org/x/net/context"
|
||||
@ -127,7 +125,9 @@ func TestContainerdRestart(t *testing.T) {
|
||||
task, err := cntr.Task(ctx, nil)
|
||||
require.NoError(t, err)
|
||||
_, err = task.Delete(ctx, containerd.WithProcessKill)
|
||||
require.NoError(t, err)
|
||||
if err != nil {
|
||||
require.True(t, errdefs.IsNotFound(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,149 +196,4 @@ func TestContainerdRestart(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Note: The test moves runc binary.
|
||||
// The test requires:
|
||||
// 1) The runtime is runc;
|
||||
// 2) runc is in PATH;
|
||||
func TestUnknownStateAfterContainerdRestart(t *testing.T) {
|
||||
if *runtimeHandler != "" {
|
||||
t.Skip("unsupported config: runtime handler is set")
|
||||
}
|
||||
runcPath, err := exec.LookPath("runc")
|
||||
if err != nil {
|
||||
t.Skip("unsupported config: runc not in PATH")
|
||||
}
|
||||
|
||||
sbConfig := PodSandboxConfig("sandbox", "sandbox-unknown-state")
|
||||
|
||||
const testImage = "busybox"
|
||||
t.Logf("Pull test image %q", testImage)
|
||||
img, err := imageService.PullImage(&runtime.ImageSpec{Image: testImage}, nil, sbConfig)
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
assert.NoError(t, imageService.RemoveImage(&runtime.ImageSpec{Image: img}))
|
||||
}()
|
||||
|
||||
t.Log("Should not be able to create sandbox without runc")
|
||||
tmpRuncPath := Randomize(runcPath)
|
||||
require.NoError(t, os.Rename(runcPath, tmpRuncPath))
|
||||
defer func() {
|
||||
os.Rename(tmpRuncPath, runcPath)
|
||||
}()
|
||||
sb, err := runtimeService.RunPodSandbox(sbConfig, "")
|
||||
if err == nil {
|
||||
assert.NoError(t, runtimeService.StopPodSandbox(sb))
|
||||
assert.NoError(t, runtimeService.RemovePodSandbox(sb))
|
||||
t.Skip("unsupported config: runc is not being used")
|
||||
}
|
||||
require.NoError(t, os.Rename(tmpRuncPath, runcPath))
|
||||
|
||||
t.Log("Create a sandbox")
|
||||
sb, err = runtimeService.RunPodSandbox(sbConfig, "")
|
||||
require.NoError(t, err)
|
||||
defer func() {
|
||||
// Make sure the sandbox is cleaned up in any case.
|
||||
runtimeService.StopPodSandbox(sb)
|
||||
runtimeService.RemovePodSandbox(sb)
|
||||
}()
|
||||
ps, err := runtimeService.PodSandboxStatus(sb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, runtime.PodSandboxState_SANDBOX_READY, ps.GetState())
|
||||
|
||||
t.Log("Create a container")
|
||||
cnConfig := ContainerConfig(
|
||||
"container-unknown-state",
|
||||
testImage,
|
||||
WithCommand("sleep", "1000"),
|
||||
)
|
||||
cn, err := runtimeService.CreateContainer(sb, cnConfig, sbConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Log("Start the container")
|
||||
require.NoError(t, runtimeService.StartContainer(cn))
|
||||
cs, err := runtimeService.ContainerStatus(cn)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, runtime.ContainerState_CONTAINER_RUNNING, cs.GetState())
|
||||
|
||||
t.Log("Move runc binary, so that container/sandbox can't be loaded after restart")
|
||||
tmpRuncPath = Randomize(runcPath)
|
||||
require.NoError(t, os.Rename(runcPath, tmpRuncPath))
|
||||
defer func() {
|
||||
os.Rename(tmpRuncPath, runcPath)
|
||||
}()
|
||||
|
||||
t.Log("Restart containerd")
|
||||
RestartContainerd(t)
|
||||
|
||||
t.Log("Sandbox should be in NOTREADY state after containerd restart")
|
||||
ps, err = runtimeService.PodSandboxStatus(sb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, runtime.PodSandboxState_SANDBOX_NOTREADY, ps.GetState())
|
||||
|
||||
t.Log("Container should be in UNKNOWN state after containerd restart")
|
||||
cs, err = runtimeService.ContainerStatus(cn)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, runtime.ContainerState_CONTAINER_UNKNOWN, cs.GetState())
|
||||
|
||||
t.Log("Stop/remove the sandbox should fail for the lack of runc")
|
||||
assert.Error(t, runtimeService.StopPodSandbox(sb))
|
||||
assert.Error(t, runtimeService.RemovePodSandbox(sb))
|
||||
|
||||
t.Log("Stop/remove the container should fail for the lack of runc")
|
||||
assert.Error(t, runtimeService.StopContainer(cn, 10))
|
||||
assert.Error(t, runtimeService.RemoveContainer(cn))
|
||||
|
||||
t.Log("Move runc back")
|
||||
require.NoError(t, os.Rename(tmpRuncPath, runcPath))
|
||||
|
||||
t.Log("Sandbox should still be in NOTREADY state")
|
||||
ps, err = runtimeService.PodSandboxStatus(sb)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, runtime.PodSandboxState_SANDBOX_NOTREADY, ps.GetState())
|
||||
|
||||
t.Log("Container should still be in UNKNOWN state")
|
||||
cs, err = runtimeService.ContainerStatus(cn)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, runtime.ContainerState_CONTAINER_UNKNOWN, cs.GetState())
|
||||
|
||||
t.Log("Sandbox operations which require running state should fail")
|
||||
_, err = runtimeService.PortForward(&runtime.PortForwardRequest{
|
||||
PodSandboxId: sb,
|
||||
Port: []int32{8080},
|
||||
})
|
||||
assert.Error(t, err)
|
||||
|
||||
t.Log("Container operations which require running state should fail")
|
||||
assert.Error(t, runtimeService.ReopenContainerLog(cn))
|
||||
_, _, err = runtimeService.ExecSync(cn, []string{"ls"}, 10*time.Second)
|
||||
assert.Error(t, err)
|
||||
_, err = runtimeService.Attach(&runtime.AttachRequest{
|
||||
ContainerId: cn,
|
||||
Stdin: true,
|
||||
Stdout: true,
|
||||
Stderr: true,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
|
||||
t.Log("Containerd should still be running now")
|
||||
_, err = runtimeService.Status()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Log("Remove the container should fail in this state")
|
||||
assert.Error(t, runtimeService.RemoveContainer(cn))
|
||||
|
||||
t.Log("Remove the sandbox should fail in this state")
|
||||
assert.Error(t, runtimeService.RemovePodSandbox(sb))
|
||||
|
||||
t.Log("Should be able to stop container in this state")
|
||||
assert.NoError(t, runtimeService.StopContainer(cn, 10))
|
||||
|
||||
t.Log("Should be able to stop sandbox in this state")
|
||||
assert.NoError(t, runtimeService.StopPodSandbox(sb))
|
||||
|
||||
t.Log("Should be able to remove container after stop")
|
||||
assert.NoError(t, runtimeService.RemoveContainer(cn))
|
||||
|
||||
t.Log("Should be able to remove sandbox after stop")
|
||||
assert.NoError(t, runtimeService.RemovePodSandbox(sb))
|
||||
}
|
||||
// TODO: Add back the unknown state test.
|
||||
|
@ -21,30 +21,30 @@ package server
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/containerd/cgroups"
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetWorkingSet(t *testing.T) {
|
||||
for desc, test := range map[string]struct {
|
||||
memory *cgroups.MemoryStat
|
||||
memory *v1.MemoryStat
|
||||
expected uint64
|
||||
}{
|
||||
"nil memory usage": {
|
||||
memory: &cgroups.MemoryStat{},
|
||||
memory: &v1.MemoryStat{},
|
||||
expected: 0,
|
||||
},
|
||||
"memory usage higher than inactive_total_file": {
|
||||
memory: &cgroups.MemoryStat{
|
||||
memory: &v1.MemoryStat{
|
||||
TotalInactiveFile: 1000,
|
||||
Usage: &cgroups.MemoryEntry{Usage: 2000},
|
||||
Usage: &v1.MemoryEntry{Usage: 2000},
|
||||
},
|
||||
expected: 1000,
|
||||
},
|
||||
"memory usage lower than inactive_total_file": {
|
||||
memory: &cgroups.MemoryStat{
|
||||
memory: &v1.MemoryStat{
|
||||
TotalInactiveFile: 2000,
|
||||
Usage: &cgroups.MemoryEntry{Usage: 1000},
|
||||
Usage: &v1.MemoryEntry{Usage: 1000},
|
||||
},
|
||||
expected: 0,
|
||||
},
|
||||
|
@ -22,7 +22,7 @@ github.com/prometheus/client_model 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c
|
||||
github.com/prometheus/client_golang f4fb1b73fb099f396a7f0036bf86aa8def4ed823
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db
|
||||
github.com/opencontainers/runc f4982d86f7fde0b6f953cc62ccc4022c519a10a9 # v1.0.0-rc8-32-gf4982d86
|
||||
github.com/opencontainers/runc d736ef14f0288d6993a1845745d6756cfc9ddd5a # v1.0.0-rc9
|
||||
github.com/opencontainers/image-spec v1.0.1
|
||||
github.com/opencontainers/go-digest c9281466c8b2f606084ac71339773efd177436e7
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1
|
||||
@ -44,9 +44,9 @@ github.com/containerd/ttrpc 92c8520ef9f86600c650dd540266a007bf03670f
|
||||
github.com/containerd/go-runc 9007c2405372fe28918845901a3276c0915689a1
|
||||
github.com/containerd/fifo bda0ff6ed73c67bfb5e62bc9c697f146b7fd7f13
|
||||
github.com/containerd/continuity f2a389ac0a02ce21c09edd7344677a601970f41c
|
||||
github.com/containerd/containerd ed16170c4c399c57f25d6aa1e97b345ed6ab96cb
|
||||
github.com/containerd/containerd a6a0c8b6e36415a151d93d096c1c0af9e0bd7977
|
||||
github.com/containerd/console 0650fd9eeb50bab4fc99dceb9f2e14cf58f36e7f
|
||||
github.com/containerd/cgroups c4b9ac5c7601384c965b9646fc515884e091ebb9
|
||||
github.com/containerd/cgroups abd0b19954a6b05e0963f48427062d1481b7faad
|
||||
github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
|
||||
github.com/Microsoft/hcsshim c088f411aaf3585d8dffc9deb4289ffa32854497 # TODO(windows): update this in containerd/containerd
|
||||
github.com/Microsoft/go-winio v0.4.14
|
||||
|
36
vendor/github.com/containerd/cgroups/blkio.go
generated
vendored
36
vendor/github.com/containerd/cgroups/blkio.go
generated
vendored
@ -26,17 +26,33 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
func NewBlkio(root string) *blkioController {
|
||||
return &blkioController{
|
||||
root: filepath.Join(root, string(Blkio)),
|
||||
// NewBlkio returns a Blkio controller given the root folder of cgroups.
|
||||
// It may optionally accept other configuration options, such as ProcRoot(path)
|
||||
func NewBlkio(root string, options ...func(controller *blkioController)) *blkioController {
|
||||
ctrl := &blkioController{
|
||||
root: filepath.Join(root, string(Blkio)),
|
||||
procRoot: "/proc",
|
||||
}
|
||||
for _, opt := range options {
|
||||
opt(ctrl)
|
||||
}
|
||||
return ctrl
|
||||
}
|
||||
|
||||
// ProcRoot overrides the default location of the "/proc" filesystem
|
||||
func ProcRoot(path string) func(controller *blkioController) {
|
||||
return func(c *blkioController) {
|
||||
c.procRoot = path
|
||||
}
|
||||
}
|
||||
|
||||
type blkioController struct {
|
||||
root string
|
||||
root string
|
||||
procRoot string
|
||||
}
|
||||
|
||||
func (b *blkioController) Name() Name {
|
||||
@ -72,8 +88,8 @@ func (b *blkioController) Update(path string, resources *specs.LinuxResources) e
|
||||
return b.Create(path, resources)
|
||||
}
|
||||
|
||||
func (b *blkioController) Stat(path string, stats *Metrics) error {
|
||||
stats.Blkio = &BlkIOStat{}
|
||||
func (b *blkioController) Stat(path string, stats *v1.Metrics) error {
|
||||
stats.Blkio = &v1.BlkIOStat{}
|
||||
settings := []blkioStatSettings{
|
||||
{
|
||||
name: "throttle.io_serviced",
|
||||
@ -122,7 +138,7 @@ func (b *blkioController) Stat(path string, stats *Metrics) error {
|
||||
},
|
||||
)
|
||||
}
|
||||
f, err := os.Open("/proc/diskstats")
|
||||
f, err := os.Open(filepath.Join(b.procRoot, "diskstats"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -141,7 +157,7 @@ func (b *blkioController) Stat(path string, stats *Metrics) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *blkioController) readEntry(devices map[deviceKey]string, path, name string, entry *[]*BlkIOEntry) error {
|
||||
func (b *blkioController) readEntry(devices map[deviceKey]string, path, name string, entry *[]*v1.BlkIOEntry) error {
|
||||
f, err := os.Open(filepath.Join(b.Path(path), fmt.Sprintf("blkio.%s", name)))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -180,7 +196,7 @@ func (b *blkioController) readEntry(devices map[deviceKey]string, path, name str
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*entry = append(*entry, &BlkIOEntry{
|
||||
*entry = append(*entry, &v1.BlkIOEntry{
|
||||
Device: devices[deviceKey{major, minor}],
|
||||
Major: major,
|
||||
Minor: minor,
|
||||
@ -268,7 +284,7 @@ type blkioSettings struct {
|
||||
|
||||
type blkioStatSettings struct {
|
||||
name string
|
||||
entry *[]*BlkIOEntry
|
||||
entry *[]*v1.BlkIOEntry
|
||||
}
|
||||
|
||||
func uintf(v interface{}) []byte {
|
||||
|
11
vendor/github.com/containerd/cgroups/cgroup.go
generated
vendored
11
vendor/github.com/containerd/cgroups/cgroup.go
generated
vendored
@ -25,6 +25,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -246,7 +247,7 @@ func (c *cgroup) Delete() error {
|
||||
}
|
||||
|
||||
// Stat returns the current metrics for the cgroup
|
||||
func (c *cgroup) Stat(handlers ...ErrorHandler) (*Metrics, error) {
|
||||
func (c *cgroup) Stat(handlers ...ErrorHandler) (*v1.Metrics, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.err != nil {
|
||||
@ -256,10 +257,10 @@ func (c *cgroup) Stat(handlers ...ErrorHandler) (*Metrics, error) {
|
||||
handlers = append(handlers, errPassthrough)
|
||||
}
|
||||
var (
|
||||
stats = &Metrics{
|
||||
CPU: &CPUStat{
|
||||
Throttling: &Throttle{},
|
||||
Usage: &CPUUsage{},
|
||||
stats = &v1.Metrics{
|
||||
CPU: &v1.CPUStat{
|
||||
Throttling: &v1.Throttle{},
|
||||
Usage: &v1.CPUUsage{},
|
||||
},
|
||||
}
|
||||
wg = &sync.WaitGroup{}
|
||||
|
3
vendor/github.com/containerd/cgroups/control.go
generated
vendored
3
vendor/github.com/containerd/cgroups/control.go
generated
vendored
@ -19,6 +19,7 @@ package cgroups
|
||||
import (
|
||||
"os"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
@ -68,7 +69,7 @@ type Cgroup interface {
|
||||
// subsystems are moved one at a time
|
||||
MoveTo(Cgroup) error
|
||||
// Stat returns the stats for all subsystems in the cgroup
|
||||
Stat(...ErrorHandler) (*Metrics, error)
|
||||
Stat(...ErrorHandler) (*v1.Metrics, error)
|
||||
// Update updates all the subsystems with the provided resource changes
|
||||
Update(resources *specs.LinuxResources) error
|
||||
// Processes returns all the processes in a select subsystem for the cgroup
|
||||
|
3
vendor/github.com/containerd/cgroups/cpu.go
generated
vendored
3
vendor/github.com/containerd/cgroups/cpu.go
generated
vendored
@ -24,6 +24,7 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
@ -100,7 +101,7 @@ func (c *cpuController) Update(path string, resources *specs.LinuxResources) err
|
||||
return c.Create(path, resources)
|
||||
}
|
||||
|
||||
func (c *cpuController) Stat(path string, stats *Metrics) error {
|
||||
func (c *cpuController) Stat(path string, stats *v1.Metrics) error {
|
||||
f, err := os.Open(filepath.Join(c.Path(path), "cpu.stat"))
|
||||
if err != nil {
|
||||
return err
|
||||
|
4
vendor/github.com/containerd/cgroups/cpuacct.go
generated
vendored
4
vendor/github.com/containerd/cgroups/cpuacct.go
generated
vendored
@ -22,6 +22,8 @@ import (
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
)
|
||||
|
||||
const nanosecondsInSecond = 1000000000
|
||||
@ -46,7 +48,7 @@ func (c *cpuacctController) Path(path string) string {
|
||||
return filepath.Join(c.root, path)
|
||||
}
|
||||
|
||||
func (c *cpuacctController) Stat(path string, stats *Metrics) error {
|
||||
func (c *cpuacctController) Stat(path string, stats *v1.Metrics) error {
|
||||
user, kernel, err := c.getUsage(path)
|
||||
if err != nil {
|
||||
return err
|
||||
|
13
vendor/github.com/containerd/cgroups/go.mod
generated
vendored
Normal file
13
vendor/github.com/containerd/cgroups/go.mod
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
module github.com/containerd/cgroups
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e
|
||||
github.com/gogo/protobuf v1.2.1
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700
|
||||
github.com/pkg/errors v0.8.1
|
||||
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f
|
||||
)
|
7
vendor/github.com/containerd/cgroups/hugetlb.go
generated
vendored
7
vendor/github.com/containerd/cgroups/hugetlb.go
generated
vendored
@ -23,6 +23,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
@ -67,7 +68,7 @@ func (h *hugetlbController) Create(path string, resources *specs.LinuxResources)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *hugetlbController) Stat(path string, stats *Metrics) error {
|
||||
func (h *hugetlbController) Stat(path string, stats *v1.Metrics) error {
|
||||
for _, size := range h.sizes {
|
||||
s, err := h.readSizeStat(path, size)
|
||||
if err != nil {
|
||||
@ -78,8 +79,8 @@ func (h *hugetlbController) Stat(path string, stats *Metrics) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *hugetlbController) readSizeStat(path, size string) (*HugetlbStat, error) {
|
||||
s := HugetlbStat{
|
||||
func (h *hugetlbController) readSizeStat(path, size string) (*v1.HugetlbStat, error) {
|
||||
s := v1.HugetlbStat{
|
||||
Pagesize: size,
|
||||
}
|
||||
for _, t := range []struct {
|
||||
|
62
vendor/github.com/containerd/cgroups/memory.go
generated
vendored
62
vendor/github.com/containerd/cgroups/memory.go
generated
vendored
@ -27,19 +27,48 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func NewMemory(root string) *memoryController {
|
||||
return &memoryController{
|
||||
root: filepath.Join(root, string(Memory)),
|
||||
// NewMemory returns a Memory controller given the root folder of cgroups.
|
||||
// It may optionally accept other configuration options, such as IgnoreModules(...)
|
||||
func NewMemory(root string, options ...func(*memoryController)) *memoryController {
|
||||
mc := &memoryController{
|
||||
root: filepath.Join(root, string(Memory)),
|
||||
ignored: map[string]struct{}{},
|
||||
}
|
||||
for _, opt := range options {
|
||||
opt(mc)
|
||||
}
|
||||
return mc
|
||||
}
|
||||
|
||||
// IgnoreModules configure the memory controller to not read memory metrics for some
|
||||
// module names (e.g. passing "memsw" would avoid all the memory.memsw.* entries)
|
||||
func IgnoreModules(names ...string) func(*memoryController) {
|
||||
return func(mc *memoryController) {
|
||||
for _, name := range names {
|
||||
mc.ignored[name] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OptionalSwap allows the memory controller to not fail if cgroups is not accounting
|
||||
// Swap memory (there are no memory.memsw.* entries)
|
||||
func OptionalSwap() func(*memoryController) {
|
||||
return func(mc *memoryController) {
|
||||
_, err := os.Stat(filepath.Join(mc.root, "memory.memsw.usage_in_bytes"))
|
||||
if os.IsNotExist(err) {
|
||||
mc.ignored["memsw"] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type memoryController struct {
|
||||
root string
|
||||
root string
|
||||
ignored map[string]struct{}
|
||||
}
|
||||
|
||||
func (m *memoryController) Name() Name {
|
||||
@ -97,24 +126,24 @@ func (m *memoryController) Update(path string, resources *specs.LinuxResources)
|
||||
return m.set(path, settings)
|
||||
}
|
||||
|
||||
func (m *memoryController) Stat(path string, stats *Metrics) error {
|
||||
func (m *memoryController) Stat(path string, stats *v1.Metrics) error {
|
||||
f, err := os.Open(filepath.Join(m.Path(path), "memory.stat"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
stats.Memory = &MemoryStat{
|
||||
Usage: &MemoryEntry{},
|
||||
Swap: &MemoryEntry{},
|
||||
Kernel: &MemoryEntry{},
|
||||
KernelTCP: &MemoryEntry{},
|
||||
stats.Memory = &v1.MemoryStat{
|
||||
Usage: &v1.MemoryEntry{},
|
||||
Swap: &v1.MemoryEntry{},
|
||||
Kernel: &v1.MemoryEntry{},
|
||||
KernelTCP: &v1.MemoryEntry{},
|
||||
}
|
||||
if err := m.parseStats(f, stats.Memory); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, t := range []struct {
|
||||
module string
|
||||
entry *MemoryEntry
|
||||
entry *v1.MemoryEntry
|
||||
}{
|
||||
{
|
||||
module: "",
|
||||
@ -133,6 +162,9 @@ func (m *memoryController) Stat(path string, stats *Metrics) error {
|
||||
entry: stats.Memory.KernelTCP,
|
||||
},
|
||||
} {
|
||||
if _, ok := m.ignored[t.module]; ok {
|
||||
continue
|
||||
}
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
value *uint64
|
||||
@ -197,7 +229,7 @@ func writeEventFD(root string, cfd, efd uintptr) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *memoryController) parseStats(r io.Reader, stat *MemoryStat) error {
|
||||
func (m *memoryController) parseStats(r io.Reader, stat *v1.MemoryStat) error {
|
||||
var (
|
||||
raw = make(map[string]uint64)
|
||||
sc = bufio.NewScanner(r)
|
||||
@ -282,7 +314,7 @@ func getMemorySettings(resources *specs.LinuxResources) []memorySettings {
|
||||
value: mem.Limit,
|
||||
},
|
||||
{
|
||||
name: "soft_limit_in_bytes",
|
||||
name: "soft_limit_in_bytes",
|
||||
value: mem.Reservation,
|
||||
},
|
||||
{
|
||||
|
5
vendor/github.com/containerd/cgroups/pids.go
generated
vendored
5
vendor/github.com/containerd/cgroups/pids.go
generated
vendored
@ -23,6 +23,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
@ -62,7 +63,7 @@ func (p *pidsController) Update(path string, resources *specs.LinuxResources) er
|
||||
return p.Create(path, resources)
|
||||
}
|
||||
|
||||
func (p *pidsController) Stat(path string, stats *Metrics) error {
|
||||
func (p *pidsController) Stat(path string, stats *v1.Metrics) error {
|
||||
current, err := readUint(filepath.Join(p.Path(path), "pids.current"))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -77,7 +78,7 @@ func (p *pidsController) Stat(path string, stats *Metrics) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
stats.Pids = &PidsStat{
|
||||
stats.Pids = &v1.PidsStat{
|
||||
Current: current,
|
||||
Limit: max,
|
||||
}
|
||||
|
13
vendor/github.com/containerd/cgroups/rdma.go
generated
vendored
13
vendor/github.com/containerd/cgroups/rdma.go
generated
vendored
@ -24,6 +24,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
@ -80,7 +81,7 @@ func (p *rdmaController) Update(path string, resources *specs.LinuxResources) er
|
||||
return p.Create(path, resources)
|
||||
}
|
||||
|
||||
func parseRdmaKV(raw string, entry *RdmaEntry) {
|
||||
func parseRdmaKV(raw string, entry *v1.RdmaEntry) {
|
||||
var value uint64
|
||||
var err error
|
||||
|
||||
@ -103,13 +104,13 @@ func parseRdmaKV(raw string, entry *RdmaEntry) {
|
||||
}
|
||||
}
|
||||
|
||||
func toRdmaEntry(strEntries []string) []*RdmaEntry {
|
||||
var rdmaEntries []*RdmaEntry
|
||||
func toRdmaEntry(strEntries []string) []*v1.RdmaEntry {
|
||||
var rdmaEntries []*v1.RdmaEntry
|
||||
for i := range strEntries {
|
||||
parts := strings.Fields(strEntries[i])
|
||||
switch len(parts) {
|
||||
case 3:
|
||||
entry := new(RdmaEntry)
|
||||
entry := new(v1.RdmaEntry)
|
||||
entry.Device = parts[0]
|
||||
parseRdmaKV(parts[1], entry)
|
||||
parseRdmaKV(parts[2], entry)
|
||||
@ -122,7 +123,7 @@ func toRdmaEntry(strEntries []string) []*RdmaEntry {
|
||||
return rdmaEntries
|
||||
}
|
||||
|
||||
func (p *rdmaController) Stat(path string, stats *Metrics) error {
|
||||
func (p *rdmaController) Stat(path string, stats *v1.Metrics) error {
|
||||
|
||||
currentData, err := ioutil.ReadFile(filepath.Join(p.Path(path), "rdma.current"))
|
||||
if err != nil {
|
||||
@ -145,7 +146,7 @@ func (p *rdmaController) Stat(path string, stats *Metrics) error {
|
||||
currentEntries := toRdmaEntry(currentPerDevices)
|
||||
maxEntries := toRdmaEntry(maxPerDevices)
|
||||
|
||||
stats.Rdma = &RdmaStat{
|
||||
stats.Rdma = &v1.RdmaStat{
|
||||
Current: currentEntries,
|
||||
Limit: maxEntries,
|
||||
}
|
||||
|
17
vendor/github.com/containerd/cgroups/stats/v1/doc.go
generated
vendored
Normal file
17
vendor/github.com/containerd/cgroups/stats/v1/doc.go
generated
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
File diff suppressed because it is too large
Load Diff
3
vendor/github.com/containerd/cgroups/subsystem.go
generated
vendored
3
vendor/github.com/containerd/cgroups/subsystem.go
generated
vendored
@ -19,6 +19,7 @@ package cgroups
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
@ -85,7 +86,7 @@ type deleter interface {
|
||||
|
||||
type stater interface {
|
||||
Subsystem
|
||||
Stat(path string, stats *Metrics) error
|
||||
Stat(path string, stats *v1.Metrics) error
|
||||
}
|
||||
|
||||
type updater interface {
|
||||
|
28
vendor/github.com/containerd/containerd/README.md
generated
vendored
28
vendor/github.com/containerd/containerd/README.md
generated
vendored
@ -210,6 +210,34 @@ See [PLUGINS.md](PLUGINS.md) for how to create plugins
|
||||
Please see [RELEASES.md](RELEASES.md) for details on versioning and stability
|
||||
of containerd components.
|
||||
|
||||
Downloadable 64-bit Intel/AMD binaries of all official releases are available on
|
||||
our [releases page](https://github.com/containerd/containerd/releases), as well as
|
||||
auto-published to the [cri-containerd-release storage bucket](https://console.cloud.google.com/storage/browser/cri-containerd-release?pli=1).
|
||||
|
||||
For other architectures and distribution support, you will find that many
|
||||
Linux distributions package their own containerd and provide it across several
|
||||
architectures, such as [Canonical's Ubuntu packaging](https://launchpad.net/ubuntu/bionic/+package/containerd).
|
||||
|
||||
#### Enabling command auto-completion
|
||||
|
||||
Starting with containerd 1.4, the urfave client feature for auto-creation of bash
|
||||
autocompletion data is enabled. To use the autocomplete feature in your shell, source
|
||||
the autocomplete/bash_autocomplete file in your .bashrc file while setting the `PROG`
|
||||
variable to `ctr`:
|
||||
|
||||
```
|
||||
$ PROG=ctr source vendor/github.com/urfave/cli/autocomplete/bash_autocomplete
|
||||
```
|
||||
|
||||
#### Distribution of `ctr` autocomplete for bash
|
||||
|
||||
Copy `vendor/github.com/urfave/cli/autocomplete/bash_autocomplete` into
|
||||
`/etc/bash_completion.d/` and rename it to `ctr`.
|
||||
|
||||
Provide documentation to users to `source` this file into their shell if
|
||||
you don't place the autocomplete file in a location where it is automatically
|
||||
loaded for user's bash shell environment.
|
||||
|
||||
### Communication
|
||||
|
||||
For async communication and long running discussions please use issues and pull requests on the github repo.
|
||||
|
@ -29,7 +29,7 @@ func serviceFlags() []cli.Flag {
|
||||
return nil
|
||||
}
|
||||
|
||||
// applyPlatformFlags applys platform-specific flags.
|
||||
// applyPlatformFlags applies platform-specific flags.
|
||||
func applyPlatformFlags(context *cli.Context) {
|
||||
}
|
||||
|
||||
|
2
vendor/github.com/containerd/containerd/images/archive/exporter.go
generated
vendored
2
vendor/github.com/containerd/containerd/images/archive/exporter.go
generated
vendored
@ -263,7 +263,7 @@ func getRecords(ctx context.Context, store content.Provider, desc ocispec.Descri
|
||||
images.HandlerFunc(exportHandler),
|
||||
)
|
||||
|
||||
// Walk sequentially since the number of fetchs is likely one and doing in
|
||||
// Walk sequentially since the number of fetches is likely one and doing in
|
||||
// parallel requires locking the export handler
|
||||
if err := images.Walk(ctx, handlers, desc); err != nil {
|
||||
return nil, err
|
||||
|
2
vendor/github.com/containerd/containerd/images/archive/importer.go
generated
vendored
2
vendor/github.com/containerd/containerd/images/archive/importer.go
generated
vendored
@ -124,7 +124,7 @@ func ImportIndex(ctx context.Context, store content.Store, reader io.Reader, opt
|
||||
}
|
||||
|
||||
// If OCI layout was given, interpret the tar as an OCI layout.
|
||||
// When not provided, the layout of the tar will be interpretted
|
||||
// When not provided, the layout of the tar will be interpreted
|
||||
// as Docker v1.1 or v1.2.
|
||||
if ociLayout.Version != "" {
|
||||
if ociLayout.Version != ocispec.ImageLayoutVersion {
|
||||
|
2
vendor/github.com/containerd/containerd/images/archive/reference.go
generated
vendored
2
vendor/github.com/containerd/containerd/images/archive/reference.go
generated
vendored
@ -20,7 +20,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/reference"
|
||||
distref "github.com/docker/distribution/reference"
|
||||
distref "github.com/containerd/containerd/reference/docker"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
12
vendor/github.com/containerd/containerd/lease.go
generated
vendored
12
vendor/github.com/containerd/containerd/lease.go
generated
vendored
@ -24,7 +24,7 @@ import (
|
||||
)
|
||||
|
||||
// WithLease attaches a lease on the context
|
||||
func (c *Client) WithLease(ctx context.Context) (context.Context, func(context.Context) error, error) {
|
||||
func (c *Client) WithLease(ctx context.Context, opts ...leases.Opt) (context.Context, func(context.Context) error, error) {
|
||||
_, ok := leases.FromContext(ctx)
|
||||
if ok {
|
||||
return ctx, func(context.Context) error {
|
||||
@ -34,7 +34,15 @@ func (c *Client) WithLease(ctx context.Context) (context.Context, func(context.C
|
||||
|
||||
ls := c.LeasesService()
|
||||
|
||||
l, err := ls.Create(ctx, leases.WithRandomID(), leases.WithExpiration(24*time.Hour))
|
||||
if len(opts) == 0 {
|
||||
// Use default lease configuration if no options provided
|
||||
opts = []leases.Opt{
|
||||
leases.WithRandomID(),
|
||||
leases.WithExpiration(24 * time.Hour),
|
||||
}
|
||||
}
|
||||
|
||||
l, err := ls.Create(ctx, opts...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
267
vendor/github.com/containerd/containerd/metadata/containers.go
generated
vendored
267
vendor/github.com/containerd/containerd/metadata/containers.go
generated
vendored
@ -19,6 +19,7 @@ package metadata
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
@ -35,13 +36,13 @@ import (
|
||||
)
|
||||
|
||||
type containerStore struct {
|
||||
tx *bolt.Tx
|
||||
db *DB
|
||||
}
|
||||
|
||||
// NewContainerStore returns a Store backed by an underlying bolt DB
|
||||
func NewContainerStore(tx *bolt.Tx) containers.Store {
|
||||
func NewContainerStore(db *DB) containers.Store {
|
||||
return &containerStore{
|
||||
tx: tx,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,14 +52,21 @@ func (s *containerStore) Get(ctx context.Context, id string) (containers.Contain
|
||||
return containers.Container{}, err
|
||||
}
|
||||
|
||||
bkt := getContainerBucket(s.tx, namespace, id)
|
||||
if bkt == nil {
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q in namespace %q", id, namespace)
|
||||
}
|
||||
|
||||
container := containers.Container{ID: id}
|
||||
if err := readContainer(&container, bkt); err != nil {
|
||||
return containers.Container{}, errors.Wrapf(err, "failed to read container %q", id)
|
||||
|
||||
if err := view(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
bkt := getContainerBucket(tx, namespace, id)
|
||||
if bkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "container %q in namespace %q", id, namespace)
|
||||
}
|
||||
|
||||
if err := readContainer(&container, bkt); err != nil {
|
||||
return errors.Wrapf(err, "failed to read container %q", id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return containers.Container{}, err
|
||||
}
|
||||
|
||||
return container, nil
|
||||
@ -75,27 +83,30 @@ func (s *containerStore) List(ctx context.Context, fs ...string) ([]containers.C
|
||||
return nil, errors.Wrap(errdefs.ErrInvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
bkt := getContainersBucket(s.tx, namespace)
|
||||
if bkt == nil {
|
||||
return nil, nil // empty store
|
||||
}
|
||||
|
||||
var m []containers.Container
|
||||
if err := bkt.ForEach(func(k, v []byte) error {
|
||||
cbkt := bkt.Bucket(k)
|
||||
if cbkt == nil {
|
||||
|
||||
if err := view(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
bkt := getContainersBucket(tx, namespace)
|
||||
if bkt == nil {
|
||||
return nil // empty store
|
||||
}
|
||||
|
||||
return bkt.ForEach(func(k, v []byte) error {
|
||||
cbkt := bkt.Bucket(k)
|
||||
if cbkt == nil {
|
||||
return nil
|
||||
}
|
||||
container := containers.Container{ID: string(k)}
|
||||
|
||||
if err := readContainer(&container, cbkt); err != nil {
|
||||
return errors.Wrapf(err, "failed to read container %q", string(k))
|
||||
}
|
||||
|
||||
if filter.Match(adaptContainer(container)) {
|
||||
m = append(m, container)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
container := containers.Container{ID: string(k)}
|
||||
|
||||
if err := readContainer(&container, cbkt); err != nil {
|
||||
return errors.Wrapf(err, "failed to read container %q", string(k))
|
||||
}
|
||||
|
||||
if filter.Match(adaptContainer(container)) {
|
||||
m = append(m, container)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -113,23 +124,29 @@ func (s *containerStore) Create(ctx context.Context, container containers.Contai
|
||||
return containers.Container{}, errors.Wrap(err, "create container failed validation")
|
||||
}
|
||||
|
||||
bkt, err := createContainersBucket(s.tx, namespace)
|
||||
if err != nil {
|
||||
return containers.Container{}, err
|
||||
}
|
||||
|
||||
cbkt, err := bkt.CreateBucket([]byte(container.ID))
|
||||
if err != nil {
|
||||
if err == bolt.ErrBucketExists {
|
||||
err = errors.Wrapf(errdefs.ErrAlreadyExists, "container %q", container.ID)
|
||||
if err := update(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
bkt, err := createContainersBucket(tx, namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return containers.Container{}, err
|
||||
}
|
||||
|
||||
container.CreatedAt = time.Now().UTC()
|
||||
container.UpdatedAt = container.CreatedAt
|
||||
if err := writeContainer(cbkt, &container); err != nil {
|
||||
return containers.Container{}, errors.Wrapf(err, "failed to write container %q", container.ID)
|
||||
cbkt, err := bkt.CreateBucket([]byte(container.ID))
|
||||
if err != nil {
|
||||
if err == bolt.ErrBucketExists {
|
||||
err = errors.Wrapf(errdefs.ErrAlreadyExists, "container %q", container.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
container.CreatedAt = time.Now().UTC()
|
||||
container.UpdatedAt = container.CreatedAt
|
||||
if err := writeContainer(cbkt, &container); err != nil {
|
||||
return errors.Wrapf(err, "failed to write container %q", container.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return containers.Container{}, err
|
||||
}
|
||||
|
||||
return container, nil
|
||||
@ -145,85 +162,91 @@ func (s *containerStore) Update(ctx context.Context, container containers.Contai
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "must specify a container id")
|
||||
}
|
||||
|
||||
bkt := getContainersBucket(s.tx, namespace)
|
||||
if bkt == nil {
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "cannot update container %q in namespace %q", container.ID, namespace)
|
||||
}
|
||||
|
||||
cbkt := bkt.Bucket([]byte(container.ID))
|
||||
if cbkt == nil {
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
|
||||
}
|
||||
|
||||
var updated containers.Container
|
||||
if err := readContainer(&updated, cbkt); err != nil {
|
||||
return updated, errors.Wrapf(err, "failed to read container %q", container.ID)
|
||||
}
|
||||
createdat := updated.CreatedAt
|
||||
updated.ID = container.ID
|
||||
|
||||
if len(fieldpaths) == 0 {
|
||||
// only allow updates to these field on full replace.
|
||||
fieldpaths = []string{"labels", "spec", "extensions", "image", "snapshotkey"}
|
||||
|
||||
// Fields that are immutable must cause an error when no field paths
|
||||
// are provided. This allows these fields to become mutable in the
|
||||
// future.
|
||||
if updated.Snapshotter != container.Snapshotter {
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter field is immutable")
|
||||
if err := update(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
bkt := getContainersBucket(tx, namespace)
|
||||
if bkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "cannot update container %q in namespace %q", container.ID, namespace)
|
||||
}
|
||||
|
||||
if updated.Runtime.Name != container.Runtime.Name {
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name field is immutable")
|
||||
cbkt := bkt.Bucket([]byte(container.ID))
|
||||
if cbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "container %q", container.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// apply the field mask. If you update this code, you better follow the
|
||||
// field mask rules in field_mask.proto. If you don't know what this
|
||||
// is, do not update this code.
|
||||
for _, path := range fieldpaths {
|
||||
if strings.HasPrefix(path, "labels.") {
|
||||
if updated.Labels == nil {
|
||||
updated.Labels = map[string]string{}
|
||||
if err := readContainer(&updated, cbkt); err != nil {
|
||||
return errors.Wrapf(err, "failed to read container %q", container.ID)
|
||||
}
|
||||
createdat := updated.CreatedAt
|
||||
updated.ID = container.ID
|
||||
|
||||
if len(fieldpaths) == 0 {
|
||||
// only allow updates to these field on full replace.
|
||||
fieldpaths = []string{"labels", "spec", "extensions", "image", "snapshotkey"}
|
||||
|
||||
// Fields that are immutable must cause an error when no field paths
|
||||
// are provided. This allows these fields to become mutable in the
|
||||
// future.
|
||||
if updated.Snapshotter != container.Snapshotter {
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Snapshotter field is immutable")
|
||||
}
|
||||
key := strings.TrimPrefix(path, "labels.")
|
||||
updated.Labels[key] = container.Labels[key]
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(path, "extensions.") {
|
||||
if updated.Extensions == nil {
|
||||
updated.Extensions = map[string]types.Any{}
|
||||
if updated.Runtime.Name != container.Runtime.Name {
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "container.Runtime.Name field is immutable")
|
||||
}
|
||||
key := strings.TrimPrefix(path, "extensions.")
|
||||
updated.Extensions[key] = container.Extensions[key]
|
||||
continue
|
||||
}
|
||||
|
||||
switch path {
|
||||
case "labels":
|
||||
updated.Labels = container.Labels
|
||||
case "spec":
|
||||
updated.Spec = container.Spec
|
||||
case "extensions":
|
||||
updated.Extensions = container.Extensions
|
||||
case "image":
|
||||
updated.Image = container.Image
|
||||
case "snapshotkey":
|
||||
updated.SnapshotKey = container.SnapshotKey
|
||||
default:
|
||||
return containers.Container{}, errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
|
||||
// apply the field mask. If you update this code, you better follow the
|
||||
// field mask rules in field_mask.proto. If you don't know what this
|
||||
// is, do not update this code.
|
||||
for _, path := range fieldpaths {
|
||||
if strings.HasPrefix(path, "labels.") {
|
||||
if updated.Labels == nil {
|
||||
updated.Labels = map[string]string{}
|
||||
}
|
||||
key := strings.TrimPrefix(path, "labels.")
|
||||
updated.Labels[key] = container.Labels[key]
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(path, "extensions.") {
|
||||
if updated.Extensions == nil {
|
||||
updated.Extensions = map[string]types.Any{}
|
||||
}
|
||||
key := strings.TrimPrefix(path, "extensions.")
|
||||
updated.Extensions[key] = container.Extensions[key]
|
||||
continue
|
||||
}
|
||||
|
||||
switch path {
|
||||
case "labels":
|
||||
updated.Labels = container.Labels
|
||||
case "spec":
|
||||
updated.Spec = container.Spec
|
||||
case "extensions":
|
||||
updated.Extensions = container.Extensions
|
||||
case "image":
|
||||
updated.Image = container.Image
|
||||
case "snapshotkey":
|
||||
updated.SnapshotKey = container.SnapshotKey
|
||||
default:
|
||||
return errors.Wrapf(errdefs.ErrInvalidArgument, "cannot update %q field on %q", path, container.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateContainer(&updated); err != nil {
|
||||
return containers.Container{}, errors.Wrap(err, "update failed validation")
|
||||
}
|
||||
if err := validateContainer(&updated); err != nil {
|
||||
return errors.Wrap(err, "update failed validation")
|
||||
}
|
||||
|
||||
updated.CreatedAt = createdat
|
||||
updated.UpdatedAt = time.Now().UTC()
|
||||
if err := writeContainer(cbkt, &updated); err != nil {
|
||||
return containers.Container{}, errors.Wrapf(err, "failed to write container %q", container.ID)
|
||||
updated.CreatedAt = createdat
|
||||
updated.UpdatedAt = time.Now().UTC()
|
||||
if err := writeContainer(cbkt, &updated); err != nil {
|
||||
return errors.Wrapf(err, "failed to write container %q", container.ID)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return containers.Container{}, err
|
||||
}
|
||||
|
||||
return updated, nil
|
||||
@ -235,15 +258,23 @@ func (s *containerStore) Delete(ctx context.Context, id string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
bkt := getContainersBucket(s.tx, namespace)
|
||||
if bkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %q in namespace %q", id, namespace)
|
||||
}
|
||||
return update(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
bkt := getContainersBucket(tx, namespace)
|
||||
if bkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "cannot delete container %q in namespace %q", id, namespace)
|
||||
}
|
||||
|
||||
if err := bkt.DeleteBucket([]byte(id)); err == bolt.ErrBucketNotFound {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "container %v", id)
|
||||
}
|
||||
return err
|
||||
if err := bkt.DeleteBucket([]byte(id)); err != nil {
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "container %v", id)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
atomic.AddUint32(&s.db.dirty, 1)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func validateContainer(container *containers.Container) error {
|
||||
|
4
vendor/github.com/containerd/containerd/metadata/content.go
generated
vendored
4
vendor/github.com/containerd/containerd/metadata/content.go
generated
vendored
@ -21,6 +21,7 @@ import (
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
@ -221,9 +222,8 @@ func (cs *contentStore) Delete(ctx context.Context, dgst digest.Digest) error {
|
||||
}
|
||||
|
||||
// Mark content store as dirty for triggering garbage collection
|
||||
cs.db.dirtyL.Lock()
|
||||
atomic.AddUint32(&cs.db.dirty, 1)
|
||||
cs.db.dirtyCS = true
|
||||
cs.db.dirtyL.Unlock()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
33
vendor/github.com/containerd/containerd/metadata/db.go
generated
vendored
33
vendor/github.com/containerd/containerd/metadata/db.go
generated
vendored
@ -21,6 +21,7 @@ import (
|
||||
"encoding/binary"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/content"
|
||||
@ -75,10 +76,16 @@ type DB struct {
|
||||
// sweep phases without preventing read transactions.
|
||||
wlock sync.RWMutex
|
||||
|
||||
// dirty flags and lock keeps track of datastores which have had deletions
|
||||
// since the last garbage collection. These datastores will will be garbage
|
||||
// collected during the next garbage collection.
|
||||
dirtyL sync.Mutex
|
||||
// dirty flag indicates that references have been removed which require
|
||||
// a garbage collection to ensure the database is clean. This tracks
|
||||
// the number of dirty operations. This should be updated and read
|
||||
// atomically if outside of wlock.Lock.
|
||||
dirty uint32
|
||||
|
||||
// dirtySS and dirtyCS flags keeps track of datastores which have had
|
||||
// deletions since the last garbage collection. These datastores will
|
||||
// be garbage collected during the next garbage collection. These
|
||||
// should only be updated inside of a write transaction or wlock.Lock.
|
||||
dirtySS map[string]struct{}
|
||||
dirtyCS bool
|
||||
|
||||
@ -162,7 +169,7 @@ func (m *DB) Init(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Previous version fo database found
|
||||
// Previous version of database found
|
||||
if schema != "v0" {
|
||||
updates := migrations[i:]
|
||||
|
||||
@ -237,12 +244,10 @@ func (m *DB) Update(fn func(*bolt.Tx) error) error {
|
||||
defer m.wlock.RUnlock()
|
||||
err := m.db.Update(fn)
|
||||
if err == nil {
|
||||
m.dirtyL.Lock()
|
||||
dirty := m.dirtyCS || len(m.dirtySS) > 0
|
||||
dirty := atomic.LoadUint32(&m.dirty) > 0
|
||||
for _, fn := range m.mutationCallbacks {
|
||||
fn(dirty)
|
||||
}
|
||||
m.dirtyL.Unlock()
|
||||
}
|
||||
|
||||
return err
|
||||
@ -254,9 +259,9 @@ func (m *DB) Update(fn func(*bolt.Tx) error) error {
|
||||
// The callback function is an argument for whether a deletion has occurred
|
||||
// since the last garbage collection.
|
||||
func (m *DB) RegisterMutationCallback(fn func(bool)) {
|
||||
m.dirtyL.Lock()
|
||||
m.wlock.Lock()
|
||||
m.mutationCallbacks = append(m.mutationCallbacks, fn)
|
||||
m.dirtyL.Unlock()
|
||||
m.wlock.Unlock()
|
||||
}
|
||||
|
||||
// GCStats holds the duration for the different phases of the garbage collector
|
||||
@ -282,8 +287,6 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m.dirtyL.Lock()
|
||||
|
||||
if err := m.db.Update(func(tx *bolt.Tx) error {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
@ -309,7 +312,6 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
m.dirtyL.Unlock()
|
||||
m.wlock.Unlock()
|
||||
return nil, err
|
||||
}
|
||||
@ -317,6 +319,9 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
var stats GCStats
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// reset dirty, no need for atomic inside of wlock.Lock
|
||||
m.dirty = 0
|
||||
|
||||
if len(m.dirtySS) > 0 {
|
||||
var sl sync.Mutex
|
||||
stats.SnapshotD = map[string]time.Duration{}
|
||||
@ -349,8 +354,6 @@ func (m *DB) GarbageCollect(ctx context.Context) (gc.Stats, error) {
|
||||
m.dirtyCS = false
|
||||
}
|
||||
|
||||
m.dirtyL.Unlock()
|
||||
|
||||
stats.MetaD = time.Since(t1)
|
||||
m.wlock.Unlock()
|
||||
|
||||
|
18
vendor/github.com/containerd/containerd/metadata/images.go
generated
vendored
18
vendor/github.com/containerd/containerd/metadata/images.go
generated
vendored
@ -21,6 +21,7 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
@ -249,19 +250,16 @@ func (s *imageStore) Delete(ctx context.Context, name string, opts ...images.Del
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
|
||||
err = bkt.DeleteBucket([]byte(name))
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
if err = bkt.DeleteBucket([]byte(name)); err != nil {
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// A reference to a piece of content has been removed,
|
||||
// mark content store as dirty for triggering garbage
|
||||
// collection
|
||||
s.db.dirtyL.Lock()
|
||||
s.db.dirtyCS = true
|
||||
s.db.dirtyL.Unlock()
|
||||
atomic.AddUint32(&s.db.dirty, 1)
|
||||
|
||||
return err
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
|
309
vendor/github.com/containerd/containerd/metadata/leases.go
generated
vendored
309
vendor/github.com/containerd/containerd/metadata/leases.go
generated
vendored
@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
@ -35,14 +36,14 @@ import (
|
||||
// LeaseManager manages the create/delete lifecycle of leases
|
||||
// and also returns existing leases
|
||||
type LeaseManager struct {
|
||||
tx *bolt.Tx
|
||||
db *DB
|
||||
}
|
||||
|
||||
// NewLeaseManager creates a new lease manager for managing leases using
|
||||
// the provided database transaction.
|
||||
func NewLeaseManager(tx *bolt.Tx) *LeaseManager {
|
||||
func NewLeaseManager(db *DB) *LeaseManager {
|
||||
return &LeaseManager{
|
||||
tx: tx,
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,35 +64,40 @@ func (lm *LeaseManager) Create(ctx context.Context, opts ...leases.Opt) (leases.
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
|
||||
topbkt, err := createBucketIfNotExists(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if err != nil {
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
|
||||
txbkt, err := topbkt.CreateBucket([]byte(l.ID))
|
||||
if err != nil {
|
||||
if err == bolt.ErrBucketExists {
|
||||
err = errdefs.ErrAlreadyExists
|
||||
if err := update(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt, err := createBucketIfNotExists(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return leases.Lease{}, errors.Wrapf(err, "lease %q", l.ID)
|
||||
}
|
||||
|
||||
t := time.Now().UTC()
|
||||
createdAt, err := t.MarshalBinary()
|
||||
if err != nil {
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
if err := txbkt.Put(bucketKeyCreatedAt, createdAt); err != nil {
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
|
||||
if l.Labels != nil {
|
||||
if err := boltutil.WriteLabels(txbkt, l.Labels); err != nil {
|
||||
return leases.Lease{}, err
|
||||
txbkt, err := topbkt.CreateBucket([]byte(l.ID))
|
||||
if err != nil {
|
||||
if err == bolt.ErrBucketExists {
|
||||
err = errdefs.ErrAlreadyExists
|
||||
}
|
||||
return errors.Wrapf(err, "lease %q", l.ID)
|
||||
}
|
||||
}
|
||||
l.CreatedAt = t
|
||||
|
||||
t := time.Now().UTC()
|
||||
createdAt, err := t.MarshalBinary()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := txbkt.Put(bucketKeyCreatedAt, createdAt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l.Labels != nil {
|
||||
if err := boltutil.WriteLabels(txbkt, l.Labels); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
l.CreatedAt = t
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
@ -102,17 +108,22 @@ func (lm *LeaseManager) Delete(ctx context.Context, lease leases.Lease, _ ...lea
|
||||
return err
|
||||
}
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
if err := topbkt.DeleteBucket([]byte(lease.ID)); err != nil {
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
return update(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
if err := topbkt.DeleteBucket([]byte(lease.ID)); err != nil {
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
err = errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
atomic.AddUint32(&lm.db.dirty, 1)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// List lists all active leases
|
||||
@ -129,39 +140,41 @@ func (lm *LeaseManager) List(ctx context.Context, fs ...string) ([]leases.Lease,
|
||||
|
||||
var ll []leases.Lease
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if topbkt == nil {
|
||||
return ll, nil
|
||||
}
|
||||
|
||||
if err := topbkt.ForEach(func(k, v []byte) error {
|
||||
if v != nil {
|
||||
if err := view(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases)
|
||||
if topbkt == nil {
|
||||
return nil
|
||||
}
|
||||
txbkt := topbkt.Bucket(k)
|
||||
|
||||
l := leases.Lease{
|
||||
ID: string(k),
|
||||
}
|
||||
return topbkt.ForEach(func(k, v []byte) error {
|
||||
if v != nil {
|
||||
return nil
|
||||
}
|
||||
txbkt := topbkt.Bucket(k)
|
||||
|
||||
if v := txbkt.Get(bucketKeyCreatedAt); v != nil {
|
||||
t := &l.CreatedAt
|
||||
if err := t.UnmarshalBinary(v); err != nil {
|
||||
l := leases.Lease{
|
||||
ID: string(k),
|
||||
}
|
||||
|
||||
if v := txbkt.Get(bucketKeyCreatedAt); v != nil {
|
||||
t := &l.CreatedAt
|
||||
if err := t.UnmarshalBinary(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
labels, err := boltutil.ReadLabels(txbkt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
l.Labels = labels
|
||||
|
||||
labels, err := boltutil.ReadLabels(txbkt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
l.Labels = labels
|
||||
if filter.Match(adaptLease(l)) {
|
||||
ll = append(ll, l)
|
||||
}
|
||||
|
||||
if filter.Match(adaptLease(l)) {
|
||||
ll = append(ll, l)
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -176,24 +189,26 @@ func (lm *LeaseManager) AddResource(ctx context.Context, lease leases.Lease, r l
|
||||
return err
|
||||
}
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
return update(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
|
||||
keys, ref, err := parseLeaseResource(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bkt := topbkt
|
||||
for _, key := range keys {
|
||||
bkt, err = bkt.CreateBucketIfNotExists([]byte(key))
|
||||
keys, ref, err := parseLeaseResource(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return bkt.Put([]byte(ref), nil)
|
||||
|
||||
bkt := topbkt
|
||||
for _, key := range keys {
|
||||
bkt, err = bkt.CreateBucketIfNotExists([]byte(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return bkt.Put([]byte(ref), nil)
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteResource dereferences the resource by the provided lease.
|
||||
@ -203,28 +218,35 @@ func (lm *LeaseManager) DeleteResource(ctx context.Context, lease leases.Lease,
|
||||
return err
|
||||
}
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
|
||||
keys, ref, err := parseLeaseResource(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bkt := topbkt
|
||||
for _, key := range keys {
|
||||
if bkt == nil {
|
||||
break
|
||||
return update(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
bkt = bkt.Bucket([]byte(key))
|
||||
}
|
||||
|
||||
if bkt == nil {
|
||||
keys, ref, err := parseLeaseResource(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bkt := topbkt
|
||||
for _, key := range keys {
|
||||
if bkt == nil {
|
||||
break
|
||||
}
|
||||
bkt = bkt.Bucket([]byte(key))
|
||||
}
|
||||
|
||||
if bkt != nil {
|
||||
if err := bkt.Delete([]byte(ref)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
atomic.AddUint32(&lm.db.dirty, 1)
|
||||
|
||||
return nil
|
||||
}
|
||||
return bkt.Delete([]byte(ref))
|
||||
})
|
||||
}
|
||||
|
||||
// ListResources lists all the resources referenced by the lease.
|
||||
@ -234,59 +256,66 @@ func (lm *LeaseManager) ListResources(ctx context.Context, lease leases.Lease) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
topbkt := getBucket(lm.tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return nil, errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
var rs []leases.Resource
|
||||
|
||||
rs := make([]leases.Resource, 0)
|
||||
if err := view(ctx, lm.db, func(tx *bolt.Tx) error {
|
||||
|
||||
// content resources
|
||||
if cbkt := topbkt.Bucket(bucketKeyObjectContent); cbkt != nil {
|
||||
if err := cbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: string(bucketKeyObjectContent),
|
||||
})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
topbkt := getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectLeases, []byte(lease.ID))
|
||||
if topbkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "lease %q", lease.ID)
|
||||
}
|
||||
}
|
||||
|
||||
// ingest resources
|
||||
if lbkt := topbkt.Bucket(bucketKeyObjectIngests); lbkt != nil {
|
||||
if err := lbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: string(bucketKeyObjectIngests),
|
||||
})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// snapshot resources
|
||||
if sbkt := topbkt.Bucket(bucketKeyObjectSnapshots); sbkt != nil {
|
||||
if err := sbkt.ForEach(func(sk, sv []byte) error {
|
||||
if sv != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
snbkt := sbkt.Bucket(sk)
|
||||
return snbkt.ForEach(func(k, _ []byte) error {
|
||||
// content resources
|
||||
if cbkt := topbkt.Bucket(bucketKeyObjectContent); cbkt != nil {
|
||||
if err := cbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: fmt.Sprintf("%s/%s", bucketKeyObjectSnapshots, sk),
|
||||
Type: string(bucketKeyObjectContent),
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// ingest resources
|
||||
if lbkt := topbkt.Bucket(bucketKeyObjectIngests); lbkt != nil {
|
||||
if err := lbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: string(bucketKeyObjectIngests),
|
||||
})
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// snapshot resources
|
||||
if sbkt := topbkt.Bucket(bucketKeyObjectSnapshots); sbkt != nil {
|
||||
if err := sbkt.ForEach(func(sk, sv []byte) error {
|
||||
if sv != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
snbkt := sbkt.Bucket(sk)
|
||||
return snbkt.ForEach(func(k, _ []byte) error {
|
||||
rs = append(rs, leases.Resource{
|
||||
ID: string(k),
|
||||
Type: fmt.Sprintf("%s/%s", bucketKeyObjectSnapshots, sk),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs, nil
|
||||
}
|
||||
|
4
vendor/github.com/containerd/containerd/metadata/snapshot.go
generated
vendored
4
vendor/github.com/containerd/containerd/metadata/snapshot.go
generated
vendored
@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
@ -517,9 +518,8 @@ func (s *snapshotter) Remove(ctx context.Context, key string) error {
|
||||
}
|
||||
|
||||
// Mark snapshotter as dirty for triggering garbage collection
|
||||
s.db.dirtyL.Lock()
|
||||
atomic.AddUint32(&s.db.dirty, 1)
|
||||
s.db.dirtySS[s.name] = struct{}{}
|
||||
s.db.dirtyL.Unlock()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
24
vendor/github.com/containerd/containerd/metrics/types/v1/types.go
generated
vendored
24
vendor/github.com/containerd/containerd/metrics/types/v1/types.go
generated
vendored
@ -18,27 +18,29 @@
|
||||
|
||||
package v1
|
||||
|
||||
import "github.com/containerd/cgroups"
|
||||
import (
|
||||
v1 "github.com/containerd/cgroups/stats/v1"
|
||||
)
|
||||
|
||||
type (
|
||||
// Metrics alias
|
||||
Metrics = cgroups.Metrics
|
||||
Metrics = v1.Metrics
|
||||
// BlkIOEntry alias
|
||||
BlkIOEntry = cgroups.BlkIOEntry
|
||||
BlkIOEntry = v1.BlkIOEntry
|
||||
// MemoryStat alias
|
||||
MemoryStat = cgroups.MemoryStat
|
||||
MemoryStat = v1.MemoryStat
|
||||
// CPUStat alias
|
||||
CPUStat = cgroups.CPUStat
|
||||
CPUStat = v1.CPUStat
|
||||
// CPUUsage alias
|
||||
CPUUsage = cgroups.CPUUsage
|
||||
CPUUsage = v1.CPUUsage
|
||||
// BlkIOStat alias
|
||||
BlkIOStat = cgroups.BlkIOStat
|
||||
BlkIOStat = v1.BlkIOStat
|
||||
// PidsStat alias
|
||||
PidsStat = cgroups.PidsStat
|
||||
PidsStat = v1.PidsStat
|
||||
// RdmaStat alias
|
||||
RdmaStat = cgroups.RdmaStat
|
||||
RdmaStat = v1.RdmaStat
|
||||
// RdmaEntry alias
|
||||
RdmaEntry = cgroups.RdmaEntry
|
||||
RdmaEntry = v1.RdmaEntry
|
||||
// HugetlbStat alias
|
||||
HugetlbStat = cgroups.HugetlbStat
|
||||
HugetlbStat = v1.HugetlbStat
|
||||
)
|
||||
|
2
vendor/github.com/containerd/containerd/namespaces/context.go
generated
vendored
2
vendor/github.com/containerd/containerd/namespaces/context.go
generated
vendored
@ -64,7 +64,7 @@ func Namespace(ctx context.Context) (string, bool) {
|
||||
return namespace, ok
|
||||
}
|
||||
|
||||
// NamespaceRequired returns the valid namepace from the context or an error.
|
||||
// NamespaceRequired returns the valid namespace from the context or an error.
|
||||
func NamespaceRequired(ctx context.Context) (string, error) {
|
||||
namespace, ok := Namespace(ctx)
|
||||
if !ok || namespace == "" {
|
||||
|
2
vendor/github.com/containerd/containerd/oci/spec.go
generated
vendored
2
vendor/github.com/containerd/containerd/oci/spec.go
generated
vendored
@ -78,7 +78,7 @@ func generateDefaultSpecWithPlatform(ctx context.Context, platform, id string, s
|
||||
return err
|
||||
}
|
||||
|
||||
// ApplyOpts applys the options to the given spec, injecting data from the
|
||||
// ApplyOpts applies the options to the given spec, injecting data from the
|
||||
// context, client and container instance.
|
||||
func ApplyOpts(ctx context.Context, client Client, c *containers.Container, s *Spec, opts ...SpecOpts) error {
|
||||
for _, o := range opts {
|
||||
|
4
vendor/github.com/containerd/containerd/pkg/process/deleted_state.go
generated
vendored
4
vendor/github.com/containerd/containerd/pkg/process/deleted_state.go
generated
vendored
@ -69,3 +69,7 @@ func (s *deletedState) SetExited(status int) {
|
||||
func (s *deletedState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
|
||||
return nil, errors.Errorf("cannot exec in a deleted state")
|
||||
}
|
||||
|
||||
func (s *deletedState) Status(ctx context.Context) (string, error) {
|
||||
return "stopped", nil
|
||||
}
|
||||
|
14
vendor/github.com/containerd/containerd/pkg/process/exec.go
generated
vendored
14
vendor/github.com/containerd/containerd/pkg/process/exec.go
generated
vendored
@ -261,17 +261,5 @@ func (e *execProcess) Status(ctx context.Context) (string, error) {
|
||||
}
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
// if we don't have a pid(pid=0) then the exec process has just been created
|
||||
if e.pid.get() == 0 {
|
||||
return "created", nil
|
||||
}
|
||||
if e.pid.get() == StoppedPID {
|
||||
return "stopped", nil
|
||||
}
|
||||
// if we have a pid and it can be signaled, the process is running
|
||||
if err := unix.Kill(e.pid.get(), 0); err == nil {
|
||||
return "running", nil
|
||||
}
|
||||
// else if we have a pid but it can nolonger be signaled, it has stopped
|
||||
return "stopped", nil
|
||||
return e.execState.Status(ctx)
|
||||
}
|
||||
|
13
vendor/github.com/containerd/containerd/pkg/process/exec_state.go
generated
vendored
13
vendor/github.com/containerd/containerd/pkg/process/exec_state.go
generated
vendored
@ -31,6 +31,7 @@ type execState interface {
|
||||
Delete(context.Context) error
|
||||
Kill(context.Context, uint32, bool) error
|
||||
SetExited(int)
|
||||
Status(context.Context) (string, error)
|
||||
}
|
||||
|
||||
type execCreatedState struct {
|
||||
@ -82,6 +83,10 @@ func (s *execCreatedState) SetExited(status int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *execCreatedState) Status(ctx context.Context) (string, error) {
|
||||
return "created", nil
|
||||
}
|
||||
|
||||
type execRunningState struct {
|
||||
p *execProcess
|
||||
}
|
||||
@ -120,6 +125,10 @@ func (s *execRunningState) SetExited(status int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *execRunningState) Status(ctx context.Context) (string, error) {
|
||||
return "running", nil
|
||||
}
|
||||
|
||||
type execStoppedState struct {
|
||||
p *execProcess
|
||||
}
|
||||
@ -157,3 +166,7 @@ func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error
|
||||
func (s *execStoppedState) SetExited(status int) {
|
||||
// no op
|
||||
}
|
||||
|
||||
func (s *execStoppedState) Status(ctx context.Context) (string, error) {
|
||||
return "stopped", nil
|
||||
}
|
||||
|
28
vendor/github.com/containerd/containerd/pkg/process/init.go
generated
vendored
28
vendor/github.com/containerd/containerd/pkg/process/init.go
generated
vendored
@ -56,12 +56,14 @@ type Init struct {
|
||||
|
||||
WorkDir string
|
||||
|
||||
id string
|
||||
Bundle string
|
||||
console console.Console
|
||||
Platform stdio.Platform
|
||||
io *processIO
|
||||
runtime *runc.Runc
|
||||
id string
|
||||
Bundle string
|
||||
console console.Console
|
||||
Platform stdio.Platform
|
||||
io *processIO
|
||||
runtime *runc.Runc
|
||||
// pausing preserves the pausing state.
|
||||
pausing *atomicBool
|
||||
status int
|
||||
exited time.Time
|
||||
pid safePid
|
||||
@ -97,6 +99,7 @@ func New(id string, runtime *runc.Runc, stdio stdio.Stdio) *Init {
|
||||
p := &Init{
|
||||
id: id,
|
||||
runtime: runtime,
|
||||
pausing: new(atomicBool),
|
||||
stdio: stdio,
|
||||
status: 0,
|
||||
waitBlock: make(chan struct{}),
|
||||
@ -237,17 +240,14 @@ func (p *Init) ExitedAt() time.Time {
|
||||
|
||||
// Status of the process
|
||||
func (p *Init) Status(ctx context.Context) (string, error) {
|
||||
if p.pausing.get() {
|
||||
return "pausing", nil
|
||||
}
|
||||
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
c, err := p.runtime.State(ctx, p.id)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "does not exist") {
|
||||
return "stopped", nil
|
||||
}
|
||||
return "", p.runtimeError(err, "OCI runtime state failed")
|
||||
}
|
||||
return c.Status, nil
|
||||
return p.initState.Status(ctx)
|
||||
}
|
||||
|
||||
// Start the init process
|
||||
|
28
vendor/github.com/containerd/containerd/pkg/process/init_state.go
generated
vendored
28
vendor/github.com/containerd/containerd/pkg/process/init_state.go
generated
vendored
@ -37,6 +37,7 @@ type initState interface {
|
||||
Exec(context.Context, string, *ExecConfig) (Process, error)
|
||||
Kill(context.Context, uint32, bool) error
|
||||
SetExited(int)
|
||||
Status(context.Context) (string, error)
|
||||
}
|
||||
|
||||
type createdState struct {
|
||||
@ -103,6 +104,10 @@ func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (Pr
|
||||
return s.p.exec(ctx, path, r)
|
||||
}
|
||||
|
||||
func (s *createdState) Status(ctx context.Context) (string, error) {
|
||||
return "created", nil
|
||||
}
|
||||
|
||||
type createdCheckpointState struct {
|
||||
p *Init
|
||||
opts *runc.RestoreOpts
|
||||
@ -211,6 +216,10 @@ func (s *createdCheckpointState) Exec(ctx context.Context, path string, r *ExecC
|
||||
return nil, errors.Errorf("cannot exec in a created state")
|
||||
}
|
||||
|
||||
func (s *createdCheckpointState) Status(ctx context.Context) (string, error) {
|
||||
return "created", nil
|
||||
}
|
||||
|
||||
type runningState struct {
|
||||
p *Init
|
||||
}
|
||||
@ -228,6 +237,13 @@ func (s *runningState) transition(name string) error {
|
||||
}
|
||||
|
||||
func (s *runningState) Pause(ctx context.Context) error {
|
||||
s.p.pausing.set(true)
|
||||
// NOTE "pausing" will be returned in the short window
|
||||
// after `transition("paused")`, before `pausing` is reset
|
||||
// to false. That doesn't break the state machine, just
|
||||
// delays the "paused" state a little bit.
|
||||
defer s.p.pausing.set(false)
|
||||
|
||||
if err := s.p.runtime.Pause(ctx, s.p.id); err != nil {
|
||||
return s.p.runtimeError(err, "OCI runtime pause failed")
|
||||
}
|
||||
@ -271,6 +287,10 @@ func (s *runningState) Exec(ctx context.Context, path string, r *ExecConfig) (Pr
|
||||
return s.p.exec(ctx, path, r)
|
||||
}
|
||||
|
||||
func (s *runningState) Status(ctx context.Context) (string, error) {
|
||||
return "running", nil
|
||||
}
|
||||
|
||||
type pausedState struct {
|
||||
p *Init
|
||||
}
|
||||
@ -335,6 +355,10 @@ func (s *pausedState) Exec(ctx context.Context, path string, r *ExecConfig) (Pro
|
||||
return nil, errors.Errorf("cannot exec in a paused state")
|
||||
}
|
||||
|
||||
func (s *pausedState) Status(ctx context.Context) (string, error) {
|
||||
return "paused", nil
|
||||
}
|
||||
|
||||
type stoppedState struct {
|
||||
p *Init
|
||||
}
|
||||
@ -387,3 +411,7 @@ func (s *stoppedState) SetExited(status int) {
|
||||
func (s *stoppedState) Exec(ctx context.Context, path string, r *ExecConfig) (Process, error) {
|
||||
return nil, errors.Errorf("cannot exec in a stopped state")
|
||||
}
|
||||
|
||||
func (s *stoppedState) Status(ctx context.Context) (string, error) {
|
||||
return "stopped", nil
|
||||
}
|
||||
|
16
vendor/github.com/containerd/containerd/pkg/process/utils.go
generated
vendored
16
vendor/github.com/containerd/containerd/pkg/process/utils.go
generated
vendored
@ -27,6 +27,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
@ -62,6 +63,20 @@ func (s *safePid) set(pid int) {
|
||||
s.Unlock()
|
||||
}
|
||||
|
||||
type atomicBool int32
|
||||
|
||||
func (ab *atomicBool) set(b bool) {
|
||||
if b {
|
||||
atomic.StoreInt32((*int32)(ab), 1)
|
||||
} else {
|
||||
atomic.StoreInt32((*int32)(ab), 0)
|
||||
}
|
||||
}
|
||||
|
||||
func (ab *atomicBool) get() bool {
|
||||
return atomic.LoadInt32((*int32)(ab)) == 1
|
||||
}
|
||||
|
||||
// TODO(mlaventure): move to runc package?
|
||||
func getLastRuntimeError(r *runc.Runc) (string, error) {
|
||||
if r.Log == "" {
|
||||
@ -127,6 +142,7 @@ func checkKillError(err error) error {
|
||||
}
|
||||
if strings.Contains(err.Error(), "os: process already finished") ||
|
||||
strings.Contains(err.Error(), "container not running") ||
|
||||
strings.Contains(strings.ToLower(err.Error()), "no such process") ||
|
||||
err == unix.ESRCH {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "process already finished")
|
||||
}
|
||||
|
2
vendor/github.com/containerd/containerd/process.go
generated
vendored
2
vendor/github.com/containerd/containerd/process.go
generated
vendored
@ -61,7 +61,7 @@ func NewExitStatus(code uint32, t time.Time, err error) *ExitStatus {
|
||||
}
|
||||
}
|
||||
|
||||
// ExitStatus encapsulates a process' exit status.
|
||||
// ExitStatus encapsulates a process's exit status.
|
||||
// It is used by `Wait()` to return either a process exit code or an error
|
||||
type ExitStatus struct {
|
||||
code uint32
|
||||
|
797
vendor/github.com/containerd/containerd/reference/docker/reference.go
generated
vendored
Normal file
797
vendor/github.com/containerd/containerd/reference/docker/reference.go
generated
vendored
Normal file
@ -0,0 +1,797 @@
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Package docker provides a general type to represent any way of referencing images within the registry.
|
||||
// Its main purpose is to abstract tags and digests (content-addressable hash).
|
||||
//
|
||||
// Grammar
|
||||
//
|
||||
// reference := name [ ":" tag ] [ "@" digest ]
|
||||
// name := [domain '/'] path-component ['/' path-component]*
|
||||
// domain := domain-component ['.' domain-component]* [':' port-number]
|
||||
// domain-component := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/
|
||||
// port-number := /[0-9]+/
|
||||
// path-component := alpha-numeric [separator alpha-numeric]*
|
||||
// alpha-numeric := /[a-z0-9]+/
|
||||
// separator := /[_.]|__|[-]*/
|
||||
//
|
||||
// tag := /[\w][\w.-]{0,127}/
|
||||
//
|
||||
// digest := digest-algorithm ":" digest-hex
|
||||
// digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ]*
|
||||
// digest-algorithm-separator := /[+.-_]/
|
||||
// digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/
|
||||
// digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value
|
||||
//
|
||||
// identifier := /[a-f0-9]{64}/
|
||||
// short-identifier := /[a-f0-9]{6,64}/
|
||||
package docker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
)
|
||||
|
||||
const (
|
||||
// NameTotalLengthMax is the maximum total number of characters in a repository name.
|
||||
NameTotalLengthMax = 255
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrReferenceInvalidFormat represents an error while trying to parse a string as a reference.
|
||||
ErrReferenceInvalidFormat = errors.New("invalid reference format")
|
||||
|
||||
// ErrTagInvalidFormat represents an error while trying to parse a string as a tag.
|
||||
ErrTagInvalidFormat = errors.New("invalid tag format")
|
||||
|
||||
// ErrDigestInvalidFormat represents an error while trying to parse a string as a tag.
|
||||
ErrDigestInvalidFormat = errors.New("invalid digest format")
|
||||
|
||||
// ErrNameContainsUppercase is returned for invalid repository names that contain uppercase characters.
|
||||
ErrNameContainsUppercase = errors.New("repository name must be lowercase")
|
||||
|
||||
// ErrNameEmpty is returned for empty, invalid repository names.
|
||||
ErrNameEmpty = errors.New("repository name must have at least one component")
|
||||
|
||||
// ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax.
|
||||
ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax)
|
||||
|
||||
// ErrNameNotCanonical is returned when a name is not canonical.
|
||||
ErrNameNotCanonical = errors.New("repository name must be canonical")
|
||||
)
|
||||
|
||||
// Reference is an opaque object reference identifier that may include
|
||||
// modifiers such as a hostname, name, tag, and digest.
|
||||
type Reference interface {
|
||||
// String returns the full reference
|
||||
String() string
|
||||
}
|
||||
|
||||
// Field provides a wrapper type for resolving correct reference types when
|
||||
// working with encoding.
|
||||
type Field struct {
|
||||
reference Reference
|
||||
}
|
||||
|
||||
// AsField wraps a reference in a Field for encoding.
|
||||
func AsField(reference Reference) Field {
|
||||
return Field{reference}
|
||||
}
|
||||
|
||||
// Reference unwraps the reference type from the field to
|
||||
// return the Reference object. This object should be
|
||||
// of the appropriate type to further check for different
|
||||
// reference types.
|
||||
func (f Field) Reference() Reference {
|
||||
return f.reference
|
||||
}
|
||||
|
||||
// MarshalText serializes the field to byte text which
|
||||
// is the string of the reference.
|
||||
func (f Field) MarshalText() (p []byte, err error) {
|
||||
return []byte(f.reference.String()), nil
|
||||
}
|
||||
|
||||
// UnmarshalText parses text bytes by invoking the
|
||||
// reference parser to ensure the appropriately
|
||||
// typed reference object is wrapped by field.
|
||||
func (f *Field) UnmarshalText(p []byte) error {
|
||||
r, err := Parse(string(p))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.reference = r
|
||||
return nil
|
||||
}
|
||||
|
||||
// Named is an object with a full name
|
||||
type Named interface {
|
||||
Reference
|
||||
Name() string
|
||||
}
|
||||
|
||||
// Tagged is an object which has a tag
|
||||
type Tagged interface {
|
||||
Reference
|
||||
Tag() string
|
||||
}
|
||||
|
||||
// NamedTagged is an object including a name and tag.
|
||||
type NamedTagged interface {
|
||||
Named
|
||||
Tag() string
|
||||
}
|
||||
|
||||
// Digested is an object which has a digest
|
||||
// in which it can be referenced by
|
||||
type Digested interface {
|
||||
Reference
|
||||
Digest() digest.Digest
|
||||
}
|
||||
|
||||
// Canonical reference is an object with a fully unique
|
||||
// name including a name with domain and digest
|
||||
type Canonical interface {
|
||||
Named
|
||||
Digest() digest.Digest
|
||||
}
|
||||
|
||||
// namedRepository is a reference to a repository with a name.
|
||||
// A namedRepository has both domain and path components.
|
||||
type namedRepository interface {
|
||||
Named
|
||||
Domain() string
|
||||
Path() string
|
||||
}
|
||||
|
||||
// Domain returns the domain part of the Named reference
|
||||
func Domain(named Named) string {
|
||||
if r, ok := named.(namedRepository); ok {
|
||||
return r.Domain()
|
||||
}
|
||||
domain, _ := splitDomain(named.Name())
|
||||
return domain
|
||||
}
|
||||
|
||||
// Path returns the name without the domain part of the Named reference
|
||||
func Path(named Named) (name string) {
|
||||
if r, ok := named.(namedRepository); ok {
|
||||
return r.Path()
|
||||
}
|
||||
_, path := splitDomain(named.Name())
|
||||
return path
|
||||
}
|
||||
|
||||
func splitDomain(name string) (string, string) {
|
||||
match := anchoredNameRegexp.FindStringSubmatch(name)
|
||||
if len(match) != 3 {
|
||||
return "", name
|
||||
}
|
||||
return match[1], match[2]
|
||||
}
|
||||
|
||||
// SplitHostname splits a named reference into a
|
||||
// hostname and name string. If no valid hostname is
|
||||
// found, the hostname is empty and the full value
|
||||
// is returned as name
|
||||
// DEPRECATED: Use Domain or Path
|
||||
func SplitHostname(named Named) (string, string) {
|
||||
if r, ok := named.(namedRepository); ok {
|
||||
return r.Domain(), r.Path()
|
||||
}
|
||||
return splitDomain(named.Name())
|
||||
}
|
||||
|
||||
// Parse parses s and returns a syntactically valid Reference.
|
||||
// If an error was encountered it is returned, along with a nil Reference.
|
||||
// NOTE: Parse will not handle short digests.
|
||||
func Parse(s string) (Reference, error) {
|
||||
matches := ReferenceRegexp.FindStringSubmatch(s)
|
||||
if matches == nil {
|
||||
if s == "" {
|
||||
return nil, ErrNameEmpty
|
||||
}
|
||||
if ReferenceRegexp.FindStringSubmatch(strings.ToLower(s)) != nil {
|
||||
return nil, ErrNameContainsUppercase
|
||||
}
|
||||
return nil, ErrReferenceInvalidFormat
|
||||
}
|
||||
|
||||
if len(matches[1]) > NameTotalLengthMax {
|
||||
return nil, ErrNameTooLong
|
||||
}
|
||||
|
||||
var repo repository
|
||||
|
||||
nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1])
|
||||
if len(nameMatch) == 3 {
|
||||
repo.domain = nameMatch[1]
|
||||
repo.path = nameMatch[2]
|
||||
} else {
|
||||
repo.domain = ""
|
||||
repo.path = matches[1]
|
||||
}
|
||||
|
||||
ref := reference{
|
||||
namedRepository: repo,
|
||||
tag: matches[2],
|
||||
}
|
||||
if matches[3] != "" {
|
||||
var err error
|
||||
ref.digest, err = digest.Parse(matches[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
r := getBestReferenceType(ref)
|
||||
if r == nil {
|
||||
return nil, ErrNameEmpty
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// ParseNamed parses s and returns a syntactically valid reference implementing
|
||||
// the Named interface. The reference must have a name and be in the canonical
|
||||
// form, otherwise an error is returned.
|
||||
// If an error was encountered it is returned, along with a nil Reference.
|
||||
// NOTE: ParseNamed will not handle short digests.
|
||||
func ParseNamed(s string) (Named, error) {
|
||||
named, err := ParseNormalizedNamed(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if named.String() != s {
|
||||
return nil, ErrNameNotCanonical
|
||||
}
|
||||
return named, nil
|
||||
}
|
||||
|
||||
// WithName returns a named object representing the given string. If the input
|
||||
// is invalid ErrReferenceInvalidFormat will be returned.
|
||||
func WithName(name string) (Named, error) {
|
||||
if len(name) > NameTotalLengthMax {
|
||||
return nil, ErrNameTooLong
|
||||
}
|
||||
|
||||
match := anchoredNameRegexp.FindStringSubmatch(name)
|
||||
if match == nil || len(match) != 3 {
|
||||
return nil, ErrReferenceInvalidFormat
|
||||
}
|
||||
return repository{
|
||||
domain: match[1],
|
||||
path: match[2],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WithTag combines the name from "name" and the tag from "tag" to form a
|
||||
// reference incorporating both the name and the tag.
|
||||
func WithTag(name Named, tag string) (NamedTagged, error) {
|
||||
if !anchoredTagRegexp.MatchString(tag) {
|
||||
return nil, ErrTagInvalidFormat
|
||||
}
|
||||
var repo repository
|
||||
if r, ok := name.(namedRepository); ok {
|
||||
repo.domain = r.Domain()
|
||||
repo.path = r.Path()
|
||||
} else {
|
||||
repo.path = name.Name()
|
||||
}
|
||||
if canonical, ok := name.(Canonical); ok {
|
||||
return reference{
|
||||
namedRepository: repo,
|
||||
tag: tag,
|
||||
digest: canonical.Digest(),
|
||||
}, nil
|
||||
}
|
||||
return taggedReference{
|
||||
namedRepository: repo,
|
||||
tag: tag,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WithDigest combines the name from "name" and the digest from "digest" to form
|
||||
// a reference incorporating both the name and the digest.
|
||||
func WithDigest(name Named, digest digest.Digest) (Canonical, error) {
|
||||
if !anchoredDigestRegexp.MatchString(digest.String()) {
|
||||
return nil, ErrDigestInvalidFormat
|
||||
}
|
||||
var repo repository
|
||||
if r, ok := name.(namedRepository); ok {
|
||||
repo.domain = r.Domain()
|
||||
repo.path = r.Path()
|
||||
} else {
|
||||
repo.path = name.Name()
|
||||
}
|
||||
if tagged, ok := name.(Tagged); ok {
|
||||
return reference{
|
||||
namedRepository: repo,
|
||||
tag: tagged.Tag(),
|
||||
digest: digest,
|
||||
}, nil
|
||||
}
|
||||
return canonicalReference{
|
||||
namedRepository: repo,
|
||||
digest: digest,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// TrimNamed removes any tag or digest from the named reference.
|
||||
func TrimNamed(ref Named) Named {
|
||||
domain, path := SplitHostname(ref)
|
||||
return repository{
|
||||
domain: domain,
|
||||
path: path,
|
||||
}
|
||||
}
|
||||
|
||||
func getBestReferenceType(ref reference) Reference {
|
||||
if ref.Name() == "" {
|
||||
// Allow digest only references
|
||||
if ref.digest != "" {
|
||||
return digestReference(ref.digest)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if ref.tag == "" {
|
||||
if ref.digest != "" {
|
||||
return canonicalReference{
|
||||
namedRepository: ref.namedRepository,
|
||||
digest: ref.digest,
|
||||
}
|
||||
}
|
||||
return ref.namedRepository
|
||||
}
|
||||
if ref.digest == "" {
|
||||
return taggedReference{
|
||||
namedRepository: ref.namedRepository,
|
||||
tag: ref.tag,
|
||||
}
|
||||
}
|
||||
|
||||
return ref
|
||||
}
|
||||
|
||||
type reference struct {
|
||||
namedRepository
|
||||
tag string
|
||||
digest digest.Digest
|
||||
}
|
||||
|
||||
func (r reference) String() string {
|
||||
return r.Name() + ":" + r.tag + "@" + r.digest.String()
|
||||
}
|
||||
|
||||
func (r reference) Tag() string {
|
||||
return r.tag
|
||||
}
|
||||
|
||||
func (r reference) Digest() digest.Digest {
|
||||
return r.digest
|
||||
}
|
||||
|
||||
type repository struct {
|
||||
domain string
|
||||
path string
|
||||
}
|
||||
|
||||
func (r repository) String() string {
|
||||
return r.Name()
|
||||
}
|
||||
|
||||
func (r repository) Name() string {
|
||||
if r.domain == "" {
|
||||
return r.path
|
||||
}
|
||||
return r.domain + "/" + r.path
|
||||
}
|
||||
|
||||
func (r repository) Domain() string {
|
||||
return r.domain
|
||||
}
|
||||
|
||||
func (r repository) Path() string {
|
||||
return r.path
|
||||
}
|
||||
|
||||
type digestReference digest.Digest
|
||||
|
||||
func (d digestReference) String() string {
|
||||
return digest.Digest(d).String()
|
||||
}
|
||||
|
||||
func (d digestReference) Digest() digest.Digest {
|
||||
return digest.Digest(d)
|
||||
}
|
||||
|
||||
type taggedReference struct {
|
||||
namedRepository
|
||||
tag string
|
||||
}
|
||||
|
||||
func (t taggedReference) String() string {
|
||||
return t.Name() + ":" + t.tag
|
||||
}
|
||||
|
||||
func (t taggedReference) Tag() string {
|
||||
return t.tag
|
||||
}
|
||||
|
||||
type canonicalReference struct {
|
||||
namedRepository
|
||||
digest digest.Digest
|
||||
}
|
||||
|
||||
func (c canonicalReference) String() string {
|
||||
return c.Name() + "@" + c.digest.String()
|
||||
}
|
||||
|
||||
func (c canonicalReference) Digest() digest.Digest {
|
||||
return c.digest
|
||||
}
|
||||
|
||||
var (
|
||||
// alphaNumericRegexp defines the alpha numeric atom, typically a
|
||||
// component of names. This only allows lower case characters and digits.
|
||||
alphaNumericRegexp = match(`[a-z0-9]+`)
|
||||
|
||||
// separatorRegexp defines the separators allowed to be embedded in name
|
||||
// components. This allow one period, one or two underscore and multiple
|
||||
// dashes.
|
||||
separatorRegexp = match(`(?:[._]|__|[-]*)`)
|
||||
|
||||
// nameComponentRegexp restricts registry path component names to start
|
||||
// with at least one letter or number, with following parts able to be
|
||||
// separated by one period, one or two underscore and multiple dashes.
|
||||
nameComponentRegexp = expression(
|
||||
alphaNumericRegexp,
|
||||
optional(repeated(separatorRegexp, alphaNumericRegexp)))
|
||||
|
||||
// domainComponentRegexp restricts the registry domain component of a
|
||||
// repository name to start with a component as defined by DomainRegexp
|
||||
// and followed by an optional port.
|
||||
domainComponentRegexp = match(`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`)
|
||||
|
||||
// DomainRegexp defines the structure of potential domain components
|
||||
// that may be part of image names. This is purposely a subset of what is
|
||||
// allowed by DNS to ensure backwards compatibility with Docker image
|
||||
// names.
|
||||
DomainRegexp = expression(
|
||||
domainComponentRegexp,
|
||||
optional(repeated(literal(`.`), domainComponentRegexp)),
|
||||
optional(literal(`:`), match(`[0-9]+`)))
|
||||
|
||||
// TagRegexp matches valid tag names. From docker/docker:graph/tags.go.
|
||||
TagRegexp = match(`[\w][\w.-]{0,127}`)
|
||||
|
||||
// anchoredTagRegexp matches valid tag names, anchored at the start and
|
||||
// end of the matched string.
|
||||
anchoredTagRegexp = anchored(TagRegexp)
|
||||
|
||||
// DigestRegexp matches valid digests.
|
||||
DigestRegexp = match(`[A-Za-z][A-Za-z0-9]*(?:[-_+.][A-Za-z][A-Za-z0-9]*)*[:][[:xdigit:]]{32,}`)
|
||||
|
||||
// anchoredDigestRegexp matches valid digests, anchored at the start and
|
||||
// end of the matched string.
|
||||
anchoredDigestRegexp = anchored(DigestRegexp)
|
||||
|
||||
// NameRegexp is the format for the name component of references. The
|
||||
// regexp has capturing groups for the domain and name part omitting
|
||||
// the separating forward slash from either.
|
||||
NameRegexp = expression(
|
||||
optional(DomainRegexp, literal(`/`)),
|
||||
nameComponentRegexp,
|
||||
optional(repeated(literal(`/`), nameComponentRegexp)))
|
||||
|
||||
// anchoredNameRegexp is used to parse a name value, capturing the
|
||||
// domain and trailing components.
|
||||
anchoredNameRegexp = anchored(
|
||||
optional(capture(DomainRegexp), literal(`/`)),
|
||||
capture(nameComponentRegexp,
|
||||
optional(repeated(literal(`/`), nameComponentRegexp))))
|
||||
|
||||
// ReferenceRegexp is the full supported format of a reference. The regexp
|
||||
// is anchored and has capturing groups for name, tag, and digest
|
||||
// components.
|
||||
ReferenceRegexp = anchored(capture(NameRegexp),
|
||||
optional(literal(":"), capture(TagRegexp)),
|
||||
optional(literal("@"), capture(DigestRegexp)))
|
||||
|
||||
// IdentifierRegexp is the format for string identifier used as a
|
||||
// content addressable identifier using sha256. These identifiers
|
||||
// are like digests without the algorithm, since sha256 is used.
|
||||
IdentifierRegexp = match(`([a-f0-9]{64})`)
|
||||
|
||||
// ShortIdentifierRegexp is the format used to represent a prefix
|
||||
// of an identifier. A prefix may be used to match a sha256 identifier
|
||||
// within a list of trusted identifiers.
|
||||
ShortIdentifierRegexp = match(`([a-f0-9]{6,64})`)
|
||||
|
||||
// anchoredIdentifierRegexp is used to check or match an
|
||||
// identifier value, anchored at start and end of string.
|
||||
anchoredIdentifierRegexp = anchored(IdentifierRegexp)
|
||||
)
|
||||
|
||||
// match compiles the string to a regular expression.
|
||||
var match = regexp.MustCompile
|
||||
|
||||
// literal compiles s into a literal regular expression, escaping any regexp
|
||||
// reserved characters.
|
||||
func literal(s string) *regexp.Regexp {
|
||||
re := match(regexp.QuoteMeta(s))
|
||||
|
||||
if _, complete := re.LiteralPrefix(); !complete {
|
||||
panic("must be a literal")
|
||||
}
|
||||
|
||||
return re
|
||||
}
|
||||
|
||||
// expression defines a full expression, where each regular expression must
|
||||
// follow the previous.
|
||||
func expression(res ...*regexp.Regexp) *regexp.Regexp {
|
||||
var s string
|
||||
for _, re := range res {
|
||||
s += re.String()
|
||||
}
|
||||
|
||||
return match(s)
|
||||
}
|
||||
|
||||
// optional wraps the expression in a non-capturing group and makes the
|
||||
// production optional.
|
||||
func optional(res ...*regexp.Regexp) *regexp.Regexp {
|
||||
return match(group(expression(res...)).String() + `?`)
|
||||
}
|
||||
|
||||
// repeated wraps the regexp in a non-capturing group to get one or more
|
||||
// matches.
|
||||
func repeated(res ...*regexp.Regexp) *regexp.Regexp {
|
||||
return match(group(expression(res...)).String() + `+`)
|
||||
}
|
||||
|
||||
// group wraps the regexp in a non-capturing group.
|
||||
func group(res ...*regexp.Regexp) *regexp.Regexp {
|
||||
return match(`(?:` + expression(res...).String() + `)`)
|
||||
}
|
||||
|
||||
// capture wraps the expression in a capturing group.
|
||||
func capture(res ...*regexp.Regexp) *regexp.Regexp {
|
||||
return match(`(` + expression(res...).String() + `)`)
|
||||
}
|
||||
|
||||
// anchored anchors the regular expression by adding start and end delimiters.
|
||||
func anchored(res ...*regexp.Regexp) *regexp.Regexp {
|
||||
return match(`^` + expression(res...).String() + `$`)
|
||||
}
|
||||
|
||||
var (
|
||||
legacyDefaultDomain = "index.docker.io"
|
||||
defaultDomain = "docker.io"
|
||||
officialRepoName = "library"
|
||||
defaultTag = "latest"
|
||||
)
|
||||
|
||||
// normalizedNamed represents a name which has been
|
||||
// normalized and has a familiar form. A familiar name
|
||||
// is what is used in Docker UI. An example normalized
|
||||
// name is "docker.io/library/ubuntu" and corresponding
|
||||
// familiar name of "ubuntu".
|
||||
type normalizedNamed interface {
|
||||
Named
|
||||
Familiar() Named
|
||||
}
|
||||
|
||||
// ParseNormalizedNamed parses a string into a named reference
|
||||
// transforming a familiar name from Docker UI to a fully
|
||||
// qualified reference. If the value may be an identifier
|
||||
// use ParseAnyReference.
|
||||
func ParseNormalizedNamed(s string) (Named, error) {
|
||||
if ok := anchoredIdentifierRegexp.MatchString(s); ok {
|
||||
return nil, fmt.Errorf("invalid repository name (%s), cannot specify 64-byte hexadecimal strings", s)
|
||||
}
|
||||
domain, remainder := splitDockerDomain(s)
|
||||
var remoteName string
|
||||
if tagSep := strings.IndexRune(remainder, ':'); tagSep > -1 {
|
||||
remoteName = remainder[:tagSep]
|
||||
} else {
|
||||
remoteName = remainder
|
||||
}
|
||||
if strings.ToLower(remoteName) != remoteName {
|
||||
return nil, errors.New("invalid reference format: repository name must be lowercase")
|
||||
}
|
||||
|
||||
ref, err := Parse(domain + "/" + remainder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
named, isNamed := ref.(Named)
|
||||
if !isNamed {
|
||||
return nil, fmt.Errorf("reference %s has no name", ref.String())
|
||||
}
|
||||
return named, nil
|
||||
}
|
||||
|
||||
// ParseDockerRef normalizes the image reference following the docker convention. This is added
|
||||
// mainly for backward compatibility.
|
||||
// The reference returned can only be either tagged or digested. For reference contains both tag
|
||||
// and digest, the function returns digested reference, e.g. docker.io/library/busybox:latest@
|
||||
// sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa will be returned as
|
||||
// docker.io/library/busybox@sha256:7cc4b5aefd1d0cadf8d97d4350462ba51c694ebca145b08d7d41b41acc8db5aa.
|
||||
func ParseDockerRef(ref string) (Named, error) {
|
||||
named, err := ParseNormalizedNamed(ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, ok := named.(NamedTagged); ok {
|
||||
if canonical, ok := named.(Canonical); ok {
|
||||
// The reference is both tagged and digested, only
|
||||
// return digested.
|
||||
newNamed, err := WithName(canonical.Name())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newCanonical, err := WithDigest(newNamed, canonical.Digest())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newCanonical, nil
|
||||
}
|
||||
}
|
||||
return TagNameOnly(named), nil
|
||||
}
|
||||
|
||||
// splitDockerDomain splits a repository name to domain and remotename string.
|
||||
// If no valid domain is found, the default domain is used. Repository name
|
||||
// needs to be already validated before.
|
||||
func splitDockerDomain(name string) (domain, remainder string) {
|
||||
i := strings.IndexRune(name, '/')
|
||||
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
|
||||
domain, remainder = defaultDomain, name
|
||||
} else {
|
||||
domain, remainder = name[:i], name[i+1:]
|
||||
}
|
||||
if domain == legacyDefaultDomain {
|
||||
domain = defaultDomain
|
||||
}
|
||||
if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
|
||||
remainder = officialRepoName + "/" + remainder
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// familiarizeName returns a shortened version of the name familiar
|
||||
// to to the Docker UI. Familiar names have the default domain
|
||||
// "docker.io" and "library/" repository prefix removed.
|
||||
// For example, "docker.io/library/redis" will have the familiar
|
||||
// name "redis" and "docker.io/dmcgowan/myapp" will be "dmcgowan/myapp".
|
||||
// Returns a familiarized named only reference.
|
||||
func familiarizeName(named namedRepository) repository {
|
||||
repo := repository{
|
||||
domain: named.Domain(),
|
||||
path: named.Path(),
|
||||
}
|
||||
|
||||
if repo.domain == defaultDomain {
|
||||
repo.domain = ""
|
||||
// Handle official repositories which have the pattern "library/<official repo name>"
|
||||
if split := strings.Split(repo.path, "/"); len(split) == 2 && split[0] == officialRepoName {
|
||||
repo.path = split[1]
|
||||
}
|
||||
}
|
||||
return repo
|
||||
}
|
||||
|
||||
func (r reference) Familiar() Named {
|
||||
return reference{
|
||||
namedRepository: familiarizeName(r.namedRepository),
|
||||
tag: r.tag,
|
||||
digest: r.digest,
|
||||
}
|
||||
}
|
||||
|
||||
func (r repository) Familiar() Named {
|
||||
return familiarizeName(r)
|
||||
}
|
||||
|
||||
func (t taggedReference) Familiar() Named {
|
||||
return taggedReference{
|
||||
namedRepository: familiarizeName(t.namedRepository),
|
||||
tag: t.tag,
|
||||
}
|
||||
}
|
||||
|
||||
func (c canonicalReference) Familiar() Named {
|
||||
return canonicalReference{
|
||||
namedRepository: familiarizeName(c.namedRepository),
|
||||
digest: c.digest,
|
||||
}
|
||||
}
|
||||
|
||||
// TagNameOnly adds the default tag "latest" to a reference if it only has
|
||||
// a repo name.
|
||||
func TagNameOnly(ref Named) Named {
|
||||
if IsNameOnly(ref) {
|
||||
namedTagged, err := WithTag(ref, defaultTag)
|
||||
if err != nil {
|
||||
// Default tag must be valid, to create a NamedTagged
|
||||
// type with non-validated input the WithTag function
|
||||
// should be used instead
|
||||
panic(err)
|
||||
}
|
||||
return namedTagged
|
||||
}
|
||||
return ref
|
||||
}
|
||||
|
||||
// ParseAnyReference parses a reference string as a possible identifier,
|
||||
// full digest, or familiar name.
|
||||
func ParseAnyReference(ref string) (Reference, error) {
|
||||
if ok := anchoredIdentifierRegexp.MatchString(ref); ok {
|
||||
return digestReference("sha256:" + ref), nil
|
||||
}
|
||||
if dgst, err := digest.Parse(ref); err == nil {
|
||||
return digestReference(dgst), nil
|
||||
}
|
||||
|
||||
return ParseNormalizedNamed(ref)
|
||||
}
|
||||
|
||||
// IsNameOnly returns true if reference only contains a repo name.
|
||||
func IsNameOnly(ref Named) bool {
|
||||
if _, ok := ref.(NamedTagged); ok {
|
||||
return false
|
||||
}
|
||||
if _, ok := ref.(Canonical); ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// FamiliarName returns the familiar name string
|
||||
// for the given named, familiarizing if needed.
|
||||
func FamiliarName(ref Named) string {
|
||||
if nn, ok := ref.(normalizedNamed); ok {
|
||||
return nn.Familiar().Name()
|
||||
}
|
||||
return ref.Name()
|
||||
}
|
||||
|
||||
// FamiliarString returns the familiar string representation
|
||||
// for the given reference, familiarizing if needed.
|
||||
func FamiliarString(ref Reference) string {
|
||||
if nn, ok := ref.(normalizedNamed); ok {
|
||||
return nn.Familiar().String()
|
||||
}
|
||||
return ref.String()
|
||||
}
|
||||
|
||||
// FamiliarMatch reports whether ref matches the specified pattern.
|
||||
// See https://godoc.org/path#Match for supported patterns.
|
||||
func FamiliarMatch(pattern string, ref Reference) (bool, error) {
|
||||
matched, err := path.Match(pattern, FamiliarString(ref))
|
||||
if namedRef, isNamed := ref.(Named); isNamed && !matched {
|
||||
matched, _ = path.Match(pattern, FamiliarName(namedRef))
|
||||
}
|
||||
return matched, err
|
||||
}
|
@ -1,4 +1,20 @@
|
||||
package errcode
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
"encoding/json"
|
@ -1,4 +1,20 @@
|
||||
package errcode
|
||||
/*
|
||||
Copyright The containerd Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
5
vendor/github.com/containerd/containerd/remotes/docker/fetcher.go
generated
vendored
5
vendor/github.com/containerd/containerd/remotes/docker/fetcher.go
generated
vendored
@ -29,7 +29,6 @@ import (
|
||||
"github.com/containerd/containerd/errdefs"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/docker/distribution/registry/api/errcode"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@ -136,7 +135,7 @@ func (r dockerFetcher) Fetch(ctx context.Context, desc ocispec.Descriptor) (io.R
|
||||
}
|
||||
|
||||
func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string, offset int64) (io.ReadCloser, error) {
|
||||
req.header.Set("Accept", strings.Join([]string{mediatype, `*`}, ", "))
|
||||
req.header.Set("Accept", strings.Join([]string{mediatype, `*/*`}, ", "))
|
||||
|
||||
if offset > 0 {
|
||||
// Note: "Accept-Ranges: bytes" cannot be trusted as some endpoints
|
||||
@ -160,7 +159,7 @@ func (r dockerFetcher) open(ctx context.Context, req *request, mediatype string,
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return nil, errors.Wrapf(errdefs.ErrNotFound, "content at %v not found", req.String())
|
||||
}
|
||||
var registryErr errcode.Errors
|
||||
var registryErr Errors
|
||||
if err := json.NewDecoder(resp.Body).Decode(®istryErr); err != nil || registryErr.Len() < 1 {
|
||||
return nil, errors.Errorf("unexpected status code %v: %v", req.String(), resp.Status)
|
||||
}
|
||||
|
2
vendor/github.com/containerd/containerd/remotes/docker/pusher.go
generated
vendored
2
vendor/github.com/containerd/containerd/remotes/docker/pusher.go
generated
vendored
@ -80,7 +80,7 @@ func (p dockerPusher) Push(ctx context.Context, desc ocispec.Descriptor) (conten
|
||||
}
|
||||
|
||||
req := p.request(host, http.MethodHead, existCheck...)
|
||||
req.header.Set("Accept", strings.Join([]string{desc.MediaType, `*`}, ", "))
|
||||
req.header.Set("Accept", strings.Join([]string{desc.MediaType, `*/*`}, ", "))
|
||||
|
||||
log.G(ctx).WithField("url", req.String()).Debugf("checking and pushing to")
|
||||
|
||||
|
2
vendor/github.com/containerd/containerd/remotes/docker/resolver.go
generated
vendored
2
vendor/github.com/containerd/containerd/remotes/docker/resolver.go
generated
vendored
@ -155,7 +155,7 @@ func NewResolver(options ResolverOptions) remotes.Resolver {
|
||||
images.MediaTypeDockerSchema2Manifest,
|
||||
images.MediaTypeDockerSchema2ManifestList,
|
||||
ocispec.MediaTypeImageManifest,
|
||||
ocispec.MediaTypeImageIndex, "*"}, ", "))
|
||||
ocispec.MediaTypeImageIndex, "*/*"}, ", "))
|
||||
} else {
|
||||
resolveHeader["Accept"] = options.Headers["Accept"]
|
||||
delete(options.Headers, "Accept")
|
||||
|
31
vendor/github.com/containerd/containerd/runtime/v1/linux/runtime.go
generated
vendored
31
vendor/github.com/containerd/containerd/runtime/v1/linux/runtime.go
generated
vendored
@ -50,7 +50,6 @@ import (
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
@ -112,13 +111,13 @@ func New(ic *plugin.InitContext) (interface{}, error) {
|
||||
}
|
||||
cfg := ic.Config.(*Config)
|
||||
r := &Runtime{
|
||||
root: ic.Root,
|
||||
state: ic.State,
|
||||
tasks: runtime.NewTaskList(),
|
||||
db: m.(*metadata.DB),
|
||||
address: ic.Address,
|
||||
events: ic.Events,
|
||||
config: cfg,
|
||||
root: ic.Root,
|
||||
state: ic.State,
|
||||
tasks: runtime.NewTaskList(),
|
||||
containers: metadata.NewContainerStore(m.(*metadata.DB)),
|
||||
address: ic.Address,
|
||||
events: ic.Events,
|
||||
config: cfg,
|
||||
}
|
||||
tasks, err := r.restoreTasks(ic.Context)
|
||||
if err != nil {
|
||||
@ -138,9 +137,9 @@ type Runtime struct {
|
||||
state string
|
||||
address string
|
||||
|
||||
tasks *runtime.TaskList
|
||||
db *metadata.DB
|
||||
events *exchange.Exchange
|
||||
tasks *runtime.TaskList
|
||||
containers containers.Store
|
||||
events *exchange.Exchange
|
||||
|
||||
config *Config
|
||||
}
|
||||
@ -508,14 +507,8 @@ func (r *Runtime) getRuntime(ctx context.Context, ns, id string) (*runc.Runc, er
|
||||
}
|
||||
|
||||
func (r *Runtime) getRuncOptions(ctx context.Context, id string) (*runctypes.RuncOptions, error) {
|
||||
var container containers.Container
|
||||
|
||||
if err := r.db.View(func(tx *bolt.Tx) error {
|
||||
store := metadata.NewContainerStore(tx)
|
||||
var err error
|
||||
container, err = store.Get(ctx, id)
|
||||
return err
|
||||
}); err != nil {
|
||||
container, err := r.containers.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
12
vendor/github.com/containerd/containerd/runtime/v1/linux/task.go
generated
vendored
12
vendor/github.com/containerd/containerd/runtime/v1/linux/task.go
generated
vendored
@ -91,9 +91,12 @@ func (t *Task) PID() uint32 {
|
||||
|
||||
// Delete the task and return the exit status
|
||||
func (t *Task) Delete(ctx context.Context) (*runtime.Exit, error) {
|
||||
rsp, err := t.shim.Delete(ctx, empty)
|
||||
if err != nil && !errdefs.IsNotFound(err) {
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
rsp, shimErr := t.shim.Delete(ctx, empty)
|
||||
if shimErr != nil {
|
||||
shimErr = errdefs.FromGRPC(shimErr)
|
||||
if !errdefs.IsNotFound(shimErr) {
|
||||
return nil, shimErr
|
||||
}
|
||||
}
|
||||
t.tasks.Delete(ctx, t.id)
|
||||
if err := t.shim.KillShim(ctx); err != nil {
|
||||
@ -102,6 +105,9 @@ func (t *Task) Delete(ctx context.Context) (*runtime.Exit, error) {
|
||||
if err := t.bundle.Delete(); err != nil {
|
||||
log.G(ctx).WithError(err).Error("failed to delete bundle")
|
||||
}
|
||||
if shimErr != nil {
|
||||
return nil, shimErr
|
||||
}
|
||||
t.events.Publish(ctx, runtime.TaskDeleteEventTopic, &eventstypes.TaskDelete{
|
||||
ContainerID: t.id,
|
||||
ExitStatus: rsp.ExitStatus,
|
||||
|
4
vendor/github.com/containerd/containerd/runtime/v1/shim/service.go
generated
vendored
4
vendor/github.com/containerd/containerd/runtime/v1/shim/service.go
generated
vendored
@ -217,7 +217,7 @@ func (s *Service) Delete(ctx context.Context, r *ptypes.Empty) (*shimapi.DeleteR
|
||||
return nil, err
|
||||
}
|
||||
if err := p.Delete(ctx); err != nil {
|
||||
return nil, err
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
s.mu.Lock()
|
||||
delete(s.processes, s.id)
|
||||
@ -240,7 +240,7 @@ func (s *Service) DeleteProcess(ctx context.Context, r *shimapi.DeleteProcessReq
|
||||
return nil, err
|
||||
}
|
||||
if err := p.Delete(ctx); err != nil {
|
||||
return nil, err
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
s.mu.Lock()
|
||||
delete(s.processes, r.ID)
|
||||
|
24
vendor/github.com/containerd/containerd/runtime/v2/manager.go
generated
vendored
24
vendor/github.com/containerd/containerd/runtime/v2/manager.go
generated
vendored
@ -33,7 +33,6 @@ import (
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/runtime"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
// Config for the v2 runtime
|
||||
@ -69,13 +68,15 @@ func init() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return New(ic.Context, ic.Root, ic.State, ic.Address, ic.TTRPCAddress, ic.Events, m.(*metadata.DB))
|
||||
cs := metadata.NewContainerStore(m.(*metadata.DB))
|
||||
|
||||
return New(ic.Context, ic.Root, ic.State, ic.Address, ic.TTRPCAddress, ic.Events, cs)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// New task manager for v2 shims
|
||||
func New(ctx context.Context, root, state, containerdAddress, containerdTTRPCAddress string, events *exchange.Exchange, db *metadata.DB) (*TaskManager, error) {
|
||||
func New(ctx context.Context, root, state, containerdAddress, containerdTTRPCAddress string, events *exchange.Exchange, cs containers.Store) (*TaskManager, error) {
|
||||
for _, d := range []string{root, state} {
|
||||
if err := os.MkdirAll(d, 0711); err != nil {
|
||||
return nil, err
|
||||
@ -88,7 +89,7 @@ func New(ctx context.Context, root, state, containerdAddress, containerdTTRPCAdd
|
||||
containerdTTRPCAddress: containerdTTRPCAddress,
|
||||
tasks: runtime.NewTaskList(),
|
||||
events: events,
|
||||
db: db,
|
||||
containers: cs,
|
||||
}
|
||||
if err := m.loadExistingTasks(ctx); err != nil {
|
||||
return nil, err
|
||||
@ -103,9 +104,9 @@ type TaskManager struct {
|
||||
containerdAddress string
|
||||
containerdTTRPCAddress string
|
||||
|
||||
tasks *runtime.TaskList
|
||||
events *exchange.Exchange
|
||||
db *metadata.DB
|
||||
tasks *runtime.TaskList
|
||||
events *exchange.Exchange
|
||||
containers containers.Store
|
||||
}
|
||||
|
||||
// ID of the task manager
|
||||
@ -278,13 +279,8 @@ func (m *TaskManager) loadTasks(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (m *TaskManager) container(ctx context.Context, id string) (*containers.Container, error) {
|
||||
var container containers.Container
|
||||
if err := m.db.View(func(tx *bolt.Tx) error {
|
||||
store := metadata.NewContainerStore(tx)
|
||||
var err error
|
||||
container, err = store.Get(ctx, id)
|
||||
return err
|
||||
}); err != nil {
|
||||
container, err := m.containers.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &container, nil
|
||||
|
12
vendor/github.com/containerd/containerd/runtime/v2/shim.go
generated
vendored
12
vendor/github.com/containerd/containerd/runtime/v2/shim.go
generated
vendored
@ -222,11 +222,14 @@ func (s *shim) Close() error {
|
||||
}
|
||||
|
||||
func (s *shim) Delete(ctx context.Context) (*runtime.Exit, error) {
|
||||
response, err := s.task.Delete(ctx, &task.DeleteRequest{
|
||||
response, shimErr := s.task.Delete(ctx, &task.DeleteRequest{
|
||||
ID: s.ID(),
|
||||
})
|
||||
if err != nil && !errdefs.IsNotFound(err) {
|
||||
return nil, errdefs.FromGRPC(err)
|
||||
if shimErr != nil {
|
||||
shimErr = errdefs.FromGRPC(shimErr)
|
||||
if !errdefs.IsNotFound(shimErr) {
|
||||
return nil, shimErr
|
||||
}
|
||||
}
|
||||
// remove self from the runtime task list
|
||||
// this seems dirty but it cleans up the API across runtimes, tasks, and the service
|
||||
@ -238,6 +241,9 @@ func (s *shim) Delete(ctx context.Context) (*runtime.Exit, error) {
|
||||
if err := s.bundle.Delete(); err != nil {
|
||||
log.G(ctx).WithError(err).Error("failed to delete bundle")
|
||||
}
|
||||
if shimErr != nil {
|
||||
return nil, shimErr
|
||||
}
|
||||
return &runtime.Exit{
|
||||
Status: response.ExitStatus,
|
||||
Timestamp: response.ExitedAt,
|
||||
|
40
vendor/github.com/containerd/containerd/services/containers/local.go
generated
vendored
40
vendor/github.com/containerd/containerd/services/containers/local.go
generated
vendored
@ -48,8 +48,11 @@ func init() {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
db := m.(*metadata.DB)
|
||||
return &local{
|
||||
db: m.(*metadata.DB),
|
||||
Store: metadata.NewContainerStore(db),
|
||||
db: db,
|
||||
publisher: ic.Events,
|
||||
}, nil
|
||||
},
|
||||
@ -57,6 +60,7 @@ func init() {
|
||||
}
|
||||
|
||||
type local struct {
|
||||
containers.Store
|
||||
db *metadata.DB
|
||||
publisher events.Publisher
|
||||
}
|
||||
@ -66,8 +70,8 @@ var _ api.ContainersClient = &local{}
|
||||
func (l *local) Get(ctx context.Context, req *api.GetContainerRequest, _ ...grpc.CallOption) (*api.GetContainerResponse, error) {
|
||||
var resp api.GetContainerResponse
|
||||
|
||||
return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
container, err := store.Get(ctx, req.ID)
|
||||
return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context) error {
|
||||
container, err := l.Store.Get(ctx, req.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -80,8 +84,8 @@ func (l *local) Get(ctx context.Context, req *api.GetContainerRequest, _ ...grpc
|
||||
|
||||
func (l *local) List(ctx context.Context, req *api.ListContainersRequest, _ ...grpc.CallOption) (*api.ListContainersResponse, error) {
|
||||
var resp api.ListContainersResponse
|
||||
return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
containers, err := store.List(ctx, req.Filters...)
|
||||
return &resp, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context) error {
|
||||
containers, err := l.Store.List(ctx, req.Filters...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -94,8 +98,8 @@ func (l *local) ListStream(ctx context.Context, req *api.ListContainersRequest,
|
||||
stream := &localStream{
|
||||
ctx: ctx,
|
||||
}
|
||||
return stream, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
containers, err := store.List(ctx, req.Filters...)
|
||||
return stream, errdefs.ToGRPC(l.withStoreView(ctx, func(ctx context.Context) error {
|
||||
containers, err := l.Store.List(ctx, req.Filters...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -107,10 +111,10 @@ func (l *local) ListStream(ctx context.Context, req *api.ListContainersRequest,
|
||||
func (l *local) Create(ctx context.Context, req *api.CreateContainerRequest, _ ...grpc.CallOption) (*api.CreateContainerResponse, error) {
|
||||
var resp api.CreateContainerResponse
|
||||
|
||||
if err := l.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
if err := l.withStoreUpdate(ctx, func(ctx context.Context) error {
|
||||
container := containerFromProto(&req.Container)
|
||||
|
||||
created, err := store.Create(ctx, container)
|
||||
created, err := l.Store.Create(ctx, container)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -144,13 +148,13 @@ func (l *local) Update(ctx context.Context, req *api.UpdateContainerRequest, _ .
|
||||
container = containerFromProto(&req.Container)
|
||||
)
|
||||
|
||||
if err := l.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
if err := l.withStoreUpdate(ctx, func(ctx context.Context) error {
|
||||
var fieldpaths []string
|
||||
if req.UpdateMask != nil && len(req.UpdateMask.Paths) > 0 {
|
||||
fieldpaths = append(fieldpaths, req.UpdateMask.Paths...)
|
||||
}
|
||||
|
||||
updated, err := store.Update(ctx, container, fieldpaths...)
|
||||
updated, err := l.Store.Update(ctx, container, fieldpaths...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -174,8 +178,8 @@ func (l *local) Update(ctx context.Context, req *api.UpdateContainerRequest, _ .
|
||||
}
|
||||
|
||||
func (l *local) Delete(ctx context.Context, req *api.DeleteContainerRequest, _ ...grpc.CallOption) (*ptypes.Empty, error) {
|
||||
if err := l.withStoreUpdate(ctx, func(ctx context.Context, store containers.Store) error {
|
||||
return store.Delete(ctx, req.ID)
|
||||
if err := l.withStoreUpdate(ctx, func(ctx context.Context) error {
|
||||
return l.Store.Delete(ctx, req.ID)
|
||||
}); err != nil {
|
||||
return &ptypes.Empty{}, errdefs.ToGRPC(err)
|
||||
}
|
||||
@ -189,15 +193,17 @@ func (l *local) Delete(ctx context.Context, req *api.DeleteContainerRequest, _ .
|
||||
return &ptypes.Empty{}, nil
|
||||
}
|
||||
|
||||
func (l *local) withStore(ctx context.Context, fn func(ctx context.Context, store containers.Store) error) func(tx *bolt.Tx) error {
|
||||
return func(tx *bolt.Tx) error { return fn(ctx, metadata.NewContainerStore(tx)) }
|
||||
func (l *local) withStore(ctx context.Context, fn func(ctx context.Context) error) func(tx *bolt.Tx) error {
|
||||
return func(tx *bolt.Tx) error {
|
||||
return fn(metadata.WithTransactionContext(ctx, tx))
|
||||
}
|
||||
}
|
||||
|
||||
func (l *local) withStoreView(ctx context.Context, fn func(ctx context.Context, store containers.Store) error) error {
|
||||
func (l *local) withStoreView(ctx context.Context, fn func(ctx context.Context) error) error {
|
||||
return l.db.View(l.withStore(ctx, fn))
|
||||
}
|
||||
|
||||
func (l *local) withStoreUpdate(ctx context.Context, fn func(ctx context.Context, store containers.Store) error) error {
|
||||
func (l *local) withStoreUpdate(ctx context.Context, fn func(ctx context.Context) error) error {
|
||||
return l.db.Update(l.withStore(ctx, fn))
|
||||
}
|
||||
|
||||
|
59
vendor/github.com/containerd/containerd/services/leases/local.go
generated
vendored
59
vendor/github.com/containerd/containerd/services/leases/local.go
generated
vendored
@ -24,7 +24,6 @@ import (
|
||||
"github.com/containerd/containerd/metadata"
|
||||
"github.com/containerd/containerd/plugin"
|
||||
"github.com/containerd/containerd/services"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -44,8 +43,8 @@ func init() {
|
||||
return nil, err
|
||||
}
|
||||
return &local{
|
||||
db: m.(*metadata.DB),
|
||||
gc: g.(gcScheduler),
|
||||
Manager: metadata.NewLeaseManager(m.(*metadata.DB)),
|
||||
gc: g.(gcScheduler),
|
||||
}, nil
|
||||
},
|
||||
})
|
||||
@ -56,22 +55,10 @@ type gcScheduler interface {
|
||||
}
|
||||
|
||||
type local struct {
|
||||
db *metadata.DB
|
||||
leases.Manager
|
||||
gc gcScheduler
|
||||
}
|
||||
|
||||
func (l *local) Create(ctx context.Context, opts ...leases.Opt) (leases.Lease, error) {
|
||||
var lease leases.Lease
|
||||
if err := l.db.Update(func(tx *bolt.Tx) error {
|
||||
var err error
|
||||
lease, err = metadata.NewLeaseManager(tx).Create(ctx, opts...)
|
||||
return err
|
||||
}); err != nil {
|
||||
return leases.Lease{}, err
|
||||
}
|
||||
return lease, nil
|
||||
}
|
||||
|
||||
func (l *local) Delete(ctx context.Context, lease leases.Lease, opts ...leases.DeleteOpt) error {
|
||||
var do leases.DeleteOptions
|
||||
for _, opt := range opts {
|
||||
@ -80,9 +67,7 @@ func (l *local) Delete(ctx context.Context, lease leases.Lease, opts ...leases.D
|
||||
}
|
||||
}
|
||||
|
||||
if err := l.db.Update(func(tx *bolt.Tx) error {
|
||||
return metadata.NewLeaseManager(tx).Delete(ctx, lease)
|
||||
}); err != nil {
|
||||
if err := l.Manager.Delete(ctx, lease); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -95,39 +80,3 @@ func (l *local) Delete(ctx context.Context, lease leases.Lease, opts ...leases.D
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (l *local) List(ctx context.Context, filters ...string) ([]leases.Lease, error) {
|
||||
var ll []leases.Lease
|
||||
if err := l.db.View(func(tx *bolt.Tx) error {
|
||||
var err error
|
||||
ll, err = metadata.NewLeaseManager(tx).List(ctx, filters...)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ll, nil
|
||||
}
|
||||
|
||||
func (l *local) AddResource(ctx context.Context, lease leases.Lease, r leases.Resource) error {
|
||||
return l.db.Update(func(tx *bolt.Tx) error {
|
||||
return metadata.NewLeaseManager(tx).AddResource(ctx, lease, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (l *local) DeleteResource(ctx context.Context, lease leases.Lease, r leases.Resource) error {
|
||||
return l.db.Update(func(tx *bolt.Tx) error {
|
||||
return metadata.NewLeaseManager(tx).DeleteResource(ctx, lease, r)
|
||||
})
|
||||
}
|
||||
|
||||
func (l *local) ListResources(ctx context.Context, lease leases.Lease) ([]leases.Resource, error) {
|
||||
var rs []leases.Resource
|
||||
if err := l.db.View(func(tx *bolt.Tx) error {
|
||||
var err error
|
||||
rs, err = metadata.NewLeaseManager(tx).ListResources(ctx, lease)
|
||||
return err
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rs, nil
|
||||
}
|
||||
|
35
vendor/github.com/containerd/containerd/services/tasks/local.go
generated
vendored
35
vendor/github.com/containerd/containerd/services/tasks/local.go
generated
vendored
@ -51,7 +51,6 @@ import (
|
||||
ptypes "github.com/gogo/protobuf/types"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
"github.com/pkg/errors"
|
||||
bolt "go.etcd.io/bbolt"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
@ -101,14 +100,14 @@ func initFunc(ic *plugin.InitContext) (interface{}, error) {
|
||||
monitor = runtime.NewNoopMonitor()
|
||||
}
|
||||
|
||||
cs := m.(*metadata.DB).ContentStore()
|
||||
db := m.(*metadata.DB)
|
||||
l := &local{
|
||||
runtimes: runtimes,
|
||||
db: m.(*metadata.DB),
|
||||
store: cs,
|
||||
publisher: ic.Events,
|
||||
monitor: monitor.(runtime.TaskMonitor),
|
||||
v2Runtime: v2r.(*v2.TaskManager),
|
||||
runtimes: runtimes,
|
||||
containers: metadata.NewContainerStore(db),
|
||||
store: db.ContentStore(),
|
||||
publisher: ic.Events,
|
||||
monitor: monitor.(runtime.TaskMonitor),
|
||||
v2Runtime: v2r.(*v2.TaskManager),
|
||||
}
|
||||
for _, r := range runtimes {
|
||||
tasks, err := r.Tasks(ic.Context, true)
|
||||
@ -123,10 +122,10 @@ func initFunc(ic *plugin.InitContext) (interface{}, error) {
|
||||
}
|
||||
|
||||
type local struct {
|
||||
runtimes map[string]runtime.PlatformRuntime
|
||||
db *metadata.DB
|
||||
store content.Store
|
||||
publisher events.Publisher
|
||||
runtimes map[string]runtime.PlatformRuntime
|
||||
containers containers.Store
|
||||
store content.Store
|
||||
publisher events.Publisher
|
||||
|
||||
monitor runtime.TaskMonitor
|
||||
v2Runtime *v2.TaskManager
|
||||
@ -242,7 +241,7 @@ func (l *local) Delete(ctx context.Context, r *api.DeleteTaskRequest, _ ...grpc.
|
||||
}
|
||||
exit, err := t.Delete(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
return &api.DeleteResponse{
|
||||
ExitStatus: exit.Status,
|
||||
@ -258,7 +257,7 @@ func (l *local) DeleteProcess(ctx context.Context, r *api.DeleteProcessRequest,
|
||||
}
|
||||
process, err := t.Process(ctx, r.ExecID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
exit, err := process.Delete(ctx)
|
||||
if err != nil {
|
||||
@ -647,12 +646,8 @@ func (l *local) writeContent(ctx context.Context, mediaType, ref string, r io.Re
|
||||
|
||||
func (l *local) getContainer(ctx context.Context, id string) (*containers.Container, error) {
|
||||
var container containers.Container
|
||||
if err := l.db.View(func(tx *bolt.Tx) error {
|
||||
store := metadata.NewContainerStore(tx)
|
||||
var err error
|
||||
container, err = store.Get(ctx, id)
|
||||
return err
|
||||
}); err != nil {
|
||||
container, err := l.containers.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, errdefs.ToGRPC(err)
|
||||
}
|
||||
return &container, nil
|
||||
|
36
vendor/github.com/containerd/containerd/vendor.conf
generated
vendored
36
vendor/github.com/containerd/containerd/vendor.conf
generated
vendored
@ -1,6 +1,6 @@
|
||||
github.com/containerd/go-runc e029b79d8cda8374981c64eba71f28ec38e5526f
|
||||
github.com/containerd/console 0650fd9eeb50bab4fc99dceb9f2e14cf58f36e7f
|
||||
github.com/containerd/cgroups c4b9ac5c7601384c965b9646fc515884e091ebb9
|
||||
github.com/containerd/cgroups abd0b19954a6b05e0963f48427062d1481b7faad
|
||||
github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40
|
||||
github.com/containerd/fifo bda0ff6ed73c67bfb5e62bc9c697f146b7fd7f13
|
||||
github.com/containerd/btrfs af5082808c833de0e79c1e72eea9fea239364877
|
||||
@ -20,7 +20,7 @@ github.com/gogo/protobuf v1.2.1
|
||||
github.com/gogo/googleapis v1.2.0
|
||||
github.com/golang/protobuf v1.2.0
|
||||
github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db
|
||||
github.com/opencontainers/runc f4982d86f7fde0b6f953cc62ccc4022c519a10a9 # v1.0.0-rc8-32-gf4982d86
|
||||
github.com/opencontainers/runc d736ef14f0288d6993a1845745d6756cfc9ddd5a # v1.0.0-rc9
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1
|
||||
github.com/sirupsen/logrus v1.4.1
|
||||
github.com/urfave/cli v1.22.0
|
||||
@ -51,34 +51,34 @@ github.com/cpuguy83/go-md2man v1.0.10
|
||||
github.com/russross/blackfriday v1.5.2
|
||||
|
||||
# cri dependencies
|
||||
github.com/containerd/cri f4d75d321c89b8d89bae570a7d2da1b3846c096f # release/1.3
|
||||
github.com/containerd/go-cni 49fbd9b210f3c8ee3b7fd3cd797aabaf364627c1
|
||||
github.com/containerd/cri 0ebf032aac5f6029f95a94e42161e9db7a7e84df # release/1.3+
|
||||
github.com/containerd/go-cni 0d360c50b10b350b6bb23863fd4dfb1c232b01c9
|
||||
github.com/containernetworking/cni v0.7.1
|
||||
github.com/containernetworking/plugins v0.7.6
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
|
||||
github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
|
||||
github.com/docker/spdystream 449fdfce4d962303d702fec724ef0ad181c92528
|
||||
github.com/emicklei/go-restful v2.2.1
|
||||
github.com/google/gofuzz 24818f796faf91cd76ec7bddd72458fbced7a6c1
|
||||
github.com/json-iterator/go 1.1.5
|
||||
github.com/emicklei/go-restful v2.9.5
|
||||
github.com/google/gofuzz v1.0.0
|
||||
github.com/json-iterator/go v1.1.7
|
||||
github.com/modern-go/reflect2 1.0.1
|
||||
github.com/modern-go/concurrent 1.0.3
|
||||
github.com/opencontainers/selinux v1.2.2
|
||||
github.com/seccomp/libseccomp-golang v0.9.1
|
||||
github.com/tchap/go-patricia v2.2.6
|
||||
golang.org/x/crypto 88737f569e3a9c7ab309cdc09a07fe7fc87233c3
|
||||
golang.org/x/oauth2 9f3314589c9a9136388751d9adae6b0ed400978a
|
||||
golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631
|
||||
golang.org/x/crypto 5c40567a22f818bd14a1ea7245dad9f8ef0691aa
|
||||
golang.org/x/oauth2 0f29369cfe4552d0e4bcddc57cc75f4d7e672a33
|
||||
golang.org/x/time 85acf8d2951cb2a3bde7632f9ff273ef0379bcbd
|
||||
gopkg.in/inf.v0 v0.9.0
|
||||
gopkg.in/yaml.v2 v2.2.1
|
||||
k8s.io/api kubernetes-1.15.0
|
||||
k8s.io/apimachinery kubernetes-1.15.0
|
||||
k8s.io/apiserver kubernetes-1.15.0
|
||||
k8s.io/cri-api kubernetes-1.15.0
|
||||
k8s.io/client-go kubernetes-1.15.0
|
||||
k8s.io/klog v0.3.1
|
||||
k8s.io/kubernetes v1.15.0
|
||||
gopkg.in/yaml.v2 v2.2.2
|
||||
k8s.io/api kubernetes-1.16.0-rc.2
|
||||
k8s.io/apimachinery kubernetes-1.16.0-rc.2
|
||||
k8s.io/apiserver kubernetes-1.16.0-rc.2
|
||||
k8s.io/cri-api kubernetes-1.16.0-rc.2
|
||||
k8s.io/client-go kubernetes-1.16.0-rc.2
|
||||
k8s.io/klog v0.4.0
|
||||
k8s.io/kubernetes v1.16.0-rc.2
|
||||
k8s.io/utils c2654d5206da6b7b6ace12841e8f359bb89b443c
|
||||
sigs.k8s.io/yaml v1.1.0
|
||||
|
||||
|
7
vendor/github.com/containerd/containerd/version/version.go
generated
vendored
7
vendor/github.com/containerd/containerd/version/version.go
generated
vendored
@ -16,14 +16,19 @@
|
||||
|
||||
package version
|
||||
|
||||
import "runtime"
|
||||
|
||||
var (
|
||||
// Package is filled at linking time
|
||||
Package = "github.com/containerd/containerd"
|
||||
|
||||
// Version holds the complete version number. Filled in at linking time.
|
||||
Version = "1.2.0+unknown"
|
||||
Version = "1.3.0+unknown"
|
||||
|
||||
// Revision is filled with the VCS (e.g. git) revision being used to build
|
||||
// the program at linking time.
|
||||
Revision = ""
|
||||
|
||||
// GoVersion is Go tree's version.
|
||||
GoVersion = runtime.Version()
|
||||
)
|
||||
|
40
vendor/github.com/docker/distribution/registry/api/errcode/handler.go
generated
vendored
40
vendor/github.com/docker/distribution/registry/api/errcode/handler.go
generated
vendored
@ -1,40 +0,0 @@
|
||||
package errcode
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ServeJSON attempts to serve the errcode in a JSON envelope. It marshals err
|
||||
// and sets the content-type header to 'application/json'. It will handle
|
||||
// ErrorCoder and Errors, and if necessary will create an envelope.
|
||||
func ServeJSON(w http.ResponseWriter, err error) error {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
var sc int
|
||||
|
||||
switch errs := err.(type) {
|
||||
case Errors:
|
||||
if len(errs) < 1 {
|
||||
break
|
||||
}
|
||||
|
||||
if err, ok := errs[0].(ErrorCoder); ok {
|
||||
sc = err.ErrorCode().Descriptor().HTTPStatusCode
|
||||
}
|
||||
case ErrorCoder:
|
||||
sc = errs.ErrorCode().Descriptor().HTTPStatusCode
|
||||
err = Errors{err} // create an envelope.
|
||||
default:
|
||||
// We just have an unhandled error type, so just place in an envelope
|
||||
// and move along.
|
||||
err = Errors{err}
|
||||
}
|
||||
|
||||
if sc == 0 {
|
||||
sc = http.StatusInternalServerError
|
||||
}
|
||||
|
||||
w.WriteHeader(sc)
|
||||
|
||||
return json.NewEncoder(w).Encode(err)
|
||||
}
|
1
vendor/github.com/opencontainers/runc/libcontainer/README.md
generated
vendored
1
vendor/github.com/opencontainers/runc/libcontainer/README.md
generated
vendored
@ -261,6 +261,7 @@ process := &libcontainer.Process{
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
Init: true,
|
||||
}
|
||||
|
||||
err := container.Run(process)
|
||||
|
10
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go
generated
vendored
10
vendor/github.com/opencontainers/runc/libcontainer/apparmor/apparmor.go
generated
vendored
@ -6,6 +6,8 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/utils"
|
||||
)
|
||||
|
||||
// IsEnabled returns true if apparmor is enabled for the host.
|
||||
@ -19,7 +21,7 @@ func IsEnabled() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func setprocattr(attr, value string) error {
|
||||
func setProcAttr(attr, value string) error {
|
||||
// Under AppArmor you can only change your own attr, so use /proc/self/
|
||||
// instead of /proc/<tid>/ like libapparmor does
|
||||
path := fmt.Sprintf("/proc/self/attr/%s", attr)
|
||||
@ -30,6 +32,10 @@ func setprocattr(attr, value string) error {
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
if err := utils.EnsureProcHandle(f); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fmt.Fprintf(f, "%s", value)
|
||||
return err
|
||||
}
|
||||
@ -37,7 +43,7 @@ func setprocattr(attr, value string) error {
|
||||
// changeOnExec reimplements aa_change_onexec from libapparmor in Go
|
||||
func changeOnExec(name string) error {
|
||||
value := "exec " + name
|
||||
if err := setprocattr("exec", value); err != nil {
|
||||
if err := setProcAttr("exec", value); err != nil {
|
||||
return fmt.Errorf("apparmor failed to apply profile: %s", err)
|
||||
}
|
||||
return nil
|
||||
|
5
vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go
generated
vendored
5
vendor/github.com/opencontainers/runc/libcontainer/configs/blkio_device.go
generated
vendored
@ -59,3 +59,8 @@ func NewThrottleDevice(major, minor int64, rate uint64) *ThrottleDevice {
|
||||
func (td *ThrottleDevice) String() string {
|
||||
return fmt.Sprintf("%d:%d %d", td.Major, td.Minor, td.Rate)
|
||||
}
|
||||
|
||||
// StringName formats the struct to be writable to the cgroup specific file
|
||||
func (td *ThrottleDevice) StringName(name string) string {
|
||||
return fmt.Sprintf("%d:%d %s=%d", td.Major, td.Minor, name, td.Rate)
|
||||
}
|
||||
|
8
vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go
generated
vendored
8
vendor/github.com/opencontainers/runc/libcontainer/configs/cgroup_linux.go
generated
vendored
@ -119,4 +119,12 @@ type Resources struct {
|
||||
|
||||
// Set class identifier for container's network packets
|
||||
NetClsClassid uint32 `json:"net_cls_classid_u"`
|
||||
|
||||
// Used on cgroups v2:
|
||||
|
||||
// CpuWeight sets a proportional bandwidth limit.
|
||||
CpuWeight uint64 `json:"cpu_weight"`
|
||||
|
||||
// CpuMax sets she maximum bandwidth limit (format: max period).
|
||||
CpuMax string `json:"cpu_max"`
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
// +build !linux
|
||||
|
||||
package configs
|
||||
|
||||
// TODO Windows: This can ultimately be entirely factored out on Windows as
|
1
vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
generated
vendored
1
vendor/github.com/opencontainers/runc/libcontainer/configs/config.go
generated
vendored
@ -44,6 +44,7 @@ const (
|
||||
Trap
|
||||
Allow
|
||||
Trace
|
||||
Log
|
||||
)
|
||||
|
||||
// Operator is a comparison operator to be used when matching syscall arguments in Seccomp
|
||||
|
19
vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go
generated
vendored
19
vendor/github.com/opencontainers/runc/libcontainer/devices/devices.go
generated
vendored
@ -7,11 +7,11 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotADevice denotes that a file is not a valid linux device.
|
||||
ErrNotADevice = errors.New("not a device node")
|
||||
)
|
||||
|
||||
@ -21,7 +21,8 @@ var (
|
||||
ioutilReadDir = ioutil.ReadDir
|
||||
)
|
||||
|
||||
// Given the path to a device and its cgroup_permissions(which cannot be easily queried) look up the information about a linux device and return that information as a Device struct.
|
||||
// Given the path to a device and its cgroup_permissions(which cannot be easily queried) look up the
|
||||
// information about a linux device and return that information as a Device struct.
|
||||
func DeviceFromPath(path, permissions string) (*configs.Device, error) {
|
||||
var stat unix.Stat_t
|
||||
err := unixLstat(path, &stat)
|
||||
@ -60,25 +61,29 @@ func DeviceFromPath(path, permissions string) (*configs.Device, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// HostDevices returns all devices that can be found under /dev directory.
|
||||
func HostDevices() ([]*configs.Device, error) {
|
||||
return getDevices("/dev")
|
||||
return GetDevices("/dev")
|
||||
}
|
||||
|
||||
func getDevices(path string) ([]*configs.Device, error) {
|
||||
// GetDevices recursively traverses a directory specified by path
|
||||
// and returns all devices found there.
|
||||
func GetDevices(path string) ([]*configs.Device, error) {
|
||||
files, err := ioutilReadDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := []*configs.Device{}
|
||||
var out []*configs.Device
|
||||
for _, f := range files {
|
||||
switch {
|
||||
case f.IsDir():
|
||||
switch f.Name() {
|
||||
// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
|
||||
case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts":
|
||||
// ".udev" added to address https://github.com/opencontainers/runc/issues/2093
|
||||
case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts", ".udev":
|
||||
continue
|
||||
default:
|
||||
sub, err := getDevices(filepath.Join(path, f.Name()))
|
||||
sub, err := GetDevices(filepath.Join(path, f.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
2
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_unsupported.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsenter_unsupported.go
generated
vendored
@ -1,5 +1,3 @@
|
||||
// +build !linux !cgo
|
||||
|
||||
package nsenter
|
||||
|
||||
import "C"
|
||||
|
11
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
generated
vendored
11
vendor/github.com/opencontainers/runc/libcontainer/nsenter/nsexec.c
generated
vendored
@ -50,9 +50,6 @@ enum sync_t {
|
||||
#define JUMP_CHILD 0xA0
|
||||
#define JUMP_INIT 0xA1
|
||||
|
||||
/* JSON buffer. */
|
||||
#define JSON_MAX 4096
|
||||
|
||||
/* Assume the stack grows down, so arguments should be above it. */
|
||||
struct clone_t {
|
||||
/*
|
||||
@ -148,11 +145,11 @@ static void write_log_with_info(const char *level, const char *function, int lin
|
||||
|
||||
va_start(args, format);
|
||||
if (vsnprintf(message, sizeof(message), format, args) < 0)
|
||||
return;
|
||||
va_end(args);
|
||||
goto done;
|
||||
|
||||
if (dprintf(logfd, "{\"level\":\"%s\", \"msg\": \"%s:%d %s\"}\n", level, function, line, message) < 0)
|
||||
return;
|
||||
dprintf(logfd, "{\"level\":\"%s\", \"msg\": \"%s:%d %s\"}\n", level, function, line, message);
|
||||
done:
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#define write_log(level, fmt, ...) \
|
||||
|
1
vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go
generated
vendored
1
vendor/github.com/opencontainers/runc/libcontainer/seccomp/config.go
generated
vendored
@ -22,6 +22,7 @@ var actions = map[string]configs.Action{
|
||||
"SCMP_ACT_TRAP": configs.Trap,
|
||||
"SCMP_ACT_ALLOW": configs.Allow,
|
||||
"SCMP_ACT_TRACE": configs.Trace,
|
||||
"SCMP_ACT_LOG": configs.Log,
|
||||
}
|
||||
|
||||
var archs = map[string]string{
|
||||
|
3
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go
generated
vendored
3
vendor/github.com/opencontainers/runc/libcontainer/seccomp/seccomp_linux.go
generated
vendored
@ -19,6 +19,7 @@ var (
|
||||
actTrap = libseccomp.ActTrap
|
||||
actKill = libseccomp.ActKill
|
||||
actTrace = libseccomp.ActTrace.SetReturnCode(int16(unix.EPERM))
|
||||
actLog = libseccomp.ActLog
|
||||
actErrno = libseccomp.ActErrno.SetReturnCode(int16(unix.EPERM))
|
||||
)
|
||||
|
||||
@ -112,6 +113,8 @@ func getAction(act configs.Action) (libseccomp.ScmpAction, error) {
|
||||
return actAllow, nil
|
||||
case configs.Trace:
|
||||
return actTrace, nil
|
||||
case configs.Log:
|
||||
return actLog, nil
|
||||
default:
|
||||
return libseccomp.ActInvalid, fmt.Errorf("invalid action, cannot use in rule")
|
||||
}
|
||||
|
2
vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go
generated
vendored
2
vendor/github.com/opencontainers/runc/libcontainer/system/syscall_linux_64.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
// +build linux
|
||||
// +build arm64 amd64 mips mipsle mips64 mips64le ppc ppc64 ppc64le s390x
|
||||
// +build arm64 amd64 mips mipsle mips64 mips64le ppc ppc64 ppc64le riscv64 s390x
|
||||
|
||||
package system
|
||||
|
||||
|
93
vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go
generated
vendored
Normal file
93
vendor/github.com/opencontainers/runc/libcontainer/utils/cmsg.go
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
// +build linux
|
||||
|
||||
package utils
|
||||
|
||||
/*
|
||||
* Copyright 2016, 2017 SUSE LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// MaxSendfdLen is the maximum length of the name of a file descriptor being
|
||||
// sent using SendFd. The name of the file handle returned by RecvFd will never
|
||||
// be larger than this value.
|
||||
const MaxNameLen = 4096
|
||||
|
||||
// oobSpace is the size of the oob slice required to store a single FD. Note
|
||||
// that unix.UnixRights appears to make the assumption that fd is always int32,
|
||||
// so sizeof(fd) = 4.
|
||||
var oobSpace = unix.CmsgSpace(4)
|
||||
|
||||
// RecvFd waits for a file descriptor to be sent over the given AF_UNIX
|
||||
// socket. The file name of the remote file descriptor will be recreated
|
||||
// locally (it is sent as non-auxiliary data in the same payload).
|
||||
func RecvFd(socket *os.File) (*os.File, error) {
|
||||
// For some reason, unix.Recvmsg uses the length rather than the capacity
|
||||
// when passing the msg_controllen and other attributes to recvmsg. So we
|
||||
// have to actually set the length.
|
||||
name := make([]byte, MaxNameLen)
|
||||
oob := make([]byte, oobSpace)
|
||||
|
||||
sockfd := socket.Fd()
|
||||
n, oobn, _, _, err := unix.Recvmsg(int(sockfd), name, oob, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n >= MaxNameLen || oobn != oobSpace {
|
||||
return nil, fmt.Errorf("recvfd: incorrect number of bytes read (n=%d oobn=%d)", n, oobn)
|
||||
}
|
||||
|
||||
// Truncate.
|
||||
name = name[:n]
|
||||
oob = oob[:oobn]
|
||||
|
||||
scms, err := unix.ParseSocketControlMessage(oob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(scms) != 1 {
|
||||
return nil, fmt.Errorf("recvfd: number of SCMs is not 1: %d", len(scms))
|
||||
}
|
||||
scm := scms[0]
|
||||
|
||||
fds, err := unix.ParseUnixRights(&scm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(fds) != 1 {
|
||||
return nil, fmt.Errorf("recvfd: number of fds is not 1: %d", len(fds))
|
||||
}
|
||||
fd := uintptr(fds[0])
|
||||
|
||||
return os.NewFile(fd, string(name)), nil
|
||||
}
|
||||
|
||||
// SendFd sends a file descriptor over the given AF_UNIX socket. In
|
||||
// addition, the file.Name() of the given file will also be sent as
|
||||
// non-auxiliary data in the same payload (allowing to send contextual
|
||||
// information for a file descriptor).
|
||||
func SendFd(socket *os.File, name string, fd uintptr) error {
|
||||
if len(name) >= MaxNameLen {
|
||||
return fmt.Errorf("sendfd: filename too long: %s", name)
|
||||
}
|
||||
oob := unix.UnixRights(int(fd))
|
||||
return unix.Sendmsg(int(socket.Fd()), []byte(name), oob, nil, 0)
|
||||
}
|
112
vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go
generated
vendored
Normal file
112
vendor/github.com/opencontainers/runc/libcontainer/utils/utils.go
generated
vendored
Normal file
@ -0,0 +1,112 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
exitSignalOffset = 128
|
||||
)
|
||||
|
||||
// ResolveRootfs ensures that the current working directory is
|
||||
// not a symlink and returns the absolute path to the rootfs
|
||||
func ResolveRootfs(uncleanRootfs string) (string, error) {
|
||||
rootfs, err := filepath.Abs(uncleanRootfs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.EvalSymlinks(rootfs)
|
||||
}
|
||||
|
||||
// ExitStatus returns the correct exit status for a process based on if it
|
||||
// was signaled or exited cleanly
|
||||
func ExitStatus(status unix.WaitStatus) int {
|
||||
if status.Signaled() {
|
||||
return exitSignalOffset + int(status.Signal())
|
||||
}
|
||||
return status.ExitStatus()
|
||||
}
|
||||
|
||||
// WriteJSON writes the provided struct v to w using standard json marshaling
|
||||
func WriteJSON(w io.Writer, v interface{}) error {
|
||||
data, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
// CleanPath makes a path safe for use with filepath.Join. This is done by not
|
||||
// only cleaning the path, but also (if the path is relative) adding a leading
|
||||
// '/' and cleaning it (then removing the leading '/'). This ensures that a
|
||||
// path resulting from prepending another path will always resolve to lexically
|
||||
// be a subdirectory of the prefixed path. This is all done lexically, so paths
|
||||
// that include symlinks won't be safe as a result of using CleanPath.
|
||||
func CleanPath(path string) string {
|
||||
// Deal with empty strings nicely.
|
||||
if path == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Ensure that all paths are cleaned (especially problematic ones like
|
||||
// "/../../../../../" which can cause lots of issues).
|
||||
path = filepath.Clean(path)
|
||||
|
||||
// If the path isn't absolute, we need to do more processing to fix paths
|
||||
// such as "../../../../<etc>/some/path". We also shouldn't convert absolute
|
||||
// paths to relative ones.
|
||||
if !filepath.IsAbs(path) {
|
||||
path = filepath.Clean(string(os.PathSeparator) + path)
|
||||
// This can't fail, as (by definition) all paths are relative to root.
|
||||
path, _ = filepath.Rel(string(os.PathSeparator), path)
|
||||
}
|
||||
|
||||
// Clean the path again for good measure.
|
||||
return filepath.Clean(path)
|
||||
}
|
||||
|
||||
// SearchLabels searches a list of key-value pairs for the provided key and
|
||||
// returns the corresponding value. The pairs must be separated with '='.
|
||||
func SearchLabels(labels []string, query string) string {
|
||||
for _, l := range labels {
|
||||
parts := strings.SplitN(l, "=", 2)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
if parts[0] == query {
|
||||
return parts[1]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Annotations returns the bundle path and user defined annotations from the
|
||||
// libcontainer state. We need to remove the bundle because that is a label
|
||||
// added by libcontainer.
|
||||
func Annotations(labels []string) (bundle string, userAnnotations map[string]string) {
|
||||
userAnnotations = make(map[string]string)
|
||||
for _, l := range labels {
|
||||
parts := strings.SplitN(l, "=", 2)
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
if parts[0] == "bundle" {
|
||||
bundle = parts[1]
|
||||
} else {
|
||||
userAnnotations[parts[0]] = parts[1]
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetIntSize() int {
|
||||
return int(unsafe.Sizeof(1))
|
||||
}
|
68
vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go
generated
vendored
Normal file
68
vendor/github.com/opencontainers/runc/libcontainer/utils/utils_unix.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
// +build !windows
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// EnsureProcHandle returns whether or not the given file handle is on procfs.
|
||||
func EnsureProcHandle(fh *os.File) error {
|
||||
var buf unix.Statfs_t
|
||||
if err := unix.Fstatfs(int(fh.Fd()), &buf); err != nil {
|
||||
return fmt.Errorf("ensure %s is on procfs: %v", fh.Name(), err)
|
||||
}
|
||||
if buf.Type != unix.PROC_SUPER_MAGIC {
|
||||
return fmt.Errorf("%s is not on procfs", fh.Name())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CloseExecFrom applies O_CLOEXEC to all file descriptors currently open for
|
||||
// the process (except for those below the given fd value).
|
||||
func CloseExecFrom(minFd int) error {
|
||||
fdDir, err := os.Open("/proc/self/fd")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fdDir.Close()
|
||||
|
||||
if err := EnsureProcHandle(fdDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fdList, err := fdDir.Readdirnames(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, fdStr := range fdList {
|
||||
fd, err := strconv.Atoi(fdStr)
|
||||
// Ignore non-numeric file names.
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// Ignore descriptors lower than our specified minimum.
|
||||
if fd < minFd {
|
||||
continue
|
||||
}
|
||||
// Intentionally ignore errors from unix.CloseOnExec -- the cases where
|
||||
// this might fail are basically file descriptors that have already
|
||||
// been closed (including and especially the one that was created when
|
||||
// ioutil.ReadDir did the "opendir" syscall).
|
||||
unix.CloseOnExec(fd)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewSockPair returns a new unix socket pair
|
||||
func NewSockPair(name string) (parent *os.File, child *os.File, err error) {
|
||||
fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return os.NewFile(uintptr(fds[1]), name+"-p"), os.NewFile(uintptr(fds[0]), name+"-c"), nil
|
||||
}
|
38
vendor/github.com/opencontainers/runc/vendor.conf
generated
vendored
38
vendor/github.com/opencontainers/runc/vendor.conf
generated
vendored
@ -1,26 +1,28 @@
|
||||
# OCI runtime-spec. When updating this, make sure you use a version tag rather
|
||||
# than a commit ID so it's much more obvious what version of the spec we are
|
||||
# using.
|
||||
github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4
|
||||
github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db
|
||||
|
||||
# Core libcontainer functionality.
|
||||
github.com/checkpoint-restore/go-criu v3.11
|
||||
github.com/mrunalp/fileutils ed869b029674c0e9ce4c0dfa781405c2d9946d08
|
||||
github.com/opencontainers/selinux v1.2.2
|
||||
github.com/seccomp/libseccomp-golang v0.9.1
|
||||
github.com/sirupsen/logrus 8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f
|
||||
github.com/syndtr/gocapability db04d3cc01c8b54962a58ec7e491717d06cfcc16
|
||||
github.com/vishvananda/netlink 1e2e08e8a2dcdacaae3f14ac44c5cfa31361f270
|
||||
github.com/checkpoint-restore/go-criu 17b0214f6c48980c45dc47ecb0cfd6d9e02df723 # v3.11
|
||||
github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7
|
||||
github.com/opencontainers/selinux 5215b1806f52b1fcc2070a8826c542c9d33cd3cf # v1.3.0 (+ CVE-2019-16884)
|
||||
github.com/seccomp/libseccomp-golang 689e3c1541a84461afc49c1c87352a6cedf72e9c # v0.9.1
|
||||
github.com/sirupsen/logrus 8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f # v1.4.1
|
||||
github.com/syndtr/gocapability d98352740cb2c55f81556b63d4a1ec64c5a319c2
|
||||
github.com/vishvananda/netlink 1e2e08e8a2dcdacaae3f14ac44c5cfa31361f270
|
||||
|
||||
# systemd integration.
|
||||
github.com/coreos/go-systemd v14
|
||||
github.com/coreos/pkg v3
|
||||
github.com/godbus/dbus v3
|
||||
github.com/golang/protobuf 18c9bb3261723cd5401db4d0c9fbc5c3b6c70fe8
|
||||
github.com/coreos/go-systemd 95778dfbb74eb7e4dbaf43bf7d71809650ef8076 # v19
|
||||
github.com/godbus/dbus 2ff6f7ffd60f0f2410b3105864bdd12c7894f844 # v5.0.1
|
||||
github.com/golang/protobuf 925541529c1fa6821df4e44ce2723319eb2be768 # v1.0.0
|
||||
|
||||
# Command-line interface.
|
||||
github.com/cyphar/filepath-securejoin v0.2.1
|
||||
github.com/docker/go-units v0.2.0
|
||||
github.com/urfave/cli d53eb991652b1d438abdd34ce4bfa3ef1539108e
|
||||
golang.org/x/sys 41f3e6584952bb034a481797859f6ab34b6803bd https://github.com/golang/sys
|
||||
github.com/cyphar/filepath-securejoin a261ee33d7a517f054effbf451841abaafe3e0fd # v0.2.2
|
||||
github.com/docker/go-units 47565b4f722fb6ceae66b95f853feed578a4a51c # v0.3.3
|
||||
github.com/urfave/cli cfb38830724cc34fedffe9a2a29fb54fa9169cd1 # v1.20.0
|
||||
golang.org/x/sys 9eafafc0a87e0fd0aeeba439a4573537970c44c7 https://github.com/golang/sys
|
||||
|
||||
# console dependencies
|
||||
github.com/containerd/console 2748ece16665b45a47f884001d5831ec79703880
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/containerd/console 0650fd9eeb50bab4fc99dceb9f2e14cf58f36e7f
|
||||
github.com/pkg/errors ba968bfe8b2f7e042a574c888954fccecfa385b4 # v0.8.1
|
||||
|
Loading…
Reference in New Issue
Block a user