diff --git a/pkg/agent/containerd/containerd.go b/pkg/agent/containerd/containerd.go index ffae694eff23..c38631dc29bb 100644 --- a/pkg/agent/containerd/containerd.go +++ b/pkg/agent/containerd/containerd.go @@ -15,6 +15,7 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/namespaces" "github.com/natefinch/lumberjack" + "github.com/opencontainers/runc/libcontainer/system" util2 "github.com/rancher/k3s/pkg/agent/util" "github.com/rancher/k3s/pkg/daemons/config" "github.com/sirupsen/logrus" @@ -27,10 +28,15 @@ const ( maxMsgSize = 1024 * 1024 * 16 configToml = ` [plugins.opt] - path = "%OPT%" + path = "%OPT%" [plugins.cri] stream_server_address = "%NODE%" stream_server_port = "10010" +` + configUserNSToml = ` + disable_cgroup = true + disable_apparmor = true + restrict_oom_score_adj = true ` configCNIToml = ` [plugins.cri.cni] @@ -49,6 +55,9 @@ func Run(ctx context.Context, cfg *config.Node) error { } template := configToml + if system.RunningInUserNS() { + template += configUserNSToml + } if !cfg.NoFlannel { template += configCNIToml } diff --git a/pkg/agent/run.go b/pkg/agent/run.go index 7d5d77f444e8..8fe6fc9c4077 100644 --- a/pkg/agent/run.go +++ b/pkg/agent/run.go @@ -17,6 +17,7 @@ import ( "github.com/rancher/k3s/pkg/agent/tunnel" "github.com/rancher/k3s/pkg/cli/cmds" "github.com/rancher/k3s/pkg/daemons/agent" + "github.com/rancher/k3s/pkg/rootless" "github.com/rancher/norman/pkg/clientaccess" "github.com/sirupsen/logrus" ) @@ -69,6 +70,12 @@ func Run(ctx context.Context, cfg cmds.Agent) error { return err } + if cfg.Rootless { + if err := rootless.Rootless(cfg.DataDir); err != nil { + return err + } + } + cfg.DataDir = filepath.Join(cfg.DataDir, "agent") if cfg.ClusterSecret != "" { diff --git a/pkg/cli/agent/agent.go b/pkg/cli/agent/agent.go index 647b742d65fb..a239a82954ae 100644 --- a/pkg/cli/agent/agent.go +++ b/pkg/cli/agent/agent.go @@ -10,7 +10,7 @@ import ( "github.com/rancher/k3s/pkg/agent" "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/sirupsen/logrus" "github.com/urfave/cli" @@ -57,7 +57,7 @@ func Run(ctx *cli.Context) error { 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 { return err } diff --git a/pkg/cli/cmds/agent.go b/pkg/cli/cmds/agent.go index 3e56051ad6c3..0b02acee1925 100644 --- a/pkg/cli/cmds/agent.go +++ b/pkg/cli/cmds/agent.go @@ -20,6 +20,7 @@ type Agent struct { ContainerRuntimeEndpoint string NoFlannel bool Debug bool + Rootless bool AgentShared ExtraKubeletArgs cli.StringSlice ExtraKubeProxyArgs cli.StringSlice @@ -113,6 +114,11 @@ func NewAgentCommand(action func(ctx *cli.Context) error) cli.Command { Destination: &AgentConfig.ClusterSecret, EnvVar: "K3S_CLUSTER_SECRET", }, + cli.BoolFlag{ + Name: "rootless", + Usage: "(experimental) Run rootless", + Destination: &AgentConfig.Rootless, + }, DockerFlag, FlannelFlag, NodeNameFlag, diff --git a/pkg/cli/cmds/server.go b/pkg/cli/cmds/server.go index 5453ab9014b0..62e8a77d422f 100644 --- a/pkg/cli/cmds/server.go +++ b/pkg/cli/cmds/server.go @@ -21,6 +21,7 @@ type Server struct { ExtraAPIArgs cli.StringSlice ExtraSchedulerArgs cli.StringSlice ExtraControllerArgs cli.StringSlice + Rootless bool } var ServerConfig Server @@ -124,6 +125,11 @@ func NewServerCommand(action func(*cli.Context) error) cli.Command { Usage: "Customized flag for kube-controller-manager process", Value: &ServerConfig.ExtraControllerArgs, }, + cli.BoolFlag{ + Name: "rootless", + Usage: "(experimental) Run rootless", + Destination: &ServerConfig.Rootless, + }, NodeIPFlag, NodeNameFlag, DockerFlag, diff --git a/pkg/cli/server/server.go b/pkg/cli/server/server.go index 8961532df48e..a40d4125a48c 100644 --- a/pkg/cli/server/server.go +++ b/pkg/cli/server/server.go @@ -15,12 +15,14 @@ import ( "github.com/pkg/errors" "github.com/rancher/k3s/pkg/agent" "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/norman/signal" "github.com/sirupsen/logrus" "github.com/urfave/cli" "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 ) @@ -67,18 +69,30 @@ func run(app *cli.Context, cfg *cmds.Server) error { 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") } + 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 - volume.WaitForValidHost = !cfg.DisableAgent + csi.WaitForValidHostName = !cfg.DisableAgent serverConfig := server.Config{} serverConfig.ControlConfig.ClusterSecret = cfg.ClusterSecret serverConfig.ControlConfig.DataDir = cfg.DataDir serverConfig.ControlConfig.KubeConfigOutput = cfg.KubeConfigOutput serverConfig.ControlConfig.KubeConfigMode = cfg.KubeConfigMode + serverConfig.Rootless = cfg.Rootless serverConfig.TLSConfig.HTTPSPort = cfg.HTTPSPort serverConfig.TLSConfig.HTTPPort = cfg.HTTPPort serverConfig.TLSConfig.KnownIPs = knownIPs(cfg.KnownIPs) diff --git a/pkg/daemons/agent/agent.go b/pkg/daemons/agent/agent.go index 862ea28e471f..d582368fa80a 100644 --- a/pkg/daemons/agent/agent.go +++ b/pkg/daemons/agent/agent.go @@ -9,12 +9,14 @@ import ( "strings" "time" + "github.com/opencontainers/runc/libcontainer/system" "github.com/rancher/k3s/pkg/daemons/config" "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/net" "k8s.io/component-base/logs" app2 "k8s.io/kubernetes/cmd/kube-proxy/app" "k8s.io/kubernetes/cmd/kubelet/app" + _ "k8s.io/kubernetes/pkg/client/metrics/prometheus" // for client 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["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) go func() { diff --git a/pkg/datadir/datadir.go b/pkg/datadir/datadir.go index e174a7a32510..7653a10cfca4 100644 --- a/pkg/datadir/datadir.go +++ b/pkg/datadir/datadir.go @@ -15,8 +15,12 @@ const ( ) func Resolve(dataDir string) (string, error) { + return LocalHome(dataDir, false) +} + +func LocalHome(dataDir string, forceLocal bool) (string, error) { if dataDir == "" { - if os.Getuid() == 0 { + if os.Getuid() == 0 && !forceLocal { dataDir = DefaultDataDir } else { dataDir = DefaultHomeDataDir diff --git a/pkg/kubectl/main.go b/pkg/kubectl/main.go index 09bec12e44e0..edf998ce983f 100644 --- a/pkg/kubectl/main.go +++ b/pkg/kubectl/main.go @@ -17,7 +17,7 @@ import ( func Main() { kubenv := os.Getenv("KUBECONFIG") if kubenv == "" { - config, err := server.HomeKubeConfig(false) + config, err := server.HomeKubeConfig(false, false) if _, serr := os.Stat(config); err == nil && serr == nil { os.Setenv("KUBECONFIG", config) } diff --git a/pkg/rootless/mounts.go b/pkg/rootless/mounts.go new file mode 100644 index 000000000000..6994e348ba13 --- /dev/null +++ b/pkg/rootless/mounts.go @@ -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, "") +} diff --git a/pkg/rootless/rootless.go b/pkg/rootless/rootless.go new file mode 100644 index 000000000000..398475cba19a --- /dev/null +++ b/pkg/rootless/rootless.go @@ -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 +} diff --git a/pkg/rootlessports/controller.go b/pkg/rootlessports/controller.go new file mode 100644 index 000000000000..cd5eb2acc9c2 --- /dev/null +++ b/pkg/rootlessports/controller.go @@ -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 +} diff --git a/pkg/server/server.go b/pkg/server/server.go index 7b04868035e7..28849b62fe27 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -18,6 +18,7 @@ import ( "github.com/rancher/k3s/pkg/datadir" "github.com/rancher/k3s/pkg/deploy" "github.com/rancher/k3s/pkg/helm" + "github.com/rancher/k3s/pkg/rootlessports" "github.com/rancher/k3s/pkg/servicelb" "github.com/rancher/k3s/pkg/static" "github.com/rancher/k3s/pkg/tls" @@ -36,16 +37,8 @@ import ( ) func resolveDataDir(dataDir string) (string, error) { - if dataDir == "" { - if os.Getuid() == 0 { - dataDir = "/var/lib/rancher/k3s" - } else { - dataDir = "${HOME}/.rancher/k3s" - } - } - - dataDir = filepath.Join(dataDir, "server") - return resolvehome.Resolve(dataDir) + dataDir, err := datadir.Resolve(dataDir) + return filepath.Join(dataDir, "server"), err } 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) - writeKubeConfig(certs, &config.TLSConfig, &config.ControlConfig) + writeKubeConfig(certs, &config.TLSConfig, config) return certs, nil } @@ -121,7 +114,8 @@ func startNorman(ctx context.Context, config *Config) (string, error) { MasterControllers: []norman.ControllerRegister{ helm.Register, 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 { dataDir := filepath.Join(controlConfig.DataDir, "static") @@ -138,6 +132,12 @@ func startNorman(ctx context.Context, config *Config) (string, error) { } 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 os.Getuid() == 0 { + if os.Getuid() == 0 && !rootless { return datadir.GlobalConfig, nil } 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) { - clientToken := FormatToken(config.Runtime.ClientToken, certs) +func writeKubeConfig(certs string, tlsConfig *dynamiclistener.UserConfig, config *Config) { + clientToken := FormatToken(config.ControlConfig.Runtime.ClientToken, certs) ip := tlsConfig.BindAddress if ip == "" { ip = "localhost" } url := fmt.Sprintf("https://%s:%d", ip, tlsConfig.HTTPSPort) - kubeConfig, err := HomeKubeConfig(true) + kubeConfig, err := HomeKubeConfig(true, config.Rootless) def := true if err != nil { - kubeConfig = filepath.Join(config.DataDir, "kubeconfig-k3s.yaml") + kubeConfig = filepath.Join(config.ControlConfig.DataDir, "kubeconfig-k3s.yaml") def = false } - if config.KubeConfigOutput != "" { - kubeConfig = config.KubeConfigOutput + if config.ControlConfig.KubeConfigOutput != "" { + kubeConfig = config.ControlConfig.KubeConfigOutput } if err = clientaccess.AgentAccessInfoToKubeConfig(kubeConfig, url, clientToken); err != nil { logrus.Errorf("Failed to generate kubeconfig: %v", err) } - if config.KubeConfigMode != "" { - mode, err := strconv.ParseInt(config.KubeConfigMode, 8, 0) + if config.ControlConfig.KubeConfigMode != "" { + mode, err := strconv.ParseInt(config.ControlConfig.KubeConfigMode, 8, 0) if err == nil { os.Chmod(kubeConfig, os.FileMode(mode)) } else { diff --git a/pkg/server/types.go b/pkg/server/types.go index 9dbcf44ad265..247bfe0e75c7 100644 --- a/pkg/server/types.go +++ b/pkg/server/types.go @@ -10,4 +10,5 @@ type Config struct { DisableServiceLB bool TLSConfig dynamiclistener.UserConfig ControlConfig config.Control + Rootless bool } diff --git a/pkg/servicelb/controller.go b/pkg/servicelb/controller.go index f9b5eda91174..ff28c6954925 100644 --- a/pkg/servicelb/controller.go +++ b/pkg/servicelb/controller.go @@ -34,11 +34,12 @@ var ( 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) appClients := appclient.ClientsFrom(ctx) h := &handler{ + rootless: rootless, enabled: enabled, nodeCache: clients.Node.Cache(), podCache: clients.Pod.Cache(), @@ -59,6 +60,7 @@ func Register(ctx context.Context, kubernetes kubernetes.Interface, enabled bool } type handler struct { + rootless bool enabled bool nodeCache coreclient.NodeClientCache podCache coreclient.PodClientCache @@ -189,6 +191,11 @@ func (h *handler) podIPs(pods []*core.Pod) ([]string, error) { for k := range ips { ipList = append(ipList, k) } + + if len(ipList) > 0 && h.rootless { + return []string{"127.0.0.1"}, nil + } + return ipList, nil } diff --git a/scripts/dev-server.sh b/scripts/dev-server.sh index 98f8ebbcb642..ba928b21bed1 100755 --- a/scripts/dev-server.sh +++ b/scripts/dev-server.sh @@ -5,4 +5,9 @@ mkdir -p $(dirname $0)/../bin cd $(dirname $0)/../bin 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 "$@" diff --git a/scripts/download b/scripts/download index 495e903518ae..f1f6a2572e76 100755 --- a/scripts/download +++ b/scripts/download @@ -4,7 +4,7 @@ source $(dirname $0)/version.sh cd $(dirname $0)/.. -ROOT_VERSION=v0.0.1 +ROOT_VERSION=v0.1.1 TRAEFIK_VERSION=1.64.0 CHARTS_DIR=build/static/charts diff --git a/trash.lock b/trash.lock index 8ea8702f5953..9d92d5c8e4a5 100755 --- a/trash.lock +++ b/trash.lock @@ -22,7 +22,8 @@ import: - package: github.com/containerd/continuity version: bd77b46c8352f74eb12c85bdc01f4b90f69d66b4 - package: github.com/containerd/cri - version: eb926cd79d3bac188dcc4ed7694fc9298f8831be + version: v1.2-k3s.2 + repo: https://github.com/rancher/cri.git - package: github.com/containerd/fifo version: 3d5202aec260678c48179c56f40e6f38a095738c - package: github.com/containerd/go-cni @@ -49,6 +50,8 @@ import: version: v1.1.0 - package: github.com/docker/distribution version: 0d3efadf0154c2b8a4e7b6621fff9809655cc580 +- package: github.com/docker/docker + version: c12f09bf99b54f274a5ae241dd154fa74020cbab - package: github.com/docker/go-events version: 9461782956ad83b30282bf90e31fa6a70c255ba9 - package: github.com/docker/go-metrics @@ -94,6 +97,8 @@ import: version: 1.0.3 - package: github.com/modern-go/reflect2 version: 1.0.1 +- package: github.com/morikuni/aec + version: 39771216ff4c63d11f5e604076f9c45e8be1067b - package: github.com/natefinch/lumberjack version: aee4629129445bbdfb69aa565537dcfa16544311 - package: github.com/opencontainers/go-digest @@ -113,6 +118,8 @@ import: - package: github.com/rancher/norman version: 50017efee23caa79542ef685b65a7b783e0a73ca repo: https://github.com/ibuildthecloud/norman.git +- package: github.com/rootless-containers/rootlesskit + version: 893c1c3de71f54c301fdb85a7c0dd15c1933c159 - package: github.com/seccomp/libseccomp-golang version: 32f571b70023028bd57d9288c20efbcb237f3ce0 - package: github.com/sirupsen/logrus @@ -121,6 +128,8 @@ import: version: db04d3cc01c8b54962a58ec7e491717d06cfcc16 - package: github.com/tchap/go-patricia version: v2.2.6 +- package: github.com/theckman/go-flock + version: v0.7.1 - package: github.com/urfave/cli version: 8e01ec4cd3e2d84ab2fe90d8210528ffbb06d8ff - package: github.com/xeipuuv/gojsonpointer @@ -155,148 +164,144 @@ import: - package: gopkg.in/yaml.v2 version: v2.2.1 - package: k8s.io/kubernetes - version: v1.14.1-k3s.1 + version: v1.14.1-k3s.2 repo: https://github.com/rancher/k3s.git transitive: true staging: true -- package: vbom.ml/util - version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394 -- 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/prometheus/client_model + version: model-0.0.2-12-gfa8ad6fec33561 - package: github.com/imdario/mergo version: v0.3.5 -- package: github.com/vishvananda/netns - version: be1fbeda19366dea804f00efff2dd73a1642fdcc -- package: github.com/prometheus/client_golang - version: v0.9.2 -- package: github.com/mattn/go-shellwords - version: v1.0.3-20-gf8471b0a71ded0 -- package: github.com/prometheus/procfs - version: 65c1f6f8f0fc1e2185eb9863a3bc751496404259 +- package: github.com/fsnotify/fsnotify + version: v1.3.1-1-gf12c6236fe7b5c +- package: github.com/cloudflare/cfssl + version: 1.3.2-21-g56268a613adfed +- package: github.com/spf13/cobra + version: v0.0.1-34-gc439c4fa093711 - package: github.com/vishvananda/netlink version: b2de5d10e38ecce8607e6b438b6d174f389a004e -- package: github.com/chai2010/gettext-go - version: c6fed771bfd517099caf0f7a961671fa8ed08723 -- package: github.com/container-storage-interface/spec - version: v1.1.0 -- package: github.com/hashicorp/golang-lru - version: v0.5.0 -- package: github.com/spf13/pflag - version: v1.0.1 -- package: github.com/shurcooL/sanitized_anchor_name - version: 10ef21a441db47d8b13ebcc5fd2310f636973c77 -- package: github.com/MakeNowJust/heredoc - version: bb23615498cded5e105af4ce27de75b089cbe851 -- package: github.com/prometheus/common - version: v0.2.0 -- package: github.com/coreos/go-semver - version: v0.2.0-9-ge214231b295a8e -- package: github.com/google/cadvisor - version: v0.33.1-k3s.1 - repo: https://github.com/ibuildthecloud/cadvisor.git -- package: github.com/cyphar/filepath-securejoin - version: v0.2.1-1-gae69057f2299fb -- package: github.com/ibuildthecloud/kvsql - version: 0e798b1475327aadf3b8da5d2d1f99bb93dfd667 -- package: github.com/JeffAshton/win_pdh - version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2 -- package: github.com/prometheus/client_model - version: model-0.0.2-12-gfa8ad6fec33561 +- package: github.com/google/certificate-transparency-go + version: v1.0.21 +- package: github.com/coreos/pkg + version: v4 +- package: vbom.ml/util + version: db5cfe13f5cc80a4990d98e2e1b0707a4d1a5394 - 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/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: 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/JeffAshton/win_pdh + version: 76bb4ee9f0ab50f77826f2a2ee7fb9d3880d6ec2 - 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: github.com/shurcooL/sanitized_anchor_name + version: 10ef21a441db47d8b13ebcc5fd2310f636973c77 +- package: github.com/ugorji/go + version: bdcc60b419d136a85cdf2e7cbcac34b3f1cd6e57 +- package: github.com/fatih/camelcase + version: f6a740d52f961c60348ebb109adde9f4635d7540 +- package: github.com/hashicorp/golang-lru + version: v0.5.0 +- package: github.com/prometheus/common + version: v0.2.0 +- package: github.com/sigma/go-inotify + 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: k8s.io/klog - version: v0.2.0-14-g8e90cee79f8237 -- package: github.com/munnerz/goautoneg - version: a547fc61f48d567d5b4ec6f8aee5573d8efce11d +- 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/fatih/camelcase - version: f6a740d52f961c60348ebb109adde9f4635d7540 -- package: k8s.io/utils - version: c2654d5206da6b7b6ace12841e8f359bb89b443c -- package: github.com/coreos/etcd - version: v3.3.10 +- 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: github.com/golang/groupcache - version: 02826c3e79038b59d737d3b1c0a1d937f71a4433 - 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 + version: v0.33.1-k3s.1 + repo: https://github.com/ibuildthecloud/cadvisor.git +- package: github.com/spf13/pflag + version: v1.0.1 +- package: github.com/mistifyio/go-zfs + version: v2.1.1-5-g1b4ae6fb4e77b0 - package: github.com/mitchellh/go-wordwrap version: ad45545899c7b13c020ea92b2072220eefad42b8 -- package: github.com/docker/libnetwork - version: v0.8.0-dev.2-1265-ga9cd636e378982 -- package: sigs.k8s.io/yaml +- package: github.com/ibuildthecloud/kvsql + version: 0e798b1475327aadf3b8da5d2d1f99bb93dfd667 +- package: github.com/googleapis/gnostic + version: 0c5108395e2debce0d731cf0287ddf7242066aba +- package: github.com/inconshreveable/mousetrap + version: v1.0 +- package: github.com/container-storage-interface/spec 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/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/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/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/googleapis/gnostic - version: 0c5108395e2debce0d731cf0287ddf7242066aba +- 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 diff --git a/vendor.conf b/vendor.conf index 104d81463f6d..fa77f9a200de 100644 --- a/vendor.conf +++ b/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/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/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 # 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/blang/semver v3.1.0 github.com/containernetworking/cni v0.6.0 #github.com/containernetworking/plugins v0.7.5 github.com/davecgh/go-spew v1.1.0 github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580 -#github.com/docker/docker 86f080cff0914e9694068ed78d503701667c4c00 +github.com/docker/docker c12f09bf99b54f274a5ae241dd154fa74020cbab github.com/docker/spdystream 449fdfce4d962303d702fec724ef0ad181c92528 github.com/emicklei/go-restful v2.2.1 github.com/ghodss/yaml v1.0.0 @@ -115,3 +115,9 @@ golang.org/x/oauth2 a6bd8cefa1811bd24b86f8902872e4e8225f74c4 golang.org/x/time f51c12702a4d776e4c1fa9b0fabab841babae631 gopkg.in/inf.v0 3887ee99ecf07df5b447e9b00d9c0b2adaa9f3e4 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 diff --git a/vendor/github.com/Nvveen/Gotty/LICENSE b/vendor/github.com/Nvveen/Gotty/LICENSE deleted file mode 100644 index 0b71c97360eb..000000000000 --- a/vendor/github.com/Nvveen/Gotty/LICENSE +++ /dev/null @@ -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. diff --git a/vendor/github.com/Nvveen/Gotty/README b/vendor/github.com/Nvveen/Gotty/README deleted file mode 100644 index a6b0d9a8fe25..000000000000 --- a/vendor/github.com/Nvveen/Gotty/README +++ /dev/null @@ -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. diff --git a/vendor/github.com/Nvveen/Gotty/TODO b/vendor/github.com/Nvveen/Gotty/TODO deleted file mode 100644 index 470460531ca9..000000000000 --- a/vendor/github.com/Nvveen/Gotty/TODO +++ /dev/null @@ -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. diff --git a/vendor/github.com/Nvveen/Gotty/attributes.go b/vendor/github.com/Nvveen/Gotty/attributes.go deleted file mode 100644 index a4c005fae583..000000000000 --- a/vendor/github.com/Nvveen/Gotty/attributes.go +++ /dev/null @@ -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", "", -} diff --git a/vendor/github.com/Nvveen/Gotty/gotty.go b/vendor/github.com/Nvveen/Gotty/gotty.go deleted file mode 100644 index 093cbf37e1bc..000000000000 --- a/vendor/github.com/Nvveen/Gotty/gotty.go +++ /dev/null @@ -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 -} diff --git a/vendor/github.com/Nvveen/Gotty/parser.go b/vendor/github.com/Nvveen/Gotty/parser.go deleted file mode 100644 index a9d5d23c5425..000000000000 --- a/vendor/github.com/Nvveen/Gotty/parser.go +++ /dev/null @@ -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) -} diff --git a/vendor/github.com/Nvveen/Gotty/types.go b/vendor/github.com/Nvveen/Gotty/types.go deleted file mode 100644 index 9bcc65e9b889..000000000000 --- a/vendor/github.com/Nvveen/Gotty/types.go +++ /dev/null @@ -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 -} diff --git a/vendor/github.com/containerd/cri/pkg/config/config.go b/vendor/github.com/containerd/cri/pkg/config/config.go index 7d53a7b53638..9a8d23da1220 100644 --- a/vendor/github.com/containerd/cri/pkg/config/config.go +++ b/vendor/github.com/containerd/cri/pkg/config/config.go @@ -142,6 +142,16 @@ type PluginConfig struct { // Log line longer than the limit will be split into multiple lines. Non-positive // value means no limit. 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 diff --git a/vendor/github.com/containerd/cri/pkg/server/container_create.go b/vendor/github.com/containerd/cri/pkg/server/container_create.go index 01144aaf7e0c..c39921b24bb7 100644 --- a/vendor/github.com/containerd/cri/pkg/server/container_create.go +++ b/vendor/github.com/containerd/cri/pkg/server/container_create.go @@ -416,12 +416,18 @@ func (c *criService) generateContainerSpec(id string, sandboxID string, sandboxP g.SetRootReadonly(securityContext.GetReadonlyRootfs()) - setOCILinuxResource(&g, config.GetLinux().GetResources()) - - if sandboxConfig.GetLinux().GetCgroupParent() != "" { - cgroupsPath := getCgroupsPath(sandboxConfig.GetLinux().GetCgroupParent(), id, - c.config.SystemdCgroup) - g.SetLinuxCgroupsPath(cgroupsPath) + if c.config.DisableCgroup { + g.SetLinuxCgroupsPath("") + } else { + setOCILinuxResourceCgroup(&g, config.GetLinux().GetResources()) + if sandboxConfig.GetLinux().GetCgroupParent() != "" { + 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. @@ -759,8 +765,8 @@ func setOCIBindMountsPrivileged(g *generator) { spec.Linux.MaskedPaths = nil } -// setOCILinuxResource set container resource limit. -func setOCILinuxResource(g *generator, resources *runtime.LinuxContainerResources) { +// setOCILinuxResourceCgroup set container cgroup resource limit. +func setOCILinuxResourceCgroup(g *generator, resources *runtime.LinuxContainerResources) { if resources == nil { return } @@ -768,11 +774,28 @@ func setOCILinuxResource(g *generator, resources *runtime.LinuxContainerResource g.SetLinuxResourcesCPUQuota(resources.GetCpuQuota()) g.SetLinuxResourcesCPUShares(uint64(resources.GetCpuShares())) g.SetLinuxResourcesMemoryLimit(resources.GetMemoryLimitInBytes()) - g.SetProcessOOMScoreAdj(int(resources.GetOomScoreAdj())) g.SetLinuxResourcesCPUCpus(resources.GetCpusetCpus()) 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. func getOCICapabilitiesList() []string { var caps []string diff --git a/vendor/github.com/containerd/cri/pkg/server/helpers.go b/vendor/github.com/containerd/cri/pkg/server/helpers.go index da46b6705b52..5283a3de208a 100644 --- a/vendor/github.com/containerd/cri/pkg/server/helpers.go +++ b/vendor/github.com/containerd/cri/pkg/server/helpers.go @@ -18,6 +18,7 @@ package server import ( "fmt" + "io/ioutil" "os" "path" "path/filepath" @@ -143,9 +144,9 @@ const ( // generated is unique as long as sandbox metadata is unique. func makeSandboxName(s *runtime.PodSandboxMetadata) string { return strings.Join([]string{ - s.Name, // 0 - s.Namespace, // 1 - s.Uid, // 2 + s.Name, // 0 + s.Namespace, // 1 + s.Uid, // 2 fmt.Sprintf("%d", s.Attempt), // 3 }, nameDelimiter) } @@ -155,10 +156,10 @@ func makeSandboxName(s *runtime.PodSandboxMetadata) string { // unique. func makeContainerName(c *runtime.ContainerMetadata, s *runtime.PodSandboxMetadata) string { return strings.Join([]string{ - c.Name, // 0 - s.Name, // 1: pod name - s.Namespace, // 2: pod namespace - s.Uid, // 3: pod uid + c.Name, // 0 + s.Name, // 1: pod name + s.Namespace, // 2: pod namespace + s.Uid, // 3: pod uid fmt.Sprintf("%d", c.Attempt), // 4 }, nameDelimiter) } @@ -603,3 +604,27 @@ func getTaskStatus(ctx context.Context, task containerd.Task) (containerd.Status } 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 +} diff --git a/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go b/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go index 7cbd8f192e5f..79041928c476 100644 --- a/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go +++ b/vendor/github.com/containerd/cri/pkg/server/sandbox_run.go @@ -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. // Set cgroups parent. - if config.GetLinux().GetCgroupParent() != "" { - cgroupsPath := getCgroupsPath(config.GetLinux().GetCgroupParent(), id, - c.config.SystemdCgroup) - g.SetLinuxCgroupsPath(cgroupsPath) + if c.config.DisableCgroup { + g.SetLinuxCgroupsPath("") + } else { + 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 // 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 - g.SetLinuxResourcesCPUShares(uint64(defaultSandboxCPUshares)) - g.SetProcessOOMScoreAdj(int(defaultSandboxOOMAdj)) + if !c.config.DisableCgroup { + 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.SandboxID, id) diff --git a/vendor/github.com/containerd/cri/pkg/server/service.go b/vendor/github.com/containerd/cri/pkg/server/service.go index ce648ae52b62..d041d30ddcf6 100644 --- a/vendor/github.com/containerd/cri/pkg/server/service.go +++ b/vendor/github.com/containerd/cri/pkg/server/service.go @@ -28,6 +28,7 @@ import ( cni "github.com/containerd/go-cni" runcapparmor "github.com/opencontainers/runc/libcontainer/apparmor" runcseccomp "github.com/opencontainers/runc/libcontainer/seccomp" + runcsystem "github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/selinux/go-selinux" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -108,7 +109,7 @@ func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIServi c := &criService{ config: config, client: client, - apparmorEnabled: runcapparmor.IsEnabled(), + apparmorEnabled: runcapparmor.IsEnabled() && !config.DisableApparmor, seccompEnabled: runcseccomp.IsEnabled(), os: osinterface.RealOS{}, sandboxStore: sandboxstore.NewStore(), @@ -120,6 +121,12 @@ func NewCRIService(config criconfig.Config, client *containerd.Client) (CRIServi 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 !selinux.GetEnabled() { logrus.Warn("Selinux is not supported") diff --git a/vendor/github.com/docker/distribution/registry/api/errcode/errors.go b/vendor/github.com/docker/distribution/registry/api/errcode/errors.go new file mode 100644 index 000000000000..4c35b879afd8 --- /dev/null +++ b/vendor/github.com/docker/distribution/registry/api/errcode/errors.go @@ -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 "" + 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 +} diff --git a/vendor/github.com/docker/distribution/registry/api/errcode/handler.go b/vendor/github.com/docker/distribution/registry/api/errcode/handler.go new file mode 100644 index 000000000000..d77e70473e7b --- /dev/null +++ b/vendor/github.com/docker/distribution/registry/api/errcode/handler.go @@ -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) +} diff --git a/vendor/github.com/docker/distribution/registry/api/errcode/register.go b/vendor/github.com/docker/distribution/registry/api/errcode/register.go new file mode 100644 index 000000000000..d1e8826c6d7d --- /dev/null +++ b/vendor/github.com/docker/distribution/registry/api/errcode/register.go @@ -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 +} diff --git a/vendor/github.com/docker/docker/.DEREK.yml b/vendor/github.com/docker/docker/.DEREK.yml index 3fd678917349..ca16bfab3ba7 100644 --- a/vendor/github.com/docker/docker/.DEREK.yml +++ b/vendor/github.com/docker/docker/.DEREK.yml @@ -7,7 +7,9 @@ curators: - ehazlett - fntlnz - gianarb + - kolyshkin - mgoelzer + - olljanat - programmerq - rheinwein - ripcurld0 @@ -15,3 +17,5 @@ curators: features: - comments + - pr_description_required + diff --git a/vendor/github.com/docker/docker/.mailmap b/vendor/github.com/docker/docker/.mailmap index 8b62c78d9a82..4e349e566e57 100644 --- a/vendor/github.com/docker/docker/.mailmap +++ b/vendor/github.com/docker/docker/.mailmap @@ -35,6 +35,8 @@ Allen Sun Allen Sun Andrew Weiss Andrew Weiss +Andrey Kolomentsev +Andrey Kolomentsev André Martins Andy Rothfusz Andy Smith @@ -55,9 +57,11 @@ Ben Bonnefoy Ben Golub Ben Toews Benoit Chesneau +Bevisy Zhang Bhiraj Butala Bhumika Bayani Bilal Amarni +Bily Zhang Bill Wang Bin Liu Bin Liu @@ -77,6 +81,7 @@ Chen Chuanliang Chen Mingjie Chen Qiu Chen Qiu <21321229@zju.edu.cn> +Chengfei Shang Chris Dias Chris McKinnel Christopher Biscardi @@ -97,6 +102,7 @@ Daniel Garcia Daniel Gasienica Daniel Goosen Daniel Grunwell +Daniel Hiltgen Daniel J Walsh Daniel Mizyrycki Daniel Mizyrycki @@ -104,6 +110,7 @@ Daniel Mizyrycki Daniel Norberg Daniel Watkins +Daniel Zhang Danny Yates Darren Shepherd Dattatraya Kumbhar @@ -149,6 +156,7 @@ Frederick F. Kautz IV Gabriel Nicolas Avellaneda Gaetan de Villele Gang Qiao <1373319223@qq.com> +Geon Kim George Kontridze Gerwim Feiken Giampaolo Mancini @@ -175,6 +183,7 @@ Harry Zhang Harry Zhang Harshal Patil Helen Xie +Hiroyuki Sasagawa Hollie Teal Hollie Teal Hollie Teal @@ -183,26 +192,32 @@ Huu Nguyen Hyzhou Zhy Hyzhou Zhy <1187766782@qq.com> Ilya Khlopotov +Iskander Sharipov Ivan Markin Jack Laxson Jacob Atzen Jacob Tomlinson Jaivish Kothari Jamie Hannaford +Jean Rouge Jean-Baptiste Barth Jean-Baptiste Dalido Jean-Tiare Le Bigot Jeff Anderson Jeff Nickoloff Jeroen Franse -Jessica Frazelle -Jessica Frazelle -Jessica Frazelle -Jessica Frazelle -Jessica Frazelle -Jessica Frazelle -Jessica Frazelle -Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jessica Frazelle +Jian Liao +Jiang Jinyang +Jiang Jinyang Jim Galasyn Jiuyue Ma Joey Geiger @@ -223,7 +238,9 @@ Jon Surrell Jordan Arentsen Jordan Jennings Jorit Kleine-Möllhoff -Jose Diaz-Gonzalez +Jose Diaz-Gonzalez +Jose Diaz-Gonzalez +Jose Diaz-Gonzalez Josh Bonczkowski Josh Eveleth Josh Hawn @@ -237,6 +254,7 @@ Justin Cormack Justin Cormack Justin Cormack Justin Simonelis +Justin Terry Jérôme Petazzoni Jérôme Petazzoni Jérôme Petazzoni @@ -245,8 +263,11 @@ Kai Qiang Wu (Kennan) Kai Qiang Wu (Kennan) Kamil Domański Kamjar Gerami +Karthik Nayak +Karthik Nayak Ken Cochrane Ken Herner +Ken Reese Kenfe-Mickaël Laventure Kevin Feyrer Kevin Kern @@ -260,6 +281,7 @@ Konstantin Pelykh Kotaro Yoshimatsu Kunal Kushwaha Lajos Papp +Lei Gong Lei Jitang Lei Jitang Liang Mingqiang @@ -268,7 +290,8 @@ Liao Qingwei Linus Heckemann Linus Heckemann Lokesh Mandvekar -Lorenzo Fontana +Lorenzo Fontana +Lorenzo Fontana Louis Opter Louis Opter Luca Favatella @@ -315,6 +338,8 @@ Michael Nussbaum Michael Nussbaum Michael Spetsiotis Michal Minář +Michiel de Jong +Mickaël Fortunato Miguel Angel Alvarez Cabrerizo <30386061+doncicuto@users.noreply.github.com> Miguel Angel Fernández Mihai Borobocea @@ -327,6 +352,7 @@ Moorthy RS Moysés Borges Moysés Borges Nace Oroz +Natasha Jarus Nathan LeClaire Nathan LeClaire Neil Horman @@ -338,6 +364,9 @@ Nolan Darilek O.S. Tezer O.S. Tezer Oh Jinkyun +Oliver Reason +Olli Janatuinen +Olli Janatuinen Ouyang Liduo Patrick Stapleton Paul Liljenberg @@ -359,7 +388,10 @@ Robert Terhaar Roberto G. Hashioka Roberto Muñoz Fernández Roman Dudin +Rong Zhang +Rongxiang Song Ross Boucher +Rui Cao Runshen Zhu Ryan Stelly Sakeven Jiang @@ -432,6 +464,7 @@ Tõnis Tiigi Trishna Guha Tristan Carel Tristan Carel +Tyler Brown Umesh Yadav Umesh Yadav Victor Lyuboslavsky @@ -464,8 +497,11 @@ Wei Wu cizixs Wenjun Tang Wewang Xiaorenfine Will Weaver +Xian Chaobo +Xian Chaobo Xianglin Gao Xianlu Bird +Xiaodong Zhang Xiaoyu Zhang Xuecong Liao Yamasaki Masahide @@ -477,15 +513,18 @@ Yi EungJun Ying Li Ying Li Yong Tang +Yongxin Li Yosef Fertel Yu Changchun Yu Chengxia Yu Peng Yu Peng +Yue Zhang Zachary Jaffee Zachary Jaffee ZhangHang Zhenkun Bi +Zhoulin Xie Zhou Hao Zhu Kunjia Zou Yu diff --git a/vendor/github.com/docker/docker/AUTHORS b/vendor/github.com/docker/docker/AUTHORS index 46102d7402cc..851e81014b21 100644 --- a/vendor/github.com/docker/docker/AUTHORS +++ b/vendor/github.com/docker/docker/AUTHORS @@ -118,6 +118,7 @@ Andreas Köhler Andreas Savvides Andreas Tiefenthaler Andrei Gherzan +Andrei Vagin Andrew C. Bodine Andrew Clay Shafer Andrew Duckworth @@ -137,6 +138,7 @@ Andrew Po Andrew Weiss Andrew Williams Andrews Medina +Andrey Kolomentsev Andrey Petrov Andrey Stolbovsky André Martins @@ -195,23 +197,27 @@ bdevloed Ben Bonnefoy Ben Firshman Ben Golub +Ben Gould Ben Hall Ben Sargent Ben Severson Ben Toews Ben Wiklund Benjamin Atkin +Benjamin Baker Benjamin Boudreau Benjamin Yolken Benoit Chesneau Bernerd Schaefer Bernhard M. Wiedemann Bert Goethals +Bevisy Zhang Bharath Thiruveedula Bhiraj Butala Bhumika Bayani Bilal Amarni Bill Wang +Bily Zhang Bin Liu Bingshen Wang Blake Geno @@ -246,6 +252,7 @@ Brian Torres-Gil Brian Trump Brice Jaglin Briehan Lombaard +Brielle Broder Bruno Bigras Bruno Binet Bruno Gazzera @@ -300,6 +307,7 @@ Chen Min Chen Mingjie Chen Qiu Cheng-mean Liu +Chengfei Shang Chengguang Xu chenyuzhu Chetan Birajdar @@ -325,9 +333,11 @@ Chris Swan Chris Telfer Chris Wahl Chris Weyl +Chris White Christian Berendt Christian Brauner Christian Böhme +Christian Muehlhaeuser Christian Persson Christian Rotzoll Christian Simon @@ -350,6 +360,7 @@ Cody Roseborough Coenraad Loubser Colin Dunklau Colin Hebert +Colin Panisset Colin Rice Colin Walters Collin Guarino @@ -385,6 +396,7 @@ Dan Levy Dan McPherson Dan Stine Dan Williams +Dani Hodovic Dani Louca Daniel Antlinger Daniel Dao @@ -438,12 +450,14 @@ David Mackey David Mat David Mcanulty David McKay +David P Hilton David Pelaez David R. Jenni David Röthlisberger David Sheets David Sissitka David Trott +David Wang <00107082@163.com> David Williamson David Xia David Young @@ -451,8 +465,10 @@ Davide Ceretti Dawn Chen dbdd dcylabs +Debayan De Deborah Gertrude Digges deed02392 +Deep Debroy Deng Guangxing Deni Bertovic Denis Defreyne @@ -477,6 +493,7 @@ Dieter Reuter Dillon Dixon Dima Stopel Dimitri John Ledkov +Dimitris Mandalidis Dimitris Rozakis Dimitry Andric Dinesh Subhraveti @@ -503,6 +520,7 @@ Don Kjer Don Spaulding Donald Huang Dong Chen +Donghwa Kim Donovan Jones Doron Podoleanu Doug Davis @@ -579,7 +597,9 @@ Ewa Czechowska Eystein Måløy Stenberg ezbercih Ezra Silvera +Fabian Kramm Fabian Lauer +Fabian Raetz Fabiano Rosas Fabio Falci Fabio Kung @@ -591,6 +611,7 @@ Faiz Khan falmp Fangming Fang Fangyuan Gao <21551127@zju.edu.cn> +fanjiyun Fareed Dudhia Fathi Boudra Federico Gimenez @@ -621,6 +642,7 @@ Florin Patan fonglh Foysal Iqbal Francesc Campoy +Francesco Mari Francis Chuang Francisco Carriedo Francisco Souza @@ -653,6 +675,7 @@ Gaël PORTAY Genki Takiuchi GennadySpb Geoffrey Bachelet +Geon Kim George Kontridze George MacRorie George Xie @@ -676,6 +699,7 @@ Gopikannan Venugopalsamy Gosuke Miyashita Gou Rao Govinda Fichtner +Grant Millar Grant Reaber Graydon Hoare Greg Fausak @@ -694,7 +718,9 @@ Guruprasad Gustav Sinder gwx296173 Günter Zöchbauer +haikuoliu Hakan Özler +Hamish Hutchings Hans Kristian Flaatten Hans Rødtang Hao Shu Wei @@ -702,6 +728,7 @@ Hao Zhang <21521210@zju.edu.cn> Harald Albers Harley Laue Harold Cooper +Harrison Turton Harry Zhang Harshal Patil Harshal Patil @@ -713,6 +740,7 @@ Hector Castro Helen Xie Henning Sprang Hiroshi Hatake +Hiroyuki Sasagawa Hobofan Hollie Teal Hong Xu @@ -735,6 +763,7 @@ Ian Bishop Ian Bull Ian Calvert Ian Campbell +Ian Chen Ian Lee Ian Main Ian Philpot @@ -752,9 +781,11 @@ Ilya Khlopotov imre Fitos inglesp Ingo Gottwald +Innovimax Isaac Dupree Isabel Jimenez Isao Jonas +Iskander Sharipov Ivan Babrou Ivan Fraixedes Ivan Grcic @@ -785,6 +816,7 @@ James Mills James Nesbitt James Nugent James Turnbull +James Watkins-Harvey Jamie Hannaford Jamshid Afshar Jan Keromnes @@ -817,6 +849,7 @@ jaxgeller Jay Jay Jay Kamat +Jean Rouge Jean-Baptiste Barth Jean-Baptiste Dalido Jean-Christophe Berthon @@ -847,11 +880,13 @@ Jeroen Franse Jeroen Jacobs Jesse Dearing Jesse Dubay -Jessica Frazelle +Jessica Frazelle Jezeniel Zapanta Jhon Honce Ji.Zhilong +Jian Liao Jian Zhang +Jiang Jinyang Jie Luo Jihyun Hwang Jilles Oldenbeuving @@ -862,14 +897,13 @@ Jim Perrin Jimmy Cuadra Jimmy Puckett Jimmy Song -jimmyxian Jinsoo Park +Jiri Appl Jiri Popelka Jiuyue Ma Jiří Župka -jjy -jmzwcn Joao Fernandes +Joao Trindade Joe Beda Joe Doliner Joe Ferguson @@ -908,6 +942,7 @@ Jon Johnson Jon Surrell Jon Wedaman Jonas Pfenniger +Jonathan A. Schweder Jonathan A. Sternberg Jonathan Boulle Jonathan Camp @@ -928,7 +963,7 @@ Jordan Jennings Jordan Sissel Jorge Marin Jorit Kleine-Möllhoff -Jose Diaz-Gonzalez +Jose Diaz-Gonzalez Joseph Anthony Pasquale Holsten Joseph Hager Joseph Kern @@ -982,7 +1017,8 @@ kargakis Karl Grzeszczak Karol Duleba Karthik Karanth -Karthik Nayak +Karthik Nayak +Kasper Fabæch Brandt Kate Heddleston Katie McLaughlin Kato Kazuyoshi @@ -990,6 +1026,7 @@ Katrina Owen Kawsar Saiyeed Kay Yan kayrus +Kazuhiro Sera Ke Li Ke Xu Kei Ohmura @@ -998,6 +1035,7 @@ Keli Hu Ken Cochrane Ken Herner Ken ICHIKAWA +Ken Reese Kenfe-Mickaël Laventure Kenjiro Nakayama Kent Johnson @@ -1035,9 +1073,10 @@ Krasimir Georgiev Kris-Mikael Krister Kristian Haugene Kristina Zabunova -krrg +Krystian Wojcicki Kun Zhang Kunal Kushwaha +Kunal Tyagi Kyle Conroy Kyle Linden kyu @@ -1060,6 +1099,7 @@ Leandro Siqueira Lee Chao <932819864@qq.com> Lee, Meng-Han leeplay +Lei Gong Lei Jitang Len Weincier Lennie @@ -1076,6 +1116,8 @@ Liana Lo Liang Mingqiang Liang-Chi Hsieh Liao Qingwei +Lifubang +Lihua Tang Lily Guo limsy Lin Lu @@ -1094,7 +1136,8 @@ Lloyd Dewolf Lokesh Mandvekar longliqiang88 <394564827@qq.com> Lorenz Leutgeb -Lorenzo Fontana +Lorenzo Fontana +Lotus Fenn Louis Opter Luca Favatella Luca Marturana @@ -1151,6 +1194,7 @@ Marius Gundersen Marius Sturm Marius Voila Mark Allen +Mark Jeromin Mark McGranaghan Mark McKinstry Mark Milstein @@ -1167,6 +1211,7 @@ Martijn van Oosterhout Martin Honermeyer Martin Kelly Martin Mosegaard Amdisen +Martin Muzatko Martin Redmond Mary Anthony Masahito Zembutsu @@ -1200,6 +1245,7 @@ Matthias Klumpp Matthias Kühnle Matthias Rampke Matthieu Hauglustaine +Mattias Jernberg Mauricio Garavaglia mauriyouth Max Shytikov @@ -1208,6 +1254,7 @@ Maxim Ivanov Maxim Kulkin Maxim Treskin Maxime Petazzoni +Maximiliano Maccanti Meaglith Ma meejah Megan Kostick @@ -1248,8 +1295,9 @@ Michal Wieczorek Michaël Pailloncy Michał Czeraszkiewicz Michał Gryko -Michiel@unhosted -Mickaël FORTUNATO +Michiel de Jong +Mickaël Fortunato +Mickaël Remars Miguel Angel Fernández Miguel Morales Mihai Borobocea @@ -1280,6 +1328,7 @@ Mitch Capper Mizuki Urushida mlarcher Mohammad Banikazemi +Mohammad Nasirifar Mohammed Aaqib Ansari Mohit Soni Moorthy RS @@ -1304,6 +1353,7 @@ Nan Monnand Deng Naoki Orii Natalie Parker Natanael Copa +Natasha Jarus Nate Brennand Nate Eagleson Nate Jones @@ -1337,6 +1387,7 @@ Nicolas Dudebout Nicolas Goy Nicolas Kaiser Nicolas Sterchele +Nicolas V Castet Nicolás Hock Isaza Nigel Poulton Nik Nyby @@ -1352,6 +1403,7 @@ Noah Treuhaft NobodyOnSE noducks Nolan Darilek +Noriki Nakamura nponeccop Nuutti Kotivuori nzwsch @@ -1363,8 +1415,11 @@ Ohad Schneider ohmystack Ole Reifschneider Oliver Neal +Oliver Reason Olivier Gambier Olle Jonsson +Olli Janatuinen +Omri Shiv Oriol Francès Oskar Niburski Otto Kekäläinen @@ -1420,6 +1475,7 @@ Peter Edge Peter Ericson Peter Esbensen Peter Jaffe +Peter Kang Peter Malmgren Peter Salvatore Peter Volpe @@ -1452,6 +1508,7 @@ Prasanna Gautam Pratik Karki Prayag Verma Priya Wadhwa +Projjol Banerji Przemek Hejman Pure White pysqz @@ -1475,6 +1532,7 @@ Ralph Bean Ramkumar Ramachandra Ramon Brooker Ramon van Alteren +RaviTeja Pothana Ray Tsang ReadmeCritic Recursive Madman @@ -1524,6 +1582,7 @@ Roel Van Nyen Roger Peppe Rohit Jnagal Rohit Kadam +Rohit Kapur Rojin George Roland Huß Roland Kammerer @@ -1533,6 +1592,9 @@ Roman Dudin Roman Strashkin Ron Smits Ron Williams +Rong Gao +Rong Zhang +Rongxiang Song root root root @@ -1544,8 +1606,10 @@ Rovanion Luckey Royce Remer Rozhnov Alexandr Rudolph Gottesheim +Rui Cao Rui Lopes Runshen Zhu +Russ Magee Ryan Abrams Ryan Anderson Ryan Aslett @@ -1564,6 +1628,7 @@ Ryan Wallner Ryan Zhang ryancooper7 RyanDeng +Ryo Nakao Rémy Greinhofer s. rannou s00318865 @@ -1572,6 +1637,7 @@ Sachin Joshi Sagar Hani Sainath Grandhi Sakeven Jiang +Salahuddin Khan Sally O'Malley Sam Abed Sam Alba @@ -1593,6 +1659,7 @@ Santhosh Manohar sapphiredev Sargun Dhillon Sascha Andres +Sascha Grunert Satnam Singh Satoshi Amemiya Satoshi Tagomori @@ -1619,7 +1686,9 @@ Serge Hallyn Sergey Alekseev Sergey Evstifeev Sergii Kabashniuk +Sergio Lopez Serhat Gülçiçek +SeungUkLee Sevki Hasirci Shane Canon Shane da Silva @@ -1647,6 +1716,7 @@ Sidhartha Mani sidharthamani Silas Sewell Silvan Jegen +Simão Reis Simei He Simon Eskildsen Simon Ferquel @@ -1714,10 +1784,11 @@ tang0th Tangi Colin Tatsuki Sugiura Tatsushi Inagaki +Taylan Isikdemir Taylor Jones -tbonza Ted M. Young Tehmasp Chaudhri +Tejaswini Duggaraju Tejesh Mehta terryding77 <550147740@qq.com> tgic @@ -1811,6 +1882,7 @@ Tristan Carel Troy Denton Tycho Andersen Tyler Brock +Tyler Brown Tzu-Jung Lee uhayate Ulysse Carion @@ -1871,6 +1943,7 @@ Wassim Dhif Wayne Chang Wayne Song Weerasak Chongnguluam +Wei Fu Wei Wu Wei-Ting Kuo weipeng @@ -1900,17 +1973,23 @@ WiseTrem Wolfgang Powisch Wonjun Kim xamyzhao +Xian Chaobo Xianglin Gao Xianlu Bird XiaoBing Jiang +Xiaodong Zhang +Xiaoxi He Xiaoxu Chen Xiaoyu Zhang +xichengliudui <1693291525@qq.com> xiekeyang +Ximo Guanter Gonzálbez Xinbo Weng Xinzi Zhou Xiuming Chen Xuecong Liao xuzhaokui +Yadnyawalkya Tale Yahya YAMADA Tsuyoshi Yamasaki Masahide @@ -1930,6 +2009,7 @@ Yihang Ho Ying Li Yohei Ueda Yong Tang +Yongxin Li Yongzhi Pan Yosef Fertel You-Sheng Yang (楊有勝) @@ -1940,9 +2020,12 @@ Yu Peng Yu-Ju Hong Yuan Sun Yuanhong Peng +Yue Zhang Yuhao Fang +Yuichiro Kaneko Yunxiang Huang Yurii Rashkovskii +Yusuf Tarık Günaydın Yves Junqueira Zac Dover Zach Borboa @@ -1959,8 +2042,10 @@ ZhangHang zhangxianwei Zhenan Ye <21551168@zju.edu.cn> zhenghenghuo +Zhenhai Gao Zhenkun Bi Zhou Hao +Zhoulin Xie Zhu Guihua Zhu Kunjia Zhuoyun Wei diff --git a/vendor/github.com/docker/docker/CHANGELOG.md b/vendor/github.com/docker/docker/CHANGELOG.md index fec9269b79af..83fb9f4f090b 100644 --- a/vendor/github.com/docker/docker/CHANGELOG.md +++ b/vendor/github.com/docker/docker/CHANGELOG.md @@ -99,7 +99,7 @@ be found. * 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 `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) - 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) diff --git a/vendor/github.com/docker/docker/CONTRIBUTING.md b/vendor/github.com/docker/docker/CONTRIBUTING.md index c45ae3376bb7..daefdadaed77 100644 --- a/vendor/github.com/docker/docker/CONTRIBUTING.md +++ b/vendor/github.com/docker/docker/CONTRIBUTING.md @@ -8,7 +8,7 @@ process](docs/contributing/). This page contains information about reporting issues as well as some tips and 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. ## Topics @@ -17,7 +17,7 @@ start participating. * [Design and Cleanup Proposals](#design-and-cleanup-proposals) * [Reporting Issues](#reporting-other-issues) * [Quick Contribution Tips and Guidelines](#quick-contribution-tips-and-guidelines) -* [Community Guidelines](#docker-community-guidelines) +* [Community Guidelines](#moby-community-guidelines) ## Reporting security issues diff --git a/vendor/github.com/docker/docker/Dockerfile b/vendor/github.com/docker/docker/Dockerfile index 38ca482a5a1b..62318bc9d0e3 100644 --- a/vendor/github.com/docker/docker/Dockerfile +++ b/vendor/github.com/docker/docker/Dockerfile @@ -24,18 +24,15 @@ # the case. Therefore, you don't have to disable it anymore. # -FROM golang:1.10.3 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 +FROM golang:1.12.1 AS base # allow replacing httpredir or deb mirror ARG APT_MIRROR=deb.debian.org RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list FROM base AS criu # Install CRIU for checkpoint/restore support -ENV CRIU_VERSION 3.6 -# Install dependancy packages specific to criu +ENV CRIU_VERSION 3.11 +# Install dependency packages specific to criu RUN apt-get update && apt-get install -y \ libnet-dev \ libprotobuf-c0-dev \ @@ -52,11 +49,6 @@ RUN apt-get update && apt-get install -y \ && make PREFIX=/build/ install-criu 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 RUN set -x \ && export GOPATH="$(mktemp -d)" \ @@ -64,20 +56,13 @@ RUN set -x \ && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \ && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \ 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" FROM base AS docker-py # 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 \ && cd /build \ && git checkout -q $DOCKER_PY_COMMIT @@ -118,58 +103,65 @@ FROM base AS tomlv ENV INSTALL_BINARY_NAME=tomlv 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 FROM base AS vndr ENV INSTALL_BINARY_NAME=vndr 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 FROM base AS containerd RUN apt-get update && apt-get install -y btrfs-tools ENV INSTALL_BINARY_NAME=containerd 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 FROM base AS proxy ENV INSTALL_BINARY_NAME=proxy 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 FROM base AS gometalinter ENV INSTALL_BINARY_NAME=gometalinter 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 FROM base AS dockercli ENV INSTALL_BINARY_NAME=dockercli 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 FROM runtime-dev AS runc ENV INSTALL_BINARY_NAME=runc 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 FROM base AS tini RUN apt-get update && apt-get install -y cmake vim-common COPY hack/dockerfile/install/install.sh ./install.sh ENV INSTALL_BINARY_NAME=tini 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 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 +COPY ./contrib/dockerd-rootless.sh /build # TODO: Some of this is only really needed for testing, it would be nice to split this up FROM runtime-dev AS dev RUN groupadd -r docker 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 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 @@ -183,7 +175,11 @@ RUN apt-get update && apt-get install -y \ btrfs-tools \ iptables \ jq \ + libcap2-bin \ libdevmapper-dev \ +# libffi-dev and libssl-dev appear to be required for compiling paramiko on s390x/ppc64le + libffi-dev \ + libssl-dev \ libudev-dev \ libsystemd-dev \ binutils-mingw-w64 \ @@ -192,6 +188,8 @@ RUN apt-get update && apt-get install -y \ pigz \ python-backports.ssl-match-hostname \ python-dev \ +# python-cffi appears to be required for compiling paramiko on s390x/ppc64le + python-cffi \ python-mock \ python-pip \ python-requests \ @@ -205,6 +203,9 @@ RUN apt-get update && apt-get install -y \ zip \ bzip2 \ xz-utils \ + libprotobuf-c1 \ + libnet1 \ + libnl-3-200 \ --no-install-recommends COPY --from=swagger /build/swagger* /usr/local/bin/ 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 # above. 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 -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 DOCKER_BUILDTAGS apparmor seccomp selinux @@ -236,5 +240,7 @@ WORKDIR /go/src/github.com/docker/docker VOLUME /var/lib/docker # Wrap all commands in the "docker-in-docker" script to allow nested containers ENTRYPOINT ["hack/dind"] + +FROM dev AS final # Upload docker source COPY . /go/src/github.com/docker/docker diff --git a/vendor/github.com/docker/docker/Dockerfile.e2e b/vendor/github.com/docker/docker/Dockerfile.e2e index 663a58af3307..0dab94375b78 100644 --- a/vendor/github.com/docker/docker/Dockerfile.e2e +++ b/vendor/github.com/docker/docker/Dockerfile.e2e @@ -1,14 +1,13 @@ ## 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 \ btrfs-progs-dev \ build-base \ curl \ lvm2-dev \ - jq \ - && rm -rf /var/cache/apk/* + jq RUN mkdir -p /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 \; ## 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 -RUN apk add --update \ +RUN apk --no-cache add \ bash \ ca-certificates \ g++ \ @@ -51,8 +50,7 @@ RUN apk add --update \ iptables \ pigz \ tar \ - xz \ - && rm -rf /var/cache/apk/* + xz # Add an unprivileged user to be used for tests which need it RUN addgroup docker && adduser -D -G docker unprivilegeduser -s /bin/ash diff --git a/vendor/github.com/docker/docker/Dockerfile.simple b/vendor/github.com/docker/docker/Dockerfile.simple index b0338ac0c872..51aba50af309 100644 --- a/vendor/github.com/docker/docker/Dockerfile.simple +++ b/vendor/github.com/docker/docker/Dockerfile.simple @@ -5,7 +5,7 @@ # 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 ARG APT_MIRROR=deb.debian.org @@ -37,18 +37,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ vim-common \ && 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 # Please edit hack/dockerfile/install/.installer to update them. COPY hack/dockerfile/install hack/dockerfile/install diff --git a/vendor/github.com/docker/docker/Dockerfile.windows b/vendor/github.com/docker/docker/Dockerfile.windows index 1b2c1f3c8ae0..0f1c4047baf5 100644 --- a/vendor/github.com/docker/docker/Dockerfile.windows +++ b/vendor/github.com/docker/docker/Dockerfile.windows @@ -153,6 +153,13 @@ # 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 # Use PowerShell as the default shell @@ -161,7 +168,7 @@ SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPref # Environment variable notes: # - GO_VERSION must be consistent with 'Dockerfile' used by Linux. # - 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 ` GOPATH=C:\go ` FROM_DOCKERFILE=1 diff --git a/vendor/github.com/docker/docker/Jenkinsfile b/vendor/github.com/docker/docker/Jenkinsfile new file mode 100644 index 000000000000..35eee3806c78 --- /dev/null +++ b/vendor/github.com/docker/docker/Jenkinsfile @@ -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 + ''' + } + } + } + } + } + } +} \ No newline at end of file diff --git a/vendor/github.com/docker/docker/LICENSE b/vendor/github.com/docker/docker/LICENSE index 9c8e20ab85c1..6d8d58fb676b 100644 --- a/vendor/github.com/docker/docker/LICENSE +++ b/vendor/github.com/docker/docker/LICENSE @@ -176,7 +176,7 @@ 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"); you may not use this file except in compliance with the License. diff --git a/vendor/github.com/docker/docker/MAINTAINERS b/vendor/github.com/docker/docker/MAINTAINERS index 3ac06d2728e1..9f8b9e4f7a15 100644 --- a/vendor/github.com/docker/docker/MAINTAINERS +++ b/vendor/github.com/docker/docker/MAINTAINERS @@ -36,6 +36,7 @@ "jhowardmsft", "johnstep", "justincormack", + "kolyshkin", "mhbauer", "mlaventure", "runcom", @@ -50,15 +51,6 @@ "yongtang" ] - [Org."Docs maintainers"] - - # TODO Describe the docs maintainers role. - - people = [ - "misty", - "thajeztah" - ] - [Org.Curators] # The curators help ensure that incoming issues and pull requests are properly triaged and @@ -78,6 +70,7 @@ "chanwit", "fntlnz", "gianarb", + "olljanat", "programmerq", "rheinwein", "ripcurld", @@ -162,7 +155,7 @@ # 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 - # 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 # of action with a single "Nope, we're not gonna do that". "lk4d4", @@ -365,6 +358,11 @@ Email = "justin.cormack@docker.com" GitHub = "justincormack" + [people.kolyshkin] + Name = "Kir Kolyshkin" + Email = "kolyshkin@gmail.com" + GitHub = "kolyshkin" + [people.lk4d4] Name = "Alexander Morozov" Email = "lk4d4@docker.com" @@ -380,11 +378,6 @@ Email = "mbauer@us.ibm.com" GitHub = "mhbauer" - [people.misty] - Name = "Misty Stanley-Jones" - Email = "misty@docker.com" - GitHub = "mistyhacks" - [people.mlaventure] Name = "Kenfe-Mickaël Laventure" Email = "mickael.laventure@gmail.com" @@ -400,6 +393,11 @@ Email = "mrjana@docker.com" GitHub = "mrjana" + [people.olljanat] + Name = "Olli Janatuinen" + Email = "olli.janatuinen@gmail.com" + GitHub = "olljanat" + [people.programmerq] Name = "Jeff Anderson" Email = "jeff@docker.com" diff --git a/vendor/github.com/docker/docker/Makefile b/vendor/github.com/docker/docker/Makefile index ebca5b1b027f..8a62a032cb6a 100644 --- a/vendor/github.com/docker/docker/Makefile +++ b/vendor/github.com/docker/docker/Makefile @@ -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 DOCKER_GRAPHDRIVER := $(if $(DOCKER_GRAPHDRIVER),$(DOCKER_GRAPHDRIVER),$(shell docker info 2>&1 | grep "Storage Driver" | sed 's/.*: //')) export DOCKER_GRAPHDRIVER -DOCKER_INCREMENTAL_BINARY := $(if $(DOCKER_INCREMENTAL_BINARY),$(DOCKER_INCREMENTAL_BINARY),1) -export DOCKER_INCREMENTAL_BINARY # get OS/Arch of docker engine 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) 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 # to allow things like `make KEEPBUNDLE=1 binary` easily # `project/PACKAGERS.md` have some limited documentation of some of these @@ -30,14 +34,15 @@ DOCKER_ENVS := \ -e KEEPBUNDLE \ -e DOCKER_BUILD_ARGS \ -e DOCKER_BUILD_GOGC \ + -e DOCKER_BUILD_OPTS \ -e DOCKER_BUILD_PKGS \ + -e DOCKER_BUILDKIT \ -e DOCKER_BASH_COMPLETION_PATH \ -e DOCKER_CLI_PATH \ -e DOCKER_DEBUG \ -e DOCKER_EXPERIMENTAL \ -e DOCKER_GITCOMMIT \ -e DOCKER_GRAPHDRIVER \ - -e DOCKER_INCREMENTAL_BINARY \ -e DOCKER_LDFLAGS \ -e DOCKER_PORT \ -e DOCKER_REMAP_ROOT \ @@ -48,6 +53,9 @@ DOCKER_ENVS := \ -e TESTDIRS \ -e TESTFLAGS \ -e TIMEOUT \ + -e VALIDATE_REPO \ + -e VALIDATE_BRANCH \ + -e VALIDATE_ORIGIN_BRANCH \ -e HTTP_PROXY \ -e HTTPS_PROXY \ -e NO_PROXY \ @@ -55,13 +63,18 @@ DOCKER_ENVS := \ -e https_proxy \ -e no_proxy \ -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 # to allow `make BIND_DIR=. shell` or `make BIND_DIR= test` # (default to no bind mount if DOCKER_HOST is set) # note: BINDDIR is supported for backwards-compatibility here 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)") # 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. 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_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_CACHE := -v docker-dev-cache:/root/.cache 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 := $(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_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) DOCKER_FLAGS += -t endif +ifeq ($(BIND_DIR), .) + DOCKER_BUILD_OPTS += --target=dev +endif DOCKER_RUN_DOCKER := $(DOCKER_FLAGS) "$(DOCKER_IMAGE)" @@ -121,28 +134,26 @@ binary: build ## build the linux binaries dynbinary: build ## build the linux dynbinaries $(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}) - 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: mkdir bundles -clean: clean-pkg-cache-vol ## clean up cached resources +.PHONY: clean +clean: clean-cache -clean-pkg-cache-vol: - @- $(foreach mapping,$(PKGCACHE_MAP), \ - $(shell docker volume rm $(PKGCACHE_VOLROOT)-$(shell echo $(mapping) | awk -F':/' '{ print $$1 }') > /dev/null 2>&1) \ - ) +.PHONY: clean-cache +clean-cache: + docker volume rm -f docker-dev-cache cross: build ## cross build the binaries for darwin, freebsd and\nwindows $(DOCKER_RUN_DOCKER) hack/make.sh dynbinary binary cross 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) - -init-go-pkg-cache: - $(if $(PKGCACHE_DIR), mkdir -p $(shell echo $(PKGCACHE_MAP) | sed -E 's@([^: ]*):[^ ]*@$(PKGCACHE_DIR)/\1@g')) + @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) install: ## install the linux binaries 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 $(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 $(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 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 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 @echo "Building $(INTEGRATION_CLI_MASTER_IMAGE)" 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)" $(eval tmp := integration-cli-worker-tmp) # 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 - 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) 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) diff --git a/vendor/github.com/docker/docker/ROADMAP.md b/vendor/github.com/docker/docker/ROADMAP.md index e2e6b2b960f8..775d0734ec93 100644 --- a/vendor/github.com/docker/docker/ROADMAP.md +++ b/vendor/github.com/docker/docker/ROADMAP.md @@ -35,34 +35,83 @@ issue, in the Slack channel, or in person at the Moby Summits that happen every ## 1.1 Runtime improvements -We introduced [`runC`](https://runc.io) as a standalone low-level tool for container -execution in 2015, the first stage in spinning out parts of the Engine into standalone tools. +Over time we have accumulated a lot of functionality in the container runtime +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 -[`containerd`](https://github.com/containerd/containerd), a daemon to control and monitor `runC`. -In late 2016 this was relaunched as the `containerd` 1.0 track, aiming to provide a common runtime -for the whole spectrum of container systems, including Kubernetes, with wide community support. -This change meant that there was an increased scope for `containerd`, including image management -and storage drivers. +Moby currently only utilizes containerd for basic runtime state management, e.g. starting +and stopping a container, which is what the pre-containerd 1.0 daemon provided. +Now that containerd is a full-fledged container runtime which supports full +container life-cycle management, we would like to start relying more on containerd +and removing the bits in Moby which are now duplicated. This will necessitate +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 -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. +Tracking issues: -## 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 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 the next standalone component. - We see gRPC as the natural communication layer between decoupled components. -## 1.3 Custom assembly tooling - -We have been prototyping the Moby [assembly tool](https://github.com/moby/tool) which was originally -developed for LinuxKit and intend to turn it into a more generic packaging and assembly mechanism -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. +In addition to pushing out large components into other projects, much of the +internal code structure, and in particular the +["Daemon"](https://godoc.org/github.com/docker/docker/daemon#Daemon) object, +should be split into smaller, more manageable, and more testable components. diff --git a/vendor/github.com/docker/docker/TESTING.md b/vendor/github.com/docker/docker/TESTING.md index 1231e1c5f4d9..b2c53769ca05 100644 --- a/vendor/github.com/docker/docker/TESTING.md +++ b/vendor/github.com/docker/docker/TESTING.md @@ -8,11 +8,11 @@ questions you may have as an aspiring Moby contributor. Moby has two test suites (and one legacy test suite): * 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 package. * 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/` directories, where `component` is: container, image, volume, etc. These tests perform HTTP requests to an API endpoint and 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 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 To run the unit test suite: diff --git a/vendor/github.com/docker/docker/api/common.go b/vendor/github.com/docker/docker/api/common.go index 255a81aedd6e..aa146cdaeb1a 100644 --- a/vendor/github.com/docker/docker/api/common.go +++ b/vendor/github.com/docker/docker/api/common.go @@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api" // Common constants for daemon and client. const ( // DefaultVersion of Current REST API - DefaultVersion = "1.38" + DefaultVersion = "1.40" // NoBaseImageSpecifier is the symbol used by the FROM // command to specify that no base image is to be used. diff --git a/vendor/github.com/docker/docker/api/swagger.yaml b/vendor/github.com/docker/docker/api/swagger.yaml index 86374415fd58..78c576cef25e 100644 --- a/vendor/github.com/docker/docker/api/swagger.yaml +++ b/vendor/github.com/docker/docker/api/swagger.yaml @@ -19,10 +19,10 @@ produces: consumes: - "application/json" - "text/plain" -basePath: "/v1.38" +basePath: "/v1.40" info: title: "Docker Engine API" - version: "1.38" + version: "1.40" x-logo: url: "https://docs.docker.com/images/logo-docker-main.png" description: | @@ -49,8 +49,8 @@ info: the URL is not supported by the daemon, a HTTP `400 Bad Request` error message is returned. - If you omit the version-prefix, the current version of the API (v1.38) is used. - For example, calling `/info` is the same as calling `/v1.38/info`. Using the + 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.40/info`. Using the 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, @@ -210,6 +210,43 @@ definitions: PathInContainer: "/dev/deviceName" 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: type: "object" 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. - `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. + - `npipe` Mounts a named pipe from the host into the container. Must exist prior to creating the container. type: "string" enum: - "bind" - "volume" - "tmpfs" + - "npipe" ReadOnly: description: "Whether the mount should be read-only." type: "boolean" @@ -263,6 +302,10 @@ definitions: - "rshared" - "slave" - "rslave" + NonRecursive: + description: "Disable recursive bind mount." + type: "boolean" + default: false VolumeOptions: description: "Optional configuration for the `volume` type." type: "object" @@ -415,6 +458,11 @@ definitions: items: type: "string" 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: description: "Disk limit (in bytes)." type: "integer" @@ -423,6 +471,11 @@ definitions: description: "Kernel memory limit in bytes." type: "integer" format: "int64" + example: 209715200 + KernelMemoryTCP: + description: "Hard limit for kernel TCP buffer memory (in bytes)." + type: "integer" + format: "int64" MemoryReservation: description: "Memory soft limit in bytes." type: "integer" @@ -449,9 +502,11 @@ definitions: type: "boolean" x-nullable: true 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" format: "int64" + x-nullable: true Ulimits: description: | 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" # 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: 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: type: "string" CapDrop: 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: type: "string" Dns: @@ -1473,11 +1536,9 @@ definitions: type: "string" Options: description: "Driver-specific options, specified as a map." - type: "array" - items: - type: "object" - additionalProperties: - type: "string" + type: "object" + additionalProperties: + type: "string" NetworkContainer: type: "object" @@ -1513,6 +1574,31 @@ definitions: aux: $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: type: "object" description: "Image ID or Digest" @@ -2434,6 +2520,31 @@ definitions: description: "Whether there is currently a root CA rotation in progress for the swarm" type: "boolean" 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: description: | @@ -2556,8 +2667,20 @@ definitions: type: "object" description: "CredentialSpec for managed service account (Windows only)" 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. + +


+ + + > **Note**: `CredentialSpec.File`, `CredentialSpec.Registry`, and `CredentialSpec.Config` are mutually exclusive. File: type: "string" + example: "spec.json" description: | 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 @@ -2567,7 +2690,7 @@ definitions:


- > **Note**: `CredentialSpec.File` and `CredentialSpec.Registry` are mutually exclusive. + > **Note**: `CredentialSpec.File`, `CredentialSpec.Registry`, and `CredentialSpec.Config` are mutually exclusive. Registry: type: "string" description: | @@ -2579,7 +2702,7 @@ definitions:


- > **Note**: `CredentialSpec.File` and `CredentialSpec.Registry` are mutually exclusive. + > **Note**: `CredentialSpec.File`, `CredentialSpec.Registry`, and `CredentialSpec.Config` are mutually exclusive. SELinuxContext: type: "object" description: "SELinux labels of the container" @@ -2690,7 +2813,12 @@ definitions: type: "object" properties: 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. + +


+ + > **Note**: `Configs.File` and `Configs.Runtime` are mutually exclusive type: "object" properties: Name: @@ -2706,6 +2834,14 @@ definitions: description: "Mode represents the FileMode of the file." type: "integer" format: "uint32" + Runtime: + description: | + Runtime represents a target that is not mounted into the container but is used by the task + +


+ + > **Note**: `Configs.File` and `Configs.Runtime` are mutually exclusive + type: "object" ConfigID: description: "ConfigID represents the ID of the specific config that we're referencing." 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." type: "boolean" 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: description: | Read-only spec type for non-swarm containers attached to swarm overlay @@ -2805,6 +2953,11 @@ definitions: SpreadDescriptor: "node.labels.datacenter" - Spread: 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: description: | 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) type: "boolean" example: true + PidsLimit: + description: "Indicates if the host kernel has PID limit support enabled." + type: "boolean" + example: true OomKillDisable: description: "Indicates if OOM killer disable is supported on the host." type: "boolean" @@ -3722,18 +3879,22 @@ definitions: description: | 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. + 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. type: "string" - example: "http://user:pass@proxy.corp.example.com:8080" + example: "http://xxxxx:xxxxx@proxy.corp.example.com:8080" HttpsProxy: description: | 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. + 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. type: "string" - example: "https://user:pass@proxy.corp.example.com:4443" + example: "https://xxxxx:xxxxx@proxy.corp.example.com:4443" NoProxy: description: | Comma-separated list of domain extensions for which no proxy should be @@ -3823,10 +3984,10 @@ definitions: $ref: "#/definitions/Runtime" default: runc: - path: "docker-runc" + path: "runc" example: runc: - path: "docker-runc" + path: "runc" runc-master: path: "/go/bin/runc" custom: @@ -3896,6 +4057,27 @@ definitions: - "name=seccomp,profile=default" - "name=selinux" - "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 @@ -4516,7 +4698,7 @@ paths: OomKillDisable: false OomScoreAdj: 500 PidMode: "" - PidsLimit: -1 + PidsLimit: 0 PortBindings: 22/tcp: - HostPort: "11022" @@ -5922,7 +6104,7 @@ paths: headers: X-Docker-Container-Path-Stat: type: "string" - description: "TODO" + description: "A base64 - encoded JSON object with some filesystem header information about the path" 400: description: "Bad parameter" schema: @@ -6319,6 +6501,11 @@ paths: description: "Target build stage" type: "string" default: "" + - name: "outputs" + in: "query" + description: "BuildKit output configuration" + type: "string" + default: "" responses: 200: description: "no error" @@ -6337,6 +6524,29 @@ paths: produces: - "application/json" 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 relative to daemon's time, during which build cache was not used, in Go's duration format (e.g., '24h') + - `id=` + - `parent=` + - `type=` + - `description=` + - `inuse` + - `shared` + - `private` responses: 200: description: "No error" @@ -6344,6 +6554,11 @@ paths: type: "object" title: "BuildPruneResponse" properties: + CachesDeleted: + type: "array" + items: + description: "ID of build cache object" + type: "string" SpaceReclaimed: description: "Disk space reclaimed in bytes" type: "integer" @@ -6972,9 +7187,57 @@ paths: 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: + 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: description: "server error" schema: @@ -7175,6 +7438,10 @@ paths: type: "array" items: $ref: "#/definitions/Volume" + BuildCache: + type: "array" + items: + $ref: "#/definitions/BuildCache" example: LayersSize: 1092588 Images: @@ -7589,6 +7856,7 @@ paths: schema: type: "object" title: "VolumeListResponse" + description: "Volume list response" required: [Volumes, Warnings] properties: Volumes: @@ -7665,6 +7933,8 @@ paths: description: "Volume configuration" schema: type: "object" + description: "Volume configuration" + title: "VolumeConfig" properties: Name: description: "The new volume's name. If not specified, Docker generates a name." @@ -7865,6 +8135,10 @@ paths: description: | JSON encoded value of the filters (a `map[string][]string`) to process on the networks list. Available filters: + - `dangling=` 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=` Matches a network's driver. - `id=` Matches all or part of a network ID. - `label=` or `label==` of a network label. @@ -8582,6 +8856,7 @@ paths: - `label=` - `membership=`(`accepted`|`pending`)` - `name=` + - `node.label=` - `role=`(`manager`|`worker`)` type: "string" 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 separate the container data traffic from the management traffic of the cluster. 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: description: "Force creation of a new swarm." type: "boolean" + SubnetSize: + description: | + SubnetSize specifies the subnet size of the networks created from the default subnet pool + type: "integer" + format: "uint32" Spec: $ref: "#/definitions/SwarmSpec" example: ListenAddr: "0.0.0.0:2377" AdvertiseAddr: "192.168.1.1:2377" + DataPathPort: 4789 + DefaultAddrPool: ["10.10.0.0/8", "20.20.0.0/8"] + SubnetSize: 24 ForceNewCluster: false Spec: Orchestration: {} @@ -9243,7 +9540,10 @@ paths: - name: "version" 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 type: "integer" - 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." type: "string" default: "all" + tags: ["Task"] /secrets: get: summary: "List secrets" diff --git a/vendor/github.com/docker/docker/api/types/client.go b/vendor/github.com/docker/docker/api/types/client.go index 3d2e057c9aac..4b9f50282b1f 100644 --- a/vendor/github.com/docker/docker/api/types/client.go +++ b/vendor/github.com/docker/docker/api/types/client.go @@ -7,7 +7,7 @@ import ( "github.com/docker/docker/api/types/container" "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 @@ -181,8 +181,33 @@ type ImageBuildOptions struct { Target string SessionID 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 // returned by a server after building // an image. diff --git a/vendor/github.com/docker/docker/api/types/configs.go b/vendor/github.com/docker/docker/api/types/configs.go index f6537a27f21e..178e911a7afc 100644 --- a/vendor/github.com/docker/docker/api/types/configs.go +++ b/vendor/github.com/docker/docker/api/types/configs.go @@ -55,3 +55,10 @@ type PluginEnableConfig struct { type PluginDisableConfig struct { 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 +} diff --git a/vendor/github.com/docker/docker/api/types/container/config.go b/vendor/github.com/docker/docker/api/types/container/config.go index 89ad08c23461..f767195b94b4 100644 --- a/vendor/github.com/docker/docker/api/types/container/config.go +++ b/vendor/github.com/docker/docker/api/types/container/config.go @@ -54,7 +54,7 @@ type Config struct { Env []string // List of environment variable to set in 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 - 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) Volumes map[string]struct{} // List of volumes (mounts) used for the container WorkingDir string // Current directory (PWD) in the command will be launched diff --git a/vendor/github.com/docker/docker/api/types/container/host_config.go b/vendor/github.com/docker/docker/api/types/container/host_config.go index 4ef26fa6c878..c710107702b8 100644 --- a/vendor/github.com/docker/docker/api/types/container/host_config.go +++ b/vendor/github.com/docker/docker/api/types/container/host_config.go @@ -244,6 +244,16 @@ func (n PidMode) Container() string { 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. type DeviceMapping struct { PathOnHost string @@ -327,13 +337,15 @@ type Resources struct { CpusetMems string // CpusetMems 0-2, 0,1 Devices []DeviceMapping // List of devices to map inside the container 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) 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) MemorySwap int64 // Total memory usage (memory + swap); set `-1` to enable unlimited swap MemorySwappiness *int64 // Tuning container memory swappiness behaviour 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 // Applicable to Windows @@ -369,9 +381,10 @@ type HostConfig struct { // Applicable to UNIX platforms CapAdd strslice.StrSlice // List of kernel capabilities to add to the container CapDrop strslice.StrSlice // List of kernel capabilities to remove from the container - DNS []string `json:"Dns"` // List of DNS server to lookup - DNSOptions []string `json:"DnsOptions"` // List of DNSOption to look for - DNSSearch []string `json:"DnsSearch"` // List of DNSSearch to look for + Capabilities []string `json:"Capabilities"` // List of kernel capabilities to be available for container (this overrides the default set) + DNS []string `json:"Dns"` // List of DNS server to lookup + 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 GroupAdd []string // List of additional groups that the container process will run as IpcMode IpcMode // IPC namespace to use for the container diff --git a/vendor/github.com/docker/docker/api/types/filters/parse.go b/vendor/github.com/docker/docker/api/types/filters/parse.go index a41e3d8d96ad..d8f19ae227c4 100644 --- a/vendor/github.com/docker/docker/api/types/filters/parse.go +++ b/vendor/github.com/docker/docker/api/types/filters/parse.go @@ -323,6 +323,22 @@ func (args Args) WalkValues(field string, op func(value string) error) error { 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 { m := map[string]map[string]bool{} for k, v := range d { diff --git a/vendor/github.com/docker/docker/api/types/mount/mount.go b/vendor/github.com/docker/docker/api/types/mount/mount.go index 3fef974df883..ab4446b38f6c 100644 --- a/vendor/github.com/docker/docker/api/types/mount/mount.go +++ b/vendor/github.com/docker/docker/api/types/mount/mount.go @@ -79,7 +79,8 @@ const ( // BindOptions defines options specific to mounts of type "bind". 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. diff --git a/vendor/github.com/docker/docker/api/types/network/network.go b/vendor/github.com/docker/docker/api/types/network/network.go index 761d0b34f2f1..71e97338fdc8 100644 --- a/vendor/github.com/docker/docker/api/types/network/network.go +++ b/vendor/github.com/docker/docker/api/types/network/network.go @@ -1,4 +1,8 @@ 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 type Address struct { @@ -106,3 +110,18 @@ type NetworkingConfig struct { type ConfigReference struct { 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)) +} diff --git a/vendor/github.com/docker/docker/api/types/seccomp.go b/vendor/github.com/docker/docker/api/types/seccomp.go index 67a41e1a89e8..2259c6be1e65 100644 --- a/vendor/github.com/docker/docker/api/types/seccomp.go +++ b/vendor/github.com/docker/docker/api/types/seccomp.go @@ -77,8 +77,9 @@ type Arg struct { // Filter is used to conditionally apply Seccomp rules type Filter struct { - Caps []string `json:"caps,omitempty"` - Arches []string `json:"arches,omitempty"` + Caps []string `json:"caps,omitempty"` + Arches []string `json:"arches,omitempty"` + MinKernel string `json:"minKernel,omitempty"` } // Syscall is used to match a group of syscalls in Seccomp diff --git a/vendor/github.com/docker/docker/api/types/stats.go b/vendor/github.com/docker/docker/api/types/stats.go index 60175c061360..20daebed14bd 100644 --- a/vendor/github.com/docker/docker/api/types/stats.go +++ b/vendor/github.com/docker/docker/api/types/stats.go @@ -120,7 +120,7 @@ type NetworkStats struct { RxBytes uint64 `json:"rx_bytes"` // Packets received. Windows and Linux. 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. RxErrors uint64 `json:"rx_errors"` // Incoming packets dropped. Windows and Linux. @@ -129,7 +129,7 @@ type NetworkStats struct { TxBytes uint64 `json:"tx_bytes"` // Packets sent. Windows and Linux. 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. TxErrors uint64 `json:"tx_errors"` // Outgoing packets dropped. Windows and Linux. diff --git a/vendor/github.com/docker/docker/api/types/swarm/config.go b/vendor/github.com/docker/docker/api/types/swarm/config.go index a1555cf43eee..16202ccce615 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/config.go +++ b/vendor/github.com/docker/docker/api/types/swarm/config.go @@ -27,9 +27,14 @@ type ConfigReferenceFileTarget struct { 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 type ConfigReference struct { - File *ConfigReferenceFileTarget + File *ConfigReferenceFileTarget `json:",omitempty"` + Runtime *ConfigReferenceRuntimeTarget `json:",omitempty"` ConfigID string ConfigName string } diff --git a/vendor/github.com/docker/docker/api/types/swarm/container.go b/vendor/github.com/docker/docker/api/types/swarm/container.go index 151211ff5a49..48190c1762f1 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/container.go +++ b/vendor/github.com/docker/docker/api/types/swarm/container.go @@ -33,6 +33,7 @@ type SELinuxContext struct { // CredentialSpec for managed service account (Windows only) type CredentialSpec struct { + Config string File string Registry string } @@ -71,4 +72,5 @@ type ContainerSpec struct { Secrets []*SecretReference `json:",omitempty"` Configs []*ConfigReference `json:",omitempty"` Isolation container.Isolation `json:",omitempty"` + Sysctls map[string]string `json:",omitempty"` } diff --git a/vendor/github.com/docker/docker/api/types/swarm/swarm.go b/vendor/github.com/docker/docker/api/types/swarm/swarm.go index 1b111d725b8f..b25f9996462e 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/swarm.go +++ b/vendor/github.com/docker/docker/api/types/swarm/swarm.go @@ -1,6 +1,8 @@ package swarm // import "github.com/docker/docker/api/types/swarm" -import "time" +import ( + "time" +) // ClusterInfo represents info about the cluster for outputting in "info" // it contains the same information as "Swarm", but without the JoinTokens @@ -10,6 +12,9 @@ type ClusterInfo struct { Spec Spec TLSInfo TLSInfo RootRotationInProgress bool + DefaultAddrPool []string + SubnetSize uint32 + DataPathPort uint32 } // Swarm represents a swarm. @@ -149,10 +154,13 @@ type InitRequest struct { ListenAddr string AdvertiseAddr string DataPathAddr string + DataPathPort uint32 ForceNewCluster bool Spec Spec AutoLockManagers bool Availability NodeAvailability + DefaultAddrPool []string + SubnetSize uint32 } // JoinRequest is the request used to join a swarm. @@ -201,6 +209,8 @@ type Info struct { Managers int `json:",omitempty"` Cluster *ClusterInfo `json:",omitempty"` + + Warnings []string `json:",omitempty"` } // Peer represents a peer. diff --git a/vendor/github.com/docker/docker/api/types/swarm/task.go b/vendor/github.com/docker/docker/api/types/swarm/task.go index b35605d12fd2..d5a57df5db5a 100644 --- a/vendor/github.com/docker/docker/api/types/swarm/task.go +++ b/vendor/github.com/docker/docker/api/types/swarm/task.go @@ -127,6 +127,7 @@ type ResourceRequirements struct { type Placement struct { Constraints []string `json:",omitempty"` Preferences []PlacementPreference `json:",omitempty"` + MaxReplicas uint64 `json:",omitempty"` // Platforms stores all the platforms that the image can run on. // This field is used in the platform filter for scheduling. If empty, diff --git a/vendor/github.com/docker/docker/api/types/types.go b/vendor/github.com/docker/docker/api/types/types.go index 729f4eb6c491..a39ffcb7be2d 100644 --- a/vendor/github.com/docker/docker/api/types/types.go +++ b/vendor/github.com/docker/docker/api/types/types.go @@ -102,9 +102,10 @@ type ContainerStats struct { // Ping contains response of Engine API: // GET "/_ping" type Ping struct { - APIVersion string - OSType string - Experimental bool + APIVersion string + OSType string + Experimental bool + BuilderVersion BuilderVersion } // ComponentVersion describes the version information for a specific component. @@ -157,10 +158,12 @@ type Info struct { MemoryLimit bool SwapLimit bool KernelMemory bool + KernelMemoryTCP bool CPUCfsPeriod bool `json:"CpuCfsPeriod"` CPUCfsQuota bool `json:"CpuCfsQuota"` CPUShares bool CPUSet bool + PidsLimit bool IPv4Forwarding bool BridgeNfIptables bool BridgeNfIP6tables bool `json:"BridgeNfIp6tables"` @@ -204,6 +207,8 @@ type Info struct { RuncCommit Commit InitCommit Commit SecurityOptions []string + ProductLicense string `json:",omitempty"` + Warnings []string } // KeyValue holds a key/value pair @@ -512,7 +517,8 @@ type DiskUsage struct { Images []*ImageSummary Containers []*Container Volumes []*Volume - BuilderSize int64 + BuildCache []*BuildCache + BuilderSize int64 // deprecated } // ContainersPruneReport contains the response for Engine API: @@ -539,6 +545,7 @@ type ImagesPruneReport struct { // BuildCachePruneReport contains the response for Engine API: // POST "/build/prune" type BuildCachePruneReport struct { + CachesDeleted []string SpaceReclaimed uint64 } @@ -585,3 +592,24 @@ type PushResult struct { type BuildResult struct { 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 +} diff --git a/vendor/github.com/docker/docker/api/types/volume/volume_create.go b/vendor/github.com/docker/docker/api/types/volume/volume_create.go index 539e9b97d904..f12e48612c56 100644 --- a/vendor/github.com/docker/docker/api/types/volume/volume_create.go +++ b/vendor/github.com/docker/docker/api/types/volume/volume_create.go @@ -7,7 +7,7 @@ package volume // See hack/generate-swagger-api.sh // ---------------------------------------------------------------------------- -// VolumeCreateBody +// VolumeCreateBody Volume configuration // swagger:model VolumeCreateBody type VolumeCreateBody struct { diff --git a/vendor/github.com/docker/docker/api/types/volume/volume_list.go b/vendor/github.com/docker/docker/api/types/volume/volume_list.go index 1bb279dbb3f3..020198f7371b 100644 --- a/vendor/github.com/docker/docker/api/types/volume/volume_list.go +++ b/vendor/github.com/docker/docker/api/types/volume/volume_list.go @@ -9,7 +9,7 @@ package volume import "github.com/docker/docker/api/types" -// VolumeListOKBody +// VolumeListOKBody Volume list response // swagger:model VolumeListOKBody type VolumeListOKBody struct { diff --git a/vendor/github.com/docker/docker/client/README.md b/vendor/github.com/docker/docker/client/README.md index 059dfb3ce7b9..992f18117df5 100644 --- a/vendor/github.com/docker/docker/client/README.md +++ b/vendor/github.com/docker/docker/client/README.md @@ -16,7 +16,7 @@ import ( ) func main() { - cli, err := client.NewEnvClient() + cli, err := client.NewClientWithOpts(client.FromEnv) if err != nil { panic(err) } diff --git a/vendor/github.com/docker/docker/client/build_cancel.go b/vendor/github.com/docker/docker/client/build_cancel.go new file mode 100644 index 000000000000..3aae43e3d17e --- /dev/null +++ b/vendor/github.com/docker/docker/client/build_cancel.go @@ -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 +} diff --git a/vendor/github.com/docker/docker/client/build_prune.go b/vendor/github.com/docker/docker/client/build_prune.go index c4772a04e7c5..397d67cdcf1a 100644 --- a/vendor/github.com/docker/docker/client/build_prune.go +++ b/vendor/github.com/docker/docker/client/build_prune.go @@ -4,24 +4,39 @@ import ( "context" "encoding/json" "fmt" + "net/url" "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 -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 { return nil, err } 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, err + 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 { + return nil, err + } + if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { return nil, fmt.Errorf("Error retrieving disk usage: %v", err) } diff --git a/vendor/github.com/docker/docker/client/checkpoint_list.go b/vendor/github.com/docker/docker/client/checkpoint_list.go index 2b73fb553f20..66d46dd161ba 100644 --- a/vendor/github.com/docker/docker/client/checkpoint_list.go +++ b/vendor/github.com/docker/docker/client/checkpoint_list.go @@ -18,11 +18,11 @@ func (cli *Client) CheckpointList(ctx context.Context, container string, options } resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil) + defer ensureReaderClosed(resp) if err != nil { return checkpoints, wrapResponseError(err, resp, "container", container) } err = json.NewDecoder(resp.body).Decode(&checkpoints) - ensureReaderClosed(resp) return checkpoints, err } diff --git a/vendor/github.com/docker/docker/client/client.go b/vendor/github.com/docker/docker/client/client.go index b874b3b522bb..0b7b4d953c95 100644 --- a/vendor/github.com/docker/docker/client/client.go +++ b/vendor/github.com/docker/docker/client/client.go @@ -23,7 +23,7 @@ For example, to list running containers (the equivalent of "docker ps"): ) func main() { - cli, err := client.NewEnvClient() + cli, err := client.NewClientWithOpts(client.FromEnv) if err != nil { panic(err) } @@ -47,16 +47,13 @@ import ( "net" "net/http" "net/url" - "os" "path" - "path/filepath" "strings" "github.com/docker/docker/api" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/versions" "github.com/docker/go-connections/sockets" - "github.com/docker/go-connections/tlsconfig" "github.com/pkg/errors" ) @@ -90,7 +87,7 @@ type Client struct { // 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 . -// 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. // 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. @@ -103,130 +100,6 @@ func CheckRedirect(req *http.Request, via []*http.Request) error { 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 // to modify values when creating it, like `NewClientWithOpts(WithVersion(…))` // 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{ host: DefaultDockerHost, version: api.DefaultVersion, - scheme: "http", client: client, proto: defaultProto, addr: defaultAddr, @@ -257,14 +129,18 @@ func NewClientWithOpts(ops ...func(*Client) error) (*Client, error) { if _, ok := c.client.Transport.(http.RoundTripper); !ok { return nil, fmt.Errorf("unable to verify TLS configuration, invalid transport %v", c.client.Transport) } - tlsConfig := resolveTLSConfig(c.client.Transport) - if tlsConfig != nil { - // 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. - // 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" + if c.scheme == "" { + c.scheme = "http" + + tlsConfig := resolveTLSConfig(c.client.Transport) + if tlsConfig != nil { + // 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. + // 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 @@ -283,18 +159,6 @@ func defaultHTTPClient(host string) (*http.Client, error) { }, 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 func (cli *Client) Close() error { 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) { 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)) + } +} diff --git a/vendor/github.com/docker/docker/client/client_deprecated.go b/vendor/github.com/docker/docker/client/client_deprecated.go new file mode 100644 index 000000000000..54cdfc29a84b --- /dev/null +++ b/vendor/github.com/docker/docker/client/client_deprecated.go @@ -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) +} diff --git a/vendor/github.com/docker/docker/client/config_create.go b/vendor/github.com/docker/docker/client/config_create.go index c8b802ad356c..ee7d411df06a 100644 --- a/vendor/github.com/docker/docker/client/config_create.go +++ b/vendor/github.com/docker/docker/client/config_create.go @@ -15,11 +15,11 @@ func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (t return response, err } resp, err := cli.post(ctx, "/configs/create", nil, config, nil) + defer ensureReaderClosed(resp) if err != nil { return response, err } err = json.NewDecoder(resp.body).Decode(&response) - ensureReaderClosed(resp) return response, err } diff --git a/vendor/github.com/docker/docker/client/config_inspect.go b/vendor/github.com/docker/docker/client/config_inspect.go index 4ac566ad89fc..7d0ce3e11c07 100644 --- a/vendor/github.com/docker/docker/client/config_inspect.go +++ b/vendor/github.com/docker/docker/client/config_inspect.go @@ -18,10 +18,10 @@ func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.C return swarm.Config{}, nil, err } resp, err := cli.get(ctx, "/configs/"+id, nil, nil) + defer ensureReaderClosed(resp) if err != nil { return swarm.Config{}, nil, wrapResponseError(err, resp, "config", id) } - defer ensureReaderClosed(resp) body, err := ioutil.ReadAll(resp.body) if err != nil { diff --git a/vendor/github.com/docker/docker/client/config_list.go b/vendor/github.com/docker/docker/client/config_list.go index 2b9d54606bf3..565acc6e2733 100644 --- a/vendor/github.com/docker/docker/client/config_list.go +++ b/vendor/github.com/docker/docker/client/config_list.go @@ -27,12 +27,12 @@ func (cli *Client) ConfigList(ctx context.Context, options types.ConfigListOptio } resp, err := cli.get(ctx, "/configs", query, nil) + defer ensureReaderClosed(resp) if err != nil { return nil, err } var configs []swarm.Config err = json.NewDecoder(resp.body).Decode(&configs) - ensureReaderClosed(resp) return configs, err } diff --git a/vendor/github.com/docker/docker/client/config_remove.go b/vendor/github.com/docker/docker/client/config_remove.go index a96871e98b71..a708fcaecfdc 100644 --- a/vendor/github.com/docker/docker/client/config_remove.go +++ b/vendor/github.com/docker/docker/client/config_remove.go @@ -8,6 +8,6 @@ func (cli *Client) ConfigRemove(ctx context.Context, id string) error { return err } resp, err := cli.delete(ctx, "/configs/"+id, nil, nil) - ensureReaderClosed(resp) + defer ensureReaderClosed(resp) return wrapResponseError(err, resp, "config", id) } diff --git a/vendor/github.com/docker/docker/client/container_commit.go b/vendor/github.com/docker/docker/client/container_commit.go index 377a2ea681c1..2966e88c8eca 100644 --- a/vendor/github.com/docker/docker/client/container_commit.go +++ b/vendor/github.com/docker/docker/client/container_commit.go @@ -45,11 +45,11 @@ func (cli *Client) ContainerCommit(ctx context.Context, container string, option var response types.IDResponse resp, err := cli.post(ctx, "/commit", query, options.Config, nil) + defer ensureReaderClosed(resp) if err != nil { return response, err } err = json.NewDecoder(resp.body).Decode(&response) - ensureReaderClosed(resp) return response, err } diff --git a/vendor/github.com/docker/docker/client/container_copy.go b/vendor/github.com/docker/docker/client/container_copy.go index d706260cee0f..bb278bf7f324 100644 --- a/vendor/github.com/docker/docker/client/container_copy.go +++ b/vendor/github.com/docker/docker/client/container_copy.go @@ -21,10 +21,10 @@ func (cli *Client) ContainerStatPath(ctx context.Context, containerID, path stri urlStr := "/containers/" + containerID + "/archive" response, err := cli.head(ctx, urlStr, query, nil) + defer ensureReaderClosed(response) if err != nil { return types.ContainerPathStat{}, wrapResponseError(err, response, "container:path", containerID+":"+path) } - defer ensureReaderClosed(response) return getContainerPathStatFromHeader(response.header) } @@ -45,11 +45,12 @@ func (cli *Client) CopyToContainer(ctx context.Context, containerID, dstPath str apiPath := "/containers/" + containerID + "/archive" response, err := cli.putRaw(ctx, apiPath, query, content, nil) + defer ensureReaderClosed(response) if err != nil { 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 { 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) } + // 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 { return nil, types.ContainerPathStat{}, fmt.Errorf("unexpected status code from daemon: %d", response.statusCode) } diff --git a/vendor/github.com/docker/docker/client/container_create.go b/vendor/github.com/docker/docker/client/container_create.go index d269a61894ae..5b795e0c17ce 100644 --- a/vendor/github.com/docker/docker/client/container_create.go +++ b/vendor/github.com/docker/docker/client/container_create.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "net/url" - "strings" "github.com/docker/docker/api/types/container" "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) + defer ensureReaderClosed(serverResp) 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 } err = json.NewDecoder(serverResp.body).Decode(&response) - ensureReaderClosed(serverResp) return response, err } diff --git a/vendor/github.com/docker/docker/client/container_diff.go b/vendor/github.com/docker/docker/client/container_diff.go index 3b7c90c96c95..29dac8491df5 100644 --- a/vendor/github.com/docker/docker/client/container_diff.go +++ b/vendor/github.com/docker/docker/client/container_diff.go @@ -13,11 +13,11 @@ func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]con var changes []container.ContainerChangeResponseItem serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil) + defer ensureReaderClosed(serverResp) if err != nil { return changes, err } err = json.NewDecoder(serverResp.body).Decode(&changes) - ensureReaderClosed(serverResp) return changes, err } diff --git a/vendor/github.com/docker/docker/client/container_exec.go b/vendor/github.com/docker/docker/client/container_exec.go index 535536b1e0ff..e3ee755b71dc 100644 --- a/vendor/github.com/docker/docker/client/container_exec.go +++ b/vendor/github.com/docker/docker/client/container_exec.go @@ -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) + defer ensureReaderClosed(resp) if err != nil { return response, err } err = json.NewDecoder(resp.body).Decode(&response) - ensureReaderClosed(resp) return response, err } diff --git a/vendor/github.com/docker/docker/client/container_inspect.go b/vendor/github.com/docker/docker/client/container_inspect.go index f453064cf8f4..c496bcffea53 100644 --- a/vendor/github.com/docker/docker/client/container_inspect.go +++ b/vendor/github.com/docker/docker/client/container_inspect.go @@ -16,13 +16,13 @@ func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (ty return types.ContainerJSON{}, objectNotFoundError{object: "container", id: containerID} } serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return types.ContainerJSON{}, wrapResponseError(err, serverResp, "container", containerID) } var response types.ContainerJSON err = json.NewDecoder(serverResp.body).Decode(&response) - ensureReaderClosed(serverResp) return response, err } @@ -36,10 +36,10 @@ func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID stri query.Set("size", "1") } serverResp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil) + defer ensureReaderClosed(serverResp) if err != nil { return types.ContainerJSON{}, nil, wrapResponseError(err, serverResp, "container", containerID) } - defer ensureReaderClosed(serverResp) body, err := ioutil.ReadAll(serverResp.body) if err != nil { diff --git a/vendor/github.com/docker/docker/client/container_list.go b/vendor/github.com/docker/docker/client/container_list.go index 9c218e2218ae..1e7a63a9c066 100644 --- a/vendor/github.com/docker/docker/client/container_list.go +++ b/vendor/github.com/docker/docker/client/container_list.go @@ -45,12 +45,12 @@ func (cli *Client) ContainerList(ctx context.Context, options types.ContainerLis } resp, err := cli.get(ctx, "/containers/json", query, nil) + defer ensureReaderClosed(resp) if err != nil { return nil, err } var containers []types.Container err = json.NewDecoder(resp.body).Decode(&containers) - ensureReaderClosed(resp) return containers, err } diff --git a/vendor/github.com/docker/docker/client/container_prune.go b/vendor/github.com/docker/docker/client/container_prune.go index 14f88d93bac3..04383deaaffc 100644 --- a/vendor/github.com/docker/docker/client/container_prune.go +++ b/vendor/github.com/docker/docker/client/container_prune.go @@ -23,10 +23,10 @@ func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Arg } serverResp, err := cli.post(ctx, "/containers/prune", query, nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return report, err } - defer ensureReaderClosed(serverResp) if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { return report, fmt.Errorf("Error retrieving disk usage: %v", err) diff --git a/vendor/github.com/docker/docker/client/container_remove.go b/vendor/github.com/docker/docker/client/container_remove.go index ab4cfc16f878..df81461b889c 100644 --- a/vendor/github.com/docker/docker/client/container_remove.go +++ b/vendor/github.com/docker/docker/client/container_remove.go @@ -22,6 +22,6 @@ func (cli *Client) ContainerRemove(ctx context.Context, containerID string, opti } resp, err := cli.delete(ctx, "/containers/"+containerID, query, nil) - ensureReaderClosed(resp) + defer ensureReaderClosed(resp) return wrapResponseError(err, resp, "container", containerID) } diff --git a/vendor/github.com/docker/docker/client/container_top.go b/vendor/github.com/docker/docker/client/container_top.go index 9c9fce7a040e..a5b78999bf0a 100644 --- a/vendor/github.com/docker/docker/client/container_top.go +++ b/vendor/github.com/docker/docker/client/container_top.go @@ -18,11 +18,11 @@ func (cli *Client) ContainerTop(ctx context.Context, containerID string, argumen } resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil) + defer ensureReaderClosed(resp) if err != nil { return response, err } err = json.NewDecoder(resp.body).Decode(&response) - ensureReaderClosed(resp) return response, err } diff --git a/vendor/github.com/docker/docker/client/container_update.go b/vendor/github.com/docker/docker/client/container_update.go index 14e7f23dfb8a..6917cf9fb36d 100644 --- a/vendor/github.com/docker/docker/client/container_update.go +++ b/vendor/github.com/docker/docker/client/container_update.go @@ -11,12 +11,11 @@ import ( func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.ContainerUpdateOKBody, error) { var response container.ContainerUpdateOKBody serverResp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil) + defer ensureReaderClosed(serverResp) if err != nil { return response, err } err = json.NewDecoder(serverResp.body).Decode(&response) - - ensureReaderClosed(serverResp) return response, err } diff --git a/vendor/github.com/docker/docker/client/disk_usage.go b/vendor/github.com/docker/docker/client/disk_usage.go index 8eb30eb5de22..354cd36939a8 100644 --- a/vendor/github.com/docker/docker/client/disk_usage.go +++ b/vendor/github.com/docker/docker/client/disk_usage.go @@ -13,10 +13,10 @@ func (cli *Client) DiskUsage(ctx context.Context) (types.DiskUsage, error) { var du types.DiskUsage serverResp, err := cli.get(ctx, "/system/df", nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return du, err } - defer ensureReaderClosed(serverResp) if err := json.NewDecoder(serverResp.body).Decode(&du); err != nil { return du, fmt.Errorf("Error retrieving disk usage: %v", err) diff --git a/vendor/github.com/docker/docker/client/distribution_inspect.go b/vendor/github.com/docker/docker/client/distribution_inspect.go index 7245bbeeda4d..f4e3794cb4c6 100644 --- a/vendor/github.com/docker/docker/client/distribution_inspect.go +++ b/vendor/github.com/docker/docker/client/distribution_inspect.go @@ -28,11 +28,11 @@ func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegist } resp, err := cli.get(ctx, "/distribution/"+image+"/json", url.Values{}, headers) + defer ensureReaderClosed(resp) if err != nil { return distributionInspect, err } err = json.NewDecoder(resp.body).Decode(&distributionInspect) - ensureReaderClosed(resp) return distributionInspect, err } diff --git a/vendor/github.com/docker/docker/client/errors.go b/vendor/github.com/docker/docker/client/errors.go index 0461af329d5d..001c10288141 100644 --- a/vendor/github.com/docker/docker/client/errors.go +++ b/vendor/github.com/docker/docker/client/errors.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" ) @@ -32,16 +33,19 @@ func ErrorConnectionFailed(host string) error { return errConnectionFailed{host: host} } +// Deprecated: use the errdefs.NotFound() interface instead. Kept for backward compatibility type notFound interface { error - NotFound() bool // Is the error a NotFound error + NotFound() bool } // IsErrNotFound returns true if the error is a NotFound error, which is returned // by the API when some object is not found. func IsErrNotFound(err error) bool { - te, ok := err.(notFound) - return ok && te.NotFound() + if _, ok := err.(notFound); ok { + return ok + } + return errdefs.IsNotFound(err) } type objectNotFoundError struct { @@ -49,9 +53,7 @@ type objectNotFoundError struct { id string } -func (e objectNotFoundError) NotFound() bool { - return true -} +func (e objectNotFoundError) NotFound() {} func (e objectNotFoundError) Error() string { 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: return objectNotFoundError{object: object, id: id} case resp.statusCode == http.StatusNotImplemented: - return notImplementedError{message: err.Error()} + return errdefs.NotImplemented(err) default: return err } @@ -83,8 +85,10 @@ func (u unauthorizedError) Error() string { // IsErrUnauthorized returns true if the error is caused // when a remote registry authentication fails func IsErrUnauthorized(err error) bool { - _, ok := err.(unauthorizedError) - return ok + if _, ok := err.(unauthorizedError); ok { + return ok + } + return errdefs.IsUnauthorized(err) } 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 // implemented. func IsErrNotImplemented(err error) bool { - te, ok := err.(notImplementedError) - return ok && te.NotImplemented() + if _, ok := err.(notImplementedError); ok { + return ok + } + return errdefs.IsNotImplemented(err) } // NewVersionError returns an error if the APIVersion required diff --git a/vendor/github.com/docker/docker/client/hijack.go b/vendor/github.com/docker/docker/client/hijack.go index 35f5dd86dc1e..86099827390e 100644 --- a/vendor/github.com/docker/docker/client/hijack.go +++ b/vendor/github.com/docker/docker/client/hijack.go @@ -30,7 +30,7 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu } req = cli.addHeaders(req, headers) - conn, err := cli.setupHijackConn(req, "tcp") + conn, err := cli.setupHijackConn(ctx, req, "tcp") if err != nil { 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 } -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" { 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) } -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.Header.Set("Connection", "Upgrade") 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 { return nil, errors.Wrap(err, "cannot connect to the Docker daemon. Is 'docker daemon' running on this host?") } diff --git a/vendor/github.com/docker/docker/client/image_build.go b/vendor/github.com/docker/docker/client/image_build.go index 6721460316ad..8fcf995036fb 100644 --- a/vendor/github.com/docker/docker/client/image_build.go +++ b/vendor/github.com/docker/docker/client/image_build.go @@ -30,12 +30,6 @@ func (cli *Client) ImageBuild(ctx context.Context, buildContext io.Reader, optio } 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") 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) } if options.Platform != "" { + if err := cli.NewVersionError("1.32", "platform"); err != nil { + return query, err + } 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 } diff --git a/vendor/github.com/docker/docker/client/image_history.go b/vendor/github.com/docker/docker/client/image_history.go index 0151b9517f25..b5bea10d8f63 100644 --- a/vendor/github.com/docker/docker/client/image_history.go +++ b/vendor/github.com/docker/docker/client/image_history.go @@ -12,11 +12,11 @@ import ( func (cli *Client) ImageHistory(ctx context.Context, imageID string) ([]image.HistoryResponseItem, error) { var history []image.HistoryResponseItem serverResp, err := cli.get(ctx, "/images/"+imageID+"/history", url.Values{}, nil) + defer ensureReaderClosed(serverResp) if err != nil { return history, err } err = json.NewDecoder(serverResp.body).Decode(&history) - ensureReaderClosed(serverResp) return history, err } diff --git a/vendor/github.com/docker/docker/client/image_inspect.go b/vendor/github.com/docker/docker/client/image_inspect.go index 2f8f6d2f1416..1eb8dce02591 100644 --- a/vendor/github.com/docker/docker/client/image_inspect.go +++ b/vendor/github.com/docker/docker/client/image_inspect.go @@ -15,10 +15,10 @@ func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (typ return types.ImageInspect{}, nil, objectNotFoundError{object: "image", id: imageID} } serverResp, err := cli.get(ctx, "/images/"+imageID+"/json", nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return types.ImageInspect{}, nil, wrapResponseError(err, serverResp, "image", imageID) } - defer ensureReaderClosed(serverResp) body, err := ioutil.ReadAll(serverResp.body) if err != nil { diff --git a/vendor/github.com/docker/docker/client/image_list.go b/vendor/github.com/docker/docker/client/image_list.go index 32fae27b375e..4fa8c006b2ea 100644 --- a/vendor/github.com/docker/docker/client/image_list.go +++ b/vendor/github.com/docker/docker/client/image_list.go @@ -35,11 +35,11 @@ func (cli *Client) ImageList(ctx context.Context, options types.ImageListOptions } serverResp, err := cli.get(ctx, "/images/json", query, nil) + defer ensureReaderClosed(serverResp) if err != nil { return images, err } err = json.NewDecoder(serverResp.body).Decode(&images) - ensureReaderClosed(serverResp) return images, err } diff --git a/vendor/github.com/docker/docker/client/image_prune.go b/vendor/github.com/docker/docker/client/image_prune.go index 78ee3f6c496f..56af6d7f98f4 100644 --- a/vendor/github.com/docker/docker/client/image_prune.go +++ b/vendor/github.com/docker/docker/client/image_prune.go @@ -23,10 +23,10 @@ func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) ( } serverResp, err := cli.post(ctx, "/images/prune", query, nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return report, err } - defer ensureReaderClosed(serverResp) if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { return report, fmt.Errorf("Error retrieving disk usage: %v", err) diff --git a/vendor/github.com/docker/docker/client/image_pull.go b/vendor/github.com/docker/docker/client/image_pull.go index d97aacf8c529..a23975591be2 100644 --- a/vendor/github.com/docker/docker/client/image_pull.go +++ b/vendor/github.com/docker/docker/client/image_pull.go @@ -3,12 +3,12 @@ package client // import "github.com/docker/docker/client" import ( "context" "io" - "net/http" "net/url" "strings" "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" + "github.com/docker/docker/errdefs" ) // 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) - if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil { + if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { newAuthHeader, privilegeErr := options.PrivilegeFunc() if privilegeErr != nil { return nil, privilegeErr diff --git a/vendor/github.com/docker/docker/client/image_push.go b/vendor/github.com/docker/docker/client/image_push.go index a15871c2b448..49d412ee375c 100644 --- a/vendor/github.com/docker/docker/client/image_push.go +++ b/vendor/github.com/docker/docker/client/image_push.go @@ -4,11 +4,11 @@ import ( "context" "errors" "io" - "net/http" "net/url" "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" + "github.com/docker/docker/errdefs" ) // 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) 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() if privilegeErr != nil { return nil, privilegeErr diff --git a/vendor/github.com/docker/docker/client/image_remove.go b/vendor/github.com/docker/docker/client/image_remove.go index 45d6e6f0dbad..84a41af0f2ca 100644 --- a/vendor/github.com/docker/docker/client/image_remove.go +++ b/vendor/github.com/docker/docker/client/image_remove.go @@ -21,11 +21,11 @@ func (cli *Client) ImageRemove(ctx context.Context, imageID string, options type var dels []types.ImageDeleteResponseItem resp, err := cli.delete(ctx, "/images/"+imageID, query, nil) + defer ensureReaderClosed(resp) if err != nil { return dels, wrapResponseError(err, resp, "image", imageID) } err = json.NewDecoder(resp.body).Decode(&dels) - ensureReaderClosed(resp) return dels, err } diff --git a/vendor/github.com/docker/docker/client/image_search.go b/vendor/github.com/docker/docker/client/image_search.go index 176de3c58240..82955a74775b 100644 --- a/vendor/github.com/docker/docker/client/image_search.go +++ b/vendor/github.com/docker/docker/client/image_search.go @@ -4,12 +4,12 @@ import ( "context" "encoding/json" "fmt" - "net/http" "net/url" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/errdefs" ) // ImageSearch makes the docker host to search by a term in a remote registry. @@ -29,7 +29,8 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I } resp, err := cli.tryImageSearch(ctx, query, options.RegistryAuth) - if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil { + defer ensureReaderClosed(resp) + if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { newAuthHeader, privilegeErr := options.PrivilegeFunc() if privilegeErr != nil { return results, privilegeErr @@ -41,7 +42,6 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I } err = json.NewDecoder(resp.body).Decode(&results) - ensureReaderClosed(resp) return results, err } diff --git a/vendor/github.com/docker/docker/client/info.go b/vendor/github.com/docker/docker/client/info.go index 121f256ab1cc..c856704e23f4 100644 --- a/vendor/github.com/docker/docker/client/info.go +++ b/vendor/github.com/docker/docker/client/info.go @@ -13,10 +13,10 @@ import ( func (cli *Client) Info(ctx context.Context) (types.Info, error) { var info types.Info serverResp, err := cli.get(ctx, "/info", url.Values{}, nil) + defer ensureReaderClosed(serverResp) if err != nil { return info, err } - defer ensureReaderClosed(serverResp) if err := json.NewDecoder(serverResp.body).Decode(&info); err != nil { return info, fmt.Errorf("Error reading remote info: %v", err) diff --git a/vendor/github.com/docker/docker/client/interface.go b/vendor/github.com/docker/docker/client/interface.go index 0487a0b9f35c..cde64be4b56b 100644 --- a/vendor/github.com/docker/docker/client/interface.go +++ b/vendor/github.com/docker/docker/client/interface.go @@ -38,7 +38,8 @@ type CommonAPIClient interface { ServerVersion(ctx context.Context) (types.Version, error) NegotiateAPIVersion(ctx context.Context) NegotiateAPIVersionPing(types.Ping) - DialSession(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) + DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error) + Dialer() func(context.Context) (net.Conn, error) Close() error } @@ -85,7 +86,8 @@ type DistributionAPIClient interface { // ImageAPIClient defines API client methods for the images type ImageAPIClient interface { ImageBuild(ctx context.Context, context io.Reader, options types.ImageBuildOptions) (types.ImageBuildResponse, error) - BuildCachePrune(ctx context.Context) (*types.BuildCachePruneReport, error) + BuildCachePrune(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) + BuildCancel(ctx context.Context, id string) error ImageCreate(ctx context.Context, parentReference string, options types.ImageCreateOptions) (io.ReadCloser, error) ImageHistory(ctx context.Context, image string) ([]image.HistoryResponseItem, error) ImageImport(ctx context.Context, source types.ImageImportSource, ref string, options types.ImageImportOptions) (io.ReadCloser, error) diff --git a/vendor/github.com/docker/docker/client/login.go b/vendor/github.com/docker/docker/client/login.go index 7d6618190040..f05852063823 100644 --- a/vendor/github.com/docker/docker/client/login.go +++ b/vendor/github.com/docker/docker/client/login.go @@ -3,7 +3,6 @@ package client // import "github.com/docker/docker/client" import ( "context" "encoding/json" - "net/http" "net/url" "github.com/docker/docker/api/types" @@ -14,16 +13,13 @@ import ( // It returns unauthorizedError when the authentication fails. func (cli *Client) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, error) { resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil) + defer ensureReaderClosed(resp) - if resp.statusCode == http.StatusUnauthorized { - return registry.AuthenticateOKBody{}, unauthorizedError{err} - } if err != nil { return registry.AuthenticateOKBody{}, err } var response registry.AuthenticateOKBody err = json.NewDecoder(resp.body).Decode(&response) - ensureReaderClosed(resp) return response, err } diff --git a/vendor/github.com/docker/docker/client/network_create.go b/vendor/github.com/docker/docker/client/network_create.go index 41da2ac6109a..278d9383a86b 100644 --- a/vendor/github.com/docker/docker/client/network_create.go +++ b/vendor/github.com/docker/docker/client/network_create.go @@ -15,11 +15,11 @@ func (cli *Client) NetworkCreate(ctx context.Context, name string, options types } var response types.NetworkCreateResponse serverResp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil) + defer ensureReaderClosed(serverResp) if err != nil { return response, err } - json.NewDecoder(serverResp.body).Decode(&response) - ensureReaderClosed(serverResp) + err = json.NewDecoder(serverResp.body).Decode(&response) return response, err } diff --git a/vendor/github.com/docker/docker/client/network_inspect.go b/vendor/github.com/docker/docker/client/network_inspect.go index 025f6d8757da..89a05b3021a4 100644 --- a/vendor/github.com/docker/docker/client/network_inspect.go +++ b/vendor/github.com/docker/docker/client/network_inspect.go @@ -34,10 +34,10 @@ func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, query.Set("scope", options.Scope) } resp, err = cli.get(ctx, "/networks/"+networkID, query, nil) + defer ensureReaderClosed(resp) if err != nil { return networkResource, nil, wrapResponseError(err, resp, "network", networkID) } - defer ensureReaderClosed(resp) body, err := ioutil.ReadAll(resp.body) if err != nil { diff --git a/vendor/github.com/docker/docker/client/network_list.go b/vendor/github.com/docker/docker/client/network_list.go index f16b2f562404..7130c1364eb2 100644 --- a/vendor/github.com/docker/docker/client/network_list.go +++ b/vendor/github.com/docker/docker/client/network_list.go @@ -22,10 +22,10 @@ func (cli *Client) NetworkList(ctx context.Context, options types.NetworkListOpt } var networkResources []types.NetworkResource resp, err := cli.get(ctx, "/networks", query, nil) + defer ensureReaderClosed(resp) if err != nil { return networkResources, err } err = json.NewDecoder(resp.body).Decode(&networkResources) - ensureReaderClosed(resp) return networkResources, err } diff --git a/vendor/github.com/docker/docker/client/network_prune.go b/vendor/github.com/docker/docker/client/network_prune.go index 6418b8b60704..cebb18821925 100644 --- a/vendor/github.com/docker/docker/client/network_prune.go +++ b/vendor/github.com/docker/docker/client/network_prune.go @@ -23,10 +23,10 @@ func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) } serverResp, err := cli.post(ctx, "/networks/prune", query, nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return report, err } - defer ensureReaderClosed(serverResp) if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { return report, fmt.Errorf("Error retrieving network prune report: %v", err) diff --git a/vendor/github.com/docker/docker/client/network_remove.go b/vendor/github.com/docker/docker/client/network_remove.go index 12741437be35..e71b16d86929 100644 --- a/vendor/github.com/docker/docker/client/network_remove.go +++ b/vendor/github.com/docker/docker/client/network_remove.go @@ -5,6 +5,6 @@ import "context" // NetworkRemove removes an existent network from the docker host. func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error { resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil) - ensureReaderClosed(resp) + defer ensureReaderClosed(resp) return wrapResponseError(err, resp, "network", networkID) } diff --git a/vendor/github.com/docker/docker/client/node_inspect.go b/vendor/github.com/docker/docker/client/node_inspect.go index 593b2e9f0b3f..d296c9fdde38 100644 --- a/vendor/github.com/docker/docker/client/node_inspect.go +++ b/vendor/github.com/docker/docker/client/node_inspect.go @@ -15,10 +15,10 @@ func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm return swarm.Node{}, nil, objectNotFoundError{object: "node", id: nodeID} } serverResp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return swarm.Node{}, nil, wrapResponseError(err, serverResp, "node", nodeID) } - defer ensureReaderClosed(serverResp) body, err := ioutil.ReadAll(serverResp.body) if err != nil { diff --git a/vendor/github.com/docker/docker/client/node_list.go b/vendor/github.com/docker/docker/client/node_list.go index 9883f6fc52d5..c212906bc718 100644 --- a/vendor/github.com/docker/docker/client/node_list.go +++ b/vendor/github.com/docker/docker/client/node_list.go @@ -25,12 +25,12 @@ func (cli *Client) NodeList(ctx context.Context, options types.NodeListOptions) } resp, err := cli.get(ctx, "/nodes", query, nil) + defer ensureReaderClosed(resp) if err != nil { return nil, err } var nodes []swarm.Node err = json.NewDecoder(resp.body).Decode(&nodes) - ensureReaderClosed(resp) return nodes, err } diff --git a/vendor/github.com/docker/docker/client/node_remove.go b/vendor/github.com/docker/docker/client/node_remove.go index e7a75057155b..03ab87809741 100644 --- a/vendor/github.com/docker/docker/client/node_remove.go +++ b/vendor/github.com/docker/docker/client/node_remove.go @@ -15,6 +15,6 @@ func (cli *Client) NodeRemove(ctx context.Context, nodeID string, options types. } resp, err := cli.delete(ctx, "/nodes/"+nodeID, query, nil) - ensureReaderClosed(resp) + defer ensureReaderClosed(resp) return wrapResponseError(err, resp, "node", nodeID) } diff --git a/vendor/github.com/docker/docker/client/options.go b/vendor/github.com/docker/docker/client/options.go new file mode 100644 index 000000000000..089be0d50ddd --- /dev/null +++ b/vendor/github.com/docker/docker/client/options.go @@ -0,0 +1,146 @@ +package client + +import ( + "context" + "net" + "net/http" + "os" + "path/filepath" + + "github.com/docker/go-connections/sockets" + "github.com/docker/go-connections/tlsconfig" + "github.com/pkg/errors" +) + +// 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 != "" { + if err := WithVersion(version)(c); err != nil { + return err + } + } + return nil +} + +// WithDialer applies the dialer.DialContext to the client transport. This can be +// used to set the Timeout and KeepAlive settings of the client. +// Deprecated: use WithDialContext +func WithDialer(dialer *net.Dialer) func(*Client) error { + return WithDialContext(dialer.DialContext) +} + +// WithDialContext applies the dialer to the client transport. This can be +// used to set the Timeout and KeepAlive settings of the client. +func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) func(*Client) error { + return func(c *Client) error { + if transport, ok := c.client.Transport.(*http.Transport); ok { + transport.DialContext = dialContext + return nil + } + return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport) + } +} + +// 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 + } +} + +// WithScheme overrides the client scheme with the specified one +func WithScheme(scheme string) func(*Client) error { + return func(c *Client) error { + c.scheme = scheme + 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) + } +} + +// WithVersion overrides the client version with the specified one +func WithVersion(version string) func(*Client) error { + return func(c *Client) error { + c.version = version + c.manualOverride = true + return nil + } +} diff --git a/vendor/github.com/docker/docker/client/ping.go b/vendor/github.com/docker/docker/client/ping.go index 85d38adb51d9..4553e0fb718f 100644 --- a/vendor/github.com/docker/docker/client/ping.go +++ b/vendor/github.com/docker/docker/client/ping.go @@ -2,31 +2,63 @@ package client // import "github.com/docker/docker/client" import ( "context" + "net/http" "path" "github.com/docker/docker/api/types" + "github.com/docker/docker/errdefs" ) -// Ping pings the server and returns the value of the "Docker-Experimental", "OS-Type" & "API-Version" headers +// Ping pings the server and returns the value of the "Docker-Experimental", +// "Builder-Version", "OS-Type" & "API-Version" headers. It attempts to use +// a HEAD request on the endpoint, but falls back to GET if HEAD is not supported +// by the daemon. func (cli *Client) Ping(ctx context.Context) (types.Ping, error) { var ping types.Ping - req, err := cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil) + + // Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest() + // because ping requests are used during API version negotiation, so we want + // to hit the non-versioned /_ping endpoint, not /v1.xx/_ping + req, err := cli.buildRequest("HEAD", path.Join(cli.basePath, "/_ping"), nil, nil) if err != nil { return ping, err } serverResp, err := cli.doRequest(ctx, req) + if err == nil { + defer ensureReaderClosed(serverResp) + switch serverResp.statusCode { + case http.StatusOK, http.StatusInternalServerError: + // Server handled the request, so parse the response + return parsePingResponse(cli, serverResp) + } + } + + req, err = cli.buildRequest("GET", path.Join(cli.basePath, "/_ping"), nil, nil) if err != nil { return ping, err } + serverResp, err = cli.doRequest(ctx, req) defer ensureReaderClosed(serverResp) + if err != nil { + return ping, err + } + return parsePingResponse(cli, serverResp) +} - if serverResp.header != nil { - ping.APIVersion = serverResp.header.Get("API-Version") - - if serverResp.header.Get("Docker-Experimental") == "true" { - ping.Experimental = true - } - ping.OSType = serverResp.header.Get("OSType") +func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) { + var ping types.Ping + if resp.header == nil { + err := cli.checkResponseErr(resp) + return ping, errdefs.FromStatusCode(err, resp.statusCode) + } + ping.APIVersion = resp.header.Get("API-Version") + ping.OSType = resp.header.Get("OSType") + if resp.header.Get("Docker-Experimental") == "true" { + ping.Experimental = true + } + if bv := resp.header.Get("Builder-Version"); bv != "" { + ping.BuilderVersion = types.BuilderVersion(bv) } - return ping, cli.checkResponseErr(serverResp) + err := cli.checkResponseErr(resp) + return ping, errdefs.FromStatusCode(err, resp.statusCode) } diff --git a/vendor/github.com/docker/docker/client/plugin_create.go b/vendor/github.com/docker/docker/client/plugin_create.go index 4591db50fda5..b95dbaf68633 100644 --- a/vendor/github.com/docker/docker/client/plugin_create.go +++ b/vendor/github.com/docker/docker/client/plugin_create.go @@ -18,9 +18,6 @@ func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, cr query.Set("name", createOptions.RepoName) resp, err := cli.postRaw(ctx, "/plugins/create", query, createContext, headers) - if err != nil { - return err - } ensureReaderClosed(resp) return err } diff --git a/vendor/github.com/docker/docker/client/plugin_inspect.go b/vendor/github.com/docker/docker/client/plugin_inspect.go index 0ab7beaee8fb..81b89732b03a 100644 --- a/vendor/github.com/docker/docker/client/plugin_inspect.go +++ b/vendor/github.com/docker/docker/client/plugin_inspect.go @@ -15,11 +15,11 @@ func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*type return nil, nil, objectNotFoundError{object: "plugin", id: name} } resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil) + defer ensureReaderClosed(resp) if err != nil { return nil, nil, wrapResponseError(err, resp, "plugin", name) } - defer ensureReaderClosed(resp) body, err := ioutil.ReadAll(resp.body) if err != nil { return nil, nil, err diff --git a/vendor/github.com/docker/docker/client/plugin_install.go b/vendor/github.com/docker/docker/client/plugin_install.go index 13baa40a9b06..012afe61cacf 100644 --- a/vendor/github.com/docker/docker/client/plugin_install.go +++ b/vendor/github.com/docker/docker/client/plugin_install.go @@ -4,11 +4,11 @@ import ( "context" "encoding/json" "io" - "net/http" "net/url" "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" ) @@ -78,7 +78,7 @@ func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileg func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options types.PluginInstallOptions) (types.PluginPrivileges, error) { resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth) - if resp.statusCode == http.StatusUnauthorized && options.PrivilegeFunc != nil { + if errdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil { // todo: do inspect before to check existing name before checking privileges newAuthHeader, privilegeErr := options.PrivilegeFunc() if privilegeErr != nil { diff --git a/vendor/github.com/docker/docker/client/plugin_list.go b/vendor/github.com/docker/docker/client/plugin_list.go index ade1051a9700..8285cecd6e17 100644 --- a/vendor/github.com/docker/docker/client/plugin_list.go +++ b/vendor/github.com/docker/docker/client/plugin_list.go @@ -22,11 +22,11 @@ func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.P query.Set("filters", filterJSON) } resp, err := cli.get(ctx, "/plugins", query, nil) + defer ensureReaderClosed(resp) if err != nil { return plugins, wrapResponseError(err, resp, "plugin", "") } err = json.NewDecoder(resp.body).Decode(&plugins) - ensureReaderClosed(resp) return plugins, err } diff --git a/vendor/github.com/docker/docker/client/plugin_remove.go b/vendor/github.com/docker/docker/client/plugin_remove.go index 8563bab0dbcf..51ca1040d6d2 100644 --- a/vendor/github.com/docker/docker/client/plugin_remove.go +++ b/vendor/github.com/docker/docker/client/plugin_remove.go @@ -15,6 +15,6 @@ func (cli *Client) PluginRemove(ctx context.Context, name string, options types. } resp, err := cli.delete(ctx, "/plugins/"+name, query, nil) - ensureReaderClosed(resp) + defer ensureReaderClosed(resp) return wrapResponseError(err, resp, "plugin", name) } diff --git a/vendor/github.com/docker/docker/client/request.go b/vendor/github.com/docker/docker/client/request.go index a19d62aa52c4..0afe26d5880a 100644 --- a/vendor/github.com/docker/docker/client/request.go +++ b/vendor/github.com/docker/docker/client/request.go @@ -15,8 +15,8 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" - "golang.org/x/net/context/ctxhttp" ) // serverResponse is a wrapper for http API responses. @@ -121,22 +121,24 @@ func (cli *Client) sendRequest(ctx context.Context, method, path string, query u } resp, err := cli.doRequest(ctx, req) if err != nil { - return resp, err + return resp, errdefs.FromStatusCode(err, resp.statusCode) } - return resp, cli.checkResponseErr(resp) + err = cli.checkResponseErr(resp) + return resp, errdefs.FromStatusCode(err, resp.statusCode) } func (cli *Client) doRequest(ctx context.Context, req *http.Request) (serverResponse, error) { serverResp := serverResponse{statusCode: -1, reqURL: req.URL} - resp, err := ctxhttp.Do(ctx, cli.client, req) + req = req.WithContext(ctx) + resp, err := cli.client.Do(req) if err != nil { if cli.scheme != "https" && strings.Contains(err.Error(), "malformed HTTP response") { return serverResp, fmt.Errorf("%v.\n* Are you trying to connect to a TLS-enabled daemon without TLS?", err) } if cli.scheme == "https" && strings.Contains(err.Error(), "bad certificate") { - return serverResp, fmt.Errorf("The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: %v", err) + return serverResp, errors.Wrap(err, "The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings") } // Don't decorate context sentinel errors; users may be comparing to @@ -195,9 +197,21 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error { return nil } - body, err := ioutil.ReadAll(serverResp.body) - if err != nil { - return err + var body []byte + var err error + if serverResp.body != nil { + bodyMax := 1 * 1024 * 1024 // 1 MiB + bodyR := &io.LimitedReader{ + R: serverResp.body, + N: int64(bodyMax), + } + body, err = ioutil.ReadAll(bodyR) + if err != nil { + return err + } + if bodyR.N == 0 { + return fmt.Errorf("request returned %s with a message (> %d bytes) for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), bodyMax, serverResp.reqURL) + } } if len(body) == 0 { return fmt.Errorf("request returned %s for API route and version %s, check if the server supports the requested API version", http.StatusText(serverResp.statusCode), serverResp.reqURL) @@ -212,14 +226,14 @@ func (cli *Client) checkResponseErr(serverResp serverResponse) error { if (cli.version == "" || versions.GreaterThan(cli.version, "1.23")) && ct == "application/json" { var errorResponse types.ErrorResponse if err := json.Unmarshal(body, &errorResponse); err != nil { - return fmt.Errorf("Error reading JSON: %v", err) + return errors.Wrap(err, "Error reading JSON") } - errorMessage = errorResponse.Message + errorMessage = strings.TrimSpace(errorResponse.Message) } else { - errorMessage = string(body) + errorMessage = strings.TrimSpace(string(body)) } - return fmt.Errorf("Error response from daemon: %s", strings.TrimSpace(errorMessage)) + return errors.Wrap(errors.New(errorMessage), "Error response from daemon") } func (cli *Client) addHeaders(req *http.Request, headers headers) *http.Request { diff --git a/vendor/github.com/docker/docker/client/secret_create.go b/vendor/github.com/docker/docker/client/secret_create.go index 09fae82f2a1b..fd5b914136c3 100644 --- a/vendor/github.com/docker/docker/client/secret_create.go +++ b/vendor/github.com/docker/docker/client/secret_create.go @@ -15,11 +15,11 @@ func (cli *Client) SecretCreate(ctx context.Context, secret swarm.SecretSpec) (t return response, err } resp, err := cli.post(ctx, "/secrets/create", nil, secret, nil) + defer ensureReaderClosed(resp) if err != nil { return response, err } err = json.NewDecoder(resp.body).Decode(&response) - ensureReaderClosed(resp) return response, err } diff --git a/vendor/github.com/docker/docker/client/secret_inspect.go b/vendor/github.com/docker/docker/client/secret_inspect.go index e8322f458910..d093916c9a46 100644 --- a/vendor/github.com/docker/docker/client/secret_inspect.go +++ b/vendor/github.com/docker/docker/client/secret_inspect.go @@ -18,10 +18,10 @@ func (cli *Client) SecretInspectWithRaw(ctx context.Context, id string) (swarm.S return swarm.Secret{}, nil, objectNotFoundError{object: "secret", id: id} } resp, err := cli.get(ctx, "/secrets/"+id, nil, nil) + defer ensureReaderClosed(resp) if err != nil { return swarm.Secret{}, nil, wrapResponseError(err, resp, "secret", id) } - defer ensureReaderClosed(resp) body, err := ioutil.ReadAll(resp.body) if err != nil { diff --git a/vendor/github.com/docker/docker/client/secret_list.go b/vendor/github.com/docker/docker/client/secret_list.go index f6bf7ba470de..a0289c9f440f 100644 --- a/vendor/github.com/docker/docker/client/secret_list.go +++ b/vendor/github.com/docker/docker/client/secret_list.go @@ -27,12 +27,12 @@ func (cli *Client) SecretList(ctx context.Context, options types.SecretListOptio } resp, err := cli.get(ctx, "/secrets", query, nil) + defer ensureReaderClosed(resp) if err != nil { return nil, err } var secrets []swarm.Secret err = json.NewDecoder(resp.body).Decode(&secrets) - ensureReaderClosed(resp) return secrets, err } diff --git a/vendor/github.com/docker/docker/client/secret_remove.go b/vendor/github.com/docker/docker/client/secret_remove.go index e9d521829320..c16f55580416 100644 --- a/vendor/github.com/docker/docker/client/secret_remove.go +++ b/vendor/github.com/docker/docker/client/secret_remove.go @@ -8,6 +8,6 @@ func (cli *Client) SecretRemove(ctx context.Context, id string) error { return err } resp, err := cli.delete(ctx, "/secrets/"+id, nil, nil) - ensureReaderClosed(resp) + defer ensureReaderClosed(resp) return wrapResponseError(err, resp, "secret", id) } diff --git a/vendor/github.com/docker/docker/client/service_create.go b/vendor/github.com/docker/docker/client/service_create.go index 8fadda4a9064..620fc6cff757 100644 --- a/vendor/github.com/docker/docker/client/service_create.go +++ b/vendor/github.com/docker/docker/client/service_create.go @@ -72,6 +72,7 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, var response types.ServiceCreateResponse resp, err := cli.post(ctx, "/services/create", nil, service, headers) + defer ensureReaderClosed(resp) if err != nil { return response, err } @@ -82,7 +83,6 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec, response.Warnings = append(response.Warnings, digestWarning(service.TaskTemplate.ContainerSpec.Image)) } - ensureReaderClosed(resp) return response, err } diff --git a/vendor/github.com/docker/docker/client/service_inspect.go b/vendor/github.com/docker/docker/client/service_inspect.go index de6aa22de76d..2801483b80f5 100644 --- a/vendor/github.com/docker/docker/client/service_inspect.go +++ b/vendor/github.com/docker/docker/client/service_inspect.go @@ -20,10 +20,10 @@ func (cli *Client) ServiceInspectWithRaw(ctx context.Context, serviceID string, query := url.Values{} query.Set("insertDefaults", fmt.Sprintf("%v", opts.InsertDefaults)) serverResp, err := cli.get(ctx, "/services/"+serviceID, query, nil) + defer ensureReaderClosed(serverResp) if err != nil { return swarm.Service{}, nil, wrapResponseError(err, serverResp, "service", serviceID) } - defer ensureReaderClosed(serverResp) body, err := ioutil.ReadAll(serverResp.body) if err != nil { diff --git a/vendor/github.com/docker/docker/client/service_list.go b/vendor/github.com/docker/docker/client/service_list.go index 7d53e2b9b9e0..64d35e715982 100644 --- a/vendor/github.com/docker/docker/client/service_list.go +++ b/vendor/github.com/docker/docker/client/service_list.go @@ -24,12 +24,12 @@ func (cli *Client) ServiceList(ctx context.Context, options types.ServiceListOpt } resp, err := cli.get(ctx, "/services", query, nil) + defer ensureReaderClosed(resp) if err != nil { return nil, err } var services []swarm.Service err = json.NewDecoder(resp.body).Decode(&services) - ensureReaderClosed(resp) return services, err } diff --git a/vendor/github.com/docker/docker/client/service_remove.go b/vendor/github.com/docker/docker/client/service_remove.go index fe3421bec82f..953a2adf5aec 100644 --- a/vendor/github.com/docker/docker/client/service_remove.go +++ b/vendor/github.com/docker/docker/client/service_remove.go @@ -5,6 +5,6 @@ import "context" // ServiceRemove kills and removes a service. func (cli *Client) ServiceRemove(ctx context.Context, serviceID string) error { resp, err := cli.delete(ctx, "/services/"+serviceID, nil, nil) - ensureReaderClosed(resp) + defer ensureReaderClosed(resp) return wrapResponseError(err, resp, "service", serviceID) } diff --git a/vendor/github.com/docker/docker/client/service_update.go b/vendor/github.com/docker/docker/client/service_update.go index 5a7a61b01ffd..cd0f59e21338 100644 --- a/vendor/github.com/docker/docker/client/service_update.go +++ b/vendor/github.com/docker/docker/client/service_update.go @@ -10,7 +10,9 @@ import ( "github.com/docker/docker/api/types/swarm" ) -// ServiceUpdate updates a Service. +// ServiceUpdate updates a Service. The version number is required to avoid conflicting writes. +// It should be the value as set *before* the update. You can find this value in the Meta field +// of swarm.Service, which can be found using ServiceInspectWithRaw. func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options types.ServiceUpdateOptions) (types.ServiceUpdateResponse, error) { var ( query = url.Values{} @@ -77,6 +79,7 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version var response types.ServiceUpdateResponse resp, err := cli.post(ctx, "/services/"+serviceID+"/update", query, service, headers) + defer ensureReaderClosed(resp) if err != nil { return response, err } @@ -87,6 +90,5 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version response.Warnings = append(response.Warnings, digestWarning(service.TaskTemplate.ContainerSpec.Image)) } - ensureReaderClosed(resp) return response, err } diff --git a/vendor/github.com/docker/docker/client/session.go b/vendor/github.com/docker/docker/client/session.go deleted file mode 100644 index c247123b456d..000000000000 --- a/vendor/github.com/docker/docker/client/session.go +++ /dev/null @@ -1,18 +0,0 @@ -package client // import "github.com/docker/docker/client" - -import ( - "context" - "net" - "net/http" -) - -// DialSession returns a connection that can be used communication with daemon -func (cli *Client) DialSession(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error) { - req, err := http.NewRequest("POST", "/session", nil) - if err != nil { - return nil, err - } - req = cli.addHeaders(req, meta) - - return cli.setupHijackConn(req, proto) -} diff --git a/vendor/github.com/docker/docker/client/swarm_get_unlock_key.go b/vendor/github.com/docker/docker/client/swarm_get_unlock_key.go index 0c50c01a8c09..19f59dd582a9 100644 --- a/vendor/github.com/docker/docker/client/swarm_get_unlock_key.go +++ b/vendor/github.com/docker/docker/client/swarm_get_unlock_key.go @@ -10,12 +10,12 @@ import ( // SwarmGetUnlockKey retrieves the swarm's unlock key. func (cli *Client) SwarmGetUnlockKey(ctx context.Context) (types.SwarmUnlockKeyResponse, error) { serverResp, err := cli.get(ctx, "/swarm/unlockkey", nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return types.SwarmUnlockKeyResponse{}, err } var response types.SwarmUnlockKeyResponse err = json.NewDecoder(serverResp.body).Decode(&response) - ensureReaderClosed(serverResp) return response, err } diff --git a/vendor/github.com/docker/docker/client/swarm_init.go b/vendor/github.com/docker/docker/client/swarm_init.go index 742ca0f0416a..da3c1637ef04 100644 --- a/vendor/github.com/docker/docker/client/swarm_init.go +++ b/vendor/github.com/docker/docker/client/swarm_init.go @@ -10,12 +10,12 @@ import ( // SwarmInit initializes the swarm. func (cli *Client) SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error) { serverResp, err := cli.post(ctx, "/swarm/init", nil, req, nil) + defer ensureReaderClosed(serverResp) if err != nil { return "", err } var response string err = json.NewDecoder(serverResp.body).Decode(&response) - ensureReaderClosed(serverResp) return response, err } diff --git a/vendor/github.com/docker/docker/client/swarm_inspect.go b/vendor/github.com/docker/docker/client/swarm_inspect.go index cfaabb25b1ef..b52b67a8849b 100644 --- a/vendor/github.com/docker/docker/client/swarm_inspect.go +++ b/vendor/github.com/docker/docker/client/swarm_inspect.go @@ -10,12 +10,12 @@ import ( // SwarmInspect inspects the swarm. func (cli *Client) SwarmInspect(ctx context.Context) (swarm.Swarm, error) { serverResp, err := cli.get(ctx, "/swarm", nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return swarm.Swarm{}, err } var response swarm.Swarm err = json.NewDecoder(serverResp.body).Decode(&response) - ensureReaderClosed(serverResp) return response, err } diff --git a/vendor/github.com/docker/docker/client/task_inspect.go b/vendor/github.com/docker/docker/client/task_inspect.go index e1c0a736da58..44d40ba5ae83 100644 --- a/vendor/github.com/docker/docker/client/task_inspect.go +++ b/vendor/github.com/docker/docker/client/task_inspect.go @@ -15,10 +15,10 @@ func (cli *Client) TaskInspectWithRaw(ctx context.Context, taskID string) (swarm return swarm.Task{}, nil, objectNotFoundError{object: "task", id: taskID} } serverResp, err := cli.get(ctx, "/tasks/"+taskID, nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return swarm.Task{}, nil, wrapResponseError(err, serverResp, "task", taskID) } - defer ensureReaderClosed(serverResp) body, err := ioutil.ReadAll(serverResp.body) if err != nil { diff --git a/vendor/github.com/docker/docker/client/task_list.go b/vendor/github.com/docker/docker/client/task_list.go index 42d20c1b8d1a..4869b44493b1 100644 --- a/vendor/github.com/docker/docker/client/task_list.go +++ b/vendor/github.com/docker/docker/client/task_list.go @@ -24,12 +24,12 @@ func (cli *Client) TaskList(ctx context.Context, options types.TaskListOptions) } resp, err := cli.get(ctx, "/tasks", query, nil) + defer ensureReaderClosed(resp) if err != nil { return nil, err } var tasks []swarm.Task err = json.NewDecoder(resp.body).Decode(&tasks) - ensureReaderClosed(resp) return tasks, err } diff --git a/vendor/github.com/docker/docker/client/version.go b/vendor/github.com/docker/docker/client/version.go index 1989f6d6d2ba..8f17ff4e87af 100644 --- a/vendor/github.com/docker/docker/client/version.go +++ b/vendor/github.com/docker/docker/client/version.go @@ -10,12 +10,12 @@ import ( // ServerVersion returns information of the docker client and server host. func (cli *Client) ServerVersion(ctx context.Context) (types.Version, error) { resp, err := cli.get(ctx, "/version", nil, nil) + defer ensureReaderClosed(resp) if err != nil { return types.Version{}, err } var server types.Version err = json.NewDecoder(resp.body).Decode(&server) - ensureReaderClosed(resp) return server, err } diff --git a/vendor/github.com/docker/docker/client/volume_create.go b/vendor/github.com/docker/docker/client/volume_create.go index f1f6fcdc4a2d..92761b3c639e 100644 --- a/vendor/github.com/docker/docker/client/volume_create.go +++ b/vendor/github.com/docker/docker/client/volume_create.go @@ -12,10 +12,10 @@ import ( func (cli *Client) VolumeCreate(ctx context.Context, options volumetypes.VolumeCreateBody) (types.Volume, error) { var volume types.Volume resp, err := cli.post(ctx, "/volumes/create", nil, options, nil) + defer ensureReaderClosed(resp) if err != nil { return volume, err } err = json.NewDecoder(resp.body).Decode(&volume) - ensureReaderClosed(resp) return volume, err } diff --git a/vendor/github.com/docker/docker/client/volume_inspect.go b/vendor/github.com/docker/docker/client/volume_inspect.go index f840682d2ec7..e20b2c67c7a1 100644 --- a/vendor/github.com/docker/docker/client/volume_inspect.go +++ b/vendor/github.com/docker/docker/client/volume_inspect.go @@ -23,10 +23,10 @@ func (cli *Client) VolumeInspectWithRaw(ctx context.Context, volumeID string) (t var volume types.Volume resp, err := cli.get(ctx, "/volumes/"+volumeID, nil, nil) + defer ensureReaderClosed(resp) if err != nil { return volume, nil, wrapResponseError(err, resp, "volume", volumeID) } - defer ensureReaderClosed(resp) body, err := ioutil.ReadAll(resp.body) if err != nil { diff --git a/vendor/github.com/docker/docker/client/volume_list.go b/vendor/github.com/docker/docker/client/volume_list.go index 284554d67c03..2380d5638215 100644 --- a/vendor/github.com/docker/docker/client/volume_list.go +++ b/vendor/github.com/docker/docker/client/volume_list.go @@ -22,11 +22,11 @@ func (cli *Client) VolumeList(ctx context.Context, filter filters.Args) (volumet query.Set("filters", filterJSON) } resp, err := cli.get(ctx, "/volumes", query, nil) + defer ensureReaderClosed(resp) if err != nil { return volumes, err } err = json.NewDecoder(resp.body).Decode(&volumes) - ensureReaderClosed(resp) return volumes, err } diff --git a/vendor/github.com/docker/docker/client/volume_prune.go b/vendor/github.com/docker/docker/client/volume_prune.go index 70041efed8b1..6e324708f2b1 100644 --- a/vendor/github.com/docker/docker/client/volume_prune.go +++ b/vendor/github.com/docker/docker/client/volume_prune.go @@ -23,10 +23,10 @@ func (cli *Client) VolumesPrune(ctx context.Context, pruneFilters filters.Args) } serverResp, err := cli.post(ctx, "/volumes/prune", query, nil, nil) + defer ensureReaderClosed(serverResp) if err != nil { return report, err } - defer ensureReaderClosed(serverResp) if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil { return report, fmt.Errorf("Error retrieving volume prune report: %v", err) diff --git a/vendor/github.com/docker/docker/client/volume_remove.go b/vendor/github.com/docker/docker/client/volume_remove.go index fc5a71d3349e..79decdafab88 100644 --- a/vendor/github.com/docker/docker/client/volume_remove.go +++ b/vendor/github.com/docker/docker/client/volume_remove.go @@ -16,6 +16,6 @@ func (cli *Client) VolumeRemove(ctx context.Context, volumeID string, force bool } } resp, err := cli.delete(ctx, "/volumes/"+volumeID, query, nil) - ensureReaderClosed(resp) + defer ensureReaderClosed(resp) return wrapResponseError(err, resp, "volume", volumeID) } diff --git a/vendor/github.com/docker/docker/errdefs/defs.go b/vendor/github.com/docker/docker/errdefs/defs.go new file mode 100644 index 000000000000..61e7456b4ebf --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/defs.go @@ -0,0 +1,69 @@ +package errdefs // import "github.com/docker/docker/errdefs" + +// ErrNotFound signals that the requested object doesn't exist +type ErrNotFound interface { + NotFound() +} + +// ErrInvalidParameter signals that the user input is invalid +type ErrInvalidParameter interface { + InvalidParameter() +} + +// ErrConflict signals that some internal state conflicts with the requested action and can't be performed. +// A change in state should be able to clear this error. +type ErrConflict interface { + Conflict() +} + +// ErrUnauthorized is used to signify that the user is not authorized to perform a specific action +type ErrUnauthorized interface { + Unauthorized() +} + +// ErrUnavailable signals that the requested action/subsystem is not available. +type ErrUnavailable interface { + Unavailable() +} + +// ErrForbidden signals that the requested action cannot be performed under any circumstances. +// When a ErrForbidden is returned, the caller should never retry the action. +type ErrForbidden interface { + Forbidden() +} + +// ErrSystem signals that some internal error occurred. +// An example of this would be a failed mount request. +type ErrSystem interface { + System() +} + +// ErrNotModified signals that an action can't be performed because it's already in the desired state +type ErrNotModified interface { + NotModified() +} + +// ErrNotImplemented signals that the requested action/feature is not implemented on the system as configured. +type ErrNotImplemented interface { + NotImplemented() +} + +// ErrUnknown signals that the kind of error that occurred is not known. +type ErrUnknown interface { + Unknown() +} + +// ErrCancelled signals that the action was cancelled. +type ErrCancelled interface { + Cancelled() +} + +// ErrDeadline signals that the deadline was reached before the action completed. +type ErrDeadline interface { + DeadlineExceeded() +} + +// ErrDataLoss indicates that data was lost or there is data corruption. +type ErrDataLoss interface { + DataLoss() +} diff --git a/vendor/github.com/docker/docker/errdefs/doc.go b/vendor/github.com/docker/docker/errdefs/doc.go new file mode 100644 index 000000000000..c211f174fc11 --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/doc.go @@ -0,0 +1,8 @@ +// Package errdefs defines a set of error interfaces that packages should use for communicating classes of errors. +// Errors that cross the package boundary should implement one (and only one) of these interfaces. +// +// Packages should not reference these interfaces directly, only implement them. +// To check if a particular error implements one of these interfaces, there are helper +// functions provided (e.g. `Is`) which can be used rather than asserting the interfaces directly. +// If you must assert on these interfaces, be sure to check the causal chain (`err.Cause()`). +package errdefs // import "github.com/docker/docker/errdefs" diff --git a/vendor/github.com/docker/docker/errdefs/helpers.go b/vendor/github.com/docker/docker/errdefs/helpers.go new file mode 100644 index 000000000000..c9916e01354e --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/helpers.go @@ -0,0 +1,227 @@ +package errdefs // import "github.com/docker/docker/errdefs" + +import "context" + +type errNotFound struct{ error } + +func (errNotFound) NotFound() {} + +func (e errNotFound) Cause() error { + return e.error +} + +// NotFound is a helper to create an error of the class with the same name from any error type +func NotFound(err error) error { + if err == nil || IsNotFound(err) { + return err + } + return errNotFound{err} +} + +type errInvalidParameter struct{ error } + +func (errInvalidParameter) InvalidParameter() {} + +func (e errInvalidParameter) Cause() error { + return e.error +} + +// InvalidParameter is a helper to create an error of the class with the same name from any error type +func InvalidParameter(err error) error { + if err == nil || IsInvalidParameter(err) { + return err + } + return errInvalidParameter{err} +} + +type errConflict struct{ error } + +func (errConflict) Conflict() {} + +func (e errConflict) Cause() error { + return e.error +} + +// Conflict is a helper to create an error of the class with the same name from any error type +func Conflict(err error) error { + if err == nil || IsConflict(err) { + return err + } + return errConflict{err} +} + +type errUnauthorized struct{ error } + +func (errUnauthorized) Unauthorized() {} + +func (e errUnauthorized) Cause() error { + return e.error +} + +// Unauthorized is a helper to create an error of the class with the same name from any error type +func Unauthorized(err error) error { + if err == nil || IsUnauthorized(err) { + return err + } + return errUnauthorized{err} +} + +type errUnavailable struct{ error } + +func (errUnavailable) Unavailable() {} + +func (e errUnavailable) Cause() error { + return e.error +} + +// Unavailable is a helper to create an error of the class with the same name from any error type +func Unavailable(err error) error { + if err == nil || IsUnavailable(err) { + return err + } + return errUnavailable{err} +} + +type errForbidden struct{ error } + +func (errForbidden) Forbidden() {} + +func (e errForbidden) Cause() error { + return e.error +} + +// Forbidden is a helper to create an error of the class with the same name from any error type +func Forbidden(err error) error { + if err == nil || IsForbidden(err) { + return err + } + return errForbidden{err} +} + +type errSystem struct{ error } + +func (errSystem) System() {} + +func (e errSystem) Cause() error { + return e.error +} + +// System is a helper to create an error of the class with the same name from any error type +func System(err error) error { + if err == nil || IsSystem(err) { + return err + } + return errSystem{err} +} + +type errNotModified struct{ error } + +func (errNotModified) NotModified() {} + +func (e errNotModified) Cause() error { + return e.error +} + +// NotModified is a helper to create an error of the class with the same name from any error type +func NotModified(err error) error { + if err == nil || IsNotModified(err) { + return err + } + return errNotModified{err} +} + +type errNotImplemented struct{ error } + +func (errNotImplemented) NotImplemented() {} + +func (e errNotImplemented) Cause() error { + return e.error +} + +// NotImplemented is a helper to create an error of the class with the same name from any error type +func NotImplemented(err error) error { + if err == nil || IsNotImplemented(err) { + return err + } + return errNotImplemented{err} +} + +type errUnknown struct{ error } + +func (errUnknown) Unknown() {} + +func (e errUnknown) Cause() error { + return e.error +} + +// Unknown is a helper to create an error of the class with the same name from any error type +func Unknown(err error) error { + if err == nil || IsUnknown(err) { + return err + } + return errUnknown{err} +} + +type errCancelled struct{ error } + +func (errCancelled) Cancelled() {} + +func (e errCancelled) Cause() error { + return e.error +} + +// Cancelled is a helper to create an error of the class with the same name from any error type +func Cancelled(err error) error { + if err == nil || IsCancelled(err) { + return err + } + return errCancelled{err} +} + +type errDeadline struct{ error } + +func (errDeadline) DeadlineExceeded() {} + +func (e errDeadline) Cause() error { + return e.error +} + +// Deadline is a helper to create an error of the class with the same name from any error type +func Deadline(err error) error { + if err == nil || IsDeadline(err) { + return err + } + return errDeadline{err} +} + +type errDataLoss struct{ error } + +func (errDataLoss) DataLoss() {} + +func (e errDataLoss) Cause() error { + return e.error +} + +// DataLoss is a helper to create an error of the class with the same name from any error type +func DataLoss(err error) error { + if err == nil || IsDataLoss(err) { + return err + } + return errDataLoss{err} +} + +// FromContext returns the error class from the passed in context +func FromContext(ctx context.Context) error { + e := ctx.Err() + if e == nil { + return nil + } + + if e == context.Canceled { + return Cancelled(e) + } + if e == context.DeadlineExceeded { + return Deadline(e) + } + return Unknown(e) +} diff --git a/vendor/github.com/docker/docker/errdefs/http_helpers.go b/vendor/github.com/docker/docker/errdefs/http_helpers.go new file mode 100644 index 000000000000..ac9bf6d33e67 --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/http_helpers.go @@ -0,0 +1,172 @@ +package errdefs // import "github.com/docker/docker/errdefs" + +import ( + "fmt" + "net/http" + + "github.com/docker/distribution/registry/api/errcode" + "github.com/sirupsen/logrus" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// GetHTTPErrorStatusCode retrieves status code from error message. +func GetHTTPErrorStatusCode(err error) int { + if err == nil { + logrus.WithFields(logrus.Fields{"error": err}).Error("unexpected HTTP error handling") + return http.StatusInternalServerError + } + + var statusCode int + + // Stop right there + // Are you sure you should be adding a new error class here? Do one of the existing ones work? + + // Note that the below functions are already checking the error causal chain for matches. + switch { + case IsNotFound(err): + statusCode = http.StatusNotFound + case IsInvalidParameter(err): + statusCode = http.StatusBadRequest + case IsConflict(err): + statusCode = http.StatusConflict + case IsUnauthorized(err): + statusCode = http.StatusUnauthorized + case IsUnavailable(err): + statusCode = http.StatusServiceUnavailable + case IsForbidden(err): + statusCode = http.StatusForbidden + case IsNotModified(err): + statusCode = http.StatusNotModified + case IsNotImplemented(err): + statusCode = http.StatusNotImplemented + case IsSystem(err) || IsUnknown(err) || IsDataLoss(err) || IsDeadline(err) || IsCancelled(err): + statusCode = http.StatusInternalServerError + default: + statusCode = statusCodeFromGRPCError(err) + if statusCode != http.StatusInternalServerError { + return statusCode + } + statusCode = statusCodeFromDistributionError(err) + if statusCode != http.StatusInternalServerError { + return statusCode + } + if e, ok := err.(causer); ok { + return GetHTTPErrorStatusCode(e.Cause()) + } + + logrus.WithFields(logrus.Fields{ + "module": "api", + "error_type": fmt.Sprintf("%T", err), + }).Debugf("FIXME: Got an API for which error does not match any expected type!!!: %+v", err) + } + + if statusCode == 0 { + statusCode = http.StatusInternalServerError + } + + return statusCode +} + +// FromStatusCode creates an errdef error, based on the provided HTTP status-code +func FromStatusCode(err error, statusCode int) error { + if err == nil { + return err + } + switch statusCode { + case http.StatusNotFound: + err = NotFound(err) + case http.StatusBadRequest: + err = InvalidParameter(err) + case http.StatusConflict: + err = Conflict(err) + case http.StatusUnauthorized: + err = Unauthorized(err) + case http.StatusServiceUnavailable: + err = Unavailable(err) + case http.StatusForbidden: + err = Forbidden(err) + case http.StatusNotModified: + err = NotModified(err) + case http.StatusNotImplemented: + err = NotImplemented(err) + case http.StatusInternalServerError: + if !IsSystem(err) && !IsUnknown(err) && !IsDataLoss(err) && !IsDeadline(err) && !IsCancelled(err) { + err = System(err) + } + default: + logrus.WithFields(logrus.Fields{ + "module": "api", + "status_code": fmt.Sprintf("%d", statusCode), + }).Debugf("FIXME: Got an status-code for which error does not match any expected type!!!: %d", statusCode) + + switch { + case statusCode >= 200 && statusCode < 400: + // it's a client error + case statusCode >= 400 && statusCode < 500: + err = InvalidParameter(err) + case statusCode >= 500 && statusCode < 600: + err = System(err) + default: + err = Unknown(err) + } + } + return err +} + +// statusCodeFromGRPCError returns status code according to gRPC error +func statusCodeFromGRPCError(err error) int { + switch status.Code(err) { + case codes.InvalidArgument: // code 3 + return http.StatusBadRequest + case codes.NotFound: // code 5 + return http.StatusNotFound + case codes.AlreadyExists: // code 6 + return http.StatusConflict + case codes.PermissionDenied: // code 7 + return http.StatusForbidden + case codes.FailedPrecondition: // code 9 + return http.StatusBadRequest + case codes.Unauthenticated: // code 16 + return http.StatusUnauthorized + case codes.OutOfRange: // code 11 + return http.StatusBadRequest + case codes.Unimplemented: // code 12 + return http.StatusNotImplemented + case codes.Unavailable: // code 14 + return http.StatusServiceUnavailable + default: + if e, ok := err.(causer); ok { + return statusCodeFromGRPCError(e.Cause()) + } + // codes.Canceled(1) + // codes.Unknown(2) + // codes.DeadlineExceeded(4) + // codes.ResourceExhausted(8) + // codes.Aborted(10) + // codes.Internal(13) + // codes.DataLoss(15) + return http.StatusInternalServerError + } +} + +// statusCodeFromDistributionError returns status code according to registry errcode +// code is loosely based on errcode.ServeJSON() in docker/distribution +func statusCodeFromDistributionError(err error) int { + switch errs := err.(type) { + case errcode.Errors: + if len(errs) < 1 { + return http.StatusInternalServerError + } + if _, ok := errs[0].(errcode.ErrorCoder); ok { + return statusCodeFromDistributionError(errs[0]) + } + case errcode.ErrorCoder: + return errs.ErrorCode().Descriptor().HTTPStatusCode + default: + if e, ok := err.(causer); ok { + return statusCodeFromDistributionError(e.Cause()) + } + } + return http.StatusInternalServerError +} diff --git a/vendor/github.com/docker/docker/errdefs/is.go b/vendor/github.com/docker/docker/errdefs/is.go new file mode 100644 index 000000000000..3abf07d0c357 --- /dev/null +++ b/vendor/github.com/docker/docker/errdefs/is.go @@ -0,0 +1,107 @@ +package errdefs // import "github.com/docker/docker/errdefs" + +type causer interface { + Cause() error +} + +func getImplementer(err error) error { + switch e := err.(type) { + case + ErrNotFound, + ErrInvalidParameter, + ErrConflict, + ErrUnauthorized, + ErrUnavailable, + ErrForbidden, + ErrSystem, + ErrNotModified, + ErrNotImplemented, + ErrCancelled, + ErrDeadline, + ErrDataLoss, + ErrUnknown: + return err + case causer: + return getImplementer(e.Cause()) + default: + return err + } +} + +// IsNotFound returns if the passed in error is an ErrNotFound +func IsNotFound(err error) bool { + _, ok := getImplementer(err).(ErrNotFound) + return ok +} + +// IsInvalidParameter returns if the passed in error is an ErrInvalidParameter +func IsInvalidParameter(err error) bool { + _, ok := getImplementer(err).(ErrInvalidParameter) + return ok +} + +// IsConflict returns if the passed in error is an ErrConflict +func IsConflict(err error) bool { + _, ok := getImplementer(err).(ErrConflict) + return ok +} + +// IsUnauthorized returns if the passed in error is an ErrUnauthorized +func IsUnauthorized(err error) bool { + _, ok := getImplementer(err).(ErrUnauthorized) + return ok +} + +// IsUnavailable returns if the passed in error is an ErrUnavailable +func IsUnavailable(err error) bool { + _, ok := getImplementer(err).(ErrUnavailable) + return ok +} + +// IsForbidden returns if the passed in error is an ErrForbidden +func IsForbidden(err error) bool { + _, ok := getImplementer(err).(ErrForbidden) + return ok +} + +// IsSystem returns if the passed in error is an ErrSystem +func IsSystem(err error) bool { + _, ok := getImplementer(err).(ErrSystem) + return ok +} + +// IsNotModified returns if the passed in error is a NotModified error +func IsNotModified(err error) bool { + _, ok := getImplementer(err).(ErrNotModified) + return ok +} + +// IsNotImplemented returns if the passed in error is an ErrNotImplemented +func IsNotImplemented(err error) bool { + _, ok := getImplementer(err).(ErrNotImplemented) + return ok +} + +// IsUnknown returns if the passed in error is an ErrUnknown +func IsUnknown(err error) bool { + _, ok := getImplementer(err).(ErrUnknown) + return ok +} + +// IsCancelled returns if the passed in error is an ErrCancelled +func IsCancelled(err error) bool { + _, ok := getImplementer(err).(ErrCancelled) + return ok +} + +// IsDeadline returns if the passed in error is an ErrDeadline +func IsDeadline(err error) bool { + _, ok := getImplementer(err).(ErrDeadline) + return ok +} + +// IsDataLoss returns if the passed in error is an ErrDataLoss +func IsDataLoss(err error) bool { + _, ok := getImplementer(err).(ErrDataLoss) + return ok +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools.go b/vendor/github.com/docker/docker/pkg/idtools/idtools.go new file mode 100644 index 000000000000..230422eac827 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools.go @@ -0,0 +1,267 @@ +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "bufio" + "fmt" + "os" + "sort" + "strconv" + "strings" +) + +// IDMap contains a single entry for user namespace range remapping. An array +// of IDMap entries represents the structure that will be provided to the Linux +// kernel for creating a user namespace. +type IDMap struct { + ContainerID int `json:"container_id"` + HostID int `json:"host_id"` + Size int `json:"size"` +} + +type subIDRange struct { + Start int + Length int +} + +type ranges []subIDRange + +func (e ranges) Len() int { return len(e) } +func (e ranges) Swap(i, j int) { e[i], e[j] = e[j], e[i] } +func (e ranges) Less(i, j int) bool { return e[i].Start < e[j].Start } + +const ( + subuidFileName = "/etc/subuid" + subgidFileName = "/etc/subgid" +) + +// MkdirAllAndChown creates a directory (include any along the path) and then modifies +// ownership to the requested uid/gid. If the directory already exists, this +// function will still change ownership to the requested uid/gid pair. +func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error { + return mkdirAs(path, mode, owner, true, true) +} + +// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid. +// If the directory already exists, this function still changes ownership. +// Note that unlike os.Mkdir(), this function does not return IsExist error +// in case path already exists. +func MkdirAndChown(path string, mode os.FileMode, owner Identity) error { + return mkdirAs(path, mode, owner, false, true) +} + +// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies +// ownership ONLY of newly created directories to the requested uid/gid. If the +// directories along the path exist, no change of ownership will be performed +func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error { + return mkdirAs(path, mode, owner, true, false) +} + +// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps. +// If the maps are empty, then the root uid/gid will default to "real" 0/0 +func GetRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) { + uid, err := toHost(0, uidMap) + if err != nil { + return -1, -1, err + } + gid, err := toHost(0, gidMap) + if err != nil { + return -1, -1, err + } + return uid, gid, nil +} + +// toContainer takes an id mapping, and uses it to translate a +// host ID to the remapped ID. If no map is provided, then the translation +// assumes a 1-to-1 mapping and returns the passed in id +func toContainer(hostID int, idMap []IDMap) (int, error) { + if idMap == nil { + return hostID, nil + } + for _, m := range idMap { + if (hostID >= m.HostID) && (hostID <= (m.HostID + m.Size - 1)) { + contID := m.ContainerID + (hostID - m.HostID) + return contID, nil + } + } + return -1, fmt.Errorf("Host ID %d cannot be mapped to a container ID", hostID) +} + +// toHost takes an id mapping and a remapped ID, and translates the +// ID to the mapped host ID. If no map is provided, then the translation +// assumes a 1-to-1 mapping and returns the passed in id # +func toHost(contID int, idMap []IDMap) (int, error) { + if idMap == nil { + return contID, nil + } + for _, m := range idMap { + if (contID >= m.ContainerID) && (contID <= (m.ContainerID + m.Size - 1)) { + hostID := m.HostID + (contID - m.ContainerID) + return hostID, nil + } + } + return -1, fmt.Errorf("Container ID %d cannot be mapped to a host ID", contID) +} + +// Identity is either a UID and GID pair or a SID (but not both) +type Identity struct { + UID int + GID int + SID string +} + +// IdentityMapping contains a mappings of UIDs and GIDs +type IdentityMapping struct { + uids []IDMap + gids []IDMap +} + +// NewIdentityMapping takes a requested user and group name and +// using the data from /etc/sub{uid,gid} ranges, creates the +// proper uid and gid remapping ranges for that user/group pair +func NewIdentityMapping(username, groupname string) (*IdentityMapping, error) { + subuidRanges, err := parseSubuid(username) + if err != nil { + return nil, err + } + subgidRanges, err := parseSubgid(groupname) + if err != nil { + return nil, err + } + if len(subuidRanges) == 0 { + return nil, fmt.Errorf("No subuid ranges found for user %q", username) + } + if len(subgidRanges) == 0 { + return nil, fmt.Errorf("No subgid ranges found for group %q", groupname) + } + + return &IdentityMapping{ + uids: createIDMap(subuidRanges), + gids: createIDMap(subgidRanges), + }, nil +} + +// NewIDMappingsFromMaps creates a new mapping from two slices +// Deprecated: this is a temporary shim while transitioning to IDMapping +func NewIDMappingsFromMaps(uids []IDMap, gids []IDMap) *IdentityMapping { + return &IdentityMapping{uids: uids, gids: gids} +} + +// RootPair returns a uid and gid pair for the root user. The error is ignored +// because a root user always exists, and the defaults are correct when the uid +// and gid maps are empty. +func (i *IdentityMapping) RootPair() Identity { + uid, gid, _ := GetRootUIDGID(i.uids, i.gids) + return Identity{UID: uid, GID: gid} +} + +// ToHost returns the host UID and GID for the container uid, gid. +// Remapping is only performed if the ids aren't already the remapped root ids +func (i *IdentityMapping) ToHost(pair Identity) (Identity, error) { + var err error + target := i.RootPair() + + if pair.UID != target.UID { + target.UID, err = toHost(pair.UID, i.uids) + if err != nil { + return target, err + } + } + + if pair.GID != target.GID { + target.GID, err = toHost(pair.GID, i.gids) + } + return target, err +} + +// ToContainer returns the container UID and GID for the host uid and gid +func (i *IdentityMapping) ToContainer(pair Identity) (int, int, error) { + uid, err := toContainer(pair.UID, i.uids) + if err != nil { + return -1, -1, err + } + gid, err := toContainer(pair.GID, i.gids) + return uid, gid, err +} + +// Empty returns true if there are no id mappings +func (i *IdentityMapping) Empty() bool { + return len(i.uids) == 0 && len(i.gids) == 0 +} + +// UIDs return the UID mapping +// TODO: remove this once everything has been refactored to use pairs +func (i *IdentityMapping) UIDs() []IDMap { + return i.uids +} + +// GIDs return the UID mapping +// TODO: remove this once everything has been refactored to use pairs +func (i *IdentityMapping) GIDs() []IDMap { + return i.gids +} + +func createIDMap(subidRanges ranges) []IDMap { + idMap := []IDMap{} + + // sort the ranges by lowest ID first + sort.Sort(subidRanges) + containerID := 0 + for _, idrange := range subidRanges { + idMap = append(idMap, IDMap{ + ContainerID: containerID, + HostID: idrange.Start, + Size: idrange.Length, + }) + containerID = containerID + idrange.Length + } + return idMap +} + +func parseSubuid(username string) (ranges, error) { + return parseSubidFile(subuidFileName, username) +} + +func parseSubgid(username string) (ranges, error) { + return parseSubidFile(subgidFileName, username) +} + +// parseSubidFile will read the appropriate file (/etc/subuid or /etc/subgid) +// and return all found ranges for a specified username. If the special value +// "ALL" is supplied for username, then all ranges in the file will be returned +func parseSubidFile(path, username string) (ranges, error) { + var rangeList ranges + + subidFile, err := os.Open(path) + if err != nil { + return rangeList, err + } + defer subidFile.Close() + + s := bufio.NewScanner(subidFile) + for s.Scan() { + if err := s.Err(); err != nil { + return rangeList, err + } + + text := strings.TrimSpace(s.Text()) + if text == "" || strings.HasPrefix(text, "#") { + continue + } + parts := strings.Split(text, ":") + if len(parts) != 3 { + return rangeList, fmt.Errorf("Cannot parse subuid/gid information: Format not correct for %s file", path) + } + if parts[0] == username || username == "ALL" { + startid, err := strconv.Atoi(parts[1]) + if err != nil { + return rangeList, fmt.Errorf("String to int conversion failed during subuid/gid parsing of %s: %v", path, err) + } + length, err := strconv.Atoi(parts[2]) + if err != nil { + return rangeList, fmt.Errorf("String to int conversion failed during subuid/gid parsing of %s: %v", path, err) + } + rangeList = append(rangeList, subIDRange{startid, length}) + } + } + return rangeList, nil +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go b/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go new file mode 100644 index 000000000000..fb239743a01a --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go @@ -0,0 +1,231 @@ +// +build !windows + +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "sync" + "syscall" + + "github.com/docker/docker/pkg/system" + "github.com/opencontainers/runc/libcontainer/user" +) + +var ( + entOnce sync.Once + getentCmd string +) + +func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error { + // make an array containing the original path asked for, plus (for mkAll == true) + // all path components leading up to the complete path that don't exist before we MkdirAll + // so that we can chown all of them properly at the end. If chownExisting is false, we won't + // chown the full directory path if it exists + + var paths []string + + stat, err := system.Stat(path) + if err == nil { + if !stat.IsDir() { + return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR} + } + if !chownExisting { + return nil + } + + // short-circuit--we were called with an existing directory and chown was requested + return lazyChown(path, owner.UID, owner.GID, stat) + } + + if os.IsNotExist(err) { + paths = []string{path} + } + + if mkAll { + // walk back to "/" looking for directories which do not exist + // and add them to the paths array for chown after creation + dirPath := path + for { + dirPath = filepath.Dir(dirPath) + if dirPath == "/" { + break + } + if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) { + paths = append(paths, dirPath) + } + } + if err := system.MkdirAll(path, mode, ""); err != nil { + return err + } + } else { + if err := os.Mkdir(path, mode); err != nil && !os.IsExist(err) { + return err + } + } + // even if it existed, we will chown the requested path + any subpaths that + // didn't exist when we called MkdirAll + for _, pathComponent := range paths { + if err := lazyChown(pathComponent, owner.UID, owner.GID, nil); err != nil { + return err + } + } + return nil +} + +// CanAccess takes a valid (existing) directory and a uid, gid pair and determines +// if that uid, gid pair has access (execute bit) to the directory +func CanAccess(path string, pair Identity) bool { + statInfo, err := system.Stat(path) + if err != nil { + return false + } + fileMode := os.FileMode(statInfo.Mode()) + permBits := fileMode.Perm() + return accessible(statInfo.UID() == uint32(pair.UID), + statInfo.GID() == uint32(pair.GID), permBits) +} + +func accessible(isOwner, isGroup bool, perms os.FileMode) bool { + if isOwner && (perms&0100 == 0100) { + return true + } + if isGroup && (perms&0010 == 0010) { + return true + } + if perms&0001 == 0001 { + return true + } + return false +} + +// LookupUser uses traditional local system files lookup (from libcontainer/user) on a username, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupUser(username string) (user.User, error) { + // first try a local system files lookup using existing capabilities + usr, err := user.LookupUser(username) + if err == nil { + return usr, nil + } + // local files lookup failed; attempt to call `getent` to query configured passwd dbs + usr, err = getentUser(fmt.Sprintf("%s %s", "passwd", username)) + if err != nil { + return user.User{}, err + } + return usr, nil +} + +// LookupUID uses traditional local system files lookup (from libcontainer/user) on a uid, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupUID(uid int) (user.User, error) { + // first try a local system files lookup using existing capabilities + usr, err := user.LookupUid(uid) + if err == nil { + return usr, nil + } + // local files lookup failed; attempt to call `getent` to query configured passwd dbs + return getentUser(fmt.Sprintf("%s %d", "passwd", uid)) +} + +func getentUser(args string) (user.User, error) { + reader, err := callGetent(args) + if err != nil { + return user.User{}, err + } + users, err := user.ParsePasswd(reader) + if err != nil { + return user.User{}, err + } + if len(users) == 0 { + return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", strings.Split(args, " ")[1]) + } + return users[0], nil +} + +// LookupGroup uses traditional local system files lookup (from libcontainer/user) on a group name, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupGroup(groupname string) (user.Group, error) { + // first try a local system files lookup using existing capabilities + group, err := user.LookupGroup(groupname) + if err == nil { + return group, nil + } + // local files lookup failed; attempt to call `getent` to query configured group dbs + return getentGroup(fmt.Sprintf("%s %s", "group", groupname)) +} + +// LookupGID uses traditional local system files lookup (from libcontainer/user) on a group ID, +// followed by a call to `getent` for supporting host configured non-files passwd and group dbs +func LookupGID(gid int) (user.Group, error) { + // first try a local system files lookup using existing capabilities + group, err := user.LookupGid(gid) + if err == nil { + return group, nil + } + // local files lookup failed; attempt to call `getent` to query configured group dbs + return getentGroup(fmt.Sprintf("%s %d", "group", gid)) +} + +func getentGroup(args string) (user.Group, error) { + reader, err := callGetent(args) + if err != nil { + return user.Group{}, err + } + groups, err := user.ParseGroup(reader) + if err != nil { + return user.Group{}, err + } + if len(groups) == 0 { + return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", strings.Split(args, " ")[1]) + } + return groups[0], nil +} + +func callGetent(args string) (io.Reader, error) { + entOnce.Do(func() { getentCmd, _ = resolveBinary("getent") }) + // if no `getent` command on host, can't do anything else + if getentCmd == "" { + return nil, fmt.Errorf("") + } + out, err := execCmd(getentCmd, args) + if err != nil { + exitCode, errC := system.GetExitCode(err) + if errC != nil { + return nil, err + } + switch exitCode { + case 1: + return nil, fmt.Errorf("getent reported invalid parameters/database unknown") + case 2: + terms := strings.Split(args, " ") + return nil, fmt.Errorf("getent unable to find entry %q in %s database", terms[1], terms[0]) + case 3: + return nil, fmt.Errorf("getent database doesn't support enumeration") + default: + return nil, err + } + + } + return bytes.NewReader(out), nil +} + +// lazyChown performs a chown only if the uid/gid don't match what's requested +// Normally a Chown is a no-op if uid/gid match, but in some cases this can still cause an error, e.g. if the +// dir is on an NFS share, so don't call chown unless we absolutely must. +func lazyChown(p string, uid, gid int, stat *system.StatT) error { + if stat == nil { + var err error + stat, err = system.Stat(p) + if err != nil { + return err + } + } + if stat.UID() == uint32(uid) && stat.GID() == uint32(gid) { + return nil + } + return os.Chown(p, uid, gid) +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go b/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go new file mode 100644 index 000000000000..4ae38a1b17bb --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go @@ -0,0 +1,25 @@ +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "os" + + "github.com/docker/docker/pkg/system" +) + +// This is currently a wrapper around MkdirAll, however, since currently +// permissions aren't set through this path, the identity isn't utilized. +// Ownership is handled elsewhere, but in the future could be support here +// too. +func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error { + if err := system.MkdirAll(path, mode, ""); err != nil { + return err + } + return nil +} + +// CanAccess takes a valid (existing) directory and a uid, gid pair and determines +// if that uid, gid pair has access (execute bit) to the directory +// Windows does not require/support this function, so always return true +func CanAccess(path string, identity Identity) bool { + return true +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go new file mode 100644 index 000000000000..6272c5a40471 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go @@ -0,0 +1,164 @@ +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "fmt" + "regexp" + "sort" + "strconv" + "strings" + "sync" +) + +// add a user and/or group to Linux /etc/passwd, /etc/group using standard +// Linux distribution commands: +// adduser --system --shell /bin/false --disabled-login --disabled-password --no-create-home --group +// useradd -r -s /bin/false + +var ( + once sync.Once + userCommand string + + cmdTemplates = map[string]string{ + "adduser": "--system --shell /bin/false --no-create-home --disabled-login --disabled-password --group %s", + "useradd": "-r -s /bin/false %s", + "usermod": "-%s %d-%d %s", + } + + idOutRegexp = regexp.MustCompile(`uid=([0-9]+).*gid=([0-9]+)`) + // default length for a UID/GID subordinate range + defaultRangeLen = 65536 + defaultRangeStart = 100000 + userMod = "usermod" +) + +// AddNamespaceRangesUser takes a username and uses the standard system +// utility to create a system user/group pair used to hold the +// /etc/sub{uid,gid} ranges which will be used for user namespace +// mapping ranges in containers. +func AddNamespaceRangesUser(name string) (int, int, error) { + if err := addUser(name); err != nil { + return -1, -1, fmt.Errorf("Error adding user %q: %v", name, err) + } + + // Query the system for the created uid and gid pair + out, err := execCmd("id", name) + if err != nil { + return -1, -1, fmt.Errorf("Error trying to find uid/gid for new user %q: %v", name, err) + } + matches := idOutRegexp.FindStringSubmatch(strings.TrimSpace(string(out))) + if len(matches) != 3 { + return -1, -1, fmt.Errorf("Can't find uid, gid from `id` output: %q", string(out)) + } + uid, err := strconv.Atoi(matches[1]) + if err != nil { + return -1, -1, fmt.Errorf("Can't convert found uid (%s) to int: %v", matches[1], err) + } + gid, err := strconv.Atoi(matches[2]) + if err != nil { + return -1, -1, fmt.Errorf("Can't convert found gid (%s) to int: %v", matches[2], err) + } + + // Now we need to create the subuid/subgid ranges for our new user/group (system users + // do not get auto-created ranges in subuid/subgid) + + if err := createSubordinateRanges(name); err != nil { + return -1, -1, fmt.Errorf("Couldn't create subordinate ID ranges: %v", err) + } + return uid, gid, nil +} + +func addUser(userName string) error { + once.Do(func() { + // set up which commands are used for adding users/groups dependent on distro + if _, err := resolveBinary("adduser"); err == nil { + userCommand = "adduser" + } else if _, err := resolveBinary("useradd"); err == nil { + userCommand = "useradd" + } + }) + if userCommand == "" { + return fmt.Errorf("Cannot add user; no useradd/adduser binary found") + } + args := fmt.Sprintf(cmdTemplates[userCommand], userName) + out, err := execCmd(userCommand, args) + if err != nil { + return fmt.Errorf("Failed to add user with error: %v; output: %q", err, string(out)) + } + return nil +} + +func createSubordinateRanges(name string) error { + + // first, we should verify that ranges weren't automatically created + // by the distro tooling + ranges, err := parseSubuid(name) + if err != nil { + return fmt.Errorf("Error while looking for subuid ranges for user %q: %v", name, err) + } + if len(ranges) == 0 { + // no UID ranges; let's create one + startID, err := findNextUIDRange() + if err != nil { + return fmt.Errorf("Can't find available subuid range: %v", err) + } + out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "v", startID, startID+defaultRangeLen-1, name)) + if err != nil { + return fmt.Errorf("Unable to add subuid range to user: %q; output: %s, err: %v", name, out, err) + } + } + + ranges, err = parseSubgid(name) + if err != nil { + return fmt.Errorf("Error while looking for subgid ranges for user %q: %v", name, err) + } + if len(ranges) == 0 { + // no GID ranges; let's create one + startID, err := findNextGIDRange() + if err != nil { + return fmt.Errorf("Can't find available subgid range: %v", err) + } + out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "w", startID, startID+defaultRangeLen-1, name)) + if err != nil { + return fmt.Errorf("Unable to add subgid range to user: %q; output: %s, err: %v", name, out, err) + } + } + return nil +} + +func findNextUIDRange() (int, error) { + ranges, err := parseSubuid("ALL") + if err != nil { + return -1, fmt.Errorf("Couldn't parse all ranges in /etc/subuid file: %v", err) + } + sort.Sort(ranges) + return findNextRangeStart(ranges) +} + +func findNextGIDRange() (int, error) { + ranges, err := parseSubgid("ALL") + if err != nil { + return -1, fmt.Errorf("Couldn't parse all ranges in /etc/subgid file: %v", err) + } + sort.Sort(ranges) + return findNextRangeStart(ranges) +} + +func findNextRangeStart(rangeList ranges) (int, error) { + startID := defaultRangeStart + for _, arange := range rangeList { + if wouldOverlap(arange, startID) { + startID = arange.Start + arange.Length + } + } + return startID, nil +} + +func wouldOverlap(arange subIDRange, ID int) bool { + low := ID + high := ID + defaultRangeLen + if (low >= arange.Start && low <= arange.Start+arange.Length) || + (high <= arange.Start+arange.Length && high >= arange.Start) { + return true + } + return false +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go new file mode 100644 index 000000000000..e7c4d63118c3 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go @@ -0,0 +1,12 @@ +// +build !linux + +package idtools // import "github.com/docker/docker/pkg/idtools" + +import "fmt" + +// AddNamespaceRangesUser takes a name and finds an unused uid, gid pair +// and calls the appropriate helper function to add the group and then +// the user to the group in /etc/group and /etc/passwd respectively. +func AddNamespaceRangesUser(name string) (int, int, error) { + return -1, -1, fmt.Errorf("No support for adding users or groups on this OS") +} diff --git a/vendor/github.com/docker/docker/pkg/idtools/utils_unix.go b/vendor/github.com/docker/docker/pkg/idtools/utils_unix.go new file mode 100644 index 000000000000..903ac4501b4b --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/idtools/utils_unix.go @@ -0,0 +1,32 @@ +// +build !windows + +package idtools // import "github.com/docker/docker/pkg/idtools" + +import ( + "fmt" + "os/exec" + "path/filepath" + "strings" +) + +func resolveBinary(binname string) (string, error) { + binaryPath, err := exec.LookPath(binname) + if err != nil { + return "", err + } + resolvedPath, err := filepath.EvalSymlinks(binaryPath) + if err != nil { + return "", err + } + //only return no error if the final resolved binary basename + //matches what was searched for + if filepath.Base(resolvedPath) == binname { + return resolvedPath, nil + } + return "", fmt.Errorf("Binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath) +} + +func execCmd(cmd, args string) ([]byte, error) { + execCmd := exec.Command(cmd, strings.Split(args, " ")...) + return execCmd.CombinedOutput() +} diff --git a/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go b/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go index dd95f367041e..a68b566cea2c 100644 --- a/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go +++ b/vendor/github.com/docker/docker/pkg/jsonmessage/jsonmessage.go @@ -4,13 +4,12 @@ import ( "encoding/json" "fmt" "io" - "os" "strings" "time" - "github.com/Nvveen/Gotty" "github.com/docker/docker/pkg/term" "github.com/docker/go-units" + "github.com/morikuni/aec" ) // RFC3339NanoFixed is time.RFC3339Nano with nanoseconds padded using zeros to @@ -151,60 +150,23 @@ type JSONMessage struct { Aux *json.RawMessage `json:"aux,omitempty"` } -/* Satisfied by gotty.TermInfo as well as noTermInfo from below */ -type termInfo interface { - Parse(attr string, params ...interface{}) (string, error) +func clearLine(out io.Writer) { + eraseMode := aec.EraseModes.All + cl := aec.EraseLine(eraseMode) + fmt.Fprint(out, cl) } -type noTermInfo struct{} // canary used when no terminfo. - -func (ti *noTermInfo) Parse(attr string, params ...interface{}) (string, error) { - return "", fmt.Errorf("noTermInfo") -} - -func clearLine(out io.Writer, ti termInfo) { - // el2 (clear whole line) is not exposed by terminfo. - - // First clear line from beginning to cursor - if attr, err := ti.Parse("el1"); err == nil { - fmt.Fprintf(out, "%s", attr) - } else { - fmt.Fprintf(out, "\x1b[1K") - } - // Then clear line from cursor to end - if attr, err := ti.Parse("el"); err == nil { - fmt.Fprintf(out, "%s", attr) - } else { - fmt.Fprintf(out, "\x1b[K") - } -} - -func cursorUp(out io.Writer, ti termInfo, l int) { - if l == 0 { // Should never be the case, but be tolerant - return - } - if attr, err := ti.Parse("cuu", l); err == nil { - fmt.Fprintf(out, "%s", attr) - } else { - fmt.Fprintf(out, "\x1b[%dA", l) - } +func cursorUp(out io.Writer, l uint) { + fmt.Fprint(out, aec.Up(l)) } -func cursorDown(out io.Writer, ti termInfo, l int) { - if l == 0 { // Should never be the case, but be tolerant - return - } - if attr, err := ti.Parse("cud", l); err == nil { - fmt.Fprintf(out, "%s", attr) - } else { - fmt.Fprintf(out, "\x1b[%dB", l) - } +func cursorDown(out io.Writer, l uint) { + fmt.Fprint(out, aec.Down(l)) } -// Display displays the JSONMessage to `out`. `termInfo` is non-nil if `out` -// is a terminal. If this is the case, it will erase the entire current line -// when displaying the progressbar. -func (jm *JSONMessage) Display(out io.Writer, termInfo termInfo) error { +// Display displays the JSONMessage to `out`. If `isTerminal` is true, it will erase the +// entire current line when displaying the progressbar. +func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error { if jm.Error != nil { if jm.Error.Code == 401 { return fmt.Errorf("authentication is required") @@ -212,8 +174,8 @@ func (jm *JSONMessage) Display(out io.Writer, termInfo termInfo) error { return jm.Error } var endl string - if termInfo != nil && jm.Stream == "" && jm.Progress != nil { - clearLine(out, termInfo) + if isTerminal && jm.Stream == "" && jm.Progress != nil { + clearLine(out) endl = "\r" fmt.Fprintf(out, endl) } else if jm.Progress != nil && jm.Progress.String() != "" { //disable progressbar in non-terminal @@ -230,7 +192,7 @@ func (jm *JSONMessage) Display(out io.Writer, termInfo termInfo) error { if jm.From != "" { fmt.Fprintf(out, "(from %s) ", jm.From) } - if jm.Progress != nil && termInfo != nil { + if jm.Progress != nil && isTerminal { fmt.Fprintf(out, "%s %s%s", jm.Status, jm.Progress.String(), endl) } else if jm.ProgressMessage != "" { //deprecated fmt.Fprintf(out, "%s %s%s", jm.Status, jm.ProgressMessage, endl) @@ -248,25 +210,11 @@ func (jm *JSONMessage) Display(out io.Writer, termInfo termInfo) error { func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, isTerminal bool, auxCallback func(JSONMessage)) error { var ( dec = json.NewDecoder(in) - ids = make(map[string]int) + ids = make(map[string]uint) ) - var termInfo termInfo - - if isTerminal { - term := os.Getenv("TERM") - if term == "" { - term = "vt102" - } - - var err error - if termInfo, err = gotty.OpenTermInfo(term); err != nil { - termInfo = &noTermInfo{} - } - } - for { - diff := 0 + var diff uint var jm JSONMessage if err := dec.Decode(&jm); err != nil { if err == io.EOF { @@ -294,15 +242,15 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, // when we output something that's not // accounted for in the map, such as a line // with no ID. - line = len(ids) + line = uint(len(ids)) ids[jm.ID] = line - if termInfo != nil { + if isTerminal { fmt.Fprintf(out, "\n") } } - diff = len(ids) - line - if termInfo != nil { - cursorUp(out, termInfo, diff) + diff = uint(len(ids)) - line + if isTerminal { + cursorUp(out, diff) } } else { // When outputting something that isn't progress @@ -310,11 +258,11 @@ func DisplayJSONMessagesStream(in io.Reader, out io.Writer, terminalFd uintptr, // don't want progress entries from some previous // operation to be updated (for example, pull -a // with multiple tags). - ids = make(map[string]int) + ids = make(map[string]uint) } - err := jm.Display(out, termInfo) - if jm.ID != "" && termInfo != nil { - cursorDown(out, termInfo, diff) + err := jm.Display(out, isTerminal) + if jm.ID != "" && isTerminal { + cursorDown(out, diff) } if err != nil { return err diff --git a/vendor/github.com/docker/docker/pkg/mount/flags.go b/vendor/github.com/docker/docker/pkg/mount/flags.go index 272363b68540..ffd473311dac 100644 --- a/vendor/github.com/docker/docker/pkg/mount/flags.go +++ b/vendor/github.com/docker/docker/pkg/mount/flags.go @@ -135,15 +135,3 @@ func parseOptions(options string) (int, string) { } return flag, strings.Join(data, ",") } - -// ParseTmpfsOptions parse fstab type mount options into flags and data -func ParseTmpfsOptions(options string) (int, string, error) { - flags, data := parseOptions(options) - for _, o := range strings.Split(data, ",") { - opt := strings.SplitN(o, "=", 2) - if !validFlags[opt[0]] { - return 0, "", fmt.Errorf("Invalid tmpfs option %q", opt) - } - } - return flags, data, nil -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mount.go b/vendor/github.com/docker/docker/pkg/mount/mount.go index 874aff6545cc..4afd63c427b3 100644 --- a/vendor/github.com/docker/docker/pkg/mount/mount.go +++ b/vendor/github.com/docker/docker/pkg/mount/mount.go @@ -2,12 +2,46 @@ package mount // import "github.com/docker/docker/pkg/mount" import ( "sort" + "strconv" "strings" - "syscall" "github.com/sirupsen/logrus" ) +// mountError records an error from mount or unmount operation +type mountError struct { + op string + source, target string + flags uintptr + data string + err error +} + +func (e *mountError) Error() string { + out := e.op + " " + + if e.source != "" { + out += e.source + ":" + e.target + } else { + out += e.target + } + + if e.flags != uintptr(0) { + out += ", flags: 0x" + strconv.FormatUint(uint64(e.flags), 16) + } + if e.data != "" { + out += ", data: " + e.data + } + + out += ": " + e.err.Error() + return out +} + +// Cause returns the underlying cause of the error +func (e *mountError) Cause() error { + return e.err +} + // FilterFunc is a type defining a callback function // to filter out unwanted entries. It takes a pointer // to an Info struct (not fully populated, currently @@ -89,12 +123,7 @@ func ForceMount(device, target, mType, options string) error { // Unmount lazily unmounts a filesystem on supported platforms, otherwise // does a normal unmount. func Unmount(target string) error { - err := unmount(target, mntDetach) - if err == syscall.EINVAL { - // ignore "not mounted" error - err = nil - } - return err + return unmount(target, mntDetach) } // RecursiveUnmount unmounts the target and all mounts underneath, starting with @@ -114,25 +143,14 @@ func RecursiveUnmount(target string) error { logrus.Debugf("Trying to unmount %s", m.Mountpoint) err = unmount(m.Mountpoint, mntDetach) if err != nil { - // If the error is EINVAL either this whole package is wrong (invalid flags passed to unmount(2)) or this is - // not a mountpoint (which is ok in this case). - // Meanwhile calling `Mounted()` is very expensive. - // - // We've purposefully used `syscall.EINVAL` here instead of `unix.EINVAL` to avoid platform branching - // Since `EINVAL` is defined for both Windows and Linux in the `syscall` package (and other platforms), - // this is nicer than defining a custom value that we can refer to in each platform file. - if err == syscall.EINVAL { - continue - } - if i == len(mounts)-1 { + if i == len(mounts)-1 { // last mount if mounted, e := Mounted(m.Mountpoint); e != nil || mounted { return err } - continue + } else { + // This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem + logrus.WithError(err).Warnf("Failed to unmount submount %s", m.Mountpoint) } - // This is some submount, we can ignore this error for now, the final unmount will fail if this is a real problem - logrus.WithError(err).Warnf("Failed to unmount submount %s", m.Mountpoint) - continue } logrus.Debugf("Unmounted %s", m.Mountpoint) diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go b/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go index b6ab83a23079..09ad36060830 100644 --- a/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go +++ b/vendor/github.com/docker/docker/pkg/mount/mounter_freebsd.go @@ -11,11 +11,9 @@ package mount // import "github.com/docker/docker/pkg/mount" import "C" import ( - "fmt" "strings" + "syscall" "unsafe" - - "golang.org/x/sys/unix" ) func allocateIOVecs(options []string) []C.struct_iovec { @@ -49,12 +47,13 @@ func mount(device, target, mType string, flag uintptr, data string) error { } if errno := C.nmount(&rawOptions[0], C.uint(len(options)), C.int(flag)); errno != 0 { - reason := C.GoString(C.strerror(*C.__error())) - return fmt.Errorf("Failed to call nmount: %s", reason) + return &mountError{ + op: "mount", + source: device, + target: target, + flags: flag, + err: syscall.Errno(errno), + } } return nil } - -func unmount(target string, flag int) error { - return unix.Unmount(target, flag) -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go b/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go index 631daf10a5ab..a0a1ad2364a1 100644 --- a/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go +++ b/vendor/github.com/docker/docker/pkg/mount/mounter_linux.go @@ -33,25 +33,41 @@ func mount(device, target, mType string, flags uintptr, data string) error { // Initial call applying all non-propagation flags for mount // or remount with changed data if err := unix.Mount(device, target, mType, oflags, data); err != nil { - return err + return &mountError{ + op: "mount", + source: device, + target: target, + flags: oflags, + data: data, + err: err, + } } } if flags&ptypes != 0 { // Change the propagation type. if err := unix.Mount("", target, "", flags&pflags, ""); err != nil { - return err + return &mountError{ + op: "remount", + target: target, + flags: flags & pflags, + err: err, + } } } if oflags&broflags == broflags { // Remount the bind to apply read only. - return unix.Mount("", target, "", oflags|unix.MS_REMOUNT, "") + if err := unix.Mount("", target, "", oflags|unix.MS_REMOUNT, ""); err != nil { + return &mountError{ + op: "remount-ro", + target: target, + flags: oflags | unix.MS_REMOUNT, + err: err, + } + + } } return nil } - -func unmount(target string, flag int) error { - return unix.Unmount(target, flag) -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go index 1428dffa5296..c3e5aec27448 100644 --- a/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go +++ b/vendor/github.com/docker/docker/pkg/mount/mounter_unsupported.go @@ -5,7 +5,3 @@ package mount // import "github.com/docker/docker/pkg/mount" func mount(device, target, mType string, flag uintptr, data string) error { panic("Not implemented") } - -func unmount(target string, flag int) error { - panic("Not implemented") -} diff --git a/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go b/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go index c1dba01fc31c..fe6e3ddba132 100644 --- a/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go +++ b/vendor/github.com/docker/docker/pkg/mount/mountinfo_linux.go @@ -7,16 +7,21 @@ import ( "os" "strconv" "strings" + + "github.com/pkg/errors" ) func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) { s := bufio.NewScanner(r) out := []*Info{} + var err error for s.Scan() { - if err := s.Err(); err != nil { + if err = s.Err(); err != nil { return nil, err } /* + See http://man7.org/linux/man-pages/man5/proc.5.html + 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue (1)(2)(3) (4) (5) (6) (7) (8) (9) (10) (11) @@ -52,8 +57,15 @@ func parseInfoFile(r io.Reader, filter FilterFunc) ([]*Info, error) { p.Major, _ = strconv.Atoi(mm[0]) p.Minor, _ = strconv.Atoi(mm[1]) - p.Root = fields[3] - p.Mountpoint = fields[4] + p.Root, err = strconv.Unquote(`"` + fields[3] + `"`) + if err != nil { + return nil, errors.Wrapf(err, "Parsing '%s' failed: unable to unquote root field", fields[3]) + } + + p.Mountpoint, err = strconv.Unquote(`"` + fields[4] + `"`) + if err != nil { + return nil, errors.Wrapf(err, "Parsing '%s' failed: unable to unquote mount point field", fields[4]) + } p.Opts = fields[5] var skip, stop bool diff --git a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go b/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go index 538f6637a043..8a100f0bc85a 100644 --- a/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go +++ b/vendor/github.com/docker/docker/pkg/mount/sharedsubtree_linux.go @@ -48,18 +48,22 @@ func MakeRUnbindable(mountPoint string) error { return ensureMountedAs(mountPoint, "runbindable") } -func ensureMountedAs(mountPoint, options string) error { - mounted, err := Mounted(mountPoint) +// MakeMount ensures that the file or directory given is a mount point, +// bind mounting it to itself it case it is not. +func MakeMount(mnt string) error { + mounted, err := Mounted(mnt) if err != nil { return err } - - if !mounted { - if err := Mount(mountPoint, mountPoint, "none", "bind,rw"); err != nil { - return err - } + if mounted { + return nil } - if _, err = Mounted(mountPoint); err != nil { + + return Mount(mnt, mnt, "none", "bind") +} + +func ensureMountedAs(mountPoint, options string) error { + if err := MakeMount(mountPoint); err != nil { return err } diff --git a/vendor/github.com/docker/docker/pkg/mount/unmount_unix.go b/vendor/github.com/docker/docker/pkg/mount/unmount_unix.go new file mode 100644 index 000000000000..4be4276851f5 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/unmount_unix.go @@ -0,0 +1,22 @@ +// +build !windows + +package mount // import "github.com/docker/docker/pkg/mount" + +import "golang.org/x/sys/unix" + +func unmount(target string, flags int) error { + err := unix.Unmount(target, flags) + if err == nil || err == unix.EINVAL { + // Ignore "not mounted" error here. Note the same error + // can be returned if flags are invalid, so this code + // assumes that the flags value is always correct. + return nil + } + + return &mountError{ + op: "umount", + target: target, + flags: uintptr(flags), + err: err, + } +} diff --git a/vendor/github.com/docker/docker/pkg/mount/unmount_unsupported.go b/vendor/github.com/docker/docker/pkg/mount/unmount_unsupported.go new file mode 100644 index 000000000000..a88ad35774ab --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/mount/unmount_unsupported.go @@ -0,0 +1,7 @@ +// +build windows + +package mount // import "github.com/docker/docker/pkg/mount" + +func unmount(target string, flag int) error { + panic("Not implemented") +} diff --git a/vendor/github.com/docker/docker/pkg/parsers/parsers.go b/vendor/github.com/docker/docker/pkg/parsers/parsers.go index c4186a4c0a51..068e52480746 100644 --- a/vendor/github.com/docker/docker/pkg/parsers/parsers.go +++ b/vendor/github.com/docker/docker/pkg/parsers/parsers.go @@ -18,6 +18,24 @@ func ParseKeyValueOpt(opt string) (string, string, error) { return strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]), nil } +// ParseUintListMaximum parses and validates the specified string as the value +// found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be +// one of the formats below. Note that duplicates are actually allowed in the +// input string. It returns a `map[int]bool` with available elements from `val` +// set to `true`. Values larger than `maximum` cause an error if max is non zero, +// in order to stop the map becoming excessively large. +// Supported formats: +// 7 +// 1-6 +// 0,3-4,7,8-10 +// 0-0,0,1-7 +// 03,1-3 <- this is gonna get parsed as [1,2,3] +// 3,2,1 +// 0-2,3,1 +func ParseUintListMaximum(val string, maximum int) (map[int]bool, error) { + return parseUintList(val, maximum) +} + // ParseUintList parses and validates the specified string as the value // found in some cgroup file (e.g. `cpuset.cpus`, `cpuset.mems`), which could be // one of the formats below. Note that duplicates are actually allowed in the @@ -32,6 +50,10 @@ func ParseKeyValueOpt(opt string) (string, string, error) { // 3,2,1 // 0-2,3,1 func ParseUintList(val string) (map[int]bool, error) { + return parseUintList(val, 0) +} + +func parseUintList(val string, maximum int) (map[int]bool, error) { if val == "" { return map[int]bool{}, nil } @@ -46,6 +68,9 @@ func ParseUintList(val string) (map[int]bool, error) { if err != nil { return nil, errInvalidFormat } + if maximum != 0 && v > maximum { + return nil, fmt.Errorf("value of out range, maximum is %d", maximum) + } availableInts[v] = true } else { split := strings.SplitN(r, "-", 2) @@ -60,6 +85,9 @@ func ParseUintList(val string) (map[int]bool, error) { if max < min { return nil, errInvalidFormat } + if maximum != 0 && max > maximum { + return nil, fmt.Errorf("value of out range, maximum is %d", maximum) + } for i := min; i <= max; i++ { availableInts[i] = true } diff --git a/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go b/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go index 09fb4b2d2930..e7eed24240c6 100644 --- a/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go +++ b/vendor/github.com/docker/docker/pkg/reexec/command_unsupported.go @@ -6,6 +6,10 @@ import ( "os/exec" ) +func Self() string { + return "" +} + // Command is unsupported on operating systems apart from Linux, Windows, and Darwin. func Command(args ...string) *exec.Cmd { return nil diff --git a/vendor/github.com/docker/docker/pkg/signal/signal_linux.go b/vendor/github.com/docker/docker/pkg/signal/signal_linux.go index caed97c963e2..4013bded1361 100644 --- a/vendor/github.com/docker/docker/pkg/signal/signal_linux.go +++ b/vendor/github.com/docker/docker/pkg/signal/signal_linux.go @@ -1,3 +1,5 @@ +// +build !mips,!mipsle,!mips64,!mips64le + package signal // import "github.com/docker/docker/pkg/signal" import ( diff --git a/vendor/github.com/docker/docker/pkg/signal/signal_linux_mipsx.go b/vendor/github.com/docker/docker/pkg/signal/signal_linux_mipsx.go new file mode 100644 index 000000000000..4c7989121607 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/signal/signal_linux_mipsx.go @@ -0,0 +1,84 @@ +// +build linux +// +build mips mipsle mips64 mips64le + +package signal // import "github.com/docker/docker/pkg/signal" + +import ( + "syscall" + + "golang.org/x/sys/unix" +) + +const ( + sigrtmin = 34 + sigrtmax = 127 +) + +// SignalMap is a map of Linux signals. +var SignalMap = map[string]syscall.Signal{ + "ABRT": unix.SIGABRT, + "ALRM": unix.SIGALRM, + "BUS": unix.SIGBUS, + "CHLD": unix.SIGCHLD, + "CLD": unix.SIGCLD, + "CONT": unix.SIGCONT, + "FPE": unix.SIGFPE, + "HUP": unix.SIGHUP, + "ILL": unix.SIGILL, + "INT": unix.SIGINT, + "IO": unix.SIGIO, + "IOT": unix.SIGIOT, + "KILL": unix.SIGKILL, + "PIPE": unix.SIGPIPE, + "POLL": unix.SIGPOLL, + "PROF": unix.SIGPROF, + "PWR": unix.SIGPWR, + "QUIT": unix.SIGQUIT, + "SEGV": unix.SIGSEGV, + "SIGEMT": unix.SIGEMT, + "STOP": unix.SIGSTOP, + "SYS": unix.SIGSYS, + "TERM": unix.SIGTERM, + "TRAP": unix.SIGTRAP, + "TSTP": unix.SIGTSTP, + "TTIN": unix.SIGTTIN, + "TTOU": unix.SIGTTOU, + "URG": unix.SIGURG, + "USR1": unix.SIGUSR1, + "USR2": unix.SIGUSR2, + "VTALRM": unix.SIGVTALRM, + "WINCH": unix.SIGWINCH, + "XCPU": unix.SIGXCPU, + "XFSZ": unix.SIGXFSZ, + "RTMIN": sigrtmin, + "RTMIN+1": sigrtmin + 1, + "RTMIN+2": sigrtmin + 2, + "RTMIN+3": sigrtmin + 3, + "RTMIN+4": sigrtmin + 4, + "RTMIN+5": sigrtmin + 5, + "RTMIN+6": sigrtmin + 6, + "RTMIN+7": sigrtmin + 7, + "RTMIN+8": sigrtmin + 8, + "RTMIN+9": sigrtmin + 9, + "RTMIN+10": sigrtmin + 10, + "RTMIN+11": sigrtmin + 11, + "RTMIN+12": sigrtmin + 12, + "RTMIN+13": sigrtmin + 13, + "RTMIN+14": sigrtmin + 14, + "RTMIN+15": sigrtmin + 15, + "RTMAX-14": sigrtmax - 14, + "RTMAX-13": sigrtmax - 13, + "RTMAX-12": sigrtmax - 12, + "RTMAX-11": sigrtmax - 11, + "RTMAX-10": sigrtmax - 10, + "RTMAX-9": sigrtmax - 9, + "RTMAX-8": sigrtmax - 8, + "RTMAX-7": sigrtmax - 7, + "RTMAX-6": sigrtmax - 6, + "RTMAX-5": sigrtmax - 5, + "RTMAX-4": sigrtmax - 4, + "RTMAX-3": sigrtmax - 3, + "RTMAX-2": sigrtmax - 2, + "RTMAX-1": sigrtmax - 1, + "RTMAX": sigrtmax, +} diff --git a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE index b9fbf3c98fb5..5d80670bc0f8 100644 --- a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE +++ b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.APACHE @@ -176,7 +176,7 @@ END OF TERMS AND CONDITIONS - Copyright 2014-2017 Docker, Inc. + Copyright 2014-2018 Docker, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD index 4c056c5ed277..2ee8768d3156 100644 --- a/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD +++ b/vendor/github.com/docker/docker/pkg/symlink/LICENSE.BSD @@ -1,4 +1,4 @@ -Copyright (c) 2014-2017 The Docker & Go Authors. All rights reserved. +Copyright (c) 2014-2018 The Docker & Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go index 8fc0ecc25e6b..5fa5a5628c0d 100644 --- a/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go +++ b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo.go @@ -47,6 +47,9 @@ type cgroupMemInfo struct { // Whether kernel memory limit is supported or not KernelMemory bool + + // Whether kernel memory TCP limit is supported or not + KernelMemoryTCP bool } type cgroupCPUInfo struct { @@ -117,11 +120,19 @@ func (c cgroupCpusetInfo) IsCpusetMemsAvailable(provided string) (bool, error) { } func isCpusetListAvailable(provided, available string) (bool, error) { - parsedProvided, err := parsers.ParseUintList(provided) + parsedAvailable, err := parsers.ParseUintList(available) if err != nil { return false, err } - parsedAvailable, err := parsers.ParseUintList(available) + // 8192 is the normal maximum number of CPUs in Linux, so accept numbers up to this + // or more if we actually have more CPUs. + max := 8192 + for m := range parsedAvailable { + if m > max { + max = m + } + } + parsedProvided, err := parsers.ParseUintListMaximum(provided, max) if err != nil { return false, err } diff --git a/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go index dde5be19bc67..7b36d6d13075 100644 --- a/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go +++ b/vendor/github.com/docker/docker/pkg/sysinfo/sysinfo_linux.go @@ -26,218 +26,241 @@ func findCgroupMountpoints() (map[string]string, error) { return mps, nil } +type infoCollector func(info *SysInfo, cgMounts map[string]string) (warnings []string) + // New returns a new SysInfo, using the filesystem to detect which features // the kernel supports. If `quiet` is `false` warnings are printed in logs // whenever an error occurs or misconfigurations are present. func New(quiet bool) *SysInfo { + var ops []infoCollector + var warnings []string sysInfo := &SysInfo{} cgMounts, err := findCgroupMountpoints() if err != nil { - logrus.Warnf("Failed to parse cgroup information: %v", err) + logrus.Warn(err) } else { - sysInfo.cgroupMemInfo = checkCgroupMem(cgMounts, quiet) - sysInfo.cgroupCPUInfo = checkCgroupCPU(cgMounts, quiet) - sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet) - sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet) - sysInfo.cgroupPids = checkCgroupPids(quiet) - } - - _, ok := cgMounts["devices"] - sysInfo.CgroupDevicesEnabled = ok - - sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward") - sysInfo.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables") - sysInfo.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables") - - // Check if AppArmor is supported. - if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { - sysInfo.AppArmor = true - } - - // Check if Seccomp is supported, via CONFIG_SECCOMP. - if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL { - // Make sure the kernel has CONFIG_SECCOMP_FILTER. - if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL { - sysInfo.Seccomp = true + ops = append(ops, []infoCollector{ + applyMemoryCgroupInfo, + applyCPUCgroupInfo, + applyBlkioCgroupInfo, + applyCPUSetCgroupInfo, + applyPIDSCgroupInfo, + applyDevicesCgroupInfo, + }...) + } + + ops = append(ops, []infoCollector{ + applyNetworkingInfo, + applyAppArmorInfo, + applySeccompInfo, + }...) + + for _, o := range ops { + w := o(sysInfo, cgMounts) + warnings = append(warnings, w...) + } + if !quiet { + for _, w := range warnings { + logrus.Warn(w) } } - return sysInfo } -// checkCgroupMem reads the memory information from the memory cgroup mount point. -func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo { +// applyMemoryCgroupInfo reads the memory information from the memory cgroup mount point. +func applyMemoryCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { + var warnings []string mountPoint, ok := cgMounts["memory"] if !ok { - if !quiet { - logrus.Warn("Your kernel does not support cgroup memory limit") - } - return cgroupMemInfo{} + warnings = append(warnings, "Your kernel does not support cgroup memory limit") + return warnings } + info.MemoryLimit = ok - swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes") - if !quiet && !swapLimit { - logrus.Warn("Your kernel does not support swap memory limit") + info.SwapLimit = cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes") + if !info.SwapLimit { + warnings = append(warnings, "Your kernel does not support swap memory limit") } - memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes") - if !quiet && !memoryReservation { - logrus.Warn("Your kernel does not support memory reservation") + info.MemoryReservation = cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes") + if !info.MemoryReservation { + warnings = append(warnings, "Your kernel does not support memory reservation") } - oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control") - if !quiet && !oomKillDisable { - logrus.Warn("Your kernel does not support oom control") + info.OomKillDisable = cgroupEnabled(mountPoint, "memory.oom_control") + if !info.OomKillDisable { + warnings = append(warnings, "Your kernel does not support oom control") } - memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness") - if !quiet && !memorySwappiness { - logrus.Warn("Your kernel does not support memory swappiness") + info.MemorySwappiness = cgroupEnabled(mountPoint, "memory.swappiness") + if !info.MemorySwappiness { + warnings = append(warnings, "Your kernel does not support memory swappiness") } - kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes") - if !quiet && !kernelMemory { - logrus.Warn("Your kernel does not support kernel memory limit") + info.KernelMemory = cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes") + if !info.KernelMemory { + warnings = append(warnings, "Your kernel does not support kernel memory limit") } - - return cgroupMemInfo{ - MemoryLimit: true, - SwapLimit: swapLimit, - MemoryReservation: memoryReservation, - OomKillDisable: oomKillDisable, - MemorySwappiness: memorySwappiness, - KernelMemory: kernelMemory, + info.KernelMemoryTCP = cgroupEnabled(mountPoint, "memory.kmem.tcp.limit_in_bytes") + if !info.KernelMemoryTCP { + warnings = append(warnings, "Your kernel does not support kernel memory TCP limit") } + + return warnings } -// checkCgroupCPU reads the cpu information from the cpu cgroup mount point. -func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo { +// applyCPUCgroupInfo reads the cpu information from the cpu cgroup mount point. +func applyCPUCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { + var warnings []string mountPoint, ok := cgMounts["cpu"] if !ok { - if !quiet { - logrus.Warn("Unable to find cpu cgroup in mounts") - } - return cgroupCPUInfo{} + warnings = append(warnings, "Unable to find cpu cgroup in mounts") + return warnings } - cpuShares := cgroupEnabled(mountPoint, "cpu.shares") - if !quiet && !cpuShares { - logrus.Warn("Your kernel does not support cgroup cpu shares") + info.CPUShares = cgroupEnabled(mountPoint, "cpu.shares") + if !info.CPUShares { + warnings = append(warnings, "Your kernel does not support cgroup cpu shares") } - cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us") - if !quiet && !cpuCfsPeriod { - logrus.Warn("Your kernel does not support cgroup cfs period") + info.CPUCfsPeriod = cgroupEnabled(mountPoint, "cpu.cfs_period_us") + if !info.CPUCfsPeriod { + warnings = append(warnings, "Your kernel does not support cgroup cfs period") } - cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us") - if !quiet && !cpuCfsQuota { - logrus.Warn("Your kernel does not support cgroup cfs quotas") + info.CPUCfsQuota = cgroupEnabled(mountPoint, "cpu.cfs_quota_us") + if !info.CPUCfsQuota { + warnings = append(warnings, "Your kernel does not support cgroup cfs quotas") } - cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us") - if !quiet && !cpuRealtimePeriod { - logrus.Warn("Your kernel does not support cgroup rt period") + info.CPURealtimePeriod = cgroupEnabled(mountPoint, "cpu.rt_period_us") + if !info.CPURealtimePeriod { + warnings = append(warnings, "Your kernel does not support cgroup rt period") } - cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us") - if !quiet && !cpuRealtimeRuntime { - logrus.Warn("Your kernel does not support cgroup rt runtime") + info.CPURealtimeRuntime = cgroupEnabled(mountPoint, "cpu.rt_runtime_us") + if !info.CPURealtimeRuntime { + warnings = append(warnings, "Your kernel does not support cgroup rt runtime") } - return cgroupCPUInfo{ - CPUShares: cpuShares, - CPUCfsPeriod: cpuCfsPeriod, - CPUCfsQuota: cpuCfsQuota, - CPURealtimePeriod: cpuRealtimePeriod, - CPURealtimeRuntime: cpuRealtimeRuntime, - } + return warnings } -// checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point. -func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo { +// applyBlkioCgroupInfo reads the blkio information from the blkio cgroup mount point. +func applyBlkioCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { + var warnings []string mountPoint, ok := cgMounts["blkio"] if !ok { - if !quiet { - logrus.Warn("Unable to find blkio cgroup in mounts") - } - return cgroupBlkioInfo{} + warnings = append(warnings, "Unable to find blkio cgroup in mounts") + return warnings } - weight := cgroupEnabled(mountPoint, "blkio.weight") - if !quiet && !weight { - logrus.Warn("Your kernel does not support cgroup blkio weight") + info.BlkioWeight = cgroupEnabled(mountPoint, "blkio.weight") + if !info.BlkioWeight { + warnings = append(warnings, "Your kernel does not support cgroup blkio weight") } - weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device") - if !quiet && !weightDevice { - logrus.Warn("Your kernel does not support cgroup blkio weight_device") + info.BlkioWeightDevice = cgroupEnabled(mountPoint, "blkio.weight_device") + if !info.BlkioWeightDevice { + warnings = append(warnings, "Your kernel does not support cgroup blkio weight_device") } - readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device") - if !quiet && !readBpsDevice { - logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device") + info.BlkioReadBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device") + if !info.BlkioReadBpsDevice { + warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.read_bps_device") } - writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device") - if !quiet && !writeBpsDevice { - logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device") + info.BlkioWriteBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device") + if !info.BlkioWriteBpsDevice { + warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.write_bps_device") } - readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device") - if !quiet && !readIOpsDevice { - logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device") + info.BlkioReadIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device") + if !info.BlkioReadIOpsDevice { + warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.read_iops_device") } - writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device") - if !quiet && !writeIOpsDevice { - logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device") - } - return cgroupBlkioInfo{ - BlkioWeight: weight, - BlkioWeightDevice: weightDevice, - BlkioReadBpsDevice: readBpsDevice, - BlkioWriteBpsDevice: writeBpsDevice, - BlkioReadIOpsDevice: readIOpsDevice, - BlkioWriteIOpsDevice: writeIOpsDevice, + info.BlkioWriteIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device") + if !info.BlkioWriteIOpsDevice { + warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.write_iops_device") } + + return warnings } -// checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point. -func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo { +// applyCPUSetCgroupInfo reads the cpuset information from the cpuset cgroup mount point. +func applyCPUSetCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { + var warnings []string mountPoint, ok := cgMounts["cpuset"] if !ok { - if !quiet { - logrus.Warn("Unable to find cpuset cgroup in mounts") - } - return cgroupCpusetInfo{} + warnings = append(warnings, "Unable to find cpuset cgroup in mounts") + return warnings } + info.Cpuset = ok + + var err error cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus")) if err != nil { - return cgroupCpusetInfo{} + return warnings } + info.Cpus = strings.TrimSpace(string(cpus)) mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems")) if err != nil { - return cgroupCpusetInfo{} + return warnings } + info.Mems = strings.TrimSpace(string(mems)) - return cgroupCpusetInfo{ - Cpuset: true, - Cpus: strings.TrimSpace(string(cpus)), - Mems: strings.TrimSpace(string(mems)), - } + return warnings } -// checkCgroupPids reads the pids information from the pids cgroup mount point. -func checkCgroupPids(quiet bool) cgroupPids { - _, err := cgroups.FindCgroupMountpoint("pids") +// applyPIDSCgroupInfo reads the pids information from the pids cgroup mount point. +func applyPIDSCgroupInfo(info *SysInfo, _ map[string]string) []string { + var warnings []string + _, err := cgroups.FindCgroupMountpoint("", "pids") if err != nil { - if !quiet { - logrus.Warn(err) + warnings = append(warnings, err.Error()) + return warnings + } + info.PidsLimit = true + return warnings +} + +// applyDevicesCgroupInfo reads the pids information from the devices cgroup mount point. +func applyDevicesCgroupInfo(info *SysInfo, cgMounts map[string]string) []string { + var warnings []string + _, ok := cgMounts["devices"] + info.CgroupDevicesEnabled = ok + return warnings +} + +// applyNetworkingInfo adds networking information to the info. +func applyNetworkingInfo(info *SysInfo, _ map[string]string) []string { + var warnings []string + info.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward") + info.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables") + info.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables") + return warnings +} + +// applyAppArmorInfo adds AppArmor information to the info. +func applyAppArmorInfo(info *SysInfo, _ map[string]string) []string { + var warnings []string + if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { + if _, err := ioutil.ReadFile("/sys/kernel/security/apparmor/profiles"); err == nil { + info.AppArmor = true } - return cgroupPids{} } + return warnings +} - return cgroupPids{ - PidsLimit: true, +// applySeccompInfo checks if Seccomp is supported, via CONFIG_SECCOMP. +func applySeccompInfo(info *SysInfo, _ map[string]string) []string { + var warnings []string + // Check if Seccomp is supported, via CONFIG_SECCOMP. + if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL { + // Make sure the kernel has CONFIG_SECCOMP_FILTER. + if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL { + info.Seccomp = true + } } + return warnings } func cgroupEnabled(mountPoint, name string) bool { diff --git a/vendor/github.com/docker/docker/pkg/system/args_windows.go b/vendor/github.com/docker/docker/pkg/system/args_windows.go new file mode 100644 index 000000000000..b7c9487a0674 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/args_windows.go @@ -0,0 +1,16 @@ +package system // import "github.com/docker/docker/pkg/system" + +import ( + "strings" + + "golang.org/x/sys/windows" +) + +// EscapeArgs makes a Windows-style escaped command line from a set of arguments +func EscapeArgs(args []string) string { + escapedArgs := make([]string, len(args)) + for i, a := range args { + escapedArgs[i] = windows.EscapeArg(a) + } + return strings.Join(escapedArgs, " ") +} diff --git a/vendor/github.com/docker/docker/pkg/system/filesys_windows.go b/vendor/github.com/docker/docker/pkg/system/filesys_windows.go index a1f6013f1397..3049ff38a4a9 100644 --- a/vendor/github.com/docker/docker/pkg/system/filesys_windows.go +++ b/vendor/github.com/docker/docker/pkg/system/filesys_windows.go @@ -18,8 +18,6 @@ import ( const ( // SddlAdministratorsLocalSystem is local administrators plus NT AUTHORITY\System SddlAdministratorsLocalSystem = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" - // SddlNtvmAdministratorsLocalSystem is NT VIRTUAL MACHINE\Virtual Machines plus local administrators plus NT AUTHORITY\System - SddlNtvmAdministratorsLocalSystem = "D:P(A;OICI;GA;;;S-1-5-83-0)(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" ) // MkdirAllWithACL is a wrapper for MkdirAll that creates a directory diff --git a/vendor/github.com/docker/docker/pkg/system/init_unix.go b/vendor/github.com/docker/docker/pkg/system/init_unix.go index 4996a67c12e5..c2bb0f4cc497 100644 --- a/vendor/github.com/docker/docker/pkg/system/init_unix.go +++ b/vendor/github.com/docker/docker/pkg/system/init_unix.go @@ -5,3 +5,8 @@ package system // import "github.com/docker/docker/pkg/system" // InitLCOW does nothing since LCOW is a windows only feature func InitLCOW(experimental bool) { } + +// ContainerdRuntimeSupported returns true if the use of ContainerD runtime is supported. +func ContainerdRuntimeSupported(_ bool, _ string) bool { + return true +} diff --git a/vendor/github.com/docker/docker/pkg/system/init_windows.go b/vendor/github.com/docker/docker/pkg/system/init_windows.go index 4910ff69d666..7f675012854b 100644 --- a/vendor/github.com/docker/docker/pkg/system/init_windows.go +++ b/vendor/github.com/docker/docker/pkg/system/init_windows.go @@ -1,7 +1,19 @@ package system // import "github.com/docker/docker/pkg/system" -// lcowSupported determines if Linux Containers on Windows are supported. -var lcowSupported = false +import ( + "os" + + "github.com/sirupsen/logrus" +) + +var ( + // lcowSupported determines if Linux Containers on Windows are supported. + lcowSupported = false + + // containerdRuntimeSupported determines if ContainerD should be the runtime. + // As of March 2019, this is an experimental feature. + containerdRuntimeSupported = false +) // InitLCOW sets whether LCOW is supported or not func InitLCOW(experimental bool) { @@ -10,3 +22,19 @@ func InitLCOW(experimental bool) { lcowSupported = true } } + +// InitContainerdRuntime sets whether to use ContainerD for runtime +// on Windows. This is an experimental feature still in development, and +// also requires an environment variable to be set (so as not to turn the +// feature on from simply experimental which would also mean LCOW. +func InitContainerdRuntime(experimental bool, cdPath string) { + if experimental && len(cdPath) > 0 && len(os.Getenv("DOCKER_WINDOWS_CONTAINERD_RUNTIME")) > 0 { + logrus.Warnf("Using ContainerD runtime. This feature is experimental") + containerdRuntimeSupported = true + } +} + +// ContainerdRuntimeSupported returns true if the use of ContainerD runtime is supported. +func ContainerdRuntimeSupported() bool { + return containerdRuntimeSupported +} diff --git a/vendor/github.com/docker/docker/pkg/system/lcow.go b/vendor/github.com/docker/docker/pkg/system/lcow.go index 5c3fbfe6f4a7..5be3e2182ba0 100644 --- a/vendor/github.com/docker/docker/pkg/system/lcow.go +++ b/vendor/github.com/docker/docker/pkg/system/lcow.go @@ -1,69 +1,32 @@ package system // import "github.com/docker/docker/pkg/system" import ( - "fmt" "runtime" "strings" specs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" ) -// ValidatePlatform determines if a platform structure is valid. -// TODO This is a temporary function - can be replaced by parsing from -// https://github.com/containerd/containerd/pull/1403/files at a later date. -// @jhowardmsft -func ValidatePlatform(platform *specs.Platform) error { - platform.Architecture = strings.ToLower(platform.Architecture) - platform.OS = strings.ToLower(platform.OS) - // Based on https://github.com/moby/moby/pull/34642#issuecomment-330375350, do - // not support anything except operating system. - if platform.Architecture != "" { - return fmt.Errorf("invalid platform architecture %q", platform.Architecture) - } - if platform.OS != "" { - if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) { - return fmt.Errorf("invalid platform os %q", platform.OS) - } - } - if len(platform.OSFeatures) != 0 { - return fmt.Errorf("invalid platform osfeatures %q", platform.OSFeatures) - } - if platform.OSVersion != "" { - return fmt.Errorf("invalid platform osversion %q", platform.OSVersion) - } - if platform.Variant != "" { - return fmt.Errorf("invalid platform variant %q", platform.Variant) - } - return nil -} - -// ParsePlatform parses a platform string in the format os[/arch[/variant] -// into an OCI image-spec platform structure. -// TODO This is a temporary function - can be replaced by parsing from -// https://github.com/containerd/containerd/pull/1403/files at a later date. -// @jhowardmsft -func ParsePlatform(in string) *specs.Platform { - p := &specs.Platform{} - elements := strings.SplitN(strings.ToLower(in), "/", 3) - if len(elements) == 3 { - p.Variant = elements[2] - } - if len(elements) >= 2 { - p.Architecture = elements[1] - } - if len(elements) >= 1 { - p.OS = elements[0] - } - return p -} - // IsOSSupported determines if an operating system is supported by the host func IsOSSupported(os string) bool { - if runtime.GOOS == os { + if strings.EqualFold(runtime.GOOS, os) { return true } - if LCOWSupported() && os == "linux" { + if LCOWSupported() && strings.EqualFold(os, "linux") { return true } return false } + +// ValidatePlatform determines if a platform structure is valid. +// TODO This is a temporary windows-only function, should be replaced by +// comparison of worker capabilities +func ValidatePlatform(platform specs.Platform) error { + if runtime.GOOS == "windows" { + if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) { + return errors.Errorf("unsupported os %s", platform.OS) + } + } + return nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/lstat_unix.go b/vendor/github.com/docker/docker/pkg/system/lstat_unix.go index 7477995f1bfd..de5a1c0fb26d 100644 --- a/vendor/github.com/docker/docker/pkg/system/lstat_unix.go +++ b/vendor/github.com/docker/docker/pkg/system/lstat_unix.go @@ -3,6 +3,7 @@ package system // import "github.com/docker/docker/pkg/system" import ( + "os" "syscall" ) @@ -13,7 +14,7 @@ import ( func Lstat(path string) (*StatT, error) { s := &syscall.Stat_t{} if err := syscall.Lstat(path, s); err != nil { - return nil, err + return nil, &os.PathError{Op: "Lstat", Path: path, Err: err} } return fromStatT(s) } diff --git a/vendor/github.com/docker/docker/pkg/system/path_unix.go b/vendor/github.com/docker/docker/pkg/system/path_unix.go new file mode 100644 index 000000000000..b0b93196a15c --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/path_unix.go @@ -0,0 +1,10 @@ +// +build !windows + +package system // import "github.com/docker/docker/pkg/system" + +// GetLongPathName converts Windows short pathnames to full pathnames. +// For example C:\Users\ADMIN~1 --> C:\Users\Administrator. +// It is a no-op on non-Windows platforms +func GetLongPathName(path string) (string, error) { + return path, nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/path_windows.go b/vendor/github.com/docker/docker/pkg/system/path_windows.go new file mode 100644 index 000000000000..188f2c2957a4 --- /dev/null +++ b/vendor/github.com/docker/docker/pkg/system/path_windows.go @@ -0,0 +1,24 @@ +package system // import "github.com/docker/docker/pkg/system" + +import "syscall" + +// GetLongPathName converts Windows short pathnames to full pathnames. +// For example C:\Users\ADMIN~1 --> C:\Users\Administrator. +// It is a no-op on non-Windows platforms +func GetLongPathName(path string) (string, error) { + // See https://groups.google.com/forum/#!topic/golang-dev/1tufzkruoTg + p := syscall.StringToUTF16(path) + b := p // GetLongPathName says we can reuse buffer + n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + if n > uint32(len(b)) { + b = make([]uint16, n) + _, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) + if err != nil { + return "", err + } + } + return syscall.UTF16ToString(b), nil +} diff --git a/vendor/github.com/docker/docker/pkg/system/rm.go b/vendor/github.com/docker/docker/pkg/system/rm.go index 02e4d262216e..b3109918004a 100644 --- a/vendor/github.com/docker/docker/pkg/system/rm.go +++ b/vendor/github.com/docker/docker/pkg/system/rm.go @@ -34,7 +34,7 @@ func EnsureRemoveAll(dir string) error { for { err := os.RemoveAll(dir) if err == nil { - return err + return nil } pe, ok := err.(*os.PathError) diff --git a/vendor/github.com/docker/docker/pkg/system/stat_unix.go b/vendor/github.com/docker/docker/pkg/system/stat_unix.go index 3d7e2ebbefaf..86bb6dd55e6a 100644 --- a/vendor/github.com/docker/docker/pkg/system/stat_unix.go +++ b/vendor/github.com/docker/docker/pkg/system/stat_unix.go @@ -3,6 +3,7 @@ package system // import "github.com/docker/docker/pkg/system" import ( + "os" "syscall" ) @@ -59,7 +60,7 @@ func (s StatT) IsDir() bool { func Stat(path string) (*StatT, error) { s := &syscall.Stat_t{} if err := syscall.Stat(path, s); err != nil { - return nil, err + return nil, &os.PathError{Op: "Stat", Path: path, Err: err} } return fromStatT(s) } diff --git a/vendor/github.com/docker/docker/pkg/system/syscall_windows.go b/vendor/github.com/docker/docker/pkg/system/syscall_windows.go index ee7e0256f333..4ae92fa6c7d7 100644 --- a/vendor/github.com/docker/docker/pkg/system/syscall_windows.go +++ b/vendor/github.com/docker/docker/pkg/system/syscall_windows.go @@ -2,16 +2,62 @@ package system // import "github.com/docker/docker/pkg/system" import ( "fmt" + "syscall" "unsafe" "github.com/sirupsen/logrus" "golang.org/x/sys/windows" ) +const ( + OWNER_SECURITY_INFORMATION = 0x00000001 + GROUP_SECURITY_INFORMATION = 0x00000002 + DACL_SECURITY_INFORMATION = 0x00000004 + SACL_SECURITY_INFORMATION = 0x00000008 + LABEL_SECURITY_INFORMATION = 0x00000010 + ATTRIBUTE_SECURITY_INFORMATION = 0x00000020 + SCOPE_SECURITY_INFORMATION = 0x00000040 + PROCESS_TRUST_LABEL_SECURITY_INFORMATION = 0x00000080 + ACCESS_FILTER_SECURITY_INFORMATION = 0x00000100 + BACKUP_SECURITY_INFORMATION = 0x00010000 + PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000 + PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000 + UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000 + UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000 +) + +const ( + SE_UNKNOWN_OBJECT_TYPE = iota + SE_FILE_OBJECT + SE_SERVICE + SE_PRINTER + SE_REGISTRY_KEY + SE_LMSHARE + SE_KERNEL_OBJECT + SE_WINDOW_OBJECT + SE_DS_OBJECT + SE_DS_OBJECT_ALL + SE_PROVIDER_DEFINED_OBJECT + SE_WMIGUID_OBJECT + SE_REGISTRY_WOW64_32KEY +) + +const ( + SeTakeOwnershipPrivilege = "SeTakeOwnershipPrivilege" +) + +const ( + ContainerAdministratorSidString = "S-1-5-93-2-1" + ContainerUserSidString = "S-1-5-93-2-2" +) + var ( - ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") - procGetVersionExW = modkernel32.NewProc("GetVersionExW") - procGetProductInfo = modkernel32.NewProc("GetProductInfo") + ntuserApiset = windows.NewLazyDLL("ext-ms-win-ntuser-window-l1-1-0") + modadvapi32 = windows.NewLazySystemDLL("advapi32.dll") + procGetVersionExW = modkernel32.NewProc("GetVersionExW") + procGetProductInfo = modkernel32.NewProc("GetProductInfo") + procSetNamedSecurityInfo = modadvapi32.NewProc("SetNamedSecurityInfoW") + procGetSecurityDescriptorDacl = modadvapi32.NewProc("GetSecurityDescriptorDacl") ) // OSVersion is a wrapper for Windows version information @@ -125,3 +171,23 @@ func HasWin32KSupport() bool { // APIs. return ntuserApiset.Load() == nil } + +func SetNamedSecurityInfo(objectName *uint16, objectType uint32, securityInformation uint32, sidOwner *windows.SID, sidGroup *windows.SID, dacl *byte, sacl *byte) (result error) { + r0, _, _ := syscall.Syscall9(procSetNamedSecurityInfo.Addr(), 7, uintptr(unsafe.Pointer(objectName)), uintptr(objectType), uintptr(securityInformation), uintptr(unsafe.Pointer(sidOwner)), uintptr(unsafe.Pointer(sidGroup)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(sacl)), 0, 0) + if r0 != 0 { + result = syscall.Errno(r0) + } + return +} + +func GetSecurityDescriptorDacl(securityDescriptor *byte, daclPresent *uint32, dacl **byte, daclDefaulted *uint32) (result error) { + r1, _, e1 := syscall.Syscall6(procGetSecurityDescriptorDacl.Addr(), 4, uintptr(unsafe.Pointer(securityDescriptor)), uintptr(unsafe.Pointer(daclPresent)), uintptr(unsafe.Pointer(dacl)), uintptr(unsafe.Pointer(daclDefaulted)), 0, 0) + if r1 == 0 { + if e1 != 0 { + result = syscall.Errno(e1) + } else { + result = syscall.EINVAL + } + } + return +} diff --git a/vendor/github.com/docker/docker/pkg/term/term_windows.go b/vendor/github.com/docker/docker/pkg/term/term_windows.go index 64ead3c53b8c..a3c3db131574 100644 --- a/vendor/github.com/docker/docker/pkg/term/term_windows.go +++ b/vendor/github.com/docker/docker/pkg/term/term_windows.go @@ -62,13 +62,6 @@ func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) { } } - if os.Getenv("ConEmuANSI") == "ON" || os.Getenv("ConsoleZVersion") != "" { - // The ConEmu and ConsoleZ terminals emulate ANSI on output streams well. - emulateStdin = true - emulateStdout = false - emulateStderr = false - } - // Temporarily use STD_INPUT_HANDLE, STD_OUTPUT_HANDLE and // STD_ERROR_HANDLE from syscall rather than x/sys/windows as long as // go-ansiterm hasn't switch to x/sys/windows. diff --git a/vendor/github.com/docker/docker/pkg/truncindex/truncindex.go b/vendor/github.com/docker/docker/pkg/truncindex/truncindex.go index d5c840cf1336..b7a11a38c042 100644 --- a/vendor/github.com/docker/docker/pkg/truncindex/truncindex.go +++ b/vendor/github.com/docker/docker/pkg/truncindex/truncindex.go @@ -108,7 +108,7 @@ func (idx *TruncIndex) Get(s string) (string, error) { if id != "" { // we haven't found the ID if there are two or more IDs id = "" - return ErrAmbiguousPrefix{prefix: string(prefix)} + return ErrAmbiguousPrefix{prefix: s} } id = string(prefix) return nil diff --git a/vendor/github.com/docker/docker/poule.yml b/vendor/github.com/docker/docker/poule.yml index fe1cb3d10324..d05c764b38ab 100644 --- a/vendor/github.com/docker/docker/poule.yml +++ b/vendor/github.com/docker/docker/poule.yml @@ -89,6 +89,11 @@ configurations: [ windowsRS1 ], label: "rebuild/windowsRS1", } + - type: rebuild + settings: { + configurations: [ windowsRS5 ], + label: "rebuild/windowsRS5-process", + } - type: rebuild settings: { configurations: [ z ], diff --git a/vendor/github.com/docker/docker/vendor.conf b/vendor/github.com/docker/docker/vendor.conf index a313759028f7..607952d991b9 100644 --- a/vendor/github.com/docker/docker/vendor.conf +++ b/vendor/github.com/docker/docker/vendor.conf @@ -1,69 +1,73 @@ # the following lines are in sorted order, FYI github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109 -github.com/Microsoft/hcsshim v0.6.11 -github.com/Microsoft/go-winio v0.4.7 +github.com/Microsoft/hcsshim ba3d6667710fa905116f39a19d059c4c1016be7c +github.com/Microsoft/go-winio c599b533b43b1363d7d7c6cfda5ede70ed73ff13 github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git github.com/golang/gddo 9b12a26f3fbd7397dee4e20939ddca719d840d2a -github.com/gorilla/context v1.1 -github.com/gorilla/mux v1.1 -github.com/Microsoft/opengcs v0.3.6 +github.com/google/uuid v1.1.1 +github.com/gorilla/mux v1.7.0 +github.com/Microsoft/opengcs a10967154e143a36014584a6f664344e3bb0aa64 +github.com/konsorten/go-windows-terminal-sequences v1.0.1 github.com/kr/pty 5cf931ef8f github.com/mattn/go-shellwords v1.0.3 -github.com/sirupsen/logrus v1.0.3 +github.com/sirupsen/logrus v1.3.0 github.com/tchap/go-patricia v2.2.6 github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 -golang.org/x/net 0ed95abb35c445290478a5348a7b38bb154135fd -golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd -github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1 -github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6 -golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756 -github.com/pmezard/go-difflib v1.0.0 -github.com/gotestyourself/gotestyourself cf3a5ab914a2efa8bc838d09f5918c1d44d029 +golang.org/x/net a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1 +golang.org/x/sys d455e41777fca6e8a5a79e34a14b8368bc11d9ba +github.com/docker/go-units 47565b4f722fb6ceae66b95f853feed578a4a51c # v0.3.3 +github.com/docker/go-connections 7395e3f8aa162843a74ed6d48e79627d9792ac55 # v0.4.0 +golang.org/x/text f21a4dfb5e38f5895301dc265a8def02365cc3d0 # v0.3.0 +gotest.tools v2.1.0 github.com/google/go-cmp v0.2.0 github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5 -github.com/imdario/mergo v0.3.5 -golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5 +github.com/imdario/mergo v0.3.6 +golang.org/x/sync 1d60e4601c6fd243af51cc01ddf169918a5407ca # buildkit -github.com/moby/buildkit 43e758232a0ac7d50c6a11413186e16684fc1e4f -github.com/tonistiigi/fsutil dc68c74458923f357474a9178bd198aa3ed11a5f +github.com/moby/buildkit e9aca5bef87e19173b99d8668db0338dcaaa5f33 +github.com/tonistiigi/fsutil 1bdbf124ad494a771e99e0cdcd16326375f8b2c9 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7 +github.com/google/shlex 6f45313302b9c56850fc17f99e40caebce98c716 +github.com/opentracing-contrib/go-stdlib b1a47cfbdd7543e70e9ef3e73d0802ad306cc1cc +github.com/mitchellh/hashstructure 2bca23e0e452137f789efbc8610126fd8b94f73b +github.com/gofrs/flock 7f43ea2e6a643ad441fc12d0ecc0d3388b300c53 # v0.7.0 #get libnetwork packages -# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy accordingly -github.com/docker/libnetwork 19279f0492417475b6bfbd0aa529f73e8f178fb5 +# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly +github.com/docker/libnetwork 1a06131fb8a047d919f7deaf02a4c414d7884b83 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b github.com/hashicorp/memberlist 3d8438da9589e7b608a83ffac1ef8211486bcb7c github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372 -github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d +github.com/hashicorp/go-sockaddr 6d291a969b86c4b633730bfc6b8b9d64c3aafed9 github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870 -github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef +github.com/docker/libkv 458977154600b9f23984d9f4b82e79570b5ae12b github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25 github.com/vishvananda/netlink b2de5d10e38ecce8607e6b438b6d174f389a004e -# When updating, consider updating TOMLV_COMMIT in hack/dockerfile/install/tomlv accordingly -github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895 +# When updating, consider updating TOMLV_COMMIT in hack/dockerfile/install/tomlv.installer accordingly +github.com/BurntSushi/toml 3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005 # v0.3.1 github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374 github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d -github.com/coreos/etcd v3.2.1 +github.com/coreos/etcd v3.3.9 github.com/coreos/go-semver v0.2.0 -github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065 +github.com/ugorji/go v1.1.1 github.com/hashicorp/consul v0.5.2 -github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904 github.com/miekg/dns v1.0.7 github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb +go.etcd.io/bbolt v1.3.1-etcd.8 # get graph and distribution packages -github.com/docker/distribution 83389a148052d74ac602f5f1d62f86ff2f3c4aa5 -github.com/vbatts/tar-split v0.10.2 +github.com/docker/distribution 0d3efadf0154c2b8a4e7b6621fff9809655cc580 +github.com/vbatts/tar-split v0.11.0 github.com/opencontainers/go-digest v1.0.0-rc1 # get go-zfs packages @@ -72,9 +76,13 @@ github.com/pborman/uuid v1.0 google.golang.org/grpc v1.12.0 -# When updating, also update RUNC_COMMIT in hack/dockerfile/install/runc accordingly -github.com/opencontainers/runc 69663f0bd4b60df09991c08812a60108003fa340 -github.com/opencontainers/runtime-spec v1.0.1 +# The version of runc should match the version that is used by the containerd +# version that is used. If you need to update runc, open a pull request in +# the containerd project first, and update both after that is merged. +# This commit does not need to match RUNC_COMMIT as it is used for helper +# packages but should be newer or equal. +github.com/opencontainers/runc 2b18fe1d885ee5083ef9f0838fee39b62d653e30 +github.com/opencontainers/runtime-spec 29686dbc5559d93fb1ef402eeda3e35c38d75af4 # v1.0.1-59-g29686db github.com/opencontainers/image-spec v1.0.1 github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 @@ -82,7 +90,7 @@ github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0 github.com/coreos/go-systemd v17 github.com/godbus/dbus v4.0.0 github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852 -github.com/golang/protobuf v1.1.0 +github.com/golang/protobuf v1.2.0 # gelf logging driver deps github.com/Graylog2/go-gelf 4143646226541087117ff2f83334ea48b3201841 @@ -93,7 +101,7 @@ github.com/philhofer/fwd 98c11a7a6ec829d672b03833c3d69a7fae1ca972 github.com/tinylib/msgp 3b556c64540842d4f82967be066a7f7fffc3adad # fsnotify -github.com/fsnotify/fsnotify 4da3e2cfbabc9f751898f250b49f2439785783a1 +github.com/fsnotify/fsnotify v1.4.7 # awslogs deps github.com/aws/aws-sdk-go v1.12.66 @@ -112,51 +120,45 @@ github.com/googleapis/gax-go v2.0.0 google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9 # containerd -github.com/containerd/containerd 63522d9eaa5a0443d225642c4b6f4f5fdedf932b +github.com/containerd/containerd a15b6e2097c48b632dbdc63254bad4c62b69e709 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c -github.com/containerd/continuity d3c23511c1bf5851696cba83143d9cbcd666869b -github.com/containerd/cgroups fe281dd265766145e943a034aa41086474ea6130 -github.com/containerd/console 9290d21dc56074581f619579c43d970b4514bc08 -github.com/containerd/go-runc f271fa2021de855d4d918dbef83c5fe19db1bdd -github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788 -github.com/stevvooe/ttrpc d4528379866b0ce7e9d71f3eb96f0582fc374577 +github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d +github.com/containerd/cgroups 4994991857f9b0ae8dc439551e8bebdbb4bf66c1 +github.com/containerd/console c12b1e7919c14469339a5d38f2f8ed9b64a9de23 +github.com/containerd/go-runc 5a6d9f37cfa36b15efba46dc7ea349fa9b7143c3 +github.com/containerd/typeurl a93fcdb778cd272c6e9b3028b2f42d813e785d40 +github.com/containerd/ttrpc f02858b1457c5ca3aaec3a0803eb0d59f96e41d6 github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef # cluster -github.com/docker/swarmkit edd5641391926a50bc5f7040e20b7efc05003c26 -github.com/gogo/protobuf v1.0.0 -github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a +github.com/docker/swarmkit 18e7e58ea1a5ec016625a636d0d52500eea123bc +github.com/gogo/protobuf v1.2.0 +github.com/cloudflare/cfssl 1.3.2 github.com/fernet/fernet-go 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2 -github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e -golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491 -golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb +github.com/google/certificate-transparency-go v1.0.20 +golang.org/x/crypto b7391e95e576cacdcdd422573063bc057239113d +golang.org/x/time fbb02b2291d28baffd63558aa44b4b56f178d650 github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad -github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990 -github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4 -github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8 +github.com/hashicorp/go-immutable-radix 826af9ccf0feeee615d546d69b11f8e98da8c8f1 git://github.com/tonistiigi/go-immutable-radix.git +github.com/hashicorp/golang-lru 0fb14efe8c47ae851c0034ed7a448854d3d34cf3 +github.com/coreos/pkg v3 github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0 -github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e -github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9 -github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6 -github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8 -github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5 +github.com/prometheus/client_golang v0.8.0 +github.com/beorn7/perks 3a771d992973f24aa725d07868b467d1ddfceaf +github.com/prometheus/client_model 6f3806018612930941127f2a7c6c453ba2c527d2 +github.com/prometheus/common 7600349dcfe1abd18d72d3a1770870d9800a7801 +github.com/prometheus/procfs 7d6f385de8bea29190f15ba9931442a0eaef9af7 github.com/matttproud/golang_protobuf_extensions v1.0.0 -github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9 -github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0 +github.com/pkg/errors 645ef00459ed84a119197bfb8d8205042c6df63d # v0.8.0 +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 # cli github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.1 -github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 -github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty +github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 # v1.0 +github.com/morikuni/aec 39771216ff4c63d11f5e604076f9c45e8be1067b # metrics github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18 -github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd - - -# archive/tar (for Go 1.10, see https://github.com/golang/go/issues/24787) -# mkdir -p ./vendor/archive -# git clone -b go-1.10 --depth=1 git@github.com:kolyshkin/go-tar.git ./vendor/archive/tar -# vndr # to clean up test files +github.com/opencontainers/selinux 9e2c5215628a2567782777efb2049f385484f918 # v1.2 diff --git a/vendor/github.com/morikuni/aec/LICENSE b/vendor/github.com/morikuni/aec/LICENSE new file mode 100644 index 000000000000..1c2640164192 --- /dev/null +++ b/vendor/github.com/morikuni/aec/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Taihei Morikuni + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/morikuni/aec/README.md b/vendor/github.com/morikuni/aec/README.md new file mode 100644 index 000000000000..3cbc4343ee26 --- /dev/null +++ b/vendor/github.com/morikuni/aec/README.md @@ -0,0 +1,178 @@ +# aec + +[![GoDoc](https://godoc.org/github.com/morikuni/aec?status.svg)](https://godoc.org/github.com/morikuni/aec) + +Go wrapper for ANSI escape code. + +## Install + +```bash +go get github.com/morikuni/aec +``` + +## Features + +ANSI escape codes depend on terminal environment. +Some of these features may not work. +Check supported Font-Style/Font-Color features with [checkansi](./checkansi). + +[Wikipedia](https://en.wikipedia.org/wiki/ANSI_escape_code) for more detail. + +### Cursor + +- `Up(n)` +- `Down(n)` +- `Right(n)` +- `Left(n)` +- `NextLine(n)` +- `PreviousLine(n)` +- `Column(col)` +- `Position(row, col)` +- `Save` +- `Restore` +- `Hide` +- `Show` +- `Report` + +### Erase + +- `EraseDisplay(mode)` +- `EraseLine(mode)` + +### Scroll + +- `ScrollUp(n)` +- `ScrollDown(n)` + +### Font Style + +- `Bold` +- `Faint` +- `Italic` +- `Underline` +- `BlinkSlow` +- `BlinkRapid` +- `Inverse` +- `Conceal` +- `CrossOut` +- `Frame` +- `Encircle` +- `Overline` + +### Font Color + +Foreground color. + +- `DefaultF` +- `BlackF` +- `RedF` +- `GreenF` +- `YellowF` +- `BlueF` +- `MagentaF` +- `CyanF` +- `WhiteF` +- `LightBlackF` +- `LightRedF` +- `LightGreenF` +- `LightYellowF` +- `LightBlueF` +- `LightMagentaF` +- `LightCyanF` +- `LightWhiteF` +- `Color3BitF(color)` +- `Color8BitF(color)` +- `FullColorF(r, g, b)` + +Background color. + +- `DefaultB` +- `BlackB` +- `RedB` +- `GreenB` +- `YellowB` +- `BlueB` +- `MagentaB` +- `CyanB` +- `WhiteB` +- `LightBlackB` +- `LightRedB` +- `LightGreenB` +- `LightYellowB` +- `LightBlueB` +- `LightMagentaB` +- `LightCyanB` +- `LightWhiteB` +- `Color3BitB(color)` +- `Color8BitB(color)` +- `FullColorB(r, g, b)` + +### Color Converter + +24bit RGB color to ANSI color. + +- `NewRGB3Bit(r, g, b)` +- `NewRGB8Bit(r, g, b)` + +### Builder + +To mix these features. + +```go +custom := aec.EmptyBuilder.Right(2).RGB8BitF(128, 255, 64).RedB().ANSI +custom.Apply("Hello World") +``` + +## Usage + +1. Create ANSI by `aec.XXX().With(aec.YYY())` or `aec.EmptyBuilder.XXX().YYY().ANSI` +2. Print ANSI by `fmt.Print(ansi, "some string", aec.Reset)` or `fmt.Print(ansi.Apply("some string"))` + +`aec.Reset` should be added when using font style or font color features. + +## Example + +Simple progressbar. + +![sample](./sample.gif) + +```go +package main + +import ( + "fmt" + "strings" + "time" + + "github.com/morikuni/aec" +) + +func main() { + const n = 20 + builder := aec.EmptyBuilder + + up2 := aec.Up(2) + col := aec.Column(n + 2) + bar := aec.Color8BitF(aec.NewRGB8Bit(64, 255, 64)) + label := builder.LightRedF().Underline().With(col).Right(1).ANSI + + // for up2 + fmt.Println() + fmt.Println() + + for i := 0; i <= n; i++ { + fmt.Print(up2) + fmt.Println(label.Apply(fmt.Sprint(i, "/", n))) + fmt.Print("[") + fmt.Print(bar.Apply(strings.Repeat("=", i))) + fmt.Println(col.Apply("]")) + time.Sleep(100 * time.Millisecond) + } +} +``` + +## License + +[MIT](./LICENSE) + + diff --git a/vendor/github.com/morikuni/aec/aec.go b/vendor/github.com/morikuni/aec/aec.go new file mode 100644 index 000000000000..566be6eb1ef5 --- /dev/null +++ b/vendor/github.com/morikuni/aec/aec.go @@ -0,0 +1,137 @@ +package aec + +import "fmt" + +// EraseMode is listed in a variable EraseModes. +type EraseMode uint + +var ( + // EraseModes is a list of EraseMode. + EraseModes struct { + // All erase all. + All EraseMode + + // Head erase to head. + Head EraseMode + + // Tail erase to tail. + Tail EraseMode + } + + // Save saves the cursor position. + Save ANSI + + // Restore restores the cursor position. + Restore ANSI + + // Hide hides the cursor. + Hide ANSI + + // Show shows the cursor. + Show ANSI + + // Report reports the cursor position. + Report ANSI +) + +// Up moves up the cursor. +func Up(n uint) ANSI { + if n == 0 { + return empty + } + return newAnsi(fmt.Sprintf(esc+"%dA", n)) +} + +// Down moves down the cursor. +func Down(n uint) ANSI { + if n == 0 { + return empty + } + return newAnsi(fmt.Sprintf(esc+"%dB", n)) +} + +// Right moves right the cursor. +func Right(n uint) ANSI { + if n == 0 { + return empty + } + return newAnsi(fmt.Sprintf(esc+"%dC", n)) +} + +// Left moves left the cursor. +func Left(n uint) ANSI { + if n == 0 { + return empty + } + return newAnsi(fmt.Sprintf(esc+"%dD", n)) +} + +// NextLine moves down the cursor to head of a line. +func NextLine(n uint) ANSI { + if n == 0 { + return empty + } + return newAnsi(fmt.Sprintf(esc+"%dE", n)) +} + +// PreviousLine moves up the cursor to head of a line. +func PreviousLine(n uint) ANSI { + if n == 0 { + return empty + } + return newAnsi(fmt.Sprintf(esc+"%dF", n)) +} + +// Column set the cursor position to a given column. +func Column(col uint) ANSI { + return newAnsi(fmt.Sprintf(esc+"%dG", col)) +} + +// Position set the cursor position to a given absolute position. +func Position(row, col uint) ANSI { + return newAnsi(fmt.Sprintf(esc+"%d;%dH", row, col)) +} + +// EraseDisplay erases display by given EraseMode. +func EraseDisplay(m EraseMode) ANSI { + return newAnsi(fmt.Sprintf(esc+"%dJ", m)) +} + +// EraseLine erases lines by given EraseMode. +func EraseLine(m EraseMode) ANSI { + return newAnsi(fmt.Sprintf(esc+"%dK", m)) +} + +// ScrollUp scrolls up the page. +func ScrollUp(n int) ANSI { + if n == 0 { + return empty + } + return newAnsi(fmt.Sprintf(esc+"%dS", n)) +} + +// ScrollDown scrolls down the page. +func ScrollDown(n int) ANSI { + if n == 0 { + return empty + } + return newAnsi(fmt.Sprintf(esc+"%dT", n)) +} + +func init() { + EraseModes = struct { + All EraseMode + Head EraseMode + Tail EraseMode + }{ + Tail: 0, + Head: 1, + All: 2, + } + + Save = newAnsi(esc + "s") + Restore = newAnsi(esc + "u") + Hide = newAnsi(esc + "?25l") + Show = newAnsi(esc + "?25h") + Report = newAnsi(esc + "6n") +} diff --git a/vendor/github.com/morikuni/aec/ansi.go b/vendor/github.com/morikuni/aec/ansi.go new file mode 100644 index 000000000000..e60722e6e60b --- /dev/null +++ b/vendor/github.com/morikuni/aec/ansi.go @@ -0,0 +1,59 @@ +package aec + +import ( + "fmt" + "strings" +) + +const esc = "\x1b[" + +// Reset resets SGR effect. +const Reset string = "\x1b[0m" + +var empty = newAnsi("") + +// ANSI represents ANSI escape code. +type ANSI interface { + fmt.Stringer + + // With adapts given ANSIs. + With(...ANSI) ANSI + + // Apply wraps given string in ANSI. + Apply(string) string +} + +type ansiImpl string + +func newAnsi(s string) *ansiImpl { + r := ansiImpl(s) + return &r +} + +func (a *ansiImpl) With(ansi ...ANSI) ANSI { + return concat(append([]ANSI{a}, ansi...)) +} + +func (a *ansiImpl) Apply(s string) string { + return a.String() + s + Reset +} + +func (a *ansiImpl) String() string { + return string(*a) +} + +// Apply wraps given string in ANSIs. +func Apply(s string, ansi ...ANSI) string { + if len(ansi) == 0 { + return s + } + return concat(ansi).Apply(s) +} + +func concat(ansi []ANSI) ANSI { + strs := make([]string, 0, len(ansi)) + for _, p := range ansi { + strs = append(strs, p.String()) + } + return newAnsi(strings.Join(strs, "")) +} diff --git a/vendor/github.com/morikuni/aec/builder.go b/vendor/github.com/morikuni/aec/builder.go new file mode 100644 index 000000000000..13bd002d4e30 --- /dev/null +++ b/vendor/github.com/morikuni/aec/builder.go @@ -0,0 +1,388 @@ +package aec + +// Builder is a lightweight syntax to construct customized ANSI. +type Builder struct { + ANSI ANSI +} + +// EmptyBuilder is an initialized Builder. +var EmptyBuilder *Builder + +// NewBuilder creates a Builder from existing ANSI. +func NewBuilder(a ...ANSI) *Builder { + return &Builder{concat(a)} +} + +// With is a syntax for With. +func (builder *Builder) With(a ...ANSI) *Builder { + return NewBuilder(builder.ANSI.With(a...)) +} + +// Up is a syntax for Up. +func (builder *Builder) Up(n uint) *Builder { + return builder.With(Up(n)) +} + +// Down is a syntax for Down. +func (builder *Builder) Down(n uint) *Builder { + return builder.With(Down(n)) +} + +// Right is a syntax for Right. +func (builder *Builder) Right(n uint) *Builder { + return builder.With(Right(n)) +} + +// Left is a syntax for Left. +func (builder *Builder) Left(n uint) *Builder { + return builder.With(Left(n)) +} + +// NextLine is a syntax for NextLine. +func (builder *Builder) NextLine(n uint) *Builder { + return builder.With(NextLine(n)) +} + +// PreviousLine is a syntax for PreviousLine. +func (builder *Builder) PreviousLine(n uint) *Builder { + return builder.With(PreviousLine(n)) +} + +// Column is a syntax for Column. +func (builder *Builder) Column(col uint) *Builder { + return builder.With(Column(col)) +} + +// Position is a syntax for Position. +func (builder *Builder) Position(row, col uint) *Builder { + return builder.With(Position(row, col)) +} + +// EraseDisplay is a syntax for EraseDisplay. +func (builder *Builder) EraseDisplay(m EraseMode) *Builder { + return builder.With(EraseDisplay(m)) +} + +// EraseLine is a syntax for EraseLine. +func (builder *Builder) EraseLine(m EraseMode) *Builder { + return builder.With(EraseLine(m)) +} + +// ScrollUp is a syntax for ScrollUp. +func (builder *Builder) ScrollUp(n int) *Builder { + return builder.With(ScrollUp(n)) +} + +// ScrollDown is a syntax for ScrollDown. +func (builder *Builder) ScrollDown(n int) *Builder { + return builder.With(ScrollDown(n)) +} + +// Save is a syntax for Save. +func (builder *Builder) Save() *Builder { + return builder.With(Save) +} + +// Restore is a syntax for Restore. +func (builder *Builder) Restore() *Builder { + return builder.With(Restore) +} + +// Hide is a syntax for Hide. +func (builder *Builder) Hide() *Builder { + return builder.With(Hide) +} + +// Show is a syntax for Show. +func (builder *Builder) Show() *Builder { + return builder.With(Show) +} + +// Report is a syntax for Report. +func (builder *Builder) Report() *Builder { + return builder.With(Report) +} + +// Bold is a syntax for Bold. +func (builder *Builder) Bold() *Builder { + return builder.With(Bold) +} + +// Faint is a syntax for Faint. +func (builder *Builder) Faint() *Builder { + return builder.With(Faint) +} + +// Italic is a syntax for Italic. +func (builder *Builder) Italic() *Builder { + return builder.With(Italic) +} + +// Underline is a syntax for Underline. +func (builder *Builder) Underline() *Builder { + return builder.With(Underline) +} + +// BlinkSlow is a syntax for BlinkSlow. +func (builder *Builder) BlinkSlow() *Builder { + return builder.With(BlinkSlow) +} + +// BlinkRapid is a syntax for BlinkRapid. +func (builder *Builder) BlinkRapid() *Builder { + return builder.With(BlinkRapid) +} + +// Inverse is a syntax for Inverse. +func (builder *Builder) Inverse() *Builder { + return builder.With(Inverse) +} + +// Conceal is a syntax for Conceal. +func (builder *Builder) Conceal() *Builder { + return builder.With(Conceal) +} + +// CrossOut is a syntax for CrossOut. +func (builder *Builder) CrossOut() *Builder { + return builder.With(CrossOut) +} + +// BlackF is a syntax for BlackF. +func (builder *Builder) BlackF() *Builder { + return builder.With(BlackF) +} + +// RedF is a syntax for RedF. +func (builder *Builder) RedF() *Builder { + return builder.With(RedF) +} + +// GreenF is a syntax for GreenF. +func (builder *Builder) GreenF() *Builder { + return builder.With(GreenF) +} + +// YellowF is a syntax for YellowF. +func (builder *Builder) YellowF() *Builder { + return builder.With(YellowF) +} + +// BlueF is a syntax for BlueF. +func (builder *Builder) BlueF() *Builder { + return builder.With(BlueF) +} + +// MagentaF is a syntax for MagentaF. +func (builder *Builder) MagentaF() *Builder { + return builder.With(MagentaF) +} + +// CyanF is a syntax for CyanF. +func (builder *Builder) CyanF() *Builder { + return builder.With(CyanF) +} + +// WhiteF is a syntax for WhiteF. +func (builder *Builder) WhiteF() *Builder { + return builder.With(WhiteF) +} + +// DefaultF is a syntax for DefaultF. +func (builder *Builder) DefaultF() *Builder { + return builder.With(DefaultF) +} + +// BlackB is a syntax for BlackB. +func (builder *Builder) BlackB() *Builder { + return builder.With(BlackB) +} + +// RedB is a syntax for RedB. +func (builder *Builder) RedB() *Builder { + return builder.With(RedB) +} + +// GreenB is a syntax for GreenB. +func (builder *Builder) GreenB() *Builder { + return builder.With(GreenB) +} + +// YellowB is a syntax for YellowB. +func (builder *Builder) YellowB() *Builder { + return builder.With(YellowB) +} + +// BlueB is a syntax for BlueB. +func (builder *Builder) BlueB() *Builder { + return builder.With(BlueB) +} + +// MagentaB is a syntax for MagentaB. +func (builder *Builder) MagentaB() *Builder { + return builder.With(MagentaB) +} + +// CyanB is a syntax for CyanB. +func (builder *Builder) CyanB() *Builder { + return builder.With(CyanB) +} + +// WhiteB is a syntax for WhiteB. +func (builder *Builder) WhiteB() *Builder { + return builder.With(WhiteB) +} + +// DefaultB is a syntax for DefaultB. +func (builder *Builder) DefaultB() *Builder { + return builder.With(DefaultB) +} + +// Frame is a syntax for Frame. +func (builder *Builder) Frame() *Builder { + return builder.With(Frame) +} + +// Encircle is a syntax for Encircle. +func (builder *Builder) Encircle() *Builder { + return builder.With(Encircle) +} + +// Overline is a syntax for Overline. +func (builder *Builder) Overline() *Builder { + return builder.With(Overline) +} + +// LightBlackF is a syntax for LightBlueF. +func (builder *Builder) LightBlackF() *Builder { + return builder.With(LightBlackF) +} + +// LightRedF is a syntax for LightRedF. +func (builder *Builder) LightRedF() *Builder { + return builder.With(LightRedF) +} + +// LightGreenF is a syntax for LightGreenF. +func (builder *Builder) LightGreenF() *Builder { + return builder.With(LightGreenF) +} + +// LightYellowF is a syntax for LightYellowF. +func (builder *Builder) LightYellowF() *Builder { + return builder.With(LightYellowF) +} + +// LightBlueF is a syntax for LightBlueF. +func (builder *Builder) LightBlueF() *Builder { + return builder.With(LightBlueF) +} + +// LightMagentaF is a syntax for LightMagentaF. +func (builder *Builder) LightMagentaF() *Builder { + return builder.With(LightMagentaF) +} + +// LightCyanF is a syntax for LightCyanF. +func (builder *Builder) LightCyanF() *Builder { + return builder.With(LightCyanF) +} + +// LightWhiteF is a syntax for LightWhiteF. +func (builder *Builder) LightWhiteF() *Builder { + return builder.With(LightWhiteF) +} + +// LightBlackB is a syntax for LightBlackB. +func (builder *Builder) LightBlackB() *Builder { + return builder.With(LightBlackB) +} + +// LightRedB is a syntax for LightRedB. +func (builder *Builder) LightRedB() *Builder { + return builder.With(LightRedB) +} + +// LightGreenB is a syntax for LightGreenB. +func (builder *Builder) LightGreenB() *Builder { + return builder.With(LightGreenB) +} + +// LightYellowB is a syntax for LightYellowB. +func (builder *Builder) LightYellowB() *Builder { + return builder.With(LightYellowB) +} + +// LightBlueB is a syntax for LightBlueB. +func (builder *Builder) LightBlueB() *Builder { + return builder.With(LightBlueB) +} + +// LightMagentaB is a syntax for LightMagentaB. +func (builder *Builder) LightMagentaB() *Builder { + return builder.With(LightMagentaB) +} + +// LightCyanB is a syntax for LightCyanB. +func (builder *Builder) LightCyanB() *Builder { + return builder.With(LightCyanB) +} + +// LightWhiteB is a syntax for LightWhiteB. +func (builder *Builder) LightWhiteB() *Builder { + return builder.With(LightWhiteB) +} + +// Color3BitF is a syntax for Color3BitF. +func (builder *Builder) Color3BitF(c RGB3Bit) *Builder { + return builder.With(Color3BitF(c)) +} + +// Color3BitB is a syntax for Color3BitB. +func (builder *Builder) Color3BitB(c RGB3Bit) *Builder { + return builder.With(Color3BitB(c)) +} + +// Color8BitF is a syntax for Color8BitF. +func (builder *Builder) Color8BitF(c RGB8Bit) *Builder { + return builder.With(Color8BitF(c)) +} + +// Color8BitB is a syntax for Color8BitB. +func (builder *Builder) Color8BitB(c RGB8Bit) *Builder { + return builder.With(Color8BitB(c)) +} + +// FullColorF is a syntax for FullColorF. +func (builder *Builder) FullColorF(r, g, b uint8) *Builder { + return builder.With(FullColorF(r, g, b)) +} + +// FullColorB is a syntax for FullColorB. +func (builder *Builder) FullColorB(r, g, b uint8) *Builder { + return builder.With(FullColorB(r, g, b)) +} + +// RGB3BitF is a syntax for Color3BitF with NewRGB3Bit. +func (builder *Builder) RGB3BitF(r, g, b uint8) *Builder { + return builder.Color3BitF(NewRGB3Bit(r, g, b)) +} + +// RGB3BitB is a syntax for Color3BitB with NewRGB3Bit. +func (builder *Builder) RGB3BitB(r, g, b uint8) *Builder { + return builder.Color3BitB(NewRGB3Bit(r, g, b)) +} + +// RGB8BitF is a syntax for Color8BitF with NewRGB8Bit. +func (builder *Builder) RGB8BitF(r, g, b uint8) *Builder { + return builder.Color8BitF(NewRGB8Bit(r, g, b)) +} + +// RGB8BitB is a syntax for Color8BitB with NewRGB8Bit. +func (builder *Builder) RGB8BitB(r, g, b uint8) *Builder { + return builder.Color8BitB(NewRGB8Bit(r, g, b)) +} + +func init() { + EmptyBuilder = &Builder{empty} +} diff --git a/vendor/github.com/morikuni/aec/sample.gif b/vendor/github.com/morikuni/aec/sample.gif new file mode 100644 index 000000000000..c6c613bb7064 Binary files /dev/null and b/vendor/github.com/morikuni/aec/sample.gif differ diff --git a/vendor/github.com/morikuni/aec/sgr.go b/vendor/github.com/morikuni/aec/sgr.go new file mode 100644 index 000000000000..0ba3464e6dbd --- /dev/null +++ b/vendor/github.com/morikuni/aec/sgr.go @@ -0,0 +1,202 @@ +package aec + +import ( + "fmt" +) + +// RGB3Bit is a 3bit RGB color. +type RGB3Bit uint8 + +// RGB8Bit is a 8bit RGB color. +type RGB8Bit uint8 + +func newSGR(n uint) ANSI { + return newAnsi(fmt.Sprintf(esc+"%dm", n)) +} + +// NewRGB3Bit create a RGB3Bit from given RGB. +func NewRGB3Bit(r, g, b uint8) RGB3Bit { + return RGB3Bit((r >> 7) | ((g >> 6) & 0x2) | ((b >> 5) & 0x4)) +} + +// NewRGB8Bit create a RGB8Bit from given RGB. +func NewRGB8Bit(r, g, b uint8) RGB8Bit { + return RGB8Bit(16 + 36*(r/43) + 6*(g/43) + b/43) +} + +// Color3BitF set the foreground color of text. +func Color3BitF(c RGB3Bit) ANSI { + return newAnsi(fmt.Sprintf(esc+"%dm", c+30)) +} + +// Color3BitB set the background color of text. +func Color3BitB(c RGB3Bit) ANSI { + return newAnsi(fmt.Sprintf(esc+"%dm", c+40)) +} + +// Color8BitF set the foreground color of text. +func Color8BitF(c RGB8Bit) ANSI { + return newAnsi(fmt.Sprintf(esc+"38;5;%dm", c)) +} + +// Color8BitB set the background color of text. +func Color8BitB(c RGB8Bit) ANSI { + return newAnsi(fmt.Sprintf(esc+"48;5;%dm", c)) +} + +// FullColorF set the foreground color of text. +func FullColorF(r, g, b uint8) ANSI { + return newAnsi(fmt.Sprintf(esc+"38;2;%d;%d;%dm", r, g, b)) +} + +// FullColorB set the foreground color of text. +func FullColorB(r, g, b uint8) ANSI { + return newAnsi(fmt.Sprintf(esc+"48;2;%d;%d;%dm", r, g, b)) +} + +// Style +var ( + // Bold set the text style to bold or increased intensity. + Bold ANSI + + // Faint set the text style to faint. + Faint ANSI + + // Italic set the text style to italic. + Italic ANSI + + // Underline set the text style to underline. + Underline ANSI + + // BlinkSlow set the text style to slow blink. + BlinkSlow ANSI + + // BlinkRapid set the text style to rapid blink. + BlinkRapid ANSI + + // Inverse swap the foreground color and background color. + Inverse ANSI + + // Conceal set the text style to conceal. + Conceal ANSI + + // CrossOut set the text style to crossed out. + CrossOut ANSI + + // Frame set the text style to framed. + Frame ANSI + + // Encircle set the text style to encircled. + Encircle ANSI + + // Overline set the text style to overlined. + Overline ANSI +) + +// Foreground color of text. +var ( + // DefaultF is the default color of foreground. + DefaultF ANSI + + // Normal color + BlackF ANSI + RedF ANSI + GreenF ANSI + YellowF ANSI + BlueF ANSI + MagentaF ANSI + CyanF ANSI + WhiteF ANSI + + // Light color + LightBlackF ANSI + LightRedF ANSI + LightGreenF ANSI + LightYellowF ANSI + LightBlueF ANSI + LightMagentaF ANSI + LightCyanF ANSI + LightWhiteF ANSI +) + +// Background color of text. +var ( + // DefaultB is the default color of background. + DefaultB ANSI + + // Normal color + BlackB ANSI + RedB ANSI + GreenB ANSI + YellowB ANSI + BlueB ANSI + MagentaB ANSI + CyanB ANSI + WhiteB ANSI + + // Light color + LightBlackB ANSI + LightRedB ANSI + LightGreenB ANSI + LightYellowB ANSI + LightBlueB ANSI + LightMagentaB ANSI + LightCyanB ANSI + LightWhiteB ANSI +) + +func init() { + Bold = newSGR(1) + Faint = newSGR(2) + Italic = newSGR(3) + Underline = newSGR(4) + BlinkSlow = newSGR(5) + BlinkRapid = newSGR(6) + Inverse = newSGR(7) + Conceal = newSGR(8) + CrossOut = newSGR(9) + + BlackF = newSGR(30) + RedF = newSGR(31) + GreenF = newSGR(32) + YellowF = newSGR(33) + BlueF = newSGR(34) + MagentaF = newSGR(35) + CyanF = newSGR(36) + WhiteF = newSGR(37) + + DefaultF = newSGR(39) + + BlackB = newSGR(40) + RedB = newSGR(41) + GreenB = newSGR(42) + YellowB = newSGR(43) + BlueB = newSGR(44) + MagentaB = newSGR(45) + CyanB = newSGR(46) + WhiteB = newSGR(47) + + DefaultB = newSGR(49) + + Frame = newSGR(51) + Encircle = newSGR(52) + Overline = newSGR(53) + + LightBlackF = newSGR(90) + LightRedF = newSGR(91) + LightGreenF = newSGR(92) + LightYellowF = newSGR(93) + LightBlueF = newSGR(94) + LightMagentaF = newSGR(95) + LightCyanF = newSGR(96) + LightWhiteF = newSGR(97) + + LightBlackB = newSGR(100) + LightRedB = newSGR(101) + LightGreenB = newSGR(102) + LightYellowB = newSGR(103) + LightBlueB = newSGR(104) + LightMagentaB = newSGR(105) + LightCyanB = newSGR(106) + LightWhiteB = newSGR(107) +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/.gitignore b/vendor/github.com/rootless-containers/rootlesskit/.gitignore new file mode 100644 index 000000000000..e660fd93d319 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/.gitignore @@ -0,0 +1 @@ +bin/ diff --git a/vendor/github.com/rootless-containers/rootlesskit/.travis.yml b/vendor/github.com/rootless-containers/rootlesskit/.travis.yml new file mode 100644 index 000000000000..383fd02dbf77 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/.travis.yml @@ -0,0 +1,8 @@ +dist: trusty +sudo: required + +services: + - docker + +script: + - ./hack/test.sh diff --git a/vendor/github.com/rootless-containers/rootlesskit/Gopkg.lock b/vendor/github.com/rootless-containers/rootlesskit/Gopkg.lock new file mode 100644 index 000000000000..36b4a002fe00 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/Gopkg.lock @@ -0,0 +1,175 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + digest = "1:f9ae348e1f793dcf9ed930ed47136a67343dbd6809c5c91391322267f4476892" + name = "github.com/Microsoft/go-winio" + packages = ["."] + pruneopts = "UT" + revision = "1a8911d1ed007260465c3bfbbc785ac6915a0bb8" + version = "v0.4.12" + +[[projects]] + branch = "master" + digest = "1:e48c63e818c67fbf3d7afe20bba33134ab1a5bf384847385384fd027652a5a96" + name = "github.com/containerd/continuity" + packages = ["pathdriver"] + pruneopts = "UT" + revision = "004b46473808b3e7a4a3049c20e4376c91eb966d" + +[[projects]] + branch = "master" + digest = "1:89dcd15024ee0d555b0b481e6e76a2b07dbd1e0824f4af19d10ace4736958e4a" + name = "github.com/docker/docker" + packages = [ + "pkg/idtools", + "pkg/mount", + "pkg/system", + ] + pruneopts = "UT" + revision = "c12f09bf99b54f274a5ae241dd154fa74020cbab" + +[[projects]] + digest = "1:6f82cacd0af5921e99bf3f46748705239b36489464f4529a1589bc895764fb18" + name = "github.com/docker/go-units" + packages = ["."] + pruneopts = "UT" + revision = "47565b4f722fb6ceae66b95f853feed578a4a51c" + version = "v0.3.3" + +[[projects]] + digest = "1:582b704bebaa06b48c29b0cec224a6058a09c86883aaddabde889cd1a5f73e1b" + name = "github.com/google/uuid" + packages = ["."] + pruneopts = "UT" + revision = "0cd6bf5da1e1c83f8b45653022c74f71af0538a4" + version = "v1.1.1" + +[[projects]] + digest = "1:ca59b1175189b3f0e9f1793d2c350114be36eaabbe5b9f554b35edee1de50aea" + name = "github.com/gorilla/mux" + packages = ["."] + pruneopts = "UT" + revision = "a7962380ca08b5a188038c69871b8d3fbdf31e89" + version = "v1.7.0" + +[[projects]] + branch = "master" + digest = "1:dd1e851f4e3a5ee3f51613c79a01666e04e5e9289e2da3f6f815c008010fc02f" + name = "github.com/jamescun/tuntap" + packages = ["."] + pruneopts = "UT" + revision = "434f1022c06e56e7e283a2dbe05b1481201fb5fe" + +[[projects]] + digest = "1:31e761d97c76151dde79e9d28964a812c46efc5baee4085b86f68f0c654450de" + name = "github.com/konsorten/go-windows-terminal-sequences" + packages = ["."] + pruneopts = "UT" + revision = "f55edac94c9bbba5d6182a4be46d86a2c9b5b50e" + version = "v1.0.2" + +[[projects]] + branch = "master" + digest = "1:7ebb95e7ff71069f17b26e1190df4cff019f170017202f00cd36a6262b03d20b" + name = "github.com/moby/vpnkit" + packages = ["go/pkg/vmnet"] + pruneopts = "UT" + revision = "c253dad08f384fa2ed3ad5961455eaa5c6531dd9" + +[[projects]] + digest = "1:ee4d4af67d93cc7644157882329023ce9a7bcfce956a079069a9405521c7cc8d" + name = "github.com/opencontainers/go-digest" + packages = ["."] + pruneopts = "UT" + revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf" + version = "v1.0.0-rc1" + +[[projects]] + digest = "1:11db38d694c130c800d0aefb502fb02519e514dc53d9804ce51d1ad25ec27db6" + name = "github.com/opencontainers/image-spec" + packages = [ + "specs-go", + "specs-go/v1", + ] + pruneopts = "UT" + revision = "d60099175f88c47cd379c4738d158884749ed235" + version = "v1.0.1" + +[[projects]] + branch = "master" + digest = "1:eecbbd6bfbfbe1acdad4b22c4fd530ab569df1634deef359e40d2ee4f85057f9" + name = "github.com/opencontainers/runc" + packages = ["libcontainer/user"] + pruneopts = "UT" + revision = "6a3f4749b81768cd01ef3da117ef0a19cd572652" + +[[projects]] + digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" + name = "github.com/pkg/errors" + packages = ["."] + pruneopts = "UT" + revision = "ba968bfe8b2f7e042a574c888954fccecfa385b4" + version = "v0.8.1" + +[[projects]] + digest = "1:fd61cf4ae1953d55df708acb6b91492d538f49c305b364a014049914495db426" + name = "github.com/sirupsen/logrus" + packages = ["."] + pruneopts = "UT" + revision = "8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f" + version = "v1.4.1" + +[[projects]] + digest = "1:d7b2d6ad2a9768bb5c9e3bfa4d9ceaa635ca2737cca288507986f116fa4b8da2" + name = "github.com/theckman/go-flock" + packages = ["."] + pruneopts = "UT" + revision = "392e7fae8f1b0bdbd67dad7237d23f618feb6dbb" + version = "v0.7.1" + +[[projects]] + digest = "1:b24d38b282bacf9791408a080f606370efa3d364e4b5fd9ba0f7b87786d3b679" + name = "github.com/urfave/cli" + packages = ["."] + pruneopts = "UT" + revision = "cfb38830724cc34fedffe9a2a29fb54fa9169cd1" + version = "v1.20.0" + +[[projects]] + branch = "master" + digest = "1:7ccb2dbb79f60b4e530c7dc3a0b3681b3869cf7ea91c645735e4dd4e6e3264fd" + name = "golang.org/x/net" + packages = ["context/ctxhttp"] + pruneopts = "UT" + revision = "74de082e2cca95839e88aa0aeee5aadf6ce7710f" + +[[projects]] + branch = "master" + digest = "1:aa9254a749f8b6d34bfa7e422b9365f255d0e2457d4bb8d3de1e7b22d8b81410" + name = "golang.org/x/sys" + packages = [ + "unix", + "windows", + ] + pruneopts = "UT" + revision = "baf5eb976a8cd65845293cd814ea151018552292" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + input-imports = [ + "github.com/docker/docker/pkg/idtools", + "github.com/google/uuid", + "github.com/gorilla/mux", + "github.com/jamescun/tuntap", + "github.com/moby/vpnkit/go/pkg/vmnet", + "github.com/pkg/errors", + "github.com/sirupsen/logrus", + "github.com/theckman/go-flock", + "github.com/urfave/cli", + "golang.org/x/net/context/ctxhttp", + "golang.org/x/sys/unix", + ] + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/vendor/github.com/rootless-containers/rootlesskit/Gopkg.toml b/vendor/github.com/rootless-containers/rootlesskit/Gopkg.toml new file mode 100644 index 000000000000..9a1b2653cf7d --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/Gopkg.toml @@ -0,0 +1,41 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + +[[override]] + name = "github.com/opencontainers/runc" + branch = "master" + +[[override]] + name = "github.com/docker/docker" + branch = "master" + +[[override]] + name = "github.com/moby/vpnkit" + branch = "master" + +[prune] + go-tests = true + unused-packages = true diff --git a/vendor/github.com/rootless-containers/rootlesskit/LICENSE b/vendor/github.com/rootless-containers/rootlesskit/LICENSE new file mode 100644 index 000000000000..d64569567334 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/rootless-containers/rootlesskit/Makefile b/vendor/github.com/rootless-containers/rootlesskit/Makefile new file mode 100644 index 000000000000..6363e82eeced --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/Makefile @@ -0,0 +1,23 @@ +GO=go +GO_FILES=$(shell find . -name *.go) +BINARIES=rootlesskit rootlessctl rootlesskit-docker-proxy + +.PHONY: all +all: $(addprefix bin/, $(BINARIES)) + +.PHONY: clean +clean: + $(RM) -r bin/ + +bin/rootlesskit: $(GO_FILES) + $(GO) build -o $@ -v github.com/rootless-containers/rootlesskit/cmd/rootlesskit + +bin/rootlessctl: $(GO_FILES) + $(GO) build -o $@ -v github.com/rootless-containers/rootlesskit/cmd/rootlessctl + +bin/rootlesskit-docker-proxy: $(GO_FILES) + $(GO) build -o $@ -v github.com/rootless-containers/rootlesskit/cmd/rootlesskit-docker-proxy + +.PHONY: test +test: + ./hack/test.sh diff --git a/vendor/github.com/rootless-containers/rootlesskit/README.md b/vendor/github.com/rootless-containers/rootlesskit/README.md new file mode 100644 index 000000000000..634918537f7d --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/README.md @@ -0,0 +1,283 @@ +# RootlessKit: the gate to the rootless world + +`rootlesskit` is a kind of Linux-native "fake root" utility, made for mainly running [Docker and Kubernetes as an unprivileged user](https://github.com/rootless-containers/usernetes). + +`rootlesskit` does an equivalent of [`unshare(1)`](http://man7.org/linux/man-pages/man1/unshare.1.html) and [`newuidmap(1)`](http://man7.org/linux/man-pages/man1/newuidmap.1.html)/[`newgidmap(1)`](http://man7.org/linux/man-pages/man1/newgidmap.1.html) in a single command, for creating unprivileged [`user_namespaces(7)`](http://man7.org/linux/man-pages/man7/user_namespaces.7.html) and [`mount_namespaces(7)`](http://man7.org/linux/man-pages/man7/user_namespaces.7.html) with [`subuid(5)`](http://man7.org/linux/man-pages/man5/subuid.5.html) and [`subgid(5)`](http://man7.org/linux/man-pages/man5/subgid.5.html). + +`rootlesskit` also supports network namespace isolation and userspace NAT using ["slirp"](#slirp). +Kernel NAT using SUID-enabled [`lxc-user-nic(1)`](https://linuxcontainers.org/lxc/manpages/man1/lxc-user-nic.1.html) is also on the plan. + +## Projects using RootlessKit + +* [Usernetes](https://github.com/rootless-containers/usernetes): Docker & Kubernetes, installable under a non-root user's `$HOME`. +* [BuildKit](https://github.com/moby/buildkit): Next-generation `docker build` backend + +## Setup + +```console +$ go get github.com/rootless-containers/rootlesskit/cmd/rootlesskit +$ go get github.com/rootless-containers/rootlesskit/cmd/rootlessctl +``` + +Requirements: +* Some distros such as Debian (excluding Ubuntu) and Arch Linux require `sudo sh -c "echo 1 > /proc/sys/kernel/unprivileged_userns_clone"`. +* `newuidmap` and `newgidmap` need to be installed on the host. These commands are provided by the `uidmap` package on most distros. +* `/etc/subuid` and `/etc/subgid` should contain >= 65536 sub-IDs. e.g. `penguin:231072:65536`. + +```console +$ id -u +1001 +$ whoami +penguin +$ grep ^$(whoami): /etc/subuid +penguin:231072:65536 +$ grep ^$(whoami): /etc/subgid +penguin:231072:65536 +``` + + +## Usage + +Inside `rootlesskit`, your UID is mapped to 0 but it is not the real root: + +```console +$ rootlesskit bash +rootlesskit$ id +uid=0(root) gid=0(root) groups=0(root),65534(nogroup) +rootlesskit$ ls -l /etc/shadow +-rw-r----- 1 nobody nogroup 1050 Aug 21 19:02 /etc/shadow +rootlesskit$ $ cat /etc/shadow +cat: /etc/shadow: Permission denied +``` + +Environment variables are kept untouched: + +```console +$ rootlesskit bash +rootlesskit$ echo $USER +penguin +rootlesskit$ echo $HOME +/home/penguin +rootlesskit$ echo $XDG_RUNTIME_DIR +/run/user/1001 +``` + +Filesystems can be isolated from the host with `--copy-up`: + +```console +$ rootlesskit --copy-up=/etc bash +rootlesskit$ rm /etc/resolv.conf +rootlesskit$ vi /etc/resolv.conf +``` + +You can even create network namespaces with [Slirp](#slirp): + +```console +$ rootlesskit --copy-up=/etc --copy-up=/run --net=slirp4netns bash +rootlesskit$ ip netns add foo +... +``` + +Proc filesystem view: + +```console +$ rootlesskit bash +rootlesskit$ cat /proc/self/uid_map + 0 1001 1 + 1 231072 65536 +rootlesskit$ cat /proc/self/gid_map + 0 1001 1 + 1 231072 65536 +rootlesskit$ cat /proc/self/setgroups +allow +``` + +Full CLI options: + +```console +$ rootlesskit --help +NAME: + rootlesskit - the gate to the rootless world + +USAGE: + rootlesskit [global options] command [command options] [arguments...] + +VERSION: + 0.3.0-alpha.0 + +COMMANDS: + help, h Shows a list of commands or help for one command + +GLOBAL OPTIONS: + --debug debug mode + --state-dir value state directory + --net value network driver [host, slirp4netns, vpnkit, vdeplug_slirp] (default: "host") + --slirp4netns-binary value path of slirp4netns binary for --net=slirp4netns (default: "slirp4netns") + --vpnkit-binary value path of VPNKit binary for --net=vpnkit (default: "vpnkit") + --mtu value MTU for non-host network (default: 65520 for slirp4netns, 1500 for others) (default: 0) + --cidr value CIDR for slirp4netns network (default: 10.0.2.0/24, requires slirp4netns v0.3.0+ for custom CIDR) + --disable-host-loopback prohibit connecting to 127.0.0.1:* on the host namespace + --copy-up value mount a filesystem and copy-up the contents. e.g. "--copy-up=/etc" (typically required for non-host network) + --copy-up-mode value copy-up mode [tmpfs+symlink] (default: "tmpfs+symlink") + --port-driver value port driver for non-host network. [none, socat] (default: "none") + --help, -h show help + --version, -v print the version +``` + +## Building from source +`rootlesskit` and `rootlessctl` can be built from source using: + +``` +make +``` + +## State directory + +The following files will be created in the `--state-dir` directory: +* `lock`: lock file +* `child_pid`: decimal PID text that can be used for `nsenter(1)`. +* `api.sock`: REST API socket for `rootlessctl`. See [Port forwarding](#port-forwarding) section. + +Undocumented files are subject to change. + +## Environment variables + +The following environment variables will be set for the child process: +* `ROOTLESSKIT_STATE_DIR` (since v0.3.0): absolute path to the state dir + +Undocumented environment variables are subject to change. + +## Slirp + +Remarks: +* Specifying `--copy-up=/etc` is highly recommended unless `/etc/resolv.conf` is statically configured. Otherwise `/etc/resolv.conf` will be invalidated when it is recreated on the host, typically by NetworkManager or systemd-resolved. + +Currently there are three slirp implementations supported by rootlesskit: +* `--net=slirp4netns`, using [slirp4netns](https://github.com/rootless-containers/slirp4netns) (recommended) +* `--net=vpnkit`, using [VPNKit](https://github.com/moby/vpnkit) +* `--net=vdeplug_slirp`, using [vdeplug_slirp](https://github.com/rd235/vdeplug_slirp) + +Usage: + +```console +$ rootlesskit --state-dir=/run/user/1001/rootlesskit/foo --net=slirp4netns --copy-up=/etc bash +rootlesskit$ ip a +1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 + link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 + inet 127.0.0.1/8 scope host lo + valid_lft forever preferred_lft forever + inet6 ::1/128 scope host + valid_lft forever preferred_lft forever +2: tap0: mtu 1500 qdisc fq_codel state UP group default qlen 1000 + link/ether 42:b6:8d:e4:02:c4 brd ff:ff:ff:ff:ff:ff + inet 10.0.2.100/24 scope global tap0 + valid_lft forever preferred_lft forever + inet6 fe80::40b6:8dff:fee4:2c4/64 scope link + valid_lft forever preferred_lft forever +rootlesskit$ ip r +default via 10.0.2.2 dev tap0 +10.0.2.0/24 dev tap0 proto kernel scope link src 10.0.2.100 +rootlesskit$ cat /etc/resolv.conf +nameserver 10.0.2.3 +rootlesskit$ curl https://www.google.com +... +``` + +Default network configuration for `--net=slirp4netns` and `--net=vdeplug_slirp`: +* IP: 10.0.2.100/24 +* Gateway: 10.0.2.2 +* DNS: 10.0.2.3 +* Host: 10.0.2.2, 10.0.2.3 + +Default network configuration for `--net=vpnkit`: +* IP: 192.168.65.3/24 +* Gateway: 192.168.65.1 +* DNS: 192.168.65.1 +* Host: 192.168.65.2 + +`--net=slirp4netns` supports specifying custom CIDR, e.g. `--cidr=10.0.3.0/24` (requires slirp4netns v0.3.0+) + +It is highly recommended to disable host loopback address by specyfing `--disable-host-loopback`. + +### Port forwarding + +`rootlessctl` can be used for exposing the ports in the network namespace to the host network namespace. +You also need to launch `rootlesskit` with `--port-driver=(socat|slirp4netns|builtin)`. `builtin` is the fastest but currently experimental. + +For example, to expose 80 in the child as 8080 in the parent: + +```console +$ rootlesskit --state-dir=/run/user/1001/rootlesskit/foo --net=slirp4netns --copy-up=/etc --port-driver=socat bash +rootlesskit$ rootlessctl --socket=/run/user/1001/rootlesskit/foo/api.sock add-ports 0.0.0.0:8080:80/tcp +1 +rootlesskit$ rootlessctl --socket=/run/user/1001/rootlesskit/foo/api.sock list-ports +ID PROTO PARENTIP PARENTPORT CHILDPORT +1 tcp 0.0.0.0 8080 80 +rootlesskit$ rootlessctl --socket=/run/user/1001/rootlesskit/foo/api.sock remove-ports 1 +1 +``` + +You can also expose the ports manually without using the API socket. +```console +$ pid=$(cat /run/user/1001/rootlesskit/foo/child_pid) +$ socat -t -- TCP-LISTEN:8080,reuseaddr,fork EXEC:"nsenter -U -n -t $pid socat -t -- STDIN TCP4\:127.0.0.1\:80" +``` + +### Routing ping packets + +To route ping packets, you need to set up `net.ipv4.ping_group_range` properly. + +```console +$ sudo sh -c "echo 0 2147483647 > /proc/sys/net/ipv4/ping_group_range" +``` + +Note: routing ping packets is not supported for `--net=vpnkit`. + +### Annex: benchmark (MTU=1500) + +Aug 1, 2018, on Travis: https://travis-ci.org/rootless-containers/rootlesskit/builds/410721610 + +* `--net=slirp4netns`: 1.07 Gbits/sec +* `--net=vpnkit`: 528 Mbits/sec +* `--net=vdeplug_slirp`: 771 Mbits/sec + +Note: slirp4netns can reach 8.18 Gbits/sec with MTU=65520: https://github.com/rootless-containers/slirp4netns/pull/20 + +### Annex: how to install `slirp4netns` (required for `--net=slirp4netns`) + +See also https://github.com/rootless-containers/slirp4netns + +```console +$ git clone https://github.com/rootless-containers/slirp4netns +$ cd slirp4netns +$ ./autogen.sh && ./configure && make +$ cp slirp4netns ~/bin +``` + +RPM is also available for Fedora: https://rpms.remirepo.net/rpmphp/zoom.php?rpm=slirp4netns + +```console +$ sudo dnf install slirp4netns +``` + +### Annex: how to install VPNKit (required for `--net=vpnkit`) + +See also https://github.com/moby/vpnkit + +```console +$ git clone https://github.com/moby/vpnkit.git +$ cd vpnkit +$ make +$ cp vpnkit.exe ~/bin/vpnkit +``` + +### Annex: how to install `vdeplug_slirp` (required for `--net=vdeplug_slirp`) + +You need to install the following components: + +* https://github.com/rd235/s2argv-execs +* https://github.com/rd235/vdeplug4 (depends on `s2argv-execs`) +* https://github.com/rd235/libslirp +* https://github.com/rd235/vdeplug_slirp (depends on `vdeplug4` and `libslirp`) + +Please refer to README in the each of the components. diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/api/client/client.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/api/client/client.go new file mode 100644 index 000000000000..914b0d1d8afa --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/api/client/client.go @@ -0,0 +1,151 @@ +package client + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net" + "net/http" + "os" + + "github.com/pkg/errors" + "golang.org/x/net/context/ctxhttp" + + "github.com/rootless-containers/rootlesskit/pkg/port" +) + +type Client interface { + HTTPClient() *http.Client + PortManager() port.Manager +} + +// New creates a client. +// socketPath is a path to the UNIX socket, without unix:// prefix. +func New(socketPath string) (Client, error) { + if _, err := os.Stat(socketPath); err != nil { + return nil, err + } + hc := &http.Client{ + Transport: &http.Transport{ + DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) { + var d net.Dialer + return d.DialContext(ctx, "unix", socketPath) + }, + }, + } + return NewWithHTTPClient(hc), nil +} + +func NewWithHTTPClient(hc *http.Client) Client { + return &client{ + Client: hc, + version: "v1", + dummyHost: "rootlesskit", + } +} + +type client struct { + *http.Client + // version is always "v1" + // TODO(AkihiroSuda): negotiate the version + version string + dummyHost string +} + +func (c *client) HTTPClient() *http.Client { + return c.Client +} + +func (c *client) PortManager() port.Manager { + return &portManager{ + client: c, + } +} + +func readAtMost(r io.Reader, maxBytes int) ([]byte, error) { + lr := &io.LimitedReader{ + R: r, + N: int64(maxBytes), + } + b, err := ioutil.ReadAll(lr) + if err != nil { + return b, err + } + if lr.N == 0 { + return b, errors.Errorf("expected at most %d bytes, got more", maxBytes) + } + return b, nil +} + +func successful(resp *http.Response) error { + if resp == nil { + return errors.New("nil response") + } + if resp.StatusCode/100 != 2 { + b, _ := readAtMost(resp.Body, 64*1024) + return errors.Errorf("unexpected HTTP status %s, body=%q", resp.Status, string(b)) + } + return nil +} + +type portManager struct { + *client +} + +func (pm *portManager) AddPort(ctx context.Context, spec port.Spec) (*port.Status, error) { + m, err := json.Marshal(spec) + if err != nil { + return nil, err + } + u := fmt.Sprintf("http://%s/%s/ports", pm.client.dummyHost, pm.client.version) + resp, err := ctxhttp.Post(ctx, pm.client.HTTPClient(), u, "application/json", bytes.NewReader(m)) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if err := successful(resp); err != nil { + return nil, err + } + dec := json.NewDecoder(resp.Body) + var status port.Status + if err := dec.Decode(&status); err != nil { + return nil, err + } + return &status, nil +} +func (pm *portManager) ListPorts(ctx context.Context) ([]port.Status, error) { + u := fmt.Sprintf("http://%s/%s/ports", pm.client.dummyHost, pm.client.version) + resp, err := ctxhttp.Get(ctx, pm.client.HTTPClient(), u) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if err := successful(resp); err != nil { + return nil, err + } + var statuses []port.Status + dec := json.NewDecoder(resp.Body) + if err := dec.Decode(&statuses); err != nil { + return nil, err + } + return statuses, nil +} +func (pm *portManager) RemovePort(ctx context.Context, id int) error { + u := fmt.Sprintf("http://%s/%s/ports/%d", pm.client.dummyHost, pm.client.version, id) + req, err := http.NewRequest("DELETE", u, nil) + if err != nil { + return err + } + resp, err := ctxhttp.Do(ctx, pm.client.HTTPClient(), req) + if err != nil { + return err + } + defer resp.Body.Close() + if err := successful(resp); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/api/openapi.yaml b/vendor/github.com/rootless-containers/rootlesskit/pkg/api/openapi.yaml new file mode 100644 index 000000000000..2accffb0f3bf --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/api/openapi.yaml @@ -0,0 +1,82 @@ +# When you made a change to this YAML, please validate with https://editor.swagger.io +openapi: 3.0.2 +info: + version: 1.0.0 + title: RootlessKit API +servers: + - url: 'http://rootlesskit/v1' + description: Local UNIX socket server. The host part of the URL is ignored. +paths: + /ports: + get: + responses: + '200': + description: An array of PortStatus + content: + application/json: + schema: + $ref: '#/components/schemas/PortStatuses' + post: + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/PortSpec' + responses: + '201': + description: PortStatus with ID + content: + application/json: + schema: + $ref: '#/components/schemas/PortStatus' + '/ports/{id}': + delete: + parameters: + - name: id + in: path + required: true + schema: + type: integer + format: int64 + responses: + '200': + description: Null response +components: + schemas: + PortSpec: + required: + - proto + properties: + proto: + type: string + enum: + - tcp + - udp + - sctp + parentIP: + type: string + parentPort: + type: integer + format: int32 + minimum: 1 + maximum: 65535 +# future version may support requests with parentPort<=0 for automatic port assignment + childPort: + type: integer + format: int32 + minimum: 1 + maximum: 65535 + PortStatus: + required: + - id + properties: + id: + type: integer + format: int64 + spec: + $ref: '#/components/schemas/PortSpec' + PortStatuses: + type: array + items: + $ref: '#/components/schemas/PortStatus' diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/api/router/router.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/api/router/router.go new file mode 100644 index 000000000000..93291df268e9 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/api/router/router.go @@ -0,0 +1,114 @@ +package router + +import ( + "context" + "encoding/json" + "net/http" + "strconv" + + "github.com/gorilla/mux" + "github.com/pkg/errors" + + "github.com/rootless-containers/rootlesskit/pkg/port" +) + +type Backend struct { + // PortDriver MUST be thread-safe. + // PortDriver can be nil + PortDriver port.ParentDriver +} + +func (b *Backend) onError(w http.ResponseWriter, r *http.Request, err error, ec int) { + w.WriteHeader(ec) + w.Header().Set("Content-Type", "application/json") + // it is safe to return the err to the client, because the client is reliable + type errorJSON struct { + Message string `json:"message"` + } + e := errorJSON{ + Message: err.Error(), + } + _ = json.NewEncoder(w).Encode(e) +} + +func (b *Backend) onPortDriverNil(w http.ResponseWriter, r *http.Request) { + b.onError(w, r, errors.New("no PortDriver is available"), http.StatusBadRequest) +} + +// GetPorts is handler for GET /v{N}/ports +func (b *Backend) GetPorts(w http.ResponseWriter, r *http.Request) { + if b.PortDriver == nil { + b.onPortDriverNil(w, r) + return + } + ports, err := b.PortDriver.ListPorts(context.TODO()) + if err != nil { + b.onError(w, r, err, http.StatusInternalServerError) + return + } + m, err := json.Marshal(ports) + if err != nil { + b.onError(w, r, err, http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(m) +} + +// PostPort is the handler for POST /v{N}/ports +func (b *Backend) PostPort(w http.ResponseWriter, r *http.Request) { + if b.PortDriver == nil { + b.onPortDriverNil(w, r) + return + } + decoder := json.NewDecoder(r.Body) + var portSpec port.Spec + if err := decoder.Decode(&portSpec); err != nil { + b.onError(w, r, err, http.StatusBadRequest) + return + } + portStatus, err := b.PortDriver.AddPort(context.TODO(), portSpec) + if err != nil { + b.onError(w, r, err, http.StatusBadRequest) + return + } + m, err := json.Marshal(portStatus) + if err != nil { + b.onError(w, r, err, http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusCreated) + w.Write(m) +} + +// DeletePort is the handler for POST /v{N}/ports/{id} +func (b *Backend) DeletePort(w http.ResponseWriter, r *http.Request) { + if b.PortDriver == nil { + b.onPortDriverNil(w, r) + return + } + idStr, ok := mux.Vars(r)["id"] + if !ok { + b.onError(w, r, errors.New("id not specified"), http.StatusBadRequest) + return + } + id, err := strconv.Atoi(idStr) + if err != nil { + b.onError(w, r, errors.Wrapf(err, "bad id %s", idStr), http.StatusBadRequest) + return + } + if err := b.PortDriver.RemovePort(context.TODO(), id); err != nil { + b.onError(w, r, err, http.StatusBadRequest) + return + } + w.WriteHeader(http.StatusOK) +} + +func AddRoutes(r *mux.Router, b *Backend) { + v1 := r.PathPrefix("/v1").Subrouter() + v1.Path("/ports").Methods("GET").HandlerFunc(b.GetPorts) + v1.Path("/ports").Methods("POST").HandlerFunc(b.PostPort) + v1.Path("/ports/{id}").Methods("DELETE").HandlerFunc(b.DeletePort) +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/child/child.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/child.go new file mode 100644 index 000000000000..8b2b581b5b86 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/child.go @@ -0,0 +1,224 @@ +package child + +import ( + "io/ioutil" + "os" + "os/exec" + "strconv" + "syscall" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + "github.com/rootless-containers/rootlesskit/pkg/common" + "github.com/rootless-containers/rootlesskit/pkg/copyup" + "github.com/rootless-containers/rootlesskit/pkg/msgutil" + "github.com/rootless-containers/rootlesskit/pkg/network" + "github.com/rootless-containers/rootlesskit/pkg/port" +) + +func createCmd(targetCmd []string) (*exec.Cmd, error) { + var args []string + if len(targetCmd) > 1 { + args = targetCmd[1:] + } + cmd := exec.Command(targetCmd[0], args...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.Env = os.Environ() + cmd.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + } + return cmd, nil +} + +// mountSysfs is needed for mounting /sys/class/net +// when netns is unshared. +func mountSysfs() error { + tmp, err := ioutil.TempDir("/tmp", "rksys") + if err != nil { + return errors.Wrap(err, "creating a directory under /tmp") + } + defer os.RemoveAll(tmp) + cmds := [][]string{{"mount", "--rbind", "/sys/fs/cgroup", tmp}} + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + return errors.Wrapf(err, "executing %v", cmds) + } + cmds = [][]string{{"mount", "-t", "sysfs", "none", "/sys"}} + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + // when the sysfs in the parent namespace is RO, + // we can't mount RW sysfs even in the child namespace. + // https://github.com/rootless-containers/rootlesskit/pull/23#issuecomment-429292632 + // https://github.com/torvalds/linux/blob/9f203e2f2f065cd74553e6474f0ae3675f39fb0f/fs/namespace.c#L3326-L3328 + cmdsRo := [][]string{{"mount", "-t", "sysfs", "-o", "ro", "none", "/sys"}} + logrus.Warnf("failed to mount sysfs (%v), falling back to read-only mount (%v): %v", + cmds, cmdsRo, err) + if err := common.Execs(os.Stderr, os.Environ(), cmdsRo); err != nil { + // when /sys/firmware is masked, even RO sysfs can't be mounted + logrus.Warnf("failed to mount sysfs (%v): %v", cmdsRo, err) + } + } + cmds = [][]string{{"mount", "-n", "--move", tmp, "/sys/fs/cgroup"}} + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + return errors.Wrapf(err, "executing %v", cmds) + } + return nil +} + +func activateLoopback() error { + cmds := [][]string{ + {"ip", "link", "set", "lo", "up"}, + } + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + return errors.Wrapf(err, "executing %v", cmds) + } + return nil +} + +func activateTap(tap, ip string, netmask int, gateway string, mtu int) error { + cmds := [][]string{ + {"ip", "link", "set", tap, "up"}, + {"ip", "link", "set", "dev", tap, "mtu", strconv.Itoa(mtu)}, + {"ip", "addr", "add", ip + "/" + strconv.Itoa(netmask), "dev", tap}, + {"ip", "route", "add", "default", "via", gateway, "dev", tap}, + } + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + return errors.Wrapf(err, "executing %v", cmds) + } + return nil +} + +func setupCopyDir(driver copyup.ChildDriver, dirs []string) (bool, error) { + if driver != nil { + etcWasCopied := false + copied, err := driver.CopyUp(dirs) + for _, d := range copied { + if d == "/etc" { + etcWasCopied = true + break + } + } + return etcWasCopied, err + } + if len(dirs) != 0 { + return false, errors.New("copy-up driver is not specified") + } + return false, nil +} + +func setupNet(msg common.Message, etcWasCopied bool, driver network.ChildDriver) error { + // HostNetwork + if driver == nil { + return nil + } + // for /sys/class/net + if err := mountSysfs(); err != nil { + return err + } + if err := activateLoopback(); err != nil { + return err + } + tap, err := driver.ConfigureTap(msg.Network) + if err != nil { + return err + } + if err := activateTap(tap, msg.Network.IP, msg.Network.Netmask, msg.Network.Gateway, msg.Network.MTU); err != nil { + return err + } + if etcWasCopied { + if err := writeResolvConf(msg.Network.DNS); err != nil { + return err + } + if err := writeEtcHosts(); err != nil { + return err + } + } else { + logrus.Warn("Mounting /etc/resolv.conf without copying-up /etc. " + + "Note that /etc/resolv.conf in the namespace will be unmounted when it is recreated on the host. " + + "Unless /etc/resolv.conf is statically configured, copying-up /etc is highly recommended. " + + "Please refer to RootlessKit documentation for further information.") + if err := mountResolvConf(msg.StateDir, msg.Network.DNS); err != nil { + return err + } + if err := mountEtcHosts(msg.StateDir); err != nil { + return err + } + } + return nil +} + +type Opt struct { + PipeFDEnvKey string // needs to be set + TargetCmd []string // needs to be set + NetworkDriver network.ChildDriver // nil for HostNetwork + CopyUpDriver copyup.ChildDriver // cannot be nil if len(CopyUpDirs) != 0 + CopyUpDirs []string + PortDriver port.ChildDriver +} + +func Child(opt Opt) error { + if opt.PipeFDEnvKey == "" { + return errors.New("pipe FD env key is not set") + } + pipeFDStr := os.Getenv(opt.PipeFDEnvKey) + if pipeFDStr == "" { + return errors.Errorf("%s is not set", opt.PipeFDEnvKey) + } + pipeFD, err := strconv.Atoi(pipeFDStr) + if err != nil { + return errors.Wrapf(err, "unexpected fd value: %s", pipeFDStr) + } + pipeR := os.NewFile(uintptr(pipeFD), "") + var msg common.Message + if _, err := msgutil.UnmarshalFromReader(pipeR, &msg); err != nil { + return errors.Wrapf(err, "parsing message from fd %d", pipeFD) + } + logrus.Debugf("child: got msg from parent: %+v", msg) + if msg.Stage == 0 { + // the parent has configured the child's uid_map and gid_map, but the child doesn't have caps here. + // so we exec the child again to obtain caps. + // PID should be kept. + if err = syscall.Exec("/proc/self/exe", os.Args, os.Environ()); err != nil { + return err + } + panic("should not reach here") + } + if msg.Stage != 1 { + return errors.Errorf("expected stage 1, got stage %d", msg.Stage) + } + os.Unsetenv(opt.PipeFDEnvKey) + if err := pipeR.Close(); err != nil { + return errors.Wrapf(err, "failed to close fd %d", pipeFD) + } + if msg.StateDir == "" { + return errors.New("got empty StateDir") + } + etcWasCopied, err := setupCopyDir(opt.CopyUpDriver, opt.CopyUpDirs) + if err != nil { + return err + } + if err := setupNet(msg, etcWasCopied, opt.NetworkDriver); err != nil { + return err + } + portQuitCh := make(chan struct{}) + portErrCh := make(chan error) + if opt.PortDriver != nil { + go func() { + portErrCh <- opt.PortDriver.RunChildDriver(msg.Port.Opaque, portQuitCh) + }() + } + + cmd, err := createCmd(opt.TargetCmd) + if err != nil { + return err + } + if err := cmd.Run(); err != nil { + return errors.Wrapf(err, "command %v exited", opt.TargetCmd) + } + if opt.PortDriver != nil { + portQuitCh <- struct{}{} + return <-portErrCh + } + return nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/child/hosts.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/hosts.go new file mode 100644 index 000000000000..4f739102100c --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/hosts.go @@ -0,0 +1,66 @@ +package child + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "github.com/pkg/errors" + + "github.com/rootless-containers/rootlesskit/pkg/common" +) + +// generateEtcHosts makes sure the current hostname is resolved into +// 127.0.0.1 or ::1, not into the host eth0 IP address. +// +// Note that /etc/hosts is not used by nslookup/dig. (Use `getent ahostsv4` instead.) +func generateEtcHosts() ([]byte, error) { + etcHosts, err := ioutil.ReadFile("/etc/hosts") + if err != nil { + return nil, err + } + hostname, err := os.Hostname() + if err != nil { + return nil, err + } + // FIXME: no need to add the entry if already added + s := fmt.Sprintf("%s\n127.0.0.1 %s\n::1 %s\n", + string(etcHosts), hostname, hostname) + return []byte(s), nil +} + +// writeEtcHosts is akin to writeResolvConf +// TODO: dedupe +func writeEtcHosts() error { + newEtcHosts, err := generateEtcHosts() + if err != nil { + return err + } + // remove copied-up link + _ = os.Remove("/etc/hosts") + if err := ioutil.WriteFile("/etc/hosts", newEtcHosts, 0644); err != nil { + return errors.Wrapf(err, "writing /etc/hosts") + } + return nil +} + +// mountEtcHosts is akin to mountResolvConf +// TODO: dedupe +func mountEtcHosts(tempDir string) error { + newEtcHosts, err := generateEtcHosts() + if err != nil { + return err + } + myEtcHosts := filepath.Join(tempDir, "hosts") + if err := ioutil.WriteFile(myEtcHosts, newEtcHosts, 0644); err != nil { + return errors.Wrapf(err, "writing %s", myEtcHosts) + } + cmds := [][]string{ + {"mount", "--bind", myEtcHosts, "/etc/hosts"}, + } + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + return errors.Wrapf(err, "executing %v", cmds) + } + return nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/child/resolvconf.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/resolvconf.go new file mode 100644 index 000000000000..56cc70926a22 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/child/resolvconf.go @@ -0,0 +1,46 @@ +package child + +import ( + "io/ioutil" + "os" + "path/filepath" + + "github.com/pkg/errors" + + "github.com/rootless-containers/rootlesskit/pkg/common" +) + +func generateResolvConf(dns string) []byte { + return []byte("nameserver " + dns + "\n") +} + +func writeResolvConf(dns string) error { + // remove copied-up link + _ = os.Remove("/etc/resolv.conf") + if err := ioutil.WriteFile("/etc/resolv.conf", generateResolvConf(dns), 0644); err != nil { + return errors.Wrapf(err, "writing %s", "/etc/resolv.conf") + } + return nil +} + +// mountResolvConf does not work when /etc/resolv.conf is a managed by +// systemd or NetworkManager, because our bind-mounted /etc/resolv.conf (in our namespaces) +// is unexpectedly unmounted when /etc/resolv.conf is recreated in the initial initial namespace. +// +// If /etc/resolv.conf is a symlink, e.g. to ../run/systemd/resolve/stub-resolv.conf, +// our bind-mounted /etc/resolv.conf is still unmounted when /run/systemd/resolve/stub-resolv.conf is recreated. +// +// Use writeResolvConf with copying-up /etc for most cases. +func mountResolvConf(tempDir, dns string) error { + myResolvConf := filepath.Join(tempDir, "resolv.conf") + if err := ioutil.WriteFile(myResolvConf, generateResolvConf(dns), 0644); err != nil { + return errors.Wrapf(err, "writing %s", myResolvConf) + } + cmds := [][]string{ + {"mount", "--bind", myResolvConf, "/etc/resolv.conf"}, + } + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + return errors.Wrapf(err, "executing %v", cmds) + } + return nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/common/common.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/common/common.go new file mode 100644 index 000000000000..461a3ac4cc1b --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/common/common.go @@ -0,0 +1,12 @@ +package common + +func Seq(fns []func() error) func() error { + return func() error { + for _, fn := range fns { + if err := fn(); err != nil { + return err + } + } + return nil + } +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/common/exec.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/common/exec.go new file mode 100644 index 000000000000..3d4c7d721fde --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/common/exec.go @@ -0,0 +1,48 @@ +package common + +import ( + "io" + "os/exec" + "syscall" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +func GetExecExitStatus(err error) (int, bool) { + err = errors.Cause(err) + if err == nil { + return 0, false + } + exitErr, ok := err.(*exec.ExitError) + if !ok { + return 0, false + } + status, ok := exitErr.Sys().(syscall.WaitStatus) + if !ok { + return 0, false + } + return status.ExitStatus(), true +} + +func Execs(o io.Writer, env []string, cmds [][]string) error { + for _, cmd := range cmds { + var args []string + if len(cmd) > 1 { + args = cmd[1:] + } + x := exec.Command(cmd[0], args...) + x.Stdin = nil + x.Stdout = o + x.Stderr = o + x.Env = env + x.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + } + logrus.Debugf("executing %v", cmd) + if err := x.Run(); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/common/message.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/common/message.go new file mode 100644 index 000000000000..e9ce61c39c3e --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/common/message.go @@ -0,0 +1,36 @@ +package common + +// Message is sent from the parent to the child +// as JSON, with uint32le length header. +type Message struct { + Stage int // 0 for Message 0, 1 for Message 1 + Message0 + Message1 +} + +// Message0 is sent after setting up idmap +type Message0 struct { +} + +// Message 1 is sent after setting up other stuff +type Message1 struct { + // StateDir cannot be empty + StateDir string + Network NetworkMessage + Port PortMessage +} + +// NetworkMessage is empty for HostNetwork. +type NetworkMessage struct { + IP string + Netmask int + Gateway string + DNS string + MTU int + // Opaque strings are specific to driver + Opaque map[string]string +} + +type PortMessage struct { + Opaque map[string]string +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/copyup.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/copyup.go new file mode 100644 index 000000000000..526773e1b87f --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/copyup.go @@ -0,0 +1,5 @@ +package copyup + +type ChildDriver interface { + CopyUp([]string) ([]string, error) +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/tmpfssymlink/tmpfssymlink.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/tmpfssymlink/tmpfssymlink.go new file mode 100644 index 000000000000..f4bd49589581 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/copyup/tmpfssymlink/tmpfssymlink.go @@ -0,0 +1,82 @@ +package tmpfssymlink + +import ( + "io/ioutil" + "os" + "path/filepath" + + "github.com/pkg/errors" + + "github.com/rootless-containers/rootlesskit/pkg/common" + "github.com/rootless-containers/rootlesskit/pkg/copyup" +) + +func NewChildDriver() copyup.ChildDriver { + return &childDriver{} +} + +type childDriver struct { +} + +func (d *childDriver) CopyUp(dirs []string) ([]string, error) { + // we create bind0 outside of StateDir so as to allow + // copying up /run with stateDir=/run/user/1001/rootlesskit/default. + bind0, err := ioutil.TempDir("/tmp", "rootlesskit-b") + if err != nil { + return nil, errors.Wrap(err, "creating bind0 directory under /tmp") + } + defer os.RemoveAll(bind0) + var copied []string + for _, d := range dirs { + d := filepath.Clean(d) + if d == "/tmp" { + // TODO: we can support copy-up /tmp by changing bind0TempDir + return copied, errors.New("/tmp cannot be copied up") + } + cmds := [][]string{ + // TODO: read-only bind (does not work well for /run) + {"mount", "--rbind", d, bind0}, + {"mount", "-n", "-t", "tmpfs", "none", d}, + } + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + return copied, errors.Wrapf(err, "executing %v", cmds) + } + bind1, err := ioutil.TempDir(d, ".ro") + if err != nil { + return copied, errors.Wrapf(err, "creating a directory under %s", d) + } + cmds = [][]string{ + {"mount", "-n", "--move", bind0, bind1}, + } + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + return copied, errors.Wrapf(err, "executing %v", cmds) + } + files, err := ioutil.ReadDir(bind1) + if err != nil { + return copied, errors.Wrapf(err, "reading dir %s", bind1) + } + for _, f := range files { + fFull := filepath.Join(bind1, f.Name()) + var symlinkSrc string + if f.Mode()&os.ModeSymlink != 0 { + symlinkSrc, err = os.Readlink(fFull) + if err != nil { + return copied, errors.Wrapf(err, "reading dir %s", fFull) + } + } else { + symlinkSrc = filepath.Join(filepath.Base(bind1), f.Name()) + } + symlinkDst := filepath.Join(d, f.Name()) + // `mount` may create extra `/etc/mtab` after mounting empty tmpfs on /etc + // https://github.com/rootless-containers/rootlesskit/issues/45 + if err = os.RemoveAll(symlinkDst); err != nil { + return copied, errors.Wrapf(err, "removing %s", symlinkDst) + } + if err := os.Symlink(symlinkSrc, symlinkDst); err != nil { + return copied, errors.Wrapf(err, "symlinking %s to %s", symlinkSrc, symlinkDst) + } + } + copied = append(copied, d) + } + return copied, nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/msgutil/msgutil.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/msgutil/msgutil.go new file mode 100644 index 000000000000..a0a0c94c638a --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/msgutil/msgutil.go @@ -0,0 +1,66 @@ +// Package msgutil provides utility for JSON message with uint32le header +package msgutil + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "io" + + "github.com/pkg/errors" +) + +const ( + maxLength = 1 << 16 +) + +func MarshalToWriter(w io.Writer, x interface{}) (int, error) { + b, err := json.Marshal(x) + if err != nil { + return 0, err + } + if len(b) > maxLength { + return 0, errors.Errorf("bad message length: %d (max: %d)", len(b), maxLength) + } + h := make([]byte, 4) + binary.LittleEndian.PutUint32(h, uint32(len(b))) + return w.Write(append(h, b...)) +} + +func UnmarshalFromReader(r io.Reader, x interface{}) (int, error) { + hdr := make([]byte, 4) + n, err := r.Read(hdr) + if err != nil { + return n, err + } + if n != 4 { + return n, errors.Errorf("read %d bytes, expected 4 bytes", n) + } + bLen := binary.LittleEndian.Uint32(hdr) + if bLen > maxLength || bLen < 1 { + return n, errors.Errorf("bad message length: %d (max: %d)", bLen, maxLength) + } + b := make([]byte, bLen) + n, err = r.Read(b) + if err != nil { + return 4 + n, err + } + if n != int(bLen) { + return 4 + n, errors.Errorf("read %d bytes, expected %d bytes", n, bLen) + } + return 4 + n, json.Unmarshal(b, x) +} + +func Marshal(x interface{}) ([]byte, error) { + var b bytes.Buffer + _, err := MarshalToWriter(&b, x) + return b.Bytes(), err +} + +func Unmarshal(b []byte, x interface{}) error { + n, err := UnmarshalFromReader(bytes.NewReader(b), x) + if n != len(b) { + return errors.Errorf("read %d bytes, expected %d bytes", n, len(b)) + } + return err +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/network/iputils/iputils.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/iputils/iputils.go new file mode 100644 index 000000000000..036574ce3eb3 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/iputils/iputils.go @@ -0,0 +1,24 @@ +package iputils + +import ( + "encoding/binary" + "math" + "net" + + "github.com/pkg/errors" +) + +func AddIPInt(ip net.IP, i int) (net.IP, error) { + ip = ip.To4() + if ip == nil { + return nil, errors.Errorf("expected IPv4 address, got %s", ip.String()) + } + ui32 := binary.BigEndian.Uint32(ip) + resInt64 := int64(ui32) + int64(i) + if resInt64 > int64(math.MaxUint32) { + return nil, errors.Errorf("%s + %d overflows", ip.String(), i) + } + res := make(net.IP, 4) + binary.BigEndian.PutUint32(res, uint32(resInt64)) + return res, nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/network/network.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/network.go new file mode 100644 index 000000000000..fa2d336f3322 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/network.go @@ -0,0 +1,18 @@ +package network + +import ( + "github.com/rootless-containers/rootlesskit/pkg/common" +) + +// ParentDriver is called from the parent namespace +type ParentDriver interface { + // MTU returns MTU + MTU() int + // ConfigureNetwork sets up Slirp, updates msg, and returns destructor function. + ConfigureNetwork(childPID int, stateDir string) (netmsg *common.NetworkMessage, cleanup func() error, err error) +} + +// ChildDriver is called from the child namespace +type ChildDriver interface { + ConfigureTap(netmsg common.NetworkMessage) (tap string, err error) +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/network/parentutils/parentutils.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/parentutils/parentutils.go new file mode 100644 index 000000000000..a24a93bff6d8 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/parentutils/parentutils.go @@ -0,0 +1,24 @@ +package parentutils + +import ( + "github.com/pkg/errors" + "os" + "strconv" + + "github.com/rootless-containers/rootlesskit/pkg/common" +) + +func PrepareTap(pid int, tap string) error { + cmds := [][]string{ + nsenter(pid, []string{"ip", "tuntap", "add", "name", tap, "mode", "tap"}), + nsenter(pid, []string{"ip", "link", "set", tap, "up"}), + } + if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil { + return errors.Wrapf(err, "executing %v", cmds) + } + return nil +} + +func nsenter(pid int, cmd []string) []string { + return append([]string{"nsenter", "-t", strconv.Itoa(pid), "-n", "-m", "-U", "--preserve-credentials"}, cmd...) +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns/slirp4netns.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns/slirp4netns.go new file mode 100644 index 000000000000..ea9160946361 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns/slirp4netns.go @@ -0,0 +1,138 @@ +package slirp4netns + +import ( + "context" + "net" + "os/exec" + "strconv" + "syscall" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + + "github.com/rootless-containers/rootlesskit/pkg/common" + "github.com/rootless-containers/rootlesskit/pkg/network" + "github.com/rootless-containers/rootlesskit/pkg/network/iputils" + "github.com/rootless-containers/rootlesskit/pkg/network/parentutils" +) + +// NewParentDriver instantiates new parent driver. +// ipnet is supported only for slirp4netns v0.3.0+. +// ipnet MUST be nil for slirp4netns < v0.3.0. +// +// disableHostLoopback is supported only for slirp4netns v0.3.0+ +// apiSocketPath is supported only for slirp4netns v0.3.0+ +func NewParentDriver(binary string, mtu int, ipnet *net.IPNet, disableHostLoopback bool, apiSocketPath string) network.ParentDriver { + if binary == "" { + panic("got empty slirp4netns binary") + } + if mtu < 0 { + panic("got negative mtu") + } + if mtu == 0 { + mtu = 65520 + } + return &parentDriver{ + binary: binary, + mtu: mtu, + ipnet: ipnet, + disableHostLoopback: disableHostLoopback, + apiSocketPath: apiSocketPath, + } +} + +const opaqueTap = "slirp4netns.tap" + +type parentDriver struct { + binary string + mtu int + ipnet *net.IPNet + disableHostLoopback bool + apiSocketPath string +} + +func (d *parentDriver) MTU() int { + return d.mtu +} + +func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common.NetworkMessage, func() error, error) { + tap := "tap0" + var cleanups []func() error + if err := parentutils.PrepareTap(childPID, tap); err != nil { + return nil, common.Seq(cleanups), errors.Wrapf(err, "setting up tap %s", tap) + } + ctx, cancel := context.WithCancel(context.Background()) + opts := []string{"--mtu", strconv.Itoa(d.mtu)} + if d.disableHostLoopback { + opts = append(opts, "--disable-host-loopback") + } + if d.ipnet != nil { + opts = append(opts, "--cidr", d.ipnet.String()) + } + if d.apiSocketPath != "" { + opts = append(opts, "--api-socket", d.apiSocketPath) + } + cmd := exec.CommandContext(ctx, d.binary, append(opts, []string{strconv.Itoa(childPID), tap}...)...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + } + cleanups = append(cleanups, func() error { + logrus.Debugf("killing slirp4netns") + cancel() + wErr := cmd.Wait() + logrus.Debugf("killed slirp4netns: %v", wErr) + return nil + }) + if err := cmd.Start(); err != nil { + return nil, common.Seq(cleanups), errors.Wrapf(err, "executing %v", cmd) + } + netmsg := common.NetworkMessage{ + MTU: d.mtu, + Opaque: map[string]string{ + opaqueTap: tap, + }, + } + if d.ipnet != nil { + // TODO: get the actual configuration via slirp4netns API? + x, err := iputils.AddIPInt(d.ipnet.IP, 100) + if err != nil { + return nil, common.Seq(cleanups), err + } + netmsg.IP = x.String() + netmsg.Netmask, _ = d.ipnet.Mask.Size() + x, err = iputils.AddIPInt(d.ipnet.IP, 2) + if err != nil { + return nil, common.Seq(cleanups), err + } + netmsg.Gateway = x.String() + x, err = iputils.AddIPInt(d.ipnet.IP, 3) + if err != nil { + return nil, common.Seq(cleanups), err + } + netmsg.DNS = x.String() + } else { + netmsg.IP = "10.0.2.100" + netmsg.Netmask = 24 + netmsg.Gateway = "10.0.2.2" + netmsg.DNS = "10.0.2.3" + } + return &netmsg, common.Seq(cleanups), nil +} + +func NewChildDriver() network.ChildDriver { + return &childDriver{} +} + +type childDriver struct { +} + +func (d *childDriver) ConfigureTap(netmsg common.NetworkMessage) (string, error) { + tap := netmsg.Opaque[opaqueTap] + if tap == "" { + return "", errors.New("could not determine the preconfigured tap") + } + // tap is created and "up". + // IP stuff and MTU are not configured by the parent here, + // and they are up to the child. + return tap, nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/parent/parent.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/parent/parent.go new file mode 100644 index 000000000000..93edb50dd41a --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/parent/parent.go @@ -0,0 +1,272 @@ +package parent + +import ( + "context" + "io/ioutil" + "net" + "net/http" + "os" + "os/exec" + "os/user" + "path/filepath" + "strconv" + "syscall" + + "github.com/docker/docker/pkg/idtools" + "github.com/gorilla/mux" + "github.com/pkg/errors" + "github.com/theckman/go-flock" + + "github.com/rootless-containers/rootlesskit/pkg/api/router" + "github.com/rootless-containers/rootlesskit/pkg/common" + "github.com/rootless-containers/rootlesskit/pkg/msgutil" + "github.com/rootless-containers/rootlesskit/pkg/network" + "github.com/rootless-containers/rootlesskit/pkg/port" +) + +type Opt struct { + PipeFDEnvKey string // needs to be set + StateDir string // directory needs to be precreated + StateDirEnvKey string // optional env key to propagate StateDir value + NetworkDriver network.ParentDriver // nil for HostNetwork + PortDriver port.ParentDriver // nil for --port-driver=none +} + +// Documented state files. Undocumented ones are subject to change. +const ( + StateFileLock = "lock" + StateFileChildPID = "child_pid" // decimal pid number text + StateFileAPISock = "api.sock" // REST API Socket +) + +func Parent(opt Opt) error { + if opt.PipeFDEnvKey == "" { + return errors.New("pipe FD env key is not set") + } + if opt.StateDir == "" { + return errors.New("state dir is not set") + } + if !filepath.IsAbs(opt.StateDir) { + return errors.New("state dir must be absolute") + } + if stat, err := os.Stat(opt.StateDir); err != nil || !stat.IsDir() { + return errors.Wrap(err, "state dir is inaccessible") + } + lockPath := filepath.Join(opt.StateDir, StateFileLock) + lock := flock.NewFlock(lockPath) + locked, err := lock.TryLock() + if err != nil { + return errors.Wrapf(err, "failed to lock %s", lockPath) + } + if !locked { + return errors.Errorf("failed to lock %s, another RootlessKit is running with the same state directory?", lockPath) + } + defer os.RemoveAll(opt.StateDir) + defer lock.Unlock() + // when the previous execution crashed, the state dir may not be removed successfully. + // explicitly remove everything in the state dir except the lock file here. + for _, f := range []string{StateFileChildPID} { + p := filepath.Join(opt.StateDir, f) + if err := os.RemoveAll(p); err != nil { + return errors.Wrapf(err, "failed to remove %s", p) + } + } + + pipeR, pipeW, err := os.Pipe() + if err != nil { + return err + } + cmd := exec.Command("/proc/self/exe", os.Args[1:]...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + Cloneflags: syscall.CLONE_NEWUSER, + Unshareflags: syscall.CLONE_NEWNS, + } + if opt.NetworkDriver != nil { + cmd.SysProcAttr.Unshareflags |= syscall.CLONE_NEWNET + } + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.ExtraFiles = []*os.File{pipeR} + cmd.Env = append(os.Environ(), opt.PipeFDEnvKey+"=3") + if opt.StateDirEnvKey != "" { + cmd.Env = append(cmd.Env, opt.StateDirEnvKey+"="+opt.StateDir) + } + if err := cmd.Start(); err != nil { + return errors.Wrap(err, "failed to start the child") + } + childPIDPath := filepath.Join(opt.StateDir, StateFileChildPID) + if err := ioutil.WriteFile(childPIDPath, []byte(strconv.Itoa(cmd.Process.Pid)), 0444); err != nil { + return errors.Wrapf(err, "failed to write the child PID %d to %s", cmd.Process.Pid, childPIDPath) + } + if err := setupUIDGIDMap(cmd.Process.Pid); err != nil { + return errors.Wrap(err, "failed to setup UID/GID map") + } + // send message 0 + msg := common.Message{ + Stage: 0, + Message0: common.Message0{}, + } + if _, err := msgutil.MarshalToWriter(pipeW, &msg); err != nil { + return err + } + + // configure Network driver + msg = common.Message{ + Stage: 1, + Message1: common.Message1{ + StateDir: opt.StateDir, + }, + } + if opt.NetworkDriver != nil { + netMsg, cleanupNetwork, err := opt.NetworkDriver.ConfigureNetwork(cmd.Process.Pid, opt.StateDir) + if cleanupNetwork != nil { + defer cleanupNetwork() + } + if err != nil { + return errors.Wrapf(err, "failed to setup network %+v", opt.NetworkDriver) + } + msg.Message1.Network = *netMsg + } + + // configure Port driver + portDriverInitComplete := make(chan struct{}) + portDriverQuit := make(chan struct{}) + portDriverErr := make(chan error) + if opt.PortDriver != nil { + msg.Message1.Port.Opaque = opt.PortDriver.OpaqueForChild() + cctx := &port.ChildContext{ + PID: cmd.Process.Pid, + IP: net.ParseIP(msg.Network.IP).To4(), + } + go func() { + portDriverErr <- opt.PortDriver.RunParentDriver(portDriverInitComplete, + portDriverQuit, cctx) + }() + } + + // send message 1 + if _, err := msgutil.MarshalToWriter(pipeW, &msg); err != nil { + return err + } + if err := pipeW.Close(); err != nil { + return err + } + // wait for port driver to be ready + if opt.PortDriver != nil { + select { + case <-portDriverInitComplete: + case err = <-portDriverErr: + return err + } + } + // listens the API + apiSockPath := filepath.Join(opt.StateDir, StateFileAPISock) + apiCloser, err := listenServeAPI(apiSockPath, &router.Backend{PortDriver: opt.PortDriver}) + if err != nil { + return err + } + // block until the child exits + if err := cmd.Wait(); err != nil { + return errors.Wrap(err, "child exited") + } + // close the API socket + if err := apiCloser.Close(); err != nil { + return errors.Wrapf(err, "failed to close %s", apiSockPath) + } + // shut down port driver + if opt.PortDriver != nil { + portDriverQuit <- struct{}{} + err = <-portDriverErr + } + return err +} + +func newugidmapArgs() ([]string, []string, error) { + u, err := user.Current() + if err != nil { + return nil, nil, err + } + uidMap := []string{ + "0", + u.Uid, + "1", + } + gidMap := []string{ + "0", + u.Gid, + "1", + } + + // get both subid maps + // uses username for groupname in case primary groupname is not the same + // idtools will fall back to getent if /etc/passwd does not contain username + // works with external auth, ie sssd, ldap, nis + ims, err := idtools.NewIdentityMapping(u.Username, u.Username) + if err != nil { + return nil, nil, err + } + + uidMapLast := 1 + for _, im := range ims.UIDs() { + uidMap = append(uidMap, []string{ + strconv.Itoa(uidMapLast), + strconv.Itoa(im.HostID), + strconv.Itoa(im.Size), + }...) + uidMapLast += im.Size + } + gidMapLast := 1 + for _, im := range ims.GIDs() { + gidMap = append(gidMap, []string{ + strconv.Itoa(gidMapLast), + strconv.Itoa(im.HostID), + strconv.Itoa(im.Size), + }...) + gidMapLast += im.Size + } + + return uidMap, gidMap, nil +} + +func setupUIDGIDMap(pid int) error { + uArgs, gArgs, err := newugidmapArgs() + if err != nil { + return errors.Wrap(err, "failed to compute uid/gid map") + } + pidS := strconv.Itoa(pid) + cmd := exec.Command("newuidmap", append([]string{pidS}, uArgs...)...) + out, err := cmd.CombinedOutput() + if err != nil { + return errors.Wrapf(err, "newuidmap %s %v failed: %s", pidS, uArgs, string(out)) + } + cmd = exec.Command("newgidmap", append([]string{pidS}, gArgs...)...) + out, err = cmd.CombinedOutput() + if err != nil { + return errors.Wrapf(err, "newgidmap %s %v failed: %s", pidS, gArgs, string(out)) + } + return nil +} + +// apiCloser is implemented by *http.Server +type apiCloser interface { + Close() error + Shutdown(context.Context) error +} + +func listenServeAPI(socketPath string, backend *router.Backend) (apiCloser, error) { + r := mux.NewRouter() + router.AddRoutes(r, backend) + srv := &http.Server{Handler: r} + err := os.RemoveAll(socketPath) + if err != nil { + return nil, err + } + l, err := net.Listen("unix", socketPath) + if err != nil { + return nil, err + } + go srv.Serve(l) + return srv, nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/port.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/port.go new file mode 100644 index 000000000000..9ef46f549d46 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/port.go @@ -0,0 +1,51 @@ +package port + +import ( + "context" + "net" +) + +type Spec struct { + Proto string `json:"proto,omitempty"` // either "tcp" or "udp". in future "sctp" will be supported as well. + ParentIP string `json:"parentIP,omitempty"` // IPv4 address. can be empty (0.0.0.0). + ParentPort int `json:"parentPort,omitempty"` + ChildPort int `json:"childPort,omitempty"` +} + +type Status struct { + ID int `json:"id"` + Spec Spec `json:"spec"` +} + +// Manager MUST be thread-safe. +type Manager interface { + AddPort(ctx context.Context, spec Spec) (*Status, error) + ListPorts(ctx context.Context) ([]Status, error) + RemovePort(ctx context.Context, id int) error +} + +// ChildContext is used for RunParentDriver +type ChildContext struct { + // PID of the child, can be used for ns-entering to the child namespaces. + PID int + // IP of the tap device + IP net.IP +} + +// ParentDriver is a driver for the parent process. +type ParentDriver interface { + Manager + // OpaqueForChild typically consists of socket path + // for controlling child from parent + OpaqueForChild() map[string]string + // RunParentDriver signals initComplete when ParentDriver is ready to + // serve as Manager. + // RunParentDriver blocks until quit is signaled. + // + // ChildContext is optional. + RunParentDriver(initComplete chan struct{}, quit <-chan struct{}, cctx *ChildContext) error +} + +type ChildDriver interface { + RunChildDriver(opaque map[string]string, quit <-chan struct{}) error +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/portutil/portutil.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/portutil/portutil.go new file mode 100644 index 000000000000..f1aa5f859357 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/portutil/portutil.go @@ -0,0 +1,67 @@ +package portutil + +import ( + "net" + "regexp" + "strconv" + + "github.com/pkg/errors" + + "github.com/rootless-containers/rootlesskit/pkg/port" +) + +// ParsePortSpec parses a Docker-like representation of PortSpec. +// e.g. "127.0.0.1:8080:80/tcp" +func ParsePortSpec(s string) (*port.Spec, error) { + r := regexp.MustCompile("^([0-9a-f\\.]+):([0-9]+):([0-9]+)/([a-z]+)$") + g := r.FindStringSubmatch(s) + if len(g) != 5 { + return nil, errors.Errorf("unexpected PortSpec string: %q", s) + } + parentIP := g[1] + parentPort, err := strconv.Atoi(g[2]) + if err != nil { + return nil, errors.Wrapf(err, "unexpected ParentPort in PortSpec string: %q", s) + } + childPort, err := strconv.Atoi(g[3]) + if err != nil { + return nil, errors.Wrapf(err, "unexpected ChildPort in PortSpec string: %q", s) + } + proto := g[4] + // validation is up to the caller (as json.Unmarshal doesn't validate values) + return &port.Spec{ + Proto: proto, + ParentIP: parentIP, + ParentPort: parentPort, + ChildPort: childPort, + }, nil +} + +// ValidatePortSpec validates *port.Spec. +// existingPorts can be optionally passed for detecting conflicts. +func ValidatePortSpec(spec port.Spec, existingPorts map[int]*port.Status) error { + if spec.Proto != "tcp" && spec.Proto != "udp" { + return errors.Errorf("unknown proto: %q", spec.Proto) + } + if spec.ParentIP != "" { + if net.ParseIP(spec.ParentIP) == nil { + return errors.Errorf("invalid ParentIP: %q", spec.ParentIP) + } + } + if spec.ParentPort <= 0 || spec.ParentPort > 65535 { + return errors.Errorf("invalid ParentPort: %q", spec.ParentPort) + } + if spec.ChildPort <= 0 || spec.ChildPort > 65535 { + return errors.Errorf("invalid ChildPort: %q", spec.ChildPort) + } + for id, p := range existingPorts { + sp := p.Spec + sameProto := sp.Proto == spec.Proto + sameParent := sp.ParentIP == spec.ParentIP && sp.ParentPort == spec.ParentPort + sameChild := sp.ChildPort == spec.ChildPort + if sameProto && (sameParent || sameChild) { + return errors.Errorf("conflict with ID %d", id) + } + } + return nil +} diff --git a/vendor/github.com/rootless-containers/rootlesskit/pkg/port/socat/socat.go b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/socat/socat.go new file mode 100644 index 000000000000..9dbb0a5c3a39 --- /dev/null +++ b/vendor/github.com/rootless-containers/rootlesskit/pkg/port/socat/socat.go @@ -0,0 +1,218 @@ +package socat + +import ( + "context" + "fmt" + "io" + "net" + "os" + "os/exec" + "sync" + "syscall" + "time" + + "github.com/pkg/errors" + + "github.com/rootless-containers/rootlesskit/pkg/port" + "github.com/rootless-containers/rootlesskit/pkg/port/portutil" +) + +func NewParentDriver(logWriter io.Writer) (port.ParentDriver, error) { + if _, err := exec.LookPath("socat"); err != nil { + return nil, err + } + if _, err := exec.LookPath("nsenter"); err != nil { + return nil, err + } + d := driver{ + logWriter: logWriter, + ports: make(map[int]*port.Status, 0), + stoppers: make(map[int]func() error, 0), + nextID: 1, + } + return &d, nil +} + +type driver struct { + logWriter io.Writer + mu sync.Mutex + childPID int + ports map[int]*port.Status + stoppers map[int]func() error + nextID int +} + +func (d *driver) OpaqueForChild() map[string]string { + // NOP, as this driver does not have child-side logic. + return nil +} + +func (d *driver) RunParentDriver(initComplete chan struct{}, quit <-chan struct{}, cctx *port.ChildContext) error { + if cctx == nil || cctx.PID <= 0 { + return errors.New("child PID not set") + } + d.childPID = cctx.PID + initComplete <- struct{}{} + <-quit + return nil +} + +func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, error) { + if d.childPID <= 0 { + return nil, errors.New("child PID not set") + } + d.mu.Lock() + err := portutil.ValidatePortSpec(spec, d.ports) + d.mu.Unlock() + if err != nil { + return nil, err + } + cf := func() (*exec.Cmd, error) { + return createSocatCmd(ctx, spec, d.logWriter, d.childPID) + } + routineErrorCh := make(chan error) + routineStopCh := make(chan struct{}) + routineStop := func() error { + close(routineStopCh) + return <-routineErrorCh + } + go portRoutine(cf, routineStopCh, routineErrorCh, d.logWriter) + d.mu.Lock() + id := d.nextID + st := port.Status{ + ID: id, + Spec: spec, + } + d.ports[id] = &st + d.stoppers[id] = routineStop + d.nextID++ + d.mu.Unlock() + return &st, nil +} + +func (d *driver) ListPorts(ctx context.Context) ([]port.Status, error) { + var ports []port.Status + d.mu.Lock() + for _, p := range d.ports { + ports = append(ports, *p) + } + d.mu.Unlock() + return ports, nil +} + +func (d *driver) RemovePort(ctx context.Context, id int) error { + d.mu.Lock() + defer d.mu.Unlock() + stop, ok := d.stoppers[id] + if !ok { + return errors.Errorf("unknown port id: %d", id) + } + err := stop() + delete(d.stoppers, id) + delete(d.ports, id) + return err +} + +func createSocatCmd(ctx context.Context, spec port.Spec, logWriter io.Writer, childPID int) (*exec.Cmd, error) { + if spec.Proto != "tcp" && spec.Proto != "udp" { + return nil, errors.Errorf("unsupported proto: %s", spec.Proto) + } + ipStr := "0.0.0.0" + if spec.ParentIP != "" { + ip := net.ParseIP(spec.ParentIP) + if ip == nil { + return nil, errors.Errorf("unsupported parentIP: %s", spec.ParentIP) + } + ip = ip.To4() + if ip == nil { + return nil, errors.Errorf("unsupported parentIP (v6?): %s", spec.ParentIP) + } + ipStr = ip.String() + } + if spec.ParentPort < 1 || spec.ParentPort > 65535 { + return nil, errors.Errorf("unsupported parentPort: %d", spec.ParentPort) + } + if spec.ChildPort < 1 || spec.ChildPort > 65535 { + return nil, errors.Errorf("unsupported childPort: %d", spec.ChildPort) + } + var cmd *exec.Cmd + switch spec.Proto { + case "tcp": + cmd = exec.CommandContext(ctx, + "socat", + fmt.Sprintf("TCP-LISTEN:%d,bind=%s,reuseaddr,fork,rcvbuf=65536,sndbuf=65536", spec.ParentPort, ipStr), + fmt.Sprintf("EXEC:\"%s\",nofork", + fmt.Sprintf("nsenter -U -n --preserve-credentials -t %d socat STDIN TCP4:127.0.0.1:%d", childPID, spec.ChildPort))) + case "udp": + cmd = exec.CommandContext(ctx, + "socat", + fmt.Sprintf("UDP-LISTEN:%d,bind=%s,reuseaddr,fork,rcvbuf=65536,sndbuf=65536", spec.ParentPort, ipStr), + fmt.Sprintf("EXEC:\"%s\",nofork", + fmt.Sprintf("nsenter -U -n --preserve-credentials -t %d socat STDIN UDP4:127.0.0.1:%d", childPID, spec.ChildPort))) + } + cmd.Env = os.Environ() + cmd.Stdout = logWriter + cmd.Stderr = logWriter + cmd.SysProcAttr = &syscall.SysProcAttr{ + Pdeathsig: syscall.SIGKILL, + } + return cmd, nil +} + +type cmdFactory func() (*exec.Cmd, error) + +func portRoutine(cf cmdFactory, stopCh <-chan struct{}, errWCh chan error, logWriter io.Writer) { + retry := 0 + doneCh := make(chan error) + for { + cmd, err := cf() + if err != nil { + errWCh <- err + return + } + cmdDesc := fmt.Sprintf("%s %v", cmd.Path, cmd.Args) + fmt.Fprintf(logWriter, "[exec] starting cmd %s\n", cmdDesc) + if err := cmd.Start(); err != nil { + errWCh <- err + return + } + pid := cmd.Process.Pid + go func() { + err := cmd.Wait() + doneCh <- err + }() + select { + case err := <-doneCh: + // even if err == nil (unexpected for socat), continue the loop + retry++ + sleepDuration := time.Duration((retry*100)%(30*1000)) * time.Millisecond + fmt.Fprintf(logWriter, "[exec] retrying cmd %s after sleeping %v, count=%d, err=%v\n", + cmdDesc, sleepDuration, retry, err) + select { + case <-time.After(sleepDuration): + case <-stopCh: + errWCh <- err + return + } + case <-stopCh: + fmt.Fprintf(logWriter, "[exec] killing cmd %s pid %d\n", cmdDesc, pid) + syscall.Kill(pid, syscall.SIGKILL) + fmt.Fprintf(logWriter, "[exec] killed cmd %s pid %d\n", cmdDesc, pid) + close(errWCh) + return + } + } +} + +func NewChildDriver() port.ChildDriver { + return &childDriver{} +} + +type childDriver struct { +} + +func (d *childDriver) RunChildDriver(opaque map[string]string, quit <-chan struct{}) error { + // NOP + <-quit + return nil +} diff --git a/vendor/github.com/theckman/go-flock/.gitignore b/vendor/github.com/theckman/go-flock/.gitignore new file mode 100644 index 000000000000..daf913b1b347 --- /dev/null +++ b/vendor/github.com/theckman/go-flock/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/vendor/github.com/theckman/go-flock/.travis.yml b/vendor/github.com/theckman/go-flock/.travis.yml new file mode 100644 index 000000000000..b791a74213c2 --- /dev/null +++ b/vendor/github.com/theckman/go-flock/.travis.yml @@ -0,0 +1,10 @@ +language: go +go: + - 1.10.x + - 1.11.x +script: go test -v -check.vv -race ./... +sudo: false +notifications: + email: + on_success: never + on_failure: always diff --git a/vendor/github.com/theckman/go-flock/LICENSE b/vendor/github.com/theckman/go-flock/LICENSE new file mode 100644 index 000000000000..aff7d358e246 --- /dev/null +++ b/vendor/github.com/theckman/go-flock/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2015, Tim Heckman +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* 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. + +* Neither the name of linode-netint nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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 HOLDER 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. diff --git a/vendor/github.com/theckman/go-flock/README.md b/vendor/github.com/theckman/go-flock/README.md new file mode 100644 index 000000000000..7375e72eeb45 --- /dev/null +++ b/vendor/github.com/theckman/go-flock/README.md @@ -0,0 +1,41 @@ +# flock +[![TravisCI Build Status](https://img.shields.io/travis/gofrs/flock/master.svg?style=flat)](https://travis-ci.org/gofrs/flock) +[![GoDoc](https://img.shields.io/badge/godoc-go--flock-blue.svg?style=flat)](https://godoc.org/github.com/gofrs/flock) +[![License](https://img.shields.io/badge/license-BSD_3--Clause-brightgreen.svg?style=flat)](https://github.com/gofrs/flock/blob/master/LICENSE) +[![Go Report Card](https://goreportcard.com/badge/github.com/gofrs/flock)](https://goreportcard.com/report/github.com/gofrs/flock) + +`flock` implements a thread-safe sync.Locker interface for file locking. It also +includes a non-blocking TryLock() function to allow locking without blocking execution. + +## License +`flock` is released under the BSD 3-Clause License. See the `LICENSE` file for more details. + +## Go Compatibility +This package makes use of the `context` package that was introduced in Go 1.7. As such, this +package has an implicit dependency on Go 1.7+. + +## Installation +``` +go get -u github.com/gofrs/flock +``` + +## Usage +```Go +import "github.com/gofrs/flock" + +fileLock := flock.New("/var/lock/go-lock.lock") + +locked, err := fileLock.TryLock() + +if err != nil { + // handle locking error +} + +if locked { + // do work + fileLock.Unlock() +} +``` + +For more detailed usage information take a look at the package API docs on +[GoDoc](https://godoc.org/github.com/gofrs/flock). diff --git a/vendor/github.com/theckman/go-flock/appveyor.yml b/vendor/github.com/theckman/go-flock/appveyor.yml new file mode 100644 index 000000000000..6848e94bf886 --- /dev/null +++ b/vendor/github.com/theckman/go-flock/appveyor.yml @@ -0,0 +1,25 @@ +version: '{build}' + +build: false +deploy: false + +clone_folder: 'c:\gopath\src\github.com\gofrs\flock' + +environment: + GOPATH: 'c:\gopath' + GOVERSION: '1.11' + +init: + - git config --global core.autocrlf input + +install: + - rmdir c:\go /s /q + - appveyor DownloadFile https://storage.googleapis.com/golang/go%GOVERSION%.windows-amd64.msi + - msiexec /i go%GOVERSION%.windows-amd64.msi /q + - set Path=c:\go\bin;c:\gopath\bin;%Path% + - go version + - go env + +test_script: + - go get -t ./... + - go test -race -v ./... diff --git a/vendor/github.com/theckman/go-flock/flock.go b/vendor/github.com/theckman/go-flock/flock.go new file mode 100644 index 000000000000..8f109b8a967b --- /dev/null +++ b/vendor/github.com/theckman/go-flock/flock.go @@ -0,0 +1,127 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +// Package flock implements a thread-safe interface for file locking. +// It also includes a non-blocking TryLock() function to allow locking +// without blocking execution. +// +// Package flock is released under the BSD 3-Clause License. See the LICENSE file +// for more details. +// +// While using this library, remember that the locking behaviors are not +// guaranteed to be the same on each platform. For example, some UNIX-like +// operating systems will transparently convert a shared lock to an exclusive +// lock. If you Unlock() the flock from a location where you believe that you +// have the shared lock, you may accidentally drop the exclusive lock. +package flock + +import ( + "context" + "os" + "sync" + "time" +) + +// Flock is the struct type to handle file locking. All fields are unexported, +// with access to some of the fields provided by getter methods (Path() and Locked()). +type Flock struct { + path string + m sync.RWMutex + fh *os.File + l bool + r bool +} + +// New returns a new instance of *Flock. The only parameter +// it takes is the path to the desired lockfile. +func New(path string) *Flock { + return &Flock{path: path} +} + +// NewFlock returns a new instance of *Flock. The only parameter +// it takes is the path to the desired lockfile. +// +// Deprecated: Use New instead. +func NewFlock(path string) *Flock { + return New(path) +} + +// Close is equivalent to calling Unlock. +// +// This will release the lock and close the underlying file descriptor. +// It will not remove the file from disk, that's up to your application. +func (f *Flock) Close() error { + return f.Unlock() +} + +// Path returns the path as provided in NewFlock(). +func (f *Flock) Path() string { + return f.path +} + +// Locked returns the lock state (locked: true, unlocked: false). +// +// Warning: by the time you use the returned value, the state may have changed. +func (f *Flock) Locked() bool { + f.m.RLock() + defer f.m.RUnlock() + return f.l +} + +// RLocked returns the read lock state (locked: true, unlocked: false). +// +// Warning: by the time you use the returned value, the state may have changed. +func (f *Flock) RLocked() bool { + f.m.RLock() + defer f.m.RUnlock() + return f.r +} + +func (f *Flock) String() string { + return f.path +} + +// TryLockContext repeatedly tries to take an exclusive lock until one of the +// conditions is met: TryLock succeeds, TryLock fails with error, or Context +// Done channel is closed. +func (f *Flock) TryLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) { + return tryCtx(ctx, f.TryLock, retryDelay) +} + +// TryRLockContext repeatedly tries to take a shared lock until one of the +// conditions is met: TryRLock succeeds, TryRLock fails with error, or Context +// Done channel is closed. +func (f *Flock) TryRLockContext(ctx context.Context, retryDelay time.Duration) (bool, error) { + return tryCtx(ctx, f.TryRLock, retryDelay) +} + +func tryCtx(ctx context.Context, fn func() (bool, error), retryDelay time.Duration) (bool, error) { + if ctx.Err() != nil { + return false, ctx.Err() + } + for { + if ok, err := fn(); ok || err != nil { + return ok, err + } + select { + case <-ctx.Done(): + return false, ctx.Err() + case <-time.After(retryDelay): + // try again + } + } +} + +func (f *Flock) setFh() error { + // open a new os.File instance + // create it if it doesn't exist, and open the file read-only. + fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_RDONLY, os.FileMode(0600)) + if err != nil { + return err + } + + // set the filehandle on the struct + f.fh = fh + return nil +} diff --git a/vendor/github.com/theckman/go-flock/flock_unix.go b/vendor/github.com/theckman/go-flock/flock_unix.go new file mode 100644 index 000000000000..45f71a707c3f --- /dev/null +++ b/vendor/github.com/theckman/go-flock/flock_unix.go @@ -0,0 +1,195 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +// +build !windows + +package flock + +import ( + "os" + "syscall" +) + +// Lock is a blocking call to try and take an exclusive file lock. It will wait +// until it is able to obtain the exclusive file lock. It's recommended that +// TryLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already exclusive-locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. +// +// If the *Flock has a shared lock (RLock), this may transparently replace the +// shared lock with an exclusive lock on some UNIX-like operating systems. Be +// careful when using exclusive locks in conjunction with shared locks +// (RLock()), because calling Unlock() may accidentally release the exclusive +// lock that was once a shared lock. +func (f *Flock) Lock() error { + return f.lock(&f.l, syscall.LOCK_EX) +} + +// RLock is a blocking call to try and take a shared file lock. It will wait +// until it is able to obtain the shared file lock. It's recommended that +// TryRLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already shared-locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. +func (f *Flock) RLock() error { + return f.lock(&f.r, syscall.LOCK_SH) +} + +func (f *Flock) lock(locked *bool, flag int) error { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return nil + } + + if f.fh == nil { + if err := f.setFh(); err != nil { + return err + } + } + + if err := syscall.Flock(int(f.fh.Fd()), flag); err != nil { + shouldRetry, reopenErr := f.reopenFDOnError(err) + if reopenErr != nil { + return reopenErr + } + + if !shouldRetry { + return err + } + + if err = syscall.Flock(int(f.fh.Fd()), flag); err != nil { + return err + } + } + + *locked = true + return nil +} + +// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so +// while it is running the Locked() and RLocked() functions will be blocked. +// +// This function short-circuits if we are unlocked already. If not, it calls +// syscall.LOCK_UN on the file and closes the file descriptor. It does not +// remove the file from disk. It's up to your application to do. +// +// Please note, if your shared lock became an exclusive lock this may +// unintentionally drop the exclusive lock if called by the consumer that +// believes they have a shared lock. Please see Lock() for more details. +func (f *Flock) Unlock() error { + f.m.Lock() + defer f.m.Unlock() + + // if we aren't locked or if the lockfile instance is nil + // just return a nil error because we are unlocked + if (!f.l && !f.r) || f.fh == nil { + return nil + } + + // mark the file as unlocked + if err := syscall.Flock(int(f.fh.Fd()), syscall.LOCK_UN); err != nil { + return err + } + + f.fh.Close() + + f.l = false + f.r = false + f.fh = nil + + return nil +} + +// TryLock is the preferred function for taking an exclusive file lock. This +// function takes an RW-mutex lock before it tries to lock the file, so there is +// the possibility that this function may block for a short time if another +// goroutine is trying to take any action. +// +// The actual file lock is non-blocking. If we are unable to get the exclusive +// file lock, the function will return false instead of waiting for the lock. If +// we get the lock, we also set the *Flock instance as being exclusive-locked. +func (f *Flock) TryLock() (bool, error) { + return f.try(&f.l, syscall.LOCK_EX) +} + +// TryRLock is the preferred function for taking a shared file lock. This +// function takes an RW-mutex lock before it tries to lock the file, so there is +// the possibility that this function may block for a short time if another +// goroutine is trying to take any action. +// +// The actual file lock is non-blocking. If we are unable to get the shared file +// lock, the function will return false instead of waiting for the lock. If we +// get the lock, we also set the *Flock instance as being share-locked. +func (f *Flock) TryRLock() (bool, error) { + return f.try(&f.r, syscall.LOCK_SH) +} + +func (f *Flock) try(locked *bool, flag int) (bool, error) { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return true, nil + } + + if f.fh == nil { + if err := f.setFh(); err != nil { + return false, err + } + } + + var retried bool +retry: + err := syscall.Flock(int(f.fh.Fd()), flag|syscall.LOCK_NB) + + switch err { + case syscall.EWOULDBLOCK: + return false, nil + case nil: + *locked = true + return true, nil + } + if !retried { + if shouldRetry, reopenErr := f.reopenFDOnError(err); reopenErr != nil { + return false, reopenErr + } else if shouldRetry { + retried = true + goto retry + } + } + + return false, err +} + +// reopenFDOnError determines whether we should reopen the file handle +// in readwrite mode and try again. This comes from util-linux/sys-utils/flock.c: +// Since Linux 3.4 (commit 55725513) +// Probably NFSv4 where flock() is emulated by fcntl(). +func (f *Flock) reopenFDOnError(err error) (bool, error) { + if err != syscall.EIO && err != syscall.EBADF { + return false, nil + } + if st, err := f.fh.Stat(); err == nil { + // if the file is able to be read and written + if st.Mode()&0600 == 0600 { + f.fh.Close() + f.fh = nil + + // reopen in read-write mode and set the filehandle + fh, err := os.OpenFile(f.path, os.O_CREATE|os.O_RDWR, os.FileMode(0600)) + if err != nil { + return false, err + } + f.fh = fh + return true, nil + } + } + + return false, nil +} diff --git a/vendor/github.com/theckman/go-flock/flock_winapi.go b/vendor/github.com/theckman/go-flock/flock_winapi.go new file mode 100644 index 000000000000..fe405a255ae5 --- /dev/null +++ b/vendor/github.com/theckman/go-flock/flock_winapi.go @@ -0,0 +1,76 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +// +build windows + +package flock + +import ( + "syscall" + "unsafe" +) + +var ( + kernel32, _ = syscall.LoadLibrary("kernel32.dll") + procLockFileEx, _ = syscall.GetProcAddress(kernel32, "LockFileEx") + procUnlockFileEx, _ = syscall.GetProcAddress(kernel32, "UnlockFileEx") +) + +const ( + winLockfileFailImmediately = 0x00000001 + winLockfileExclusiveLock = 0x00000002 + winLockfileSharedLock = 0x00000000 +) + +// Use of 0x00000000 for the shared lock is a guess based on some the MS Windows +// `LockFileEX` docs, which document the `LOCKFILE_EXCLUSIVE_LOCK` flag as: +// +// > The function requests an exclusive lock. Otherwise, it requests a shared +// > lock. +// +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365203(v=vs.85).aspx + +func lockFileEx(handle syscall.Handle, flags uint32, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) { + r1, _, errNo := syscall.Syscall6( + uintptr(procLockFileEx), + 6, + uintptr(handle), + uintptr(flags), + uintptr(reserved), + uintptr(numberOfBytesToLockLow), + uintptr(numberOfBytesToLockHigh), + uintptr(unsafe.Pointer(offset))) + + if r1 != 1 { + if errNo == 0 { + return false, syscall.EINVAL + } + + return false, errNo + } + + return true, 0 +} + +func unlockFileEx(handle syscall.Handle, reserved uint32, numberOfBytesToLockLow uint32, numberOfBytesToLockHigh uint32, offset *syscall.Overlapped) (bool, syscall.Errno) { + r1, _, errNo := syscall.Syscall6( + uintptr(procUnlockFileEx), + 5, + uintptr(handle), + uintptr(reserved), + uintptr(numberOfBytesToLockLow), + uintptr(numberOfBytesToLockHigh), + uintptr(unsafe.Pointer(offset)), + 0) + + if r1 != 1 { + if errNo == 0 { + return false, syscall.EINVAL + } + + return false, errNo + } + + return true, 0 +} diff --git a/vendor/github.com/theckman/go-flock/flock_windows.go b/vendor/github.com/theckman/go-flock/flock_windows.go new file mode 100644 index 000000000000..9f4a5f10d246 --- /dev/null +++ b/vendor/github.com/theckman/go-flock/flock_windows.go @@ -0,0 +1,140 @@ +// Copyright 2015 Tim Heckman. All rights reserved. +// Use of this source code is governed by the BSD 3-Clause +// license that can be found in the LICENSE file. + +package flock + +import ( + "syscall" +) + +// ErrorLockViolation is the error code returned from the Windows syscall when a +// lock would block and you ask to fail immediately. +const ErrorLockViolation syscall.Errno = 0x21 // 33 + +// Lock is a blocking call to try and take an exclusive file lock. It will wait +// until it is able to obtain the exclusive file lock. It's recommended that +// TryLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. +func (f *Flock) Lock() error { + return f.lock(&f.l, winLockfileExclusiveLock) +} + +// RLock is a blocking call to try and take a shared file lock. It will wait +// until it is able to obtain the shared file lock. It's recommended that +// TryRLock() be used over this function. This function may block the ability to +// query the current Locked() or RLocked() status due to a RW-mutex lock. +// +// If we are already locked, this function short-circuits and returns +// immediately assuming it can take the mutex lock. +func (f *Flock) RLock() error { + return f.lock(&f.r, winLockfileSharedLock) +} + +func (f *Flock) lock(locked *bool, flag uint32) error { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return nil + } + + if f.fh == nil { + if err := f.setFh(); err != nil { + return err + } + } + + if _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag, 0, 1, 0, &syscall.Overlapped{}); errNo > 0 { + return errNo + } + + *locked = true + return nil +} + +// Unlock is a function to unlock the file. This file takes a RW-mutex lock, so +// while it is running the Locked() and RLocked() functions will be blocked. +// +// This function short-circuits if we are unlocked already. If not, it calls +// UnlockFileEx() on the file and closes the file descriptor. It does not remove +// the file from disk. It's up to your application to do. +func (f *Flock) Unlock() error { + f.m.Lock() + defer f.m.Unlock() + + // if we aren't locked or if the lockfile instance is nil + // just return a nil error because we are unlocked + if (!f.l && !f.r) || f.fh == nil { + return nil + } + + // mark the file as unlocked + if _, errNo := unlockFileEx(syscall.Handle(f.fh.Fd()), 0, 1, 0, &syscall.Overlapped{}); errNo > 0 { + return errNo + } + + f.fh.Close() + + f.l = false + f.r = false + f.fh = nil + + return nil +} + +// TryLock is the preferred function for taking an exclusive file lock. This +// function does take a RW-mutex lock before it tries to lock the file, so there +// is the possibility that this function may block for a short time if another +// goroutine is trying to take any action. +// +// The actual file lock is non-blocking. If we are unable to get the exclusive +// file lock, the function will return false instead of waiting for the lock. If +// we get the lock, we also set the *Flock instance as being exclusive-locked. +func (f *Flock) TryLock() (bool, error) { + return f.try(&f.l, winLockfileExclusiveLock) +} + +// TryRLock is the preferred function for taking a shared file lock. This +// function does take a RW-mutex lock before it tries to lock the file, so there +// is the possibility that this function may block for a short time if another +// goroutine is trying to take any action. +// +// The actual file lock is non-blocking. If we are unable to get the shared file +// lock, the function will return false instead of waiting for the lock. If we +// get the lock, we also set the *Flock instance as being shared-locked. +func (f *Flock) TryRLock() (bool, error) { + return f.try(&f.r, winLockfileSharedLock) +} + +func (f *Flock) try(locked *bool, flag uint32) (bool, error) { + f.m.Lock() + defer f.m.Unlock() + + if *locked { + return true, nil + } + + if f.fh == nil { + if err := f.setFh(); err != nil { + return false, err + } + } + + _, errNo := lockFileEx(syscall.Handle(f.fh.Fd()), flag|winLockfileFailImmediately, 0, 1, 0, &syscall.Overlapped{}) + + if errNo > 0 { + if errNo == ErrorLockViolation || errNo == syscall.ERROR_IO_PENDING { + return false, nil + } + + return false, errNo + } + + *locked = true + + return true, nil +} diff --git a/vendor/k8s.io/client-go/pkg/version/base.go b/vendor/k8s.io/client-go/pkg/version/base.go index 0a83f947a44c..619599c3bf8e 100644 --- a/vendor/k8s.io/client-go/pkg/version/base.go +++ b/vendor/k8s.io/client-go/pkg/version/base.go @@ -3,8 +3,8 @@ package version var ( gitMajor = "1" gitMinor = "14" - gitVersion = "v1.14.1-k3s.1" - gitCommit = "5f445def7ecfc428e253013b1b4d0dc893a5359a" + gitVersion = "v1.14.1-k3s.2" + gitCommit = "4213ae70315b8ea7c6ef0845fd81f783219be9bc" gitTreeState = "clean" - buildDate = "2019-04-09T03:40+00:00Z" + buildDate = "2019-04-09T17:02+00:00Z" ) diff --git a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/qos_container_manager_linux.go b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/qos_container_manager_linux.go index e5389dfd6d50..496b13390d02 100644 --- a/vendor/k8s.io/kubernetes/pkg/kubelet/cm/qos_container_manager_linux.go +++ b/vendor/k8s.io/kubernetes/pkg/kubelet/cm/qos_container_manager_linux.go @@ -119,7 +119,11 @@ func (m *qosContainerManagerImpl) Start(getNodeAllocatable func() v1.ResourceLis } else { // to ensure we actually have the right state, we update the config on startup if err := cm.Update(containerConfig); err != nil { - return fmt.Errorf("failed to update top level %v QOS cgroup : %v", qosClass, err) + if rsystem.RunningInUserNS() { + klog.Errorf("failed to update top level %v QOS cgroup : %v", qosClass, err) + } else { + return fmt.Errorf("failed to update top level %v QOS cgroup : %v", qosClass, err) + } } } } diff --git a/vendor/k8s.io/kubernetes/pkg/version/base.go b/vendor/k8s.io/kubernetes/pkg/version/base.go index 0a83f947a44c..619599c3bf8e 100644 --- a/vendor/k8s.io/kubernetes/pkg/version/base.go +++ b/vendor/k8s.io/kubernetes/pkg/version/base.go @@ -3,8 +3,8 @@ package version var ( gitMajor = "1" gitMinor = "14" - gitVersion = "v1.14.1-k3s.1" - gitCommit = "5f445def7ecfc428e253013b1b4d0dc893a5359a" + gitVersion = "v1.14.1-k3s.2" + gitCommit = "4213ae70315b8ea7c6ef0845fd81f783219be9bc" gitTreeState = "clean" - buildDate = "2019-04-09T03:40+00:00Z" + buildDate = "2019-04-09T17:02+00:00Z" ) diff --git a/vendor/k8s.io/kubernetes/pkg/volume/csi/csi_plugin.go b/vendor/k8s.io/kubernetes/pkg/volume/csi/csi_plugin.go index 10e58a17f1ed..d16c210d6e97 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/csi/csi_plugin.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/csi/csi_plugin.go @@ -23,6 +23,7 @@ import ( "path" "sort" "strings" + "sync" "time" "context" @@ -63,6 +64,12 @@ const ( csiResyncPeriod = time.Minute ) +var ( + WaitForValidHostName bool + csiPluginInstance *csiPlugin + csiPluginLock sync.Mutex +) + var deprecatedSocketDirVersions = []string{"0.1.0", "0.2.0", "0.3.0", "0.4.0"} type csiPlugin struct { @@ -80,11 +87,18 @@ const ephemeralDriverMode driverMode = "ephemeral" // ProbeVolumePlugins returns implemented plugins func ProbeVolumePlugins() []volume.VolumePlugin { - p := &csiPlugin{ + csiPluginLock.Lock() + defer csiPluginLock.Unlock() + + if csiPluginInstance != nil { + return []volume.VolumePlugin{csiPluginInstance} + } + + csiPluginInstance = &csiPlugin{ host: nil, blockEnabled: utilfeature.DefaultFeatureGate.Enabled(features.CSIBlockVolume), } - return []volume.VolumePlugin{p} + return []volume.VolumePlugin{csiPluginInstance} } // volume.VolumePlugin methods @@ -208,6 +222,21 @@ func (h *RegistrationHandler) DeRegisterPlugin(pluginName string) { } func (p *csiPlugin) Init(host volume.VolumeHost) error { + csiPluginLock.Lock() + defer csiPluginLock.Unlock() + + if WaitForValidHostName && host.GetHostName() == "" { + for { + if p.host != nil { + return nil + } + csiPluginLock.Unlock() + time.Sleep(time.Second) + klog.Infof("Waiting for CSI volume hostname") + csiPluginLock.Lock() + } + } + p.host = host if utilfeature.DefaultFeatureGate.Enabled(features.CSIDriverRegistry) { diff --git a/vendor/k8s.io/kubernetes/pkg/volume/plugins.go b/vendor/k8s.io/kubernetes/pkg/volume/plugins.go index 84279b6e92e4..5d8af29a974a 100644 --- a/vendor/k8s.io/kubernetes/pkg/volume/plugins.go +++ b/vendor/k8s.io/kubernetes/pkg/volume/plugins.go @@ -18,11 +18,6 @@ package volume import ( "fmt" - "net" - "strings" - "sync" - "time" - authenticationv1 "k8s.io/api/authentication/v1" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -37,10 +32,9 @@ import ( "k8s.io/kubernetes/pkg/util/mount" "k8s.io/kubernetes/pkg/volume/util/recyclerclient" "k8s.io/kubernetes/pkg/volume/util/subpath" -) - -var ( - WaitForValidHost = false + "net" + "strings" + "sync" ) type ProbeOperation uint32 @@ -556,19 +550,6 @@ func NewSpecFromPersistentVolume(pv *v1.PersistentVolume, readOnly bool) *Spec { // This must be called exactly once before any New* methods are called on any // plugins. func (pm *VolumePluginMgr) InitPlugins(plugins []VolumePlugin, prober DynamicPluginProber, host VolumeHost) error { - if host.GetHostName() == "" && WaitForValidHost { - for { - pm.mutex.Lock() - if pm.Host != nil && pm.Host.GetHostName() != "" { - pm.mutex.Unlock() - break - } - pm.mutex.Unlock() - klog.Infof("Waiting for volume plugins to be initialized") - time.Sleep(time.Second) - } - } - pm.mutex.Lock() defer pm.mutex.Unlock()