mirror of
https://github.com/mudler/luet.git
synced 2025-09-11 12:13:32 +00:00
Update gomod and vendor
This commit is contained in:
39
vendor/github.com/moby/buildkit/executor/executor.go
generated
vendored
Normal file
39
vendor/github.com/moby/buildkit/executor/executor.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package executor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/moby/buildkit/cache"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
)
|
||||
|
||||
type Meta struct {
|
||||
Args []string
|
||||
Env []string
|
||||
User string
|
||||
Cwd string
|
||||
Tty bool
|
||||
ReadonlyRootFS bool
|
||||
ExtraHosts []HostIP
|
||||
NetMode pb.NetMode
|
||||
SecurityMode pb.SecurityMode
|
||||
}
|
||||
|
||||
type Mount struct {
|
||||
Src cache.Mountable
|
||||
Selector string
|
||||
Dest string
|
||||
Readonly bool
|
||||
}
|
||||
|
||||
type Executor interface {
|
||||
// TODO: add stdout/err
|
||||
Exec(ctx context.Context, meta Meta, rootfs cache.Mountable, mounts []Mount, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
|
||||
}
|
||||
|
||||
type HostIP struct {
|
||||
Host string
|
||||
IP net.IP
|
||||
}
|
78
vendor/github.com/moby/buildkit/executor/oci/hosts.go
generated
vendored
Normal file
78
vendor/github.com/moby/buildkit/executor/oci/hosts.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package oci
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/moby/buildkit/executor"
|
||||
"github.com/moby/buildkit/identity"
|
||||
)
|
||||
|
||||
const hostsContent = `
|
||||
127.0.0.1 localhost buildkitsandbox
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
`
|
||||
|
||||
func GetHostsFile(ctx context.Context, stateDir string, extraHosts []executor.HostIP, idmap *idtools.IdentityMapping) (string, func(), error) {
|
||||
if len(extraHosts) == 0 {
|
||||
_, err := g.Do(ctx, stateDir, func(ctx context.Context) (interface{}, error) {
|
||||
_, _, err := makeHostsFile(stateDir, nil, idmap)
|
||||
return nil, err
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return filepath.Join(stateDir, "hosts"), func() {}, nil
|
||||
}
|
||||
return makeHostsFile(stateDir, extraHosts, idmap)
|
||||
}
|
||||
|
||||
func makeHostsFile(stateDir string, extraHosts []executor.HostIP, idmap *idtools.IdentityMapping) (string, func(), error) {
|
||||
p := filepath.Join(stateDir, "hosts")
|
||||
if len(extraHosts) != 0 {
|
||||
p += "." + identity.NewID()
|
||||
}
|
||||
_, err := os.Stat(p)
|
||||
if err == nil {
|
||||
return "", func() {}, nil
|
||||
}
|
||||
if !os.IsNotExist(err) {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
|
||||
if _, err := b.Write([]byte(hostsContent)); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
for _, h := range extraHosts {
|
||||
if _, err := b.Write([]byte(fmt.Sprintf("%s\t%s\n", h.IP.String(), h.Host))); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
tmpPath := p + ".tmp"
|
||||
if err := ioutil.WriteFile(tmpPath, b.Bytes(), 0644); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if idmap != nil {
|
||||
root := idmap.RootPair()
|
||||
if err := os.Chown(tmpPath, root.UID, root.GID); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Rename(tmpPath, p); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return p, func() {
|
||||
os.RemoveAll(p)
|
||||
}, nil
|
||||
}
|
117
vendor/github.com/moby/buildkit/executor/oci/mounts.go
generated
vendored
Normal file
117
vendor/github.com/moby/buildkit/executor/oci/mounts.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// MountOpts sets oci spec specific info for mount points
|
||||
type MountOpts func([]specs.Mount) ([]specs.Mount, error)
|
||||
|
||||
//GetMounts returns default required for buildkit
|
||||
// https://github.com/moby/buildkit/issues/429
|
||||
func GetMounts(ctx context.Context, mountOpts ...MountOpts) ([]specs.Mount, error) {
|
||||
mounts := []specs.Mount{
|
||||
{
|
||||
Destination: "/proc",
|
||||
Type: "proc",
|
||||
Source: "proc",
|
||||
},
|
||||
{
|
||||
Destination: "/dev",
|
||||
Type: "tmpfs",
|
||||
Source: "tmpfs",
|
||||
Options: []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/pts",
|
||||
Type: "devpts",
|
||||
Source: "devpts",
|
||||
Options: []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/shm",
|
||||
Type: "tmpfs",
|
||||
Source: "shm",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
|
||||
},
|
||||
{
|
||||
Destination: "/dev/mqueue",
|
||||
Type: "mqueue",
|
||||
Source: "mqueue",
|
||||
Options: []string{"nosuid", "noexec", "nodev"},
|
||||
},
|
||||
{
|
||||
Destination: "/sys",
|
||||
Type: "sysfs",
|
||||
Source: "sysfs",
|
||||
Options: []string{"nosuid", "noexec", "nodev", "ro"},
|
||||
},
|
||||
}
|
||||
var err error
|
||||
for _, o := range mountOpts {
|
||||
mounts, err = o(mounts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return mounts, nil
|
||||
}
|
||||
|
||||
func withROBind(src, dest string) func(m []specs.Mount) ([]specs.Mount, error) {
|
||||
return func(m []specs.Mount) ([]specs.Mount, error) {
|
||||
m = append(m, specs.Mount{
|
||||
Destination: dest,
|
||||
Type: "bind",
|
||||
Source: src,
|
||||
Options: []string{"rbind", "ro"},
|
||||
})
|
||||
return m, nil
|
||||
}
|
||||
}
|
||||
|
||||
func hasPrefix(p, prefixDir string) bool {
|
||||
prefixDir = filepath.Clean(prefixDir)
|
||||
if prefixDir == "/" {
|
||||
return true
|
||||
}
|
||||
p = filepath.Clean(p)
|
||||
return p == prefixDir || strings.HasPrefix(p, prefixDir+"/")
|
||||
}
|
||||
|
||||
func removeMountsWithPrefix(mounts []specs.Mount, prefixDir string) []specs.Mount {
|
||||
var ret []specs.Mount
|
||||
for _, m := range mounts {
|
||||
if !hasPrefix(m.Destination, prefixDir) {
|
||||
ret = append(ret, m)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func withProcessMode(processMode ProcessMode) func([]specs.Mount) ([]specs.Mount, error) {
|
||||
return func(m []specs.Mount) ([]specs.Mount, error) {
|
||||
switch processMode {
|
||||
case ProcessSandbox:
|
||||
// keep the default
|
||||
case NoProcessSandbox:
|
||||
m = removeMountsWithPrefix(m, "/proc")
|
||||
procMount := specs.Mount{
|
||||
Destination: "/proc",
|
||||
Type: "bind",
|
||||
Source: "/proc",
|
||||
// NOTE: "rbind"+"ro" does not make /proc read-only recursively.
|
||||
// So we keep maskedPath and readonlyPaths (although not mandatory for rootless mode)
|
||||
Options: []string{"rbind"},
|
||||
}
|
||||
m = append([]specs.Mount{procMount}, m...)
|
||||
default:
|
||||
return nil, errors.Errorf("unknown process mode: %v", processMode)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
}
|
123
vendor/github.com/moby/buildkit/executor/oci/resolvconf.go
generated
vendored
Normal file
123
vendor/github.com/moby/buildkit/executor/oci/resolvconf.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/docker/libnetwork/resolvconf"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/moby/buildkit/util/flightcontrol"
|
||||
)
|
||||
|
||||
var g flightcontrol.Group
|
||||
var notFirstRun bool
|
||||
var lastNotEmpty bool
|
||||
|
||||
// overridden by tests
|
||||
var resolvconfGet = resolvconf.Get
|
||||
|
||||
type DNSConfig struct {
|
||||
Nameservers []string
|
||||
Options []string
|
||||
SearchDomains []string
|
||||
}
|
||||
|
||||
func GetResolvConf(ctx context.Context, stateDir string, idmap *idtools.IdentityMapping, dns *DNSConfig) (string, error) {
|
||||
p := filepath.Join(stateDir, "resolv.conf")
|
||||
_, err := g.Do(ctx, stateDir, func(ctx context.Context) (interface{}, error) {
|
||||
generate := !notFirstRun
|
||||
notFirstRun = true
|
||||
|
||||
if !generate {
|
||||
fi, err := os.Stat(p)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
generate = true
|
||||
}
|
||||
if !generate {
|
||||
fiMain, err := os.Stat(resolvconf.Path())
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
if lastNotEmpty {
|
||||
generate = true
|
||||
lastNotEmpty = false
|
||||
}
|
||||
} else {
|
||||
if fi.ModTime().Before(fiMain.ModTime()) {
|
||||
generate = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !generate {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
var dt []byte
|
||||
f, err := resolvconfGet()
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
dt = f.Content
|
||||
}
|
||||
|
||||
if dns != nil {
|
||||
var (
|
||||
dnsNameservers = resolvconf.GetNameservers(dt, types.IP)
|
||||
dnsSearchDomains = resolvconf.GetSearchDomains(dt)
|
||||
dnsOptions = resolvconf.GetOptions(dt)
|
||||
)
|
||||
if len(dns.Nameservers) > 0 {
|
||||
dnsNameservers = dns.Nameservers
|
||||
}
|
||||
if len(dns.SearchDomains) > 0 {
|
||||
dnsSearchDomains = dns.SearchDomains
|
||||
}
|
||||
if len(dns.Options) > 0 {
|
||||
dnsOptions = dns.Options
|
||||
}
|
||||
|
||||
f, err = resolvconf.Build(p+".tmp", dnsNameservers, dnsSearchDomains, dnsOptions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dt = f.Content
|
||||
}
|
||||
|
||||
f, err = resolvconf.FilterResolvDNS(dt, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tmpPath := p + ".tmp"
|
||||
if err := ioutil.WriteFile(tmpPath, f.Content, 0644); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if idmap != nil {
|
||||
root := idmap.RootPair()
|
||||
if err := os.Chown(tmpPath, root.UID, root.GID); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.Rename(tmpPath, p); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "", nil
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return p, nil
|
||||
}
|
13
vendor/github.com/moby/buildkit/executor/oci/spec.go
generated
vendored
Normal file
13
vendor/github.com/moby/buildkit/executor/oci/spec.go
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package oci
|
||||
|
||||
// ProcMode configures PID namespaces
|
||||
type ProcessMode int
|
||||
|
||||
const (
|
||||
// ProcessSandbox unshares pidns and mount procfs.
|
||||
ProcessSandbox ProcessMode = iota
|
||||
// NoProcessSandbox uses host pidns and bind-mount procfs.
|
||||
// Note that NoProcessSandbox allows build containers to kill (and potentially ptrace) an arbitrary process in the BuildKit host namespace.
|
||||
// NoProcessSandbox should be enabled only when the BuildKit is running in a container as an unprivileged user.
|
||||
NoProcessSandbox
|
||||
)
|
254
vendor/github.com/moby/buildkit/executor/oci/spec_unix.go
generated
vendored
Normal file
254
vendor/github.com/moby/buildkit/executor/oci/spec_unix.go
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
// +build !windows
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"sync"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
"github.com/containerd/containerd/contrib/seccomp"
|
||||
"github.com/containerd/containerd/mount"
|
||||
"github.com/containerd/containerd/namespaces"
|
||||
"github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/continuity/fs"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/mitchellh/hashstructure"
|
||||
"github.com/moby/buildkit/executor"
|
||||
"github.com/moby/buildkit/snapshot"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
"github.com/moby/buildkit/util/entitlements/security"
|
||||
"github.com/moby/buildkit/util/network"
|
||||
"github.com/moby/buildkit/util/system"
|
||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Ideally we don't have to import whole containerd just for the default spec
|
||||
|
||||
// GenerateSpec generates spec using containerd functionality.
|
||||
// opts are ignored for s.Process, s.Hostname, and s.Mounts .
|
||||
func GenerateSpec(ctx context.Context, meta executor.Meta, mounts []executor.Mount, id, resolvConf, hostsFile string, namespace network.Namespace, processMode ProcessMode, idmap *idtools.IdentityMapping, opts ...oci.SpecOpts) (*specs.Spec, func(), error) {
|
||||
c := &containers.Container{
|
||||
ID: id,
|
||||
}
|
||||
_, ok := namespaces.Namespace(ctx)
|
||||
if !ok {
|
||||
ctx = namespaces.WithNamespace(ctx, "buildkit")
|
||||
}
|
||||
if meta.SecurityMode == pb.SecurityMode_INSECURE {
|
||||
opts = append(opts, security.WithInsecureSpec())
|
||||
} else if system.SeccompSupported() && meta.SecurityMode == pb.SecurityMode_SANDBOX {
|
||||
opts = append(opts, seccomp.WithDefaultProfile())
|
||||
}
|
||||
|
||||
switch processMode {
|
||||
case NoProcessSandbox:
|
||||
// Mount for /proc is replaced in GetMounts()
|
||||
opts = append(opts,
|
||||
oci.WithHostNamespace(specs.PIDNamespace))
|
||||
// TODO(AkihiroSuda): Configure seccomp to disable ptrace (and prctl?) explicitly
|
||||
}
|
||||
|
||||
// Note that containerd.GenerateSpec is namespaced so as to make
|
||||
// specs.Linux.CgroupsPath namespaced
|
||||
s, err := oci.GenerateSpec(ctx, nil, c, opts...)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// set the networking information on the spec
|
||||
namespace.Set(s)
|
||||
|
||||
s.Process.Args = meta.Args
|
||||
s.Process.Env = meta.Env
|
||||
s.Process.Cwd = meta.Cwd
|
||||
s.Process.Rlimits = nil // reset open files limit
|
||||
s.Process.NoNewPrivileges = false // reset nonewprivileges
|
||||
s.Hostname = "buildkitsandbox"
|
||||
|
||||
s.Mounts, err = GetMounts(ctx,
|
||||
withProcessMode(processMode),
|
||||
withROBind(resolvConf, "/etc/resolv.conf"),
|
||||
withROBind(hostsFile, "/etc/hosts"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
s.Mounts = append(s.Mounts, specs.Mount{
|
||||
Destination: "/sys/fs/cgroup",
|
||||
Type: "cgroup",
|
||||
Source: "cgroup",
|
||||
Options: []string{"ro", "nosuid", "noexec", "nodev"},
|
||||
})
|
||||
|
||||
if processMode == NoProcessSandbox {
|
||||
var maskedPaths []string
|
||||
for _, s := range s.Linux.MaskedPaths {
|
||||
if !hasPrefix(s, "/proc") {
|
||||
maskedPaths = append(maskedPaths, s)
|
||||
}
|
||||
}
|
||||
s.Linux.MaskedPaths = maskedPaths
|
||||
var readonlyPaths []string
|
||||
for _, s := range s.Linux.ReadonlyPaths {
|
||||
if !hasPrefix(s, "/proc") {
|
||||
readonlyPaths = append(readonlyPaths, s)
|
||||
}
|
||||
}
|
||||
s.Linux.ReadonlyPaths = readonlyPaths
|
||||
}
|
||||
|
||||
if meta.SecurityMode == pb.SecurityMode_INSECURE {
|
||||
if err = oci.WithWriteableCgroupfs(ctx, nil, c, s); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err = oci.WithWriteableSysfs(ctx, nil, c, s); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if idmap != nil {
|
||||
s.Linux.Namespaces = append(s.Linux.Namespaces, specs.LinuxNamespace{
|
||||
Type: specs.UserNamespace,
|
||||
})
|
||||
s.Linux.UIDMappings = specMapping(idmap.UIDs())
|
||||
s.Linux.GIDMappings = specMapping(idmap.GIDs())
|
||||
}
|
||||
|
||||
sm := &submounts{}
|
||||
|
||||
var releasers []func() error
|
||||
releaseAll := func() {
|
||||
sm.cleanup()
|
||||
for _, f := range releasers {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
for _, m := range mounts {
|
||||
if m.Src == nil {
|
||||
return nil, nil, errors.Errorf("mount %s has no source", m.Dest)
|
||||
}
|
||||
mountable, err := m.Src.Mount(ctx, m.Readonly)
|
||||
if err != nil {
|
||||
releaseAll()
|
||||
return nil, nil, errors.Wrapf(err, "failed to mount %s", m.Dest)
|
||||
}
|
||||
mounts, release, err := mountable.Mount()
|
||||
if err != nil {
|
||||
releaseAll()
|
||||
return nil, nil, errors.WithStack(err)
|
||||
}
|
||||
releasers = append(releasers, release)
|
||||
for _, mount := range mounts {
|
||||
mount, err = sm.subMount(mount, m.Selector)
|
||||
if err != nil {
|
||||
releaseAll()
|
||||
return nil, nil, err
|
||||
}
|
||||
s.Mounts = append(s.Mounts, specs.Mount{
|
||||
Destination: m.Dest,
|
||||
Type: mount.Type,
|
||||
Source: mount.Source,
|
||||
Options: mount.Options,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return s, releaseAll, nil
|
||||
}
|
||||
|
||||
type mountRef struct {
|
||||
mount mount.Mount
|
||||
unmount func() error
|
||||
}
|
||||
|
||||
type submounts struct {
|
||||
m map[uint64]mountRef
|
||||
}
|
||||
|
||||
func (s *submounts) subMount(m mount.Mount, subPath string) (mount.Mount, error) {
|
||||
if path.Join("/", subPath) == "/" {
|
||||
return m, nil
|
||||
}
|
||||
if s.m == nil {
|
||||
s.m = map[uint64]mountRef{}
|
||||
}
|
||||
h, err := hashstructure.Hash(m, nil)
|
||||
if err != nil {
|
||||
return mount.Mount{}, nil
|
||||
}
|
||||
if mr, ok := s.m[h]; ok {
|
||||
sm, err := sub(mr.mount, subPath)
|
||||
if err != nil {
|
||||
return mount.Mount{}, nil
|
||||
}
|
||||
return sm, nil
|
||||
}
|
||||
|
||||
lm := snapshot.LocalMounterWithMounts([]mount.Mount{m})
|
||||
|
||||
mp, err := lm.Mount()
|
||||
if err != nil {
|
||||
return mount.Mount{}, err
|
||||
}
|
||||
|
||||
opts := []string{"rbind"}
|
||||
for _, opt := range m.Options {
|
||||
if opt == "ro" {
|
||||
opts = append(opts, opt)
|
||||
}
|
||||
}
|
||||
|
||||
s.m[h] = mountRef{
|
||||
mount: mount.Mount{
|
||||
Source: mp,
|
||||
Type: "bind",
|
||||
Options: opts,
|
||||
},
|
||||
unmount: lm.Unmount,
|
||||
}
|
||||
|
||||
sm, err := sub(s.m[h].mount, subPath)
|
||||
if err != nil {
|
||||
return mount.Mount{}, err
|
||||
}
|
||||
return sm, nil
|
||||
}
|
||||
|
||||
func (s *submounts) cleanup() {
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(s.m))
|
||||
for _, m := range s.m {
|
||||
func(m mountRef) {
|
||||
go func() {
|
||||
m.unmount()
|
||||
wg.Done()
|
||||
}()
|
||||
}(m)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func sub(m mount.Mount, subPath string) (mount.Mount, error) {
|
||||
src, err := fs.RootPath(m.Source, subPath)
|
||||
if err != nil {
|
||||
return mount.Mount{}, err
|
||||
}
|
||||
m.Source = src
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func specMapping(s []idtools.IDMap) []specs.LinuxIDMapping {
|
||||
var ids []specs.LinuxIDMapping
|
||||
for _, item := range s {
|
||||
ids = append(ids, specs.LinuxIDMapping{
|
||||
HostID: uint32(item.HostID),
|
||||
ContainerID: uint32(item.ContainerID),
|
||||
Size: uint32(item.Size),
|
||||
})
|
||||
}
|
||||
return ids
|
||||
}
|
99
vendor/github.com/moby/buildkit/executor/oci/user.go
generated
vendored
Normal file
99
vendor/github.com/moby/buildkit/executor/oci/user.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containerd/containerd/containers"
|
||||
containerdoci "github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/continuity/fs"
|
||||
"github.com/opencontainers/runc/libcontainer/user"
|
||||
"github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
func GetUser(ctx context.Context, root, username string) (uint32, uint32, []uint32, error) {
|
||||
// fast path from uid/gid
|
||||
if uid, gid, err := ParseUIDGID(username); err == nil {
|
||||
return uid, gid, nil, nil
|
||||
}
|
||||
|
||||
passwdFile, err := openUserFile(root, "/etc/passwd")
|
||||
if err == nil {
|
||||
defer passwdFile.Close()
|
||||
}
|
||||
groupFile, err := openUserFile(root, "/etc/group")
|
||||
if err == nil {
|
||||
defer groupFile.Close()
|
||||
}
|
||||
|
||||
execUser, err := user.GetExecUser(username, nil, passwdFile, groupFile)
|
||||
if err != nil {
|
||||
return 0, 0, nil, err
|
||||
}
|
||||
var sgids []uint32
|
||||
for _, g := range execUser.Sgids {
|
||||
sgids = append(sgids, uint32(g))
|
||||
}
|
||||
return uint32(execUser.Uid), uint32(execUser.Gid), sgids, nil
|
||||
}
|
||||
|
||||
// ParseUIDGID takes the fast path to parse UID and GID if and only if they are both provided
|
||||
func ParseUIDGID(str string) (uid uint32, gid uint32, err error) {
|
||||
if str == "" {
|
||||
return 0, 0, nil
|
||||
}
|
||||
parts := strings.SplitN(str, ":", 2)
|
||||
if len(parts) == 1 {
|
||||
return 0, 0, errors.New("groups ID is not provided")
|
||||
}
|
||||
if uid, err = parseUID(parts[0]); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
if gid, err = parseUID(parts[1]); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func openUserFile(root, p string) (*os.File, error) {
|
||||
p, err := fs.RootPath(root, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return os.Open(p)
|
||||
}
|
||||
|
||||
func parseUID(str string) (uint32, error) {
|
||||
if str == "root" {
|
||||
return 0, nil
|
||||
}
|
||||
uid, err := strconv.ParseUint(str, 10, 32)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint32(uid), nil
|
||||
}
|
||||
|
||||
// WithUIDGID allows the UID and GID for the Process to be set
|
||||
// FIXME: This is a temporeray fix for the missing supplementary GIDs from containerd
|
||||
// once the PR in containerd is merged we should remove this function.
|
||||
func WithUIDGID(uid, gid uint32, sgids []uint32) containerdoci.SpecOpts {
|
||||
return func(_ context.Context, _ containerdoci.Client, _ *containers.Container, s *containerdoci.Spec) error {
|
||||
setProcess(s)
|
||||
s.Process.User.UID = uid
|
||||
s.Process.User.GID = gid
|
||||
s.Process.User.AdditionalGids = sgids
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// setProcess sets Process to empty if unset
|
||||
// FIXME: Same on this one. Need to be removed after containerd fix merged
|
||||
func setProcess(s *containerdoci.Spec) {
|
||||
if s.Process == nil {
|
||||
s.Process = &specs.Process{}
|
||||
}
|
||||
}
|
337
vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
generated
vendored
Normal file
337
vendor/github.com/moby/buildkit/executor/runcexecutor/executor.go
generated
vendored
Normal file
@@ -0,0 +1,337 @@
|
||||
package runcexecutor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/containerd/containerd/mount"
|
||||
containerdoci "github.com/containerd/containerd/oci"
|
||||
"github.com/containerd/continuity/fs"
|
||||
runc "github.com/containerd/go-runc"
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/moby/buildkit/cache"
|
||||
"github.com/moby/buildkit/executor"
|
||||
"github.com/moby/buildkit/executor/oci"
|
||||
"github.com/moby/buildkit/identity"
|
||||
"github.com/moby/buildkit/solver/pb"
|
||||
"github.com/moby/buildkit/util/network"
|
||||
rootlessspecconv "github.com/moby/buildkit/util/rootless/specconv"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type Opt struct {
|
||||
// root directory
|
||||
Root string
|
||||
CommandCandidates []string
|
||||
// without root privileges (has nothing to do with Opt.Root directory)
|
||||
Rootless bool
|
||||
// DefaultCgroupParent is the cgroup-parent name for executor
|
||||
DefaultCgroupParent string
|
||||
// ProcessMode
|
||||
ProcessMode oci.ProcessMode
|
||||
IdentityMapping *idtools.IdentityMapping
|
||||
// runc run --no-pivot (unrecommended)
|
||||
NoPivot bool
|
||||
DNS *oci.DNSConfig
|
||||
OOMScoreAdj *int
|
||||
}
|
||||
|
||||
var defaultCommandCandidates = []string{"buildkit-runc", "runc"}
|
||||
|
||||
type runcExecutor struct {
|
||||
runc *runc.Runc
|
||||
root string
|
||||
cmd string
|
||||
cgroupParent string
|
||||
rootless bool
|
||||
networkProviders map[pb.NetMode]network.Provider
|
||||
processMode oci.ProcessMode
|
||||
idmap *idtools.IdentityMapping
|
||||
noPivot bool
|
||||
dns *oci.DNSConfig
|
||||
oomScoreAdj *int
|
||||
}
|
||||
|
||||
func New(opt Opt, networkProviders map[pb.NetMode]network.Provider) (executor.Executor, error) {
|
||||
cmds := opt.CommandCandidates
|
||||
if cmds == nil {
|
||||
cmds = defaultCommandCandidates
|
||||
}
|
||||
|
||||
var cmd string
|
||||
var found bool
|
||||
for _, cmd = range cmds {
|
||||
if _, err := exec.LookPath(cmd); err == nil {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return nil, errors.Errorf("failed to find %s binary", cmd)
|
||||
}
|
||||
|
||||
root := opt.Root
|
||||
|
||||
if err := os.MkdirAll(root, 0711); err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to create %s", root)
|
||||
}
|
||||
|
||||
root, err := filepath.Abs(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
root, err = filepath.EvalSymlinks(root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// clean up old hosts/resolv.conf file. ignore errors
|
||||
os.RemoveAll(filepath.Join(root, "hosts"))
|
||||
os.RemoveAll(filepath.Join(root, "resolv.conf"))
|
||||
|
||||
runtime := &runc.Runc{
|
||||
Command: cmd,
|
||||
Log: filepath.Join(root, "runc-log.json"),
|
||||
LogFormat: runc.JSON,
|
||||
PdeathSignal: syscall.SIGKILL, // this can still leak the process
|
||||
Setpgid: true,
|
||||
// we don't execute runc with --rootless=(true|false) explicitly,
|
||||
// so as to support non-runc runtimes
|
||||
}
|
||||
|
||||
w := &runcExecutor{
|
||||
runc: runtime,
|
||||
root: root,
|
||||
cgroupParent: opt.DefaultCgroupParent,
|
||||
rootless: opt.Rootless,
|
||||
networkProviders: networkProviders,
|
||||
processMode: opt.ProcessMode,
|
||||
idmap: opt.IdentityMapping,
|
||||
noPivot: opt.NoPivot,
|
||||
dns: opt.DNS,
|
||||
oomScoreAdj: opt.OOMScoreAdj,
|
||||
}
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (w *runcExecutor) Exec(ctx context.Context, meta executor.Meta, root cache.Mountable, mounts []executor.Mount, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error {
|
||||
provider, ok := w.networkProviders[meta.NetMode]
|
||||
if !ok {
|
||||
return errors.Errorf("unknown network mode %s", meta.NetMode)
|
||||
}
|
||||
namespace, err := provider.New()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer namespace.Close()
|
||||
|
||||
if meta.NetMode == pb.NetMode_HOST {
|
||||
logrus.Info("enabling HostNetworking")
|
||||
}
|
||||
|
||||
resolvConf, err := oci.GetResolvConf(ctx, w.root, w.idmap, w.dns)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hostsFile, clean, err := oci.GetHostsFile(ctx, w.root, meta.ExtraHosts, w.idmap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if clean != nil {
|
||||
defer clean()
|
||||
}
|
||||
|
||||
mountable, err := root.Mount(ctx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rootMount, release, err := mountable.Mount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if release != nil {
|
||||
defer release()
|
||||
}
|
||||
|
||||
id := identity.NewID()
|
||||
bundle := filepath.Join(w.root, id)
|
||||
|
||||
if err := os.Mkdir(bundle, 0711); err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(bundle)
|
||||
|
||||
identity := idtools.Identity{}
|
||||
if w.idmap != nil {
|
||||
identity = w.idmap.RootPair()
|
||||
}
|
||||
|
||||
rootFSPath := filepath.Join(bundle, "rootfs")
|
||||
if err := idtools.MkdirAllAndChown(rootFSPath, 0700, identity); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := mount.All(rootMount, rootFSPath); err != nil {
|
||||
return err
|
||||
}
|
||||
defer mount.Unmount(rootFSPath, 0)
|
||||
|
||||
uid, gid, sgids, err := oci.GetUser(ctx, rootFSPath, meta.User)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.Create(filepath.Join(bundle, "config.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
opts := []containerdoci.SpecOpts{oci.WithUIDGID(uid, gid, sgids)}
|
||||
|
||||
if meta.ReadonlyRootFS {
|
||||
opts = append(opts, containerdoci.WithRootFSReadonly())
|
||||
}
|
||||
|
||||
identity = idtools.Identity{
|
||||
UID: int(uid),
|
||||
GID: int(gid),
|
||||
}
|
||||
if w.idmap != nil {
|
||||
identity, err = w.idmap.ToHost(identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if w.cgroupParent != "" {
|
||||
var cgroupsPath string
|
||||
lastSeparator := w.cgroupParent[len(w.cgroupParent)-1:]
|
||||
if strings.Contains(w.cgroupParent, ".slice") && lastSeparator == ":" {
|
||||
cgroupsPath = w.cgroupParent + id
|
||||
} else {
|
||||
cgroupsPath = filepath.Join("/", w.cgroupParent, "buildkit", id)
|
||||
}
|
||||
opts = append(opts, containerdoci.WithCgroup(cgroupsPath))
|
||||
}
|
||||
spec, cleanup, err := oci.GenerateSpec(ctx, meta, mounts, id, resolvConf, hostsFile, namespace, w.processMode, w.idmap, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
spec.Root.Path = rootFSPath
|
||||
if _, ok := root.(cache.ImmutableRef); ok { // TODO: pass in with mount, not ref type
|
||||
spec.Root.Readonly = true
|
||||
}
|
||||
|
||||
newp, err := fs.RootPath(rootFSPath, meta.Cwd)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "working dir %s points to invalid target", newp)
|
||||
}
|
||||
if _, err := os.Stat(newp); err != nil {
|
||||
if err := idtools.MkdirAllAndChown(newp, 0755, identity); err != nil {
|
||||
return errors.Wrapf(err, "failed to create working directory %s", newp)
|
||||
}
|
||||
}
|
||||
|
||||
spec.Process.OOMScoreAdj = w.oomScoreAdj
|
||||
if w.rootless {
|
||||
if err := rootlessspecconv.ToRootless(spec); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(f).Encode(spec); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// runCtx/killCtx is used for extra check in case the kill command blocks
|
||||
runCtx, cancelRun := context.WithCancel(context.Background())
|
||||
defer cancelRun()
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
killCtx, timeout := context.WithTimeout(context.Background(), 7*time.Second)
|
||||
if err := w.runc.Kill(killCtx, id, int(syscall.SIGKILL), nil); err != nil {
|
||||
logrus.Errorf("failed to kill runc %s: %+v", id, err)
|
||||
select {
|
||||
case <-killCtx.Done():
|
||||
timeout()
|
||||
cancelRun()
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
timeout()
|
||||
select {
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
case <-done:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
logrus.Debugf("> creating %s %v", id, meta.Args)
|
||||
status, err := w.runc.Run(runCtx, id, bundle, &runc.CreateOpts{
|
||||
IO: &forwardIO{stdin: stdin, stdout: stdout, stderr: stderr},
|
||||
NoPivot: w.noPivot,
|
||||
})
|
||||
close(done)
|
||||
|
||||
if status != 0 || err != nil {
|
||||
if err == nil {
|
||||
err = errors.Errorf("exit code: %d", status)
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return errors.Wrapf(ctx.Err(), err.Error())
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type forwardIO struct {
|
||||
stdin io.ReadCloser
|
||||
stdout, stderr io.WriteCloser
|
||||
}
|
||||
|
||||
func (s *forwardIO) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *forwardIO) Set(cmd *exec.Cmd) {
|
||||
cmd.Stdin = s.stdin
|
||||
cmd.Stdout = s.stdout
|
||||
cmd.Stderr = s.stderr
|
||||
}
|
||||
|
||||
func (s *forwardIO) Stdin() io.WriteCloser {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *forwardIO) Stdout() io.ReadCloser {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *forwardIO) Stderr() io.ReadCloser {
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user