mirror of https://github.com/k3s-io/k3s
commit
b5217e2888
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/containerd/containerd"
|
"github.com/containerd/containerd"
|
||||||
"github.com/containerd/containerd/namespaces"
|
"github.com/containerd/containerd/namespaces"
|
||||||
"github.com/natefinch/lumberjack"
|
"github.com/natefinch/lumberjack"
|
||||||
|
"github.com/opencontainers/runc/libcontainer/system"
|
||||||
util2 "github.com/rancher/k3s/pkg/agent/util"
|
util2 "github.com/rancher/k3s/pkg/agent/util"
|
||||||
"github.com/rancher/k3s/pkg/daemons/config"
|
"github.com/rancher/k3s/pkg/daemons/config"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -27,10 +28,15 @@ const (
|
||||||
maxMsgSize = 1024 * 1024 * 16
|
maxMsgSize = 1024 * 1024 * 16
|
||||||
configToml = `
|
configToml = `
|
||||||
[plugins.opt]
|
[plugins.opt]
|
||||||
path = "%OPT%"
|
path = "%OPT%"
|
||||||
[plugins.cri]
|
[plugins.cri]
|
||||||
stream_server_address = "%NODE%"
|
stream_server_address = "%NODE%"
|
||||||
stream_server_port = "10010"
|
stream_server_port = "10010"
|
||||||
|
`
|
||||||
|
configUserNSToml = `
|
||||||
|
disable_cgroup = true
|
||||||
|
disable_apparmor = true
|
||||||
|
restrict_oom_score_adj = true
|
||||||
`
|
`
|
||||||
configCNIToml = `
|
configCNIToml = `
|
||||||
[plugins.cri.cni]
|
[plugins.cri.cni]
|
||||||
|
@ -49,6 +55,9 @@ func Run(ctx context.Context, cfg *config.Node) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
template := configToml
|
template := configToml
|
||||||
|
if system.RunningInUserNS() {
|
||||||
|
template += configUserNSToml
|
||||||
|
}
|
||||||
if !cfg.NoFlannel {
|
if !cfg.NoFlannel {
|
||||||
template += configCNIToml
|
template += configCNIToml
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/rancher/k3s/pkg/agent/tunnel"
|
"github.com/rancher/k3s/pkg/agent/tunnel"
|
||||||
"github.com/rancher/k3s/pkg/cli/cmds"
|
"github.com/rancher/k3s/pkg/cli/cmds"
|
||||||
"github.com/rancher/k3s/pkg/daemons/agent"
|
"github.com/rancher/k3s/pkg/daemons/agent"
|
||||||
|
"github.com/rancher/k3s/pkg/rootless"
|
||||||
"github.com/rancher/norman/pkg/clientaccess"
|
"github.com/rancher/norman/pkg/clientaccess"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -69,6 +70,12 @@ func Run(ctx context.Context, cfg cmds.Agent) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.Rootless {
|
||||||
|
if err := rootless.Rootless(cfg.DataDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cfg.DataDir = filepath.Join(cfg.DataDir, "agent")
|
cfg.DataDir = filepath.Join(cfg.DataDir, "agent")
|
||||||
|
|
||||||
if cfg.ClusterSecret != "" {
|
if cfg.ClusterSecret != "" {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/rancher/k3s/pkg/agent"
|
"github.com/rancher/k3s/pkg/agent"
|
||||||
"github.com/rancher/k3s/pkg/cli/cmds"
|
"github.com/rancher/k3s/pkg/cli/cmds"
|
||||||
"github.com/rancher/norman/pkg/resolvehome"
|
"github.com/rancher/k3s/pkg/datadir"
|
||||||
"github.com/rancher/norman/signal"
|
"github.com/rancher/norman/signal"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
|
@ -57,7 +57,7 @@ func Run(ctx *cli.Context) error {
|
||||||
|
|
||||||
logrus.Infof("Starting k3s agent %s", ctx.App.Version)
|
logrus.Infof("Starting k3s agent %s", ctx.App.Version)
|
||||||
|
|
||||||
dataDir, err := resolvehome.Resolve(cmds.AgentConfig.DataDir)
|
dataDir, err := datadir.LocalHome(cmds.AgentConfig.DataDir, cmds.AgentConfig.Rootless)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ type Agent struct {
|
||||||
ContainerRuntimeEndpoint string
|
ContainerRuntimeEndpoint string
|
||||||
NoFlannel bool
|
NoFlannel bool
|
||||||
Debug bool
|
Debug bool
|
||||||
|
Rootless bool
|
||||||
AgentShared
|
AgentShared
|
||||||
ExtraKubeletArgs cli.StringSlice
|
ExtraKubeletArgs cli.StringSlice
|
||||||
ExtraKubeProxyArgs cli.StringSlice
|
ExtraKubeProxyArgs cli.StringSlice
|
||||||
|
@ -113,6 +114,11 @@ func NewAgentCommand(action func(ctx *cli.Context) error) cli.Command {
|
||||||
Destination: &AgentConfig.ClusterSecret,
|
Destination: &AgentConfig.ClusterSecret,
|
||||||
EnvVar: "K3S_CLUSTER_SECRET",
|
EnvVar: "K3S_CLUSTER_SECRET",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "rootless",
|
||||||
|
Usage: "(experimental) Run rootless",
|
||||||
|
Destination: &AgentConfig.Rootless,
|
||||||
|
},
|
||||||
DockerFlag,
|
DockerFlag,
|
||||||
FlannelFlag,
|
FlannelFlag,
|
||||||
NodeNameFlag,
|
NodeNameFlag,
|
||||||
|
|
|
@ -21,6 +21,7 @@ type Server struct {
|
||||||
ExtraAPIArgs cli.StringSlice
|
ExtraAPIArgs cli.StringSlice
|
||||||
ExtraSchedulerArgs cli.StringSlice
|
ExtraSchedulerArgs cli.StringSlice
|
||||||
ExtraControllerArgs cli.StringSlice
|
ExtraControllerArgs cli.StringSlice
|
||||||
|
Rootless bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var ServerConfig Server
|
var ServerConfig Server
|
||||||
|
@ -124,6 +125,11 @@ func NewServerCommand(action func(*cli.Context) error) cli.Command {
|
||||||
Usage: "Customized flag for kube-controller-manager process",
|
Usage: "Customized flag for kube-controller-manager process",
|
||||||
Value: &ServerConfig.ExtraControllerArgs,
|
Value: &ServerConfig.ExtraControllerArgs,
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "rootless",
|
||||||
|
Usage: "(experimental) Run rootless",
|
||||||
|
Destination: &ServerConfig.Rootless,
|
||||||
|
},
|
||||||
NodeIPFlag,
|
NodeIPFlag,
|
||||||
NodeNameFlag,
|
NodeNameFlag,
|
||||||
DockerFlag,
|
DockerFlag,
|
||||||
|
|
|
@ -15,12 +15,14 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/rancher/k3s/pkg/agent"
|
"github.com/rancher/k3s/pkg/agent"
|
||||||
"github.com/rancher/k3s/pkg/cli/cmds"
|
"github.com/rancher/k3s/pkg/cli/cmds"
|
||||||
|
"github.com/rancher/k3s/pkg/datadir"
|
||||||
|
"github.com/rancher/k3s/pkg/rootless"
|
||||||
"github.com/rancher/k3s/pkg/server"
|
"github.com/rancher/k3s/pkg/server"
|
||||||
"github.com/rancher/norman/signal"
|
"github.com/rancher/norman/signal"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
"k8s.io/apimachinery/pkg/util/net"
|
"k8s.io/apimachinery/pkg/util/net"
|
||||||
"k8s.io/kubernetes/pkg/volume"
|
"k8s.io/kubernetes/pkg/volume/csi"
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3" // ensure we have sqlite
|
_ "github.com/mattn/go-sqlite3" // ensure we have sqlite
|
||||||
)
|
)
|
||||||
|
@ -67,18 +69,30 @@ func run(app *cli.Context, cfg *cmds.Server) error {
|
||||||
|
|
||||||
setupLogging(app)
|
setupLogging(app)
|
||||||
|
|
||||||
if !cfg.DisableAgent && os.Getuid() != 0 {
|
if !cfg.DisableAgent && os.Getuid() != 0 && !cfg.Rootless {
|
||||||
return fmt.Errorf("must run as root unless --disable-agent is specified")
|
return fmt.Errorf("must run as root unless --disable-agent is specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.Rootless {
|
||||||
|
dataDir, err := datadir.LocalHome(cfg.DataDir, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cfg.DataDir = dataDir
|
||||||
|
if err := rootless.Rootless(dataDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If running agent in server, set this so that CSI initializes properly
|
// If running agent in server, set this so that CSI initializes properly
|
||||||
volume.WaitForValidHost = !cfg.DisableAgent
|
csi.WaitForValidHostName = !cfg.DisableAgent
|
||||||
|
|
||||||
serverConfig := server.Config{}
|
serverConfig := server.Config{}
|
||||||
serverConfig.ControlConfig.ClusterSecret = cfg.ClusterSecret
|
serverConfig.ControlConfig.ClusterSecret = cfg.ClusterSecret
|
||||||
serverConfig.ControlConfig.DataDir = cfg.DataDir
|
serverConfig.ControlConfig.DataDir = cfg.DataDir
|
||||||
serverConfig.ControlConfig.KubeConfigOutput = cfg.KubeConfigOutput
|
serverConfig.ControlConfig.KubeConfigOutput = cfg.KubeConfigOutput
|
||||||
serverConfig.ControlConfig.KubeConfigMode = cfg.KubeConfigMode
|
serverConfig.ControlConfig.KubeConfigMode = cfg.KubeConfigMode
|
||||||
|
serverConfig.Rootless = cfg.Rootless
|
||||||
serverConfig.TLSConfig.HTTPSPort = cfg.HTTPSPort
|
serverConfig.TLSConfig.HTTPSPort = cfg.HTTPSPort
|
||||||
serverConfig.TLSConfig.HTTPPort = cfg.HTTPPort
|
serverConfig.TLSConfig.HTTPPort = cfg.HTTPPort
|
||||||
serverConfig.TLSConfig.KnownIPs = knownIPs(cfg.KnownIPs)
|
serverConfig.TLSConfig.KnownIPs = knownIPs(cfg.KnownIPs)
|
||||||
|
|
|
@ -9,12 +9,14 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/opencontainers/runc/libcontainer/system"
|
||||||
"github.com/rancher/k3s/pkg/daemons/config"
|
"github.com/rancher/k3s/pkg/daemons/config"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"k8s.io/apimachinery/pkg/util/net"
|
"k8s.io/apimachinery/pkg/util/net"
|
||||||
"k8s.io/component-base/logs"
|
"k8s.io/component-base/logs"
|
||||||
app2 "k8s.io/kubernetes/cmd/kube-proxy/app"
|
app2 "k8s.io/kubernetes/cmd/kube-proxy/app"
|
||||||
"k8s.io/kubernetes/cmd/kubelet/app"
|
"k8s.io/kubernetes/cmd/kubelet/app"
|
||||||
|
|
||||||
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
|
_ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client metric registration
|
||||||
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
|
_ "k8s.io/kubernetes/pkg/version/prometheus" // for version metric registration
|
||||||
)
|
)
|
||||||
|
@ -107,8 +109,11 @@ func kubelet(cfg *config.Agent) {
|
||||||
argsMap["runtime-cgroups"] = root
|
argsMap["runtime-cgroups"] = root
|
||||||
argsMap["kubelet-cgroups"] = root
|
argsMap["kubelet-cgroups"] = root
|
||||||
}
|
}
|
||||||
args := config.GetArgsList(argsMap, cfg.ExtraKubeletArgs)
|
if system.RunningInUserNS() {
|
||||||
|
argsMap["feature-gates"] = "DevicePlugins=false"
|
||||||
|
}
|
||||||
|
|
||||||
|
args := config.GetArgsList(argsMap, cfg.ExtraKubeletArgs)
|
||||||
command.SetArgs(args)
|
command.SetArgs(args)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
@ -15,8 +15,12 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func Resolve(dataDir string) (string, error) {
|
func Resolve(dataDir string) (string, error) {
|
||||||
|
return LocalHome(dataDir, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LocalHome(dataDir string, forceLocal bool) (string, error) {
|
||||||
if dataDir == "" {
|
if dataDir == "" {
|
||||||
if os.Getuid() == 0 {
|
if os.Getuid() == 0 && !forceLocal {
|
||||||
dataDir = DefaultDataDir
|
dataDir = DefaultDataDir
|
||||||
} else {
|
} else {
|
||||||
dataDir = DefaultHomeDataDir
|
dataDir = DefaultHomeDataDir
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
func Main() {
|
func Main() {
|
||||||
kubenv := os.Getenv("KUBECONFIG")
|
kubenv := os.Getenv("KUBECONFIG")
|
||||||
if kubenv == "" {
|
if kubenv == "" {
|
||||||
config, err := server.HomeKubeConfig(false)
|
config, err := server.HomeKubeConfig(false, false)
|
||||||
if _, serr := os.Stat(config); err == nil && serr == nil {
|
if _, serr := os.Stat(config); err == nil && serr == nil {
|
||||||
os.Setenv("KUBECONFIG", config)
|
os.Setenv("KUBECONFIG", config)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
package rootless
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupMounts(stateDir string) error {
|
||||||
|
mountMap := [][]string{
|
||||||
|
{"/run", ""},
|
||||||
|
{"/var/run", ""},
|
||||||
|
{"/var/log", filepath.Join(stateDir, "logs")},
|
||||||
|
{"/var/lib/cni", filepath.Join(stateDir, "cni")},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range mountMap {
|
||||||
|
if err := setupMount(v[0], v[1]); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to setup mount %s => %s", v[0], v[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupMount(target, dir string) error {
|
||||||
|
toCreate := target
|
||||||
|
for {
|
||||||
|
if toCreate == "/" {
|
||||||
|
return fmt.Errorf("missing /%s on the root filesystem", strings.Split(target, "/")[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(toCreate, 0700); err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
toCreate = filepath.Base(toCreate)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debug("Mounting none ", toCreate, " tmpfs")
|
||||||
|
if err := unix.Mount("none", toCreate, "tmpfs", 0, ""); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to mount tmpfs to %s", toCreate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(target, 0700); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to create directory %s")
|
||||||
|
}
|
||||||
|
|
||||||
|
if dir == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to create directory %s")
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debug("Mounting ", dir, target, " none bind")
|
||||||
|
return unix.Mount(dir, target, "none", unix.MS_BIND, "")
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
package rootless
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/rootless-containers/rootlesskit/pkg/child"
|
||||||
|
"github.com/rootless-containers/rootlesskit/pkg/copyup/tmpfssymlink"
|
||||||
|
"github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns"
|
||||||
|
"github.com/rootless-containers/rootlesskit/pkg/parent"
|
||||||
|
"github.com/rootless-containers/rootlesskit/pkg/port/socat"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
pipeFD = "_K3S_ROOTLESS_FD"
|
||||||
|
childEnv = "_K3S_ROOTLESS_SOCK"
|
||||||
|
Sock = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
func Rootless(stateDir string) error {
|
||||||
|
defer func() {
|
||||||
|
os.Unsetenv(pipeFD)
|
||||||
|
os.Unsetenv(childEnv)
|
||||||
|
}()
|
||||||
|
|
||||||
|
hasFD := os.Getenv(pipeFD) != ""
|
||||||
|
hasChildEnv := os.Getenv(childEnv) != ""
|
||||||
|
|
||||||
|
if hasFD {
|
||||||
|
logrus.Debug("Running rootless child")
|
||||||
|
childOpt, err := createChildOpt()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
if err := child.Child(*childOpt); err != nil {
|
||||||
|
logrus.Fatal("child died", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasChildEnv {
|
||||||
|
Sock = os.Getenv(childEnv)
|
||||||
|
logrus.Debug("Running rootless process")
|
||||||
|
return setupMounts(stateDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debug("Running rootless parent")
|
||||||
|
parentOpt, err := createParentOpt(filepath.Join(stateDir, "rootless"))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.Setenv(childEnv, filepath.Join(parentOpt.StateDir, parent.StateFileAPISock))
|
||||||
|
if err := parent.Parent(*parentOpt); err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCIDR(s string) (*net.IPNet, error) {
|
||||||
|
if s == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
ip, ipnet, err := net.ParseCIDR(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ip.Equal(ipnet.IP) {
|
||||||
|
return nil, errors.Errorf("cidr must be like 10.0.2.0/24, not like 10.0.2.100/24")
|
||||||
|
}
|
||||||
|
return ipnet, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createParentOpt(stateDir string) (*parent.Opt, error) {
|
||||||
|
if err := os.MkdirAll(stateDir, 0755); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to mkdir %s", stateDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
stateDir, err := ioutil.TempDir("", "rootless")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
opt := &parent.Opt{
|
||||||
|
StateDir: stateDir,
|
||||||
|
}
|
||||||
|
|
||||||
|
mtu := 0
|
||||||
|
ipnet, err := parseCIDR("10.41.0.0/16")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
disableHostLoopback := true
|
||||||
|
binary := "slirp4netns"
|
||||||
|
if _, err := exec.LookPath(binary); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
opt.NetworkDriver = slirp4netns.NewParentDriver(binary, mtu, ipnet, disableHostLoopback, "")
|
||||||
|
opt.PortDriver, err = socat.NewParentDriver(&logrusDebugWriter{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
opt.PipeFDEnvKey = pipeFD
|
||||||
|
|
||||||
|
return opt, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type logrusDebugWriter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *logrusDebugWriter) Write(p []byte) (int, error) {
|
||||||
|
s := strings.TrimSuffix(string(p), "\n")
|
||||||
|
logrus.Debug(s)
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createChildOpt() (*child.Opt, error) {
|
||||||
|
opt := &child.Opt{}
|
||||||
|
opt.TargetCmd = os.Args
|
||||||
|
opt.PipeFDEnvKey = pipeFD
|
||||||
|
opt.NetworkDriver = slirp4netns.NewChildDriver()
|
||||||
|
opt.CopyUpDirs = []string{"/etc", "/run"}
|
||||||
|
opt.CopyUpDriver = tmpfssymlink.NewChildDriver()
|
||||||
|
return opt, nil
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
package rootlessports
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rancher/k3s/pkg/rootless"
|
||||||
|
coreClients "github.com/rancher/k3s/types/apis/core/v1"
|
||||||
|
"github.com/rootless-containers/rootlesskit/pkg/api/client"
|
||||||
|
"github.com/rootless-containers/rootlesskit/pkg/port"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
all = "_all_"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Register(ctx context.Context, httpsPort int) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
rootlessClient client.Client
|
||||||
|
)
|
||||||
|
|
||||||
|
if rootless.Sock == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
coreClients := coreClients.ClientsFrom(ctx)
|
||||||
|
for i := 0; i < 30; i++ {
|
||||||
|
rootlessClient, err = client.New(rootless.Sock)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
logrus.Infof("waiting for rootless API socket %s: %v", rootless.Sock, err)
|
||||||
|
time.Sleep(1 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
h := &handler{
|
||||||
|
rootlessClient: rootlessClient,
|
||||||
|
serviceClient: coreClients.Service,
|
||||||
|
serviceCache: coreClients.Service.Cache(),
|
||||||
|
httpsPort: httpsPort,
|
||||||
|
ctx: ctx,
|
||||||
|
}
|
||||||
|
coreClients.Service.Interface().Controller().AddHandler(ctx, "rootlessports", h.serviceChanged)
|
||||||
|
coreClients.Service.Enqueue("", all)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type handler struct {
|
||||||
|
rootlessClient client.Client
|
||||||
|
serviceClient coreClients.ServiceClient
|
||||||
|
serviceCache coreClients.ServiceClientCache
|
||||||
|
httpsPort int
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) serviceChanged(key string, svc *v1.Service) (runtime.Object, error) {
|
||||||
|
if key != all {
|
||||||
|
h.serviceClient.Enqueue("", all)
|
||||||
|
return svc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ports, err := h.rootlessClient.PortManager().ListPorts(h.ctx)
|
||||||
|
if err != nil {
|
||||||
|
return svc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
boundPorts := map[int]int{}
|
||||||
|
for _, port := range ports {
|
||||||
|
boundPorts[port.Spec.ParentPort] = port.ID
|
||||||
|
}
|
||||||
|
|
||||||
|
toBindPort, err := h.toBindPorts()
|
||||||
|
if err != nil {
|
||||||
|
return svc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for bindPort, childBindPort := range toBindPort {
|
||||||
|
if _, ok := boundPorts[bindPort]; ok {
|
||||||
|
logrus.Debugf("Parent port %d to child already bound", bindPort)
|
||||||
|
delete(boundPorts, bindPort)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err := h.rootlessClient.PortManager().AddPort(h.ctx, port.Spec{
|
||||||
|
Proto: "tcp",
|
||||||
|
ParentPort: bindPort,
|
||||||
|
ChildPort: childBindPort,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return svc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Infof("Bound parent port %s:%d to child namespace port %d", status.Spec.ParentIP,
|
||||||
|
status.Spec.ParentPort, status.Spec.ChildPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
for bindPort, id := range boundPorts {
|
||||||
|
if err := h.rootlessClient.PortManager().RemovePort(h.ctx, id); err != nil {
|
||||||
|
return svc, err
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Infof("Removed parent port %d to child namespace", bindPort)
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) toBindPorts() (map[int]int, error) {
|
||||||
|
svcs, err := h.serviceCache.List("", labels.Everything())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
toBindPorts := map[int]int{
|
||||||
|
h.httpsPort: h.httpsPort,
|
||||||
|
}
|
||||||
|
for _, svc := range svcs {
|
||||||
|
for _, ingress := range svc.Status.LoadBalancer.Ingress {
|
||||||
|
if ingress.IP == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, port := range svc.Spec.Ports {
|
||||||
|
if port.Protocol != v1.ProtocolTCP {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if port.Port != 0 {
|
||||||
|
if port.Port <= 1024 {
|
||||||
|
toBindPorts[10000+int(port.Port)] = int(port.Port)
|
||||||
|
} else {
|
||||||
|
toBindPorts[int(port.Port)] = int(port.Port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return toBindPorts, nil
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/rancher/k3s/pkg/datadir"
|
"github.com/rancher/k3s/pkg/datadir"
|
||||||
"github.com/rancher/k3s/pkg/deploy"
|
"github.com/rancher/k3s/pkg/deploy"
|
||||||
"github.com/rancher/k3s/pkg/helm"
|
"github.com/rancher/k3s/pkg/helm"
|
||||||
|
"github.com/rancher/k3s/pkg/rootlessports"
|
||||||
"github.com/rancher/k3s/pkg/servicelb"
|
"github.com/rancher/k3s/pkg/servicelb"
|
||||||
"github.com/rancher/k3s/pkg/static"
|
"github.com/rancher/k3s/pkg/static"
|
||||||
"github.com/rancher/k3s/pkg/tls"
|
"github.com/rancher/k3s/pkg/tls"
|
||||||
|
@ -36,16 +37,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func resolveDataDir(dataDir string) (string, error) {
|
func resolveDataDir(dataDir string) (string, error) {
|
||||||
if dataDir == "" {
|
dataDir, err := datadir.Resolve(dataDir)
|
||||||
if os.Getuid() == 0 {
|
return filepath.Join(dataDir, "server"), err
|
||||||
dataDir = "/var/lib/rancher/k3s"
|
|
||||||
} else {
|
|
||||||
dataDir = "${HOME}/.rancher/k3s"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dataDir = filepath.Join(dataDir, "server")
|
|
||||||
return resolvehome.Resolve(dataDir)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartServer(ctx context.Context, config *Config) (string, error) {
|
func StartServer(ctx context.Context, config *Config) (string, error) {
|
||||||
|
@ -72,7 +65,7 @@ func StartServer(ctx context.Context, config *Config) (string, error) {
|
||||||
}
|
}
|
||||||
printTokens(certs, ip.String(), &config.TLSConfig, &config.ControlConfig)
|
printTokens(certs, ip.String(), &config.TLSConfig, &config.ControlConfig)
|
||||||
|
|
||||||
writeKubeConfig(certs, &config.TLSConfig, &config.ControlConfig)
|
writeKubeConfig(certs, &config.TLSConfig, config)
|
||||||
|
|
||||||
return certs, nil
|
return certs, nil
|
||||||
}
|
}
|
||||||
|
@ -121,7 +114,8 @@ func startNorman(ctx context.Context, config *Config) (string, error) {
|
||||||
MasterControllers: []norman.ControllerRegister{
|
MasterControllers: []norman.ControllerRegister{
|
||||||
helm.Register,
|
helm.Register,
|
||||||
func(ctx context.Context) error {
|
func(ctx context.Context) error {
|
||||||
return servicelb.Register(ctx, norman.GetServer(ctx).K8sClient, !config.DisableServiceLB)
|
return servicelb.Register(ctx, norman.GetServer(ctx).K8sClient, !config.DisableServiceLB,
|
||||||
|
config.Rootless)
|
||||||
},
|
},
|
||||||
func(ctx context.Context) error {
|
func(ctx context.Context) error {
|
||||||
dataDir := filepath.Join(controlConfig.DataDir, "static")
|
dataDir := filepath.Join(controlConfig.DataDir, "static")
|
||||||
|
@ -138,6 +132,12 @@ func startNorman(ctx context.Context, config *Config) (string, error) {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
func(ctx context.Context) error {
|
||||||
|
if !config.DisableServiceLB && config.Rootless {
|
||||||
|
return rootlessports.Register(ctx, config.TLSConfig.HTTPSPort)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,9 +156,9 @@ func startNorman(ctx context.Context, config *Config) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func HomeKubeConfig(write bool) (string, error) {
|
func HomeKubeConfig(write, rootless bool) (string, error) {
|
||||||
if write {
|
if write {
|
||||||
if os.Getuid() == 0 {
|
if os.Getuid() == 0 && !rootless {
|
||||||
return datadir.GlobalConfig, nil
|
return datadir.GlobalConfig, nil
|
||||||
}
|
}
|
||||||
return resolvehome.Resolve(datadir.HomeConfig)
|
return resolvehome.Resolve(datadir.HomeConfig)
|
||||||
|
@ -194,30 +194,30 @@ func printTokens(certs, advertiseIP string, tlsConfig *dynamiclistener.UserConfi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeKubeConfig(certs string, tlsConfig *dynamiclistener.UserConfig, config *config.Control) {
|
func writeKubeConfig(certs string, tlsConfig *dynamiclistener.UserConfig, config *Config) {
|
||||||
clientToken := FormatToken(config.Runtime.ClientToken, certs)
|
clientToken := FormatToken(config.ControlConfig.Runtime.ClientToken, certs)
|
||||||
ip := tlsConfig.BindAddress
|
ip := tlsConfig.BindAddress
|
||||||
if ip == "" {
|
if ip == "" {
|
||||||
ip = "localhost"
|
ip = "localhost"
|
||||||
}
|
}
|
||||||
url := fmt.Sprintf("https://%s:%d", ip, tlsConfig.HTTPSPort)
|
url := fmt.Sprintf("https://%s:%d", ip, tlsConfig.HTTPSPort)
|
||||||
kubeConfig, err := HomeKubeConfig(true)
|
kubeConfig, err := HomeKubeConfig(true, config.Rootless)
|
||||||
def := true
|
def := true
|
||||||
if err != nil {
|
if err != nil {
|
||||||
kubeConfig = filepath.Join(config.DataDir, "kubeconfig-k3s.yaml")
|
kubeConfig = filepath.Join(config.ControlConfig.DataDir, "kubeconfig-k3s.yaml")
|
||||||
def = false
|
def = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.KubeConfigOutput != "" {
|
if config.ControlConfig.KubeConfigOutput != "" {
|
||||||
kubeConfig = config.KubeConfigOutput
|
kubeConfig = config.ControlConfig.KubeConfigOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = clientaccess.AgentAccessInfoToKubeConfig(kubeConfig, url, clientToken); err != nil {
|
if err = clientaccess.AgentAccessInfoToKubeConfig(kubeConfig, url, clientToken); err != nil {
|
||||||
logrus.Errorf("Failed to generate kubeconfig: %v", err)
|
logrus.Errorf("Failed to generate kubeconfig: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.KubeConfigMode != "" {
|
if config.ControlConfig.KubeConfigMode != "" {
|
||||||
mode, err := strconv.ParseInt(config.KubeConfigMode, 8, 0)
|
mode, err := strconv.ParseInt(config.ControlConfig.KubeConfigMode, 8, 0)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
os.Chmod(kubeConfig, os.FileMode(mode))
|
os.Chmod(kubeConfig, os.FileMode(mode))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -10,4 +10,5 @@ type Config struct {
|
||||||
DisableServiceLB bool
|
DisableServiceLB bool
|
||||||
TLSConfig dynamiclistener.UserConfig
|
TLSConfig dynamiclistener.UserConfig
|
||||||
ControlConfig config.Control
|
ControlConfig config.Control
|
||||||
|
Rootless bool
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,11 +34,12 @@ var (
|
||||||
trueVal = true
|
trueVal = true
|
||||||
)
|
)
|
||||||
|
|
||||||
func Register(ctx context.Context, kubernetes kubernetes.Interface, enabled bool) error {
|
func Register(ctx context.Context, kubernetes kubernetes.Interface, enabled, rootless bool) error {
|
||||||
clients := coreclient.ClientsFrom(ctx)
|
clients := coreclient.ClientsFrom(ctx)
|
||||||
appClients := appclient.ClientsFrom(ctx)
|
appClients := appclient.ClientsFrom(ctx)
|
||||||
|
|
||||||
h := &handler{
|
h := &handler{
|
||||||
|
rootless: rootless,
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
nodeCache: clients.Node.Cache(),
|
nodeCache: clients.Node.Cache(),
|
||||||
podCache: clients.Pod.Cache(),
|
podCache: clients.Pod.Cache(),
|
||||||
|
@ -59,6 +60,7 @@ func Register(ctx context.Context, kubernetes kubernetes.Interface, enabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
|
rootless bool
|
||||||
enabled bool
|
enabled bool
|
||||||
nodeCache coreclient.NodeClientCache
|
nodeCache coreclient.NodeClientCache
|
||||||
podCache coreclient.PodClientCache
|
podCache coreclient.PodClientCache
|
||||||
|
@ -189,6 +191,11 @@ func (h *handler) podIPs(pods []*core.Pod) ([]string, error) {
|
||||||
for k := range ips {
|
for k := range ips {
|
||||||
ipList = append(ipList, k)
|
ipList = append(ipList, k)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(ipList) > 0 && h.rootless {
|
||||||
|
return []string{"127.0.0.1"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
return ipList, nil
|
return ipList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,9 @@ mkdir -p $(dirname $0)/../bin
|
||||||
cd $(dirname $0)/../bin
|
cd $(dirname $0)/../bin
|
||||||
|
|
||||||
echo Running
|
echo Running
|
||||||
go run -tags "apparmor" ../main.go --debug server --disable-agent "$@"
|
ARGS="--disable-agent"
|
||||||
|
if echo -- "$@" | grep -q rootless; then
|
||||||
|
ARGS=""
|
||||||
|
PATH=$(pwd):$PATH
|
||||||
|
fi
|
||||||
|
go run -tags "apparmor" ../main.go server $ARGS "$@"
|
||||||
|
|
|
@ -4,7 +4,7 @@ source $(dirname $0)/version.sh
|
||||||
|
|
||||||
cd $(dirname $0)/..
|
cd $(dirname $0)/..
|
||||||
|
|
||||||
ROOT_VERSION=v0.0.1
|
ROOT_VERSION=v0.1.1
|
||||||
TRAEFIK_VERSION=1.64.0
|
TRAEFIK_VERSION=1.64.0
|
||||||
CHARTS_DIR=build/static/charts
|
CHARTS_DIR=build/static/charts
|
||||||
|
|
||||||
|
|
261
trash.lock
261
trash.lock
|
@ -22,7 +22,8 @@ import:
|
||||||
- package: github.com/containerd/continuity
|
- package: github.com/containerd/continuity
|
||||||
version: bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
|
version: bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
|
||||||
- package: github.com/containerd/cri
|
- package: github.com/containerd/cri
|
||||||
version: eb926cd79d3bac188dcc4ed7694fc9298f8831be
|
version: v1.2-k3s.2
|
||||||
|
repo: https://github.com/rancher/cri.git
|
||||||
- package: github.com/containerd/fifo
|
- package: github.com/containerd/fifo
|
||||||
version: 3d5202aec260678c48179c56f40e6f38a095738c
|
version: 3d5202aec260678c48179c56f40e6f38a095738c
|
||||||
- package: github.com/containerd/go-cni
|
- package: github.com/containerd/go-cni
|
||||||
|
@ -49,6 +50,8 @@ import:
|
||||||
version: v1.1.0
|
version: v1.1.0
|
||||||
- package: github.com/docker/distribution
|
- package: github.com/docker/distribution
|
||||||
version: 0d3efadf0154c2b8a4e7b6621fff9809655cc580
|
version: 0d3efadf0154c2b8a4e7b6621fff9809655cc580
|
||||||
|
- package: github.com/docker/docker
|
||||||
|
version: c12f09bf99b54f274a5ae241dd154fa74020cbab
|
||||||
- package: github.com/docker/go-events
|
- package: github.com/docker/go-events
|
||||||
version: 9461782956ad83b30282bf90e31fa6a70c255ba9
|
version: 9461782956ad83b30282bf90e31fa6a70c255ba9
|
||||||
- package: github.com/docker/go-metrics
|
- package: github.com/docker/go-metrics
|
||||||
|
@ -94,6 +97,8 @@ import:
|
||||||
version: 1.0.3
|
version: 1.0.3
|
||||||
- package: github.com/modern-go/reflect2
|
- package: github.com/modern-go/reflect2
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
|
- package: github.com/morikuni/aec
|
||||||
|
version: 39771216ff4c63d11f5e604076f9c45e8be1067b
|
||||||
- package: github.com/natefinch/lumberjack
|
- package: github.com/natefinch/lumberjack
|
||||||
version: aee4629129445bbdfb69aa565537dcfa16544311
|
version: aee4629129445bbdfb69aa565537dcfa16544311
|
||||||
- package: github.com/opencontainers/go-digest
|
- package: github.com/opencontainers/go-digest
|
||||||
|
@ -113,6 +118,8 @@ import:
|
||||||
- package: github.com/rancher/norman
|
- package: github.com/rancher/norman
|
||||||
version: 50017efee23caa79542ef685b65a7b783e0a73ca
|
version: 50017efee23caa79542ef685b65a7b783e0a73ca
|
||||||
repo: https://github.com/ibuildthecloud/norman.git
|
repo: https://github.com/ibuildthecloud/norman.git
|
||||||
|
- package: github.com/rootless-containers/rootlesskit
|
||||||
|
version: 893c1c3de71f54c301fdb85a7c0dd15c1933c159
|
||||||
- package: github.com/seccomp/libseccomp-golang
|
- package: github.com/seccomp/libseccomp-golang
|
||||||
version: 32f571b70023028bd57d9288c20efbcb237f3ce0
|
version: 32f571b70023028bd57d9288c20efbcb237f3ce0
|
||||||
- package: github.com/sirupsen/logrus
|
- package: github.com/sirupsen/logrus
|
||||||
|
@ -121,6 +128,8 @@ import:
|
||||||
version: db04d3cc01c8b54962a58ec7e491717d06cfcc16
|
version: db04d3cc01c8b54962a58ec7e491717d06cfcc16
|
||||||
- package: github.com/tchap/go-patricia
|
- package: github.com/tchap/go-patricia
|
||||||
version: v2.2.6
|
version: v2.2.6
|
||||||
|
- package: github.com/theckman/go-flock
|
||||||
|
version: v0.7.1
|
||||||
- package: github.com/urfave/cli
|
- package: github.com/urfave/cli
|
||||||
version: 8e01ec4cd3e2d84ab2fe90d8210528ffbb06d8ff
|
version: 8e01ec4cd3e2d84ab2fe90d8210528ffbb06d8ff
|
||||||
- package: github.com/xeipuuv/gojsonpointer
|
- package: github.com/xeipuuv/gojsonpointer
|
||||||
|
@ -155,148 +164,144 @@ import:
|
||||||
- package: gopkg.in/yaml.v2
|
- package: gopkg.in/yaml.v2
|
||||||
version: v2.2.1
|
version: v2.2.1
|
||||||
- package: k8s.io/kubernetes
|
- package: k8s.io/kubernetes
|
||||||
version: v1.14.1-k3s.1
|
version: v1.14.1-k3s.2
|
||||||
repo: https://github.com/rancher/k3s.git
|
repo: https://github.com/rancher/k3s.git
|
||||||
transitive: true
|
transitive: true
|
||||||
staging: true
|
staging: true
|
||||||
- package: vbom.ml/util
|
- package: github.com/prometheus/client_model
|
||||||
version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394
|
version: model-0.0.2-12-gfa8ad6fec33561
|
||||||
- package: github.com/mxk/go-flowrate
|
|
||||||
version: cca7078d478f8520f85629ad7c68962d31ed7682
|
|
||||||
- package: github.com/ugorji/go
|
|
||||||
version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57
|
|
||||||
- package: github.com/sigma/go-inotify
|
|
||||||
version: c87b6cf5033d2c6486046f045eeebdc3d910fd38
|
|
||||||
- package: github.com/spf13/cobra
|
|
||||||
version: v0.0.1-34-gc439c4fa093711
|
|
||||||
- package: github.com/liggitt/tabwriter
|
|
||||||
version: 89fcab3d43de07060e4fd4c1547430ed57e87f24
|
|
||||||
- package: github.com/mindprince/gonvml
|
|
||||||
version: fee913ce8fb235edf54739d259ca0ecc226c7b8a
|
|
||||||
- package: github.com/mistifyio/go-zfs
|
|
||||||
version: v2.1.1-5-g1b4ae6fb4e77b0
|
|
||||||
- package: github.com/peterbourgon/diskv
|
|
||||||
version: v2.0.1
|
|
||||||
- package: github.com/russross/blackfriday
|
|
||||||
version: v1.4-2-g300106c228d52c
|
|
||||||
- package: github.com/inconshreveable/mousetrap
|
|
||||||
version: v1.0
|
|
||||||
- package: github.com/imdario/mergo
|
- package: github.com/imdario/mergo
|
||||||
version: v0.3.5
|
version: v0.3.5
|
||||||
- package: github.com/vishvananda/netns
|
- package: github.com/fsnotify/fsnotify
|
||||||
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
|
version: v1.3.1-1-gf12c6236fe7b5c
|
||||||
- package: github.com/prometheus/client_golang
|
- package: github.com/cloudflare/cfssl
|
||||||
version: v0.9.2
|
version: 1.3.2-21-g56268a613adfed
|
||||||
- package: github.com/mattn/go-shellwords
|
- package: github.com/spf13/cobra
|
||||||
version: v1.0.3-20-gf8471b0a71ded0
|
version: v0.0.1-34-gc439c4fa093711
|
||||||
- package: github.com/prometheus/procfs
|
|
||||||
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
|
|
||||||
- package: github.com/vishvananda/netlink
|
- package: github.com/vishvananda/netlink
|
||||||
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
|
version: b2de5d10e38ecce8607e6b438b6d174f389a004e
|
||||||
- package: github.com/chai2010/gettext-go
|
- package: github.com/google/certificate-transparency-go
|
||||||
version: c6fed771bfd517099caf0f7a961671fa8ed08723
|
version: v1.0.21
|
||||||
- package: github.com/container-storage-interface/spec
|
- package: github.com/coreos/pkg
|
||||||
version: v1.1.0
|
version: v4
|
||||||
- package: github.com/hashicorp/golang-lru
|
- package: vbom.ml/util
|
||||||
version: v0.5.0
|
version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394
|
||||||
- package: github.com/spf13/pflag
|
- package: github.com/miekg/dns
|
||||||
version: v1.0.1
|
version: 5d001d020961ae1c184f9f8152fdc73810481677
|
||||||
|
- package: github.com/munnerz/goautoneg
|
||||||
|
version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d
|
||||||
|
- package: github.com/google/btree
|
||||||
|
version: 7d79101e329e5a3adf994758c578dab82b90c017
|
||||||
|
- package: github.com/karrick/godirwalk
|
||||||
|
version: v1.7.5
|
||||||
|
- package: github.com/coreos/etcd
|
||||||
|
version: v3.3.10
|
||||||
|
- package: github.com/gregjones/httpcache
|
||||||
|
version: 787624de3eb7bd915c329cba748687a3b22666a6
|
||||||
|
- package: github.com/armon/circbuf
|
||||||
|
version: bbbad097214e2918d8543d5201d12bfd7bca254d
|
||||||
|
- package: github.com/docker/libnetwork
|
||||||
|
version: v0.8.0-dev.2-1265-ga9cd636e378982
|
||||||
|
- package: github.com/jonboulle/clockwork
|
||||||
|
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
|
||||||
|
- package: k8s.io/gengo
|
||||||
|
version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95
|
||||||
|
- package: github.com/JeffAshton/win_pdh
|
||||||
|
version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2
|
||||||
|
- package: github.com/robfig/cron
|
||||||
|
version: v1-53-gdf38d32658d878
|
||||||
- package: github.com/shurcooL/sanitized_anchor_name
|
- package: github.com/shurcooL/sanitized_anchor_name
|
||||||
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
|
version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
|
||||||
- package: github.com/MakeNowJust/heredoc
|
- package: github.com/ugorji/go
|
||||||
version: bb23615498cded5e105af4ce27de75b089cbe851
|
version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57
|
||||||
|
- package: github.com/fatih/camelcase
|
||||||
|
version: f6a740d52f961c60348ebb109adde9f4635d7540
|
||||||
|
- package: github.com/hashicorp/golang-lru
|
||||||
|
version: v0.5.0
|
||||||
- package: github.com/prometheus/common
|
- package: github.com/prometheus/common
|
||||||
version: v0.2.0
|
version: v0.2.0
|
||||||
- package: github.com/coreos/go-semver
|
- package: github.com/sigma/go-inotify
|
||||||
version: v0.2.0-9-ge214231b295a8e
|
version: c87b6cf5033d2c6486046f045eeebdc3d910fd38
|
||||||
|
- package: sigs.k8s.io/yaml
|
||||||
|
version: v1.1.0
|
||||||
|
- package: k8s.io/heapster
|
||||||
|
version: v1.2.0-beta.1
|
||||||
|
- package: github.com/golang/groupcache
|
||||||
|
version: 02826c3e79038b59d737d3b1c0a1d937f71a4433
|
||||||
|
- package: gopkg.in/square/go-jose.v2
|
||||||
|
version: v2.1.6-4-g89060dee6a84df
|
||||||
|
- package: github.com/Azure/go-ansiterm
|
||||||
|
version: d6e3b3328b783f23731bc4d058875b0371ff8109
|
||||||
|
- package: github.com/mattn/go-shellwords
|
||||||
|
version: v1.0.3-20-gf8471b0a71ded0
|
||||||
|
- package: github.com/prometheus/client_golang
|
||||||
|
version: v0.9.2
|
||||||
|
- package: github.com/docker/go-units
|
||||||
|
version: v0.3.1-11-g9e638d38cf6977
|
||||||
|
- package: github.com/chai2010/gettext-go
|
||||||
|
version: c6fed771bfd517099caf0f7a961671fa8ed08723
|
||||||
|
- package: github.com/daviddengcn/go-colortext
|
||||||
|
version: 511bcaf42ccd42c38aba7427b6673277bf19e2a1
|
||||||
|
- package: github.com/vishvananda/netns
|
||||||
|
version: be1fbeda19366dea804f00efff2dd73a1642fdcc
|
||||||
|
- package: github.com/docker/go-connections
|
||||||
|
version: v0.3.0
|
||||||
|
- package: gopkg.in/natefinch/lumberjack.v2
|
||||||
|
version: v1.0-16-g20b71e5b60d756
|
||||||
|
- package: github.com/russross/blackfriday
|
||||||
|
version: v1.4-2-g300106c228d52c
|
||||||
- package: github.com/google/cadvisor
|
- package: github.com/google/cadvisor
|
||||||
version: v0.33.1-k3s.1
|
version: v0.33.1-k3s.1
|
||||||
repo: https://github.com/ibuildthecloud/cadvisor.git
|
repo: https://github.com/ibuildthecloud/cadvisor.git
|
||||||
- package: github.com/cyphar/filepath-securejoin
|
- package: github.com/spf13/pflag
|
||||||
version: v0.2.1-1-gae69057f2299fb
|
version: v1.0.1
|
||||||
- package: github.com/ibuildthecloud/kvsql
|
- package: github.com/mistifyio/go-zfs
|
||||||
version: 0e798b1475327aadf3b8da5d2d1f99bb93dfd667
|
version: v2.1.1-5-g1b4ae6fb4e77b0
|
||||||
- package: github.com/JeffAshton/win_pdh
|
|
||||||
version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2
|
|
||||||
- package: github.com/prometheus/client_model
|
|
||||||
version: model-0.0.2-12-gfa8ad6fec33561
|
|
||||||
- package: github.com/miekg/dns
|
|
||||||
version: 5d001d020961ae1c184f9f8152fdc73810481677
|
|
||||||
- package: github.com/daviddengcn/go-colortext
|
|
||||||
version: 511bcaf42ccd42c38aba7427b6673277bf19e2a1
|
|
||||||
- package: github.com/gregjones/httpcache
|
|
||||||
version: 787624de3eb7bd915c329cba748687a3b22666a6
|
|
||||||
- package: github.com/karrick/godirwalk
|
|
||||||
version: v1.7.5
|
|
||||||
- package: k8s.io/gengo
|
|
||||||
version: 51747d6e00da1fc578d5a333a93bb2abcbce7a95
|
|
||||||
- package: k8s.io/heapster
|
|
||||||
version: v1.2.0-beta.1
|
|
||||||
- package: github.com/checkpoint-restore/go-criu
|
|
||||||
version: v3.11
|
|
||||||
- package: github.com/google/btree
|
|
||||||
version: 7d79101e329e5a3adf994758c578dab82b90c017
|
|
||||||
- package: github.com/google/certificate-transparency-go
|
|
||||||
version: v1.0.21
|
|
||||||
- package: github.com/robfig/cron
|
|
||||||
version: v1-53-gdf38d32658d878
|
|
||||||
- package: github.com/mrunalp/fileutils
|
|
||||||
version: 4ee1cc9a80582a0c75febdd5cfa779ee4361cbca
|
|
||||||
- package: github.com/Nvveen/Gotty
|
|
||||||
version: cd527374f1e5bff4938207604a14f2e38a9cf512
|
|
||||||
- package: github.com/exponent-io/jsonpath
|
|
||||||
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5
|
|
||||||
- package: github.com/fsnotify/fsnotify
|
|
||||||
version: v1.3.1-1-gf12c6236fe7b5c
|
|
||||||
- package: github.com/jteeuwen/go-bindata
|
|
||||||
version: v3.0.7-72-ga0ff2567cfb709
|
|
||||||
- package: gopkg.in/square/go-jose.v2
|
|
||||||
version: v2.1.6-4-g89060dee6a84df
|
|
||||||
- package: k8s.io/klog
|
|
||||||
version: v0.2.0-14-g8e90cee79f8237
|
|
||||||
- package: github.com/munnerz/goautoneg
|
|
||||||
version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d
|
|
||||||
- package: github.com/docker/go-units
|
|
||||||
version: v0.3.1-11-g9e638d38cf6977
|
|
||||||
- package: github.com/fatih/camelcase
|
|
||||||
version: f6a740d52f961c60348ebb109adde9f4635d7540
|
|
||||||
- package: k8s.io/utils
|
|
||||||
version: c2654d5206da6b7b6ace12841e8f359bb89b443c
|
|
||||||
- package: github.com/coreos/etcd
|
|
||||||
version: v3.3.10
|
|
||||||
- package: github.com/docker/go-connections
|
|
||||||
version: v0.3.0
|
|
||||||
- package: github.com/golang/groupcache
|
|
||||||
version: 02826c3e79038b59d737d3b1c0a1d937f71a4433
|
|
||||||
- package: gopkg.in/natefinch/lumberjack.v2
|
|
||||||
version: v1.0-16-g20b71e5b60d756
|
|
||||||
- package: github.com/mitchellh/go-wordwrap
|
- package: github.com/mitchellh/go-wordwrap
|
||||||
version: ad45545899c7b13c020ea92b2072220eefad42b8
|
version: ad45545899c7b13c020ea92b2072220eefad42b8
|
||||||
- package: github.com/docker/libnetwork
|
- package: github.com/ibuildthecloud/kvsql
|
||||||
version: v0.8.0-dev.2-1265-ga9cd636e378982
|
version: 0e798b1475327aadf3b8da5d2d1f99bb93dfd667
|
||||||
- package: sigs.k8s.io/yaml
|
|
||||||
version: v1.1.0
|
|
||||||
- package: github.com/euank/go-kmsg-parser
|
|
||||||
version: v2.0.0
|
|
||||||
- package: github.com/evanphx/json-patch
|
|
||||||
version: v4.1.0-19-g5858425f75500d
|
|
||||||
- package: github.com/lithammer/dedent
|
|
||||||
version: v1.1.0
|
|
||||||
- package: github.com/jonboulle/clockwork
|
|
||||||
version: 72f9bd7c4e0c2a40055ab3d0f09654f730cce982
|
|
||||||
- package: github.com/cloudflare/cfssl
|
|
||||||
version: 1.3.2-21-g56268a613adfed
|
|
||||||
- package: github.com/docker/docker
|
|
||||||
version: docs-v1.12.0-rc4-2016-07-15-9510-ga9fbbdc8dd8794
|
|
||||||
- package: github.com/coreos/pkg
|
|
||||||
version: v4
|
|
||||||
- package: github.com/Azure/go-ansiterm
|
|
||||||
version: d6e3b3328b783f23731bc4d058875b0371ff8109
|
|
||||||
- package: github.com/armon/circbuf
|
|
||||||
version: bbbad097214e2918d8543d5201d12bfd7bca254d
|
|
||||||
- package: golang.org/x/tools
|
|
||||||
version: 7f7074d5bcfd282eb16bc382b0bb3da762461985
|
|
||||||
- package: github.com/pborman/uuid
|
|
||||||
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
|
|
||||||
- package: github.com/googleapis/gnostic
|
- package: github.com/googleapis/gnostic
|
||||||
version: 0c5108395e2debce0d731cf0287ddf7242066aba
|
version: 0c5108395e2debce0d731cf0287ddf7242066aba
|
||||||
|
- package: github.com/inconshreveable/mousetrap
|
||||||
|
version: v1.0
|
||||||
|
- package: github.com/container-storage-interface/spec
|
||||||
|
version: v1.1.0
|
||||||
|
- package: github.com/cyphar/filepath-securejoin
|
||||||
|
version: v0.2.1-1-gae69057f2299fb
|
||||||
|
- package: github.com/mrunalp/fileutils
|
||||||
|
version: 4ee1cc9a80582a0c75febdd5cfa779ee4361cbca
|
||||||
|
- package: github.com/lithammer/dedent
|
||||||
|
version: v1.1.0
|
||||||
|
- package: github.com/mxk/go-flowrate
|
||||||
|
version: cca7078d478f8520f85629ad7c68962d31ed7682
|
||||||
|
- package: github.com/peterbourgon/diskv
|
||||||
|
version: v2.0.1
|
||||||
|
- package: github.com/prometheus/procfs
|
||||||
|
version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259
|
||||||
|
- package: github.com/jteeuwen/go-bindata
|
||||||
|
version: v3.0.7-72-ga0ff2567cfb709
|
||||||
|
- package: github.com/pborman/uuid
|
||||||
|
version: ca53cad383cad2479bbba7f7a1a05797ec1386e4
|
||||||
|
- package: github.com/checkpoint-restore/go-criu
|
||||||
|
version: v3.11
|
||||||
|
- package: github.com/MakeNowJust/heredoc
|
||||||
|
version: bb23615498cded5e105af4ce27de75b089cbe851
|
||||||
|
- package: github.com/liggitt/tabwriter
|
||||||
|
version: 89fcab3d43de07060e4fd4c1547430ed57e87f24
|
||||||
|
- package: github.com/exponent-io/jsonpath
|
||||||
|
version: d6023ce2651d8eafb5c75bb0c7167536102ec9f5
|
||||||
|
- package: golang.org/x/tools
|
||||||
|
version: 7f7074d5bcfd282eb16bc382b0bb3da762461985
|
||||||
|
- package: github.com/evanphx/json-patch
|
||||||
|
version: v4.1.0-19-g5858425f75500d
|
||||||
|
- package: github.com/mindprince/gonvml
|
||||||
|
version: fee913ce8fb235edf54739d259ca0ecc226c7b8a
|
||||||
|
- package: k8s.io/klog
|
||||||
|
version: v0.2.0-14-g8e90cee79f8237
|
||||||
|
- package: github.com/coreos/go-semver
|
||||||
|
version: v0.2.0-9-ge214231b295a8e
|
||||||
|
- package: github.com/euank/go-kmsg-parser
|
||||||
|
version: v2.0.0
|
||||||
|
- package: k8s.io/utils
|
||||||
|
version: c2654d5206da6b7b6ace12841e8f359bb89b443c
|
||||||
|
|
12
vendor.conf
12
vendor.conf
|
@ -9,7 +9,7 @@ package=github.com/opencontainers/runc/libcontainer/nsenter
|
||||||
package=github.com/opencontainers/runc/libcontainer/specconv
|
package=github.com/opencontainers/runc/libcontainer/specconv
|
||||||
package=github.com/opencontainers/runc/contrib/cmd/recvtty
|
package=github.com/opencontainers/runc/contrib/cmd/recvtty
|
||||||
|
|
||||||
k8s.io/kubernetes v1.14.1-k3s.1 https://github.com/rancher/k3s.git transitive=true,staging=true
|
k8s.io/kubernetes v1.14.1-k3s.2 https://github.com/rancher/k3s.git transitive=true,staging=true
|
||||||
|
|
||||||
github.com/rancher/norman 50017efee23caa79542ef685b65a7b783e0a73ca https://github.com/ibuildthecloud/norman.git
|
github.com/rancher/norman 50017efee23caa79542ef685b65a7b783e0a73ca https://github.com/ibuildthecloud/norman.git
|
||||||
github.com/coreos/flannel 823afe66b2266bf71f5bec24e6e28b26d70cfc7c https://github.com/ibuildthecloud/flannel.git
|
github.com/coreos/flannel 823afe66b2266bf71f5bec24e6e28b26d70cfc7c https://github.com/ibuildthecloud/flannel.git
|
||||||
|
@ -85,14 +85,14 @@ go.etcd.io/bbolt v1.3.1-etcd.8
|
||||||
github.com/kubernetes-sigs/cri-tools c465773e3ad8c941d1756c0a467d550b04a8f65b https://github.com/ibuildthecloud/cri-tools.git
|
github.com/kubernetes-sigs/cri-tools c465773e3ad8c941d1756c0a467d550b04a8f65b https://github.com/ibuildthecloud/cri-tools.git
|
||||||
|
|
||||||
# cri dependencies
|
# cri dependencies
|
||||||
github.com/containerd/cri eb926cd79d3bac188dcc4ed7694fc9298f8831be # release/1.2 branch
|
github.com/containerd/cri v1.2-k3s.2 https://github.com/rancher/cri.git
|
||||||
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
|
github.com/containerd/go-cni 40bcf8ec8acd7372be1d77031d585d5d8e561c90
|
||||||
github.com/blang/semver v3.1.0
|
github.com/blang/semver v3.1.0
|
||||||
github.com/containernetworking/cni v0.6.0
|
github.com/containernetworking/cni v0.6.0
|
||||||
#github.com/containernetworking/plugins v0.7.5
|
#github.com/containernetworking/plugins v0.7.5
|
||||||
github.com/davecgh/go-spew v1.1.0
|
github.com/davecgh/go-spew v1.1.0
|
||||||
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
|
github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580
|
||||||
#github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00
|
github.com/docker/docker c12f09bf99b54f274a5ae241dd154fa74020cbab
|
||||||
github.com/docker/spdystream 449fdfce4d962303d702fec724ef0ad181c92528
|
github.com/docker/spdystream 449fdfce4d962303d702fec724ef0ad181c92528
|
||||||
github.com/emicklei/go-restful v2.2.1
|
github.com/emicklei/go-restful v2.2.1
|
||||||
github.com/ghodss/yaml v1.0.0
|
github.com/ghodss/yaml v1.0.0
|
||||||
|
@ -115,3 +115,9 @@ golang.org/x/oauth2 a6bd8cefa1811bd24b86f8902872e4e8225f74c4
|
||||||
golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631
|
golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631
|
||||||
gopkg.in/inf.v0 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
|
gopkg.in/inf.v0 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4
|
||||||
gopkg.in/yaml.v2 v2.2.1
|
gopkg.in/yaml.v2 v2.2.1
|
||||||
|
|
||||||
|
# rootless
|
||||||
|
github.com/rootless-containers/rootlesskit 893c1c3de71f54c301fdb85a7c0dd15c1933c159
|
||||||
|
github.com/theckman/go-flock v0.7.1
|
||||||
|
|
||||||
|
github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
Copyright (c) 2012, Neal van Veen (nealvanveen@gmail.com)
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
The views and conclusions contained in the software and documentation are those
|
|
||||||
of the authors and should not be interpreted as representing official policies,
|
|
||||||
either expressed or implied, of the FreeBSD Project.
|
|
|
@ -1,5 +0,0 @@
|
||||||
Gotty is a library written in Go that determines and reads termcap database
|
|
||||||
files to produce an interface for interacting with the capabilities of a
|
|
||||||
terminal.
|
|
||||||
See the godoc documentation or the source code for more information about
|
|
||||||
function usage.
|
|
|
@ -1,3 +0,0 @@
|
||||||
gotty.go:// TODO add more concurrency to name lookup, look for more opportunities.
|
|
||||||
all:// TODO add more documentation, with function usage in a doc.go file.
|
|
||||||
all:// TODO add more testing/benchmarking with go test.
|
|
|
@ -1,514 +0,0 @@
|
||||||
// Copyright 2012 Neal van Veen. All rights reserved.
|
|
||||||
// Usage of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
package gotty
|
|
||||||
|
|
||||||
// Boolean capabilities
|
|
||||||
var BoolAttr = [...]string{
|
|
||||||
"auto_left_margin", "bw",
|
|
||||||
"auto_right_margin", "am",
|
|
||||||
"no_esc_ctlc", "xsb",
|
|
||||||
"ceol_standout_glitch", "xhp",
|
|
||||||
"eat_newline_glitch", "xenl",
|
|
||||||
"erase_overstrike", "eo",
|
|
||||||
"generic_type", "gn",
|
|
||||||
"hard_copy", "hc",
|
|
||||||
"has_meta_key", "km",
|
|
||||||
"has_status_line", "hs",
|
|
||||||
"insert_null_glitch", "in",
|
|
||||||
"memory_above", "da",
|
|
||||||
"memory_below", "db",
|
|
||||||
"move_insert_mode", "mir",
|
|
||||||
"move_standout_mode", "msgr",
|
|
||||||
"over_strike", "os",
|
|
||||||
"status_line_esc_ok", "eslok",
|
|
||||||
"dest_tabs_magic_smso", "xt",
|
|
||||||
"tilde_glitch", "hz",
|
|
||||||
"transparent_underline", "ul",
|
|
||||||
"xon_xoff", "nxon",
|
|
||||||
"needs_xon_xoff", "nxon",
|
|
||||||
"prtr_silent", "mc5i",
|
|
||||||
"hard_cursor", "chts",
|
|
||||||
"non_rev_rmcup", "nrrmc",
|
|
||||||
"no_pad_char", "npc",
|
|
||||||
"non_dest_scroll_region", "ndscr",
|
|
||||||
"can_change", "ccc",
|
|
||||||
"back_color_erase", "bce",
|
|
||||||
"hue_lightness_saturation", "hls",
|
|
||||||
"col_addr_glitch", "xhpa",
|
|
||||||
"cr_cancels_micro_mode", "crxm",
|
|
||||||
"has_print_wheel", "daisy",
|
|
||||||
"row_addr_glitch", "xvpa",
|
|
||||||
"semi_auto_right_margin", "sam",
|
|
||||||
"cpi_changes_res", "cpix",
|
|
||||||
"lpi_changes_res", "lpix",
|
|
||||||
"backspaces_with_bs", "",
|
|
||||||
"crt_no_scrolling", "",
|
|
||||||
"no_correctly_working_cr", "",
|
|
||||||
"gnu_has_meta_key", "",
|
|
||||||
"linefeed_is_newline", "",
|
|
||||||
"has_hardware_tabs", "",
|
|
||||||
"return_does_clr_eol", "",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Numerical capabilities
|
|
||||||
var NumAttr = [...]string{
|
|
||||||
"columns", "cols",
|
|
||||||
"init_tabs", "it",
|
|
||||||
"lines", "lines",
|
|
||||||
"lines_of_memory", "lm",
|
|
||||||
"magic_cookie_glitch", "xmc",
|
|
||||||
"padding_baud_rate", "pb",
|
|
||||||
"virtual_terminal", "vt",
|
|
||||||
"width_status_line", "wsl",
|
|
||||||
"num_labels", "nlab",
|
|
||||||
"label_height", "lh",
|
|
||||||
"label_width", "lw",
|
|
||||||
"max_attributes", "ma",
|
|
||||||
"maximum_windows", "wnum",
|
|
||||||
"max_colors", "colors",
|
|
||||||
"max_pairs", "pairs",
|
|
||||||
"no_color_video", "ncv",
|
|
||||||
"buffer_capacity", "bufsz",
|
|
||||||
"dot_vert_spacing", "spinv",
|
|
||||||
"dot_horz_spacing", "spinh",
|
|
||||||
"max_micro_address", "maddr",
|
|
||||||
"max_micro_jump", "mjump",
|
|
||||||
"micro_col_size", "mcs",
|
|
||||||
"micro_line_size", "mls",
|
|
||||||
"number_of_pins", "npins",
|
|
||||||
"output_res_char", "orc",
|
|
||||||
"output_res_line", "orl",
|
|
||||||
"output_res_horz_inch", "orhi",
|
|
||||||
"output_res_vert_inch", "orvi",
|
|
||||||
"print_rate", "cps",
|
|
||||||
"wide_char_size", "widcs",
|
|
||||||
"buttons", "btns",
|
|
||||||
"bit_image_entwining", "bitwin",
|
|
||||||
"bit_image_type", "bitype",
|
|
||||||
"magic_cookie_glitch_ul", "",
|
|
||||||
"carriage_return_delay", "",
|
|
||||||
"new_line_delay", "",
|
|
||||||
"backspace_delay", "",
|
|
||||||
"horizontal_tab_delay", "",
|
|
||||||
"number_of_function_keys", "",
|
|
||||||
}
|
|
||||||
|
|
||||||
// String capabilities
|
|
||||||
var StrAttr = [...]string{
|
|
||||||
"back_tab", "cbt",
|
|
||||||
"bell", "bel",
|
|
||||||
"carriage_return", "cr",
|
|
||||||
"change_scroll_region", "csr",
|
|
||||||
"clear_all_tabs", "tbc",
|
|
||||||
"clear_screen", "clear",
|
|
||||||
"clr_eol", "el",
|
|
||||||
"clr_eos", "ed",
|
|
||||||
"column_address", "hpa",
|
|
||||||
"command_character", "cmdch",
|
|
||||||
"cursor_address", "cup",
|
|
||||||
"cursor_down", "cud1",
|
|
||||||
"cursor_home", "home",
|
|
||||||
"cursor_invisible", "civis",
|
|
||||||
"cursor_left", "cub1",
|
|
||||||
"cursor_mem_address", "mrcup",
|
|
||||||
"cursor_normal", "cnorm",
|
|
||||||
"cursor_right", "cuf1",
|
|
||||||
"cursor_to_ll", "ll",
|
|
||||||
"cursor_up", "cuu1",
|
|
||||||
"cursor_visible", "cvvis",
|
|
||||||
"delete_character", "dch1",
|
|
||||||
"delete_line", "dl1",
|
|
||||||
"dis_status_line", "dsl",
|
|
||||||
"down_half_line", "hd",
|
|
||||||
"enter_alt_charset_mode", "smacs",
|
|
||||||
"enter_blink_mode", "blink",
|
|
||||||
"enter_bold_mode", "bold",
|
|
||||||
"enter_ca_mode", "smcup",
|
|
||||||
"enter_delete_mode", "smdc",
|
|
||||||
"enter_dim_mode", "dim",
|
|
||||||
"enter_insert_mode", "smir",
|
|
||||||
"enter_secure_mode", "invis",
|
|
||||||
"enter_protected_mode", "prot",
|
|
||||||
"enter_reverse_mode", "rev",
|
|
||||||
"enter_standout_mode", "smso",
|
|
||||||
"enter_underline_mode", "smul",
|
|
||||||
"erase_chars", "ech",
|
|
||||||
"exit_alt_charset_mode", "rmacs",
|
|
||||||
"exit_attribute_mode", "sgr0",
|
|
||||||
"exit_ca_mode", "rmcup",
|
|
||||||
"exit_delete_mode", "rmdc",
|
|
||||||
"exit_insert_mode", "rmir",
|
|
||||||
"exit_standout_mode", "rmso",
|
|
||||||
"exit_underline_mode", "rmul",
|
|
||||||
"flash_screen", "flash",
|
|
||||||
"form_feed", "ff",
|
|
||||||
"from_status_line", "fsl",
|
|
||||||
"init_1string", "is1",
|
|
||||||
"init_2string", "is2",
|
|
||||||
"init_3string", "is3",
|
|
||||||
"init_file", "if",
|
|
||||||
"insert_character", "ich1",
|
|
||||||
"insert_line", "il1",
|
|
||||||
"insert_padding", "ip",
|
|
||||||
"key_backspace", "kbs",
|
|
||||||
"key_catab", "ktbc",
|
|
||||||
"key_clear", "kclr",
|
|
||||||
"key_ctab", "kctab",
|
|
||||||
"key_dc", "kdch1",
|
|
||||||
"key_dl", "kdl1",
|
|
||||||
"key_down", "kcud1",
|
|
||||||
"key_eic", "krmir",
|
|
||||||
"key_eol", "kel",
|
|
||||||
"key_eos", "ked",
|
|
||||||
"key_f0", "kf0",
|
|
||||||
"key_f1", "kf1",
|
|
||||||
"key_f10", "kf10",
|
|
||||||
"key_f2", "kf2",
|
|
||||||
"key_f3", "kf3",
|
|
||||||
"key_f4", "kf4",
|
|
||||||
"key_f5", "kf5",
|
|
||||||
"key_f6", "kf6",
|
|
||||||
"key_f7", "kf7",
|
|
||||||
"key_f8", "kf8",
|
|
||||||
"key_f9", "kf9",
|
|
||||||
"key_home", "khome",
|
|
||||||
"key_ic", "kich1",
|
|
||||||
"key_il", "kil1",
|
|
||||||
"key_left", "kcub1",
|
|
||||||
"key_ll", "kll",
|
|
||||||
"key_npage", "knp",
|
|
||||||
"key_ppage", "kpp",
|
|
||||||
"key_right", "kcuf1",
|
|
||||||
"key_sf", "kind",
|
|
||||||
"key_sr", "kri",
|
|
||||||
"key_stab", "khts",
|
|
||||||
"key_up", "kcuu1",
|
|
||||||
"keypad_local", "rmkx",
|
|
||||||
"keypad_xmit", "smkx",
|
|
||||||
"lab_f0", "lf0",
|
|
||||||
"lab_f1", "lf1",
|
|
||||||
"lab_f10", "lf10",
|
|
||||||
"lab_f2", "lf2",
|
|
||||||
"lab_f3", "lf3",
|
|
||||||
"lab_f4", "lf4",
|
|
||||||
"lab_f5", "lf5",
|
|
||||||
"lab_f6", "lf6",
|
|
||||||
"lab_f7", "lf7",
|
|
||||||
"lab_f8", "lf8",
|
|
||||||
"lab_f9", "lf9",
|
|
||||||
"meta_off", "rmm",
|
|
||||||
"meta_on", "smm",
|
|
||||||
"newline", "_glitch",
|
|
||||||
"pad_char", "npc",
|
|
||||||
"parm_dch", "dch",
|
|
||||||
"parm_delete_line", "dl",
|
|
||||||
"parm_down_cursor", "cud",
|
|
||||||
"parm_ich", "ich",
|
|
||||||
"parm_index", "indn",
|
|
||||||
"parm_insert_line", "il",
|
|
||||||
"parm_left_cursor", "cub",
|
|
||||||
"parm_right_cursor", "cuf",
|
|
||||||
"parm_rindex", "rin",
|
|
||||||
"parm_up_cursor", "cuu",
|
|
||||||
"pkey_key", "pfkey",
|
|
||||||
"pkey_local", "pfloc",
|
|
||||||
"pkey_xmit", "pfx",
|
|
||||||
"print_screen", "mc0",
|
|
||||||
"prtr_off", "mc4",
|
|
||||||
"prtr_on", "mc5",
|
|
||||||
"repeat_char", "rep",
|
|
||||||
"reset_1string", "rs1",
|
|
||||||
"reset_2string", "rs2",
|
|
||||||
"reset_3string", "rs3",
|
|
||||||
"reset_file", "rf",
|
|
||||||
"restore_cursor", "rc",
|
|
||||||
"row_address", "mvpa",
|
|
||||||
"save_cursor", "row_address",
|
|
||||||
"scroll_forward", "ind",
|
|
||||||
"scroll_reverse", "ri",
|
|
||||||
"set_attributes", "sgr",
|
|
||||||
"set_tab", "hts",
|
|
||||||
"set_window", "wind",
|
|
||||||
"tab", "s_magic_smso",
|
|
||||||
"to_status_line", "tsl",
|
|
||||||
"underline_char", "uc",
|
|
||||||
"up_half_line", "hu",
|
|
||||||
"init_prog", "iprog",
|
|
||||||
"key_a1", "ka1",
|
|
||||||
"key_a3", "ka3",
|
|
||||||
"key_b2", "kb2",
|
|
||||||
"key_c1", "kc1",
|
|
||||||
"key_c3", "kc3",
|
|
||||||
"prtr_non", "mc5p",
|
|
||||||
"char_padding", "rmp",
|
|
||||||
"acs_chars", "acsc",
|
|
||||||
"plab_norm", "pln",
|
|
||||||
"key_btab", "kcbt",
|
|
||||||
"enter_xon_mode", "smxon",
|
|
||||||
"exit_xon_mode", "rmxon",
|
|
||||||
"enter_am_mode", "smam",
|
|
||||||
"exit_am_mode", "rmam",
|
|
||||||
"xon_character", "xonc",
|
|
||||||
"xoff_character", "xoffc",
|
|
||||||
"ena_acs", "enacs",
|
|
||||||
"label_on", "smln",
|
|
||||||
"label_off", "rmln",
|
|
||||||
"key_beg", "kbeg",
|
|
||||||
"key_cancel", "kcan",
|
|
||||||
"key_close", "kclo",
|
|
||||||
"key_command", "kcmd",
|
|
||||||
"key_copy", "kcpy",
|
|
||||||
"key_create", "kcrt",
|
|
||||||
"key_end", "kend",
|
|
||||||
"key_enter", "kent",
|
|
||||||
"key_exit", "kext",
|
|
||||||
"key_find", "kfnd",
|
|
||||||
"key_help", "khlp",
|
|
||||||
"key_mark", "kmrk",
|
|
||||||
"key_message", "kmsg",
|
|
||||||
"key_move", "kmov",
|
|
||||||
"key_next", "knxt",
|
|
||||||
"key_open", "kopn",
|
|
||||||
"key_options", "kopt",
|
|
||||||
"key_previous", "kprv",
|
|
||||||
"key_print", "kprt",
|
|
||||||
"key_redo", "krdo",
|
|
||||||
"key_reference", "kref",
|
|
||||||
"key_refresh", "krfr",
|
|
||||||
"key_replace", "krpl",
|
|
||||||
"key_restart", "krst",
|
|
||||||
"key_resume", "kres",
|
|
||||||
"key_save", "ksav",
|
|
||||||
"key_suspend", "kspd",
|
|
||||||
"key_undo", "kund",
|
|
||||||
"key_sbeg", "kBEG",
|
|
||||||
"key_scancel", "kCAN",
|
|
||||||
"key_scommand", "kCMD",
|
|
||||||
"key_scopy", "kCPY",
|
|
||||||
"key_screate", "kCRT",
|
|
||||||
"key_sdc", "kDC",
|
|
||||||
"key_sdl", "kDL",
|
|
||||||
"key_select", "kslt",
|
|
||||||
"key_send", "kEND",
|
|
||||||
"key_seol", "kEOL",
|
|
||||||
"key_sexit", "kEXT",
|
|
||||||
"key_sfind", "kFND",
|
|
||||||
"key_shelp", "kHLP",
|
|
||||||
"key_shome", "kHOM",
|
|
||||||
"key_sic", "kIC",
|
|
||||||
"key_sleft", "kLFT",
|
|
||||||
"key_smessage", "kMSG",
|
|
||||||
"key_smove", "kMOV",
|
|
||||||
"key_snext", "kNXT",
|
|
||||||
"key_soptions", "kOPT",
|
|
||||||
"key_sprevious", "kPRV",
|
|
||||||
"key_sprint", "kPRT",
|
|
||||||
"key_sredo", "kRDO",
|
|
||||||
"key_sreplace", "kRPL",
|
|
||||||
"key_sright", "kRIT",
|
|
||||||
"key_srsume", "kRES",
|
|
||||||
"key_ssave", "kSAV",
|
|
||||||
"key_ssuspend", "kSPD",
|
|
||||||
"key_sundo", "kUND",
|
|
||||||
"req_for_input", "rfi",
|
|
||||||
"key_f11", "kf11",
|
|
||||||
"key_f12", "kf12",
|
|
||||||
"key_f13", "kf13",
|
|
||||||
"key_f14", "kf14",
|
|
||||||
"key_f15", "kf15",
|
|
||||||
"key_f16", "kf16",
|
|
||||||
"key_f17", "kf17",
|
|
||||||
"key_f18", "kf18",
|
|
||||||
"key_f19", "kf19",
|
|
||||||
"key_f20", "kf20",
|
|
||||||
"key_f21", "kf21",
|
|
||||||
"key_f22", "kf22",
|
|
||||||
"key_f23", "kf23",
|
|
||||||
"key_f24", "kf24",
|
|
||||||
"key_f25", "kf25",
|
|
||||||
"key_f26", "kf26",
|
|
||||||
"key_f27", "kf27",
|
|
||||||
"key_f28", "kf28",
|
|
||||||
"key_f29", "kf29",
|
|
||||||
"key_f30", "kf30",
|
|
||||||
"key_f31", "kf31",
|
|
||||||
"key_f32", "kf32",
|
|
||||||
"key_f33", "kf33",
|
|
||||||
"key_f34", "kf34",
|
|
||||||
"key_f35", "kf35",
|
|
||||||
"key_f36", "kf36",
|
|
||||||
"key_f37", "kf37",
|
|
||||||
"key_f38", "kf38",
|
|
||||||
"key_f39", "kf39",
|
|
||||||
"key_f40", "kf40",
|
|
||||||
"key_f41", "kf41",
|
|
||||||
"key_f42", "kf42",
|
|
||||||
"key_f43", "kf43",
|
|
||||||
"key_f44", "kf44",
|
|
||||||
"key_f45", "kf45",
|
|
||||||
"key_f46", "kf46",
|
|
||||||
"key_f47", "kf47",
|
|
||||||
"key_f48", "kf48",
|
|
||||||
"key_f49", "kf49",
|
|
||||||
"key_f50", "kf50",
|
|
||||||
"key_f51", "kf51",
|
|
||||||
"key_f52", "kf52",
|
|
||||||
"key_f53", "kf53",
|
|
||||||
"key_f54", "kf54",
|
|
||||||
"key_f55", "kf55",
|
|
||||||
"key_f56", "kf56",
|
|
||||||
"key_f57", "kf57",
|
|
||||||
"key_f58", "kf58",
|
|
||||||
"key_f59", "kf59",
|
|
||||||
"key_f60", "kf60",
|
|
||||||
"key_f61", "kf61",
|
|
||||||
"key_f62", "kf62",
|
|
||||||
"key_f63", "kf63",
|
|
||||||
"clr_bol", "el1",
|
|
||||||
"clear_margins", "mgc",
|
|
||||||
"set_left_margin", "smgl",
|
|
||||||
"set_right_margin", "smgr",
|
|
||||||
"label_format", "fln",
|
|
||||||
"set_clock", "sclk",
|
|
||||||
"display_clock", "dclk",
|
|
||||||
"remove_clock", "rmclk",
|
|
||||||
"create_window", "cwin",
|
|
||||||
"goto_window", "wingo",
|
|
||||||
"hangup", "hup",
|
|
||||||
"dial_phone", "dial",
|
|
||||||
"quick_dial", "qdial",
|
|
||||||
"tone", "tone",
|
|
||||||
"pulse", "pulse",
|
|
||||||
"flash_hook", "hook",
|
|
||||||
"fixed_pause", "pause",
|
|
||||||
"wait_tone", "wait",
|
|
||||||
"user0", "u0",
|
|
||||||
"user1", "u1",
|
|
||||||
"user2", "u2",
|
|
||||||
"user3", "u3",
|
|
||||||
"user4", "u4",
|
|
||||||
"user5", "u5",
|
|
||||||
"user6", "u6",
|
|
||||||
"user7", "u7",
|
|
||||||
"user8", "u8",
|
|
||||||
"user9", "u9",
|
|
||||||
"orig_pair", "op",
|
|
||||||
"orig_colors", "oc",
|
|
||||||
"initialize_color", "initc",
|
|
||||||
"initialize_pair", "initp",
|
|
||||||
"set_color_pair", "scp",
|
|
||||||
"set_foreground", "setf",
|
|
||||||
"set_background", "setb",
|
|
||||||
"change_char_pitch", "cpi",
|
|
||||||
"change_line_pitch", "lpi",
|
|
||||||
"change_res_horz", "chr",
|
|
||||||
"change_res_vert", "cvr",
|
|
||||||
"define_char", "defc",
|
|
||||||
"enter_doublewide_mode", "swidm",
|
|
||||||
"enter_draft_quality", "sdrfq",
|
|
||||||
"enter_italics_mode", "sitm",
|
|
||||||
"enter_leftward_mode", "slm",
|
|
||||||
"enter_micro_mode", "smicm",
|
|
||||||
"enter_near_letter_quality", "snlq",
|
|
||||||
"enter_normal_quality", "snrmq",
|
|
||||||
"enter_shadow_mode", "sshm",
|
|
||||||
"enter_subscript_mode", "ssubm",
|
|
||||||
"enter_superscript_mode", "ssupm",
|
|
||||||
"enter_upward_mode", "sum",
|
|
||||||
"exit_doublewide_mode", "rwidm",
|
|
||||||
"exit_italics_mode", "ritm",
|
|
||||||
"exit_leftward_mode", "rlm",
|
|
||||||
"exit_micro_mode", "rmicm",
|
|
||||||
"exit_shadow_mode", "rshm",
|
|
||||||
"exit_subscript_mode", "rsubm",
|
|
||||||
"exit_superscript_mode", "rsupm",
|
|
||||||
"exit_upward_mode", "rum",
|
|
||||||
"micro_column_address", "mhpa",
|
|
||||||
"micro_down", "mcud1",
|
|
||||||
"micro_left", "mcub1",
|
|
||||||
"micro_right", "mcuf1",
|
|
||||||
"micro_row_address", "mvpa",
|
|
||||||
"micro_up", "mcuu1",
|
|
||||||
"order_of_pins", "porder",
|
|
||||||
"parm_down_micro", "mcud",
|
|
||||||
"parm_left_micro", "mcub",
|
|
||||||
"parm_right_micro", "mcuf",
|
|
||||||
"parm_up_micro", "mcuu",
|
|
||||||
"select_char_set", "scs",
|
|
||||||
"set_bottom_margin", "smgb",
|
|
||||||
"set_bottom_margin_parm", "smgbp",
|
|
||||||
"set_left_margin_parm", "smglp",
|
|
||||||
"set_right_margin_parm", "smgrp",
|
|
||||||
"set_top_margin", "smgt",
|
|
||||||
"set_top_margin_parm", "smgtp",
|
|
||||||
"start_bit_image", "sbim",
|
|
||||||
"start_char_set_def", "scsd",
|
|
||||||
"stop_bit_image", "rbim",
|
|
||||||
"stop_char_set_def", "rcsd",
|
|
||||||
"subscript_characters", "subcs",
|
|
||||||
"superscript_characters", "supcs",
|
|
||||||
"these_cause_cr", "docr",
|
|
||||||
"zero_motion", "zerom",
|
|
||||||
"char_set_names", "csnm",
|
|
||||||
"key_mouse", "kmous",
|
|
||||||
"mouse_info", "minfo",
|
|
||||||
"req_mouse_pos", "reqmp",
|
|
||||||
"get_mouse", "getm",
|
|
||||||
"set_a_foreground", "setaf",
|
|
||||||
"set_a_background", "setab",
|
|
||||||
"pkey_plab", "pfxl",
|
|
||||||
"device_type", "devt",
|
|
||||||
"code_set_init", "csin",
|
|
||||||
"set0_des_seq", "s0ds",
|
|
||||||
"set1_des_seq", "s1ds",
|
|
||||||
"set2_des_seq", "s2ds",
|
|
||||||
"set3_des_seq", "s3ds",
|
|
||||||
"set_lr_margin", "smglr",
|
|
||||||
"set_tb_margin", "smgtb",
|
|
||||||
"bit_image_repeat", "birep",
|
|
||||||
"bit_image_newline", "binel",
|
|
||||||
"bit_image_carriage_return", "bicr",
|
|
||||||
"color_names", "colornm",
|
|
||||||
"define_bit_image_region", "defbi",
|
|
||||||
"end_bit_image_region", "endbi",
|
|
||||||
"set_color_band", "setcolor",
|
|
||||||
"set_page_length", "slines",
|
|
||||||
"display_pc_char", "dispc",
|
|
||||||
"enter_pc_charset_mode", "smpch",
|
|
||||||
"exit_pc_charset_mode", "rmpch",
|
|
||||||
"enter_scancode_mode", "smsc",
|
|
||||||
"exit_scancode_mode", "rmsc",
|
|
||||||
"pc_term_options", "pctrm",
|
|
||||||
"scancode_escape", "scesc",
|
|
||||||
"alt_scancode_esc", "scesa",
|
|
||||||
"enter_horizontal_hl_mode", "ehhlm",
|
|
||||||
"enter_left_hl_mode", "elhlm",
|
|
||||||
"enter_low_hl_mode", "elohlm",
|
|
||||||
"enter_right_hl_mode", "erhlm",
|
|
||||||
"enter_top_hl_mode", "ethlm",
|
|
||||||
"enter_vertical_hl_mode", "evhlm",
|
|
||||||
"set_a_attributes", "sgr1",
|
|
||||||
"set_pglen_inch", "slength",
|
|
||||||
"termcap_init2", "",
|
|
||||||
"termcap_reset", "",
|
|
||||||
"linefeed_if_not_lf", "",
|
|
||||||
"backspace_if_not_bs", "",
|
|
||||||
"other_non_function_keys", "",
|
|
||||||
"arrow_key_map", "",
|
|
||||||
"acs_ulcorner", "",
|
|
||||||
"acs_llcorner", "",
|
|
||||||
"acs_urcorner", "",
|
|
||||||
"acs_lrcorner", "",
|
|
||||||
"acs_ltee", "",
|
|
||||||
"acs_rtee", "",
|
|
||||||
"acs_btee", "",
|
|
||||||
"acs_ttee", "",
|
|
||||||
"acs_hline", "",
|
|
||||||
"acs_vline", "",
|
|
||||||
"acs_plus", "",
|
|
||||||
"memory_lock", "",
|
|
||||||
"memory_unlock", "",
|
|
||||||
"box_chars_1", "",
|
|
||||||
}
|
|
|
@ -1,238 +0,0 @@
|
||||||
// Copyright 2012 Neal van Veen. All rights reserved.
|
|
||||||
// Usage of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
// Gotty is a Go-package for reading and parsing the terminfo database
|
|
||||||
package gotty
|
|
||||||
|
|
||||||
// TODO add more concurrency to name lookup, look for more opportunities.
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Open a terminfo file by the name given and construct a TermInfo object.
|
|
||||||
// If something went wrong reading the terminfo database file, an error is
|
|
||||||
// returned.
|
|
||||||
func OpenTermInfo(termName string) (*TermInfo, error) {
|
|
||||||
var term *TermInfo
|
|
||||||
var err error
|
|
||||||
// Find the environment variables
|
|
||||||
termloc := os.Getenv("TERMINFO")
|
|
||||||
if len(termloc) == 0 {
|
|
||||||
// Search like ncurses
|
|
||||||
locations := []string{os.Getenv("HOME") + "/.terminfo/", "/etc/terminfo/",
|
|
||||||
"/lib/terminfo/", "/usr/share/terminfo/"}
|
|
||||||
var path string
|
|
||||||
for _, str := range locations {
|
|
||||||
// Construct path
|
|
||||||
path = str + string(termName[0]) + "/" + termName
|
|
||||||
// Check if path can be opened
|
|
||||||
file, _ := os.Open(path)
|
|
||||||
if file != nil {
|
|
||||||
// Path can open, fall out and use current path
|
|
||||||
file.Close()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(path) > 0 {
|
|
||||||
term, err = readTermInfo(path)
|
|
||||||
} else {
|
|
||||||
err = errors.New(fmt.Sprintf("No terminfo file(-location) found"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return term, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open a terminfo file from the environment variable containing the current
|
|
||||||
// terminal name and construct a TermInfo object. If something went wrong
|
|
||||||
// reading the terminfo database file, an error is returned.
|
|
||||||
func OpenTermInfoEnv() (*TermInfo, error) {
|
|
||||||
termenv := os.Getenv("TERM")
|
|
||||||
return OpenTermInfo(termenv)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return an attribute by the name attr provided. If none can be found,
|
|
||||||
// an error is returned.
|
|
||||||
func (term *TermInfo) GetAttribute(attr string) (stacker, error) {
|
|
||||||
// Channel to store the main value in.
|
|
||||||
var value stacker
|
|
||||||
// Add a blocking WaitGroup
|
|
||||||
var block sync.WaitGroup
|
|
||||||
// Keep track of variable being written.
|
|
||||||
written := false
|
|
||||||
// Function to put into goroutine.
|
|
||||||
f := func(ats interface{}) {
|
|
||||||
var ok bool
|
|
||||||
var v stacker
|
|
||||||
// Switch on type of map to use and assign value to it.
|
|
||||||
switch reflect.TypeOf(ats).Elem().Kind() {
|
|
||||||
case reflect.Bool:
|
|
||||||
v, ok = ats.(map[string]bool)[attr]
|
|
||||||
case reflect.Int16:
|
|
||||||
v, ok = ats.(map[string]int16)[attr]
|
|
||||||
case reflect.String:
|
|
||||||
v, ok = ats.(map[string]string)[attr]
|
|
||||||
}
|
|
||||||
// If ok, a value is found, so we can write.
|
|
||||||
if ok {
|
|
||||||
value = v
|
|
||||||
written = true
|
|
||||||
}
|
|
||||||
// Goroutine is done
|
|
||||||
block.Done()
|
|
||||||
}
|
|
||||||
block.Add(3)
|
|
||||||
// Go for all 3 attribute lists.
|
|
||||||
go f(term.boolAttributes)
|
|
||||||
go f(term.numAttributes)
|
|
||||||
go f(term.strAttributes)
|
|
||||||
// Wait until every goroutine is done.
|
|
||||||
block.Wait()
|
|
||||||
// If a value has been written, return it.
|
|
||||||
if written {
|
|
||||||
return value, nil
|
|
||||||
}
|
|
||||||
// Otherwise, error.
|
|
||||||
return nil, fmt.Errorf("Erorr finding attribute")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return an attribute by the name attr provided. If none can be found,
|
|
||||||
// an error is returned. A name is first converted to its termcap value.
|
|
||||||
func (term *TermInfo) GetAttributeName(name string) (stacker, error) {
|
|
||||||
tc := GetTermcapName(name)
|
|
||||||
return term.GetAttribute(tc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A utility function that finds and returns the termcap equivalent of a
|
|
||||||
// variable name.
|
|
||||||
func GetTermcapName(name string) string {
|
|
||||||
// Termcap name
|
|
||||||
var tc string
|
|
||||||
// Blocking group
|
|
||||||
var wait sync.WaitGroup
|
|
||||||
// Function to put into a goroutine
|
|
||||||
f := func(attrs []string) {
|
|
||||||
// Find the string corresponding to the name
|
|
||||||
for i, s := range attrs {
|
|
||||||
if s == name {
|
|
||||||
tc = attrs[i+1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Goroutine is finished
|
|
||||||
wait.Done()
|
|
||||||
}
|
|
||||||
wait.Add(3)
|
|
||||||
// Go for all 3 attribute lists
|
|
||||||
go f(BoolAttr[:])
|
|
||||||
go f(NumAttr[:])
|
|
||||||
go f(StrAttr[:])
|
|
||||||
// Wait until every goroutine is done
|
|
||||||
wait.Wait()
|
|
||||||
// Return the termcap name
|
|
||||||
return tc
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function takes a path to a terminfo file and reads it in binary
|
|
||||||
// form to construct the actual TermInfo file.
|
|
||||||
func readTermInfo(path string) (*TermInfo, error) {
|
|
||||||
// Open the terminfo file
|
|
||||||
file, err := os.Open(path)
|
|
||||||
defer file.Close()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// magic, nameSize, boolSize, nrSNum, nrOffsetsStr, strSize
|
|
||||||
// Header is composed of the magic 0432 octal number, size of the name
|
|
||||||
// section, size of the boolean section, the amount of number values,
|
|
||||||
// the number of offsets of strings, and the size of the string section.
|
|
||||||
var header [6]int16
|
|
||||||
// Byte array is used to read in byte values
|
|
||||||
var byteArray []byte
|
|
||||||
// Short array is used to read in short values
|
|
||||||
var shArray []int16
|
|
||||||
// TermInfo object to store values
|
|
||||||
var term TermInfo
|
|
||||||
|
|
||||||
// Read in the header
|
|
||||||
err = binary.Read(file, binary.LittleEndian, &header)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// If magic number isn't there or isn't correct, we have the wrong filetype
|
|
||||||
if header[0] != 0432 {
|
|
||||||
return nil, errors.New(fmt.Sprintf("Wrong filetype"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read in the names
|
|
||||||
byteArray = make([]byte, header[1])
|
|
||||||
err = binary.Read(file, binary.LittleEndian, &byteArray)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
term.Names = strings.Split(string(byteArray), "|")
|
|
||||||
|
|
||||||
// Read in the booleans
|
|
||||||
byteArray = make([]byte, header[2])
|
|
||||||
err = binary.Read(file, binary.LittleEndian, &byteArray)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
term.boolAttributes = make(map[string]bool)
|
|
||||||
for i, b := range byteArray {
|
|
||||||
if b == 1 {
|
|
||||||
term.boolAttributes[BoolAttr[i*2+1]] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If the number of bytes read is not even, a byte for alignment is added
|
|
||||||
if len(byteArray)%2 != 0 {
|
|
||||||
err = binary.Read(file, binary.LittleEndian, make([]byte, 1))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read in shorts
|
|
||||||
shArray = make([]int16, header[3])
|
|
||||||
err = binary.Read(file, binary.LittleEndian, &shArray)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
term.numAttributes = make(map[string]int16)
|
|
||||||
for i, n := range shArray {
|
|
||||||
if n != 0377 && n > -1 {
|
|
||||||
term.numAttributes[NumAttr[i*2+1]] = n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the offsets into the short array
|
|
||||||
shArray = make([]int16, header[4])
|
|
||||||
err = binary.Read(file, binary.LittleEndian, &shArray)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// Read the actual strings in the byte array
|
|
||||||
byteArray = make([]byte, header[5])
|
|
||||||
err = binary.Read(file, binary.LittleEndian, &byteArray)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
term.strAttributes = make(map[string]string)
|
|
||||||
// We get an offset, and then iterate until the string is null-terminated
|
|
||||||
for i, offset := range shArray {
|
|
||||||
if offset > -1 {
|
|
||||||
r := offset
|
|
||||||
for ; byteArray[r] != 0; r++ {
|
|
||||||
}
|
|
||||||
term.strAttributes[StrAttr[i*2+1]] = string(byteArray[offset:r])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &term, nil
|
|
||||||
}
|
|
|
@ -1,362 +0,0 @@
|
||||||
// Copyright 2012 Neal van Veen. All rights reserved.
|
|
||||||
// Usage of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
package gotty
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var exp = [...]string{
|
|
||||||
"%%",
|
|
||||||
"%c",
|
|
||||||
"%s",
|
|
||||||
"%p(\\d)",
|
|
||||||
"%P([A-z])",
|
|
||||||
"%g([A-z])",
|
|
||||||
"%'(.)'",
|
|
||||||
"%{([0-9]+)}",
|
|
||||||
"%l",
|
|
||||||
"%\\+|%-|%\\*|%/|%m",
|
|
||||||
"%&|%\\||%\\^",
|
|
||||||
"%=|%>|%<",
|
|
||||||
"%A|%O",
|
|
||||||
"%!|%~",
|
|
||||||
"%i",
|
|
||||||
"%(:[\\ #\\-\\+]{0,4})?(\\d+\\.\\d+|\\d+)?[doxXs]",
|
|
||||||
"%\\?(.*?);",
|
|
||||||
}
|
|
||||||
|
|
||||||
var regex *regexp.Regexp
|
|
||||||
var staticVar map[byte]stacker
|
|
||||||
|
|
||||||
// Parses the attribute that is received with name attr and parameters params.
|
|
||||||
func (term *TermInfo) Parse(attr string, params ...interface{}) (string, error) {
|
|
||||||
// Get the attribute name first.
|
|
||||||
iface, err := term.GetAttribute(attr)
|
|
||||||
str, ok := iface.(string)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if !ok {
|
|
||||||
return str, errors.New("Only string capabilities can be parsed.")
|
|
||||||
}
|
|
||||||
// Construct the hidden parser struct so we can use a recursive stack based
|
|
||||||
// parser.
|
|
||||||
ps := &parser{}
|
|
||||||
// Dynamic variables only exist in this context.
|
|
||||||
ps.dynamicVar = make(map[byte]stacker, 26)
|
|
||||||
ps.parameters = make([]stacker, len(params))
|
|
||||||
// Convert the parameters to insert them into the parser struct.
|
|
||||||
for i, x := range params {
|
|
||||||
ps.parameters[i] = x
|
|
||||||
}
|
|
||||||
// Recursively walk and return.
|
|
||||||
result, err := ps.walk(str)
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parses the attribute that is received with name attr and parameters params.
|
|
||||||
// Only works on full name of a capability that is given, which it uses to
|
|
||||||
// search for the termcap name.
|
|
||||||
func (term *TermInfo) ParseName(attr string, params ...interface{}) (string, error) {
|
|
||||||
tc := GetTermcapName(attr)
|
|
||||||
return term.Parse(tc, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Identify each token in a stack based manner and do the actual parsing.
|
|
||||||
func (ps *parser) walk(attr string) (string, error) {
|
|
||||||
// We use a buffer to get the modified string.
|
|
||||||
var buf bytes.Buffer
|
|
||||||
// Next, find and identify all tokens by their indices and strings.
|
|
||||||
tokens := regex.FindAllStringSubmatch(attr, -1)
|
|
||||||
if len(tokens) == 0 {
|
|
||||||
return attr, nil
|
|
||||||
}
|
|
||||||
indices := regex.FindAllStringIndex(attr, -1)
|
|
||||||
q := 0 // q counts the matches of one token
|
|
||||||
// Iterate through the string per character.
|
|
||||||
for i := 0; i < len(attr); i++ {
|
|
||||||
// If the current position is an identified token, execute the following
|
|
||||||
// steps.
|
|
||||||
if q < len(indices) && i >= indices[q][0] && i < indices[q][1] {
|
|
||||||
// Switch on token.
|
|
||||||
switch {
|
|
||||||
case tokens[q][0][:2] == "%%":
|
|
||||||
// Literal percentage character.
|
|
||||||
buf.WriteByte('%')
|
|
||||||
case tokens[q][0][:2] == "%c":
|
|
||||||
// Pop a character.
|
|
||||||
c, err := ps.st.pop()
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
buf.WriteByte(c.(byte))
|
|
||||||
case tokens[q][0][:2] == "%s":
|
|
||||||
// Pop a string.
|
|
||||||
str, err := ps.st.pop()
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
if _, ok := str.(string); !ok {
|
|
||||||
return buf.String(), errors.New("Stack head is not a string")
|
|
||||||
}
|
|
||||||
buf.WriteString(str.(string))
|
|
||||||
case tokens[q][0][:2] == "%p":
|
|
||||||
// Push a parameter on the stack.
|
|
||||||
index, err := strconv.ParseInt(tokens[q][1], 10, 8)
|
|
||||||
index--
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
if int(index) >= len(ps.parameters) {
|
|
||||||
return buf.String(), errors.New("Parameters index out of bound")
|
|
||||||
}
|
|
||||||
ps.st.push(ps.parameters[index])
|
|
||||||
case tokens[q][0][:2] == "%P":
|
|
||||||
// Pop a variable from the stack as a dynamic or static variable.
|
|
||||||
val, err := ps.st.pop()
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
index := tokens[q][2]
|
|
||||||
if len(index) > 1 {
|
|
||||||
errorStr := fmt.Sprintf("%s is not a valid dynamic variables index",
|
|
||||||
index)
|
|
||||||
return buf.String(), errors.New(errorStr)
|
|
||||||
}
|
|
||||||
// Specify either dynamic or static.
|
|
||||||
if index[0] >= 'a' && index[0] <= 'z' {
|
|
||||||
ps.dynamicVar[index[0]] = val
|
|
||||||
} else if index[0] >= 'A' && index[0] <= 'Z' {
|
|
||||||
staticVar[index[0]] = val
|
|
||||||
}
|
|
||||||
case tokens[q][0][:2] == "%g":
|
|
||||||
// Push a variable from the stack as a dynamic or static variable.
|
|
||||||
index := tokens[q][3]
|
|
||||||
if len(index) > 1 {
|
|
||||||
errorStr := fmt.Sprintf("%s is not a valid static variables index",
|
|
||||||
index)
|
|
||||||
return buf.String(), errors.New(errorStr)
|
|
||||||
}
|
|
||||||
var val stacker
|
|
||||||
if index[0] >= 'a' && index[0] <= 'z' {
|
|
||||||
val = ps.dynamicVar[index[0]]
|
|
||||||
} else if index[0] >= 'A' && index[0] <= 'Z' {
|
|
||||||
val = staticVar[index[0]]
|
|
||||||
}
|
|
||||||
ps.st.push(val)
|
|
||||||
case tokens[q][0][:2] == "%'":
|
|
||||||
// Push a character constant.
|
|
||||||
con := tokens[q][4]
|
|
||||||
if len(con) > 1 {
|
|
||||||
errorStr := fmt.Sprintf("%s is not a valid character constant", con)
|
|
||||||
return buf.String(), errors.New(errorStr)
|
|
||||||
}
|
|
||||||
ps.st.push(con[0])
|
|
||||||
case tokens[q][0][:2] == "%{":
|
|
||||||
// Push an integer constant.
|
|
||||||
con, err := strconv.ParseInt(tokens[q][5], 10, 32)
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
ps.st.push(con)
|
|
||||||
case tokens[q][0][:2] == "%l":
|
|
||||||
// Push the length of the string that is popped from the stack.
|
|
||||||
popStr, err := ps.st.pop()
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
if _, ok := popStr.(string); !ok {
|
|
||||||
errStr := fmt.Sprintf("Stack head is not a string")
|
|
||||||
return buf.String(), errors.New(errStr)
|
|
||||||
}
|
|
||||||
ps.st.push(len(popStr.(string)))
|
|
||||||
case tokens[q][0][:2] == "%?":
|
|
||||||
// If-then-else construct. First, the whole string is identified and
|
|
||||||
// then inside this substring, we can specify which parts to switch on.
|
|
||||||
ifReg, _ := regexp.Compile("%\\?(.*)%t(.*)%e(.*);|%\\?(.*)%t(.*);")
|
|
||||||
ifTokens := ifReg.FindStringSubmatch(tokens[q][0])
|
|
||||||
var (
|
|
||||||
ifStr string
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
// Parse the if-part to determine if-else.
|
|
||||||
if len(ifTokens[1]) > 0 {
|
|
||||||
ifStr, err = ps.walk(ifTokens[1])
|
|
||||||
} else { // else
|
|
||||||
ifStr, err = ps.walk(ifTokens[4])
|
|
||||||
}
|
|
||||||
// Return any errors
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
} else if len(ifStr) > 0 {
|
|
||||||
// Self-defined limitation, not sure if this is correct, but didn't
|
|
||||||
// seem like it.
|
|
||||||
return buf.String(), errors.New("If-clause cannot print statements")
|
|
||||||
}
|
|
||||||
var thenStr string
|
|
||||||
// Pop the first value that is set by parsing the if-clause.
|
|
||||||
choose, err := ps.st.pop()
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
// Switch to if or else.
|
|
||||||
if choose.(int) == 0 && len(ifTokens[1]) > 0 {
|
|
||||||
thenStr, err = ps.walk(ifTokens[3])
|
|
||||||
} else if choose.(int) != 0 {
|
|
||||||
if len(ifTokens[1]) > 0 {
|
|
||||||
thenStr, err = ps.walk(ifTokens[2])
|
|
||||||
} else {
|
|
||||||
thenStr, err = ps.walk(ifTokens[5])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
buf.WriteString(thenStr)
|
|
||||||
case tokens[q][0][len(tokens[q][0])-1] == 'd': // Fallthrough for printing
|
|
||||||
fallthrough
|
|
||||||
case tokens[q][0][len(tokens[q][0])-1] == 'o': // digits.
|
|
||||||
fallthrough
|
|
||||||
case tokens[q][0][len(tokens[q][0])-1] == 'x':
|
|
||||||
fallthrough
|
|
||||||
case tokens[q][0][len(tokens[q][0])-1] == 'X':
|
|
||||||
fallthrough
|
|
||||||
case tokens[q][0][len(tokens[q][0])-1] == 's':
|
|
||||||
token := tokens[q][0]
|
|
||||||
// Remove the : that comes before a flag.
|
|
||||||
if token[1] == ':' {
|
|
||||||
token = token[:1] + token[2:]
|
|
||||||
}
|
|
||||||
digit, err := ps.st.pop()
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
// The rest is determined like the normal formatted prints.
|
|
||||||
digitStr := fmt.Sprintf(token, digit.(int))
|
|
||||||
buf.WriteString(digitStr)
|
|
||||||
case tokens[q][0][:2] == "%i":
|
|
||||||
// Increment the parameters by one.
|
|
||||||
if len(ps.parameters) < 2 {
|
|
||||||
return buf.String(), errors.New("Not enough parameters to increment.")
|
|
||||||
}
|
|
||||||
val1, val2 := ps.parameters[0].(int), ps.parameters[1].(int)
|
|
||||||
val1++
|
|
||||||
val2++
|
|
||||||
ps.parameters[0], ps.parameters[1] = val1, val2
|
|
||||||
default:
|
|
||||||
// The rest of the tokens is a special case, where two values are
|
|
||||||
// popped and then operated on by the token that comes after them.
|
|
||||||
op1, err := ps.st.pop()
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
op2, err := ps.st.pop()
|
|
||||||
if err != nil {
|
|
||||||
return buf.String(), err
|
|
||||||
}
|
|
||||||
var result stacker
|
|
||||||
switch tokens[q][0][:2] {
|
|
||||||
case "%+":
|
|
||||||
// Addition
|
|
||||||
result = op2.(int) + op1.(int)
|
|
||||||
case "%-":
|
|
||||||
// Subtraction
|
|
||||||
result = op2.(int) - op1.(int)
|
|
||||||
case "%*":
|
|
||||||
// Multiplication
|
|
||||||
result = op2.(int) * op1.(int)
|
|
||||||
case "%/":
|
|
||||||
// Division
|
|
||||||
result = op2.(int) / op1.(int)
|
|
||||||
case "%m":
|
|
||||||
// Modulo
|
|
||||||
result = op2.(int) % op1.(int)
|
|
||||||
case "%&":
|
|
||||||
// Bitwise AND
|
|
||||||
result = op2.(int) & op1.(int)
|
|
||||||
case "%|":
|
|
||||||
// Bitwise OR
|
|
||||||
result = op2.(int) | op1.(int)
|
|
||||||
case "%^":
|
|
||||||
// Bitwise XOR
|
|
||||||
result = op2.(int) ^ op1.(int)
|
|
||||||
case "%=":
|
|
||||||
// Equals
|
|
||||||
result = op2 == op1
|
|
||||||
case "%>":
|
|
||||||
// Greater-than
|
|
||||||
result = op2.(int) > op1.(int)
|
|
||||||
case "%<":
|
|
||||||
// Lesser-than
|
|
||||||
result = op2.(int) < op1.(int)
|
|
||||||
case "%A":
|
|
||||||
// Logical AND
|
|
||||||
result = op2.(bool) && op1.(bool)
|
|
||||||
case "%O":
|
|
||||||
// Logical OR
|
|
||||||
result = op2.(bool) || op1.(bool)
|
|
||||||
case "%!":
|
|
||||||
// Logical complement
|
|
||||||
result = !op1.(bool)
|
|
||||||
case "%~":
|
|
||||||
// Bitwise complement
|
|
||||||
result = ^(op1.(int))
|
|
||||||
}
|
|
||||||
ps.st.push(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
i = indices[q][1] - 1
|
|
||||||
q++
|
|
||||||
} else {
|
|
||||||
// We are not "inside" a token, so just skip until the end or the next
|
|
||||||
// token, and add all characters to the buffer.
|
|
||||||
j := i
|
|
||||||
if q != len(indices) {
|
|
||||||
for !(j >= indices[q][0] && j < indices[q][1]) {
|
|
||||||
j++
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
j = len(attr)
|
|
||||||
}
|
|
||||||
buf.WriteString(string(attr[i:j]))
|
|
||||||
i = j
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Return the buffer as a string.
|
|
||||||
return buf.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Push a stacker-value onto the stack.
|
|
||||||
func (st *stack) push(s stacker) {
|
|
||||||
*st = append(*st, s)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pop a stacker-value from the stack.
|
|
||||||
func (st *stack) pop() (stacker, error) {
|
|
||||||
if len(*st) == 0 {
|
|
||||||
return nil, errors.New("Stack is empty.")
|
|
||||||
}
|
|
||||||
newStack := make(stack, len(*st)-1)
|
|
||||||
val := (*st)[len(*st)-1]
|
|
||||||
copy(newStack, (*st)[:len(*st)-1])
|
|
||||||
*st = newStack
|
|
||||||
return val, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize regexes and the static vars (that don't get changed between
|
|
||||||
// calls.
|
|
||||||
func init() {
|
|
||||||
// Initialize the main regex.
|
|
||||||
expStr := strings.Join(exp[:], "|")
|
|
||||||
regex, _ = regexp.Compile(expStr)
|
|
||||||
// Initialize the static variables.
|
|
||||||
staticVar = make(map[byte]stacker, 26)
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
// Copyright 2012 Neal van Veen. All rights reserved.
|
|
||||||
// Usage of this source code is governed by a BSD-style license that can be
|
|
||||||
// found in the LICENSE file.
|
|
||||||
|
|
||||||
package gotty
|
|
||||||
|
|
||||||
type TermInfo struct {
|
|
||||||
boolAttributes map[string]bool
|
|
||||||
numAttributes map[string]int16
|
|
||||||
strAttributes map[string]string
|
|
||||||
// The various names of the TermInfo file.
|
|
||||||
Names []string
|
|
||||||
}
|
|
||||||
|
|
||||||
type stacker interface {
|
|
||||||
}
|
|
||||||
type stack []stacker
|
|
||||||
|
|
||||||
type parser struct {
|
|
||||||
st stack
|
|
||||||
parameters []stacker
|
|
||||||
dynamicVar map[byte]stacker
|
|
||||||
}
|
|
|
@ -142,6 +142,16 @@ type PluginConfig struct {
|
||||||
// Log line longer than the limit will be split into multiple lines. Non-positive
|
// Log line longer than the limit will be split into multiple lines. Non-positive
|
||||||
// value means no limit.
|
// value means no limit.
|
||||||
MaxContainerLogLineSize int `toml:"max_container_log_line_size" json:"maxContainerLogSize"`
|
MaxContainerLogLineSize int `toml:"max_container_log_line_size" json:"maxContainerLogSize"`
|
||||||
|
// DisableCgroup indicates to disable the cgroup support.
|
||||||
|
// This is useful when the containerd does not have permission to access cgroup.
|
||||||
|
DisableCgroup bool `toml:"disable_cgroup" json:"disableCgroup"`
|
||||||
|
// DisableApparmor indicates to disable the apparmor support.
|
||||||
|
// This is useful when the containerd does not have permission to access Apparmor.
|
||||||
|
DisableApparmor bool `toml:"disable_apparmor" json:"disableApparmor"`
|
||||||
|
// RestrictOOMScoreAdj indicates to limit the lower bound of OOMScoreAdj to the containerd's
|
||||||
|
// current OOMScoreADj.
|
||||||
|
// This is useful when the containerd does not have permission to decrease OOMScoreAdj.
|
||||||
|
RestrictOOMScoreAdj bool `toml:"restrict_oom_score_adj" json:"restrictOOMScoreAdj"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// X509KeyPairStreaming contains the x509 configuration for streaming
|
// X509KeyPairStreaming contains the x509 configuration for streaming
|
||||||
|
|
|
@ -416,12 +416,18 @@ func (c *criService) generateContainerSpec(id string, sandboxID string, sandboxP
|
||||||
|
|
||||||
g.SetRootReadonly(securityContext.GetReadonlyRootfs())
|
g.SetRootReadonly(securityContext.GetReadonlyRootfs())
|
||||||
|
|
||||||
setOCILinuxResource(&g, config.GetLinux().GetResources())
|
if c.config.DisableCgroup {
|
||||||
|
g.SetLinuxCgroupsPath("")
|
||||||
if sandboxConfig.GetLinux().GetCgroupParent() != "" {
|
} else {
|
||||||
cgroupsPath := getCgroupsPath(sandboxConfig.GetLinux().GetCgroupParent(), id,
|
setOCILinuxResourceCgroup(&g, config.GetLinux().GetResources())
|
||||||
c.config.SystemdCgroup)
|
if sandboxConfig.GetLinux().GetCgroupParent() != "" {
|
||||||
g.SetLinuxCgroupsPath(cgroupsPath)
|
cgroupsPath := getCgroupsPath(sandboxConfig.GetLinux().GetCgroupParent(), id,
|
||||||
|
c.config.SystemdCgroup)
|
||||||
|
g.SetLinuxCgroupsPath(cgroupsPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := setOCILinuxResourceOOMScoreAdj(&g, config.GetLinux().GetResources(), c.config.RestrictOOMScoreAdj); err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set namespaces, share namespace with sandbox container.
|
// Set namespaces, share namespace with sandbox container.
|
||||||
|
@ -759,8 +765,8 @@ func setOCIBindMountsPrivileged(g *generator) {
|
||||||
spec.Linux.MaskedPaths = nil
|
spec.Linux.MaskedPaths = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// setOCILinuxResource set container resource limit.
|
// setOCILinuxResourceCgroup set container cgroup resource limit.
|
||||||
func setOCILinuxResource(g *generator, resources *runtime.LinuxContainerResources) {
|
func setOCILinuxResourceCgroup(g *generator, resources *runtime.LinuxContainerResources) {
|
||||||
if resources == nil {
|
if resources == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -768,11 +774,28 @@ func setOCILinuxResource(g *generator, resources *runtime.LinuxContainerResource
|
||||||
g.SetLinuxResourcesCPUQuota(resources.GetCpuQuota())
|
g.SetLinuxResourcesCPUQuota(resources.GetCpuQuota())
|
||||||
g.SetLinuxResourcesCPUShares(uint64(resources.GetCpuShares()))
|
g.SetLinuxResourcesCPUShares(uint64(resources.GetCpuShares()))
|
||||||
g.SetLinuxResourcesMemoryLimit(resources.GetMemoryLimitInBytes())
|
g.SetLinuxResourcesMemoryLimit(resources.GetMemoryLimitInBytes())
|
||||||
g.SetProcessOOMScoreAdj(int(resources.GetOomScoreAdj()))
|
|
||||||
g.SetLinuxResourcesCPUCpus(resources.GetCpusetCpus())
|
g.SetLinuxResourcesCPUCpus(resources.GetCpusetCpus())
|
||||||
g.SetLinuxResourcesCPUMems(resources.GetCpusetMems())
|
g.SetLinuxResourcesCPUMems(resources.GetCpusetMems())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setOCILinuxResourceOOMScoreAdj set container OOMScoreAdj resource limit.
|
||||||
|
func setOCILinuxResourceOOMScoreAdj(g *generator, resources *runtime.LinuxContainerResources, restrictOOMScoreAdjFlag bool) error {
|
||||||
|
if resources == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
adj := int(resources.GetOomScoreAdj())
|
||||||
|
if restrictOOMScoreAdjFlag {
|
||||||
|
var err error
|
||||||
|
adj, err = restrictOOMScoreAdj(adj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.SetProcessOOMScoreAdj(adj)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// getOCICapabilitiesList returns a list of all available capabilities.
|
// getOCICapabilitiesList returns a list of all available capabilities.
|
||||||
func getOCICapabilitiesList() []string {
|
func getOCICapabilitiesList() []string {
|
||||||
var caps []string
|
var caps []string
|
||||||
|
|
|
@ -18,6 +18,7 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -143,9 +144,9 @@ const (
|
||||||
// generated is unique as long as sandbox metadata is unique.
|
// generated is unique as long as sandbox metadata is unique.
|
||||||
func makeSandboxName(s *runtime.PodSandboxMetadata) string {
|
func makeSandboxName(s *runtime.PodSandboxMetadata) string {
|
||||||
return strings.Join([]string{
|
return strings.Join([]string{
|
||||||
s.Name, // 0
|
s.Name, // 0
|
||||||
s.Namespace, // 1
|
s.Namespace, // 1
|
||||||
s.Uid, // 2
|
s.Uid, // 2
|
||||||
fmt.Sprintf("%d", s.Attempt), // 3
|
fmt.Sprintf("%d", s.Attempt), // 3
|
||||||
}, nameDelimiter)
|
}, nameDelimiter)
|
||||||
}
|
}
|
||||||
|
@ -155,10 +156,10 @@ func makeSandboxName(s *runtime.PodSandboxMetadata) string {
|
||||||
// unique.
|
// unique.
|
||||||
func makeContainerName(c *runtime.ContainerMetadata, s *runtime.PodSandboxMetadata) string {
|
func makeContainerName(c *runtime.ContainerMetadata, s *runtime.PodSandboxMetadata) string {
|
||||||
return strings.Join([]string{
|
return strings.Join([]string{
|
||||||
c.Name, // 0
|
c.Name, // 0
|
||||||
s.Name, // 1: pod name
|
s.Name, // 1: pod name
|
||||||
s.Namespace, // 2: pod namespace
|
s.Namespace, // 2: pod namespace
|
||||||
s.Uid, // 3: pod uid
|
s.Uid, // 3: pod uid
|
||||||
fmt.Sprintf("%d", c.Attempt), // 4
|
fmt.Sprintf("%d", c.Attempt), // 4
|
||||||
}, nameDelimiter)
|
}, nameDelimiter)
|
||||||
}
|
}
|
||||||
|
@ -603,3 +604,27 @@ func getTaskStatus(ctx context.Context, task containerd.Task) (containerd.Status
|
||||||
}
|
}
|
||||||
return status, nil
|
return status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCurrentOOMScoreAdj() (int, error) {
|
||||||
|
b, err := ioutil.ReadFile("/proc/self/oom_score_adj")
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Wrap(err, "could not get the daemon oom_score_adj")
|
||||||
|
}
|
||||||
|
s := strings.TrimSpace(string(b))
|
||||||
|
i, err := strconv.Atoi(s)
|
||||||
|
if err != nil {
|
||||||
|
return 0, errors.Wrap(err, "could not get the daemon oom_score_adj")
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func restrictOOMScoreAdj(preferredOOMScoreAdj int) (int, error) {
|
||||||
|
currentOOMScoreAdj, err := getCurrentOOMScoreAdj()
|
||||||
|
if err != nil {
|
||||||
|
return preferredOOMScoreAdj, err
|
||||||
|
}
|
||||||
|
if preferredOOMScoreAdj < currentOOMScoreAdj {
|
||||||
|
return currentOOMScoreAdj, nil
|
||||||
|
}
|
||||||
|
return preferredOOMScoreAdj, nil
|
||||||
|
}
|
||||||
|
|
|
@ -371,10 +371,14 @@ func (c *criService) generateSandboxContainerSpec(id string, config *runtime.Pod
|
||||||
// TODO(random-liu): [P2] Consider whether to add labels and annotations to the container.
|
// TODO(random-liu): [P2] Consider whether to add labels and annotations to the container.
|
||||||
|
|
||||||
// Set cgroups parent.
|
// Set cgroups parent.
|
||||||
if config.GetLinux().GetCgroupParent() != "" {
|
if c.config.DisableCgroup {
|
||||||
cgroupsPath := getCgroupsPath(config.GetLinux().GetCgroupParent(), id,
|
g.SetLinuxCgroupsPath("")
|
||||||
c.config.SystemdCgroup)
|
} else {
|
||||||
g.SetLinuxCgroupsPath(cgroupsPath)
|
if config.GetLinux().GetCgroupParent() != "" {
|
||||||
|
cgroupsPath := getCgroupsPath(config.GetLinux().GetCgroupParent(), id,
|
||||||
|
c.config.SystemdCgroup)
|
||||||
|
g.SetLinuxCgroupsPath(cgroupsPath)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// When cgroup parent is not set, containerd-shim will create container in a child cgroup
|
// When cgroup parent is not set, containerd-shim will create container in a child cgroup
|
||||||
// of the cgroup itself is in.
|
// of the cgroup itself is in.
|
||||||
|
@ -431,8 +435,17 @@ func (c *criService) generateSandboxContainerSpec(id string, config *runtime.Pod
|
||||||
|
|
||||||
// Note: LinuxSandboxSecurityContext does not currently provide an apparmor profile
|
// Note: LinuxSandboxSecurityContext does not currently provide an apparmor profile
|
||||||
|
|
||||||
g.SetLinuxResourcesCPUShares(uint64(defaultSandboxCPUshares))
|
if !c.config.DisableCgroup {
|
||||||
g.SetProcessOOMScoreAdj(int(defaultSandboxOOMAdj))
|
g.SetLinuxResourcesCPUShares(uint64(defaultSandboxCPUshares))
|
||||||
|
}
|
||||||
|
adj := int(defaultSandboxOOMAdj)
|
||||||
|
if c.config.RestrictOOMScoreAdj {
|
||||||
|
adj, err = restrictOOMScoreAdj(adj)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.SetProcessOOMScoreAdj(adj)
|
||||||
|
|
||||||
g.AddAnnotation(annotations.ContainerType, annotations.ContainerTypeSandbox)
|
g.AddAnnotation(annotations.ContainerType, annotations.ContainerTypeSandbox)
|
||||||
g.AddAnnotation(annotations.SandboxID, id)
|
g.AddAnnotation(annotations.SandboxID, id)
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
cni "github.com/containerd/go-cni"
|
cni "github.com/containerd/go-cni"
|
||||||
runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor"
|
runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor"
|
||||||
runcseccomp "github.com/opencontainers/runc/libcontainer/seccomp"
|
runcseccomp "github.com/opencontainers/runc/libcontainer/seccomp"
|
||||||
|
runcsystem "github.com/opencontainers/runc/libcontainer/system"
|
||||||
"github.com/opencontainers/selinux/go-selinux"
|
"github.com/opencontainers/selinux/go-selinux"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -108,7 +109,7 @@ func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIServi
|
||||||
c := &criService{
|
c := &criService{
|
||||||
config: config,
|
config: config,
|
||||||
client: client,
|
client: client,
|
||||||
apparmorEnabled: runcapparmor.IsEnabled(),
|
apparmorEnabled: runcapparmor.IsEnabled() && !config.DisableApparmor,
|
||||||
seccompEnabled: runcseccomp.IsEnabled(),
|
seccompEnabled: runcseccomp.IsEnabled(),
|
||||||
os: osinterface.RealOS{},
|
os: osinterface.RealOS{},
|
||||||
sandboxStore: sandboxstore.NewStore(),
|
sandboxStore: sandboxstore.NewStore(),
|
||||||
|
@ -120,6 +121,12 @@ func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIServi
|
||||||
initialized: atomic.NewBool(false),
|
initialized: atomic.NewBool(false),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if runcsystem.RunningInUserNS() {
|
||||||
|
if !(config.DisableCgroup && !c.apparmorEnabled && config.RestrictOOMScoreAdj) {
|
||||||
|
logrus.Warn("Running containerd in a user namespace typically requires disable_cgroup, disable_apparmor, restrict_oom_score_adj set to be true")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if c.config.EnableSelinux {
|
if c.config.EnableSelinux {
|
||||||
if !selinux.GetEnabled() {
|
if !selinux.GetEnabled() {
|
||||||
logrus.Warn("Selinux is not supported")
|
logrus.Warn("Selinux is not supported")
|
||||||
|
|
267
vendor/github.com/docker/distribution/registry/api/errcode/errors.go
generated
vendored
Normal file
267
vendor/github.com/docker/distribution/registry/api/errcode/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
package errcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrorCoder is the base interface for ErrorCode and Error allowing
|
||||||
|
// users of each to just call ErrorCode to get the real ID of each
|
||||||
|
type ErrorCoder interface {
|
||||||
|
ErrorCode() ErrorCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorCode represents the error type. The errors are serialized via strings
|
||||||
|
// and the integer format may change and should *never* be exported.
|
||||||
|
type ErrorCode int
|
||||||
|
|
||||||
|
var _ error = ErrorCode(0)
|
||||||
|
|
||||||
|
// ErrorCode just returns itself
|
||||||
|
func (ec ErrorCode) ErrorCode() ErrorCode {
|
||||||
|
return ec
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns the ID/Value
|
||||||
|
func (ec ErrorCode) Error() string {
|
||||||
|
// NOTE(stevvooe): Cannot use message here since it may have unpopulated args.
|
||||||
|
return strings.ToLower(strings.Replace(ec.String(), "_", " ", -1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Descriptor returns the descriptor for the error code.
|
||||||
|
func (ec ErrorCode) Descriptor() ErrorDescriptor {
|
||||||
|
d, ok := errorCodeToDescriptors[ec]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return ErrorCodeUnknown.Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the canonical identifier for this error code.
|
||||||
|
func (ec ErrorCode) String() string {
|
||||||
|
return ec.Descriptor().Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message returned the human-readable error message for this error code.
|
||||||
|
func (ec ErrorCode) Message() string {
|
||||||
|
return ec.Descriptor().Message
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalText encodes the receiver into UTF-8-encoded text and returns the
|
||||||
|
// result.
|
||||||
|
func (ec ErrorCode) MarshalText() (text []byte, err error) {
|
||||||
|
return []byte(ec.String()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalText decodes the form generated by MarshalText.
|
||||||
|
func (ec *ErrorCode) UnmarshalText(text []byte) error {
|
||||||
|
desc, ok := idToDescriptors[string(text)]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
desc = ErrorCodeUnknown.Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
*ec = desc.Code
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMessage creates a new Error struct based on the passed-in info and
|
||||||
|
// overrides the Message property.
|
||||||
|
func (ec ErrorCode) WithMessage(message string) Error {
|
||||||
|
return Error{
|
||||||
|
Code: ec,
|
||||||
|
Message: message,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDetail creates a new Error struct based on the passed-in info and
|
||||||
|
// set the Detail property appropriately
|
||||||
|
func (ec ErrorCode) WithDetail(detail interface{}) Error {
|
||||||
|
return Error{
|
||||||
|
Code: ec,
|
||||||
|
Message: ec.Message(),
|
||||||
|
}.WithDetail(detail)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithArgs creates a new Error struct and sets the Args slice
|
||||||
|
func (ec ErrorCode) WithArgs(args ...interface{}) Error {
|
||||||
|
return Error{
|
||||||
|
Code: ec,
|
||||||
|
Message: ec.Message(),
|
||||||
|
}.WithArgs(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error provides a wrapper around ErrorCode with extra Details provided.
|
||||||
|
type Error struct {
|
||||||
|
Code ErrorCode `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Detail interface{} `json:"detail,omitempty"`
|
||||||
|
|
||||||
|
// TODO(duglin): See if we need an "args" property so we can do the
|
||||||
|
// variable substitution right before showing the message to the user
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ error = Error{}
|
||||||
|
|
||||||
|
// ErrorCode returns the ID/Value of this Error
|
||||||
|
func (e Error) ErrorCode() ErrorCode {
|
||||||
|
return e.Code
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error returns a human readable representation of the error.
|
||||||
|
func (e Error) Error() string {
|
||||||
|
return fmt.Sprintf("%s: %s", e.Code.Error(), e.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDetail will return a new Error, based on the current one, but with
|
||||||
|
// some Detail info added
|
||||||
|
func (e Error) WithDetail(detail interface{}) Error {
|
||||||
|
return Error{
|
||||||
|
Code: e.Code,
|
||||||
|
Message: e.Message,
|
||||||
|
Detail: detail,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithArgs uses the passed-in list of interface{} as the substitution
|
||||||
|
// variables in the Error's Message string, but returns a new Error
|
||||||
|
func (e Error) WithArgs(args ...interface{}) Error {
|
||||||
|
return Error{
|
||||||
|
Code: e.Code,
|
||||||
|
Message: fmt.Sprintf(e.Code.Message(), args...),
|
||||||
|
Detail: e.Detail,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrorDescriptor provides relevant information about a given error code.
|
||||||
|
type ErrorDescriptor struct {
|
||||||
|
// Code is the error code that this descriptor describes.
|
||||||
|
Code ErrorCode
|
||||||
|
|
||||||
|
// Value provides a unique, string key, often captilized with
|
||||||
|
// underscores, to identify the error code. This value is used as the
|
||||||
|
// keyed value when serializing api errors.
|
||||||
|
Value string
|
||||||
|
|
||||||
|
// Message is a short, human readable decription of the error condition
|
||||||
|
// included in API responses.
|
||||||
|
Message string
|
||||||
|
|
||||||
|
// Description provides a complete account of the errors purpose, suitable
|
||||||
|
// for use in documentation.
|
||||||
|
Description string
|
||||||
|
|
||||||
|
// HTTPStatusCode provides the http status code that is associated with
|
||||||
|
// this error condition.
|
||||||
|
HTTPStatusCode int
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseErrorCode returns the value by the string error code.
|
||||||
|
// `ErrorCodeUnknown` will be returned if the error is not known.
|
||||||
|
func ParseErrorCode(value string) ErrorCode {
|
||||||
|
ed, ok := idToDescriptors[value]
|
||||||
|
if ok {
|
||||||
|
return ed.Code
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorCodeUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errors provides the envelope for multiple errors and a few sugar methods
|
||||||
|
// for use within the application.
|
||||||
|
type Errors []error
|
||||||
|
|
||||||
|
var _ error = Errors{}
|
||||||
|
|
||||||
|
func (errs Errors) Error() string {
|
||||||
|
switch len(errs) {
|
||||||
|
case 0:
|
||||||
|
return "<nil>"
|
||||||
|
case 1:
|
||||||
|
return errs[0].Error()
|
||||||
|
default:
|
||||||
|
msg := "errors:\n"
|
||||||
|
for _, err := range errs {
|
||||||
|
msg += err.Error() + "\n"
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the current number of errors.
|
||||||
|
func (errs Errors) Len() int {
|
||||||
|
return len(errs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON converts slice of error, ErrorCode or Error into a
|
||||||
|
// slice of Error - then serializes
|
||||||
|
func (errs Errors) MarshalJSON() ([]byte, error) {
|
||||||
|
var tmpErrs struct {
|
||||||
|
Errors []Error `json:"errors,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, daErr := range errs {
|
||||||
|
var err Error
|
||||||
|
|
||||||
|
switch daErr := daErr.(type) {
|
||||||
|
case ErrorCode:
|
||||||
|
err = daErr.WithDetail(nil)
|
||||||
|
case Error:
|
||||||
|
err = daErr
|
||||||
|
default:
|
||||||
|
err = ErrorCodeUnknown.WithDetail(daErr)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the Error struct was setup and they forgot to set the
|
||||||
|
// Message field (meaning its "") then grab it from the ErrCode
|
||||||
|
msg := err.Message
|
||||||
|
if msg == "" {
|
||||||
|
msg = err.Code.Message()
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpErrs.Errors = append(tmpErrs.Errors, Error{
|
||||||
|
Code: err.Code,
|
||||||
|
Message: msg,
|
||||||
|
Detail: err.Detail,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return json.Marshal(tmpErrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON deserializes []Error and then converts it into slice of
|
||||||
|
// Error or ErrorCode
|
||||||
|
func (errs *Errors) UnmarshalJSON(data []byte) error {
|
||||||
|
var tmpErrs struct {
|
||||||
|
Errors []Error
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(data, &tmpErrs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var newErrs Errors
|
||||||
|
for _, daErr := range tmpErrs.Errors {
|
||||||
|
// If Message is empty or exactly matches the Code's message string
|
||||||
|
// then just use the Code, no need for a full Error struct
|
||||||
|
if daErr.Detail == nil && (daErr.Message == "" || daErr.Message == daErr.Code.Message()) {
|
||||||
|
// Error's w/o details get converted to ErrorCode
|
||||||
|
newErrs = append(newErrs, daErr.Code)
|
||||||
|
} else {
|
||||||
|
// Error's w/ details are untouched
|
||||||
|
newErrs = append(newErrs, Error{
|
||||||
|
Code: daErr.Code,
|
||||||
|
Message: daErr.Message,
|
||||||
|
Detail: daErr.Detail,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*errs = newErrs
|
||||||
|
return nil
|
||||||
|
}
|
40
vendor/github.com/docker/distribution/registry/api/errcode/handler.go
generated
vendored
Normal file
40
vendor/github.com/docker/distribution/registry/api/errcode/handler.go
generated
vendored
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
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)
|
||||||
|
}
|
138
vendor/github.com/docker/distribution/registry/api/errcode/register.go
generated
vendored
Normal file
138
vendor/github.com/docker/distribution/registry/api/errcode/register.go
generated
vendored
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
package errcode
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"sort"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errorCodeToDescriptors = map[ErrorCode]ErrorDescriptor{}
|
||||||
|
idToDescriptors = map[string]ErrorDescriptor{}
|
||||||
|
groupToDescriptors = map[string][]ErrorDescriptor{}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrorCodeUnknown is a generic error that can be used as a last
|
||||||
|
// resort if there is no situation-specific error message that can be used
|
||||||
|
ErrorCodeUnknown = Register("errcode", ErrorDescriptor{
|
||||||
|
Value: "UNKNOWN",
|
||||||
|
Message: "unknown error",
|
||||||
|
Description: `Generic error returned when the error does not have an
|
||||||
|
API classification.`,
|
||||||
|
HTTPStatusCode: http.StatusInternalServerError,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ErrorCodeUnsupported is returned when an operation is not supported.
|
||||||
|
ErrorCodeUnsupported = Register("errcode", ErrorDescriptor{
|
||||||
|
Value: "UNSUPPORTED",
|
||||||
|
Message: "The operation is unsupported.",
|
||||||
|
Description: `The operation was unsupported due to a missing
|
||||||
|
implementation or invalid set of parameters.`,
|
||||||
|
HTTPStatusCode: http.StatusMethodNotAllowed,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ErrorCodeUnauthorized is returned if a request requires
|
||||||
|
// authentication.
|
||||||
|
ErrorCodeUnauthorized = Register("errcode", ErrorDescriptor{
|
||||||
|
Value: "UNAUTHORIZED",
|
||||||
|
Message: "authentication required",
|
||||||
|
Description: `The access controller was unable to authenticate
|
||||||
|
the client. Often this will be accompanied by a
|
||||||
|
Www-Authenticate HTTP response header indicating how to
|
||||||
|
authenticate.`,
|
||||||
|
HTTPStatusCode: http.StatusUnauthorized,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ErrorCodeDenied is returned if a client does not have sufficient
|
||||||
|
// permission to perform an action.
|
||||||
|
ErrorCodeDenied = Register("errcode", ErrorDescriptor{
|
||||||
|
Value: "DENIED",
|
||||||
|
Message: "requested access to the resource is denied",
|
||||||
|
Description: `The access controller denied access for the
|
||||||
|
operation on a resource.`,
|
||||||
|
HTTPStatusCode: http.StatusForbidden,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ErrorCodeUnavailable provides a common error to report unavailability
|
||||||
|
// of a service or endpoint.
|
||||||
|
ErrorCodeUnavailable = Register("errcode", ErrorDescriptor{
|
||||||
|
Value: "UNAVAILABLE",
|
||||||
|
Message: "service unavailable",
|
||||||
|
Description: "Returned when a service is not available",
|
||||||
|
HTTPStatusCode: http.StatusServiceUnavailable,
|
||||||
|
})
|
||||||
|
|
||||||
|
// ErrorCodeTooManyRequests is returned if a client attempts too many
|
||||||
|
// times to contact a service endpoint.
|
||||||
|
ErrorCodeTooManyRequests = Register("errcode", ErrorDescriptor{
|
||||||
|
Value: "TOOMANYREQUESTS",
|
||||||
|
Message: "too many requests",
|
||||||
|
Description: `Returned when a client attempts to contact a
|
||||||
|
service too many times`,
|
||||||
|
HTTPStatusCode: http.StatusTooManyRequests,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
var nextCode = 1000
|
||||||
|
var registerLock sync.Mutex
|
||||||
|
|
||||||
|
// Register will make the passed-in error known to the environment and
|
||||||
|
// return a new ErrorCode
|
||||||
|
func Register(group string, descriptor ErrorDescriptor) ErrorCode {
|
||||||
|
registerLock.Lock()
|
||||||
|
defer registerLock.Unlock()
|
||||||
|
|
||||||
|
descriptor.Code = ErrorCode(nextCode)
|
||||||
|
|
||||||
|
if _, ok := idToDescriptors[descriptor.Value]; ok {
|
||||||
|
panic(fmt.Sprintf("ErrorValue %q is already registered", descriptor.Value))
|
||||||
|
}
|
||||||
|
if _, ok := errorCodeToDescriptors[descriptor.Code]; ok {
|
||||||
|
panic(fmt.Sprintf("ErrorCode %v is already registered", descriptor.Code))
|
||||||
|
}
|
||||||
|
|
||||||
|
groupToDescriptors[group] = append(groupToDescriptors[group], descriptor)
|
||||||
|
errorCodeToDescriptors[descriptor.Code] = descriptor
|
||||||
|
idToDescriptors[descriptor.Value] = descriptor
|
||||||
|
|
||||||
|
nextCode++
|
||||||
|
return descriptor.Code
|
||||||
|
}
|
||||||
|
|
||||||
|
type byValue []ErrorDescriptor
|
||||||
|
|
||||||
|
func (a byValue) Len() int { return len(a) }
|
||||||
|
func (a byValue) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
func (a byValue) Less(i, j int) bool { return a[i].Value < a[j].Value }
|
||||||
|
|
||||||
|
// GetGroupNames returns the list of Error group names that are registered
|
||||||
|
func GetGroupNames() []string {
|
||||||
|
keys := []string{}
|
||||||
|
|
||||||
|
for k := range groupToDescriptors {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetErrorCodeGroup returns the named group of error descriptors
|
||||||
|
func GetErrorCodeGroup(name string) []ErrorDescriptor {
|
||||||
|
desc := groupToDescriptors[name]
|
||||||
|
sort.Sort(byValue(desc))
|
||||||
|
return desc
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetErrorAllDescriptors returns a slice of all ErrorDescriptors that are
|
||||||
|
// registered, irrespective of what group they're in
|
||||||
|
func GetErrorAllDescriptors() []ErrorDescriptor {
|
||||||
|
result := []ErrorDescriptor{}
|
||||||
|
|
||||||
|
for _, group := range GetGroupNames() {
|
||||||
|
result = append(result, GetErrorCodeGroup(group)...)
|
||||||
|
}
|
||||||
|
sort.Sort(byValue(result))
|
||||||
|
return result
|
||||||
|
}
|
|
@ -7,7 +7,9 @@ curators:
|
||||||
- ehazlett
|
- ehazlett
|
||||||
- fntlnz
|
- fntlnz
|
||||||
- gianarb
|
- gianarb
|
||||||
|
- kolyshkin
|
||||||
- mgoelzer
|
- mgoelzer
|
||||||
|
- olljanat
|
||||||
- programmerq
|
- programmerq
|
||||||
- rheinwein
|
- rheinwein
|
||||||
- ripcurld0
|
- ripcurld0
|
||||||
|
@ -15,3 +17,5 @@ curators:
|
||||||
|
|
||||||
features:
|
features:
|
||||||
- comments
|
- comments
|
||||||
|
- pr_description_required
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,8 @@ Allen Sun <allensun.shl@alibaba-inc.com> <allen.sun@daocloud.io>
|
||||||
Allen Sun <allensun.shl@alibaba-inc.com> <shlallen1990@gmail.com>
|
Allen Sun <allensun.shl@alibaba-inc.com> <shlallen1990@gmail.com>
|
||||||
Andrew Weiss <andrew.weiss@docker.com> <andrew.weiss@microsoft.com>
|
Andrew Weiss <andrew.weiss@docker.com> <andrew.weiss@microsoft.com>
|
||||||
Andrew Weiss <andrew.weiss@docker.com> <andrew.weiss@outlook.com>
|
Andrew Weiss <andrew.weiss@docker.com> <andrew.weiss@outlook.com>
|
||||||
|
Andrey Kolomentsev <andrey.kolomentsev@docker.com>
|
||||||
|
Andrey Kolomentsev <andrey.kolomentsev@docker.com> <andrey.kolomentsev@gmail.com>
|
||||||
André Martins <aanm90@gmail.com> <martins@noironetworks.com>
|
André Martins <aanm90@gmail.com> <martins@noironetworks.com>
|
||||||
Andy Rothfusz <github@developersupport.net> <github@metaliveblog.com>
|
Andy Rothfusz <github@developersupport.net> <github@metaliveblog.com>
|
||||||
Andy Smith <github@anarkystic.com>
|
Andy Smith <github@anarkystic.com>
|
||||||
|
@ -55,9 +57,11 @@ Ben Bonnefoy <frenchben@docker.com>
|
||||||
Ben Golub <ben.golub@dotcloud.com>
|
Ben Golub <ben.golub@dotcloud.com>
|
||||||
Ben Toews <mastahyeti@gmail.com> <mastahyeti@users.noreply.github.com>
|
Ben Toews <mastahyeti@gmail.com> <mastahyeti@users.noreply.github.com>
|
||||||
Benoit Chesneau <bchesneau@gmail.com>
|
Benoit Chesneau <bchesneau@gmail.com>
|
||||||
|
Bevisy Zhang <binbin36520@gmail.com>
|
||||||
Bhiraj Butala <abhiraj.butala@gmail.com>
|
Bhiraj Butala <abhiraj.butala@gmail.com>
|
||||||
Bhumika Bayani <bhumikabayani@gmail.com>
|
Bhumika Bayani <bhumikabayani@gmail.com>
|
||||||
Bilal Amarni <bilal.amarni@gmail.com> <bamarni@users.noreply.github.com>
|
Bilal Amarni <bilal.amarni@gmail.com> <bamarni@users.noreply.github.com>
|
||||||
|
Bily Zhang <xcoder@tenxcloud.com>
|
||||||
Bill Wang <ozbillwang@gmail.com> <SydOps@users.noreply.github.com>
|
Bill Wang <ozbillwang@gmail.com> <SydOps@users.noreply.github.com>
|
||||||
Bin Liu <liubin0329@gmail.com>
|
Bin Liu <liubin0329@gmail.com>
|
||||||
Bin Liu <liubin0329@gmail.com> <liubin0329@users.noreply.github.com>
|
Bin Liu <liubin0329@gmail.com> <liubin0329@users.noreply.github.com>
|
||||||
|
@ -77,6 +81,7 @@ Chen Chuanliang <chen.chuanliang@zte.com.cn>
|
||||||
Chen Mingjie <chenmingjie0828@163.com>
|
Chen Mingjie <chenmingjie0828@163.com>
|
||||||
Chen Qiu <cheney-90@hotmail.com>
|
Chen Qiu <cheney-90@hotmail.com>
|
||||||
Chen Qiu <cheney-90@hotmail.com> <21321229@zju.edu.cn>
|
Chen Qiu <cheney-90@hotmail.com> <21321229@zju.edu.cn>
|
||||||
|
Chengfei Shang <cfshang@alauda.io>
|
||||||
Chris Dias <cdias@microsoft.com>
|
Chris Dias <cdias@microsoft.com>
|
||||||
Chris McKinnel <chris.mckinnel@tangentlabs.co.uk>
|
Chris McKinnel <chris.mckinnel@tangentlabs.co.uk>
|
||||||
Christopher Biscardi <biscarch@sketcht.com>
|
Christopher Biscardi <biscarch@sketcht.com>
|
||||||
|
@ -97,6 +102,7 @@ Daniel Garcia <daniel@danielgarcia.info>
|
||||||
Daniel Gasienica <daniel@gasienica.ch> <dgasienica@zynga.com>
|
Daniel Gasienica <daniel@gasienica.ch> <dgasienica@zynga.com>
|
||||||
Daniel Goosen <daniel.goosen@surveysampling.com> <djgoosen@users.noreply.github.com>
|
Daniel Goosen <daniel.goosen@surveysampling.com> <djgoosen@users.noreply.github.com>
|
||||||
Daniel Grunwell <mwgrunny@gmail.com>
|
Daniel Grunwell <mwgrunny@gmail.com>
|
||||||
|
Daniel Hiltgen <daniel.hiltgen@docker.com> <dhiltgen@users.noreply.github.com>
|
||||||
Daniel J Walsh <dwalsh@redhat.com>
|
Daniel J Walsh <dwalsh@redhat.com>
|
||||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> <daniel@dotcloud.com>
|
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> <daniel@dotcloud.com>
|
||||||
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> <mzdaniel@glidelink.net>
|
Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> <mzdaniel@glidelink.net>
|
||||||
|
@ -104,6 +110,7 @@ Daniel Mizyrycki <daniel.mizyrycki@dotcloud.com> <root@vagrant-ubuntu-12.10.vagr
|
||||||
Daniel Nephin <dnephin@docker.com> <dnephin@gmail.com>
|
Daniel Nephin <dnephin@docker.com> <dnephin@gmail.com>
|
||||||
Daniel Norberg <dano@spotify.com> <daniel.norberg@gmail.com>
|
Daniel Norberg <dano@spotify.com> <daniel.norberg@gmail.com>
|
||||||
Daniel Watkins <daniel@daniel-watkins.co.uk>
|
Daniel Watkins <daniel@daniel-watkins.co.uk>
|
||||||
|
Daniel Zhang <jmzwcn@gmail.com>
|
||||||
Danny Yates <danny@codeaholics.org> <Danny.Yates@mailonline.co.uk>
|
Danny Yates <danny@codeaholics.org> <Danny.Yates@mailonline.co.uk>
|
||||||
Darren Shepherd <darren.s.shepherd@gmail.com> <darren@rancher.com>
|
Darren Shepherd <darren.s.shepherd@gmail.com> <darren@rancher.com>
|
||||||
Dattatraya Kumbhar <dattatraya.kumbhar@gslab.com>
|
Dattatraya Kumbhar <dattatraya.kumbhar@gslab.com>
|
||||||
|
@ -149,6 +156,7 @@ Frederick F. Kautz IV <fkautz@redhat.com> <fkautz@alumni.cmu.edu>
|
||||||
Gabriel Nicolas Avellaneda <avellaneda.gabriel@gmail.com>
|
Gabriel Nicolas Avellaneda <avellaneda.gabriel@gmail.com>
|
||||||
Gaetan de Villele <gdevillele@gmail.com>
|
Gaetan de Villele <gdevillele@gmail.com>
|
||||||
Gang Qiao <qiaohai8866@gmail.com> <1373319223@qq.com>
|
Gang Qiao <qiaohai8866@gmail.com> <1373319223@qq.com>
|
||||||
|
Geon Kim <geon0250@gmail.com>
|
||||||
George Kontridze <george@bugsnag.com>
|
George Kontridze <george@bugsnag.com>
|
||||||
Gerwim Feiken <g.feiken@tfe.nl> <gerwim@gmail.com>
|
Gerwim Feiken <g.feiken@tfe.nl> <gerwim@gmail.com>
|
||||||
Giampaolo Mancini <giampaolo@trampolineup.com>
|
Giampaolo Mancini <giampaolo@trampolineup.com>
|
||||||
|
@ -175,6 +183,7 @@ Harry Zhang <harryz@hyper.sh> <resouer@gmail.com>
|
||||||
Harry Zhang <resouer@163.com>
|
Harry Zhang <resouer@163.com>
|
||||||
Harshal Patil <harshal.patil@in.ibm.com> <harche@users.noreply.github.com>
|
Harshal Patil <harshal.patil@in.ibm.com> <harche@users.noreply.github.com>
|
||||||
Helen Xie <chenjg@harmonycloud.cn>
|
Helen Xie <chenjg@harmonycloud.cn>
|
||||||
|
Hiroyuki Sasagawa <hs19870702@gmail.com>
|
||||||
Hollie Teal <hollie@docker.com>
|
Hollie Teal <hollie@docker.com>
|
||||||
Hollie Teal <hollie@docker.com> <hollie.teal@docker.com>
|
Hollie Teal <hollie@docker.com> <hollie.teal@docker.com>
|
||||||
Hollie Teal <hollie@docker.com> <hollietealok@users.noreply.github.com>
|
Hollie Teal <hollie@docker.com> <hollietealok@users.noreply.github.com>
|
||||||
|
@ -183,26 +192,32 @@ Huu Nguyen <huu@prismskylabs.com> <whoshuu@gmail.com>
|
||||||
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com>
|
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com>
|
||||||
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com> <1187766782@qq.com>
|
Hyzhou Zhy <hyzhou.zhy@alibaba-inc.com> <1187766782@qq.com>
|
||||||
Ilya Khlopotov <ilya.khlopotov@gmail.com>
|
Ilya Khlopotov <ilya.khlopotov@gmail.com>
|
||||||
|
Iskander Sharipov <quasilyte@gmail.com>
|
||||||
Ivan Markin <sw@nogoegst.net> <twim@riseup.net>
|
Ivan Markin <sw@nogoegst.net> <twim@riseup.net>
|
||||||
Jack Laxson <jackjrabbit@gmail.com>
|
Jack Laxson <jackjrabbit@gmail.com>
|
||||||
Jacob Atzen <jacob@jacobatzen.dk> <jatzen@gmail.com>
|
Jacob Atzen <jacob@jacobatzen.dk> <jatzen@gmail.com>
|
||||||
Jacob Tomlinson <jacob@tom.linson.uk> <jacobtomlinson@users.noreply.github.com>
|
Jacob Tomlinson <jacob@tom.linson.uk> <jacobtomlinson@users.noreply.github.com>
|
||||||
Jaivish Kothari <janonymous.codevulture@gmail.com>
|
Jaivish Kothari <janonymous.codevulture@gmail.com>
|
||||||
Jamie Hannaford <jamie@limetree.org> <jamie.hannaford@rackspace.com>
|
Jamie Hannaford <jamie@limetree.org> <jamie.hannaford@rackspace.com>
|
||||||
|
Jean Rouge <rougej+github@gmail.com> <jer329@cornell.edu>
|
||||||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||||
Jean-Tiare Le Bigot <jt@yadutaf.fr> <admin@jtlebi.fr>
|
Jean-Tiare Le Bigot <jt@yadutaf.fr> <admin@jtlebi.fr>
|
||||||
Jeff Anderson <jeff@docker.com> <jefferya@programmerq.net>
|
Jeff Anderson <jeff@docker.com> <jefferya@programmerq.net>
|
||||||
Jeff Nickoloff <jeff.nickoloff@gmail.com> <jeff@allingeek.com>
|
Jeff Nickoloff <jeff.nickoloff@gmail.com> <jeff@allingeek.com>
|
||||||
Jeroen Franse <jeroenfranse@gmail.com>
|
Jeroen Franse <jeroenfranse@gmail.com>
|
||||||
Jessica Frazelle <jessfraz@google.com>
|
Jessica Frazelle <acidburn@microsoft.com>
|
||||||
Jessica Frazelle <jessfraz@google.com> <acidburn@docker.com>
|
Jessica Frazelle <acidburn@microsoft.com> <acidburn@docker.com>
|
||||||
Jessica Frazelle <jessfraz@google.com> <acidburn@google.com>
|
Jessica Frazelle <acidburn@microsoft.com> <acidburn@google.com>
|
||||||
Jessica Frazelle <jessfraz@google.com> <jess@docker.com>
|
Jessica Frazelle <acidburn@microsoft.com> <jess@docker.com>
|
||||||
Jessica Frazelle <jessfraz@google.com> <jess@mesosphere.com>
|
Jessica Frazelle <acidburn@microsoft.com> <jess@mesosphere.com>
|
||||||
Jessica Frazelle <jessfraz@google.com> <jfrazelle@users.noreply.github.com>
|
Jessica Frazelle <acidburn@microsoft.com> <jessfraz@google.com>
|
||||||
Jessica Frazelle <jessfraz@google.com> <me@jessfraz.com>
|
Jessica Frazelle <acidburn@microsoft.com> <jfrazelle@users.noreply.github.com>
|
||||||
Jessica Frazelle <jessfraz@google.com> <princess@docker.com>
|
Jessica Frazelle <acidburn@microsoft.com> <me@jessfraz.com>
|
||||||
|
Jessica Frazelle <acidburn@microsoft.com> <princess@docker.com>
|
||||||
|
Jian Liao <jliao@alauda.io>
|
||||||
|
Jiang Jinyang <jjyruby@gmail.com>
|
||||||
|
Jiang Jinyang <jjyruby@gmail.com> <jiangjinyang@outlook.com>
|
||||||
Jim Galasyn <jim.galasyn@docker.com>
|
Jim Galasyn <jim.galasyn@docker.com>
|
||||||
Jiuyue Ma <majiuyue@huawei.com>
|
Jiuyue Ma <majiuyue@huawei.com>
|
||||||
Joey Geiger <jgeiger@gmail.com>
|
Joey Geiger <jgeiger@gmail.com>
|
||||||
|
@ -223,7 +238,9 @@ Jon Surrell <jon.surrell@gmail.com> <jon.surrell@automattic.com>
|
||||||
Jordan Arentsen <blissdev@gmail.com>
|
Jordan Arentsen <blissdev@gmail.com>
|
||||||
Jordan Jennings <jjn2009@gmail.com> <jjn2009@users.noreply.github.com>
|
Jordan Jennings <jjn2009@gmail.com> <jjn2009@users.noreply.github.com>
|
||||||
Jorit Kleine-Möllhoff <joppich@bricknet.de> <joppich@users.noreply.github.com>
|
Jorit Kleine-Möllhoff <joppich@bricknet.de> <joppich@users.noreply.github.com>
|
||||||
Jose Diaz-Gonzalez <jose@seatgeek.com> <josegonzalez@users.noreply.github.com>
|
Jose Diaz-Gonzalez <email@josediazgonzalez.com>
|
||||||
|
Jose Diaz-Gonzalez <email@josediazgonzalez.com> <jose@seatgeek.com>
|
||||||
|
Jose Diaz-Gonzalez <email@josediazgonzalez.com> <josegonzalez@users.noreply.github.com>
|
||||||
Josh Bonczkowski <josh.bonczkowski@gmail.com>
|
Josh Bonczkowski <josh.bonczkowski@gmail.com>
|
||||||
Josh Eveleth <joshe@opendns.com> <jeveleth@users.noreply.github.com>
|
Josh Eveleth <joshe@opendns.com> <jeveleth@users.noreply.github.com>
|
||||||
Josh Hawn <josh.hawn@docker.com> <jlhawn@berkeley.edu>
|
Josh Hawn <josh.hawn@docker.com> <jlhawn@berkeley.edu>
|
||||||
|
@ -237,6 +254,7 @@ Justin Cormack <justin.cormack@docker.com>
|
||||||
Justin Cormack <justin.cormack@docker.com> <justin.cormack@unikernel.com>
|
Justin Cormack <justin.cormack@docker.com> <justin.cormack@unikernel.com>
|
||||||
Justin Cormack <justin.cormack@docker.com> <justin@specialbusservice.com>
|
Justin Cormack <justin.cormack@docker.com> <justin@specialbusservice.com>
|
||||||
Justin Simonelis <justin.p.simonelis@gmail.com> <justin.simonelis@PTS-JSIMON2.toronto.exclamation.com>
|
Justin Simonelis <justin.p.simonelis@gmail.com> <justin.simonelis@PTS-JSIMON2.toronto.exclamation.com>
|
||||||
|
Justin Terry <juterry@microsoft.com>
|
||||||
Jérôme Petazzoni <jerome.petazzoni@docker.com> <jerome.petazzoni@dotcloud.com>
|
Jérôme Petazzoni <jerome.petazzoni@docker.com> <jerome.petazzoni@dotcloud.com>
|
||||||
Jérôme Petazzoni <jerome.petazzoni@docker.com> <jerome.petazzoni@gmail.com>
|
Jérôme Petazzoni <jerome.petazzoni@docker.com> <jerome.petazzoni@gmail.com>
|
||||||
Jérôme Petazzoni <jerome.petazzoni@docker.com> <jp@enix.org>
|
Jérôme Petazzoni <jerome.petazzoni@docker.com> <jp@enix.org>
|
||||||
|
@ -245,8 +263,11 @@ Kai Qiang Wu (Kennan) <wkq5325@gmail.com>
|
||||||
Kai Qiang Wu (Kennan) <wkq5325@gmail.com> <wkqwu@cn.ibm.com>
|
Kai Qiang Wu (Kennan) <wkq5325@gmail.com> <wkqwu@cn.ibm.com>
|
||||||
Kamil Domański <kamil@domanski.co>
|
Kamil Domański <kamil@domanski.co>
|
||||||
Kamjar Gerami <kami.gerami@gmail.com>
|
Kamjar Gerami <kami.gerami@gmail.com>
|
||||||
|
Karthik Nayak <karthik.188@gmail.com>
|
||||||
|
Karthik Nayak <karthik.188@gmail.com> <Karthik.188@gmail.com>
|
||||||
Ken Cochrane <kencochrane@gmail.com> <KenCochrane@gmail.com>
|
Ken Cochrane <kencochrane@gmail.com> <KenCochrane@gmail.com>
|
||||||
Ken Herner <kherner@progress.com> <chosenken@gmail.com>
|
Ken Herner <kherner@progress.com> <chosenken@gmail.com>
|
||||||
|
Ken Reese <krrgithub@gmail.com>
|
||||||
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
||||||
Kevin Feyrer <kevin.feyrer@btinternet.com> <kevinfeyrer@users.noreply.github.com>
|
Kevin Feyrer <kevin.feyrer@btinternet.com> <kevinfeyrer@users.noreply.github.com>
|
||||||
Kevin Kern <kaiwentan@harmonycloud.cn>
|
Kevin Kern <kaiwentan@harmonycloud.cn>
|
||||||
|
@ -260,6 +281,7 @@ Konstantin Pelykh <kpelykh@zettaset.com>
|
||||||
Kotaro Yoshimatsu <kotaro.yoshimatsu@gmail.com>
|
Kotaro Yoshimatsu <kotaro.yoshimatsu@gmail.com>
|
||||||
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp> <kunal.kushwaha@gmail.com>
|
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp> <kunal.kushwaha@gmail.com>
|
||||||
Lajos Papp <lajos.papp@sequenceiq.com> <lalyos@yahoo.com>
|
Lajos Papp <lajos.papp@sequenceiq.com> <lalyos@yahoo.com>
|
||||||
|
Lei Gong <lgong@alauda.io>
|
||||||
Lei Jitang <leijitang@huawei.com>
|
Lei Jitang <leijitang@huawei.com>
|
||||||
Lei Jitang <leijitang@huawei.com> <leijitang@gmail.com>
|
Lei Jitang <leijitang@huawei.com> <leijitang@gmail.com>
|
||||||
Liang Mingqiang <mqliang.zju@gmail.com>
|
Liang Mingqiang <mqliang.zju@gmail.com>
|
||||||
|
@ -268,7 +290,8 @@ Liao Qingwei <liaoqingwei@huawei.com>
|
||||||
Linus Heckemann <lheckemann@twig-world.com>
|
Linus Heckemann <lheckemann@twig-world.com>
|
||||||
Linus Heckemann <lheckemann@twig-world.com> <anonymouse2048@gmail.com>
|
Linus Heckemann <lheckemann@twig-world.com> <anonymouse2048@gmail.com>
|
||||||
Lokesh Mandvekar <lsm5@fedoraproject.org> <lsm5@redhat.com>
|
Lokesh Mandvekar <lsm5@fedoraproject.org> <lsm5@redhat.com>
|
||||||
Lorenzo Fontana <lo@linux.com> <fontanalorenzo@me.com>
|
Lorenzo Fontana <fontanalorenz@gmail.com> <fontanalorenzo@me.com>
|
||||||
|
Lorenzo Fontana <fontanalorenz@gmail.com> <lo@linux.com>
|
||||||
Louis Opter <kalessin@kalessin.fr>
|
Louis Opter <kalessin@kalessin.fr>
|
||||||
Louis Opter <kalessin@kalessin.fr> <louis@dotcloud.com>
|
Louis Opter <kalessin@kalessin.fr> <louis@dotcloud.com>
|
||||||
Luca Favatella <luca.favatella@erlang-solutions.com> <lucafavatella@users.noreply.github.com>
|
Luca Favatella <luca.favatella@erlang-solutions.com> <lucafavatella@users.noreply.github.com>
|
||||||
|
@ -315,6 +338,8 @@ Michael Nussbaum <michael.nussbaum@getbraintree.com>
|
||||||
Michael Nussbaum <michael.nussbaum@getbraintree.com> <code@getbraintree.com>
|
Michael Nussbaum <michael.nussbaum@getbraintree.com> <code@getbraintree.com>
|
||||||
Michael Spetsiotis <michael_spets@hotmail.com>
|
Michael Spetsiotis <michael_spets@hotmail.com>
|
||||||
Michal Minář <miminar@redhat.com>
|
Michal Minář <miminar@redhat.com>
|
||||||
|
Michiel de Jong <michiel@unhosted.org>
|
||||||
|
Mickaël Fortunato <morsi.morsicus@gmail.com>
|
||||||
Miguel Angel Alvarez Cabrerizo <doncicuto@gmail.com> <30386061+doncicuto@users.noreply.github.com>
|
Miguel Angel Alvarez Cabrerizo <doncicuto@gmail.com> <30386061+doncicuto@users.noreply.github.com>
|
||||||
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
||||||
Mihai Borobocea <MihaiBorob@gmail.com> <MihaiBorobocea@gmail.com>
|
Mihai Borobocea <MihaiBorob@gmail.com> <MihaiBorobocea@gmail.com>
|
||||||
|
@ -327,6 +352,7 @@ Moorthy RS <rsmoorthy@gmail.com> <rsmoorthy@users.noreply.github.com>
|
||||||
Moysés Borges <moysesb@gmail.com>
|
Moysés Borges <moysesb@gmail.com>
|
||||||
Moysés Borges <moysesb@gmail.com> <moyses.furtado@wplex.com.br>
|
Moysés Borges <moysesb@gmail.com> <moyses.furtado@wplex.com.br>
|
||||||
Nace Oroz <orkica@gmail.com>
|
Nace Oroz <orkica@gmail.com>
|
||||||
|
Natasha Jarus <linuxmercedes@gmail.com>
|
||||||
Nathan LeClaire <nathan.leclaire@docker.com> <nathan.leclaire@gmail.com>
|
Nathan LeClaire <nathan.leclaire@docker.com> <nathan.leclaire@gmail.com>
|
||||||
Nathan LeClaire <nathan.leclaire@docker.com> <nathanleclaire@gmail.com>
|
Nathan LeClaire <nathan.leclaire@docker.com> <nathanleclaire@gmail.com>
|
||||||
Neil Horman <nhorman@tuxdriver.com> <nhorman@hmswarspite.think-freely.org>
|
Neil Horman <nhorman@tuxdriver.com> <nhorman@hmswarspite.think-freely.org>
|
||||||
|
@ -338,6 +364,9 @@ Nolan Darilek <nolan@thewordnerd.info>
|
||||||
O.S. Tezer <ostezer@gmail.com>
|
O.S. Tezer <ostezer@gmail.com>
|
||||||
O.S. Tezer <ostezer@gmail.com> <ostezer@users.noreply.github.com>
|
O.S. Tezer <ostezer@gmail.com> <ostezer@users.noreply.github.com>
|
||||||
Oh Jinkyun <tintypemolly@gmail.com> <tintypemolly@Ohui-MacBook-Pro.local>
|
Oh Jinkyun <tintypemolly@gmail.com> <tintypemolly@Ohui-MacBook-Pro.local>
|
||||||
|
Oliver Reason <oli@overrateddev.co>
|
||||||
|
Olli Janatuinen <olli.janatuinen@gmail.com>
|
||||||
|
Olli Janatuinen <olli.janatuinen@gmail.com> <olljanat@users.noreply.github.com>
|
||||||
Ouyang Liduo <oyld0210@163.com>
|
Ouyang Liduo <oyld0210@163.com>
|
||||||
Patrick Stapleton <github@gdi2290.com>
|
Patrick Stapleton <github@gdi2290.com>
|
||||||
Paul Liljenberg <liljenberg.paul@gmail.com> <letters@paulnotcom.se>
|
Paul Liljenberg <liljenberg.paul@gmail.com> <letters@paulnotcom.se>
|
||||||
|
@ -359,7 +388,10 @@ Robert Terhaar <rterhaar@atlanticdynamic.com> <robbyt@users.noreply.github.com>
|
||||||
Roberto G. Hashioka <roberto.hashioka@docker.com> <roberto_hashioka@hotmail.com>
|
Roberto G. Hashioka <roberto.hashioka@docker.com> <roberto_hashioka@hotmail.com>
|
||||||
Roberto Muñoz Fernández <robertomf@gmail.com> <roberto.munoz.fernandez.contractor@bbva.com>
|
Roberto Muñoz Fernández <robertomf@gmail.com> <roberto.munoz.fernandez.contractor@bbva.com>
|
||||||
Roman Dudin <katrmr@gmail.com> <decadent@users.noreply.github.com>
|
Roman Dudin <katrmr@gmail.com> <decadent@users.noreply.github.com>
|
||||||
|
Rong Zhang <rongzhang@alauda.io>
|
||||||
|
Rongxiang Song <tinysong1226@gmail.com>
|
||||||
Ross Boucher <rboucher@gmail.com>
|
Ross Boucher <rboucher@gmail.com>
|
||||||
|
Rui Cao <ruicao@alauda.io>
|
||||||
Runshen Zhu <runshen.zhu@gmail.com>
|
Runshen Zhu <runshen.zhu@gmail.com>
|
||||||
Ryan Stelly <ryan.stelly@live.com>
|
Ryan Stelly <ryan.stelly@live.com>
|
||||||
Sakeven Jiang <jc5930@sina.cn>
|
Sakeven Jiang <jc5930@sina.cn>
|
||||||
|
@ -432,6 +464,7 @@ Tõnis Tiigi <tonistiigi@gmail.com>
|
||||||
Trishna Guha <trishnaguha17@gmail.com>
|
Trishna Guha <trishnaguha17@gmail.com>
|
||||||
Tristan Carel <tristan@cogniteev.com>
|
Tristan Carel <tristan@cogniteev.com>
|
||||||
Tristan Carel <tristan@cogniteev.com> <tristan.carel@gmail.com>
|
Tristan Carel <tristan@cogniteev.com> <tristan.carel@gmail.com>
|
||||||
|
Tyler Brown <tylers.pile@gmail.com>
|
||||||
Umesh Yadav <umesh4257@gmail.com>
|
Umesh Yadav <umesh4257@gmail.com>
|
||||||
Umesh Yadav <umesh4257@gmail.com> <dungeonmaster18@users.noreply.github.com>
|
Umesh Yadav <umesh4257@gmail.com> <dungeonmaster18@users.noreply.github.com>
|
||||||
Victor Lyuboslavsky <victor@victoreda.com>
|
Victor Lyuboslavsky <victor@victoreda.com>
|
||||||
|
@ -464,8 +497,11 @@ Wei Wu <wuwei4455@gmail.com> cizixs <cizixs@163.com>
|
||||||
Wenjun Tang <tangwj2@lenovo.com> <dodia@163.com>
|
Wenjun Tang <tangwj2@lenovo.com> <dodia@163.com>
|
||||||
Wewang Xiaorenfine <wang.xiaoren@zte.com.cn>
|
Wewang Xiaorenfine <wang.xiaoren@zte.com.cn>
|
||||||
Will Weaver <monkey@buildingbananas.com>
|
Will Weaver <monkey@buildingbananas.com>
|
||||||
|
Xian Chaobo <xianchaobo@huawei.com>
|
||||||
|
Xian Chaobo <xianchaobo@huawei.com> <jimmyxian2004@yahoo.com.cn>
|
||||||
Xianglin Gao <xlgao@zju.edu.cn>
|
Xianglin Gao <xlgao@zju.edu.cn>
|
||||||
Xianlu Bird <xianlubird@gmail.com>
|
Xianlu Bird <xianlubird@gmail.com>
|
||||||
|
Xiaodong Zhang <a4012017@sina.com>
|
||||||
Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
|
Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
|
||||||
Xuecong Liao <satorulogic@gmail.com>
|
Xuecong Liao <satorulogic@gmail.com>
|
||||||
Yamasaki Masahide <masahide.y@gmail.com>
|
Yamasaki Masahide <masahide.y@gmail.com>
|
||||||
|
@ -477,15 +513,18 @@ Yi EungJun <eungjun.yi@navercorp.com> <semtlenori@gmail.com>
|
||||||
Ying Li <ying.li@docker.com>
|
Ying Li <ying.li@docker.com>
|
||||||
Ying Li <ying.li@docker.com> <cyli@twistedmatrix.com>
|
Ying Li <ying.li@docker.com> <cyli@twistedmatrix.com>
|
||||||
Yong Tang <yong.tang.github@outlook.com> <yongtang@users.noreply.github.com>
|
Yong Tang <yong.tang.github@outlook.com> <yongtang@users.noreply.github.com>
|
||||||
|
Yongxin Li <yxli@alauda.io>
|
||||||
Yosef Fertel <yfertel@gmail.com> <frosforever@users.noreply.github.com>
|
Yosef Fertel <yfertel@gmail.com> <frosforever@users.noreply.github.com>
|
||||||
Yu Changchun <yuchangchun1@huawei.com>
|
Yu Changchun <yuchangchun1@huawei.com>
|
||||||
Yu Chengxia <yuchengxia@huawei.com>
|
Yu Chengxia <yuchengxia@huawei.com>
|
||||||
Yu Peng <yu.peng36@zte.com.cn>
|
Yu Peng <yu.peng36@zte.com.cn>
|
||||||
Yu Peng <yu.peng36@zte.com.cn> <yupeng36@zte.com.cn>
|
Yu Peng <yu.peng36@zte.com.cn> <yupeng36@zte.com.cn>
|
||||||
|
Yue Zhang <zy675793960@yeah.net>
|
||||||
Zachary Jaffee <zjaffee@us.ibm.com> <zij@case.edu>
|
Zachary Jaffee <zjaffee@us.ibm.com> <zij@case.edu>
|
||||||
Zachary Jaffee <zjaffee@us.ibm.com> <zjaffee@apache.org>
|
Zachary Jaffee <zjaffee@us.ibm.com> <zjaffee@apache.org>
|
||||||
ZhangHang <stevezhang2014@gmail.com>
|
ZhangHang <stevezhang2014@gmail.com>
|
||||||
Zhenkun Bi <bi.zhenkun@zte.com.cn>
|
Zhenkun Bi <bi.zhenkun@zte.com.cn>
|
||||||
|
Zhoulin Xie <zhoulin.xie@daocloud.io>
|
||||||
Zhou Hao <zhouhao@cn.fujitsu.com>
|
Zhou Hao <zhouhao@cn.fujitsu.com>
|
||||||
Zhu Kunjia <zhu.kunjia@zte.com.cn>
|
Zhu Kunjia <zhu.kunjia@zte.com.cn>
|
||||||
Zou Yu <zouyu7@huawei.com>
|
Zou Yu <zouyu7@huawei.com>
|
||||||
|
|
|
@ -118,6 +118,7 @@ Andreas Köhler <andi5.py@gmx.net>
|
||||||
Andreas Savvides <andreas@editd.com>
|
Andreas Savvides <andreas@editd.com>
|
||||||
Andreas Tiefenthaler <at@an-ti.eu>
|
Andreas Tiefenthaler <at@an-ti.eu>
|
||||||
Andrei Gherzan <andrei@resin.io>
|
Andrei Gherzan <andrei@resin.io>
|
||||||
|
Andrei Vagin <avagin@gmail.com>
|
||||||
Andrew C. Bodine <acbodine@us.ibm.com>
|
Andrew C. Bodine <acbodine@us.ibm.com>
|
||||||
Andrew Clay Shafer <andrewcshafer@gmail.com>
|
Andrew Clay Shafer <andrewcshafer@gmail.com>
|
||||||
Andrew Duckworth <grillopress@gmail.com>
|
Andrew Duckworth <grillopress@gmail.com>
|
||||||
|
@ -137,6 +138,7 @@ Andrew Po <absourd.noise@gmail.com>
|
||||||
Andrew Weiss <andrew.weiss@docker.com>
|
Andrew Weiss <andrew.weiss@docker.com>
|
||||||
Andrew Williams <williams.andrew@gmail.com>
|
Andrew Williams <williams.andrew@gmail.com>
|
||||||
Andrews Medina <andrewsmedina@gmail.com>
|
Andrews Medina <andrewsmedina@gmail.com>
|
||||||
|
Andrey Kolomentsev <andrey.kolomentsev@docker.com>
|
||||||
Andrey Petrov <andrey.petrov@shazow.net>
|
Andrey Petrov <andrey.petrov@shazow.net>
|
||||||
Andrey Stolbovsky <andrey.stolbovsky@gmail.com>
|
Andrey Stolbovsky <andrey.stolbovsky@gmail.com>
|
||||||
André Martins <aanm90@gmail.com>
|
André Martins <aanm90@gmail.com>
|
||||||
|
@ -195,23 +197,27 @@ bdevloed <boris.de.vloed@gmail.com>
|
||||||
Ben Bonnefoy <frenchben@docker.com>
|
Ben Bonnefoy <frenchben@docker.com>
|
||||||
Ben Firshman <ben@firshman.co.uk>
|
Ben Firshman <ben@firshman.co.uk>
|
||||||
Ben Golub <ben.golub@dotcloud.com>
|
Ben Golub <ben.golub@dotcloud.com>
|
||||||
|
Ben Gould <ben@bengould.co.uk>
|
||||||
Ben Hall <ben@benhall.me.uk>
|
Ben Hall <ben@benhall.me.uk>
|
||||||
Ben Sargent <ben@brokendigits.com>
|
Ben Sargent <ben@brokendigits.com>
|
||||||
Ben Severson <BenSeverson@users.noreply.github.com>
|
Ben Severson <BenSeverson@users.noreply.github.com>
|
||||||
Ben Toews <mastahyeti@gmail.com>
|
Ben Toews <mastahyeti@gmail.com>
|
||||||
Ben Wiklund <ben@daisyowl.com>
|
Ben Wiklund <ben@daisyowl.com>
|
||||||
Benjamin Atkin <ben@benatkin.com>
|
Benjamin Atkin <ben@benatkin.com>
|
||||||
|
Benjamin Baker <Benjamin.baker@utexas.edu>
|
||||||
Benjamin Boudreau <boudreau.benjamin@gmail.com>
|
Benjamin Boudreau <boudreau.benjamin@gmail.com>
|
||||||
Benjamin Yolken <yolken@stripe.com>
|
Benjamin Yolken <yolken@stripe.com>
|
||||||
Benoit Chesneau <bchesneau@gmail.com>
|
Benoit Chesneau <bchesneau@gmail.com>
|
||||||
Bernerd Schaefer <bj.schaefer@gmail.com>
|
Bernerd Schaefer <bj.schaefer@gmail.com>
|
||||||
Bernhard M. Wiedemann <bwiedemann@suse.de>
|
Bernhard M. Wiedemann <bwiedemann@suse.de>
|
||||||
Bert Goethals <bert@bertg.be>
|
Bert Goethals <bert@bertg.be>
|
||||||
|
Bevisy Zhang <binbin36520@gmail.com>
|
||||||
Bharath Thiruveedula <bharath_ves@hotmail.com>
|
Bharath Thiruveedula <bharath_ves@hotmail.com>
|
||||||
Bhiraj Butala <abhiraj.butala@gmail.com>
|
Bhiraj Butala <abhiraj.butala@gmail.com>
|
||||||
Bhumika Bayani <bhumikabayani@gmail.com>
|
Bhumika Bayani <bhumikabayani@gmail.com>
|
||||||
Bilal Amarni <bilal.amarni@gmail.com>
|
Bilal Amarni <bilal.amarni@gmail.com>
|
||||||
Bill Wang <ozbillwang@gmail.com>
|
Bill Wang <ozbillwang@gmail.com>
|
||||||
|
Bily Zhang <xcoder@tenxcloud.com>
|
||||||
Bin Liu <liubin0329@gmail.com>
|
Bin Liu <liubin0329@gmail.com>
|
||||||
Bingshen Wang <bingshen.wbs@alibaba-inc.com>
|
Bingshen Wang <bingshen.wbs@alibaba-inc.com>
|
||||||
Blake Geno <blakegeno@gmail.com>
|
Blake Geno <blakegeno@gmail.com>
|
||||||
|
@ -246,6 +252,7 @@ Brian Torres-Gil <brian@dralth.com>
|
||||||
Brian Trump <btrump@yelp.com>
|
Brian Trump <btrump@yelp.com>
|
||||||
Brice Jaglin <bjaglin@teads.tv>
|
Brice Jaglin <bjaglin@teads.tv>
|
||||||
Briehan Lombaard <briehan.lombaard@gmail.com>
|
Briehan Lombaard <briehan.lombaard@gmail.com>
|
||||||
|
Brielle Broder <bbroder@google.com>
|
||||||
Bruno Bigras <bigras.bruno@gmail.com>
|
Bruno Bigras <bigras.bruno@gmail.com>
|
||||||
Bruno Binet <bruno.binet@gmail.com>
|
Bruno Binet <bruno.binet@gmail.com>
|
||||||
Bruno Gazzera <bgazzera@paginar.com>
|
Bruno Gazzera <bgazzera@paginar.com>
|
||||||
|
@ -300,6 +307,7 @@ Chen Min <chenmin46@huawei.com>
|
||||||
Chen Mingjie <chenmingjie0828@163.com>
|
Chen Mingjie <chenmingjie0828@163.com>
|
||||||
Chen Qiu <cheney-90@hotmail.com>
|
Chen Qiu <cheney-90@hotmail.com>
|
||||||
Cheng-mean Liu <soccerl@microsoft.com>
|
Cheng-mean Liu <soccerl@microsoft.com>
|
||||||
|
Chengfei Shang <cfshang@alauda.io>
|
||||||
Chengguang Xu <cgxu519@gmx.com>
|
Chengguang Xu <cgxu519@gmx.com>
|
||||||
chenyuzhu <chenyuzhi@oschina.cn>
|
chenyuzhu <chenyuzhi@oschina.cn>
|
||||||
Chetan Birajdar <birajdar.chetan@gmail.com>
|
Chetan Birajdar <birajdar.chetan@gmail.com>
|
||||||
|
@ -325,9 +333,11 @@ Chris Swan <chris.swan@iee.org>
|
||||||
Chris Telfer <ctelfer@docker.com>
|
Chris Telfer <ctelfer@docker.com>
|
||||||
Chris Wahl <github@wahlnetwork.com>
|
Chris Wahl <github@wahlnetwork.com>
|
||||||
Chris Weyl <cweyl@alumni.drew.edu>
|
Chris Weyl <cweyl@alumni.drew.edu>
|
||||||
|
Chris White <me@cwprogram.com>
|
||||||
Christian Berendt <berendt@b1-systems.de>
|
Christian Berendt <berendt@b1-systems.de>
|
||||||
Christian Brauner <christian.brauner@ubuntu.com>
|
Christian Brauner <christian.brauner@ubuntu.com>
|
||||||
Christian Böhme <developement@boehme3d.de>
|
Christian Böhme <developement@boehme3d.de>
|
||||||
|
Christian Muehlhaeuser <muesli@gmail.com>
|
||||||
Christian Persson <saser@live.se>
|
Christian Persson <saser@live.se>
|
||||||
Christian Rotzoll <ch.rotzoll@gmail.com>
|
Christian Rotzoll <ch.rotzoll@gmail.com>
|
||||||
Christian Simon <simon@swine.de>
|
Christian Simon <simon@swine.de>
|
||||||
|
@ -350,6 +360,7 @@ Cody Roseborough <crrosebo@amazon.com>
|
||||||
Coenraad Loubser <coenraad@wish.org.za>
|
Coenraad Loubser <coenraad@wish.org.za>
|
||||||
Colin Dunklau <colin.dunklau@gmail.com>
|
Colin Dunklau <colin.dunklau@gmail.com>
|
||||||
Colin Hebert <hebert.colin@gmail.com>
|
Colin Hebert <hebert.colin@gmail.com>
|
||||||
|
Colin Panisset <github@clabber.com>
|
||||||
Colin Rice <colin@daedrum.net>
|
Colin Rice <colin@daedrum.net>
|
||||||
Colin Walters <walters@verbum.org>
|
Colin Walters <walters@verbum.org>
|
||||||
Collin Guarino <collin.guarino@gmail.com>
|
Collin Guarino <collin.guarino@gmail.com>
|
||||||
|
@ -385,6 +396,7 @@ Dan Levy <dan@danlevy.net>
|
||||||
Dan McPherson <dmcphers@redhat.com>
|
Dan McPherson <dmcphers@redhat.com>
|
||||||
Dan Stine <sw@stinemail.com>
|
Dan Stine <sw@stinemail.com>
|
||||||
Dan Williams <me@deedubs.com>
|
Dan Williams <me@deedubs.com>
|
||||||
|
Dani Hodovic <dani.hodovic@gmail.com>
|
||||||
Dani Louca <dani.louca@docker.com>
|
Dani Louca <dani.louca@docker.com>
|
||||||
Daniel Antlinger <d.antlinger@gmx.at>
|
Daniel Antlinger <d.antlinger@gmx.at>
|
||||||
Daniel Dao <dqminh@cloudflare.com>
|
Daniel Dao <dqminh@cloudflare.com>
|
||||||
|
@ -438,12 +450,14 @@ David Mackey <tdmackey@booleanhaiku.com>
|
||||||
David Mat <david@davidmat.com>
|
David Mat <david@davidmat.com>
|
||||||
David Mcanulty <github@hellspark.com>
|
David Mcanulty <github@hellspark.com>
|
||||||
David McKay <david@rawkode.com>
|
David McKay <david@rawkode.com>
|
||||||
|
David P Hilton <david.hilton.p@gmail.com>
|
||||||
David Pelaez <pelaez89@gmail.com>
|
David Pelaez <pelaez89@gmail.com>
|
||||||
David R. Jenni <david.r.jenni@gmail.com>
|
David R. Jenni <david.r.jenni@gmail.com>
|
||||||
David Röthlisberger <david@rothlis.net>
|
David Röthlisberger <david@rothlis.net>
|
||||||
David Sheets <dsheets@docker.com>
|
David Sheets <dsheets@docker.com>
|
||||||
David Sissitka <me@dsissitka.com>
|
David Sissitka <me@dsissitka.com>
|
||||||
David Trott <github@davidtrott.com>
|
David Trott <github@davidtrott.com>
|
||||||
|
David Wang <00107082@163.com>
|
||||||
David Williamson <david.williamson@docker.com>
|
David Williamson <david.williamson@docker.com>
|
||||||
David Xia <dxia@spotify.com>
|
David Xia <dxia@spotify.com>
|
||||||
David Young <yangboh@cn.ibm.com>
|
David Young <yangboh@cn.ibm.com>
|
||||||
|
@ -451,8 +465,10 @@ Davide Ceretti <davide.ceretti@hogarthww.com>
|
||||||
Dawn Chen <dawnchen@google.com>
|
Dawn Chen <dawnchen@google.com>
|
||||||
dbdd <wangtong2712@gmail.com>
|
dbdd <wangtong2712@gmail.com>
|
||||||
dcylabs <dcylabs@gmail.com>
|
dcylabs <dcylabs@gmail.com>
|
||||||
|
Debayan De <debayande@users.noreply.github.com>
|
||||||
Deborah Gertrude Digges <deborah.gertrude.digges@gmail.com>
|
Deborah Gertrude Digges <deborah.gertrude.digges@gmail.com>
|
||||||
deed02392 <georgehafiz@gmail.com>
|
deed02392 <georgehafiz@gmail.com>
|
||||||
|
Deep Debroy <ddebroy@docker.com>
|
||||||
Deng Guangxing <dengguangxing@huawei.com>
|
Deng Guangxing <dengguangxing@huawei.com>
|
||||||
Deni Bertovic <deni@kset.org>
|
Deni Bertovic <deni@kset.org>
|
||||||
Denis Defreyne <denis@soundcloud.com>
|
Denis Defreyne <denis@soundcloud.com>
|
||||||
|
@ -477,6 +493,7 @@ Dieter Reuter <dieter.reuter@me.com>
|
||||||
Dillon Dixon <dillondixon@gmail.com>
|
Dillon Dixon <dillondixon@gmail.com>
|
||||||
Dima Stopel <dima@twistlock.com>
|
Dima Stopel <dima@twistlock.com>
|
||||||
Dimitri John Ledkov <dimitri.j.ledkov@intel.com>
|
Dimitri John Ledkov <dimitri.j.ledkov@intel.com>
|
||||||
|
Dimitris Mandalidis <dimitris.mandalidis@gmail.com>
|
||||||
Dimitris Rozakis <dimrozakis@gmail.com>
|
Dimitris Rozakis <dimrozakis@gmail.com>
|
||||||
Dimitry Andric <d.andric@activevideo.com>
|
Dimitry Andric <d.andric@activevideo.com>
|
||||||
Dinesh Subhraveti <dineshs@altiscale.com>
|
Dinesh Subhraveti <dineshs@altiscale.com>
|
||||||
|
@ -503,6 +520,7 @@ Don Kjer <don.kjer@gmail.com>
|
||||||
Don Spaulding <donspauldingii@gmail.com>
|
Don Spaulding <donspauldingii@gmail.com>
|
||||||
Donald Huang <don.hcd@gmail.com>
|
Donald Huang <don.hcd@gmail.com>
|
||||||
Dong Chen <dongluo.chen@docker.com>
|
Dong Chen <dongluo.chen@docker.com>
|
||||||
|
Donghwa Kim <shanytt@gmail.com>
|
||||||
Donovan Jones <git@gamma.net.nz>
|
Donovan Jones <git@gamma.net.nz>
|
||||||
Doron Podoleanu <doronp@il.ibm.com>
|
Doron Podoleanu <doronp@il.ibm.com>
|
||||||
Doug Davis <dug@us.ibm.com>
|
Doug Davis <dug@us.ibm.com>
|
||||||
|
@ -579,7 +597,9 @@ Ewa Czechowska <ewa@ai-traders.com>
|
||||||
Eystein Måløy Stenberg <eystein.maloy.stenberg@cfengine.com>
|
Eystein Måløy Stenberg <eystein.maloy.stenberg@cfengine.com>
|
||||||
ezbercih <cem.ezberci@gmail.com>
|
ezbercih <cem.ezberci@gmail.com>
|
||||||
Ezra Silvera <ezra@il.ibm.com>
|
Ezra Silvera <ezra@il.ibm.com>
|
||||||
|
Fabian Kramm <kramm@covexo.com>
|
||||||
Fabian Lauer <kontakt@softwareschmiede-saar.de>
|
Fabian Lauer <kontakt@softwareschmiede-saar.de>
|
||||||
|
Fabian Raetz <fabian.raetz@gmail.com>
|
||||||
Fabiano Rosas <farosas@br.ibm.com>
|
Fabiano Rosas <farosas@br.ibm.com>
|
||||||
Fabio Falci <fabiofalci@gmail.com>
|
Fabio Falci <fabiofalci@gmail.com>
|
||||||
Fabio Kung <fabio.kung@gmail.com>
|
Fabio Kung <fabio.kung@gmail.com>
|
||||||
|
@ -591,6 +611,7 @@ Faiz Khan <faizkhan00@gmail.com>
|
||||||
falmp <chico.lopes@gmail.com>
|
falmp <chico.lopes@gmail.com>
|
||||||
Fangming Fang <fangming.fang@arm.com>
|
Fangming Fang <fangming.fang@arm.com>
|
||||||
Fangyuan Gao <21551127@zju.edu.cn>
|
Fangyuan Gao <21551127@zju.edu.cn>
|
||||||
|
fanjiyun <fan.jiyun@zte.com.cn>
|
||||||
Fareed Dudhia <fareeddudhia@googlemail.com>
|
Fareed Dudhia <fareeddudhia@googlemail.com>
|
||||||
Fathi Boudra <fathi.boudra@linaro.org>
|
Fathi Boudra <fathi.boudra@linaro.org>
|
||||||
Federico Gimenez <fgimenez@coit.es>
|
Federico Gimenez <fgimenez@coit.es>
|
||||||
|
@ -621,6 +642,7 @@ Florin Patan <florinpatan@gmail.com>
|
||||||
fonglh <fonglh@gmail.com>
|
fonglh <fonglh@gmail.com>
|
||||||
Foysal Iqbal <foysal.iqbal.fb@gmail.com>
|
Foysal Iqbal <foysal.iqbal.fb@gmail.com>
|
||||||
Francesc Campoy <campoy@google.com>
|
Francesc Campoy <campoy@google.com>
|
||||||
|
Francesco Mari <mari.francesco@gmail.com>
|
||||||
Francis Chuang <francis.chuang@boostport.com>
|
Francis Chuang <francis.chuang@boostport.com>
|
||||||
Francisco Carriedo <fcarriedo@gmail.com>
|
Francisco Carriedo <fcarriedo@gmail.com>
|
||||||
Francisco Souza <f@souza.cc>
|
Francisco Souza <f@souza.cc>
|
||||||
|
@ -653,6 +675,7 @@ Gaël PORTAY <gael.portay@savoirfairelinux.com>
|
||||||
Genki Takiuchi <genki@s21g.com>
|
Genki Takiuchi <genki@s21g.com>
|
||||||
GennadySpb <lipenkov@gmail.com>
|
GennadySpb <lipenkov@gmail.com>
|
||||||
Geoffrey Bachelet <grosfrais@gmail.com>
|
Geoffrey Bachelet <grosfrais@gmail.com>
|
||||||
|
Geon Kim <geon0250@gmail.com>
|
||||||
George Kontridze <george@bugsnag.com>
|
George Kontridze <george@bugsnag.com>
|
||||||
George MacRorie <gmacr31@gmail.com>
|
George MacRorie <gmacr31@gmail.com>
|
||||||
George Xie <georgexsh@gmail.com>
|
George Xie <georgexsh@gmail.com>
|
||||||
|
@ -676,6 +699,7 @@ Gopikannan Venugopalsamy <gopikannan.venugopalsamy@gmail.com>
|
||||||
Gosuke Miyashita <gosukenator@gmail.com>
|
Gosuke Miyashita <gosukenator@gmail.com>
|
||||||
Gou Rao <gou@portworx.com>
|
Gou Rao <gou@portworx.com>
|
||||||
Govinda Fichtner <govinda.fichtner@googlemail.com>
|
Govinda Fichtner <govinda.fichtner@googlemail.com>
|
||||||
|
Grant Millar <grant@cylo.io>
|
||||||
Grant Reaber <grant.reaber@gmail.com>
|
Grant Reaber <grant.reaber@gmail.com>
|
||||||
Graydon Hoare <graydon@pobox.com>
|
Graydon Hoare <graydon@pobox.com>
|
||||||
Greg Fausak <greg@tacodata.com>
|
Greg Fausak <greg@tacodata.com>
|
||||||
|
@ -694,7 +718,9 @@ Guruprasad <lgp171188@gmail.com>
|
||||||
Gustav Sinder <gustav.sinder@gmail.com>
|
Gustav Sinder <gustav.sinder@gmail.com>
|
||||||
gwx296173 <gaojing3@huawei.com>
|
gwx296173 <gaojing3@huawei.com>
|
||||||
Günter Zöchbauer <guenter@gzoechbauer.com>
|
Günter Zöchbauer <guenter@gzoechbauer.com>
|
||||||
|
haikuoliu <haikuo@amazon.com>
|
||||||
Hakan Özler <hakan.ozler@kodcu.com>
|
Hakan Özler <hakan.ozler@kodcu.com>
|
||||||
|
Hamish Hutchings <moredhel@aoeu.me>
|
||||||
Hans Kristian Flaatten <hans@starefossen.com>
|
Hans Kristian Flaatten <hans@starefossen.com>
|
||||||
Hans Rødtang <hansrodtang@gmail.com>
|
Hans Rødtang <hansrodtang@gmail.com>
|
||||||
Hao Shu Wei <haosw@cn.ibm.com>
|
Hao Shu Wei <haosw@cn.ibm.com>
|
||||||
|
@ -702,6 +728,7 @@ Hao Zhang <21521210@zju.edu.cn>
|
||||||
Harald Albers <github@albersweb.de>
|
Harald Albers <github@albersweb.de>
|
||||||
Harley Laue <losinggeneration@gmail.com>
|
Harley Laue <losinggeneration@gmail.com>
|
||||||
Harold Cooper <hrldcpr@gmail.com>
|
Harold Cooper <hrldcpr@gmail.com>
|
||||||
|
Harrison Turton <harrisonturton@gmail.com>
|
||||||
Harry Zhang <harryz@hyper.sh>
|
Harry Zhang <harryz@hyper.sh>
|
||||||
Harshal Patil <harshal.patil@in.ibm.com>
|
Harshal Patil <harshal.patil@in.ibm.com>
|
||||||
Harshal Patil <harshalp@linux.vnet.ibm.com>
|
Harshal Patil <harshalp@linux.vnet.ibm.com>
|
||||||
|
@ -713,6 +740,7 @@ Hector Castro <hectcastro@gmail.com>
|
||||||
Helen Xie <chenjg@harmonycloud.cn>
|
Helen Xie <chenjg@harmonycloud.cn>
|
||||||
Henning Sprang <henning.sprang@gmail.com>
|
Henning Sprang <henning.sprang@gmail.com>
|
||||||
Hiroshi Hatake <hatake@clear-code.com>
|
Hiroshi Hatake <hatake@clear-code.com>
|
||||||
|
Hiroyuki Sasagawa <hs19870702@gmail.com>
|
||||||
Hobofan <goisser94@gmail.com>
|
Hobofan <goisser94@gmail.com>
|
||||||
Hollie Teal <hollie@docker.com>
|
Hollie Teal <hollie@docker.com>
|
||||||
Hong Xu <hong@topbug.net>
|
Hong Xu <hong@topbug.net>
|
||||||
|
@ -735,6 +763,7 @@ Ian Bishop <ianbishop@pace7.com>
|
||||||
Ian Bull <irbull@gmail.com>
|
Ian Bull <irbull@gmail.com>
|
||||||
Ian Calvert <ianjcalvert@gmail.com>
|
Ian Calvert <ianjcalvert@gmail.com>
|
||||||
Ian Campbell <ian.campbell@docker.com>
|
Ian Campbell <ian.campbell@docker.com>
|
||||||
|
Ian Chen <ianre657@gmail.com>
|
||||||
Ian Lee <IanLee1521@gmail.com>
|
Ian Lee <IanLee1521@gmail.com>
|
||||||
Ian Main <imain@redhat.com>
|
Ian Main <imain@redhat.com>
|
||||||
Ian Philpot <ian.philpot@microsoft.com>
|
Ian Philpot <ian.philpot@microsoft.com>
|
||||||
|
@ -752,9 +781,11 @@ Ilya Khlopotov <ilya.khlopotov@gmail.com>
|
||||||
imre Fitos <imre.fitos+github@gmail.com>
|
imre Fitos <imre.fitos+github@gmail.com>
|
||||||
inglesp <peter.inglesby@gmail.com>
|
inglesp <peter.inglesby@gmail.com>
|
||||||
Ingo Gottwald <in.gottwald@gmail.com>
|
Ingo Gottwald <in.gottwald@gmail.com>
|
||||||
|
Innovimax <innovimax@gmail.com>
|
||||||
Isaac Dupree <antispam@idupree.com>
|
Isaac Dupree <antispam@idupree.com>
|
||||||
Isabel Jimenez <contact.isabeljimenez@gmail.com>
|
Isabel Jimenez <contact.isabeljimenez@gmail.com>
|
||||||
Isao Jonas <isao.jonas@gmail.com>
|
Isao Jonas <isao.jonas@gmail.com>
|
||||||
|
Iskander Sharipov <quasilyte@gmail.com>
|
||||||
Ivan Babrou <ibobrik@gmail.com>
|
Ivan Babrou <ibobrik@gmail.com>
|
||||||
Ivan Fraixedes <ifcdev@gmail.com>
|
Ivan Fraixedes <ifcdev@gmail.com>
|
||||||
Ivan Grcic <igrcic@gmail.com>
|
Ivan Grcic <igrcic@gmail.com>
|
||||||
|
@ -785,6 +816,7 @@ James Mills <prologic@shortcircuit.net.au>
|
||||||
James Nesbitt <james.nesbitt@wunderkraut.com>
|
James Nesbitt <james.nesbitt@wunderkraut.com>
|
||||||
James Nugent <james@jen20.com>
|
James Nugent <james@jen20.com>
|
||||||
James Turnbull <james@lovedthanlost.net>
|
James Turnbull <james@lovedthanlost.net>
|
||||||
|
James Watkins-Harvey <jwatkins@progi-media.com>
|
||||||
Jamie Hannaford <jamie@limetree.org>
|
Jamie Hannaford <jamie@limetree.org>
|
||||||
Jamshid Afshar <jafshar@yahoo.com>
|
Jamshid Afshar <jafshar@yahoo.com>
|
||||||
Jan Keromnes <janx@linux.com>
|
Jan Keromnes <janx@linux.com>
|
||||||
|
@ -817,6 +849,7 @@ jaxgeller <jacksongeller@gmail.com>
|
||||||
Jay <imjching@hotmail.com>
|
Jay <imjching@hotmail.com>
|
||||||
Jay <teguhwpurwanto@gmail.com>
|
Jay <teguhwpurwanto@gmail.com>
|
||||||
Jay Kamat <github@jgkamat.33mail.com>
|
Jay Kamat <github@jgkamat.33mail.com>
|
||||||
|
Jean Rouge <rougej+github@gmail.com>
|
||||||
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
Jean-Baptiste Barth <jeanbaptiste.barth@gmail.com>
|
||||||
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
Jean-Baptiste Dalido <jeanbaptiste@appgratis.com>
|
||||||
Jean-Christophe Berthon <huygens@berthon.eu>
|
Jean-Christophe Berthon <huygens@berthon.eu>
|
||||||
|
@ -847,11 +880,13 @@ Jeroen Franse <jeroenfranse@gmail.com>
|
||||||
Jeroen Jacobs <github@jeroenj.be>
|
Jeroen Jacobs <github@jeroenj.be>
|
||||||
Jesse Dearing <jesse.dearing@gmail.com>
|
Jesse Dearing <jesse.dearing@gmail.com>
|
||||||
Jesse Dubay <jesse@thefortytwo.net>
|
Jesse Dubay <jesse@thefortytwo.net>
|
||||||
Jessica Frazelle <jessfraz@google.com>
|
Jessica Frazelle <acidburn@microsoft.com>
|
||||||
Jezeniel Zapanta <jpzapanta22@gmail.com>
|
Jezeniel Zapanta <jpzapanta22@gmail.com>
|
||||||
Jhon Honce <jhonce@redhat.com>
|
Jhon Honce <jhonce@redhat.com>
|
||||||
Ji.Zhilong <zhilongji@gmail.com>
|
Ji.Zhilong <zhilongji@gmail.com>
|
||||||
|
Jian Liao <jliao@alauda.io>
|
||||||
Jian Zhang <zhangjian.fnst@cn.fujitsu.com>
|
Jian Zhang <zhangjian.fnst@cn.fujitsu.com>
|
||||||
|
Jiang Jinyang <jjyruby@gmail.com>
|
||||||
Jie Luo <luo612@zju.edu.cn>
|
Jie Luo <luo612@zju.edu.cn>
|
||||||
Jihyun Hwang <jhhwang@telcoware.com>
|
Jihyun Hwang <jhhwang@telcoware.com>
|
||||||
Jilles Oldenbeuving <ojilles@gmail.com>
|
Jilles Oldenbeuving <ojilles@gmail.com>
|
||||||
|
@ -862,14 +897,13 @@ Jim Perrin <jperrin@centos.org>
|
||||||
Jimmy Cuadra <jimmy@jimmycuadra.com>
|
Jimmy Cuadra <jimmy@jimmycuadra.com>
|
||||||
Jimmy Puckett <jimmy.puckett@spinen.com>
|
Jimmy Puckett <jimmy.puckett@spinen.com>
|
||||||
Jimmy Song <rootsongjc@gmail.com>
|
Jimmy Song <rootsongjc@gmail.com>
|
||||||
jimmyxian <jimmyxian2004@yahoo.com.cn>
|
|
||||||
Jinsoo Park <cellpjs@gmail.com>
|
Jinsoo Park <cellpjs@gmail.com>
|
||||||
|
Jiri Appl <jiria@microsoft.com>
|
||||||
Jiri Popelka <jpopelka@redhat.com>
|
Jiri Popelka <jpopelka@redhat.com>
|
||||||
Jiuyue Ma <majiuyue@huawei.com>
|
Jiuyue Ma <majiuyue@huawei.com>
|
||||||
Jiří Župka <jzupka@redhat.com>
|
Jiří Župka <jzupka@redhat.com>
|
||||||
jjy <jiangjinyang@outlook.com>
|
|
||||||
jmzwcn <jmzwcn@gmail.com>
|
|
||||||
Joao Fernandes <joao.fernandes@docker.com>
|
Joao Fernandes <joao.fernandes@docker.com>
|
||||||
|
Joao Trindade <trindade.joao@gmail.com>
|
||||||
Joe Beda <joe.github@bedafamily.com>
|
Joe Beda <joe.github@bedafamily.com>
|
||||||
Joe Doliner <jdoliner@pachyderm.io>
|
Joe Doliner <jdoliner@pachyderm.io>
|
||||||
Joe Ferguson <joe@infosiftr.com>
|
Joe Ferguson <joe@infosiftr.com>
|
||||||
|
@ -908,6 +942,7 @@ Jon Johnson <jonjohnson@google.com>
|
||||||
Jon Surrell <jon.surrell@gmail.com>
|
Jon Surrell <jon.surrell@gmail.com>
|
||||||
Jon Wedaman <jweede@gmail.com>
|
Jon Wedaman <jweede@gmail.com>
|
||||||
Jonas Pfenniger <jonas@pfenniger.name>
|
Jonas Pfenniger <jonas@pfenniger.name>
|
||||||
|
Jonathan A. Schweder <jonathanschweder@gmail.com>
|
||||||
Jonathan A. Sternberg <jonathansternberg@gmail.com>
|
Jonathan A. Sternberg <jonathansternberg@gmail.com>
|
||||||
Jonathan Boulle <jonathanboulle@gmail.com>
|
Jonathan Boulle <jonathanboulle@gmail.com>
|
||||||
Jonathan Camp <jonathan@irondojo.com>
|
Jonathan Camp <jonathan@irondojo.com>
|
||||||
|
@ -928,7 +963,7 @@ Jordan Jennings <jjn2009@gmail.com>
|
||||||
Jordan Sissel <jls@semicomplete.com>
|
Jordan Sissel <jls@semicomplete.com>
|
||||||
Jorge Marin <chipironcin@users.noreply.github.com>
|
Jorge Marin <chipironcin@users.noreply.github.com>
|
||||||
Jorit Kleine-Möllhoff <joppich@bricknet.de>
|
Jorit Kleine-Möllhoff <joppich@bricknet.de>
|
||||||
Jose Diaz-Gonzalez <jose@seatgeek.com>
|
Jose Diaz-Gonzalez <email@josediazgonzalez.com>
|
||||||
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
|
Joseph Anthony Pasquale Holsten <joseph@josephholsten.com>
|
||||||
Joseph Hager <ajhager@gmail.com>
|
Joseph Hager <ajhager@gmail.com>
|
||||||
Joseph Kern <jkern@semafour.net>
|
Joseph Kern <jkern@semafour.net>
|
||||||
|
@ -982,7 +1017,8 @@ kargakis <kargakis@users.noreply.github.com>
|
||||||
Karl Grzeszczak <karlgrz@gmail.com>
|
Karl Grzeszczak <karlgrz@gmail.com>
|
||||||
Karol Duleba <mr.fuxi@gmail.com>
|
Karol Duleba <mr.fuxi@gmail.com>
|
||||||
Karthik Karanth <karanth.karthik@gmail.com>
|
Karthik Karanth <karanth.karthik@gmail.com>
|
||||||
Karthik Nayak <Karthik.188@gmail.com>
|
Karthik Nayak <karthik.188@gmail.com>
|
||||||
|
Kasper Fabæch Brandt <poizan@poizan.dk>
|
||||||
Kate Heddleston <kate.heddleston@gmail.com>
|
Kate Heddleston <kate.heddleston@gmail.com>
|
||||||
Katie McLaughlin <katie@glasnt.com>
|
Katie McLaughlin <katie@glasnt.com>
|
||||||
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
||||||
|
@ -990,6 +1026,7 @@ Katrina Owen <katrina.owen@gmail.com>
|
||||||
Kawsar Saiyeed <kawsar.saiyeed@projiris.com>
|
Kawsar Saiyeed <kawsar.saiyeed@projiris.com>
|
||||||
Kay Yan <kay.yan@daocloud.io>
|
Kay Yan <kay.yan@daocloud.io>
|
||||||
kayrus <kay.diam@gmail.com>
|
kayrus <kay.diam@gmail.com>
|
||||||
|
Kazuhiro Sera <seratch@gmail.com>
|
||||||
Ke Li <kel@splunk.com>
|
Ke Li <kel@splunk.com>
|
||||||
Ke Xu <leonhartx.k@gmail.com>
|
Ke Xu <leonhartx.k@gmail.com>
|
||||||
Kei Ohmura <ohmura.kei@gmail.com>
|
Kei Ohmura <ohmura.kei@gmail.com>
|
||||||
|
@ -998,6 +1035,7 @@ Keli Hu <dev@keli.hu>
|
||||||
Ken Cochrane <kencochrane@gmail.com>
|
Ken Cochrane <kencochrane@gmail.com>
|
||||||
Ken Herner <kherner@progress.com>
|
Ken Herner <kherner@progress.com>
|
||||||
Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com>
|
Ken ICHIKAWA <ichikawa.ken@jp.fujitsu.com>
|
||||||
|
Ken Reese <krrgithub@gmail.com>
|
||||||
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
Kenfe-Mickaël Laventure <mickael.laventure@gmail.com>
|
||||||
Kenjiro Nakayama <nakayamakenjiro@gmail.com>
|
Kenjiro Nakayama <nakayamakenjiro@gmail.com>
|
||||||
Kent Johnson <kentoj@gmail.com>
|
Kent Johnson <kentoj@gmail.com>
|
||||||
|
@ -1035,9 +1073,10 @@ Krasimir Georgiev <support@vip-consult.co.uk>
|
||||||
Kris-Mikael Krister <krismikael@protonmail.com>
|
Kris-Mikael Krister <krismikael@protonmail.com>
|
||||||
Kristian Haugene <kristian.haugene@capgemini.com>
|
Kristian Haugene <kristian.haugene@capgemini.com>
|
||||||
Kristina Zabunova <triara.xiii@gmail.com>
|
Kristina Zabunova <triara.xiii@gmail.com>
|
||||||
krrg <krrgithub@gmail.com>
|
Krystian Wojcicki <kwojcicki@sympatico.ca>
|
||||||
Kun Zhang <zkazure@gmail.com>
|
Kun Zhang <zkazure@gmail.com>
|
||||||
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
|
Kunal Kushwaha <kushwaha_kunal_v7@lab.ntt.co.jp>
|
||||||
|
Kunal Tyagi <tyagi.kunal@live.com>
|
||||||
Kyle Conroy <kyle.j.conroy@gmail.com>
|
Kyle Conroy <kyle.j.conroy@gmail.com>
|
||||||
Kyle Linden <linden.kyle@gmail.com>
|
Kyle Linden <linden.kyle@gmail.com>
|
||||||
kyu <leehk1227@gmail.com>
|
kyu <leehk1227@gmail.com>
|
||||||
|
@ -1060,6 +1099,7 @@ Leandro Siqueira <leandro.siqueira@gmail.com>
|
||||||
Lee Chao <932819864@qq.com>
|
Lee Chao <932819864@qq.com>
|
||||||
Lee, Meng-Han <sunrisedm4@gmail.com>
|
Lee, Meng-Han <sunrisedm4@gmail.com>
|
||||||
leeplay <hyeongkyu.lee@navercorp.com>
|
leeplay <hyeongkyu.lee@navercorp.com>
|
||||||
|
Lei Gong <lgong@alauda.io>
|
||||||
Lei Jitang <leijitang@huawei.com>
|
Lei Jitang <leijitang@huawei.com>
|
||||||
Len Weincier <len@cloudafrica.net>
|
Len Weincier <len@cloudafrica.net>
|
||||||
Lennie <github@consolejunkie.net>
|
Lennie <github@consolejunkie.net>
|
||||||
|
@ -1076,6 +1116,8 @@ Liana Lo <liana.lixia@gmail.com>
|
||||||
Liang Mingqiang <mqliang.zju@gmail.com>
|
Liang Mingqiang <mqliang.zju@gmail.com>
|
||||||
Liang-Chi Hsieh <viirya@gmail.com>
|
Liang-Chi Hsieh <viirya@gmail.com>
|
||||||
Liao Qingwei <liaoqingwei@huawei.com>
|
Liao Qingwei <liaoqingwei@huawei.com>
|
||||||
|
Lifubang <lifubang@acmcoder.com>
|
||||||
|
Lihua Tang <lhtang@alauda.io>
|
||||||
Lily Guo <lily.guo@docker.com>
|
Lily Guo <lily.guo@docker.com>
|
||||||
limsy <seongyeol37@gmail.com>
|
limsy <seongyeol37@gmail.com>
|
||||||
Lin Lu <doraalin@163.com>
|
Lin Lu <doraalin@163.com>
|
||||||
|
@ -1094,7 +1136,8 @@ Lloyd Dewolf <foolswisdom@gmail.com>
|
||||||
Lokesh Mandvekar <lsm5@fedoraproject.org>
|
Lokesh Mandvekar <lsm5@fedoraproject.org>
|
||||||
longliqiang88 <394564827@qq.com>
|
longliqiang88 <394564827@qq.com>
|
||||||
Lorenz Leutgeb <lorenz.leutgeb@gmail.com>
|
Lorenz Leutgeb <lorenz.leutgeb@gmail.com>
|
||||||
Lorenzo Fontana <lo@linux.com>
|
Lorenzo Fontana <fontanalorenz@gmail.com>
|
||||||
|
Lotus Fenn <fenn.lotus@gmail.com>
|
||||||
Louis Opter <kalessin@kalessin.fr>
|
Louis Opter <kalessin@kalessin.fr>
|
||||||
Luca Favatella <luca.favatella@erlang-solutions.com>
|
Luca Favatella <luca.favatella@erlang-solutions.com>
|
||||||
Luca Marturana <lucamarturana@gmail.com>
|
Luca Marturana <lucamarturana@gmail.com>
|
||||||
|
@ -1151,6 +1194,7 @@ Marius Gundersen <me@mariusgundersen.net>
|
||||||
Marius Sturm <marius@graylog.com>
|
Marius Sturm <marius@graylog.com>
|
||||||
Marius Voila <marius.voila@gmail.com>
|
Marius Voila <marius.voila@gmail.com>
|
||||||
Mark Allen <mrallen1@yahoo.com>
|
Mark Allen <mrallen1@yahoo.com>
|
||||||
|
Mark Jeromin <mark.jeromin@sysfrog.net>
|
||||||
Mark McGranaghan <mmcgrana@gmail.com>
|
Mark McGranaghan <mmcgrana@gmail.com>
|
||||||
Mark McKinstry <mmckinst@umich.edu>
|
Mark McKinstry <mmckinst@umich.edu>
|
||||||
Mark Milstein <mark@epiloque.com>
|
Mark Milstein <mark@epiloque.com>
|
||||||
|
@ -1167,6 +1211,7 @@ Martijn van Oosterhout <kleptog@svana.org>
|
||||||
Martin Honermeyer <maze@strahlungsfrei.de>
|
Martin Honermeyer <maze@strahlungsfrei.de>
|
||||||
Martin Kelly <martin@surround.io>
|
Martin Kelly <martin@surround.io>
|
||||||
Martin Mosegaard Amdisen <martin.amdisen@praqma.com>
|
Martin Mosegaard Amdisen <martin.amdisen@praqma.com>
|
||||||
|
Martin Muzatko <martin@happy-css.com>
|
||||||
Martin Redmond <redmond.martin@gmail.com>
|
Martin Redmond <redmond.martin@gmail.com>
|
||||||
Mary Anthony <mary.anthony@docker.com>
|
Mary Anthony <mary.anthony@docker.com>
|
||||||
Masahito Zembutsu <zembutsu@users.noreply.github.com>
|
Masahito Zembutsu <zembutsu@users.noreply.github.com>
|
||||||
|
@ -1200,6 +1245,7 @@ Matthias Klumpp <matthias@tenstral.net>
|
||||||
Matthias Kühnle <git.nivoc@neverbox.com>
|
Matthias Kühnle <git.nivoc@neverbox.com>
|
||||||
Matthias Rampke <mr@soundcloud.com>
|
Matthias Rampke <mr@soundcloud.com>
|
||||||
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
Matthieu Hauglustaine <matt.hauglustaine@gmail.com>
|
||||||
|
Mattias Jernberg <nostrad@gmail.com>
|
||||||
Mauricio Garavaglia <mauricio@medallia.com>
|
Mauricio Garavaglia <mauricio@medallia.com>
|
||||||
mauriyouth <mauriyouth@gmail.com>
|
mauriyouth <mauriyouth@gmail.com>
|
||||||
Max Shytikov <mshytikov@gmail.com>
|
Max Shytikov <mshytikov@gmail.com>
|
||||||
|
@ -1208,6 +1254,7 @@ Maxim Ivanov <ivanov.maxim@gmail.com>
|
||||||
Maxim Kulkin <mkulkin@mirantis.com>
|
Maxim Kulkin <mkulkin@mirantis.com>
|
||||||
Maxim Treskin <zerthurd@gmail.com>
|
Maxim Treskin <zerthurd@gmail.com>
|
||||||
Maxime Petazzoni <max@signalfuse.com>
|
Maxime Petazzoni <max@signalfuse.com>
|
||||||
|
Maximiliano Maccanti <maccanti@amazon.com>
|
||||||
Meaglith Ma <genedna@gmail.com>
|
Meaglith Ma <genedna@gmail.com>
|
||||||
meejah <meejah@meejah.ca>
|
meejah <meejah@meejah.ca>
|
||||||
Megan Kostick <mkostick@us.ibm.com>
|
Megan Kostick <mkostick@us.ibm.com>
|
||||||
|
@ -1248,8 +1295,9 @@ Michal Wieczorek <wieczorek-michal@wp.pl>
|
||||||
Michaël Pailloncy <mpapo.dev@gmail.com>
|
Michaël Pailloncy <mpapo.dev@gmail.com>
|
||||||
Michał Czeraszkiewicz <czerasz@gmail.com>
|
Michał Czeraszkiewicz <czerasz@gmail.com>
|
||||||
Michał Gryko <github@odkurzacz.org>
|
Michał Gryko <github@odkurzacz.org>
|
||||||
Michiel@unhosted <michiel@unhosted.org>
|
Michiel de Jong <michiel@unhosted.org>
|
||||||
Mickaël FORTUNATO <morsi.morsicus@gmail.com>
|
Mickaël Fortunato <morsi.morsicus@gmail.com>
|
||||||
|
Mickaël Remars <mickael@remars.com>
|
||||||
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
Miguel Angel Fernández <elmendalerenda@gmail.com>
|
||||||
Miguel Morales <mimoralea@gmail.com>
|
Miguel Morales <mimoralea@gmail.com>
|
||||||
Mihai Borobocea <MihaiBorob@gmail.com>
|
Mihai Borobocea <MihaiBorob@gmail.com>
|
||||||
|
@ -1280,6 +1328,7 @@ Mitch Capper <mitch.capper@gmail.com>
|
||||||
Mizuki Urushida <z11111001011@gmail.com>
|
Mizuki Urushida <z11111001011@gmail.com>
|
||||||
mlarcher <github@ringabell.org>
|
mlarcher <github@ringabell.org>
|
||||||
Mohammad Banikazemi <mb@us.ibm.com>
|
Mohammad Banikazemi <mb@us.ibm.com>
|
||||||
|
Mohammad Nasirifar <farnasirim@gmail.com>
|
||||||
Mohammed Aaqib Ansari <maaquib@gmail.com>
|
Mohammed Aaqib Ansari <maaquib@gmail.com>
|
||||||
Mohit Soni <mosoni@ebay.com>
|
Mohit Soni <mosoni@ebay.com>
|
||||||
Moorthy RS <rsmoorthy@gmail.com>
|
Moorthy RS <rsmoorthy@gmail.com>
|
||||||
|
@ -1304,6 +1353,7 @@ Nan Monnand Deng <monnand@gmail.com>
|
||||||
Naoki Orii <norii@cs.cmu.edu>
|
Naoki Orii <norii@cs.cmu.edu>
|
||||||
Natalie Parker <nparker@omnifone.com>
|
Natalie Parker <nparker@omnifone.com>
|
||||||
Natanael Copa <natanael.copa@docker.com>
|
Natanael Copa <natanael.copa@docker.com>
|
||||||
|
Natasha Jarus <linuxmercedes@gmail.com>
|
||||||
Nate Brennand <nate.brennand@clever.com>
|
Nate Brennand <nate.brennand@clever.com>
|
||||||
Nate Eagleson <nate@nateeag.com>
|
Nate Eagleson <nate@nateeag.com>
|
||||||
Nate Jones <nate@endot.org>
|
Nate Jones <nate@endot.org>
|
||||||
|
@ -1337,6 +1387,7 @@ Nicolas Dudebout <nicolas.dudebout@gatech.edu>
|
||||||
Nicolas Goy <kuon@goyman.com>
|
Nicolas Goy <kuon@goyman.com>
|
||||||
Nicolas Kaiser <nikai@nikai.net>
|
Nicolas Kaiser <nikai@nikai.net>
|
||||||
Nicolas Sterchele <sterchele.nicolas@gmail.com>
|
Nicolas Sterchele <sterchele.nicolas@gmail.com>
|
||||||
|
Nicolas V Castet <nvcastet@us.ibm.com>
|
||||||
Nicolás Hock Isaza <nhocki@gmail.com>
|
Nicolás Hock Isaza <nhocki@gmail.com>
|
||||||
Nigel Poulton <nigelpoulton@hotmail.com>
|
Nigel Poulton <nigelpoulton@hotmail.com>
|
||||||
Nik Nyby <nikolas@gnu.org>
|
Nik Nyby <nikolas@gnu.org>
|
||||||
|
@ -1352,6 +1403,7 @@ Noah Treuhaft <noah.treuhaft@docker.com>
|
||||||
NobodyOnSE <ich@sektor.selfip.com>
|
NobodyOnSE <ich@sektor.selfip.com>
|
||||||
noducks <onemannoducks@gmail.com>
|
noducks <onemannoducks@gmail.com>
|
||||||
Nolan Darilek <nolan@thewordnerd.info>
|
Nolan Darilek <nolan@thewordnerd.info>
|
||||||
|
Noriki Nakamura <noriki.nakamura@miraclelinux.com>
|
||||||
nponeccop <andy.melnikov@gmail.com>
|
nponeccop <andy.melnikov@gmail.com>
|
||||||
Nuutti Kotivuori <naked@iki.fi>
|
Nuutti Kotivuori <naked@iki.fi>
|
||||||
nzwsch <hi@nzwsch.com>
|
nzwsch <hi@nzwsch.com>
|
||||||
|
@ -1363,8 +1415,11 @@ Ohad Schneider <ohadschn@users.noreply.github.com>
|
||||||
ohmystack <jun.jiang02@ele.me>
|
ohmystack <jun.jiang02@ele.me>
|
||||||
Ole Reifschneider <mail@ole-reifschneider.de>
|
Ole Reifschneider <mail@ole-reifschneider.de>
|
||||||
Oliver Neal <ItsVeryWindy@users.noreply.github.com>
|
Oliver Neal <ItsVeryWindy@users.noreply.github.com>
|
||||||
|
Oliver Reason <oli@overrateddev.co>
|
||||||
Olivier Gambier <dmp42@users.noreply.github.com>
|
Olivier Gambier <dmp42@users.noreply.github.com>
|
||||||
Olle Jonsson <olle.jonsson@gmail.com>
|
Olle Jonsson <olle.jonsson@gmail.com>
|
||||||
|
Olli Janatuinen <olli.janatuinen@gmail.com>
|
||||||
|
Omri Shiv <Omri.Shiv@teradata.com>
|
||||||
Oriol Francès <oriolfa@gmail.com>
|
Oriol Francès <oriolfa@gmail.com>
|
||||||
Oskar Niburski <oskarniburski@gmail.com>
|
Oskar Niburski <oskarniburski@gmail.com>
|
||||||
Otto Kekäläinen <otto@seravo.fi>
|
Otto Kekäläinen <otto@seravo.fi>
|
||||||
|
@ -1420,6 +1475,7 @@ Peter Edge <peter.edge@gmail.com>
|
||||||
Peter Ericson <pdericson@gmail.com>
|
Peter Ericson <pdericson@gmail.com>
|
||||||
Peter Esbensen <pkesbensen@gmail.com>
|
Peter Esbensen <pkesbensen@gmail.com>
|
||||||
Peter Jaffe <pjaffe@nevo.com>
|
Peter Jaffe <pjaffe@nevo.com>
|
||||||
|
Peter Kang <peter@spell.run>
|
||||||
Peter Malmgren <ptmalmgren@gmail.com>
|
Peter Malmgren <ptmalmgren@gmail.com>
|
||||||
Peter Salvatore <peter@psftw.com>
|
Peter Salvatore <peter@psftw.com>
|
||||||
Peter Volpe <petervo@redhat.com>
|
Peter Volpe <petervo@redhat.com>
|
||||||
|
@ -1452,6 +1508,7 @@ Prasanna Gautam <prasannagautam@gmail.com>
|
||||||
Pratik Karki <prertik@outlook.com>
|
Pratik Karki <prertik@outlook.com>
|
||||||
Prayag Verma <prayag.verma@gmail.com>
|
Prayag Verma <prayag.verma@gmail.com>
|
||||||
Priya Wadhwa <priyawadhwa@google.com>
|
Priya Wadhwa <priyawadhwa@google.com>
|
||||||
|
Projjol Banerji <probaner23@gmail.com>
|
||||||
Przemek Hejman <przemyslaw.hejman@gmail.com>
|
Przemek Hejman <przemyslaw.hejman@gmail.com>
|
||||||
Pure White <daniel48@126.com>
|
Pure White <daniel48@126.com>
|
||||||
pysqz <randomq@126.com>
|
pysqz <randomq@126.com>
|
||||||
|
@ -1475,6 +1532,7 @@ Ralph Bean <rbean@redhat.com>
|
||||||
Ramkumar Ramachandra <artagnon@gmail.com>
|
Ramkumar Ramachandra <artagnon@gmail.com>
|
||||||
Ramon Brooker <rbrooker@aetherealmind.com>
|
Ramon Brooker <rbrooker@aetherealmind.com>
|
||||||
Ramon van Alteren <ramon@vanalteren.nl>
|
Ramon van Alteren <ramon@vanalteren.nl>
|
||||||
|
RaviTeja Pothana <ravi-teja@live.com>
|
||||||
Ray Tsang <rayt@google.com>
|
Ray Tsang <rayt@google.com>
|
||||||
ReadmeCritic <frankensteinbot@gmail.com>
|
ReadmeCritic <frankensteinbot@gmail.com>
|
||||||
Recursive Madman <recursive.madman@gmx.de>
|
Recursive Madman <recursive.madman@gmx.de>
|
||||||
|
@ -1524,6 +1582,7 @@ Roel Van Nyen <roel.vannyen@gmail.com>
|
||||||
Roger Peppe <rogpeppe@gmail.com>
|
Roger Peppe <rogpeppe@gmail.com>
|
||||||
Rohit Jnagal <jnagal@google.com>
|
Rohit Jnagal <jnagal@google.com>
|
||||||
Rohit Kadam <rohit.d.kadam@gmail.com>
|
Rohit Kadam <rohit.d.kadam@gmail.com>
|
||||||
|
Rohit Kapur <rkapur@flatiron.com>
|
||||||
Rojin George <rojingeorge@huawei.com>
|
Rojin George <rojingeorge@huawei.com>
|
||||||
Roland Huß <roland@jolokia.org>
|
Roland Huß <roland@jolokia.org>
|
||||||
Roland Kammerer <roland.kammerer@linbit.com>
|
Roland Kammerer <roland.kammerer@linbit.com>
|
||||||
|
@ -1533,6 +1592,9 @@ Roman Dudin <katrmr@gmail.com>
|
||||||
Roman Strashkin <roman.strashkin@gmail.com>
|
Roman Strashkin <roman.strashkin@gmail.com>
|
||||||
Ron Smits <ron.smits@gmail.com>
|
Ron Smits <ron.smits@gmail.com>
|
||||||
Ron Williams <ron.a.williams@gmail.com>
|
Ron Williams <ron.a.williams@gmail.com>
|
||||||
|
Rong Gao <gaoronggood@163.com>
|
||||||
|
Rong Zhang <rongzhang@alauda.io>
|
||||||
|
Rongxiang Song <tinysong1226@gmail.com>
|
||||||
root <docker-dummy@example.com>
|
root <docker-dummy@example.com>
|
||||||
root <root@lxdebmas.marist.edu>
|
root <root@lxdebmas.marist.edu>
|
||||||
root <root@ubuntu-14.04-amd64-vbox>
|
root <root@ubuntu-14.04-amd64-vbox>
|
||||||
|
@ -1544,8 +1606,10 @@ Rovanion Luckey <rovanion.luckey@gmail.com>
|
||||||
Royce Remer <royceremer@gmail.com>
|
Royce Remer <royceremer@gmail.com>
|
||||||
Rozhnov Alexandr <nox73@ya.ru>
|
Rozhnov Alexandr <nox73@ya.ru>
|
||||||
Rudolph Gottesheim <r.gottesheim@loot.at>
|
Rudolph Gottesheim <r.gottesheim@loot.at>
|
||||||
|
Rui Cao <ruicao@alauda.io>
|
||||||
Rui Lopes <rgl@ruilopes.com>
|
Rui Lopes <rgl@ruilopes.com>
|
||||||
Runshen Zhu <runshen.zhu@gmail.com>
|
Runshen Zhu <runshen.zhu@gmail.com>
|
||||||
|
Russ Magee <rmagee@gmail.com>
|
||||||
Ryan Abrams <rdabrams@gmail.com>
|
Ryan Abrams <rdabrams@gmail.com>
|
||||||
Ryan Anderson <anderson.ryanc@gmail.com>
|
Ryan Anderson <anderson.ryanc@gmail.com>
|
||||||
Ryan Aslett <github@mixologic.com>
|
Ryan Aslett <github@mixologic.com>
|
||||||
|
@ -1564,6 +1628,7 @@ Ryan Wallner <ryan.wallner@clusterhq.com>
|
||||||
Ryan Zhang <ryan.zhang@docker.com>
|
Ryan Zhang <ryan.zhang@docker.com>
|
||||||
ryancooper7 <ryan.cooper7@gmail.com>
|
ryancooper7 <ryan.cooper7@gmail.com>
|
||||||
RyanDeng <sheldon.d1018@gmail.com>
|
RyanDeng <sheldon.d1018@gmail.com>
|
||||||
|
Ryo Nakao <nakabonne@gmail.com>
|
||||||
Rémy Greinhofer <remy.greinhofer@livelovely.com>
|
Rémy Greinhofer <remy.greinhofer@livelovely.com>
|
||||||
s. rannou <mxs@sbrk.org>
|
s. rannou <mxs@sbrk.org>
|
||||||
s00318865 <sunyuan3@huawei.com>
|
s00318865 <sunyuan3@huawei.com>
|
||||||
|
@ -1572,6 +1637,7 @@ Sachin Joshi <sachin_jayant_joshi@hotmail.com>
|
||||||
Sagar Hani <sagarhani33@gmail.com>
|
Sagar Hani <sagarhani33@gmail.com>
|
||||||
Sainath Grandhi <sainath.grandhi@intel.com>
|
Sainath Grandhi <sainath.grandhi@intel.com>
|
||||||
Sakeven Jiang <jc5930@sina.cn>
|
Sakeven Jiang <jc5930@sina.cn>
|
||||||
|
Salahuddin Khan <salah@docker.com>
|
||||||
Sally O'Malley <somalley@redhat.com>
|
Sally O'Malley <somalley@redhat.com>
|
||||||
Sam Abed <sam.abed@gmail.com>
|
Sam Abed <sam.abed@gmail.com>
|
||||||
Sam Alba <sam.alba@gmail.com>
|
Sam Alba <sam.alba@gmail.com>
|
||||||
|
@ -1593,6 +1659,7 @@ Santhosh Manohar <santhosh@docker.com>
|
||||||
sapphiredev <se.imas.kr@gmail.com>
|
sapphiredev <se.imas.kr@gmail.com>
|
||||||
Sargun Dhillon <sargun@netflix.com>
|
Sargun Dhillon <sargun@netflix.com>
|
||||||
Sascha Andres <sascha.andres@outlook.com>
|
Sascha Andres <sascha.andres@outlook.com>
|
||||||
|
Sascha Grunert <sgrunert@suse.com>
|
||||||
Satnam Singh <satnam@raintown.org>
|
Satnam Singh <satnam@raintown.org>
|
||||||
Satoshi Amemiya <satoshi_amemiya@voyagegroup.com>
|
Satoshi Amemiya <satoshi_amemiya@voyagegroup.com>
|
||||||
Satoshi Tagomori <tagomoris@gmail.com>
|
Satoshi Tagomori <tagomoris@gmail.com>
|
||||||
|
@ -1619,7 +1686,9 @@ Serge Hallyn <serge.hallyn@ubuntu.com>
|
||||||
Sergey Alekseev <sergey.alekseev.minsk@gmail.com>
|
Sergey Alekseev <sergey.alekseev.minsk@gmail.com>
|
||||||
Sergey Evstifeev <sergey.evstifeev@gmail.com>
|
Sergey Evstifeev <sergey.evstifeev@gmail.com>
|
||||||
Sergii Kabashniuk <skabashnyuk@codenvy.com>
|
Sergii Kabashniuk <skabashnyuk@codenvy.com>
|
||||||
|
Sergio Lopez <slp@redhat.com>
|
||||||
Serhat Gülçiçek <serhat25@gmail.com>
|
Serhat Gülçiçek <serhat25@gmail.com>
|
||||||
|
SeungUkLee <lsy931106@gmail.com>
|
||||||
Sevki Hasirci <s@sevki.org>
|
Sevki Hasirci <s@sevki.org>
|
||||||
Shane Canon <scanon@lbl.gov>
|
Shane Canon <scanon@lbl.gov>
|
||||||
Shane da Silva <shane@dasilva.io>
|
Shane da Silva <shane@dasilva.io>
|
||||||
|
@ -1647,6 +1716,7 @@ Sidhartha Mani <sidharthamn@gmail.com>
|
||||||
sidharthamani <sid@rancher.com>
|
sidharthamani <sid@rancher.com>
|
||||||
Silas Sewell <silas@sewell.org>
|
Silas Sewell <silas@sewell.org>
|
||||||
Silvan Jegen <s.jegen@gmail.com>
|
Silvan Jegen <s.jegen@gmail.com>
|
||||||
|
Simão Reis <smnrsti@gmail.com>
|
||||||
Simei He <hesimei@zju.edu.cn>
|
Simei He <hesimei@zju.edu.cn>
|
||||||
Simon Eskildsen <sirup@sirupsen.com>
|
Simon Eskildsen <sirup@sirupsen.com>
|
||||||
Simon Ferquel <simon.ferquel@docker.com>
|
Simon Ferquel <simon.ferquel@docker.com>
|
||||||
|
@ -1714,10 +1784,11 @@ tang0th <tang0th@gmx.com>
|
||||||
Tangi Colin <tangicolin@gmail.com>
|
Tangi Colin <tangicolin@gmail.com>
|
||||||
Tatsuki Sugiura <sugi@nemui.org>
|
Tatsuki Sugiura <sugi@nemui.org>
|
||||||
Tatsushi Inagaki <e29253@jp.ibm.com>
|
Tatsushi Inagaki <e29253@jp.ibm.com>
|
||||||
|
Taylan Isikdemir <taylani@google.com>
|
||||||
Taylor Jones <monitorjbl@gmail.com>
|
Taylor Jones <monitorjbl@gmail.com>
|
||||||
tbonza <tylers.pile@gmail.com>
|
|
||||||
Ted M. Young <tedyoung@gmail.com>
|
Ted M. Young <tedyoung@gmail.com>
|
||||||
Tehmasp Chaudhri <tehmasp@gmail.com>
|
Tehmasp Chaudhri <tehmasp@gmail.com>
|
||||||
|
Tejaswini Duggaraju <naduggar@microsoft.com>
|
||||||
Tejesh Mehta <tejesh.mehta@gmail.com>
|
Tejesh Mehta <tejesh.mehta@gmail.com>
|
||||||
terryding77 <550147740@qq.com>
|
terryding77 <550147740@qq.com>
|
||||||
tgic <farmer1992@gmail.com>
|
tgic <farmer1992@gmail.com>
|
||||||
|
@ -1811,6 +1882,7 @@ Tristan Carel <tristan@cogniteev.com>
|
||||||
Troy Denton <trdenton@gmail.com>
|
Troy Denton <trdenton@gmail.com>
|
||||||
Tycho Andersen <tycho@docker.com>
|
Tycho Andersen <tycho@docker.com>
|
||||||
Tyler Brock <tyler.brock@gmail.com>
|
Tyler Brock <tyler.brock@gmail.com>
|
||||||
|
Tyler Brown <tylers.pile@gmail.com>
|
||||||
Tzu-Jung Lee <roylee17@gmail.com>
|
Tzu-Jung Lee <roylee17@gmail.com>
|
||||||
uhayate <uhayate.gong@daocloud.io>
|
uhayate <uhayate.gong@daocloud.io>
|
||||||
Ulysse Carion <ulyssecarion@gmail.com>
|
Ulysse Carion <ulyssecarion@gmail.com>
|
||||||
|
@ -1871,6 +1943,7 @@ Wassim Dhif <wassimdhif@gmail.com>
|
||||||
Wayne Chang <wayne@neverfear.org>
|
Wayne Chang <wayne@neverfear.org>
|
||||||
Wayne Song <wsong@docker.com>
|
Wayne Song <wsong@docker.com>
|
||||||
Weerasak Chongnguluam <singpor@gmail.com>
|
Weerasak Chongnguluam <singpor@gmail.com>
|
||||||
|
Wei Fu <fuweid89@gmail.com>
|
||||||
Wei Wu <wuwei4455@gmail.com>
|
Wei Wu <wuwei4455@gmail.com>
|
||||||
Wei-Ting Kuo <waitingkuo0527@gmail.com>
|
Wei-Ting Kuo <waitingkuo0527@gmail.com>
|
||||||
weipeng <weipeng@tuscloud.io>
|
weipeng <weipeng@tuscloud.io>
|
||||||
|
@ -1900,17 +1973,23 @@ WiseTrem <shepelyov.g@gmail.com>
|
||||||
Wolfgang Powisch <powo@powo.priv.at>
|
Wolfgang Powisch <powo@powo.priv.at>
|
||||||
Wonjun Kim <wonjun.kim@navercorp.com>
|
Wonjun Kim <wonjun.kim@navercorp.com>
|
||||||
xamyzhao <x.amy.zhao@gmail.com>
|
xamyzhao <x.amy.zhao@gmail.com>
|
||||||
|
Xian Chaobo <xianchaobo@huawei.com>
|
||||||
Xianglin Gao <xlgao@zju.edu.cn>
|
Xianglin Gao <xlgao@zju.edu.cn>
|
||||||
Xianlu Bird <xianlubird@gmail.com>
|
Xianlu Bird <xianlubird@gmail.com>
|
||||||
XiaoBing Jiang <s7v7nislands@gmail.com>
|
XiaoBing Jiang <s7v7nislands@gmail.com>
|
||||||
|
Xiaodong Zhang <a4012017@sina.com>
|
||||||
|
Xiaoxi He <xxhe@alauda.io>
|
||||||
Xiaoxu Chen <chenxiaoxu14@otcaix.iscas.ac.cn>
|
Xiaoxu Chen <chenxiaoxu14@otcaix.iscas.ac.cn>
|
||||||
Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
|
Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
|
||||||
|
xichengliudui <1693291525@qq.com>
|
||||||
xiekeyang <xiekeyang@huawei.com>
|
xiekeyang <xiekeyang@huawei.com>
|
||||||
|
Ximo Guanter Gonzálbez <joaquin.guantergonzalbez@telefonica.com>
|
||||||
Xinbo Weng <xihuanbo_0521@zju.edu.cn>
|
Xinbo Weng <xihuanbo_0521@zju.edu.cn>
|
||||||
Xinzi Zhou <imdreamrunner@gmail.com>
|
Xinzi Zhou <imdreamrunner@gmail.com>
|
||||||
Xiuming Chen <cc@cxm.cc>
|
Xiuming Chen <cc@cxm.cc>
|
||||||
Xuecong Liao <satorulogic@gmail.com>
|
Xuecong Liao <satorulogic@gmail.com>
|
||||||
xuzhaokui <cynicholas@gmail.com>
|
xuzhaokui <cynicholas@gmail.com>
|
||||||
|
Yadnyawalkya Tale <ytale@redhat.com>
|
||||||
Yahya <ya7yaz@gmail.com>
|
Yahya <ya7yaz@gmail.com>
|
||||||
YAMADA Tsuyoshi <tyamada@minimum2scp.org>
|
YAMADA Tsuyoshi <tyamada@minimum2scp.org>
|
||||||
Yamasaki Masahide <masahide.y@gmail.com>
|
Yamasaki Masahide <masahide.y@gmail.com>
|
||||||
|
@ -1930,6 +2009,7 @@ Yihang Ho <hoyihang5@gmail.com>
|
||||||
Ying Li <ying.li@docker.com>
|
Ying Li <ying.li@docker.com>
|
||||||
Yohei Ueda <yohei@jp.ibm.com>
|
Yohei Ueda <yohei@jp.ibm.com>
|
||||||
Yong Tang <yong.tang.github@outlook.com>
|
Yong Tang <yong.tang.github@outlook.com>
|
||||||
|
Yongxin Li <yxli@alauda.io>
|
||||||
Yongzhi Pan <panyongzhi@gmail.com>
|
Yongzhi Pan <panyongzhi@gmail.com>
|
||||||
Yosef Fertel <yfertel@gmail.com>
|
Yosef Fertel <yfertel@gmail.com>
|
||||||
You-Sheng Yang (楊有勝) <vicamo@gmail.com>
|
You-Sheng Yang (楊有勝) <vicamo@gmail.com>
|
||||||
|
@ -1940,9 +2020,12 @@ Yu Peng <yu.peng36@zte.com.cn>
|
||||||
Yu-Ju Hong <yjhong@google.com>
|
Yu-Ju Hong <yjhong@google.com>
|
||||||
Yuan Sun <sunyuan3@huawei.com>
|
Yuan Sun <sunyuan3@huawei.com>
|
||||||
Yuanhong Peng <pengyuanhong@huawei.com>
|
Yuanhong Peng <pengyuanhong@huawei.com>
|
||||||
|
Yue Zhang <zy675793960@yeah.net>
|
||||||
Yuhao Fang <fangyuhao@gmail.com>
|
Yuhao Fang <fangyuhao@gmail.com>
|
||||||
|
Yuichiro Kaneko <spiketeika@gmail.com>
|
||||||
Yunxiang Huang <hyxqshk@vip.qq.com>
|
Yunxiang Huang <hyxqshk@vip.qq.com>
|
||||||
Yurii Rashkovskii <yrashk@gmail.com>
|
Yurii Rashkovskii <yrashk@gmail.com>
|
||||||
|
Yusuf Tarık Günaydın <yusuf_tarik@hotmail.com>
|
||||||
Yves Junqueira <yves.junqueira@gmail.com>
|
Yves Junqueira <yves.junqueira@gmail.com>
|
||||||
Zac Dover <zdover@redhat.com>
|
Zac Dover <zdover@redhat.com>
|
||||||
Zach Borboa <zachborboa@gmail.com>
|
Zach Borboa <zachborboa@gmail.com>
|
||||||
|
@ -1959,8 +2042,10 @@ ZhangHang <stevezhang2014@gmail.com>
|
||||||
zhangxianwei <xianwei.zw@alibaba-inc.com>
|
zhangxianwei <xianwei.zw@alibaba-inc.com>
|
||||||
Zhenan Ye <21551168@zju.edu.cn>
|
Zhenan Ye <21551168@zju.edu.cn>
|
||||||
zhenghenghuo <zhenghenghuo@zju.edu.cn>
|
zhenghenghuo <zhenghenghuo@zju.edu.cn>
|
||||||
|
Zhenhai Gao <gaozh1988@live.com>
|
||||||
Zhenkun Bi <bi.zhenkun@zte.com.cn>
|
Zhenkun Bi <bi.zhenkun@zte.com.cn>
|
||||||
Zhou Hao <zhouhao@cn.fujitsu.com>
|
Zhou Hao <zhouhao@cn.fujitsu.com>
|
||||||
|
Zhoulin Xie <zhoulin.xie@daocloud.io>
|
||||||
Zhu Guihua <zhugh.fnst@cn.fujitsu.com>
|
Zhu Guihua <zhugh.fnst@cn.fujitsu.com>
|
||||||
Zhu Kunjia <zhu.kunjia@zte.com.cn>
|
Zhu Kunjia <zhu.kunjia@zte.com.cn>
|
||||||
Zhuoyun Wei <wzyboy@wzyboy.org>
|
Zhuoyun Wei <wzyboy@wzyboy.org>
|
||||||
|
|
|
@ -99,7 +99,7 @@ be found.
|
||||||
* Add `--format` option to `docker node ls` [#30424](https://github.com/docker/docker/pull/30424)
|
* Add `--format` option to `docker node ls` [#30424](https://github.com/docker/docker/pull/30424)
|
||||||
* Add `--prune` option to `docker stack deploy` to remove services that are no longer defined in the docker-compose file [#31302](https://github.com/docker/docker/pull/31302)
|
* Add `--prune` option to `docker stack deploy` to remove services that are no longer defined in the docker-compose file [#31302](https://github.com/docker/docker/pull/31302)
|
||||||
* Add `PORTS` column for `docker service ls` when using `ingress` mode [#30813](https://github.com/docker/docker/pull/30813)
|
* Add `PORTS` column for `docker service ls` when using `ingress` mode [#30813](https://github.com/docker/docker/pull/30813)
|
||||||
- Fix unnescessary re-deploying of tasks when environment-variables are used [#32364](https://github.com/docker/docker/pull/32364)
|
- Fix unnecessary re-deploying of tasks when environment-variables are used [#32364](https://github.com/docker/docker/pull/32364)
|
||||||
- Fix `docker stack deploy` not supporting `endpoint_mode` when deploying from a docker compose file [#32333](https://github.com/docker/docker/pull/32333)
|
- Fix `docker stack deploy` not supporting `endpoint_mode` when deploying from a docker compose file [#32333](https://github.com/docker/docker/pull/32333)
|
||||||
- Proceed with startup if cluster component cannot be created to allow recovering from a broken swarm setup [#31631](https://github.com/docker/docker/pull/31631)
|
- Proceed with startup if cluster component cannot be created to allow recovering from a broken swarm setup [#31631](https://github.com/docker/docker/pull/31631)
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ process](docs/contributing/).
|
||||||
|
|
||||||
This page contains information about reporting issues as well as some tips and
|
This page contains information about reporting issues as well as some tips and
|
||||||
guidelines useful to experienced open source contributors. Finally, make sure
|
guidelines useful to experienced open source contributors. Finally, make sure
|
||||||
you read our [community guidelines](#docker-community-guidelines) before you
|
you read our [community guidelines](#moby-community-guidelines) before you
|
||||||
start participating.
|
start participating.
|
||||||
|
|
||||||
## Topics
|
## Topics
|
||||||
|
@ -17,7 +17,7 @@ start participating.
|
||||||
* [Design and Cleanup Proposals](#design-and-cleanup-proposals)
|
* [Design and Cleanup Proposals](#design-and-cleanup-proposals)
|
||||||
* [Reporting Issues](#reporting-other-issues)
|
* [Reporting Issues](#reporting-other-issues)
|
||||||
* [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines)
|
* [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines)
|
||||||
* [Community Guidelines](#docker-community-guidelines)
|
* [Community Guidelines](#moby-community-guidelines)
|
||||||
|
|
||||||
## Reporting security issues
|
## Reporting security issues
|
||||||
|
|
||||||
|
|
|
@ -24,18 +24,15 @@
|
||||||
# the case. Therefore, you don't have to disable it anymore.
|
# the case. Therefore, you don't have to disable it anymore.
|
||||||
#
|
#
|
||||||
|
|
||||||
FROM golang:1.10.3 AS base
|
FROM golang:1.12.1 AS base
|
||||||
# FIXME(vdemeester) this is kept for other script depending on it to not fail right away
|
|
||||||
# Remove this once the other scripts uses something else to detect the version
|
|
||||||
ENV GO_VERSION 1.10.3
|
|
||||||
# allow replacing httpredir or deb mirror
|
# allow replacing httpredir or deb mirror
|
||||||
ARG APT_MIRROR=deb.debian.org
|
ARG APT_MIRROR=deb.debian.org
|
||||||
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list
|
||||||
|
|
||||||
FROM base AS criu
|
FROM base AS criu
|
||||||
# Install CRIU for checkpoint/restore support
|
# Install CRIU for checkpoint/restore support
|
||||||
ENV CRIU_VERSION 3.6
|
ENV CRIU_VERSION 3.11
|
||||||
# Install dependancy packages specific to criu
|
# Install dependency packages specific to criu
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
libnet-dev \
|
libnet-dev \
|
||||||
libprotobuf-c0-dev \
|
libprotobuf-c0-dev \
|
||||||
|
@ -52,11 +49,6 @@ RUN apt-get update && apt-get install -y \
|
||||||
&& make PREFIX=/build/ install-criu
|
&& make PREFIX=/build/ install-criu
|
||||||
|
|
||||||
FROM base AS registry
|
FROM base AS registry
|
||||||
# Install two versions of the registry. The first is an older version that
|
|
||||||
# only supports schema1 manifests. The second is a newer version that supports
|
|
||||||
# both. This allows integration-cli tests to cover push/pull with both schema1
|
|
||||||
# and schema2 manifests.
|
|
||||||
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
|
||||||
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
|
||||||
RUN set -x \
|
RUN set -x \
|
||||||
&& export GOPATH="$(mktemp -d)" \
|
&& export GOPATH="$(mktemp -d)" \
|
||||||
|
@ -64,20 +56,13 @@ RUN set -x \
|
||||||
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
&& (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
|
||||||
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
&& GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
|
||||||
go build -buildmode=pie -o /build/registry-v2 github.com/docker/distribution/cmd/registry \
|
go build -buildmode=pie -o /build/registry-v2 github.com/docker/distribution/cmd/registry \
|
||||||
&& case $(dpkg --print-architecture) in \
|
|
||||||
amd64|ppc64*|s390x) \
|
|
||||||
(cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1"); \
|
|
||||||
GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH"; \
|
|
||||||
go build -buildmode=pie -o /build/registry-v2-schema1 github.com/docker/distribution/cmd/registry; \
|
|
||||||
;; \
|
|
||||||
esac \
|
|
||||||
&& rm -rf "$GOPATH"
|
&& rm -rf "$GOPATH"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FROM base AS docker-py
|
FROM base AS docker-py
|
||||||
# Get the "docker-py" source so we can run their integration tests
|
# Get the "docker-py" source so we can run their integration tests
|
||||||
ENV DOCKER_PY_COMMIT 8b246db271a85d6541dc458838627e89c683e42f
|
ENV DOCKER_PY_COMMIT ac922192959870774ad8428344d9faa0555f7ba6
|
||||||
RUN git clone https://github.com/docker/docker-py.git /build \
|
RUN git clone https://github.com/docker/docker-py.git /build \
|
||||||
&& cd /build \
|
&& cd /build \
|
||||||
&& git checkout -q $DOCKER_PY_COMMIT
|
&& git checkout -q $DOCKER_PY_COMMIT
|
||||||
|
@ -118,58 +103,65 @@ FROM base AS tomlv
|
||||||
ENV INSTALL_BINARY_NAME=tomlv
|
ENV INSTALL_BINARY_NAME=tomlv
|
||||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
RUN PREFIX=/build ./install.sh $INSTALL_BINARY_NAME
|
||||||
|
|
||||||
FROM base AS vndr
|
FROM base AS vndr
|
||||||
ENV INSTALL_BINARY_NAME=vndr
|
ENV INSTALL_BINARY_NAME=vndr
|
||||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
RUN PREFIX=/build ./install.sh $INSTALL_BINARY_NAME
|
||||||
|
|
||||||
FROM base AS containerd
|
FROM base AS containerd
|
||||||
RUN apt-get update && apt-get install -y btrfs-tools
|
RUN apt-get update && apt-get install -y btrfs-tools
|
||||||
ENV INSTALL_BINARY_NAME=containerd
|
ENV INSTALL_BINARY_NAME=containerd
|
||||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
RUN PREFIX=/build ./install.sh $INSTALL_BINARY_NAME
|
||||||
|
|
||||||
FROM base AS proxy
|
FROM base AS proxy
|
||||||
ENV INSTALL_BINARY_NAME=proxy
|
ENV INSTALL_BINARY_NAME=proxy
|
||||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
RUN PREFIX=/build ./install.sh $INSTALL_BINARY_NAME
|
||||||
|
|
||||||
FROM base AS gometalinter
|
FROM base AS gometalinter
|
||||||
ENV INSTALL_BINARY_NAME=gometalinter
|
ENV INSTALL_BINARY_NAME=gometalinter
|
||||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
RUN PREFIX=/build ./install.sh $INSTALL_BINARY_NAME
|
||||||
|
|
||||||
FROM base AS dockercli
|
FROM base AS dockercli
|
||||||
ENV INSTALL_BINARY_NAME=dockercli
|
ENV INSTALL_BINARY_NAME=dockercli
|
||||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
RUN PREFIX=/build ./install.sh $INSTALL_BINARY_NAME
|
||||||
|
|
||||||
FROM runtime-dev AS runc
|
FROM runtime-dev AS runc
|
||||||
ENV INSTALL_BINARY_NAME=runc
|
ENV INSTALL_BINARY_NAME=runc
|
||||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
RUN PREFIX=/build ./install.sh $INSTALL_BINARY_NAME
|
||||||
|
|
||||||
FROM base AS tini
|
FROM base AS tini
|
||||||
RUN apt-get update && apt-get install -y cmake vim-common
|
RUN apt-get update && apt-get install -y cmake vim-common
|
||||||
COPY hack/dockerfile/install/install.sh ./install.sh
|
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||||
ENV INSTALL_BINARY_NAME=tini
|
ENV INSTALL_BINARY_NAME=tini
|
||||||
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||||
|
RUN PREFIX=/build ./install.sh $INSTALL_BINARY_NAME
|
||||||
|
|
||||||
|
FROM base AS rootlesskit
|
||||||
|
ENV INSTALL_BINARY_NAME=rootlesskit
|
||||||
|
COPY hack/dockerfile/install/install.sh ./install.sh
|
||||||
|
COPY hack/dockerfile/install/$INSTALL_BINARY_NAME.installer ./
|
||||||
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
RUN PREFIX=/build/ ./install.sh $INSTALL_BINARY_NAME
|
||||||
|
COPY ./contrib/dockerd-rootless.sh /build
|
||||||
|
|
||||||
|
|
||||||
# TODO: Some of this is only really needed for testing, it would be nice to split this up
|
# TODO: Some of this is only really needed for testing, it would be nice to split this up
|
||||||
FROM runtime-dev AS dev
|
FROM runtime-dev AS dev
|
||||||
RUN groupadd -r docker
|
RUN groupadd -r docker
|
||||||
RUN useradd --create-home --gid docker unprivilegeduser
|
RUN useradd --create-home --gid docker unprivilegeduser
|
||||||
|
# Let us use a .bashrc file
|
||||||
|
RUN ln -sfv /go/src/github.com/docker/docker/.bashrc ~/.bashrc
|
||||||
# Activate bash completion and include Docker's completion if mounted with DOCKER_BASH_COMPLETION_PATH
|
# Activate bash completion and include Docker's completion if mounted with DOCKER_BASH_COMPLETION_PATH
|
||||||
RUN echo "source /usr/share/bash-completion/bash_completion" >> /etc/bash.bashrc
|
RUN echo "source /usr/share/bash-completion/bash_completion" >> /etc/bash.bashrc
|
||||||
RUN ln -s /usr/local/completion/bash/docker /etc/bash_completion.d/docker
|
RUN ln -s /usr/local/completion/bash/docker /etc/bash_completion.d/docker
|
||||||
|
@ -183,7 +175,11 @@ RUN apt-get update && apt-get install -y \
|
||||||
btrfs-tools \
|
btrfs-tools \
|
||||||
iptables \
|
iptables \
|
||||||
jq \
|
jq \
|
||||||
|
libcap2-bin \
|
||||||
libdevmapper-dev \
|
libdevmapper-dev \
|
||||||
|
# libffi-dev and libssl-dev appear to be required for compiling paramiko on s390x/ppc64le
|
||||||
|
libffi-dev \
|
||||||
|
libssl-dev \
|
||||||
libudev-dev \
|
libudev-dev \
|
||||||
libsystemd-dev \
|
libsystemd-dev \
|
||||||
binutils-mingw-w64 \
|
binutils-mingw-w64 \
|
||||||
|
@ -192,6 +188,8 @@ RUN apt-get update && apt-get install -y \
|
||||||
pigz \
|
pigz \
|
||||||
python-backports.ssl-match-hostname \
|
python-backports.ssl-match-hostname \
|
||||||
python-dev \
|
python-dev \
|
||||||
|
# python-cffi appears to be required for compiling paramiko on s390x/ppc64le
|
||||||
|
python-cffi \
|
||||||
python-mock \
|
python-mock \
|
||||||
python-pip \
|
python-pip \
|
||||||
python-requests \
|
python-requests \
|
||||||
|
@ -205,6 +203,9 @@ RUN apt-get update && apt-get install -y \
|
||||||
zip \
|
zip \
|
||||||
bzip2 \
|
bzip2 \
|
||||||
xz-utils \
|
xz-utils \
|
||||||
|
libprotobuf-c1 \
|
||||||
|
libnet1 \
|
||||||
|
libnl-3-200 \
|
||||||
--no-install-recommends
|
--no-install-recommends
|
||||||
COPY --from=swagger /build/swagger* /usr/local/bin/
|
COPY --from=swagger /build/swagger* /usr/local/bin/
|
||||||
COPY --from=frozen-images /build/ /docker-frozen-images
|
COPY --from=frozen-images /build/ /docker-frozen-images
|
||||||
|
@ -224,9 +225,12 @@ COPY --from=docker-py /build/ /docker-py
|
||||||
# split out into a separate image, including all the `python-*` deps installed
|
# split out into a separate image, including all the `python-*` deps installed
|
||||||
# above.
|
# above.
|
||||||
RUN cd /docker-py \
|
RUN cd /docker-py \
|
||||||
&& pip install docker-pycreds==0.2.1 \
|
&& pip install docker-pycreds==0.4.0 \
|
||||||
|
&& pip install paramiko==2.4.2 \
|
||||||
&& pip install yamllint==1.5.0 \
|
&& pip install yamllint==1.5.0 \
|
||||||
&& pip install -r test-requirements.txt
|
&& pip install -r test-requirements.txt
|
||||||
|
COPY --from=rootlesskit /build/ /usr/local/bin/
|
||||||
|
COPY --from=djs55/vpnkit@sha256:e508a17cfacc8fd39261d5b4e397df2b953690da577e2c987a47630cd0c42f8e /vpnkit /usr/local/bin/vpnkit.x86_64
|
||||||
|
|
||||||
ENV PATH=/usr/local/cli:$PATH
|
ENV PATH=/usr/local/cli:$PATH
|
||||||
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
|
ENV DOCKER_BUILDTAGS apparmor seccomp selinux
|
||||||
|
@ -236,5 +240,7 @@ WORKDIR /go/src/github.com/docker/docker
|
||||||
VOLUME /var/lib/docker
|
VOLUME /var/lib/docker
|
||||||
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
# Wrap all commands in the "docker-in-docker" script to allow nested containers
|
||||||
ENTRYPOINT ["hack/dind"]
|
ENTRYPOINT ["hack/dind"]
|
||||||
|
|
||||||
|
FROM dev AS final
|
||||||
# Upload docker source
|
# Upload docker source
|
||||||
COPY . /go/src/github.com/docker/docker
|
COPY . /go/src/github.com/docker/docker
|
||||||
|
|
|
@ -1,14 +1,13 @@
|
||||||
## Step 1: Build tests
|
## Step 1: Build tests
|
||||||
FROM golang:1.10.3-alpine3.7 as builder
|
FROM golang:1.12.1-alpine3.9 as builder
|
||||||
|
|
||||||
RUN apk add --update \
|
RUN apk --no-cache add \
|
||||||
bash \
|
bash \
|
||||||
btrfs-progs-dev \
|
btrfs-progs-dev \
|
||||||
build-base \
|
build-base \
|
||||||
curl \
|
curl \
|
||||||
lvm2-dev \
|
lvm2-dev \
|
||||||
jq \
|
jq
|
||||||
&& rm -rf /var/cache/apk/*
|
|
||||||
|
|
||||||
RUN mkdir -p /go/src/github.com/docker/docker/
|
RUN mkdir -p /go/src/github.com/docker/docker/
|
||||||
WORKDIR /go/src/github.com/docker/docker/
|
WORKDIR /go/src/github.com/docker/docker/
|
||||||
|
@ -40,10 +39,10 @@ RUN hack/make.sh build-integration-test-binary
|
||||||
RUN mkdir -p /output/tests && find . -name test.main -exec cp --parents '{}' /output/tests \;
|
RUN mkdir -p /output/tests && find . -name test.main -exec cp --parents '{}' /output/tests \;
|
||||||
|
|
||||||
## Step 2: Generate testing image
|
## Step 2: Generate testing image
|
||||||
FROM alpine:3.7 as runner
|
FROM alpine:3.8 as runner
|
||||||
|
|
||||||
# GNU tar is used for generating the emptyfs image
|
# GNU tar is used for generating the emptyfs image
|
||||||
RUN apk add --update \
|
RUN apk --no-cache add \
|
||||||
bash \
|
bash \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
g++ \
|
g++ \
|
||||||
|
@ -51,8 +50,7 @@ RUN apk add --update \
|
||||||
iptables \
|
iptables \
|
||||||
pigz \
|
pigz \
|
||||||
tar \
|
tar \
|
||||||
xz \
|
xz
|
||||||
&& rm -rf /var/cache/apk/*
|
|
||||||
|
|
||||||
# Add an unprivileged user to be used for tests which need it
|
# Add an unprivileged user to be used for tests which need it
|
||||||
RUN addgroup docker && adduser -D -G docker unprivilegeduser -s /bin/ash
|
RUN addgroup docker && adduser -D -G docker unprivilegeduser -s /bin/ash
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
# This represents the bare minimum required to build and test Docker.
|
# This represents the bare minimum required to build and test Docker.
|
||||||
|
|
||||||
FROM debian:stretch
|
FROM golang:1.12.1
|
||||||
|
|
||||||
# allow replacing httpredir or deb mirror
|
# allow replacing httpredir or deb mirror
|
||||||
ARG APT_MIRROR=deb.debian.org
|
ARG APT_MIRROR=deb.debian.org
|
||||||
|
@ -37,18 +37,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
vim-common \
|
vim-common \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Install Go
|
|
||||||
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
|
|
||||||
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
|
|
||||||
# with a heads-up.
|
|
||||||
# IMPORTANT: When updating this please note that stdlib archive/tar pkg is vendored
|
|
||||||
ENV GO_VERSION 1.10.3
|
|
||||||
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" \
|
|
||||||
| tar -xzC /usr/local
|
|
||||||
ENV PATH /go/bin:/usr/local/go/bin:$PATH
|
|
||||||
ENV GOPATH /go
|
|
||||||
ENV CGO_LDFLAGS -L/lib
|
|
||||||
|
|
||||||
# Install runc, containerd, tini and docker-proxy
|
# Install runc, containerd, tini and docker-proxy
|
||||||
# Please edit hack/dockerfile/install/<name>.installer to update them.
|
# Please edit hack/dockerfile/install/<name>.installer to update them.
|
||||||
COPY hack/dockerfile/install hack/dockerfile/install
|
COPY hack/dockerfile/install hack/dockerfile/install
|
||||||
|
|
|
@ -153,6 +153,13 @@
|
||||||
|
|
||||||
|
|
||||||
# The number of build steps below are explicitly minimised to improve performance.
|
# The number of build steps below are explicitly minimised to improve performance.
|
||||||
|
|
||||||
|
# Extremely important - do not change the following line to reference a "specific" image,
|
||||||
|
# such as `mcr.microsoft.com/windows/servercore:ltsc2019`. If using this Dockerfile in process
|
||||||
|
# isolated containers, the kernel of the host must match the container image, and hence
|
||||||
|
# would fail between Windows Server 2016 (aka RS1) and Windows Server 2019 (aka RS5).
|
||||||
|
# It is expected that the image `microsoft/windowsservercore:latest` is present, and matches
|
||||||
|
# the hosts kernel version before doing a build.
|
||||||
FROM microsoft/windowsservercore
|
FROM microsoft/windowsservercore
|
||||||
|
|
||||||
# Use PowerShell as the default shell
|
# Use PowerShell as the default shell
|
||||||
|
@ -161,7 +168,7 @@ SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPref
|
||||||
# Environment variable notes:
|
# Environment variable notes:
|
||||||
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
|
# - GO_VERSION must be consistent with 'Dockerfile' used by Linux.
|
||||||
# - FROM_DOCKERFILE is used for detection of building within a container.
|
# - FROM_DOCKERFILE is used for detection of building within a container.
|
||||||
ENV GO_VERSION=1.10.3 `
|
ENV GO_VERSION=1.12.1 `
|
||||||
GIT_VERSION=2.11.1 `
|
GIT_VERSION=2.11.1 `
|
||||||
GOPATH=C:\go `
|
GOPATH=C:\go `
|
||||||
FROM_DOCKERFILE=1
|
FROM_DOCKERFILE=1
|
||||||
|
|
|
@ -0,0 +1,325 @@
|
||||||
|
def withGithubStatus(String context, Closure cl) {
|
||||||
|
def setGithubStatus = { String state ->
|
||||||
|
try {
|
||||||
|
def backref = "${BUILD_URL}flowGraphTable/"
|
||||||
|
def reposSourceURL = scm.repositories[0].getURIs()[0].toString()
|
||||||
|
step(
|
||||||
|
$class: 'GitHubCommitStatusSetter',
|
||||||
|
contextSource: [$class: "ManuallyEnteredCommitContextSource", context: context],
|
||||||
|
errorHandlers: [[$class: 'ShallowAnyErrorHandler']],
|
||||||
|
reposSource: [$class: 'ManuallyEnteredRepositorySource', url: reposSourceURL],
|
||||||
|
statusBackrefSource: [$class: 'ManuallyEnteredBackrefSource', backref: backref],
|
||||||
|
statusResultSource: [$class: 'ConditionalStatusResultSource', results: [[$class: 'AnyBuildResult', state: state]]],
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
echo "Exception from GitHubCommitStatusSetter for $context: $err"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setGithubStatus 'PENDING'
|
||||||
|
|
||||||
|
try {
|
||||||
|
cl()
|
||||||
|
} catch (err) {
|
||||||
|
// AbortException signals a "normal" build failure.
|
||||||
|
if (!(err instanceof hudson.AbortException)) {
|
||||||
|
echo "Exception in withGithubStatus for $context: $err"
|
||||||
|
}
|
||||||
|
setGithubStatus 'FAILURE'
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
setGithubStatus 'SUCCESS'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pipeline {
|
||||||
|
agent none
|
||||||
|
options {
|
||||||
|
buildDiscarder(logRotator(daysToKeepStr: '30'))
|
||||||
|
timeout(time: 3, unit: 'HOURS')
|
||||||
|
}
|
||||||
|
parameters {
|
||||||
|
booleanParam(name: 'janky', defaultValue: true, description: 'x86 Build/Test')
|
||||||
|
booleanParam(name: 'experimental', defaultValue: true, description: 'x86 Experimental Build/Test ')
|
||||||
|
booleanParam(name: 'z', defaultValue: true, description: 'IBM Z (s390x) Build/Test')
|
||||||
|
booleanParam(name: 'powerpc', defaultValue: true, description: 'PowerPC (ppc64le) Build/Test')
|
||||||
|
booleanParam(name: 'vendor', defaultValue: true, description: 'Vendor')
|
||||||
|
booleanParam(name: 'windowsRS1', defaultValue: true, description: 'Windows 2016 (RS1) Build/Test')
|
||||||
|
booleanParam(name: 'windowsRS5', defaultValue: true, description: 'Windows 2019 (RS5) Build/Test')
|
||||||
|
}
|
||||||
|
stages {
|
||||||
|
stage('Build') {
|
||||||
|
parallel {
|
||||||
|
stage('janky') {
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression { params.janky }
|
||||||
|
}
|
||||||
|
agent {
|
||||||
|
node {
|
||||||
|
label 'ubuntu-1604-overlay2-stable'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
withCredentials([string(credentialsId: '52af932f-f13f-429e-8467-e7ff8b965cdb', variable: 'CODECOV_TOKEN')]) {
|
||||||
|
withGithubStatus('janky') {
|
||||||
|
sh '''
|
||||||
|
# todo: include ip_vs in base image
|
||||||
|
sudo modprobe ip_vs
|
||||||
|
|
||||||
|
GITCOMMIT=$(git rev-parse --short HEAD)
|
||||||
|
docker build --rm --force-rm --build-arg APT_MIRROR=cdn-fastly.deb.debian.org -t docker:$GITCOMMIT .
|
||||||
|
|
||||||
|
docker run --rm -t --privileged \
|
||||||
|
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||||
|
-v "$WORKSPACE/.git:/go/src/github.com/docker/docker/.git" \
|
||||||
|
--name docker-pr$BUILD_NUMBER \
|
||||||
|
-e DOCKER_GITCOMMIT=${GITCOMMIT} \
|
||||||
|
-e DOCKER_GRAPHDRIVER=vfs \
|
||||||
|
-e DOCKER_EXECDRIVER=native \
|
||||||
|
-e CODECOV_TOKEN \
|
||||||
|
-e GIT_SHA1=${GIT_COMMIT} \
|
||||||
|
docker:$GITCOMMIT \
|
||||||
|
hack/ci/janky
|
||||||
|
'''
|
||||||
|
sh '''
|
||||||
|
GITCOMMIT=$(git rev-parse --short HEAD)
|
||||||
|
echo "Building e2e image"
|
||||||
|
docker build --build-arg DOCKER_GITCOMMIT=$GITCOMMIT -t moby-e2e-test -f Dockerfile.e2e .
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
sh '''
|
||||||
|
echo "Ensuring container killed."
|
||||||
|
docker rm -vf docker-pr$BUILD_NUMBER || true
|
||||||
|
|
||||||
|
echo "Chowning /workspace to jenkins user"
|
||||||
|
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||||
|
'''
|
||||||
|
sh '''
|
||||||
|
echo "Creating bundles.tar.gz"
|
||||||
|
(find bundles -name '*.log' -o -name '*.prof' -o -name integration.test | xargs tar -czf bundles.tar.gz) || true
|
||||||
|
'''
|
||||||
|
archiveArtifacts artifacts: 'bundles.tar.gz'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('experimental') {
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression { params.experimental }
|
||||||
|
}
|
||||||
|
agent {
|
||||||
|
node {
|
||||||
|
label 'ubuntu-1604-aufs-stable'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
withGithubStatus('experimental') {
|
||||||
|
sh '''
|
||||||
|
GITCOMMIT=$(git rev-parse --short HEAD)
|
||||||
|
docker build --rm --force-rm --build-arg APT_MIRROR=cdn-fastly.deb.debian.org -t docker:${GITCOMMIT}-exp .
|
||||||
|
|
||||||
|
docker run --rm -t --privileged \
|
||||||
|
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||||
|
-e DOCKER_EXPERIMENTAL=y \
|
||||||
|
--name docker-pr-exp$BUILD_NUMBER \
|
||||||
|
-e DOCKER_GITCOMMIT=${GITCOMMIT} \
|
||||||
|
-e DOCKER_GRAPHDRIVER=vfs \
|
||||||
|
-e DOCKER_EXECDRIVER=native \
|
||||||
|
docker:${GITCOMMIT}-exp \
|
||||||
|
hack/ci/experimental
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
sh '''
|
||||||
|
echo "Ensuring container killed."
|
||||||
|
docker rm -vf docker-pr-exp$BUILD_NUMBER || true
|
||||||
|
|
||||||
|
echo "Chowning /workspace to jenkins user"
|
||||||
|
docker run --rm -v "$WORKSPACE:/workspace" busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||||
|
'''
|
||||||
|
sh '''
|
||||||
|
echo "Creating bundles.tar.gz"
|
||||||
|
(find bundles -name '*.log' -o -name '*.prof' -o -name integration.test | xargs tar -czf bundles.tar.gz) || true
|
||||||
|
'''
|
||||||
|
archiveArtifacts artifacts: 'bundles.tar.gz'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('z') {
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression { params.z }
|
||||||
|
}
|
||||||
|
agent {
|
||||||
|
node {
|
||||||
|
label 's390x-ubuntu-1604'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
withGithubStatus('z') {
|
||||||
|
sh '''
|
||||||
|
GITCOMMIT=$(git rev-parse --short HEAD)
|
||||||
|
|
||||||
|
test -f Dockerfile.s390x && \
|
||||||
|
docker build --rm --force-rm --build-arg APT_MIRROR=cdn-fastly.deb.debian.org -t docker-s390x:$GITCOMMIT -f Dockerfile.s390x . || \
|
||||||
|
docker build --rm --force-rm --build-arg APT_MIRROR=cdn-fastly.deb.debian.org -t docker-s390x:$GITCOMMIT -f Dockerfile .
|
||||||
|
|
||||||
|
docker run --rm -t --privileged \
|
||||||
|
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||||
|
--name docker-pr-s390x$BUILD_NUMBER \
|
||||||
|
-e DOCKER_GRAPHDRIVER=vfs \
|
||||||
|
-e DOCKER_EXECDRIVER=native \
|
||||||
|
-e TIMEOUT="300m" \
|
||||||
|
-e DOCKER_GITCOMMIT=${GITCOMMIT} \
|
||||||
|
docker-s390x:$GITCOMMIT \
|
||||||
|
hack/ci/z
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
sh '''
|
||||||
|
echo "Ensuring container killed."
|
||||||
|
docker rm -vf docker-pr-s390x$BUILD_NUMBER || true
|
||||||
|
|
||||||
|
echo "Chowning /workspace to jenkins user"
|
||||||
|
docker run --rm -v "$WORKSPACE:/workspace" s390x/busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||||
|
'''
|
||||||
|
sh '''
|
||||||
|
echo "Creating bundles.tar.gz"
|
||||||
|
find bundles -name '*.log' | xargs tar -czf bundles.tar.gz
|
||||||
|
'''
|
||||||
|
archiveArtifacts artifacts: 'bundles.tar.gz'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('powerpc') {
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression { params.powerpc }
|
||||||
|
}
|
||||||
|
agent {
|
||||||
|
node {
|
||||||
|
label 'ppc64le-ubuntu-1604'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
withGithubStatus('powerpc') {
|
||||||
|
sh '''
|
||||||
|
GITCOMMIT=$(git rev-parse --short HEAD)
|
||||||
|
|
||||||
|
test -f Dockerfile.ppc64le && \
|
||||||
|
docker build --rm --force-rm --build-arg APT_MIRROR=cdn-fastly.deb.debian.org -t docker-powerpc:$GITCOMMIT -f Dockerfile.ppc64le . || \
|
||||||
|
docker build --rm --force-rm --build-arg APT_MIRROR=cdn-fastly.deb.debian.org -t docker-powerpc:$GITCOMMIT -f Dockerfile .
|
||||||
|
|
||||||
|
docker run --rm -t --privileged \
|
||||||
|
-v "$WORKSPACE/bundles:/go/src/github.com/docker/docker/bundles" \
|
||||||
|
--name docker-pr-power$BUILD_NUMBER \
|
||||||
|
-e DOCKER_GRAPHDRIVER=vfs \
|
||||||
|
-e DOCKER_EXECDRIVER=native \
|
||||||
|
-e DOCKER_GITCOMMIT=${GITCOMMIT} \
|
||||||
|
-e TIMEOUT="180m" \
|
||||||
|
docker-powerpc:$GITCOMMIT \
|
||||||
|
hack/ci/powerpc
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
sh '''
|
||||||
|
echo "Ensuring container killed."
|
||||||
|
docker rm -vf docker-pr-power$BUILD_NUMBER || true
|
||||||
|
|
||||||
|
echo "Chowning /workspace to jenkins user"
|
||||||
|
docker run --rm -v "$WORKSPACE:/workspace" ppc64le/busybox chown -R "$(id -u):$(id -g)" /workspace
|
||||||
|
'''
|
||||||
|
sh '''
|
||||||
|
echo "Creating bundles.tar.gz"
|
||||||
|
find bundles -name '*.log' | xargs tar -czf bundles.tar.gz
|
||||||
|
'''
|
||||||
|
archiveArtifacts artifacts: 'bundles.tar.gz'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('vendor') {
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression { params.vendor }
|
||||||
|
}
|
||||||
|
agent {
|
||||||
|
node {
|
||||||
|
label 'ubuntu-1604-aufs-stable'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
withGithubStatus('vendor') {
|
||||||
|
sh '''
|
||||||
|
GITCOMMIT=$(git rev-parse --short HEAD)
|
||||||
|
|
||||||
|
docker build --rm --force-rm --build-arg APT_MIRROR=cdn-fastly.deb.debian.org -t dockerven:$GITCOMMIT .
|
||||||
|
|
||||||
|
docker run --rm -t --privileged \
|
||||||
|
--name dockerven-pr$BUILD_NUMBER \
|
||||||
|
-e DOCKER_GRAPHDRIVER=vfs \
|
||||||
|
-e DOCKER_EXECDRIVER=native \
|
||||||
|
-v "$WORKSPACE/.git:/go/src/github.com/docker/docker/.git" \
|
||||||
|
-e DOCKER_GITCOMMIT=${GITCOMMIT} \
|
||||||
|
-e TIMEOUT=120m dockerven:$GITCOMMIT \
|
||||||
|
hack/validate/vendor
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('windowsRS1') {
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression { params.windowsRS1 }
|
||||||
|
}
|
||||||
|
agent {
|
||||||
|
node {
|
||||||
|
label 'windows-rs1'
|
||||||
|
customWorkspace 'c:\\gopath\\src\\github.com\\docker\\docker'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
withGithubStatus('windowsRS1') {
|
||||||
|
powershell '''
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
.\\hack\\ci\\windows.ps1
|
||||||
|
exit $LastExitCode
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('windowsRS5-process') {
|
||||||
|
when {
|
||||||
|
beforeAgent true
|
||||||
|
expression { params.windowsRS5 }
|
||||||
|
}
|
||||||
|
agent {
|
||||||
|
node {
|
||||||
|
label 'windows-rs5'
|
||||||
|
customWorkspace 'c:\\gopath\\src\\github.com\\docker\\docker'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
withGithubStatus('windowsRS5-process') {
|
||||||
|
powershell '''
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
.\\hack\\ci\\windows.ps1
|
||||||
|
exit $LastExitCode
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -176,7 +176,7 @@
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
Copyright 2013-2017 Docker, Inc.
|
Copyright 2013-2018 Docker, Inc.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
"jhowardmsft",
|
"jhowardmsft",
|
||||||
"johnstep",
|
"johnstep",
|
||||||
"justincormack",
|
"justincormack",
|
||||||
|
"kolyshkin",
|
||||||
"mhbauer",
|
"mhbauer",
|
||||||
"mlaventure",
|
"mlaventure",
|
||||||
"runcom",
|
"runcom",
|
||||||
|
@ -50,15 +51,6 @@
|
||||||
"yongtang"
|
"yongtang"
|
||||||
]
|
]
|
||||||
|
|
||||||
[Org."Docs maintainers"]
|
|
||||||
|
|
||||||
# TODO Describe the docs maintainers role.
|
|
||||||
|
|
||||||
people = [
|
|
||||||
"misty",
|
|
||||||
"thajeztah"
|
|
||||||
]
|
|
||||||
|
|
||||||
[Org.Curators]
|
[Org.Curators]
|
||||||
|
|
||||||
# The curators help ensure that incoming issues and pull requests are properly triaged and
|
# The curators help ensure that incoming issues and pull requests are properly triaged and
|
||||||
|
@ -78,6 +70,7 @@
|
||||||
"chanwit",
|
"chanwit",
|
||||||
"fntlnz",
|
"fntlnz",
|
||||||
"gianarb",
|
"gianarb",
|
||||||
|
"olljanat",
|
||||||
"programmerq",
|
"programmerq",
|
||||||
"rheinwein",
|
"rheinwein",
|
||||||
"ripcurld",
|
"ripcurld",
|
||||||
|
@ -162,7 +155,7 @@
|
||||||
|
|
||||||
# Alexander Morozov contributed many features to Docker, worked on the premise of
|
# Alexander Morozov contributed many features to Docker, worked on the premise of
|
||||||
# what later became containerd (and worked on that too), and made a "stupid" Go
|
# what later became containerd (and worked on that too), and made a "stupid" Go
|
||||||
# vendor tool specificaly for docker/docker needs: vndr (https://github.com/LK4D4/vndr).
|
# vendor tool specifically for docker/docker needs: vndr (https://github.com/LK4D4/vndr).
|
||||||
# Not many know that Alexander is a master negotiator, being able to change course
|
# Not many know that Alexander is a master negotiator, being able to change course
|
||||||
# of action with a single "Nope, we're not gonna do that".
|
# of action with a single "Nope, we're not gonna do that".
|
||||||
"lk4d4",
|
"lk4d4",
|
||||||
|
@ -365,6 +358,11 @@
|
||||||
Email = "justin.cormack@docker.com"
|
Email = "justin.cormack@docker.com"
|
||||||
GitHub = "justincormack"
|
GitHub = "justincormack"
|
||||||
|
|
||||||
|
[people.kolyshkin]
|
||||||
|
Name = "Kir Kolyshkin"
|
||||||
|
Email = "kolyshkin@gmail.com"
|
||||||
|
GitHub = "kolyshkin"
|
||||||
|
|
||||||
[people.lk4d4]
|
[people.lk4d4]
|
||||||
Name = "Alexander Morozov"
|
Name = "Alexander Morozov"
|
||||||
Email = "lk4d4@docker.com"
|
Email = "lk4d4@docker.com"
|
||||||
|
@ -380,11 +378,6 @@
|
||||||
Email = "mbauer@us.ibm.com"
|
Email = "mbauer@us.ibm.com"
|
||||||
GitHub = "mhbauer"
|
GitHub = "mhbauer"
|
||||||
|
|
||||||
[people.misty]
|
|
||||||
Name = "Misty Stanley-Jones"
|
|
||||||
Email = "misty@docker.com"
|
|
||||||
GitHub = "mistyhacks"
|
|
||||||
|
|
||||||
[people.mlaventure]
|
[people.mlaventure]
|
||||||
Name = "Kenfe-Mickaël Laventure"
|
Name = "Kenfe-Mickaël Laventure"
|
||||||
Email = "mickael.laventure@gmail.com"
|
Email = "mickael.laventure@gmail.com"
|
||||||
|
@ -400,6 +393,11 @@
|
||||||
Email = "mrjana@docker.com"
|
Email = "mrjana@docker.com"
|
||||||
GitHub = "mrjana"
|
GitHub = "mrjana"
|
||||||
|
|
||||||
|
[people.olljanat]
|
||||||
|
Name = "Olli Janatuinen"
|
||||||
|
Email = "olli.janatuinen@gmail.com"
|
||||||
|
GitHub = "olljanat"
|
||||||
|
|
||||||
[people.programmerq]
|
[people.programmerq]
|
||||||
Name = "Jeff Anderson"
|
Name = "Jeff Anderson"
|
||||||
Email = "jeff@docker.com"
|
Email = "jeff@docker.com"
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
.PHONY: all binary dynbinary build cross help init-go-pkg-cache install manpages run shell test test-docker-py test-integration test-unit validate win
|
.PHONY: all binary dynbinary build cross help install manpages run shell test test-docker-py test-integration test-unit validate win
|
||||||
|
|
||||||
# set the graph driver as the current graphdriver if not set
|
# set the graph driver as the current graphdriver if not set
|
||||||
DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //'))
|
DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //'))
|
||||||
export DOCKER_GRAPHDRIVER
|
export DOCKER_GRAPHDRIVER
|
||||||
DOCKER_INCREMENTAL_BINARY := $(if $(DOCKER_INCREMENTAL_BINARY),$(DOCKER_INCREMENTAL_BINARY),1)
|
|
||||||
export DOCKER_INCREMENTAL_BINARY
|
|
||||||
|
|
||||||
# get OS/Arch of docker engine
|
# get OS/Arch of docker engine
|
||||||
DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKER_ENGINE_OSARCH}')
|
DOCKER_OSARCH := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $${DOCKER_ENGINE_OSARCH}')
|
||||||
|
@ -13,6 +11,12 @@ DOCKERFILE := $(shell bash -c 'source hack/make/.detect-daemon-osarch && echo $$
|
||||||
DOCKER_GITCOMMIT := $(shell git rev-parse --short HEAD || echo unsupported)
|
DOCKER_GITCOMMIT := $(shell git rev-parse --short HEAD || echo unsupported)
|
||||||
export DOCKER_GITCOMMIT
|
export DOCKER_GITCOMMIT
|
||||||
|
|
||||||
|
# allow overriding the repository and branch that validation scripts are running
|
||||||
|
# against these are used in hack/validate/.validate to check what changed in the PR.
|
||||||
|
export VALIDATE_REPO
|
||||||
|
export VALIDATE_BRANCH
|
||||||
|
export VALIDATE_ORIGIN_BRANCH
|
||||||
|
|
||||||
# env vars passed through directly to Docker's build scripts
|
# env vars passed through directly to Docker's build scripts
|
||||||
# to allow things like `make KEEPBUNDLE=1 binary` easily
|
# to allow things like `make KEEPBUNDLE=1 binary` easily
|
||||||
# `project/PACKAGERS.md` have some limited documentation of some of these
|
# `project/PACKAGERS.md` have some limited documentation of some of these
|
||||||
|
@ -30,14 +34,15 @@ DOCKER_ENVS := \
|
||||||
-e KEEPBUNDLE \
|
-e KEEPBUNDLE \
|
||||||
-e DOCKER_BUILD_ARGS \
|
-e DOCKER_BUILD_ARGS \
|
||||||
-e DOCKER_BUILD_GOGC \
|
-e DOCKER_BUILD_GOGC \
|
||||||
|
-e DOCKER_BUILD_OPTS \
|
||||||
-e DOCKER_BUILD_PKGS \
|
-e DOCKER_BUILD_PKGS \
|
||||||
|
-e DOCKER_BUILDKIT \
|
||||||
-e DOCKER_BASH_COMPLETION_PATH \
|
-e DOCKER_BASH_COMPLETION_PATH \
|
||||||
-e DOCKER_CLI_PATH \
|
-e DOCKER_CLI_PATH \
|
||||||
-e DOCKER_DEBUG \
|
-e DOCKER_DEBUG \
|
||||||
-e DOCKER_EXPERIMENTAL \
|
-e DOCKER_EXPERIMENTAL \
|
||||||
-e DOCKER_GITCOMMIT \
|
-e DOCKER_GITCOMMIT \
|
||||||
-e DOCKER_GRAPHDRIVER \
|
-e DOCKER_GRAPHDRIVER \
|
||||||
-e DOCKER_INCREMENTAL_BINARY \
|
|
||||||
-e DOCKER_LDFLAGS \
|
-e DOCKER_LDFLAGS \
|
||||||
-e DOCKER_PORT \
|
-e DOCKER_PORT \
|
||||||
-e DOCKER_REMAP_ROOT \
|
-e DOCKER_REMAP_ROOT \
|
||||||
|
@ -48,6 +53,9 @@ DOCKER_ENVS := \
|
||||||
-e TESTDIRS \
|
-e TESTDIRS \
|
||||||
-e TESTFLAGS \
|
-e TESTFLAGS \
|
||||||
-e TIMEOUT \
|
-e TIMEOUT \
|
||||||
|
-e VALIDATE_REPO \
|
||||||
|
-e VALIDATE_BRANCH \
|
||||||
|
-e VALIDATE_ORIGIN_BRANCH \
|
||||||
-e HTTP_PROXY \
|
-e HTTP_PROXY \
|
||||||
-e HTTPS_PROXY \
|
-e HTTPS_PROXY \
|
||||||
-e NO_PROXY \
|
-e NO_PROXY \
|
||||||
|
@ -55,13 +63,18 @@ DOCKER_ENVS := \
|
||||||
-e https_proxy \
|
-e https_proxy \
|
||||||
-e no_proxy \
|
-e no_proxy \
|
||||||
-e VERSION \
|
-e VERSION \
|
||||||
-e PLATFORM
|
-e PLATFORM \
|
||||||
|
-e DEFAULT_PRODUCT_LICENSE \
|
||||||
|
-e PRODUCT
|
||||||
# note: we _cannot_ add "-e DOCKER_BUILDTAGS" here because even if it's unset in the shell, that would shadow the "ENV DOCKER_BUILDTAGS" set in our Dockerfile, which is very important for our official builds
|
# note: we _cannot_ add "-e DOCKER_BUILDTAGS" here because even if it's unset in the shell, that would shadow the "ENV DOCKER_BUILDTAGS" set in our Dockerfile, which is very important for our official builds
|
||||||
|
|
||||||
# to allow `make BIND_DIR=. shell` or `make BIND_DIR= test`
|
# to allow `make BIND_DIR=. shell` or `make BIND_DIR= test`
|
||||||
# (default to no bind mount if DOCKER_HOST is set)
|
# (default to no bind mount if DOCKER_HOST is set)
|
||||||
# note: BINDDIR is supported for backwards-compatibility here
|
# note: BINDDIR is supported for backwards-compatibility here
|
||||||
BIND_DIR := $(if $(BINDDIR),$(BINDDIR),$(if $(DOCKER_HOST),,bundles))
|
BIND_DIR := $(if $(BINDDIR),$(BINDDIR),$(if $(DOCKER_HOST),,bundles))
|
||||||
|
|
||||||
|
# DOCKER_MOUNT can be overriden, but use at your own risk!
|
||||||
|
ifndef DOCKER_MOUNT
|
||||||
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)")
|
DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/docker/docker/$(BIND_DIR)")
|
||||||
|
|
||||||
# This allows the test suite to be able to run without worrying about the underlying fs used by the container running the daemon (e.g. aufs-on-aufs), so long as the host running the container is running a supported fs.
|
# This allows the test suite to be able to run without worrying about the underlying fs used by the container running the daemon (e.g. aufs-on-aufs), so long as the host running the container is running a supported fs.
|
||||||
|
@ -69,17 +82,14 @@ DOCKER_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/do
|
||||||
# Note that `BIND_DIR` will already be set to `bundles` if `DOCKER_HOST` is not set (see above BIND_DIR line), in such case this will do nothing since `DOCKER_MOUNT` will already be set.
|
# Note that `BIND_DIR` will already be set to `bundles` if `DOCKER_HOST` is not set (see above BIND_DIR line), in such case this will do nothing since `DOCKER_MOUNT` will already be set.
|
||||||
DOCKER_MOUNT := $(if $(DOCKER_MOUNT),$(DOCKER_MOUNT),-v /go/src/github.com/docker/docker/bundles) -v "$(CURDIR)/.git:/go/src/github.com/docker/docker/.git"
|
DOCKER_MOUNT := $(if $(DOCKER_MOUNT),$(DOCKER_MOUNT),-v /go/src/github.com/docker/docker/bundles) -v "$(CURDIR)/.git:/go/src/github.com/docker/docker/.git"
|
||||||
|
|
||||||
# This allows to set the docker-dev container name
|
DOCKER_MOUNT_CACHE := -v docker-dev-cache:/root/.cache
|
||||||
DOCKER_CONTAINER_NAME := $(if $(CONTAINER_NAME),--name $(CONTAINER_NAME),)
|
|
||||||
|
|
||||||
# enable package cache if DOCKER_INCREMENTAL_BINARY and DOCKER_MOUNT (i.e.DOCKER_HOST) are set
|
|
||||||
PKGCACHE_MAP := gopath:/go/pkg goroot-linux_amd64:/usr/local/go/pkg/linux_amd64 goroot-linux_amd64_netgo:/usr/local/go/pkg/linux_amd64_netgo
|
|
||||||
PKGCACHE_VOLROOT := dockerdev-go-pkg-cache
|
|
||||||
PKGCACHE_VOL := $(if $(PKGCACHE_DIR),$(CURDIR)/$(PKGCACHE_DIR)/,$(PKGCACHE_VOLROOT)-)
|
|
||||||
DOCKER_MOUNT_PKGCACHE := $(if $(DOCKER_INCREMENTAL_BINARY),$(shell echo $(PKGCACHE_MAP) | sed -E 's@([^ ]*)@-v "$(PKGCACHE_VOL)\1"@g'),)
|
|
||||||
DOCKER_MOUNT_CLI := $(if $(DOCKER_CLI_PATH),-v $(shell dirname $(DOCKER_CLI_PATH)):/usr/local/cli,)
|
DOCKER_MOUNT_CLI := $(if $(DOCKER_CLI_PATH),-v $(shell dirname $(DOCKER_CLI_PATH)):/usr/local/cli,)
|
||||||
DOCKER_MOUNT_BASH_COMPLETION := $(if $(DOCKER_BASH_COMPLETION_PATH),-v $(shell dirname $(DOCKER_BASH_COMPLETION_PATH)):/usr/local/completion/bash,)
|
DOCKER_MOUNT_BASH_COMPLETION := $(if $(DOCKER_BASH_COMPLETION_PATH),-v $(shell dirname $(DOCKER_BASH_COMPLETION_PATH)):/usr/local/completion/bash,)
|
||||||
DOCKER_MOUNT := $(DOCKER_MOUNT) $(DOCKER_MOUNT_PKGCACHE) $(DOCKER_MOUNT_CLI) $(DOCKER_MOUNT_BASH_COMPLETION)
|
DOCKER_MOUNT := $(DOCKER_MOUNT) $(DOCKER_MOUNT_CACHE) $(DOCKER_MOUNT_CLI) $(DOCKER_MOUNT_BASH_COMPLETION)
|
||||||
|
endif # ifndef DOCKER_MOUNT
|
||||||
|
|
||||||
|
# This allows to set the docker-dev container name
|
||||||
|
DOCKER_CONTAINER_NAME := $(if $(CONTAINER_NAME),--name $(CONTAINER_NAME),)
|
||||||
|
|
||||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
||||||
GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g")
|
GIT_BRANCH_CLEAN := $(shell echo $(GIT_BRANCH) | sed -e "s/[^[:alnum:]]/-/g")
|
||||||
|
@ -107,6 +117,9 @@ INTERACTIVE := $(shell [ -t 0 ] && echo 1 || echo 0)
|
||||||
ifeq ($(INTERACTIVE), 1)
|
ifeq ($(INTERACTIVE), 1)
|
||||||
DOCKER_FLAGS += -t
|
DOCKER_FLAGS += -t
|
||||||
endif
|
endif
|
||||||
|
ifeq ($(BIND_DIR), .)
|
||||||
|
DOCKER_BUILD_OPTS += --target=dev
|
||||||
|
endif
|
||||||
|
|
||||||
DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)"
|
DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)"
|
||||||
|
|
||||||
|
@ -121,28 +134,26 @@ binary: build ## build the linux binaries
|
||||||
dynbinary: build ## build the linux dynbinaries
|
dynbinary: build ## build the linux dynbinaries
|
||||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary
|
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary
|
||||||
|
|
||||||
build: bundles init-go-pkg-cache
|
build: DOCKER_BUILDKIT ?= 1
|
||||||
|
build: bundles
|
||||||
$(warning The docker client CLI has moved to github.com/docker/cli. For a dev-test cycle involving the CLI, run:${\n} DOCKER_CLI_PATH=/host/path/to/cli/binary make shell ${\n} then change the cli and compile into a binary at the same location.${\n})
|
$(warning The docker client CLI has moved to github.com/docker/cli. For a dev-test cycle involving the CLI, run:${\n} DOCKER_CLI_PATH=/host/path/to/cli/binary make shell ${\n} then change the cli and compile into a binary at the same location.${\n})
|
||||||
docker build ${BUILD_APT_MIRROR} ${DOCKER_BUILD_ARGS} -t "$(DOCKER_IMAGE)" -f "$(DOCKERFILE)" .
|
DOCKER_BUILDKIT="${DOCKER_BUILDKIT}" docker build ${BUILD_APT_MIRROR} ${DOCKER_BUILD_ARGS} ${DOCKER_BUILD_OPTS} -t "$(DOCKER_IMAGE)" -f "$(DOCKERFILE)" .
|
||||||
|
|
||||||
bundles:
|
bundles:
|
||||||
mkdir bundles
|
mkdir bundles
|
||||||
|
|
||||||
clean: clean-pkg-cache-vol ## clean up cached resources
|
.PHONY: clean
|
||||||
|
clean: clean-cache
|
||||||
|
|
||||||
clean-pkg-cache-vol:
|
.PHONY: clean-cache
|
||||||
@- $(foreach mapping,$(PKGCACHE_MAP), \
|
clean-cache:
|
||||||
$(shell docker volume rm $(PKGCACHE_VOLROOT)-$(shell echo $(mapping) | awk -F':/' '{ print $$1 }') > /dev/null 2>&1) \
|
docker volume rm -f docker-dev-cache
|
||||||
)
|
|
||||||
|
|
||||||
cross: build ## cross build the binaries for darwin, freebsd and\nwindows
|
cross: build ## cross build the binaries for darwin, freebsd and\nwindows
|
||||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross
|
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross
|
||||||
|
|
||||||
help: ## this help
|
help: ## this help
|
||||||
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z0-9_-]+:.*?## / {gsub("\\\\n",sprintf("\n%22c",""), $$2);printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
|
||||||
|
|
||||||
init-go-pkg-cache:
|
|
||||||
$(if $(PKGCACHE_DIR), mkdir -p $(shell echo $(PKGCACHE_MAP) | sed -E 's@([^: ]*):[^ ]*@$(PKGCACHE_DIR)/\1@g'))
|
|
||||||
|
|
||||||
install: ## install the linux binaries
|
install: ## install the linux binaries
|
||||||
KEEPBUNDLE=1 hack/make.sh install-binary
|
KEEPBUNDLE=1 hack/make.sh install-binary
|
||||||
|
@ -164,6 +175,9 @@ test-integration-cli: test-integration ## (DEPRECATED) use test-integration
|
||||||
test-integration: build ## run the integration tests
|
test-integration: build ## run the integration tests
|
||||||
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-integration
|
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-integration
|
||||||
|
|
||||||
|
test-integration-flaky: build ## run the stress test for all new integration tests
|
||||||
|
$(DOCKER_RUN_DOCKER) hack/make.sh dynbinary test-integration-flaky
|
||||||
|
|
||||||
test-unit: build ## run the unit tests
|
test-unit: build ## run the unit tests
|
||||||
$(DOCKER_RUN_DOCKER) hack/test/unit
|
$(DOCKER_RUN_DOCKER) hack/test/unit
|
||||||
|
|
||||||
|
@ -171,7 +185,7 @@ validate: build ## validate DCO, Seccomp profile generation, gofmt,\n./pkg/ isol
|
||||||
$(DOCKER_RUN_DOCKER) hack/validate/all
|
$(DOCKER_RUN_DOCKER) hack/validate/all
|
||||||
|
|
||||||
win: build ## cross build the binary for windows
|
win: build ## cross build the binary for windows
|
||||||
$(DOCKER_RUN_DOCKER) hack/make.sh win
|
$(DOCKER_RUN_DOCKER) DOCKER_CROSSPLATFORMS=windows/amd64 hack/make.sh cross
|
||||||
|
|
||||||
.PHONY: swagger-gen
|
.PHONY: swagger-gen
|
||||||
swagger-gen:
|
swagger-gen:
|
||||||
|
@ -194,12 +208,11 @@ build-integration-cli-on-swarm: build ## build images and binary for running int
|
||||||
go build -buildmode=pie -o ./hack/integration-cli-on-swarm/integration-cli-on-swarm ./hack/integration-cli-on-swarm/host
|
go build -buildmode=pie -o ./hack/integration-cli-on-swarm/integration-cli-on-swarm ./hack/integration-cli-on-swarm/host
|
||||||
@echo "Building $(INTEGRATION_CLI_MASTER_IMAGE)"
|
@echo "Building $(INTEGRATION_CLI_MASTER_IMAGE)"
|
||||||
docker build -t $(INTEGRATION_CLI_MASTER_IMAGE) hack/integration-cli-on-swarm/agent
|
docker build -t $(INTEGRATION_CLI_MASTER_IMAGE) hack/integration-cli-on-swarm/agent
|
||||||
# For worker, we don't use `docker build` so as to enable DOCKER_INCREMENTAL_BINARY and so on
|
|
||||||
@echo "Building $(INTEGRATION_CLI_WORKER_IMAGE) from $(DOCKER_IMAGE)"
|
@echo "Building $(INTEGRATION_CLI_WORKER_IMAGE) from $(DOCKER_IMAGE)"
|
||||||
$(eval tmp := integration-cli-worker-tmp)
|
$(eval tmp := integration-cli-worker-tmp)
|
||||||
# We mount pkgcache, but not bundle (bundle needs to be baked into the image)
|
# We mount pkgcache, but not bundle (bundle needs to be baked into the image)
|
||||||
# For avoiding bakings DOCKER_GRAPHDRIVER and so on to image, we cannot use $(DOCKER_ENVS) here
|
# For avoiding bakings DOCKER_GRAPHDRIVER and so on to image, we cannot use $(DOCKER_ENVS) here
|
||||||
docker run -t -d --name $(tmp) -e DOCKER_GITCOMMIT -e BUILDFLAGS -e DOCKER_INCREMENTAL_BINARY --privileged $(DOCKER_MOUNT_PKGCACHE) $(DOCKER_IMAGE) top
|
docker run -t -d --name $(tmp) -e DOCKER_GITCOMMIT -e BUILDFLAGS --privileged $(DOCKER_IMAGE) top
|
||||||
docker exec $(tmp) hack/make.sh build-integration-test-binary dynbinary
|
docker exec $(tmp) hack/make.sh build-integration-test-binary dynbinary
|
||||||
docker exec $(tmp) go build -buildmode=pie -o /worker github.com/docker/docker/hack/integration-cli-on-swarm/agent/worker
|
docker exec $(tmp) go build -buildmode=pie -o /worker github.com/docker/docker/hack/integration-cli-on-swarm/agent/worker
|
||||||
docker commit -c 'ENTRYPOINT ["/worker"]' $(tmp) $(INTEGRATION_CLI_WORKER_IMAGE)
|
docker commit -c 'ENTRYPOINT ["/worker"]' $(tmp) $(INTEGRATION_CLI_WORKER_IMAGE)
|
||||||
|
|
|
@ -35,34 +35,83 @@ issue, in the Slack channel, or in person at the Moby Summits that happen every
|
||||||
|
|
||||||
## 1.1 Runtime improvements
|
## 1.1 Runtime improvements
|
||||||
|
|
||||||
We introduced [`runC`](https://runc.io) as a standalone low-level tool for container
|
Over time we have accumulated a lot of functionality in the container runtime
|
||||||
execution in 2015, the first stage in spinning out parts of the Engine into standalone tools.
|
aspect of Moby while also growing in other areas. Much of the container runtime
|
||||||
|
pieces are now duplicated work available in other, lower level components such
|
||||||
|
as [containerd](https://containerd.io).
|
||||||
|
|
||||||
As runC continued evolving, and the OCI specification along with it, we created
|
Moby currently only utilizes containerd for basic runtime state management, e.g. starting
|
||||||
[`containerd`](https://github.com/containerd/containerd), a daemon to control and monitor `runC`.
|
and stopping a container, which is what the pre-containerd 1.0 daemon provided.
|
||||||
In late 2016 this was relaunched as the `containerd` 1.0 track, aiming to provide a common runtime
|
Now that containerd is a full-fledged container runtime which supports full
|
||||||
for the whole spectrum of container systems, including Kubernetes, with wide community support.
|
container life-cycle management, we would like to start relying more on containerd
|
||||||
This change meant that there was an increased scope for `containerd`, including image management
|
and removing the bits in Moby which are now duplicated. This will necessitate
|
||||||
and storage drivers.
|
a significant effort to refactor and even remove large parts of Moby's codebase.
|
||||||
|
|
||||||
Moby will rely on a long-running `containerd` companion daemon for all container execution
|
Tracking issues:
|
||||||
related operations. This could open the door in the future for Engine restarts without interrupting
|
|
||||||
running containers. The switch over to containerd 1.0 is an important goal for the project, and
|
|
||||||
will result in a significant simplification of the functions implemented in this repository.
|
|
||||||
|
|
||||||
## 1.2 Internal decoupling
|
- [#38043](https://github.com/moby/moby/issues/38043) Proposal: containerd image integration
|
||||||
|
|
||||||
|
## 1.2 Image Builder
|
||||||
|
|
||||||
|
Work is ongoing to integrate [BuildKit](https://github.com/moby/buildkit) into
|
||||||
|
Moby and replace the "v0" build implementation. Buildkit offers better cache
|
||||||
|
management, parallelizable build steps, and better extensibility while also
|
||||||
|
keeping builds portable, a chief tenent of Moby's builder.
|
||||||
|
|
||||||
|
Upon completion of this effort, users will have a builder that performs better
|
||||||
|
while also being more extensible, enabling users to provide their own custom
|
||||||
|
syntax which can be either Dockerfile-like or something completely different.
|
||||||
|
|
||||||
|
See [buildpacks on buildkit](https://github.com/tonistiigi/buildkit-pack) as an
|
||||||
|
example of this extensibility.
|
||||||
|
|
||||||
|
New features for the builder and Dockerfile should be implemented first in the
|
||||||
|
BuildKit backend using an external Dockerfile implementation from the container
|
||||||
|
images. This allows everyone to test and evaluate the feature without upgrading
|
||||||
|
their daemon. New features should go to the experimental channel first, and can be
|
||||||
|
part of the `docker/dockerfile:experimental` image. From there they graduate to
|
||||||
|
`docker/dockerfile:latest` and binary releases. The Dockerfile frontend source
|
||||||
|
code is temporarily located at
|
||||||
|
[https://github.com/moby/buildkit/tree/master/frontend/dockerfile](https://github.com/moby/buildkit/tree/master/frontend/dockerfile)
|
||||||
|
with separate new features defined with go build tags.
|
||||||
|
|
||||||
|
Tracking issues:
|
||||||
|
|
||||||
|
- [#32925](https://github.com/moby/moby/issues/32925) discussion: builder future: buildkit
|
||||||
|
|
||||||
|
## 1.3 Rootless Mode
|
||||||
|
|
||||||
|
Running the daemon requires elevated privileges for many tasks. We would like to
|
||||||
|
support running the daemon as a normal, unprivileged user without requiring `suid`
|
||||||
|
binaries.
|
||||||
|
|
||||||
|
Tracking issues:
|
||||||
|
|
||||||
|
- [#37375](https://github.com/moby/moby/issues/37375) Proposal: allow running `dockerd` as an unprivileged user (aka rootless mode)
|
||||||
|
|
||||||
|
## 1.4 Testing
|
||||||
|
|
||||||
|
Moby has many tests, both unit and integration. Moby needs more tests which can
|
||||||
|
cover the full spectrum functionality and edge cases out there.
|
||||||
|
|
||||||
|
Tests in the `integration-cli` folder should also be migrated into (both in
|
||||||
|
location and style) the `integration` folder. These newer tests are simpler to
|
||||||
|
run in isolation, simpler to read, simpler to write, and more fully exercise the
|
||||||
|
API. Meanwhile tests of the docker CLI should generally live in docker/cli.
|
||||||
|
|
||||||
|
Tracking issues:
|
||||||
|
|
||||||
|
- [#32866](https://github.com/moby/moby/issues/32866) Replace integration-cli suite with API test suite
|
||||||
|
|
||||||
|
## 1.5 Internal decoupling
|
||||||
|
|
||||||
A lot of work has been done in trying to decouple Moby internals. This process of creating
|
A lot of work has been done in trying to decouple Moby internals. This process of creating
|
||||||
standalone projects with a well defined function that attract a dedicated community should continue.
|
standalone projects with a well defined function that attract a dedicated community should continue.
|
||||||
As well as integrating `containerd` we would like to integrate [BuildKit](https://github.com/moby/buildkit)
|
As well as integrating `containerd` we would like to integrate [BuildKit](https://github.com/moby/buildkit)
|
||||||
as the next standalone component.
|
as the next standalone component.
|
||||||
|
|
||||||
We see gRPC as the natural communication layer between decoupled components.
|
We see gRPC as the natural communication layer between decoupled components.
|
||||||
|
|
||||||
## 1.3 Custom assembly tooling
|
In addition to pushing out large components into other projects, much of the
|
||||||
|
internal code structure, and in particular the
|
||||||
We have been prototyping the Moby [assembly tool](https://github.com/moby/tool) which was originally
|
["Daemon"](https://godoc.org/github.com/docker/docker/daemon#Daemon) object,
|
||||||
developed for LinuxKit and intend to turn it into a more generic packaging and assembly mechanism
|
should be split into smaller, more manageable, and more testable components.
|
||||||
that can build not only the default version of Moby, as distribution packages or other useful forms,
|
|
||||||
but can also build very different container systems, themselves built of cooperating daemons built in
|
|
||||||
and running in containers. We intend to merge this functionality into this repo.
|
|
||||||
|
|
|
@ -8,11 +8,11 @@ questions you may have as an aspiring Moby contributor.
|
||||||
Moby has two test suites (and one legacy test suite):
|
Moby has two test suites (and one legacy test suite):
|
||||||
|
|
||||||
* Unit tests - use standard `go test` and
|
* Unit tests - use standard `go test` and
|
||||||
[gotestyourself/assert](https://godoc.org/github.com/gotestyourself/gotestyourself/assert) assertions. They are located in
|
[gotest.tools/assert](https://godoc.org/gotest.tools/assert) assertions. They are located in
|
||||||
the package they test. Unit tests should be fast and test only their own
|
the package they test. Unit tests should be fast and test only their own
|
||||||
package.
|
package.
|
||||||
* API integration tests - use standard `go test` and
|
* API integration tests - use standard `go test` and
|
||||||
[gotestyourself/assert](https://godoc.org/github.com/gotestyourself/gotestyourself/assert) assertions. They are located in
|
[gotest.tools/assert](https://godoc.org/gotest.tools/assert) assertions. They are located in
|
||||||
`./integration/<component>` directories, where `component` is: container,
|
`./integration/<component>` directories, where `component` is: container,
|
||||||
image, volume, etc. These tests perform HTTP requests to an API endpoint and
|
image, volume, etc. These tests perform HTTP requests to an API endpoint and
|
||||||
check the HTTP response and daemon state after the call.
|
check the HTTP response and daemon state after the call.
|
||||||
|
@ -47,6 +47,24 @@ Bugs fixes should include a unit test case which exercises the bug.
|
||||||
A bug fix may also include new assertions in an existing integration tests for the
|
A bug fix may also include new assertions in an existing integration tests for the
|
||||||
API endpoint.
|
API endpoint.
|
||||||
|
|
||||||
|
### Integration tests environment considerations
|
||||||
|
|
||||||
|
When adding new tests or modifying existing test under `integration/`, testing
|
||||||
|
environment should be properly considered. `skip.If` from
|
||||||
|
[gotest.tools/skip](https://godoc.org/gotest.tools/skip) can be used to make the
|
||||||
|
test run conditionally. Full testing environment conditions can be found at
|
||||||
|
[environment.go](https://github.com/moby/moby/blob/cb37987ee11655ed6bbef663d245e55922354c68/internal/test/environment/environment.go)
|
||||||
|
|
||||||
|
Here is a quick example. If the test needs to interact with a docker daemon on
|
||||||
|
the same host, the following condition should be checked within the test code
|
||||||
|
|
||||||
|
```go
|
||||||
|
skip.If(t, testEnv.IsRemoteDaemon())
|
||||||
|
// your integration test code
|
||||||
|
```
|
||||||
|
|
||||||
|
If a remote daemon is detected, the test will be skipped.
|
||||||
|
|
||||||
## Running tests
|
## Running tests
|
||||||
|
|
||||||
To run the unit test suite:
|
To run the unit test suite:
|
||||||
|
|
|
@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api"
|
||||||
// Common constants for daemon and client.
|
// Common constants for daemon and client.
|
||||||
const (
|
const (
|
||||||
// DefaultVersion of Current REST API
|
// DefaultVersion of Current REST API
|
||||||
DefaultVersion = "1.38"
|
DefaultVersion = "1.40"
|
||||||
|
|
||||||
// NoBaseImageSpecifier is the symbol used by the FROM
|
// NoBaseImageSpecifier is the symbol used by the FROM
|
||||||
// command to specify that no base image is to be used.
|
// command to specify that no base image is to be used.
|
||||||
|
|
|
@ -19,10 +19,10 @@ produces:
|
||||||
consumes:
|
consumes:
|
||||||
- "application/json"
|
- "application/json"
|
||||||
- "text/plain"
|
- "text/plain"
|
||||||
basePath: "/v1.38"
|
basePath: "/v1.40"
|
||||||
info:
|
info:
|
||||||
title: "Docker Engine API"
|
title: "Docker Engine API"
|
||||||
version: "1.38"
|
version: "1.40"
|
||||||
x-logo:
|
x-logo:
|
||||||
url: "https://docs.docker.com/images/logo-docker-main.png"
|
url: "https://docs.docker.com/images/logo-docker-main.png"
|
||||||
description: |
|
description: |
|
||||||
|
@ -49,8 +49,8 @@ info:
|
||||||
the URL is not supported by the daemon, a HTTP `400 Bad Request` error message
|
the URL is not supported by the daemon, a HTTP `400 Bad Request` error message
|
||||||
is returned.
|
is returned.
|
||||||
|
|
||||||
If you omit the version-prefix, the current version of the API (v1.38) is used.
|
If you omit the version-prefix, the current version of the API (v1.40) is used.
|
||||||
For example, calling `/info` is the same as calling `/v1.38/info`. Using the
|
For example, calling `/info` is the same as calling `/v1.40/info`. Using the
|
||||||
API without a version-prefix is deprecated and will be removed in a future release.
|
API without a version-prefix is deprecated and will be removed in a future release.
|
||||||
|
|
||||||
Engine releases in the near future should support this version of the API,
|
Engine releases in the near future should support this version of the API,
|
||||||
|
@ -210,6 +210,43 @@ definitions:
|
||||||
PathInContainer: "/dev/deviceName"
|
PathInContainer: "/dev/deviceName"
|
||||||
CgroupPermissions: "mrw"
|
CgroupPermissions: "mrw"
|
||||||
|
|
||||||
|
DeviceRequest:
|
||||||
|
type: "object"
|
||||||
|
description: "A request for devices to be sent to device drivers"
|
||||||
|
properties:
|
||||||
|
Driver:
|
||||||
|
type: "string"
|
||||||
|
example: "nvidia"
|
||||||
|
Count:
|
||||||
|
type: "integer"
|
||||||
|
example: -1
|
||||||
|
DeviceIDs:
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example:
|
||||||
|
- "0"
|
||||||
|
- "1"
|
||||||
|
- "GPU-fef8089b-4820-abfc-e83e-94318197576e"
|
||||||
|
Capabilities:
|
||||||
|
description: |
|
||||||
|
A list of capabilities; an OR list of AND lists of capabilities.
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example:
|
||||||
|
# gpu AND nvidia AND compute
|
||||||
|
- ["gpu", "nvidia", "compute"]
|
||||||
|
Options:
|
||||||
|
description: |
|
||||||
|
Driver-specific options, specified as a key/value pairs. These options
|
||||||
|
are passed directly to the driver.
|
||||||
|
type: "object"
|
||||||
|
additionalProperties:
|
||||||
|
type: "string"
|
||||||
|
|
||||||
ThrottleDevice:
|
ThrottleDevice:
|
||||||
type: "object"
|
type: "object"
|
||||||
properties:
|
properties:
|
||||||
|
@ -238,11 +275,13 @@ definitions:
|
||||||
- `bind` Mounts a file or directory from the host into the container. Must exist prior to creating the container.
|
- `bind` Mounts a file or directory from the host into the container. Must exist prior to creating the container.
|
||||||
- `volume` Creates a volume with the given name and options (or uses a pre-existing volume with the same name and options). These are **not** removed when the container is removed.
|
- `volume` Creates a volume with the given name and options (or uses a pre-existing volume with the same name and options). These are **not** removed when the container is removed.
|
||||||
- `tmpfs` Create a tmpfs with the given options. The mount source cannot be specified for tmpfs.
|
- `tmpfs` Create a tmpfs with the given options. The mount source cannot be specified for tmpfs.
|
||||||
|
- `npipe` Mounts a named pipe from the host into the container. Must exist prior to creating the container.
|
||||||
type: "string"
|
type: "string"
|
||||||
enum:
|
enum:
|
||||||
- "bind"
|
- "bind"
|
||||||
- "volume"
|
- "volume"
|
||||||
- "tmpfs"
|
- "tmpfs"
|
||||||
|
- "npipe"
|
||||||
ReadOnly:
|
ReadOnly:
|
||||||
description: "Whether the mount should be read-only."
|
description: "Whether the mount should be read-only."
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
|
@ -263,6 +302,10 @@ definitions:
|
||||||
- "rshared"
|
- "rshared"
|
||||||
- "slave"
|
- "slave"
|
||||||
- "rslave"
|
- "rslave"
|
||||||
|
NonRecursive:
|
||||||
|
description: "Disable recursive bind mount."
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
VolumeOptions:
|
VolumeOptions:
|
||||||
description: "Optional configuration for the `volume` type."
|
description: "Optional configuration for the `volume` type."
|
||||||
type: "object"
|
type: "object"
|
||||||
|
@ -415,6 +458,11 @@ definitions:
|
||||||
items:
|
items:
|
||||||
type: "string"
|
type: "string"
|
||||||
example: "c 13:* rwm"
|
example: "c 13:* rwm"
|
||||||
|
DeviceRequests:
|
||||||
|
description: "a list of requests for devices to be sent to device drivers"
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/DeviceRequest"
|
||||||
DiskQuota:
|
DiskQuota:
|
||||||
description: "Disk limit (in bytes)."
|
description: "Disk limit (in bytes)."
|
||||||
type: "integer"
|
type: "integer"
|
||||||
|
@ -423,6 +471,11 @@ definitions:
|
||||||
description: "Kernel memory limit in bytes."
|
description: "Kernel memory limit in bytes."
|
||||||
type: "integer"
|
type: "integer"
|
||||||
format: "int64"
|
format: "int64"
|
||||||
|
example: 209715200
|
||||||
|
KernelMemoryTCP:
|
||||||
|
description: "Hard limit for kernel TCP buffer memory (in bytes)."
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
MemoryReservation:
|
MemoryReservation:
|
||||||
description: "Memory soft limit in bytes."
|
description: "Memory soft limit in bytes."
|
||||||
type: "integer"
|
type: "integer"
|
||||||
|
@ -449,9 +502,11 @@ definitions:
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
x-nullable: true
|
x-nullable: true
|
||||||
PidsLimit:
|
PidsLimit:
|
||||||
description: "Tune a container's pids limit. Set -1 for unlimited."
|
description: |
|
||||||
|
Tune a container's PIDs limit. Set `0` or `-1` for unlimited, or `null` to not change.
|
||||||
type: "integer"
|
type: "integer"
|
||||||
format: "int64"
|
format: "int64"
|
||||||
|
x-nullable: true
|
||||||
Ulimits:
|
Ulimits:
|
||||||
description: |
|
description: |
|
||||||
A list of resource limits to set in the container. For example: `{"Name": "nofile", "Soft": 1024, "Hard": 2048}`"
|
A list of resource limits to set in the container. For example: `{"Name": "nofile", "Soft": 1024, "Hard": 2048}`"
|
||||||
|
@ -634,14 +689,22 @@ definitions:
|
||||||
$ref: "#/definitions/Mount"
|
$ref: "#/definitions/Mount"
|
||||||
|
|
||||||
# Applicable to UNIX platforms
|
# Applicable to UNIX platforms
|
||||||
|
Capabilities:
|
||||||
|
type: "array"
|
||||||
|
description: |
|
||||||
|
A list of kernel capabilities to be available for container (this overrides the default set).
|
||||||
|
|
||||||
|
Conflicts with options 'CapAdd' and 'CapDrop'"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
CapAdd:
|
CapAdd:
|
||||||
type: "array"
|
type: "array"
|
||||||
description: "A list of kernel capabilities to add to the container."
|
description: "A list of kernel capabilities to add to the container. Conflicts with option 'Capabilities'"
|
||||||
items:
|
items:
|
||||||
type: "string"
|
type: "string"
|
||||||
CapDrop:
|
CapDrop:
|
||||||
type: "array"
|
type: "array"
|
||||||
description: "A list of kernel capabilities to drop from the container."
|
description: "A list of kernel capabilities to drop from the container. Conflicts with option 'Capabilities'"
|
||||||
items:
|
items:
|
||||||
type: "string"
|
type: "string"
|
||||||
Dns:
|
Dns:
|
||||||
|
@ -1473,11 +1536,9 @@ definitions:
|
||||||
type: "string"
|
type: "string"
|
||||||
Options:
|
Options:
|
||||||
description: "Driver-specific options, specified as a map."
|
description: "Driver-specific options, specified as a map."
|
||||||
type: "array"
|
type: "object"
|
||||||
items:
|
additionalProperties:
|
||||||
type: "object"
|
type: "string"
|
||||||
additionalProperties:
|
|
||||||
type: "string"
|
|
||||||
|
|
||||||
NetworkContainer:
|
NetworkContainer:
|
||||||
type: "object"
|
type: "object"
|
||||||
|
@ -1513,6 +1574,31 @@ definitions:
|
||||||
aux:
|
aux:
|
||||||
$ref: "#/definitions/ImageID"
|
$ref: "#/definitions/ImageID"
|
||||||
|
|
||||||
|
BuildCache:
|
||||||
|
type: "object"
|
||||||
|
properties:
|
||||||
|
ID:
|
||||||
|
type: "string"
|
||||||
|
Parent:
|
||||||
|
type: "string"
|
||||||
|
Type:
|
||||||
|
type: "string"
|
||||||
|
Description:
|
||||||
|
type: "string"
|
||||||
|
InUse:
|
||||||
|
type: "boolean"
|
||||||
|
Shared:
|
||||||
|
type: "boolean"
|
||||||
|
Size:
|
||||||
|
type: "integer"
|
||||||
|
CreatedAt:
|
||||||
|
type: "integer"
|
||||||
|
LastUsedAt:
|
||||||
|
type: "integer"
|
||||||
|
x-nullable: true
|
||||||
|
UsageCount:
|
||||||
|
type: "integer"
|
||||||
|
|
||||||
ImageID:
|
ImageID:
|
||||||
type: "object"
|
type: "object"
|
||||||
description: "Image ID or Digest"
|
description: "Image ID or Digest"
|
||||||
|
@ -2434,6 +2520,31 @@ definitions:
|
||||||
description: "Whether there is currently a root CA rotation in progress for the swarm"
|
description: "Whether there is currently a root CA rotation in progress for the swarm"
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
example: false
|
example: false
|
||||||
|
DataPathPort:
|
||||||
|
description: |
|
||||||
|
DataPathPort specifies the data path port number for data traffic.
|
||||||
|
Acceptable port range is 1024 to 49151.
|
||||||
|
If no port is set or is set to 0, the default port (4789) is used.
|
||||||
|
type: "integer"
|
||||||
|
format: "uint32"
|
||||||
|
default: 4789
|
||||||
|
example: 4789
|
||||||
|
DefaultAddrPool:
|
||||||
|
description: |
|
||||||
|
Default Address Pool specifies default subnet pools for global scope networks.
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
format: "CIDR"
|
||||||
|
example: ["10.10.0.0/16", "20.20.0.0/16"]
|
||||||
|
SubnetSize:
|
||||||
|
description: |
|
||||||
|
SubnetSize specifies the subnet size of the networks created from the default subnet pool
|
||||||
|
type: "integer"
|
||||||
|
format: "uint32"
|
||||||
|
maximum: 29
|
||||||
|
default: 24
|
||||||
|
example: 24
|
||||||
|
|
||||||
JoinTokens:
|
JoinTokens:
|
||||||
description: |
|
description: |
|
||||||
|
@ -2556,8 +2667,20 @@ definitions:
|
||||||
type: "object"
|
type: "object"
|
||||||
description: "CredentialSpec for managed service account (Windows only)"
|
description: "CredentialSpec for managed service account (Windows only)"
|
||||||
properties:
|
properties:
|
||||||
|
Config:
|
||||||
|
type: "string"
|
||||||
|
example: "0bt9dmxjvjiqermk6xrop3ekq"
|
||||||
|
description: |
|
||||||
|
Load credential spec from a Swarm Config with the given ID.
|
||||||
|
The specified config must also be present in the Configs field with the Runtime property set.
|
||||||
|
|
||||||
|
<p><br /></p>
|
||||||
|
|
||||||
|
|
||||||
|
> **Note**: `CredentialSpec.File`, `CredentialSpec.Registry`, and `CredentialSpec.Config` are mutually exclusive.
|
||||||
File:
|
File:
|
||||||
type: "string"
|
type: "string"
|
||||||
|
example: "spec.json"
|
||||||
description: |
|
description: |
|
||||||
Load credential spec from this file. The file is read by the daemon, and must be present in the
|
Load credential spec from this file. The file is read by the daemon, and must be present in the
|
||||||
`CredentialSpecs` subdirectory in the docker data directory, which defaults to
|
`CredentialSpecs` subdirectory in the docker data directory, which defaults to
|
||||||
|
@ -2567,7 +2690,7 @@ definitions:
|
||||||
|
|
||||||
<p><br /></p>
|
<p><br /></p>
|
||||||
|
|
||||||
> **Note**: `CredentialSpec.File` and `CredentialSpec.Registry` are mutually exclusive.
|
> **Note**: `CredentialSpec.File`, `CredentialSpec.Registry`, and `CredentialSpec.Config` are mutually exclusive.
|
||||||
Registry:
|
Registry:
|
||||||
type: "string"
|
type: "string"
|
||||||
description: |
|
description: |
|
||||||
|
@ -2579,7 +2702,7 @@ definitions:
|
||||||
<p><br /></p>
|
<p><br /></p>
|
||||||
|
|
||||||
|
|
||||||
> **Note**: `CredentialSpec.File` and `CredentialSpec.Registry` are mutually exclusive.
|
> **Note**: `CredentialSpec.File`, `CredentialSpec.Registry`, and `CredentialSpec.Config` are mutually exclusive.
|
||||||
SELinuxContext:
|
SELinuxContext:
|
||||||
type: "object"
|
type: "object"
|
||||||
description: "SELinux labels of the container"
|
description: "SELinux labels of the container"
|
||||||
|
@ -2690,7 +2813,12 @@ definitions:
|
||||||
type: "object"
|
type: "object"
|
||||||
properties:
|
properties:
|
||||||
File:
|
File:
|
||||||
description: "File represents a specific target that is backed by a file."
|
description: |
|
||||||
|
File represents a specific target that is backed by a file.
|
||||||
|
|
||||||
|
<p><br /><p>
|
||||||
|
|
||||||
|
> **Note**: `Configs.File` and `Configs.Runtime` are mutually exclusive
|
||||||
type: "object"
|
type: "object"
|
||||||
properties:
|
properties:
|
||||||
Name:
|
Name:
|
||||||
|
@ -2706,6 +2834,14 @@ definitions:
|
||||||
description: "Mode represents the FileMode of the file."
|
description: "Mode represents the FileMode of the file."
|
||||||
type: "integer"
|
type: "integer"
|
||||||
format: "uint32"
|
format: "uint32"
|
||||||
|
Runtime:
|
||||||
|
description: |
|
||||||
|
Runtime represents a target that is not mounted into the container but is used by the task
|
||||||
|
|
||||||
|
<p><br /><p>
|
||||||
|
|
||||||
|
> **Note**: `Configs.File` and `Configs.Runtime` are mutually exclusive
|
||||||
|
type: "object"
|
||||||
ConfigID:
|
ConfigID:
|
||||||
description: "ConfigID represents the ID of the specific config that we're referencing."
|
description: "ConfigID represents the ID of the specific config that we're referencing."
|
||||||
type: "string"
|
type: "string"
|
||||||
|
@ -2725,6 +2861,18 @@ definitions:
|
||||||
description: "Run an init inside the container that forwards signals and reaps processes. This field is omitted if empty, and the default (as configured on the daemon) is used."
|
description: "Run an init inside the container that forwards signals and reaps processes. This field is omitted if empty, and the default (as configured on the daemon) is used."
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
x-nullable: true
|
x-nullable: true
|
||||||
|
Sysctls:
|
||||||
|
description: |
|
||||||
|
Set kernel namedspaced parameters (sysctls) in the container.
|
||||||
|
The Sysctls option on services accepts the same sysctls as the
|
||||||
|
are supported on containers. Note that while the same sysctls are
|
||||||
|
supported, no guarantees or checks are made about their
|
||||||
|
suitability for a clustered environment, and it's up to the user
|
||||||
|
to determine whether a given sysctl will work properly in a
|
||||||
|
Service.
|
||||||
|
type: "object"
|
||||||
|
additionalProperties:
|
||||||
|
type: "string"
|
||||||
NetworkAttachmentSpec:
|
NetworkAttachmentSpec:
|
||||||
description: |
|
description: |
|
||||||
Read-only spec type for non-swarm containers attached to swarm overlay
|
Read-only spec type for non-swarm containers attached to swarm overlay
|
||||||
|
@ -2805,6 +2953,11 @@ definitions:
|
||||||
SpreadDescriptor: "node.labels.datacenter"
|
SpreadDescriptor: "node.labels.datacenter"
|
||||||
- Spread:
|
- Spread:
|
||||||
SpreadDescriptor: "node.labels.rack"
|
SpreadDescriptor: "node.labels.rack"
|
||||||
|
MaxReplicas:
|
||||||
|
description: "Maximum number of replicas for per node (default value is 0, which is unlimited)"
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
default: 0
|
||||||
Platforms:
|
Platforms:
|
||||||
description: |
|
description: |
|
||||||
Platforms stores all the platforms that the service's image can
|
Platforms stores all the platforms that the service's image can
|
||||||
|
@ -3605,6 +3758,10 @@ definitions:
|
||||||
See [cpuset(7)](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt)
|
See [cpuset(7)](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt)
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
example: true
|
example: true
|
||||||
|
PidsLimit:
|
||||||
|
description: "Indicates if the host kernel has PID limit support enabled."
|
||||||
|
type: "boolean"
|
||||||
|
example: true
|
||||||
OomKillDisable:
|
OomKillDisable:
|
||||||
description: "Indicates if OOM killer disable is supported on the host."
|
description: "Indicates if OOM killer disable is supported on the host."
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
|
@ -3722,18 +3879,22 @@ definitions:
|
||||||
description: |
|
description: |
|
||||||
HTTP-proxy configured for the daemon. This value is obtained from the
|
HTTP-proxy configured for the daemon. This value is obtained from the
|
||||||
[`HTTP_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable.
|
[`HTTP_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable.
|
||||||
|
Credentials ([user info component](https://tools.ietf.org/html/rfc3986#section-3.2.1)) in the proxy URL
|
||||||
|
are masked in the API response.
|
||||||
|
|
||||||
Containers do not automatically inherit this configuration.
|
Containers do not automatically inherit this configuration.
|
||||||
type: "string"
|
type: "string"
|
||||||
example: "http://user:pass@proxy.corp.example.com:8080"
|
example: "http://xxxxx:xxxxx@proxy.corp.example.com:8080"
|
||||||
HttpsProxy:
|
HttpsProxy:
|
||||||
description: |
|
description: |
|
||||||
HTTPS-proxy configured for the daemon. This value is obtained from the
|
HTTPS-proxy configured for the daemon. This value is obtained from the
|
||||||
[`HTTPS_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable.
|
[`HTTPS_PROXY`](https://www.gnu.org/software/wget/manual/html_node/Proxies.html) environment variable.
|
||||||
|
Credentials ([user info component](https://tools.ietf.org/html/rfc3986#section-3.2.1)) in the proxy URL
|
||||||
|
are masked in the API response.
|
||||||
|
|
||||||
Containers do not automatically inherit this configuration.
|
Containers do not automatically inherit this configuration.
|
||||||
type: "string"
|
type: "string"
|
||||||
example: "https://user:pass@proxy.corp.example.com:4443"
|
example: "https://xxxxx:xxxxx@proxy.corp.example.com:4443"
|
||||||
NoProxy:
|
NoProxy:
|
||||||
description: |
|
description: |
|
||||||
Comma-separated list of domain extensions for which no proxy should be
|
Comma-separated list of domain extensions for which no proxy should be
|
||||||
|
@ -3823,10 +3984,10 @@ definitions:
|
||||||
$ref: "#/definitions/Runtime"
|
$ref: "#/definitions/Runtime"
|
||||||
default:
|
default:
|
||||||
runc:
|
runc:
|
||||||
path: "docker-runc"
|
path: "runc"
|
||||||
example:
|
example:
|
||||||
runc:
|
runc:
|
||||||
path: "docker-runc"
|
path: "runc"
|
||||||
runc-master:
|
runc-master:
|
||||||
path: "/go/bin/runc"
|
path: "/go/bin/runc"
|
||||||
custom:
|
custom:
|
||||||
|
@ -3896,6 +4057,27 @@ definitions:
|
||||||
- "name=seccomp,profile=default"
|
- "name=seccomp,profile=default"
|
||||||
- "name=selinux"
|
- "name=selinux"
|
||||||
- "name=userns"
|
- "name=userns"
|
||||||
|
ProductLicense:
|
||||||
|
description: |
|
||||||
|
Reports a summary of the product license on the daemon.
|
||||||
|
|
||||||
|
If a commercial license has been applied to the daemon, information
|
||||||
|
such as number of nodes, and expiration are included.
|
||||||
|
type: "string"
|
||||||
|
example: "Community Engine"
|
||||||
|
Warnings:
|
||||||
|
description: |
|
||||||
|
List of warnings / informational messages about missing features, or
|
||||||
|
issues related to the daemon configuration.
|
||||||
|
|
||||||
|
These messages can be printed by the client as information to the user.
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example:
|
||||||
|
- "WARNING: No memory limit support"
|
||||||
|
- "WARNING: bridge-nf-call-iptables is disabled"
|
||||||
|
- "WARNING: bridge-nf-call-ip6tables is disabled"
|
||||||
|
|
||||||
|
|
||||||
# PluginsInfo is a temp struct holding Plugins name
|
# PluginsInfo is a temp struct holding Plugins name
|
||||||
|
@ -4516,7 +4698,7 @@ paths:
|
||||||
OomKillDisable: false
|
OomKillDisable: false
|
||||||
OomScoreAdj: 500
|
OomScoreAdj: 500
|
||||||
PidMode: ""
|
PidMode: ""
|
||||||
PidsLimit: -1
|
PidsLimit: 0
|
||||||
PortBindings:
|
PortBindings:
|
||||||
22/tcp:
|
22/tcp:
|
||||||
- HostPort: "11022"
|
- HostPort: "11022"
|
||||||
|
@ -5922,7 +6104,7 @@ paths:
|
||||||
headers:
|
headers:
|
||||||
X-Docker-Container-Path-Stat:
|
X-Docker-Container-Path-Stat:
|
||||||
type: "string"
|
type: "string"
|
||||||
description: "TODO"
|
description: "A base64 - encoded JSON object with some filesystem header information about the path"
|
||||||
400:
|
400:
|
||||||
description: "Bad parameter"
|
description: "Bad parameter"
|
||||||
schema:
|
schema:
|
||||||
|
@ -6319,6 +6501,11 @@ paths:
|
||||||
description: "Target build stage"
|
description: "Target build stage"
|
||||||
type: "string"
|
type: "string"
|
||||||
default: ""
|
default: ""
|
||||||
|
- name: "outputs"
|
||||||
|
in: "query"
|
||||||
|
description: "BuildKit output configuration"
|
||||||
|
type: "string"
|
||||||
|
default: ""
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: "no error"
|
description: "no error"
|
||||||
|
@ -6337,6 +6524,29 @@ paths:
|
||||||
produces:
|
produces:
|
||||||
- "application/json"
|
- "application/json"
|
||||||
operationId: "BuildPrune"
|
operationId: "BuildPrune"
|
||||||
|
parameters:
|
||||||
|
- name: "keep-storage"
|
||||||
|
in: "query"
|
||||||
|
description: "Amount of disk space in bytes to keep for cache"
|
||||||
|
type: "integer"
|
||||||
|
format: "int64"
|
||||||
|
- name: "all"
|
||||||
|
in: "query"
|
||||||
|
type: "boolean"
|
||||||
|
description: "Remove all types of build cache"
|
||||||
|
- name: "filters"
|
||||||
|
in: "query"
|
||||||
|
type: "string"
|
||||||
|
description: |
|
||||||
|
A JSON encoded value of the filters (a `map[string][]string`) to process on the list of build cache objects. Available filters:
|
||||||
|
- `until=<duration>`: duration relative to daemon's time, during which build cache was not used, in Go's duration format (e.g., '24h')
|
||||||
|
- `id=<id>`
|
||||||
|
- `parent=<id>`
|
||||||
|
- `type=<string>`
|
||||||
|
- `description=<string>`
|
||||||
|
- `inuse`
|
||||||
|
- `shared`
|
||||||
|
- `private`
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: "No error"
|
description: "No error"
|
||||||
|
@ -6344,6 +6554,11 @@ paths:
|
||||||
type: "object"
|
type: "object"
|
||||||
title: "BuildPruneResponse"
|
title: "BuildPruneResponse"
|
||||||
properties:
|
properties:
|
||||||
|
CachesDeleted:
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
description: "ID of build cache object"
|
||||||
|
type: "string"
|
||||||
SpaceReclaimed:
|
SpaceReclaimed:
|
||||||
description: "Disk space reclaimed in bytes"
|
description: "Disk space reclaimed in bytes"
|
||||||
type: "integer"
|
type: "integer"
|
||||||
|
@ -6972,9 +7187,57 @@ paths:
|
||||||
API-Version:
|
API-Version:
|
||||||
type: "string"
|
type: "string"
|
||||||
description: "Max API Version the server supports"
|
description: "Max API Version the server supports"
|
||||||
|
BuildKit-Version:
|
||||||
|
type: "string"
|
||||||
|
description: "Default version of docker image builder"
|
||||||
Docker-Experimental:
|
Docker-Experimental:
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
description: "If the server is running with experimental mode enabled"
|
description: "If the server is running with experimental mode enabled"
|
||||||
|
Cache-Control:
|
||||||
|
type: "string"
|
||||||
|
default: "no-cache, no-store, must-revalidate"
|
||||||
|
Pragma:
|
||||||
|
type: "string"
|
||||||
|
default: "no-cache"
|
||||||
|
500:
|
||||||
|
description: "server error"
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/ErrorResponse"
|
||||||
|
headers:
|
||||||
|
Cache-Control:
|
||||||
|
type: "string"
|
||||||
|
default: "no-cache, no-store, must-revalidate"
|
||||||
|
Pragma:
|
||||||
|
type: "string"
|
||||||
|
default: "no-cache"
|
||||||
|
tags: ["System"]
|
||||||
|
head:
|
||||||
|
summary: "Ping"
|
||||||
|
description: "This is a dummy endpoint you can use to test if the server is accessible."
|
||||||
|
operationId: "SystemPingHead"
|
||||||
|
produces: ["text/plain"]
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: "no error"
|
||||||
|
schema:
|
||||||
|
type: "string"
|
||||||
|
example: "(empty)"
|
||||||
|
headers:
|
||||||
|
API-Version:
|
||||||
|
type: "string"
|
||||||
|
description: "Max API Version the server supports"
|
||||||
|
BuildKit-Version:
|
||||||
|
type: "string"
|
||||||
|
description: "Default version of docker image builder"
|
||||||
|
Docker-Experimental:
|
||||||
|
type: "boolean"
|
||||||
|
description: "If the server is running with experimental mode enabled"
|
||||||
|
Cache-Control:
|
||||||
|
type: "string"
|
||||||
|
default: "no-cache, no-store, must-revalidate"
|
||||||
|
Pragma:
|
||||||
|
type: "string"
|
||||||
|
default: "no-cache"
|
||||||
500:
|
500:
|
||||||
description: "server error"
|
description: "server error"
|
||||||
schema:
|
schema:
|
||||||
|
@ -7175,6 +7438,10 @@ paths:
|
||||||
type: "array"
|
type: "array"
|
||||||
items:
|
items:
|
||||||
$ref: "#/definitions/Volume"
|
$ref: "#/definitions/Volume"
|
||||||
|
BuildCache:
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/BuildCache"
|
||||||
example:
|
example:
|
||||||
LayersSize: 1092588
|
LayersSize: 1092588
|
||||||
Images:
|
Images:
|
||||||
|
@ -7589,6 +7856,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
type: "object"
|
type: "object"
|
||||||
title: "VolumeListResponse"
|
title: "VolumeListResponse"
|
||||||
|
description: "Volume list response"
|
||||||
required: [Volumes, Warnings]
|
required: [Volumes, Warnings]
|
||||||
properties:
|
properties:
|
||||||
Volumes:
|
Volumes:
|
||||||
|
@ -7665,6 +7933,8 @@ paths:
|
||||||
description: "Volume configuration"
|
description: "Volume configuration"
|
||||||
schema:
|
schema:
|
||||||
type: "object"
|
type: "object"
|
||||||
|
description: "Volume configuration"
|
||||||
|
title: "VolumeConfig"
|
||||||
properties:
|
properties:
|
||||||
Name:
|
Name:
|
||||||
description: "The new volume's name. If not specified, Docker generates a name."
|
description: "The new volume's name. If not specified, Docker generates a name."
|
||||||
|
@ -7865,6 +8135,10 @@ paths:
|
||||||
description: |
|
description: |
|
||||||
JSON encoded value of the filters (a `map[string][]string`) to process on the networks list. Available filters:
|
JSON encoded value of the filters (a `map[string][]string`) to process on the networks list. Available filters:
|
||||||
|
|
||||||
|
- `dangling=<boolean>` When set to `true` (or `1`), returns all
|
||||||
|
networks that are not in use by a container. When set to `false`
|
||||||
|
(or `0`), only networks that are in use by one or more
|
||||||
|
containers are returned.
|
||||||
- `driver=<driver-name>` Matches a network's driver.
|
- `driver=<driver-name>` Matches a network's driver.
|
||||||
- `id=<network-id>` Matches all or part of a network ID.
|
- `id=<network-id>` Matches all or part of a network ID.
|
||||||
- `label=<key>` or `label=<key>=<value>` of a network label.
|
- `label=<key>` or `label=<key>=<value>` of a network label.
|
||||||
|
@ -8582,6 +8856,7 @@ paths:
|
||||||
- `label=<engine label>`
|
- `label=<engine label>`
|
||||||
- `membership=`(`accepted`|`pending`)`
|
- `membership=`(`accepted`|`pending`)`
|
||||||
- `name=<node name>`
|
- `name=<node name>`
|
||||||
|
- `node.label=<node label>`
|
||||||
- `role=`(`manager`|`worker`)`
|
- `role=`(`manager`|`worker`)`
|
||||||
type: "string"
|
type: "string"
|
||||||
tags: ["Node"]
|
tags: ["Node"]
|
||||||
|
@ -8754,14 +9029,36 @@ paths:
|
||||||
nodes in order to reach the containers running on this node. Using this parameter it is possible to
|
nodes in order to reach the containers running on this node. Using this parameter it is possible to
|
||||||
separate the container data traffic from the management traffic of the cluster.
|
separate the container data traffic from the management traffic of the cluster.
|
||||||
type: "string"
|
type: "string"
|
||||||
|
DataPathPort:
|
||||||
|
description: |
|
||||||
|
DataPathPort specifies the data path port number for data traffic.
|
||||||
|
Acceptable port range is 1024 to 49151.
|
||||||
|
if no port is set or is set to 0, default port 4789 will be used.
|
||||||
|
type: "integer"
|
||||||
|
format: "uint32"
|
||||||
|
DefaultAddrPool:
|
||||||
|
description: |
|
||||||
|
Default Address Pool specifies default subnet pools for global scope networks.
|
||||||
|
type: "array"
|
||||||
|
items:
|
||||||
|
type: "string"
|
||||||
|
example: ["10.10.0.0/16", "20.20.0.0/16"]
|
||||||
ForceNewCluster:
|
ForceNewCluster:
|
||||||
description: "Force creation of a new swarm."
|
description: "Force creation of a new swarm."
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
|
SubnetSize:
|
||||||
|
description: |
|
||||||
|
SubnetSize specifies the subnet size of the networks created from the default subnet pool
|
||||||
|
type: "integer"
|
||||||
|
format: "uint32"
|
||||||
Spec:
|
Spec:
|
||||||
$ref: "#/definitions/SwarmSpec"
|
$ref: "#/definitions/SwarmSpec"
|
||||||
example:
|
example:
|
||||||
ListenAddr: "0.0.0.0:2377"
|
ListenAddr: "0.0.0.0:2377"
|
||||||
AdvertiseAddr: "192.168.1.1:2377"
|
AdvertiseAddr: "192.168.1.1:2377"
|
||||||
|
DataPathPort: 4789
|
||||||
|
DefaultAddrPool: ["10.10.0.0/8", "20.20.0.0/8"]
|
||||||
|
SubnetSize: 24
|
||||||
ForceNewCluster: false
|
ForceNewCluster: false
|
||||||
Spec:
|
Spec:
|
||||||
Orchestration: {}
|
Orchestration: {}
|
||||||
|
@ -9243,7 +9540,10 @@ paths:
|
||||||
|
|
||||||
- name: "version"
|
- name: "version"
|
||||||
in: "query"
|
in: "query"
|
||||||
description: "The version number of the service object being updated. This is required to avoid conflicting writes."
|
description: "The version number of the service object being updated.
|
||||||
|
This is required to avoid conflicting writes.
|
||||||
|
This version number should be the value as currently set on the service *before* the update.
|
||||||
|
You can find the current version by calling `GET /services/{id}`"
|
||||||
required: true
|
required: true
|
||||||
type: "integer"
|
type: "integer"
|
||||||
- name: "registryAuthFrom"
|
- name: "registryAuthFrom"
|
||||||
|
@ -9602,6 +9902,7 @@ paths:
|
||||||
description: "Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines."
|
description: "Only return this number of log lines from the end of the logs. Specify as an integer or `all` to output all log lines."
|
||||||
type: "string"
|
type: "string"
|
||||||
default: "all"
|
default: "all"
|
||||||
|
tags: ["Task"]
|
||||||
/secrets:
|
/secrets:
|
||||||
get:
|
get:
|
||||||
summary: "List secrets"
|
summary: "List secrets"
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
"github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CheckpointCreateOptions holds parameters to create a checkpoint from a container
|
// CheckpointCreateOptions holds parameters to create a checkpoint from a container
|
||||||
|
@ -181,8 +181,33 @@ type ImageBuildOptions struct {
|
||||||
Target string
|
Target string
|
||||||
SessionID string
|
SessionID string
|
||||||
Platform string
|
Platform string
|
||||||
|
// Version specifies the version of the unerlying builder to use
|
||||||
|
Version BuilderVersion
|
||||||
|
// BuildID is an optional identifier that can be passed together with the
|
||||||
|
// build request. The same identifier can be used to gracefully cancel the
|
||||||
|
// build with the cancel request.
|
||||||
|
BuildID string
|
||||||
|
// Outputs defines configurations for exporting build results. Only supported
|
||||||
|
// in BuildKit mode
|
||||||
|
Outputs []ImageBuildOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImageBuildOutput defines configuration for exporting a build result
|
||||||
|
type ImageBuildOutput struct {
|
||||||
|
Type string
|
||||||
|
Attrs map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuilderVersion sets the version of underlying builder to use
|
||||||
|
type BuilderVersion string
|
||||||
|
|
||||||
|
const (
|
||||||
|
// BuilderV1 is the first generation builder in docker daemon
|
||||||
|
BuilderV1 BuilderVersion = "1"
|
||||||
|
// BuilderBuildKit is builder based on moby/buildkit project
|
||||||
|
BuilderBuildKit = "2"
|
||||||
|
)
|
||||||
|
|
||||||
// ImageBuildResponse holds information
|
// ImageBuildResponse holds information
|
||||||
// returned by a server after building
|
// returned by a server after building
|
||||||
// an image.
|
// an image.
|
||||||
|
|
|
@ -55,3 +55,10 @@ type PluginEnableConfig struct {
|
||||||
type PluginDisableConfig struct {
|
type PluginDisableConfig struct {
|
||||||
ForceDisable bool
|
ForceDisable bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NetworkListConfig stores the options available for listing networks
|
||||||
|
type NetworkListConfig struct {
|
||||||
|
// TODO(@cpuguy83): naming is hard, this is pulled from what was being used in the router before moving here
|
||||||
|
Detailed bool
|
||||||
|
Verbose bool
|
||||||
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ type Config struct {
|
||||||
Env []string // List of environment variable to set in the container
|
Env []string // List of environment variable to set in the container
|
||||||
Cmd strslice.StrSlice // Command to run when starting the container
|
Cmd strslice.StrSlice // Command to run when starting the container
|
||||||
Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
|
Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
|
||||||
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (Windows specific)
|
ArgsEscaped bool `json:",omitempty"` // True if command is already escaped (meaning treat as a command line) (Windows specific).
|
||||||
Image string // Name of the image as it was passed by the operator (e.g. could be symbolic)
|
Image string // Name of the image as it was passed by the operator (e.g. could be symbolic)
|
||||||
Volumes map[string]struct{} // List of volumes (mounts) used for the container
|
Volumes map[string]struct{} // List of volumes (mounts) used for the container
|
||||||
WorkingDir string // Current directory (PWD) in the command will be launched
|
WorkingDir string // Current directory (PWD) in the command will be launched
|
||||||
|
|
|
@ -244,6 +244,16 @@ func (n PidMode) Container() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeviceRequest represents a request for devices from a device driver.
|
||||||
|
// Used by GPU device drivers.
|
||||||
|
type DeviceRequest struct {
|
||||||
|
Driver string // Name of device driver
|
||||||
|
Count int // Number of devices to request (-1 = All)
|
||||||
|
DeviceIDs []string // List of device IDs as recognizable by the device driver
|
||||||
|
Capabilities [][]string // An OR list of AND lists of device capabilities (e.g. "gpu")
|
||||||
|
Options map[string]string // Options to pass onto the device driver
|
||||||
|
}
|
||||||
|
|
||||||
// DeviceMapping represents the device mapping between the host and the container.
|
// DeviceMapping represents the device mapping between the host and the container.
|
||||||
type DeviceMapping struct {
|
type DeviceMapping struct {
|
||||||
PathOnHost string
|
PathOnHost string
|
||||||
|
@ -327,13 +337,15 @@ type Resources struct {
|
||||||
CpusetMems string // CpusetMems 0-2, 0,1
|
CpusetMems string // CpusetMems 0-2, 0,1
|
||||||
Devices []DeviceMapping // List of devices to map inside the container
|
Devices []DeviceMapping // List of devices to map inside the container
|
||||||
DeviceCgroupRules []string // List of rule to be added to the device cgroup
|
DeviceCgroupRules []string // List of rule to be added to the device cgroup
|
||||||
|
DeviceRequests []DeviceRequest // List of device requests for device drivers
|
||||||
DiskQuota int64 // Disk limit (in bytes)
|
DiskQuota int64 // Disk limit (in bytes)
|
||||||
KernelMemory int64 // Kernel memory limit (in bytes)
|
KernelMemory int64 // Kernel memory limit (in bytes)
|
||||||
|
KernelMemoryTCP int64 // Hard limit for kernel TCP buffer memory (in bytes)
|
||||||
MemoryReservation int64 // Memory soft limit (in bytes)
|
MemoryReservation int64 // Memory soft limit (in bytes)
|
||||||
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap
|
MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap
|
||||||
MemorySwappiness *int64 // Tuning container memory swappiness behaviour
|
MemorySwappiness *int64 // Tuning container memory swappiness behaviour
|
||||||
OomKillDisable *bool // Whether to disable OOM Killer or not
|
OomKillDisable *bool // Whether to disable OOM Killer or not
|
||||||
PidsLimit int64 // Setting pids limit for a container
|
PidsLimit *int64 // Setting PIDs limit for a container; Set `0` or `-1` for unlimited, or `null` to not change.
|
||||||
Ulimits []*units.Ulimit // List of ulimits to be set in the container
|
Ulimits []*units.Ulimit // List of ulimits to be set in the container
|
||||||
|
|
||||||
// Applicable to Windows
|
// Applicable to Windows
|
||||||
|
@ -369,9 +381,10 @@ type HostConfig struct {
|
||||||
// Applicable to UNIX platforms
|
// Applicable to UNIX platforms
|
||||||
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
|
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
|
||||||
CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container
|
CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container
|
||||||
DNS []string `json:"Dns"` // List of DNS server to lookup
|
Capabilities []string `json:"Capabilities"` // List of kernel capabilities to be available for container (this overrides the default set)
|
||||||
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
|
DNS []string `json:"Dns"` // List of DNS server to lookup
|
||||||
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
|
DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for
|
||||||
|
DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for
|
||||||
ExtraHosts []string // List of extra hosts
|
ExtraHosts []string // List of extra hosts
|
||||||
GroupAdd []string // List of additional groups that the container process will run as
|
GroupAdd []string // List of additional groups that the container process will run as
|
||||||
IpcMode IpcMode // IPC namespace to use for the container
|
IpcMode IpcMode // IPC namespace to use for the container
|
||||||
|
|
|
@ -323,6 +323,22 @@ func (args Args) WalkValues(field string, op func(value string) error) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clone returns a copy of args.
|
||||||
|
func (args Args) Clone() (newArgs Args) {
|
||||||
|
newArgs.fields = make(map[string]map[string]bool, len(args.fields))
|
||||||
|
for k, m := range args.fields {
|
||||||
|
var mm map[string]bool
|
||||||
|
if m != nil {
|
||||||
|
mm = make(map[string]bool, len(m))
|
||||||
|
for kk, v := range m {
|
||||||
|
mm[kk] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newArgs.fields[k] = mm
|
||||||
|
}
|
||||||
|
return newArgs
|
||||||
|
}
|
||||||
|
|
||||||
func deprecatedArgs(d map[string][]string) map[string]map[string]bool {
|
func deprecatedArgs(d map[string][]string) map[string]map[string]bool {
|
||||||
m := map[string]map[string]bool{}
|
m := map[string]map[string]bool{}
|
||||||
for k, v := range d {
|
for k, v := range d {
|
||||||
|
|
|
@ -79,7 +79,8 @@ const (
|
||||||
|
|
||||||
// BindOptions defines options specific to mounts of type "bind".
|
// BindOptions defines options specific to mounts of type "bind".
|
||||||
type BindOptions struct {
|
type BindOptions struct {
|
||||||
Propagation Propagation `json:",omitempty"`
|
Propagation Propagation `json:",omitempty"`
|
||||||
|
NonRecursive bool `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// VolumeOptions represents the options for a mount of type volume.
|
// VolumeOptions represents the options for a mount of type volume.
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
package network // import "github.com/docker/docker/api/types/network"
|
package network // import "github.com/docker/docker/api/types/network"
|
||||||
|
import (
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
|
)
|
||||||
|
|
||||||
// Address represents an IP address
|
// Address represents an IP address
|
||||||
type Address struct {
|
type Address struct {
|
||||||
|
@ -106,3 +110,18 @@ type NetworkingConfig struct {
|
||||||
type ConfigReference struct {
|
type ConfigReference struct {
|
||||||
Network string
|
Network string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var acceptedFilters = map[string]bool{
|
||||||
|
"dangling": true,
|
||||||
|
"driver": true,
|
||||||
|
"id": true,
|
||||||
|
"label": true,
|
||||||
|
"name": true,
|
||||||
|
"scope": true,
|
||||||
|
"type": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateFilters validates the list of filter args with the available filters.
|
||||||
|
func ValidateFilters(filter filters.Args) error {
|
||||||
|
return errdefs.InvalidParameter(filter.Validate(acceptedFilters))
|
||||||
|
}
|
||||||
|
|
|
@ -77,8 +77,9 @@ type Arg struct {
|
||||||
|
|
||||||
// Filter is used to conditionally apply Seccomp rules
|
// Filter is used to conditionally apply Seccomp rules
|
||||||
type Filter struct {
|
type Filter struct {
|
||||||
Caps []string `json:"caps,omitempty"`
|
Caps []string `json:"caps,omitempty"`
|
||||||
Arches []string `json:"arches,omitempty"`
|
Arches []string `json:"arches,omitempty"`
|
||||||
|
MinKernel string `json:"minKernel,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Syscall is used to match a group of syscalls in Seccomp
|
// Syscall is used to match a group of syscalls in Seccomp
|
||||||
|
|
|
@ -120,7 +120,7 @@ type NetworkStats struct {
|
||||||
RxBytes uint64 `json:"rx_bytes"`
|
RxBytes uint64 `json:"rx_bytes"`
|
||||||
// Packets received. Windows and Linux.
|
// Packets received. Windows and Linux.
|
||||||
RxPackets uint64 `json:"rx_packets"`
|
RxPackets uint64 `json:"rx_packets"`
|
||||||
// Received errors. Not used on Windows. Note that we dont `omitempty` this
|
// Received errors. Not used on Windows. Note that we don't `omitempty` this
|
||||||
// field as it is expected in the >=v1.21 API stats structure.
|
// field as it is expected in the >=v1.21 API stats structure.
|
||||||
RxErrors uint64 `json:"rx_errors"`
|
RxErrors uint64 `json:"rx_errors"`
|
||||||
// Incoming packets dropped. Windows and Linux.
|
// Incoming packets dropped. Windows and Linux.
|
||||||
|
@ -129,7 +129,7 @@ type NetworkStats struct {
|
||||||
TxBytes uint64 `json:"tx_bytes"`
|
TxBytes uint64 `json:"tx_bytes"`
|
||||||
// Packets sent. Windows and Linux.
|
// Packets sent. Windows and Linux.
|
||||||
TxPackets uint64 `json:"tx_packets"`
|
TxPackets uint64 `json:"tx_packets"`
|
||||||
// Sent errors. Not used on Windows. Note that we dont `omitempty` this
|
// Sent errors. Not used on Windows. Note that we don't `omitempty` this
|
||||||
// field as it is expected in the >=v1.21 API stats structure.
|
// field as it is expected in the >=v1.21 API stats structure.
|
||||||
TxErrors uint64 `json:"tx_errors"`
|
TxErrors uint64 `json:"tx_errors"`
|
||||||
// Outgoing packets dropped. Windows and Linux.
|
// Outgoing packets dropped. Windows and Linux.
|
||||||
|
|
|
@ -27,9 +27,14 @@ type ConfigReferenceFileTarget struct {
|
||||||
Mode os.FileMode
|
Mode os.FileMode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfigReferenceRuntimeTarget is a target for a config specifying that it
|
||||||
|
// isn't mounted into the container but instead has some other purpose.
|
||||||
|
type ConfigReferenceRuntimeTarget struct{}
|
||||||
|
|
||||||
// ConfigReference is a reference to a config in swarm
|
// ConfigReference is a reference to a config in swarm
|
||||||
type ConfigReference struct {
|
type ConfigReference struct {
|
||||||
File *ConfigReferenceFileTarget
|
File *ConfigReferenceFileTarget `json:",omitempty"`
|
||||||
|
Runtime *ConfigReferenceRuntimeTarget `json:",omitempty"`
|
||||||
ConfigID string
|
ConfigID string
|
||||||
ConfigName string
|
ConfigName string
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,7 @@ type SELinuxContext struct {
|
||||||
|
|
||||||
// CredentialSpec for managed service account (Windows only)
|
// CredentialSpec for managed service account (Windows only)
|
||||||
type CredentialSpec struct {
|
type CredentialSpec struct {
|
||||||
|
Config string
|
||||||
File string
|
File string
|
||||||
Registry string
|
Registry string
|
||||||
}
|
}
|
||||||
|
@ -71,4 +72,5 @@ type ContainerSpec struct {
|
||||||
Secrets []*SecretReference `json:",omitempty"`
|
Secrets []*SecretReference `json:",omitempty"`
|
||||||
Configs []*ConfigReference `json:",omitempty"`
|
Configs []*ConfigReference `json:",omitempty"`
|
||||||
Isolation container.Isolation `json:",omitempty"`
|
Isolation container.Isolation `json:",omitempty"`
|
||||||
|
Sysctls map[string]string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package swarm // import "github.com/docker/docker/api/types/swarm"
|
package swarm // import "github.com/docker/docker/api/types/swarm"
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// ClusterInfo represents info about the cluster for outputting in "info"
|
// ClusterInfo represents info about the cluster for outputting in "info"
|
||||||
// it contains the same information as "Swarm", but without the JoinTokens
|
// it contains the same information as "Swarm", but without the JoinTokens
|
||||||
|
@ -10,6 +12,9 @@ type ClusterInfo struct {
|
||||||
Spec Spec
|
Spec Spec
|
||||||
TLSInfo TLSInfo
|
TLSInfo TLSInfo
|
||||||
RootRotationInProgress bool
|
RootRotationInProgress bool
|
||||||
|
DefaultAddrPool []string
|
||||||
|
SubnetSize uint32
|
||||||
|
DataPathPort uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swarm represents a swarm.
|
// Swarm represents a swarm.
|
||||||
|
@ -149,10 +154,13 @@ type InitRequest struct {
|
||||||
ListenAddr string
|
ListenAddr string
|
||||||
AdvertiseAddr string
|
AdvertiseAddr string
|
||||||
DataPathAddr string
|
DataPathAddr string
|
||||||
|
DataPathPort uint32
|
||||||
ForceNewCluster bool
|
ForceNewCluster bool
|
||||||
Spec Spec
|
Spec Spec
|
||||||
AutoLockManagers bool
|
AutoLockManagers bool
|
||||||
Availability NodeAvailability
|
Availability NodeAvailability
|
||||||
|
DefaultAddrPool []string
|
||||||
|
SubnetSize uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinRequest is the request used to join a swarm.
|
// JoinRequest is the request used to join a swarm.
|
||||||
|
@ -201,6 +209,8 @@ type Info struct {
|
||||||
Managers int `json:",omitempty"`
|
Managers int `json:",omitempty"`
|
||||||
|
|
||||||
Cluster *ClusterInfo `json:",omitempty"`
|
Cluster *ClusterInfo `json:",omitempty"`
|
||||||
|
|
||||||
|
Warnings []string `json:",omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peer represents a peer.
|
// Peer represents a peer.
|
||||||
|
|
|
@ -127,6 +127,7 @@ type ResourceRequirements struct {
|
||||||
type Placement struct {
|
type Placement struct {
|
||||||
Constraints []string `json:",omitempty"`
|
Constraints []string `json:",omitempty"`
|
||||||
Preferences []PlacementPreference `json:",omitempty"`
|
Preferences []PlacementPreference `json:",omitempty"`
|
||||||
|
MaxReplicas uint64 `json:",omitempty"`
|
||||||
|
|
||||||
// Platforms stores all the platforms that the image can run on.
|
// Platforms stores all the platforms that the image can run on.
|
||||||
// This field is used in the platform filter for scheduling. If empty,
|
// This field is used in the platform filter for scheduling. If empty,
|
||||||
|
|
|
@ -102,9 +102,10 @@ type ContainerStats struct {
|
||||||
// Ping contains response of Engine API:
|
// Ping contains response of Engine API:
|
||||||
// GET "/_ping"
|
// GET "/_ping"
|
||||||
type Ping struct {
|
type Ping struct {
|
||||||
APIVersion string
|
APIVersion string
|
||||||
OSType string
|
OSType string
|
||||||
Experimental bool
|
Experimental bool
|
||||||
|
BuilderVersion BuilderVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComponentVersion describes the version information for a specific component.
|
// ComponentVersion describes the version information for a specific component.
|
||||||
|
@ -157,10 +158,12 @@ type Info struct {
|
||||||
MemoryLimit bool
|
MemoryLimit bool
|
||||||
SwapLimit bool
|
SwapLimit bool
|
||||||
KernelMemory bool
|
KernelMemory bool
|
||||||
|
KernelMemoryTCP bool
|
||||||
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
|
CPUCfsPeriod bool `json:"CpuCfsPeriod"`
|
||||||
CPUCfsQuota bool `json:"CpuCfsQuota"`
|
CPUCfsQuota bool `json:"CpuCfsQuota"`
|
||||||
CPUShares bool
|
CPUShares bool
|
||||||
CPUSet bool
|
CPUSet bool
|
||||||
|
PidsLimit bool
|
||||||
IPv4Forwarding bool
|
IPv4Forwarding bool
|
||||||
BridgeNfIptables bool
|
BridgeNfIptables bool
|
||||||
BridgeNfIP6tables bool `json:"BridgeNfIp6tables"`
|
BridgeNfIP6tables bool `json:"BridgeNfIp6tables"`
|
||||||
|
@ -204,6 +207,8 @@ type Info struct {
|
||||||
RuncCommit Commit
|
RuncCommit Commit
|
||||||
InitCommit Commit
|
InitCommit Commit
|
||||||
SecurityOptions []string
|
SecurityOptions []string
|
||||||
|
ProductLicense string `json:",omitempty"`
|
||||||
|
Warnings []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeyValue holds a key/value pair
|
// KeyValue holds a key/value pair
|
||||||
|
@ -512,7 +517,8 @@ type DiskUsage struct {
|
||||||
Images []*ImageSummary
|
Images []*ImageSummary
|
||||||
Containers []*Container
|
Containers []*Container
|
||||||
Volumes []*Volume
|
Volumes []*Volume
|
||||||
BuilderSize int64
|
BuildCache []*BuildCache
|
||||||
|
BuilderSize int64 // deprecated
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainersPruneReport contains the response for Engine API:
|
// ContainersPruneReport contains the response for Engine API:
|
||||||
|
@ -539,6 +545,7 @@ type ImagesPruneReport struct {
|
||||||
// BuildCachePruneReport contains the response for Engine API:
|
// BuildCachePruneReport contains the response for Engine API:
|
||||||
// POST "/build/prune"
|
// POST "/build/prune"
|
||||||
type BuildCachePruneReport struct {
|
type BuildCachePruneReport struct {
|
||||||
|
CachesDeleted []string
|
||||||
SpaceReclaimed uint64
|
SpaceReclaimed uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,3 +592,24 @@ type PushResult struct {
|
||||||
type BuildResult struct {
|
type BuildResult struct {
|
||||||
ID string
|
ID string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BuildCache contains information about a build cache record
|
||||||
|
type BuildCache struct {
|
||||||
|
ID string
|
||||||
|
Parent string
|
||||||
|
Type string
|
||||||
|
Description string
|
||||||
|
InUse bool
|
||||||
|
Shared bool
|
||||||
|
Size int64
|
||||||
|
CreatedAt time.Time
|
||||||
|
LastUsedAt *time.Time
|
||||||
|
UsageCount int
|
||||||
|
}
|
||||||
|
|
||||||
|
// BuildCachePruneOptions hold parameters to prune the build cache
|
||||||
|
type BuildCachePruneOptions struct {
|
||||||
|
All bool
|
||||||
|
KeepStorage int64
|
||||||
|
Filters filters.Args
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ package volume
|
||||||
// See hack/generate-swagger-api.sh
|
// See hack/generate-swagger-api.sh
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// VolumeCreateBody
|
// VolumeCreateBody Volume configuration
|
||||||
// swagger:model VolumeCreateBody
|
// swagger:model VolumeCreateBody
|
||||||
type VolumeCreateBody struct {
|
type VolumeCreateBody struct {
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ package volume
|
||||||
|
|
||||||
import "github.com/docker/docker/api/types"
|
import "github.com/docker/docker/api/types"
|
||||||
|
|
||||||
// VolumeListOKBody
|
// VolumeListOKBody Volume list response
|
||||||
// swagger:model VolumeListOKBody
|
// swagger:model VolumeListOKBody
|
||||||
type VolumeListOKBody struct {
|
type VolumeListOKBody struct {
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package client // import "github.com/docker/docker/client"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/url"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BuildCancel requests the daemon to cancel ongoing build request
|
||||||
|
func (cli *Client) BuildCancel(ctx context.Context, id string) error {
|
||||||
|
query := url.Values{}
|
||||||
|
query.Set("id", id)
|
||||||
|
|
||||||
|
serverResp, err := cli.post(ctx, "/build/cancel", query, nil, nil)
|
||||||
|
ensureReaderClosed(serverResp)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -4,23 +4,38 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BuildCachePrune requests the daemon to delete unused cache data
|
// BuildCachePrune requests the daemon to delete unused cache data
|
||||||
func (cli *Client) BuildCachePrune(ctx context.Context) (*types.BuildCachePruneReport, error) {
|
func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
|
||||||
if err := cli.NewVersionError("1.31", "build prune"); err != nil {
|
if err := cli.NewVersionError("1.31", "build prune"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
report := types.BuildCachePruneReport{}
|
report := types.BuildCachePruneReport{}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/build/prune", nil, nil, nil)
|
query := url.Values{}
|
||||||
|
if opts.All {
|
||||||
|
query.Set("all", "1")
|
||||||
|
}
|
||||||
|
query.Set("keep-storage", fmt.Sprintf("%d", opts.KeepStorage))
|
||||||
|
filters, err := filters.ToJSON(opts.Filters)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "prune could not marshal filters option")
|
||||||
|
}
|
||||||
|
query.Set("filters", filters)
|
||||||
|
|
||||||
|
serverResp, err := cli.post(ctx, "/build/prune", query, nil, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(serverResp)
|
|
||||||
|
|
||||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||||
return nil, fmt.Errorf("Error retrieving disk usage: %v", err)
|
return nil, fmt.Errorf("Error retrieving disk usage: %v", err)
|
||||||
|
|
|
@ -18,11 +18,11 @@ func (cli *Client) CheckpointList(ctx context.Context, container string, options
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil)
|
resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return checkpoints, wrapResponseError(err, resp, "container", container)
|
return checkpoints, wrapResponseError(err, resp, "container", container)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(resp.body).Decode(&checkpoints)
|
err = json.NewDecoder(resp.body).Decode(&checkpoints)
|
||||||
ensureReaderClosed(resp)
|
|
||||||
return checkpoints, err
|
return checkpoints, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ For example, to list running containers (the equivalent of "docker ps"):
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cli, err := client.NewEnvClient()
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -47,16 +47,13 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/docker/api"
|
"github.com/docker/docker/api"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
"github.com/docker/go-connections/sockets"
|
"github.com/docker/go-connections/sockets"
|
||||||
"github.com/docker/go-connections/tlsconfig"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -90,7 +87,7 @@ type Client struct {
|
||||||
// If the request is non-GET return `ErrRedirect`. Otherwise use the last response.
|
// If the request is non-GET return `ErrRedirect`. Otherwise use the last response.
|
||||||
//
|
//
|
||||||
// Go 1.8 changes behavior for HTTP redirects (specifically 301, 307, and 308) in the client .
|
// Go 1.8 changes behavior for HTTP redirects (specifically 301, 307, and 308) in the client .
|
||||||
// The Docker client (and by extension docker API client) can be made to to send a request
|
// The Docker client (and by extension docker API client) can be made to send a request
|
||||||
// like POST /containers//start where what would normally be in the name section of the URL is empty.
|
// like POST /containers//start where what would normally be in the name section of the URL is empty.
|
||||||
// This triggers an HTTP 301 from the daemon.
|
// This triggers an HTTP 301 from the daemon.
|
||||||
// In go 1.8 this 301 will be converted to a GET request, and ends up getting a 404 from the daemon.
|
// In go 1.8 this 301 will be converted to a GET request, and ends up getting a 404 from the daemon.
|
||||||
|
@ -103,130 +100,6 @@ func CheckRedirect(req *http.Request, via []*http.Request) error {
|
||||||
return ErrRedirect
|
return ErrRedirect
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEnvClient initializes a new API client based on environment variables.
|
|
||||||
// See FromEnv for a list of support environment variables.
|
|
||||||
//
|
|
||||||
// Deprecated: use NewClientWithOpts(FromEnv)
|
|
||||||
func NewEnvClient() (*Client, error) {
|
|
||||||
return NewClientWithOpts(FromEnv)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromEnv configures the client with values from environment variables.
|
|
||||||
//
|
|
||||||
// Supported environment variables:
|
|
||||||
// DOCKER_HOST to set the url to the docker server.
|
|
||||||
// DOCKER_API_VERSION to set the version of the API to reach, leave empty for latest.
|
|
||||||
// DOCKER_CERT_PATH to load the TLS certificates from.
|
|
||||||
// DOCKER_TLS_VERIFY to enable or disable TLS verification, off by default.
|
|
||||||
func FromEnv(c *Client) error {
|
|
||||||
if dockerCertPath := os.Getenv("DOCKER_CERT_PATH"); dockerCertPath != "" {
|
|
||||||
options := tlsconfig.Options{
|
|
||||||
CAFile: filepath.Join(dockerCertPath, "ca.pem"),
|
|
||||||
CertFile: filepath.Join(dockerCertPath, "cert.pem"),
|
|
||||||
KeyFile: filepath.Join(dockerCertPath, "key.pem"),
|
|
||||||
InsecureSkipVerify: os.Getenv("DOCKER_TLS_VERIFY") == "",
|
|
||||||
}
|
|
||||||
tlsc, err := tlsconfig.Client(options)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
c.client = &http.Client{
|
|
||||||
Transport: &http.Transport{TLSClientConfig: tlsc},
|
|
||||||
CheckRedirect: CheckRedirect,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if host := os.Getenv("DOCKER_HOST"); host != "" {
|
|
||||||
if err := WithHost(host)(c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if version := os.Getenv("DOCKER_API_VERSION"); version != "" {
|
|
||||||
c.version = version
|
|
||||||
c.manualOverride = true
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithTLSClientConfig applies a tls config to the client transport.
|
|
||||||
func WithTLSClientConfig(cacertPath, certPath, keyPath string) func(*Client) error {
|
|
||||||
return func(c *Client) error {
|
|
||||||
opts := tlsconfig.Options{
|
|
||||||
CAFile: cacertPath,
|
|
||||||
CertFile: certPath,
|
|
||||||
KeyFile: keyPath,
|
|
||||||
ExclusiveRootPools: true,
|
|
||||||
}
|
|
||||||
config, err := tlsconfig.Client(opts)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err, "failed to create tls config")
|
|
||||||
}
|
|
||||||
if transport, ok := c.client.Transport.(*http.Transport); ok {
|
|
||||||
transport.TLSClientConfig = config
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.Errorf("cannot apply tls config to transport: %T", c.client.Transport)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithDialer applies the dialer.DialContext to the client transport. This can be
|
|
||||||
// used to set the Timeout and KeepAlive settings of the client.
|
|
||||||
func WithDialer(dialer *net.Dialer) func(*Client) error {
|
|
||||||
return func(c *Client) error {
|
|
||||||
if transport, ok := c.client.Transport.(*http.Transport); ok {
|
|
||||||
transport.DialContext = dialer.DialContext
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithVersion overrides the client version with the specified one
|
|
||||||
func WithVersion(version string) func(*Client) error {
|
|
||||||
return func(c *Client) error {
|
|
||||||
c.version = version
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithHost overrides the client host with the specified one.
|
|
||||||
func WithHost(host string) func(*Client) error {
|
|
||||||
return func(c *Client) error {
|
|
||||||
hostURL, err := ParseHostURL(host)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.host = host
|
|
||||||
c.proto = hostURL.Scheme
|
|
||||||
c.addr = hostURL.Host
|
|
||||||
c.basePath = hostURL.Path
|
|
||||||
if transport, ok := c.client.Transport.(*http.Transport); ok {
|
|
||||||
return sockets.ConfigureTransport(transport, c.proto, c.addr)
|
|
||||||
}
|
|
||||||
return errors.Errorf("cannot apply host to transport: %T", c.client.Transport)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithHTTPClient overrides the client http client with the specified one
|
|
||||||
func WithHTTPClient(client *http.Client) func(*Client) error {
|
|
||||||
return func(c *Client) error {
|
|
||||||
if client != nil {
|
|
||||||
c.client = client
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithHTTPHeaders overrides the client default http headers
|
|
||||||
func WithHTTPHeaders(headers map[string]string) func(*Client) error {
|
|
||||||
return func(c *Client) error {
|
|
||||||
c.customHTTPHeaders = headers
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewClientWithOpts initializes a new API client with default values. It takes functors
|
// NewClientWithOpts initializes a new API client with default values. It takes functors
|
||||||
// to modify values when creating it, like `NewClientWithOpts(WithVersion(…))`
|
// to modify values when creating it, like `NewClientWithOpts(WithVersion(…))`
|
||||||
// It also initializes the custom http headers to add to each request.
|
// It also initializes the custom http headers to add to each request.
|
||||||
|
@ -242,7 +115,6 @@ func NewClientWithOpts(ops ...func(*Client) error) (*Client, error) {
|
||||||
c := &Client{
|
c := &Client{
|
||||||
host: DefaultDockerHost,
|
host: DefaultDockerHost,
|
||||||
version: api.DefaultVersion,
|
version: api.DefaultVersion,
|
||||||
scheme: "http",
|
|
||||||
client: client,
|
client: client,
|
||||||
proto: defaultProto,
|
proto: defaultProto,
|
||||||
addr: defaultAddr,
|
addr: defaultAddr,
|
||||||
|
@ -257,14 +129,18 @@ func NewClientWithOpts(ops ...func(*Client) error) (*Client, error) {
|
||||||
if _, ok := c.client.Transport.(http.RoundTripper); !ok {
|
if _, ok := c.client.Transport.(http.RoundTripper); !ok {
|
||||||
return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", c.client.Transport)
|
return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", c.client.Transport)
|
||||||
}
|
}
|
||||||
tlsConfig := resolveTLSConfig(c.client.Transport)
|
if c.scheme == "" {
|
||||||
if tlsConfig != nil {
|
c.scheme = "http"
|
||||||
// TODO(stevvooe): This isn't really the right way to write clients in Go.
|
|
||||||
// `NewClient` should probably only take an `*http.Client` and work from there.
|
tlsConfig := resolveTLSConfig(c.client.Transport)
|
||||||
// Unfortunately, the model of having a host-ish/url-thingy as the connection
|
if tlsConfig != nil {
|
||||||
// string has us confusing protocol and transport layers. We continue doing
|
// TODO(stevvooe): This isn't really the right way to write clients in Go.
|
||||||
// this to avoid breaking existing clients but this should be addressed.
|
// `NewClient` should probably only take an `*http.Client` and work from there.
|
||||||
c.scheme = "https"
|
// Unfortunately, the model of having a host-ish/url-thingy as the connection
|
||||||
|
// string has us confusing protocol and transport layers. We continue doing
|
||||||
|
// this to avoid breaking existing clients but this should be addressed.
|
||||||
|
c.scheme = "https"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c, nil
|
return c, nil
|
||||||
|
@ -283,18 +159,6 @@ func defaultHTTPClient(host string) (*http.Client, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient initializes a new API client for the given host and API version.
|
|
||||||
// It uses the given http client as transport.
|
|
||||||
// It also initializes the custom http headers to add to each request.
|
|
||||||
//
|
|
||||||
// It won't send any version information if the version number is empty. It is
|
|
||||||
// highly recommended that you set a version or your client may break if the
|
|
||||||
// server is upgraded.
|
|
||||||
// Deprecated: use NewClientWithOpts
|
|
||||||
func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) {
|
|
||||||
return NewClientWithOpts(WithHost(host), WithVersion(version), WithHTTPClient(client), WithHTTPHeaders(httpHeaders))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close the transport used by the client
|
// Close the transport used by the client
|
||||||
func (cli *Client) Close() error {
|
func (cli *Client) Close() error {
|
||||||
if t, ok := cli.client.Transport.(*http.Transport); ok {
|
if t, ok := cli.client.Transport.(*http.Transport); ok {
|
||||||
|
@ -400,3 +264,16 @@ func (cli *Client) CustomHTTPHeaders() map[string]string {
|
||||||
func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) {
|
func (cli *Client) SetCustomHTTPHeaders(headers map[string]string) {
|
||||||
cli.customHTTPHeaders = headers
|
cli.customHTTPHeaders = headers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dialer returns a dialer for a raw stream connection, with HTTP/1.1 header, that can be used for proxying the daemon connection.
|
||||||
|
// Used by `docker dial-stdio` (docker/cli#889).
|
||||||
|
func (cli *Client) Dialer() func(context.Context) (net.Conn, error) {
|
||||||
|
return func(ctx context.Context) (net.Conn, error) {
|
||||||
|
if transport, ok := cli.client.Transport.(*http.Transport); ok {
|
||||||
|
if transport.DialContext != nil && transport.TLSClientConfig == nil {
|
||||||
|
return transport.DialContext(ctx, cli.proto, cli.addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fallbackDial(cli.proto, cli.addr, resolveTLSConfig(cli.client.Transport))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// NewClient initializes a new API client for the given host and API version.
|
||||||
|
// It uses the given http client as transport.
|
||||||
|
// It also initializes the custom http headers to add to each request.
|
||||||
|
//
|
||||||
|
// It won't send any version information if the version number is empty. It is
|
||||||
|
// highly recommended that you set a version or your client may break if the
|
||||||
|
// server is upgraded.
|
||||||
|
// Deprecated: use NewClientWithOpts
|
||||||
|
func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) {
|
||||||
|
return NewClientWithOpts(WithHost(host), WithVersion(version), WithHTTPClient(client), WithHTTPHeaders(httpHeaders))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewEnvClient initializes a new API client based on environment variables.
|
||||||
|
// See FromEnv for a list of support environment variables.
|
||||||
|
//
|
||||||
|
// Deprecated: use NewClientWithOpts(FromEnv)
|
||||||
|
func NewEnvClient() (*Client, error) {
|
||||||
|
return NewClientWithOpts(FromEnv)
|
||||||
|
}
|
|
@ -15,11 +15,11 @@ func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (t
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
|
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(resp.body).Decode(&response)
|
err = json.NewDecoder(resp.body).Decode(&response)
|
||||||
ensureReaderClosed(resp)
|
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,10 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C
|
||||||
return swarm.Config{}, nil, err
|
return swarm.Config{}, nil, err
|
||||||
}
|
}
|
||||||
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
|
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id)
|
return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id)
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(resp)
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(resp.body)
|
body, err := ioutil.ReadAll(resp.body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -27,12 +27,12 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.get(ctx, "/configs", query, nil)
|
resp, err := cli.get(ctx, "/configs", query, nil)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var configs []swarm.Config
|
var configs []swarm.Config
|
||||||
err = json.NewDecoder(resp.body).Decode(&configs)
|
err = json.NewDecoder(resp.body).Decode(&configs)
|
||||||
ensureReaderClosed(resp)
|
|
||||||
return configs, err
|
return configs, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,6 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
|
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
|
||||||
ensureReaderClosed(resp)
|
defer ensureReaderClosed(resp)
|
||||||
return wrapResponseError(err, resp, "config", id)
|
return wrapResponseError(err, resp, "config", id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,11 +45,11 @@ func (cli *Client) ContainerCommit(ctx context.Context, container string, option
|
||||||
|
|
||||||
var response types.IDResponse
|
var response types.IDResponse
|
||||||
resp, err := cli.post(ctx, "/commit", query, options.Config, nil)
|
resp, err := cli.post(ctx, "/commit", query, options.Config, nil)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(resp.body).Decode(&response)
|
err = json.NewDecoder(resp.body).Decode(&response)
|
||||||
ensureReaderClosed(resp)
|
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,10 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri
|
||||||
|
|
||||||
urlStr := "/containers/" + containerID + "/archive"
|
urlStr := "/containers/" + containerID + "/archive"
|
||||||
response, err := cli.head(ctx, urlStr, query, nil)
|
response, err := cli.head(ctx, urlStr, query, nil)
|
||||||
|
defer ensureReaderClosed(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+path)
|
return types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+path)
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(response)
|
|
||||||
return getContainerPathStatFromHeader(response.header)
|
return getContainerPathStatFromHeader(response.header)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +45,12 @@ func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath str
|
||||||
apiPath := "/containers/" + containerID + "/archive"
|
apiPath := "/containers/" + containerID + "/archive"
|
||||||
|
|
||||||
response, err := cli.putRaw(ctx, apiPath, query, content, nil)
|
response, err := cli.putRaw(ctx, apiPath, query, content, nil)
|
||||||
|
defer ensureReaderClosed(response)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return wrapResponseError(err, response, "container:path", containerID+":"+dstPath)
|
return wrapResponseError(err, response, "container:path", containerID+":"+dstPath)
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(response)
|
|
||||||
|
|
||||||
|
// TODO this code converts non-error status-codes (e.g., "204 No Content") into an error; verify if this is the desired behavior
|
||||||
if response.statusCode != http.StatusOK {
|
if response.statusCode != http.StatusOK {
|
||||||
return fmt.Errorf("unexpected status code from daemon: %d", response.statusCode)
|
return fmt.Errorf("unexpected status code from daemon: %d", response.statusCode)
|
||||||
}
|
}
|
||||||
|
@ -69,6 +70,7 @@ func (cli *Client) CopyFromContainer(ctx context.Context, containerID, srcPath s
|
||||||
return nil, types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+srcPath)
|
return nil, types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+srcPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO this code converts non-error status-codes (e.g., "204 No Content") into an error; verify if this is the desired behavior
|
||||||
if response.statusCode != http.StatusOK {
|
if response.statusCode != http.StatusOK {
|
||||||
return nil, types.ContainerPathStat{}, fmt.Errorf("unexpected status code from daemon: %d", response.statusCode)
|
return nil, types.ContainerPathStat{}, fmt.Errorf("unexpected status code from daemon: %d", response.statusCode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
|
@ -43,14 +42,11 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/containers/create", query, body, nil)
|
serverResp, err := cli.post(ctx, "/containers/create", query, body, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if serverResp.statusCode == 404 && strings.Contains(err.Error(), "No such image") {
|
|
||||||
return response, objectNotFoundError{object: "image", id: config.Image}
|
|
||||||
}
|
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||||
ensureReaderClosed(serverResp)
|
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,11 +13,11 @@ func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]con
|
||||||
var changes []container.ContainerChangeResponseItem
|
var changes []container.ContainerChangeResponseItem
|
||||||
|
|
||||||
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil)
|
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return changes, err
|
return changes, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(serverResp.body).Decode(&changes)
|
err = json.NewDecoder(serverResp.body).Decode(&changes)
|
||||||
ensureReaderClosed(serverResp)
|
|
||||||
return changes, err
|
return changes, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,11 @@ func (cli *Client) ContainerExecCreate(ctx context.Context, container string, co
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil)
|
resp, err := cli.post(ctx, "/containers/"+container+"/exec", nil, config, nil)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
err = json.NewDecoder(resp.body).Decode(&response)
|
err = json.NewDecoder(resp.body).Decode(&response)
|
||||||
ensureReaderClosed(resp)
|
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,13 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ty
|
||||||
return types.ContainerJSON{}, objectNotFoundError{object: "container", id: containerID}
|
return types.ContainerJSON{}, objectNotFoundError{object: "container", id: containerID}
|
||||||
}
|
}
|
||||||
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
|
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID)
|
return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
var response types.ContainerJSON
|
var response types.ContainerJSON
|
||||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||||
ensureReaderClosed(serverResp)
|
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +36,10 @@ func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID stri
|
||||||
query.Set("size", "1")
|
query.Set("size", "1")
|
||||||
}
|
}
|
||||||
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
|
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID)
|
return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID)
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(serverResp)
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(serverResp.body)
|
body, err := ioutil.ReadAll(serverResp.body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -45,12 +45,12 @@ func (cli *Client) ContainerList(ctx context.Context, options types.ContainerLis
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.get(ctx, "/containers/json", query, nil)
|
resp, err := cli.get(ctx, "/containers/json", query, nil)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var containers []types.Container
|
var containers []types.Container
|
||||||
err = json.NewDecoder(resp.body).Decode(&containers)
|
err = json.NewDecoder(resp.body).Decode(&containers)
|
||||||
ensureReaderClosed(resp)
|
|
||||||
return containers, err
|
return containers, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,10 @@ func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Arg
|
||||||
}
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
|
serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(serverResp)
|
|
||||||
|
|
||||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||||
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
|
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
|
||||||
|
|
|
@ -22,6 +22,6 @@ func (cli *Client) ContainerRemove(ctx context.Context, containerID string, opti
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil)
|
resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil)
|
||||||
ensureReaderClosed(resp)
|
defer ensureReaderClosed(resp)
|
||||||
return wrapResponseError(err, resp, "container", containerID)
|
return wrapResponseError(err, resp, "container", containerID)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@ func (cli *Client) ContainerTop(ctx context.Context, containerID string, argumen
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil)
|
resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(resp.body).Decode(&response)
|
err = json.NewDecoder(resp.body).Decode(&response)
|
||||||
ensureReaderClosed(resp)
|
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,12 +11,11 @@ import (
|
||||||
func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) {
|
func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) {
|
||||||
var response container.ContainerUpdateOKBody
|
var response container.ContainerUpdateOKBody
|
||||||
serverResp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
|
serverResp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(serverResp.body).Decode(&response)
|
err = json.NewDecoder(serverResp.body).Decode(&response)
|
||||||
|
|
||||||
ensureReaderClosed(serverResp)
|
|
||||||
return response, err
|
return response, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,10 @@ func (cli *Client) DiskUsage(ctx context.Context) (types.DiskUsage, error) {
|
||||||
var du types.DiskUsage
|
var du types.DiskUsage
|
||||||
|
|
||||||
serverResp, err := cli.get(ctx, "/system/df", nil, nil)
|
serverResp, err := cli.get(ctx, "/system/df", nil, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return du, err
|
return du, err
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(serverResp)
|
|
||||||
|
|
||||||
if err := json.NewDecoder(serverResp.body).Decode(&du); err != nil {
|
if err := json.NewDecoder(serverResp.body).Decode(&du); err != nil {
|
||||||
return du, fmt.Errorf("Error retrieving disk usage: %v", err)
|
return du, fmt.Errorf("Error retrieving disk usage: %v", err)
|
||||||
|
|
|
@ -28,11 +28,11 @@ func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegist
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.get(ctx, "/distribution/"+image+"/json", url.Values{}, headers)
|
resp, err := cli.get(ctx, "/distribution/"+image+"/json", url.Values{}, headers)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return distributionInspect, err
|
return distributionInspect, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(resp.body).Decode(&distributionInspect)
|
err = json.NewDecoder(resp.body).Decode(&distributionInspect)
|
||||||
ensureReaderClosed(resp)
|
|
||||||
return distributionInspect, err
|
return distributionInspect, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/versions"
|
"github.com/docker/docker/api/types/versions"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,16 +33,19 @@ func ErrorConnectionFailed(host string) error {
|
||||||
return errConnectionFailed{host: host}
|
return errConnectionFailed{host: host}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use the errdefs.NotFound() interface instead. Kept for backward compatibility
|
||||||
type notFound interface {
|
type notFound interface {
|
||||||
error
|
error
|
||||||
NotFound() bool // Is the error a NotFound error
|
NotFound() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsErrNotFound returns true if the error is a NotFound error, which is returned
|
// IsErrNotFound returns true if the error is a NotFound error, which is returned
|
||||||
// by the API when some object is not found.
|
// by the API when some object is not found.
|
||||||
func IsErrNotFound(err error) bool {
|
func IsErrNotFound(err error) bool {
|
||||||
te, ok := err.(notFound)
|
if _, ok := err.(notFound); ok {
|
||||||
return ok && te.NotFound()
|
return ok
|
||||||
|
}
|
||||||
|
return errdefs.IsNotFound(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
type objectNotFoundError struct {
|
type objectNotFoundError struct {
|
||||||
|
@ -49,9 +53,7 @@ type objectNotFoundError struct {
|
||||||
id string
|
id string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e objectNotFoundError) NotFound() bool {
|
func (e objectNotFoundError) NotFound() {}
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e objectNotFoundError) Error() string {
|
func (e objectNotFoundError) Error() string {
|
||||||
return fmt.Sprintf("Error: No such %s: %s", e.object, e.id)
|
return fmt.Sprintf("Error: No such %s: %s", e.object, e.id)
|
||||||
|
@ -64,7 +66,7 @@ func wrapResponseError(err error, resp serverResponse, object, id string) error
|
||||||
case resp.statusCode == http.StatusNotFound:
|
case resp.statusCode == http.StatusNotFound:
|
||||||
return objectNotFoundError{object: object, id: id}
|
return objectNotFoundError{object: object, id: id}
|
||||||
case resp.statusCode == http.StatusNotImplemented:
|
case resp.statusCode == http.StatusNotImplemented:
|
||||||
return notImplementedError{message: err.Error()}
|
return errdefs.NotImplemented(err)
|
||||||
default:
|
default:
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -83,8 +85,10 @@ func (u unauthorizedError) Error() string {
|
||||||
// IsErrUnauthorized returns true if the error is caused
|
// IsErrUnauthorized returns true if the error is caused
|
||||||
// when a remote registry authentication fails
|
// when a remote registry authentication fails
|
||||||
func IsErrUnauthorized(err error) bool {
|
func IsErrUnauthorized(err error) bool {
|
||||||
_, ok := err.(unauthorizedError)
|
if _, ok := err.(unauthorizedError); ok {
|
||||||
return ok
|
return ok
|
||||||
|
}
|
||||||
|
return errdefs.IsUnauthorized(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
type pluginPermissionDenied struct {
|
type pluginPermissionDenied struct {
|
||||||
|
@ -118,8 +122,10 @@ func (e notImplementedError) NotImplemented() bool {
|
||||||
// This is returned by the API when a requested feature has not been
|
// This is returned by the API when a requested feature has not been
|
||||||
// implemented.
|
// implemented.
|
||||||
func IsErrNotImplemented(err error) bool {
|
func IsErrNotImplemented(err error) bool {
|
||||||
te, ok := err.(notImplementedError)
|
if _, ok := err.(notImplementedError); ok {
|
||||||
return ok && te.NotImplemented()
|
return ok
|
||||||
|
}
|
||||||
|
return errdefs.IsNotImplemented(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVersionError returns an error if the APIVersion required
|
// NewVersionError returns an error if the APIVersion required
|
||||||
|
|
|
@ -30,7 +30,7 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
|
||||||
}
|
}
|
||||||
req = cli.addHeaders(req, headers)
|
req = cli.addHeaders(req, headers)
|
||||||
|
|
||||||
conn, err := cli.setupHijackConn(req, "tcp")
|
conn, err := cli.setupHijackConn(ctx, req, "tcp")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.HijackedResponse{}, err
|
return types.HijackedResponse{}, err
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,20 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
|
||||||
return types.HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn)}, err
|
return types.HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn)}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func dial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {
|
// DialHijack returns a hijacked connection with negotiated protocol proto.
|
||||||
|
func (cli *Client) DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) {
|
||||||
|
req, err := http.NewRequest("POST", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req = cli.addHeaders(req, meta)
|
||||||
|
|
||||||
|
return cli.setupHijackConn(ctx, req, proto)
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallbackDial is used when WithDialer() was not called.
|
||||||
|
// See cli.Dialer().
|
||||||
|
func fallbackDial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {
|
||||||
if tlsConfig != nil && proto != "unix" && proto != "npipe" {
|
if tlsConfig != nil && proto != "unix" && proto != "npipe" {
|
||||||
return tls.Dial(proto, addr, tlsConfig)
|
return tls.Dial(proto, addr, tlsConfig)
|
||||||
}
|
}
|
||||||
|
@ -48,12 +61,13 @@ func dial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {
|
||||||
return net.Dial(proto, addr)
|
return net.Dial(proto, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cli *Client) setupHijackConn(req *http.Request, proto string) (net.Conn, error) {
|
func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto string) (net.Conn, error) {
|
||||||
req.Host = cli.addr
|
req.Host = cli.addr
|
||||||
req.Header.Set("Connection", "Upgrade")
|
req.Header.Set("Connection", "Upgrade")
|
||||||
req.Header.Set("Upgrade", proto)
|
req.Header.Set("Upgrade", proto)
|
||||||
|
|
||||||
conn, err := dial(cli.proto, cli.addr, resolveTLSConfig(cli.client.Transport))
|
dialer := cli.Dialer()
|
||||||
|
conn, err := dialer(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot connect to the Docker daemon. Is 'docker daemon' running on this host?")
|
return nil, errors.Wrap(err, "cannot connect to the Docker daemon. Is 'docker daemon' running on this host?")
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,12 +30,6 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio
|
||||||
}
|
}
|
||||||
headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
|
headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
|
||||||
|
|
||||||
if options.Platform != "" {
|
|
||||||
if err := cli.NewVersionError("1.32", "platform"); err != nil {
|
|
||||||
return types.ImageBuildResponse{}, err
|
|
||||||
}
|
|
||||||
query.Set("platform", options.Platform)
|
|
||||||
}
|
|
||||||
headers.Set("Content-Type", "application/x-tar")
|
headers.Set("Content-Type", "application/x-tar")
|
||||||
|
|
||||||
serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers)
|
serverResp, err := cli.postRaw(ctx, "/build", query, buildContext, headers)
|
||||||
|
@ -131,7 +125,22 @@ func (cli *Client) imageBuildOptionsToQuery(options types.ImageBuildOptions) (ur
|
||||||
query.Set("session", options.SessionID)
|
query.Set("session", options.SessionID)
|
||||||
}
|
}
|
||||||
if options.Platform != "" {
|
if options.Platform != "" {
|
||||||
|
if err := cli.NewVersionError("1.32", "platform"); err != nil {
|
||||||
|
return query, err
|
||||||
|
}
|
||||||
query.Set("platform", strings.ToLower(options.Platform))
|
query.Set("platform", strings.ToLower(options.Platform))
|
||||||
}
|
}
|
||||||
|
if options.BuildID != "" {
|
||||||
|
query.Set("buildid", options.BuildID)
|
||||||
|
}
|
||||||
|
query.Set("version", string(options.Version))
|
||||||
|
|
||||||
|
if options.Outputs != nil {
|
||||||
|
outputsJSON, err := json.Marshal(options.Outputs)
|
||||||
|
if err != nil {
|
||||||
|
return query, err
|
||||||
|
}
|
||||||
|
query.Set("outputs", string(outputsJSON))
|
||||||
|
}
|
||||||
return query, nil
|
return query, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@ import (
|
||||||
func (cli *Client) ImageHistory(ctx context.Context, imageID string) ([]image.HistoryResponseItem, error) {
|
func (cli *Client) ImageHistory(ctx context.Context, imageID string) ([]image.HistoryResponseItem, error) {
|
||||||
var history []image.HistoryResponseItem
|
var history []image.HistoryResponseItem
|
||||||
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", url.Values{}, nil)
|
serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", url.Values{}, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return history, err
|
return history, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(serverResp.body).Decode(&history)
|
err = json.NewDecoder(serverResp.body).Decode(&history)
|
||||||
ensureReaderClosed(serverResp)
|
|
||||||
return history, err
|
return history, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,10 +15,10 @@ func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (typ
|
||||||
return types.ImageInspect{}, nil, objectNotFoundError{object: "image", id: imageID}
|
return types.ImageInspect{}, nil, objectNotFoundError{object: "image", id: imageID}
|
||||||
}
|
}
|
||||||
serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil)
|
serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID)
|
return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID)
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(serverResp)
|
|
||||||
|
|
||||||
body, err := ioutil.ReadAll(serverResp.body)
|
body, err := ioutil.ReadAll(serverResp.body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -35,11 +35,11 @@ func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
serverResp, err := cli.get(ctx, "/images/json", query, nil)
|
serverResp, err := cli.get(ctx, "/images/json", query, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return images, err
|
return images, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(serverResp.body).Decode(&images)
|
err = json.NewDecoder(serverResp.body).Decode(&images)
|
||||||
ensureReaderClosed(serverResp)
|
|
||||||
return images, err
|
return images, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,10 @@ func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (
|
||||||
}
|
}
|
||||||
|
|
||||||
serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil)
|
serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil)
|
||||||
|
defer ensureReaderClosed(serverResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
defer ensureReaderClosed(serverResp)
|
|
||||||
|
|
||||||
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
|
||||||
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
|
return report, fmt.Errorf("Error retrieving disk usage: %v", err)
|
||||||
|
|
|
@ -3,12 +3,12 @@ package client // import "github.com/docker/docker/client"
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImagePull requests the docker host to pull an image from a remote registry.
|
// ImagePull requests the docker host to pull an image from a remote registry.
|
||||||
|
@ -35,7 +35,7 @@ func (cli *Client) ImagePull(ctx context.Context, refStr string, options types.I
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
|
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
|
||||||
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
|
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
|
||||||
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
||||||
if privilegeErr != nil {
|
if privilegeErr != nil {
|
||||||
return nil, privilegeErr
|
return nil, privilegeErr
|
||||||
|
|
|
@ -4,11 +4,11 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/distribution/reference"
|
"github.com/docker/distribution/reference"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/errdefs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ImagePush requests the docker host to push an image to a remote registry.
|
// ImagePush requests the docker host to push an image to a remote registry.
|
||||||
|
@ -36,7 +36,7 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options types.Im
|
||||||
query.Set("tag", tag)
|
query.Set("tag", tag)
|
||||||
|
|
||||||
resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth)
|
resp, err := cli.tryImagePush(ctx, name, query, options.RegistryAuth)
|
||||||
if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil {
|
if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
|
||||||
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
newAuthHeader, privilegeErr := options.PrivilegeFunc()
|
||||||
if privilegeErr != nil {
|
if privilegeErr != nil {
|
||||||
return nil, privilegeErr
|
return nil, privilegeErr
|
||||||
|
|
|
@ -21,11 +21,11 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options type
|
||||||
|
|
||||||
var dels []types.ImageDeleteResponseItem
|
var dels []types.ImageDeleteResponseItem
|
||||||
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
|
resp, err := cli.delete(ctx, "/images/"+imageID, query, nil)
|
||||||
|
defer ensureReaderClosed(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dels, wrapResponseError(err, resp, "image", imageID)
|
return dels, wrapResponseError(err, resp, "image", imageID)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.NewDecoder(resp.body).Decode(&dels)
|
err = json.NewDecoder(resp.body).Decode(&dels)
|
||||||
ensureReaderClosed(resp)
|
|
||||||
return dels, err
|
return dels, err
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue