Merge component 'engine' from git@github.com:docker/engine master

This commit is contained in:
GordonTheTurtle
2018-08-01 21:04:10 +00:00
304 changed files with 36359 additions and 8622 deletions

View File

@ -173,10 +173,17 @@ func WithTLSClientConfig(cacertPath, certPath, keyPath string) func(*Client) err
// 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 = dialer.DialContext
transport.DialContext = dialContext
return nil
}
return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
@ -400,3 +407,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 {
return transport.DialContext(ctx, cli.proto, cli.addr)
}
}
return fallbackDial(cli.proto, cli.addr, resolveTLSConfig(cli.client.Transport))
}
}

View File

@ -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,9 @@ 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) {
// 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 +50,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?")
}

View File

@ -39,6 +39,7 @@ type CommonAPIClient interface {
NegotiateAPIVersion(ctx context.Context)
NegotiateAPIVersionPing(types.Ping)
DialSession(ctx context.Context, proto string, meta map[string][]string) (net.Conn, error)
Dialer() func(context.Context) (net.Conn, error)
Close() error
}

View File

@ -14,5 +14,5 @@ func (cli *Client) DialSession(ctx context.Context, proto string, meta map[strin
}
req = cli.addHeaders(req, meta)
return cli.setupHijackConn(req, proto)
return cli.setupHijackConn(ctx, req, proto)
}

View File

@ -29,6 +29,7 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) {
flags.StringVarP(&conf.Root, "graph", "g", defaultDataRoot, "Root of the Docker runtime")
flags.StringVar(&conf.ExecRoot, "exec-root", defaultExecRoot, "Root directory for execution state files")
flags.StringVar(&conf.ContainerdAddr, "containerd", "", "containerd grpc address")
flags.BoolVar(&conf.CriContainerd, "cri-containerd", false, "start containerd with cri")
// "--graph" is "soft-deprecated" in favor of "data-root". This flag was added
// before Docker 1.0, so won't be removed, only hidden, to discourage its usage.

View File

@ -56,6 +56,9 @@ func (cli *DaemonCli) getPlatformRemoteOptions() ([]libcontainerd.RemoteOption,
} else {
opts = append(opts, libcontainerd.WithStartDaemon(true))
}
if !cli.Config.CriContainerd {
opts = append(opts, libcontainerd.WithPlugin("cri", nil))
}
return opts, nil
}

View File

@ -75,6 +75,8 @@ type commonBridgeConfig struct {
type NetworkConfig struct {
// Default address pools for docker networks
DefaultAddressPools opts.PoolsOpt `json:"default-address-pools,omitempty"`
// NetworkControlPlaneMTU allows to specify the control plane MTU, this will allow to optimize the network use in some components
NetworkControlPlaneMTU int `json:"network-control-plane-mtu,omitempty"`
}
// CommonTLSOptions defines TLS configuration for the daemon server.
@ -192,12 +194,15 @@ type CommonConfig struct {
// Exposed node Generic Resources
// e.g: ["orange=red", "orange=green", "orange=blue", "apple=3"]
NodeGenericResources []string `json:"node-generic-resources,omitempty"`
// NetworkControlPlaneMTU allows to specify the control plane MTU, this will allow to optimize the network use in some components
NetworkControlPlaneMTU int `json:"network-control-plane-mtu,omitempty"`
// ContainerAddr is the address used to connect to containerd if we're
// not starting it ourselves
ContainerdAddr string `json:"containerd,omitempty"`
// CriContainerd determines whether a supervised containerd instance
// should be configured with the CRI plugin enabled. This allows using
// Docker's containerd instance directly with a Kubernetes kubelet.
CriContainerd bool `json:"cri-containerd,omitempty"`
}
// IsValueSet returns true if a configuration value

View File

@ -69,3 +69,9 @@ func (conf *Config) GetInitPath() string {
}
return DefaultInitBinary
}
// GetResolvConf returns the appropriate resolv.conf
// Check setupResolvConf on how this is selected
func (conf *Config) GetResolvConf() string {
return conf.ResolvConf
}

View File

@ -37,6 +37,8 @@ type Config struct {
ShmSize opts.MemBytes `json:"default-shm-size,omitempty"`
NoNewPrivileges bool `json:"no-new-privileges,omitempty"`
IpcMode string `json:"default-ipc-mode,omitempty"`
// ResolvConf is the path to the configuration of the host resolver
ResolvConf string `json:"resolv-conf,omitempty"`
}
// BridgeConfig stores all the bridge driver specific

View File

@ -63,21 +63,13 @@ func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]lib
if container.HostConfig.NetworkMode.IsHost() {
sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
if len(container.HostConfig.ExtraHosts) == 0 {
sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
}
if len(container.HostConfig.DNS) == 0 && len(daemon.configStore.DNS) == 0 &&
len(container.HostConfig.DNSSearch) == 0 && len(daemon.configStore.DNSSearch) == 0 &&
len(container.HostConfig.DNSOptions) == 0 && len(daemon.configStore.DNSOptions) == 0 {
sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
}
} else {
// OptionUseExternalKey is mandatory for userns support.
// But optional for non-userns support
sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
}
if err = setupPathsAndSandboxOptions(container, &sboxOptions); err != nil {
if err = daemon.setupPathsAndSandboxOptions(container, &sboxOptions); err != nil {
return nil, err
}

View File

@ -369,9 +369,17 @@ func (daemon *Daemon) isNetworkHotPluggable() bool {
return true
}
func setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
func (daemon *Daemon) setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
var err error
if container.HostConfig.NetworkMode.IsHost() {
// Point to the host files, so that will be copied into the container running in host mode
*sboxOptions = append(*sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
*sboxOptions = append(*sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
} else {
*sboxOptions = append(*sboxOptions, libnetwork.OptionOriginResolvConfPath(daemon.configStore.GetResolvConf()))
}
container.HostsPath, err = container.GetRootResourcePath("hosts")
if err != nil {
return err

View File

@ -155,7 +155,7 @@ func (daemon *Daemon) isNetworkHotPluggable() bool {
return true
}
func setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
func (daemon *Daemon) setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
return nil
}

View File

@ -581,6 +581,9 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
// Do we have a disabled network?
config.DisableBridge = isBridgeNetworkDisabled(config)
// Setup the resolv.conf
setupResolvConf(config)
// Verify the platform is supported as a daemon
if !platformSupported {
return nil, errSystemNotSupported

View File

@ -8,12 +8,19 @@ import (
"regexp"
"strings"
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/internal/procfs"
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/mount"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
const (
defaultResolvConf = "/etc/resolv.conf"
alternateResolvConf = "/run/systemd/resolve/resolv.conf"
)
// On Linux, plugins use a static path for storing execution state,
// instead of deriving path from daemon's exec-root. This is because
// plugin socket files are created here and they cannot exceed max
@ -131,3 +138,30 @@ func shouldUnmountRoot(root string, info *mount.Info) bool {
}
return hasMountinfoOption(info.Optional, sharedPropagationOption)
}
// setupResolvConf sets the appropriate resolv.conf file if not specified
// When systemd-resolved is running the default /etc/resolv.conf points to
// localhost. In this case fetch the alternative config file that is in a
// different path so that containers can use it
// In all the other cases fallback to the default one
func setupResolvConf(config *config.Config) {
if config.ResolvConf != "" {
return
}
config.ResolvConf = defaultResolvConf
pids, err := procfs.PidOf("systemd-resolved")
if err != nil {
logrus.Errorf("unable to check systemd-resolved status: %s", err)
return
}
if len(pids) > 0 && pids[0] > 0 {
_, err := os.Stat(alternateResolvConf)
if err == nil {
logrus.Infof("systemd-resolved is running, so using resolvconf: %s", alternateResolvConf)
config.ResolvConf = alternateResolvConf
return
}
logrus.Infof("systemd-resolved is running, but %s is not present, fallback to %s", alternateResolvConf, defaultResolvConf)
}
}

View File

@ -1,5 +1,9 @@
// +build !linux,!freebsd,!windows
package daemon // import "github.com/docker/docker/daemon"
import "github.com/docker/docker/daemon/config"
const platformSupported = false
func setupResolvConf(config *config.Config) {
}

View File

@ -653,3 +653,6 @@ func (daemon *Daemon) loadRuntimes() error {
func (daemon *Daemon) initRuntimes(_ map[string]types.Runtime) error {
return nil
}
func setupResolvConf(config *config.Config) {
}

View File

@ -146,7 +146,7 @@ func (daemon *Daemon) filterByNameIDMatches(view container.View, ctx *listContex
continue
}
for _, eachName := range idNames {
if ctx.filters.Match("name", eachName) {
if ctx.filters.Match("name", strings.TrimPrefix(eachName, "/")) {
matches[id] = true
}
}
@ -429,7 +429,7 @@ func includeContainerInList(container *container.Snapshot, ctx *listContext) ite
}
// Do not include container if the name doesn't match
if !ctx.filters.Match("name", container.Name) {
if !ctx.filters.Match("name", strings.TrimPrefix(container.Name, "/")) {
return excludeContainer
}

View File

@ -1,15 +1,82 @@
package daemon
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/container"
"github.com/docker/docker/image"
"github.com/opencontainers/go-digest"
"github.com/pborman/uuid"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
)
var root string
func TestMain(m *testing.M) {
var err error
root, err = ioutil.TempDir("", "docker-container-test-")
if err != nil {
panic(err)
}
defer os.RemoveAll(root)
os.Exit(m.Run())
}
// This sets up a container with a name so that name filters
// work against it. It takes in a pointer to Daemon so that
// minor operations are not repeated by the caller
func setupContainerWithName(t *testing.T, name string, daemon *Daemon) *container.Container {
var (
id = uuid.New()
computedImageID = digest.FromString(id)
cRoot = filepath.Join(root, id)
)
if err := os.MkdirAll(cRoot, 0755); err != nil {
t.Fatal(err)
}
c := container.NewBaseContainer(id, cRoot)
// these are for passing includeContainerInList
c.Name = name
c.Running = true
c.HostConfig = &containertypes.HostConfig{}
// these are for passing the refreshImage reducer
c.ImageID = image.IDFromDigest(computedImageID)
c.Config = &containertypes.Config{
Image: computedImageID.String(),
}
// this is done here to avoid requiring these
// operations n x number of containers in the
// calling function
daemon.containersReplica.Save(c)
daemon.reserveName(id, name)
return c
}
func containerListContainsName(containers []*types.Container, name string) bool {
for _, container := range containers {
for _, containerName := range container.Names {
if strings.TrimPrefix(containerName, "/") == name {
return true
}
}
}
return false
}
func TestListInvalidFilter(t *testing.T) {
db, err := container.NewViewDB()
assert.Assert(t, err == nil)
@ -24,3 +91,35 @@ func TestListInvalidFilter(t *testing.T) {
})
assert.Assert(t, is.Error(err, "Invalid filter 'invalid'"))
}
func TestNameFilter(t *testing.T) {
db, err := container.NewViewDB()
assert.Assert(t, err == nil)
d := &Daemon{
containersReplica: db,
}
var (
one = setupContainerWithName(t, "a1", d)
two = setupContainerWithName(t, "a2", d)
three = setupContainerWithName(t, "b1", d)
)
// moby/moby #37453 - ^ regex not working due to prefix slash
// not being stripped
containerList, err := d.Containers(&types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "^a")),
})
assert.Assert(t, err == nil)
assert.Assert(t, is.Len(containerList, 2))
assert.Assert(t, containerListContainsName(containerList, one.Name))
assert.Assert(t, containerListContainsName(containerList, two.Name))
// Same as above but make sure it works for exact names
containerList, err = d.Containers(&types.ContainerListOptions{
Filters: filters.NewArgs(filters.Arg("name", "b1")),
})
assert.Assert(t, err == nil)
assert.Assert(t, is.Len(containerList, 1))
assert.Assert(t, containerListContainsName(containerList, three.Name))
}

View File

@ -648,7 +648,7 @@ func watchFile(name string) (filenotify.FileWatcher, error) {
logger := logrus.WithFields(logrus.Fields{
"module": "logger",
"fille": name,
"file": name,
})
if err := fileWatcher.Add(name); err != nil {

View File

@ -3,7 +3,7 @@
# LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
# updating the binary version, consider updating github.com/docker/libnetwork
# in vendor.conf accordingly
LIBNETWORK_COMMIT=3ac297bc7fd0afec9051bbb47024c9bc1d75bf5b
LIBNETWORK_COMMIT=f30a35b091cc2a431ef9856c75c343f75bb5f2e2
install_proxy() {
case "$1" in

View File

@ -50,10 +50,14 @@ if [ "$(go env GOOS)/$(go env GOARCH)" != "$(go env GOHOSTOS)/$(go env GOHOSTARC
esac
fi
# -buildmode=pie is not supported on Windows.
if [ "$(go env GOOS)" != "windows" ]; then
BUILDFLAGS+=( "-buildmode=pie" )
fi
# -buildmode=pie is not supported on Windows and Linux on mips.
case "$(go env GOOS)/$(go env GOARCH)" in
windows/*|linux/mips*)
;;
*)
BUILDFLAGS+=( "-buildmode=pie" )
;;
esac
echo "Building: $DEST/$BINARY_FULLNAME"
go build \

View File

@ -4,6 +4,8 @@ import (
"context"
"net/http"
"net/http/httptest"
"runtime"
"strconv"
"strings"
"github.com/docker/docker/api/types"
@ -13,6 +15,7 @@ import (
"github.com/docker/docker/integration-cli/cli"
"github.com/docker/docker/integration-cli/cli/build"
"github.com/docker/docker/internal/test/request"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/go-check/check"
)
@ -55,6 +58,15 @@ func (s *DockerSuite) TestAPIImagesFilter(c *check.C) {
}
func (s *DockerSuite) TestAPIImagesSaveAndLoad(c *check.C) {
if runtime.GOOS == "windows" {
v, err := kernel.GetKernelVersion()
c.Assert(err, checker.IsNil)
build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0])
if build == 16299 {
c.Skip("Temporarily disabled on RS3 builds")
}
}
testRequires(c, Network)
buildImageSuccessfully(c, "saveandload", build.WithDockerfile("FROM busybox\nENV FOO bar"))
id := getIDByName(c, "saveandload")
@ -126,6 +138,15 @@ func (s *DockerSuite) TestAPIImagesHistory(c *check.C) {
}
func (s *DockerSuite) TestAPIImagesImportBadSrc(c *check.C) {
if runtime.GOOS == "windows" {
v, err := kernel.GetKernelVersion()
c.Assert(err, checker.IsNil)
build, _ := strconv.Atoi(strings.Split(strings.SplitN(v.String(), " ", 3)[2][1:], ".")[0])
if build == 16299 {
c.Skip("Temporarily disabled on RS3 builds")
}
}
testRequires(c, Network, SameHostDaemon)
server := httptest.NewServer(http.NewServeMux())

View File

@ -1488,34 +1488,6 @@ func (s *DockerDaemonSuite) TestCleanupMountsAfterGracefulShutdown(c *check.C) {
c.Assert(strings.Contains(string(mountOut), id), check.Equals, false, comment)
}
func (s *DockerDaemonSuite) TestRunContainerWithBridgeNone(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace)
s.d.StartWithBusybox(c, "-b", "none")
out, err := s.d.Cmd("run", "--rm", "busybox", "ip", "l")
c.Assert(err, check.IsNil, check.Commentf("Output: %s", out))
c.Assert(strings.Contains(out, "eth0"), check.Equals, false,
check.Commentf("There shouldn't be eth0 in container in default(bridge) mode when bridge network is disabled: %s", out))
out, err = s.d.Cmd("run", "--rm", "--net=bridge", "busybox", "ip", "l")
c.Assert(err, check.IsNil, check.Commentf("Output: %s", out))
c.Assert(strings.Contains(out, "eth0"), check.Equals, false,
check.Commentf("There shouldn't be eth0 in container in bridge mode when bridge network is disabled: %s", out))
// the extra grep and awk clean up the output of `ip` to only list the number and name of
// interfaces, allowing for different versions of ip (e.g. inside and outside the container) to
// be used while still verifying that the interface list is the exact same
cmd := exec.Command("sh", "-c", "ip l | grep -E '^[0-9]+:' | awk -F: ' { print $1\":\"$2 } '")
stdout := bytes.NewBuffer(nil)
cmd.Stdout = stdout
if err := cmd.Run(); err != nil {
c.Fatal("Failed to get host network interface")
}
out, err = s.d.Cmd("run", "--rm", "--net=host", "busybox", "sh", "-c", "ip l | grep -E '^[0-9]+:' | awk -F: ' { print $1\":\"$2 } '")
c.Assert(err, check.IsNil, check.Commentf("Output: %s", out))
c.Assert(out, check.Equals, fmt.Sprintf("%s", stdout),
check.Commentf("The network interfaces in container should be the same with host when --net=host when bridge network is disabled: %s", out))
}
func (s *DockerDaemonSuite) TestDaemonRestartWithContainerRunning(t *check.C) {
s.d.StartWithBusybox(t)
if out, err := s.d.Cmd("run", "-d", "--name", "test", "busybox", "top"); err != nil {

View File

@ -3,6 +3,7 @@ package network
import (
"context"
"fmt"
"os"
"testing"
"github.com/docker/docker/api/types"
@ -83,3 +84,9 @@ func CheckKernelMajorVersionGreaterOrEqualThen(kernelVersion int, majorVersion i
}
return true
}
// IsUserNamespace returns whether the user namespace remapping is enabled
func IsUserNamespace() bool {
root := os.Getenv("DOCKER_REMAP_ROOT")
return root != ""
}

View File

@ -0,0 +1,58 @@
package network // import "github.com/docker/docker/integration/network"
import (
"bytes"
"context"
"os/exec"
"strings"
"testing"
"github.com/docker/docker/api/types"
"github.com/docker/docker/integration/internal/container"
"github.com/docker/docker/internal/test/daemon"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
"gotest.tools/skip"
)
func TestRunContainerWithBridgeNone(t *testing.T) {
skip.If(t, testEnv.IsRemoteDaemon, "cannot start daemon on remote test run")
skip.If(t, testEnv.DaemonInfo.OSType != "linux")
skip.If(t, IsUserNamespace())
d := daemon.New(t)
d.StartWithBusybox(t, "-b", "none")
defer d.Stop(t)
client, err := d.NewClient()
assert.Check(t, err, "error creating client")
ctx := context.Background()
id1 := container.Run(t, ctx, client)
defer client.ContainerRemove(ctx, id1, types.ContainerRemoveOptions{Force: true})
result, err := container.Exec(ctx, client, id1, []string{"ip", "l"})
assert.NilError(t, err)
assert.Check(t, is.Equal(false, strings.Contains(result.Combined(), "eth0")), "There shouldn't be eth0 in container in default(bridge) mode when bridge network is disabled")
id2 := container.Run(t, ctx, client, container.WithNetworkMode("bridge"))
defer client.ContainerRemove(ctx, id2, types.ContainerRemoveOptions{Force: true})
result, err = container.Exec(ctx, client, id2, []string{"ip", "l"})
assert.NilError(t, err)
assert.Check(t, is.Equal(false, strings.Contains(result.Combined(), "eth0")), "There shouldn't be eth0 in container in bridge mode when bridge network is disabled")
nsCommand := "ls -l /proc/self/ns/net | awk -F '->' '{print $2}'"
cmd := exec.Command("sh", "-c", nsCommand)
stdout := bytes.NewBuffer(nil)
cmd.Stdout = stdout
err = cmd.Run()
assert.NilError(t, err, "Failed to get current process network namespace: %+v", err)
id3 := container.Run(t, ctx, client, container.WithNetworkMode("host"))
defer client.ContainerRemove(ctx, id3, types.ContainerRemoveOptions{Force: true})
result, err = container.Exec(ctx, client, id3, []string{"sh", "-c", nsCommand})
assert.NilError(t, err)
assert.Check(t, is.Equal(stdout.String(), result.Combined()), "The network namspace of container should be the same with host when --net=host and bridge network is disabled")
}

View File

@ -0,0 +1,105 @@
package procfs
/*
Copyright 2015 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"unicode"
"github.com/sirupsen/logrus"
)
// PidOf finds process(es) with a specified name (regexp match)
// and return their pid(s)
func PidOf(name string) ([]int, error) {
if len(name) == 0 {
return []int{}, fmt.Errorf("name should not be empty")
}
re, err := regexp.Compile("(^|/)" + name + "$")
if err != nil {
return []int{}, err
}
return getPids(re), nil
}
func getPids(re *regexp.Regexp) []int {
pids := []int{}
dirFD, err := os.Open("/proc")
if err != nil {
return nil
}
defer dirFD.Close()
for {
// Read a small number at a time in case there are many entries, we don't want to
// allocate a lot here.
ls, err := dirFD.Readdir(10)
if err == io.EOF {
break
}
if err != nil {
return nil
}
for _, entry := range ls {
if !entry.IsDir() {
continue
}
// If the directory is not a number (i.e. not a PID), skip it
pid, err := strconv.Atoi(entry.Name())
if err != nil {
continue
}
cmdline, err := ioutil.ReadFile(filepath.Join("/proc", entry.Name(), "cmdline"))
if err != nil {
logrus.Infof("Error reading file %s: %+v", filepath.Join("/proc", entry.Name(), "cmdline"), err)
continue
}
// The bytes we read have '\0' as a separator for the command line
parts := bytes.SplitN(cmdline, []byte{0}, 2)
if len(parts) == 0 {
continue
}
// Split the command line itself we are interested in just the first part
exe := strings.FieldsFunc(string(parts[0]), func(c rune) bool {
return unicode.IsSpace(c) || c == ':'
})
if len(exe) == 0 {
continue
}
// Check if the name of the executable is what we are looking for
if re.MatchString(exe[0]) {
// Grab the PID from the directory path
pids = append(pids, pid)
}
}
}
return pids
}

View File

@ -0,0 +1,36 @@
package procfs
import (
"os"
"path/filepath"
"regexp"
"runtime"
"testing"
"gotest.tools/assert"
)
func TestPidOf(t *testing.T) {
pids, err := PidOf(filepath.Base(os.Args[0]))
assert.NilError(t, err)
assert.Check(t, len(pids) == 1)
assert.DeepEqual(t, pids[0], os.Getpid())
}
func BenchmarkGetPids(b *testing.B) {
if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
b.Skipf("not supported on GOOS=%s", runtime.GOOS)
}
re, err := regexp.Compile("(^|/)" + filepath.Base(os.Args[0]) + "$")
assert.Check(b, err == nil)
for i := 0; i < b.N; i++ {
pids := getPids(re)
b.StopTimer()
assert.Check(b, len(pids) > 0)
assert.Check(b, pids[0] == os.Getpid())
b.StartTimer()
}
}

View File

@ -200,7 +200,7 @@ func (d *Daemon) Start(t testingT, args ...string) {
ht.Helper()
}
if err := d.StartWithError(args...); err != nil {
t.Fatalf("Error starting daemon with arguments: %v", args)
t.Fatalf("Error starting daemon with arguments %v : %v", args, err)
}
}
@ -324,8 +324,8 @@ func (d *Daemon) StartWithLogFile(out *os.File, providedArgs ...string) error {
return errors.Errorf("[%s] error querying daemon for root directory: %v", d.id, err)
}
return nil
case <-d.Wait:
return errors.Errorf("[%s] Daemon exited during startup", d.id)
case err := <-d.Wait:
return errors.Errorf("[%s] Daemon exited during startup: %v", d.id, err)
}
}
}
@ -435,7 +435,7 @@ out1:
return err
case <-time.After(20 * time.Second):
// time for stopping jobs and run onShutdown hooks
d.log.Logf("[%s] daemon started", d.id)
d.log.Logf("[%s] daemon stop timeout", d.id)
break out1
}
}

View File

@ -561,7 +561,11 @@ func (c *client) CreateCheckpoint(ctx context.Context, containerID, checkpointDi
return err
}
img, err := p.(containerd.Task).Checkpoint(ctx)
opts := []containerd.CheckpointTaskOpts{}
if exit {
opts = append(opts, containerd.WithExit)
}
img, err := p.(containerd.Task).Checkpoint(ctx, opts...)
if err != nil {
return wrapError(err)
}

View File

@ -494,6 +494,10 @@ func (c *client) createLinux(id string, spec *specs.Spec, runtimeOptions interfa
CreateInUtilityVM: true,
ReadOnly: readonly,
}
// If we are 1803/RS4+ enable LinuxMetadata support by default
if system.GetOSVersion().Build >= 17134 {
md.LinuxMetadata = true
}
mds = append(mds, md)
specMount.Source = path.Join(uvmPath, mount.Destination)
}

View File

@ -31,6 +31,14 @@ func (r *remote) setDefaults() {
if r.OOMScore == 0 {
r.OOMScore = -999
}
for key, conf := range r.pluginConfs.Plugins {
if conf == nil {
r.DisabledPlugins = append(r.DisabledPlugins, key)
delete(r.pluginConfs.Plugins, key)
}
}
if r.snapshotter == "" {
r.snapshotter = "overlay"
}

View File

@ -119,6 +119,7 @@ func (s snapshotter) Apply(r Remote) error {
// WithPlugin allow configuring a containerd plugin
// configuration values passed needs to be quoted if quotes are needed in
// the toml format.
// Setting the config to nil will disable a built-in plugin
func WithPlugin(name string, conf interface{}) RemoteOption {
return pluginConf{
name: name,

View File

@ -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)

View File

@ -1,29 +1,29 @@
# 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.8
github.com/Microsoft/hcsshim v0.6.12
github.com/Microsoft/go-winio v0.4.9
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/Microsoft/opengcs v0.3.8
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.0.6
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
golang.org/x/net a680a1efc54dd51c040b3b5ce4939ea3cf2ea0d1
golang.org/x/sys ac767d655b305d4e9612f5f6e33120b9176c4ad4
github.com/docker/go-units 47565b4f722fb6ceae66b95f853feed578a4a51c # v0.3.3
github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
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 98f1604134f945d48538ffca0e18662337b4a850
@ -37,7 +37,7 @@ github.com/mitchellh/hashstructure 2bca23e0e452137f789efbc8610126fd8b94f73b
#get libnetwork packages
# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy accordingly
github.com/docker/libnetwork d00ceed44cc447c77f25cdf5d59e83163bdcb4c9
github.com/docker/libnetwork f30a35b091cc2a431ef9856c75c343f75bb5f2e2
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
@ -130,11 +130,11 @@ github.com/gogo/protobuf v1.0.0
github.com/cloudflare/cfssl 1.3.2
github.com/fernet/fernet-go 1b2437bc582b3cfbb341ee5a29f8ef5b42912ff2
github.com/google/certificate-transparency-go v1.0.20
golang.org/x/crypto 1a580b3eff7814fc9b40602fd35256c63b50f491
golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
golang.org/x/crypto a2144134853fc9a27a7b1e3eb4f19f1a76df13c9
golang.org/x/time fbb02b2291d28baffd63558aa44b4b56f178d650
github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad
github.com/hashicorp/go-immutable-radix 826af9ccf0feeee615d546d69b11f8e98da8c8f1 git://github.com/tonistiigi/go-immutable-radix.git
github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
github.com/hashicorp/golang-lru 0fb14efe8c47ae851c0034ed7a448854d3d34cf3
github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0
github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
@ -149,7 +149,7 @@ github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f
# cli
github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.1
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75 # v1.0
github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
# metrics

View File

@ -15,7 +15,6 @@ import (
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
//sys waitNamedPipe(name string, timeout uint32) (err error) = WaitNamedPipeW
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
@ -139,12 +138,14 @@ func (s pipeAddress) String() string {
}
// DialPipe connects to a named pipe by path, timing out if the connection
// takes longer than the specified duration. If timeout is nil, then the timeout
// is the default timeout established by the pipe server.
// takes longer than the specified duration. If timeout is nil, then we use
// a default timeout of 5 seconds. (We do not use WaitNamedPipe.)
func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
var absTimeout time.Time
if timeout != nil {
absTimeout = time.Now().Add(*timeout)
} else {
absTimeout = time.Now().Add(time.Second * 2)
}
var err error
var h syscall.Handle
@ -153,22 +154,13 @@ func DialPipe(path string, timeout *time.Duration) (net.Conn, error) {
if err != cERROR_PIPE_BUSY {
break
}
now := time.Now()
var ms uint32
if absTimeout.IsZero() {
ms = cNMPWAIT_USE_DEFAULT_WAIT
} else if now.After(absTimeout) {
ms = cNMPWAIT_NOWAIT
} else {
ms = uint32(absTimeout.Sub(now).Nanoseconds() / 1000 / 1000)
}
err = waitNamedPipe(path, ms)
if err != nil {
if err == cERROR_SEM_TIMEOUT {
return nil, ErrTimeout
}
break
if time.Now().After(absTimeout) {
return nil, ErrTimeout
}
// Wait 10 msec and try again. This is a rather simplistic
// view, as we always try each 10 milliseconds.
time.Sleep(time.Millisecond * 10)
}
if err != nil {
return nil, &os.PathError{Op: "open", Path: path, Err: err}
@ -349,13 +341,23 @@ func ListenPipe(path string, c *PipeConfig) (net.Listener, error) {
if err != nil {
return nil, err
}
// Immediately open and then close a client handle so that the named pipe is
// created but not currently accepting connections.
// Create a client handle and connect it. This results in the pipe
// instance always existing, so that clients see ERROR_PIPE_BUSY
// rather than ERROR_FILE_NOT_FOUND. This ties the first instance
// up so that no other instances can be used. This would have been
// cleaner if the Win32 API matched CreateFile with ConnectNamedPipe
// instead of CreateNamedPipe. (Apparently created named pipes are
// considered to be in listening state regardless of whether any
// active calls to ConnectNamedPipe are outstanding.)
h2, err := createFile(path, 0, 0, nil, syscall.OPEN_EXISTING, cSECURITY_SQOS_PRESENT|cSECURITY_ANONYMOUS, 0)
if err != nil {
syscall.Close(h)
return nil, err
}
// Close the client handle. The server side of the instance will
// still be busy, leading to ERROR_PIPE_BUSY instead of
// ERROR_NOT_FOUND, as long as we don't close the server handle,
// or disconnect the client with DisconnectNamedPipe.
syscall.Close(h2)
l := &win32PipeListener{
firstHandle: h,

View File

@ -36,6 +36,8 @@ type MappedDir struct {
BandwidthMaximum uint64
IOPSMaximum uint64
CreateInUtilityVM bool
// LinuxMetadata - Support added in 1803/RS4+.
LinuxMetadata bool `json:",omitempty"`
}
type MappedPipe struct {
@ -62,6 +64,14 @@ type MappedVirtualDisk struct {
AttachOnly bool `json:",omitempty:`
}
// AssignedDevice represents a device that has been directly assigned to a container
//
// NOTE: Support added in RS5
type AssignedDevice struct {
// InterfaceClassGUID of the device to assign to container.
InterfaceClassGUID string `json:"InterfaceClassGuid,omitempty"`
}
// ContainerConfig is used as both the input of CreateContainer
// and to convert the parameters to JSON for passing onto the HCS
type ContainerConfig struct {
@ -93,6 +103,7 @@ type ContainerConfig struct {
ContainerType string `json:",omitempty"` // "Linux" for Linux containers on Windows. Omitted otherwise.
TerminateOnLastHandleClosed bool `json:",omitempty"` // Should HCS terminate the container once all handles have been closed
MappedVirtualDisks []MappedVirtualDisk `json:",omitempty"` // Array of virtual disks to mount at start
AssignedDevices []AssignedDevice `json:",omitempty"` // Array of devices to assign. NOTE: Support added in RS5
}
type ComputeSystemQuery struct {

View File

@ -110,7 +110,7 @@ func ParseOptions(options []string) (Options, error) {
rOpts.Vhdx = filepath.Join(rOpts.KirdPath, `uvm.vhdx`)
}
if rOpts.KernelFile == "" {
rOpts.KernelFile = `bootx64.efi`
rOpts.KernelFile = `kernel`
}
if rOpts.InitrdFile == "" {
rOpts.InitrdFile = `initrd.img`

View File

@ -13,6 +13,7 @@ import (
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/symlink"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@ -287,83 +288,107 @@ func Mkfifo(in io.Reader, out io.Writer, args []string) error {
// - args[1] = flag in base 10
// - args[2] = permission mode in octal (like 0755)
func OpenFile(in io.Reader, out io.Writer, args []string) (err error) {
logrus.Debugf("OpenFile: %v", args)
defer func() {
if err != nil {
logrus.Errorf("OpenFile: return is non-nil, so writing cmdFailed back: %v", err)
// error code will be serialized by the caller, so don't write it here
WriteFileHeader(out, &FileHeader{Cmd: CmdFailed}, nil)
}
}()
if len(args) < 3 {
logrus.Errorf("OpenFile: Not enough parameters")
return ErrInvalid
}
flag, err := strconv.ParseInt(args[1], 10, 32)
if err != nil {
logrus.Errorf("OpenFile: Invalid flag: %v", err)
return err
}
perm, err := strconv.ParseUint(args[2], 8, 32)
if err != nil {
logrus.Errorf("OpenFile: Invalid permission: %v", err)
return err
}
f, err := os.OpenFile(args[0], int(flag), os.FileMode(perm))
if err != nil {
logrus.Errorf("OpenFile: Failed to open: %v", err)
return err
}
// Signal the client that OpenFile succeeded
logrus.Debugf("OpenFile: Sending OK header")
if err := WriteFileHeader(out, &FileHeader{Cmd: CmdOK}, nil); err != nil {
return err
}
for {
logrus.Debugf("OpenFile: reading header")
hdr, err := ReadFileHeader(in)
if err != nil {
logrus.Errorf("OpenFile: Failed to ReadFileHeader: %v", err)
return err
}
logrus.Debugf("OpenFile: Header: %+v", hdr)
var buf []byte
switch hdr.Cmd {
case Read:
logrus.Debugf("OpenFile: Read command")
buf = make([]byte, hdr.Size, hdr.Size)
n, err := f.Read(buf)
logrus.Debugf("OpenFile: Issued a read for %d, got %d bytes and error %v", hdr.Size, n, err)
if err != nil {
logrus.Errorf("OpenFile: Read failed: %v", err)
return err
}
buf = buf[:n]
case Write:
logrus.Debugf("OpenFile: Write command")
if _, err := io.CopyN(f, in, int64(hdr.Size)); err != nil {
logrus.Errorf("OpenFile: Write CopyN() failed: %v", err)
return err
}
case Seek:
logrus.Debugf("OpenFile: Seek command")
seekHdr := &SeekHeader{}
if err := binary.Read(in, binary.BigEndian, seekHdr); err != nil {
logrus.Errorf("OpenFile: Seek Read() failed: %v", err)
return err
}
res, err := f.Seek(seekHdr.Offset, int(seekHdr.Whence))
if err != nil {
logrus.Errorf("OpenFile: Seek Seek() failed: %v", err)
return err
}
buffer := &bytes.Buffer{}
if err := binary.Write(buffer, binary.BigEndian, res); err != nil {
logrus.Errorf("OpenFile: Seek Write() failed: %v", err)
return err
}
buf = buffer.Bytes()
case Close:
logrus.Debugf("OpenFile: Close command")
if err := f.Close(); err != nil {
return err
}
default:
logrus.Errorf("OpenFile: unknown command")
return ErrUnknown
}
logrus.Debugf("OpenFile: Writing back OK header of size %d", len(buf))
retHdr := &FileHeader{
Cmd: CmdOK,
Size: uint64(len(buf)),
}
if err := WriteFileHeader(out, retHdr, buf); err != nil {
logrus.Errorf("OpenFile: WriteFileHeader() failed: %v", err)
return err
}
@ -371,6 +396,7 @@ func OpenFile(in io.Reader, out io.Writer, args []string) (err error) {
break
}
}
logrus.Debugf("OpenFile: Done, no error")
return nil
}
@ -503,18 +529,24 @@ func ResolvePath(in io.Reader, out io.Writer, args []string) error {
// - in = size of json | json of archive.TarOptions | input tar stream
// - args[0] = extract directory name
func ExtractArchive(in io.Reader, out io.Writer, args []string) error {
logrus.Debugln("ExtractArchive:", args)
if len(args) < 1 {
logrus.Errorln("ExtractArchive: invalid args")
return ErrInvalid
}
opts, err := ReadTarOptions(in)
if err != nil {
logrus.Errorf("ExtractArchive: Failed to read tar options: %v", err)
return err
}
logrus.Debugf("ExtractArchive: Tar options: %+v", opts)
if err := archive.Untar(in, args[0], opts); err != nil {
logrus.Errorf("ExtractArchive: Failed to Untar: %v", err)
return err
}
logrus.Debugf("ExtractArchive: Success")
return nil
}

View File

@ -31,7 +31,7 @@ type unitMap map[string]int64
var (
decimalMap = unitMap{"k": KB, "m": MB, "g": GB, "t": TB, "p": PB}
binaryMap = unitMap{"k": KiB, "m": MiB, "g": GiB, "t": TiB, "p": PiB}
sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[bB]?$`)
sizeRegex = regexp.MustCompile(`^(\d+(\.\d+)*) ?([kKmMgGtTpP])?[iI]?[bB]?$`)
)
var decimapAbbrs = []string{"B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"}

View File

@ -15,6 +15,17 @@ There are many networking solutions available to suit a broad range of use-cases
```go
import (
"fmt"
"log"
"github.com/docker/docker/pkg/reexec"
"github.com/docker/libnetwork"
"github.com/docker/libnetwork/config"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/options"
)
func main() {
if reexec.Init() {
return

View File

@ -194,7 +194,7 @@ func (c *controller) handleKeyChange(keys []*types.EncryptionKey) error {
func (c *controller) agentSetup(clusterProvider cluster.Provider) error {
agent := c.getAgent()
// If the agent is already present there is no need to try to initilize it again
// If the agent is already present there is no need to try to initialize it again
if agent != nil {
return nil
}

View File

@ -372,7 +372,7 @@ func (h *Handle) set(ordinal, start, end uint64, any bool, release bool, serial
h.Lock()
}
// Previous atomic push was succesfull. Save private copy to local copy
// Previous atomic push was successful. Save private copy to local copy
h.unselected = nh.unselected
h.head = nh.head
h.dbExists = nh.dbExists

View File

@ -121,7 +121,7 @@ type NetworkController interface {
// Stop network controller
Stop()
// ReloadCondfiguration updates the controller configuration
// ReloadConfiguration updates the controller configuration
ReloadConfiguration(cfgOptions ...config.Option) error
// SetClusterProvider sets cluster provider
@ -1107,6 +1107,8 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
sb.config.hostsPath = filepath.Join(c.cfg.Daemon.DataDir, "/network/files/hosts")
sb.config.resolvConfPath = filepath.Join(c.cfg.Daemon.DataDir, "/network/files/resolv.conf")
sb.id = "ingress_sbox"
} else if sb.loadBalancerNID != "" {
sb.id = "lb_" + sb.loadBalancerNID
}
c.Unlock()

View File

@ -185,7 +185,7 @@ func Key(key ...string) string {
func ParseKey(key string) ([]string, error) {
chain := strings.Split(strings.Trim(key, "/"), "/")
// The key must atleast be equal to the rootChain in order to be considered as valid
// The key must at least be equal to the rootChain in order to be considered as valid
if len(chain) <= len(rootChain) || !reflect.DeepEqual(chain[0:len(rootChain)], rootChain) {
return nil, types.BadRequestErrorf("invalid Key : %s", key)
}
@ -589,7 +589,7 @@ func (ds *datastore) DeleteObject(kvObject KVObject) error {
defer ds.Unlock()
}
// cleaup the cache first
// cleanup the cache first
if ds.cache != nil {
// If persistent store is skipped, sequencing needs to
// happen in cache.
@ -645,7 +645,7 @@ func (ds *datastore) DeleteTree(kvObject KVObject) error {
defer ds.Unlock()
}
// cleaup the cache first
// cleanup the cache first
if ds.cache != nil {
// If persistent store is skipped, sequencing needs to
// happen in cache.

View File

@ -8,8 +8,8 @@ import (
)
var (
// ErrNotImplmented exported
ErrNotImplmented = errors.New("Functionality not implemented")
// ErrNotImplemented exported
ErrNotImplemented = errors.New("Functionality not implemented")
)
// MockData exported
@ -65,7 +65,7 @@ func (s *MockStore) Exists(key string) (bool, error) {
// List gets a range of values at "directory"
func (s *MockStore) List(prefix string) ([]*store.KVPair, error) {
return nil, ErrNotImplmented
return nil, ErrNotImplemented
}
// DeleteTree deletes a range of values at "directory"
@ -76,17 +76,17 @@ func (s *MockStore) DeleteTree(prefix string) error {
// Watch a single key for modifications
func (s *MockStore) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair, error) {
return nil, ErrNotImplmented
return nil, ErrNotImplemented
}
// WatchTree triggers a watch on a range of values at "directory"
func (s *MockStore) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) {
return nil, ErrNotImplmented
return nil, ErrNotImplemented
}
// NewLock exposed
func (s *MockStore) NewLock(key string, options *store.LockOptions) (store.Locker, error) {
return nil, ErrNotImplmented
return nil, ErrNotImplemented
}
// AtomicPut put a value at "key" if the key has not been

View File

@ -9,7 +9,7 @@ import (
"sync/atomic"
stackdump "github.com/docker/docker/pkg/signal"
"github.com/docker/libnetwork/common"
"github.com/docker/libnetwork/internal/caller"
"github.com/sirupsen/logrus"
)
@ -127,7 +127,7 @@ func notImplemented(ctx interface{}, w http.ResponseWriter, r *http.Request) {
rsp := WrongCommand("not implemented", fmt.Sprintf("URL path: %s no method implemented check /help\n", r.URL.Path))
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("command not implemented done")
HTTPReply(w, rsp, json)
@ -138,7 +138,7 @@ func help(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("help done")
n, ok := ctx.(*Server)
@ -156,7 +156,7 @@ func ready(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("ready done")
HTTPReply(w, CommandSucceed(&StringCmd{Info: "OK"}), json)
}
@ -166,7 +166,7 @@ func stackTrace(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("stack trace")
path, err := stackdump.DumpStacks("/tmp/")

View File

@ -75,10 +75,10 @@ type Driver interface {
// DecodeTableEntry passes the driver a key, value pair from table it registered
// with libnetwork. Driver should return {object ID, map[string]string} tuple.
// If DecodeTableEntry is called for a table associated with NetworkObject or
// EndpointObject the return object ID should be the network id or endppoint id
// EndpointObject the return object ID should be the network id or endpoint id
// associated with that entry. map should have information about the object that
// can be presented to the user.
// For exampe: overlay driver returns the VTEP IP of the host that has the endpoint
// For example: overlay driver returns the VTEP IP of the host that has the endpoint
// which is shown in 'network inspect --verbose'
DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string)
@ -97,7 +97,7 @@ type NetworkInfo interface {
TableEventRegister(tableName string, objType ObjectType) error
}
// InterfaceInfo provides a go interface for drivers to retrive
// InterfaceInfo provides a go interface for drivers to retrieve
// network information to interface resources.
type InterfaceInfo interface {
// SetMacAddress allows the driver to set the mac address to the endpoint interface

View File

@ -104,7 +104,7 @@ type containerConfiguration struct {
ChildEndpoints []string
}
// cnnectivityConfiguration represents the user specified configuration regarding the external connectivity
// connectivityConfiguration represents the user specified configuration regarding the external connectivity
type connectivityConfiguration struct {
PortBindings []types.PortBinding
ExposedPorts []types.TransportPort

View File

@ -84,7 +84,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
}
v4gw, _, err := net.ParseCIDR(s.GwIP)
if err != nil {
return fmt.Errorf("gatway %s is not a valid ipv4 address: %v", s.GwIP, err)
return fmt.Errorf("gateway %s is not a valid ipv4 address: %v", s.GwIP, err)
}
err = jinfo.SetGateway(v4gw)
if err != nil {
@ -101,7 +101,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
}
v6gw, _, err := net.ParseCIDR(s.GwIP)
if err != nil {
return fmt.Errorf("gatway %s is not a valid ipv6 address: %v", s.GwIP, err)
return fmt.Errorf("gateway %s is not a valid ipv6 address: %v", s.GwIP, err)
}
err = jinfo.SetGatewayIPv6(v6gw)
if err != nil {

View File

@ -68,7 +68,7 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
err = d.storeUpdate(config)
if err != nil {
d.deleteNetwork(config.ID)
logrus.Debugf("encoutered an error rolling back a network create for %s : %v", config.ID, err)
logrus.Debugf("encountered an error rolling back a network create for %s : %v", config.ID, err)
return err
}
@ -92,7 +92,7 @@ func (d *driver) createNetwork(config *configuration) error {
return err
}
config.CreatedSlaveLink = true
// notify the user in logs they have limited comunicatins
// notify the user in logs they have limited communications
if config.Parent == getDummyName(stringid.TruncateID(config.ID)) {
logrus.Debugf("Empty -o parent= and --internal flags limit communications to other containers inside of network: %s",
config.Parent)

View File

@ -30,7 +30,7 @@ func createIPVlan(containerIfName, parent, ipvlanMode string) (string, error) {
// Get the link for the master index (Example: the docker host eth iface)
parentLink, err := ns.NlHandle().LinkByName(parent)
if err != nil {
return "", fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", ipvlanType, parent, err)
return "", fmt.Errorf("error occurred looking up the %s parent iface %s error: %s", ipvlanType, parent, err)
}
// Create an ipvlan link
ipvlan := &netlink.IPVlan{
@ -169,7 +169,7 @@ func createDummyLink(dummyName, truncNetID string) error {
}
parentDummyLink, err := ns.NlHandle().LinkByName(dummyName)
if err != nil {
return fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", ipvlanType, dummyName, err)
return fmt.Errorf("error occurred looking up the %s parent iface %s error: %s", ipvlanType, dummyName, err)
}
// bring the new netlink iface up
if err := ns.NlHandle().LinkSetUp(parentDummyLink); err != nil {

View File

@ -31,7 +31,7 @@ func (d *driver) deleteNetwork(nid string) {
d.Unlock()
}
// getNetworks Safely returns a slice of existng networks
// getNetworks Safely returns a slice of existing networks
func (d *driver) getNetworks() []*network {
d.Lock()
defer d.Unlock()

View File

@ -46,7 +46,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
}
v4gw, _, err := net.ParseCIDR(s.GwIP)
if err != nil {
return fmt.Errorf("gatway %s is not a valid ipv4 address: %v", s.GwIP, err)
return fmt.Errorf("gateway %s is not a valid ipv4 address: %v", s.GwIP, err)
}
err = jinfo.SetGateway(v4gw)
if err != nil {
@ -63,7 +63,7 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
}
v6gw, _, err := net.ParseCIDR(s.GwIP)
if err != nil {
return fmt.Errorf("gatway %s is not a valid ipv6 address: %v", s.GwIP, err)
return fmt.Errorf("gateway %s is not a valid ipv6 address: %v", s.GwIP, err)
}
err = jinfo.SetGatewayIPv6(v6gw)
if err != nil {

View File

@ -72,7 +72,7 @@ func (d *driver) CreateNetwork(nid string, option map[string]interface{}, nInfo
err = d.storeUpdate(config)
if err != nil {
d.deleteNetwork(config.ID)
logrus.Debugf("encoutered an error rolling back a network create for %s : %v", config.ID, err)
logrus.Debugf("encountered an error rolling back a network create for %s : %v", config.ID, err)
return err
}
@ -96,7 +96,7 @@ func (d *driver) createNetwork(config *configuration) error {
return err
}
config.CreatedSlaveLink = true
// notify the user in logs they have limited comunicatins
// notify the user in logs they have limited communications
if config.Parent == getDummyName(stringid.TruncateID(config.ID)) {
logrus.Debugf("Empty -o parent= and --internal flags limit communications to other containers inside of network: %s",
config.Parent)

View File

@ -30,7 +30,7 @@ func createMacVlan(containerIfName, parent, macvlanMode string) (string, error)
// Get the link for the master index (Example: the docker host eth iface)
parentLink, err := ns.NlHandle().LinkByName(parent)
if err != nil {
return "", fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", macvlanType, parent, err)
return "", fmt.Errorf("error occurred looking up the %s parent iface %s error: %s", macvlanType, parent, err)
}
// Create a macvlan link
macvlan := &netlink.Macvlan{
@ -173,7 +173,7 @@ func createDummyLink(dummyName, truncNetID string) error {
}
parentDummyLink, err := ns.NlHandle().LinkByName(dummyName)
if err != nil {
return fmt.Errorf("error occoured looking up the %s parent iface %s error: %s", macvlanType, dummyName, err)
return fmt.Errorf("error occurred looking up the %s parent iface %s error: %s", macvlanType, dummyName, err)
}
// bring the new netlink iface up
if err := ns.NlHandle().LinkSetUp(parentDummyLink); err != nil {

View File

@ -601,7 +601,7 @@ func (n *network) maxMTU() int {
mtu -= vxlanEncap
if n.secure {
// In case of encryption account for the
// esp packet espansion and padding
// esp packet expansion and padding
mtu -= pktExpansion
mtu -= (mtu % 4)
}

View File

@ -47,18 +47,10 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
}
if err := n.joinSandbox(false); err != nil {
if err := n.joinSandbox(s, false, true); err != nil {
return fmt.Errorf("network sandbox join failed: %v", err)
}
if err := n.joinSubnetSandbox(s, false); err != nil {
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
}
// joinSubnetSandbox gets called when an endpoint comes up on a new subnet in the
// overlay network. Hence the Endpoint count should be updated outside joinSubnetSandbox
n.incEndpointCount()
sbox := n.sandbox()
overlayIfName, containerIfName, err := createVethPair()

View File

@ -39,7 +39,7 @@ var (
type networkTable map[string]*network
type subnet struct {
once *sync.Once
sboxInit bool
vxlanName string
brName string
vni uint32
@ -63,7 +63,7 @@ type network struct {
endpoints endpointTable
driver *driver
joinCnt int
once *sync.Once
sboxInit bool
initEpoch int
initErr error
subnets []*subnet
@ -150,7 +150,6 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
id: id,
driver: d,
endpoints: endpointTable{},
once: &sync.Once{},
subnets: []*subnet{},
}
@ -193,7 +192,6 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
s := &subnet{
subnetIP: ipd.Pool,
gwIP: ipd.Gateway,
once: &sync.Once{},
}
if len(vnis) != 0 {
@ -277,7 +275,7 @@ func (d *driver) DeleteNetwork(nid string) error {
logrus.Warnf("Failed to delete overlay endpoint %.7s from local store: %v", ep.id, err)
}
}
// flush the peerDB entries
doPeerFlush = true
delete(d.networks, nid)
@ -304,29 +302,54 @@ func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
return nil
}
func (n *network) incEndpointCount() {
n.Lock()
defer n.Unlock()
n.joinCnt++
}
func (n *network) joinSandbox(restore bool) error {
func (n *network) joinSandbox(s *subnet, restore bool, incJoinCount bool) error {
// If there is a race between two go routines here only one will win
// the other will wait.
n.once.Do(func() {
// save the error status of initSandbox in n.initErr so that
// all the racing go routines are able to know the status.
networkOnce.Do(networkOnceInit)
n.Lock()
// If non-restore initialization occurred and was successful then
// tell the peerDB to initialize the sandbox with all the peers
// previously received from networkdb. But only do this after
// unlocking the network. Otherwise we could deadlock with
// on the peerDB channel while peerDB is waiting for the network lock.
var doInitPeerDB bool
defer func() {
n.Unlock()
if doInitPeerDB {
n.driver.initSandboxPeerDB(n.id)
}
}()
if !n.sboxInit {
n.initErr = n.initSandbox(restore)
})
doInitPeerDB = n.initErr == nil && !restore
// If there was an error, we cannot recover it
n.sboxInit = true
}
return n.initErr
}
if n.initErr != nil {
return fmt.Errorf("network sandbox join failed: %v", n.initErr)
}
func (n *network) joinSubnetSandbox(s *subnet, restore bool) error {
s.once.Do(func() {
s.initErr = n.initSubnetSandbox(s, restore)
})
return s.initErr
subnetErr := s.initErr
if !s.sboxInit {
subnetErr = n.initSubnetSandbox(s, restore)
// We can recover from these errors, but not on restore
if restore || subnetErr == nil {
s.initErr = subnetErr
s.sboxInit = true
}
}
if subnetErr != nil {
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), subnetErr)
}
if incJoinCount {
n.joinCnt++
}
return nil
}
func (n *network) leaveSandbox() {
@ -337,15 +360,14 @@ func (n *network) leaveSandbox() {
return
}
// We are about to destroy sandbox since the container is leaving the network
// Reinitialize the once variable so that we will be able to trigger one time
// sandbox initialization(again) when another container joins subsequently.
n.once = &sync.Once{}
for _, s := range n.subnets {
s.once = &sync.Once{}
}
n.destroySandbox()
n.sboxInit = false
n.initErr = nil
for _, s := range n.subnets {
s.sboxInit = false
s.initErr = nil
}
}
// to be called while holding network lock
@ -478,7 +500,7 @@ func (n *network) generateVxlanName(s *subnet) string {
id = n.id[:5]
}
return "vx-" + fmt.Sprintf("%06x", n.vxlanID(s)) + "-" + id
return fmt.Sprintf("vx-%06x-%v", s.vni, id)
}
func (n *network) generateBridgeName(s *subnet) string {
@ -491,7 +513,7 @@ func (n *network) generateBridgeName(s *subnet) string {
}
func (n *network) getBridgeNamePrefix(s *subnet) string {
return "ov-" + fmt.Sprintf("%06x", n.vxlanID(s))
return fmt.Sprintf("ov-%06x", s.vni)
}
func checkOverlap(nw *net.IPNet) error {
@ -513,7 +535,7 @@ func checkOverlap(nw *net.IPNet) error {
}
func (n *network) restoreSubnetSandbox(s *subnet, brName, vxlanName string) error {
sbox := n.sandbox()
sbox := n.sbox
// restore overlay osl sandbox
Ifaces := make(map[string][]osl.IfaceOption)
@ -542,7 +564,7 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error
deleteInterfaceBySubnet(n.getBridgeNamePrefix(s), s)
}
// Try to delete the vxlan interface by vni if already present
deleteVxlanByVNI("", n.vxlanID(s))
deleteVxlanByVNI("", s.vni)
if err := checkOverlap(s.subnetIP); err != nil {
return err
@ -556,24 +578,24 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error
// it must a stale namespace from previous
// life. Destroy it completely and reclaim resourced.
networkMu.Lock()
path, ok := vniTbl[n.vxlanID(s)]
path, ok := vniTbl[s.vni]
networkMu.Unlock()
if ok {
deleteVxlanByVNI(path, n.vxlanID(s))
deleteVxlanByVNI(path, s.vni)
if err := syscall.Unmount(path, syscall.MNT_FORCE); err != nil {
logrus.Errorf("unmount of %s failed: %v", path, err)
}
os.Remove(path)
networkMu.Lock()
delete(vniTbl, n.vxlanID(s))
delete(vniTbl, s.vni)
networkMu.Unlock()
}
}
// create a bridge and vxlan device for this subnet and move it to the sandbox
sbox := n.sandbox()
sbox := n.sbox
if err := sbox.AddInterface(brName, "br",
sbox.InterfaceOptions().Address(s.gwIP),
@ -581,13 +603,30 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error
return fmt.Errorf("bridge creation in sandbox failed for subnet %q: %v", s.subnetIP.String(), err)
}
err := createVxlan(vxlanName, n.vxlanID(s), n.maxMTU())
err := createVxlan(vxlanName, s.vni, n.maxMTU())
if err != nil {
return err
}
if err := sbox.AddInterface(vxlanName, "vxlan",
sbox.InterfaceOptions().Master(brName)); err != nil {
// If adding vxlan device to the overlay namespace fails, remove the bridge interface we
// already added to the namespace. This allows the caller to try the setup again.
for _, iface := range sbox.Info().Interfaces() {
if iface.SrcName() == brName {
if ierr := iface.Remove(); ierr != nil {
logrus.Errorf("removing bridge failed from ov ns %v failed, %v", n.sbox.Key(), ierr)
}
}
}
// Also, delete the vxlan interface. Since a global vni id is associated
// with the vxlan interface, an orphaned vxlan interface will result in
// failure of vxlan device creation if the vni is assigned to some other
// network.
if deleteErr := deleteInterface(vxlanName); deleteErr != nil {
logrus.Warnf("could not delete vxlan interface, %s, error %v, after config error, %v", vxlanName, deleteErr, err)
}
return fmt.Errorf("vxlan interface creation failed for subnet %q: %v", s.subnetIP.String(), err)
}
@ -619,6 +658,7 @@ func (n *network) setupSubnetSandbox(s *subnet, brName, vxlanName string) error
return nil
}
// Must be called with the network lock
func (n *network) initSubnetSandbox(s *subnet, restore bool) error {
brName := n.generateBridgeName(s)
vxlanName := n.generateVxlanName(s)
@ -633,10 +673,8 @@ func (n *network) initSubnetSandbox(s *subnet, restore bool) error {
}
}
n.Lock()
s.vxlanName = vxlanName
s.brName = brName
n.Unlock()
return nil
}
@ -677,11 +715,7 @@ func (n *network) cleanupStaleSandboxes() {
}
func (n *network) initSandbox(restore bool) error {
n.Lock()
n.initEpoch++
n.Unlock()
networkOnce.Do(networkOnceInit)
if !restore {
if hostMode {
@ -711,12 +745,7 @@ func (n *network) initSandbox(restore bool) error {
}
// this is needed to let the peerAdd configure the sandbox
n.setSandbox(sbox)
if !restore {
// Initialize the sandbox with all the peers previously received from networkdb
n.driver.initSandboxPeerDB(n.id)
}
n.sbox = sbox
// If we are in swarm mode, we don't need anymore the watchMiss routine.
// This will save 1 thread and 1 netlink socket per network
@ -734,7 +763,7 @@ func (n *network) initSandbox(restore bool) error {
tv := syscall.NsecToTimeval(soTimeout.Nanoseconds())
err = nlSock.SetReceiveTimeout(&tv)
})
n.setNetlinkSocket(nlSock)
n.nlSocket = nlSock
if err == nil {
go n.watchMiss(nlSock, key)
@ -836,7 +865,6 @@ func (d *driver) restoreNetworkFromStore(nid string) *network {
if n != nil {
n.driver = d
n.endpoints = endpointTable{}
n.once = &sync.Once{}
d.networks[nid] = n
}
return n
@ -844,11 +872,11 @@ func (d *driver) restoreNetworkFromStore(nid string) *network {
func (d *driver) network(nid string) *network {
d.Lock()
defer d.Unlock()
n, ok := d.networks[nid]
if !ok {
n = d.restoreNetworkFromStore(nid)
}
d.Unlock()
return n
}
@ -869,26 +897,12 @@ func (d *driver) getNetworkFromStore(nid string) *network {
func (n *network) sandbox() osl.Sandbox {
n.Lock()
defer n.Unlock()
return n.sbox
}
func (n *network) setSandbox(sbox osl.Sandbox) {
n.Lock()
n.sbox = sbox
n.Unlock()
}
func (n *network) setNetlinkSocket(nlSk *nl.NetlinkSocket) {
n.Lock()
n.nlSocket = nlSk
n.Unlock()
}
func (n *network) vxlanID(s *subnet) uint32 {
n.Lock()
defer n.Unlock()
return s.vni
}
@ -997,7 +1011,6 @@ func (n *network) SetValue(value []byte) error {
subnetIP: subnetIP,
gwIP: gwIP,
vni: vni,
once: &sync.Once{},
}
n.subnets = append(n.subnets, s)
} else {
@ -1023,7 +1036,10 @@ func (n *network) writeToStore() error {
}
func (n *network) releaseVxlanID() ([]uint32, error) {
if len(n.subnets) == 0 {
n.Lock()
nSubnets := len(n.subnets)
n.Unlock()
if nSubnets == 0 {
return nil, nil
}
@ -1039,14 +1055,17 @@ func (n *network) releaseVxlanID() ([]uint32, error) {
}
}
var vnis []uint32
n.Lock()
for _, s := range n.subnets {
if n.driver.vxlanIdm != nil {
vni := n.vxlanID(s)
vnis = append(vnis, vni)
n.driver.vxlanIdm.Release(uint64(vni))
vnis = append(vnis, s.vni)
}
s.vni = 0
}
n.Unlock()
n.setVxlanID(s, 0)
for _, vni := range vnis {
n.driver.vxlanIdm.Release(uint64(vni))
}
return vnis, nil
@ -1054,7 +1073,7 @@ func (n *network) releaseVxlanID() ([]uint32, error) {
func (n *network) obtainVxlanID(s *subnet) error {
//return if the subnet already has a vxlan id assigned
if s.vni != 0 {
if n.vxlanID(s) != 0 {
return nil
}
@ -1067,7 +1086,7 @@ func (n *network) obtainVxlanID(s *subnet) error {
return fmt.Errorf("getting network %q from datastore failed %v", n.id, err)
}
if s.vni == 0 {
if n.vxlanID(s) == 0 {
vxlanID, err := n.driver.vxlanIdm.GetID(true)
if err != nil {
return fmt.Errorf("failed to allocate vxlan id: %v", err)

View File

@ -105,17 +105,6 @@ func Init(dc driverapi.DriverCallback, config map[string]interface{}) error {
logrus.Warnf("Failure during overlay endpoints restore: %v", err)
}
// If an error happened when the network join the sandbox during the endpoints restore
// we should reset it now along with the once variable, so that subsequent endpoint joins
// outside of the restore path can potentially fix the network join and succeed.
for nid, n := range d.networks {
if n.initErr != nil {
logrus.Infof("resetting init error and once variable for network %s after unsuccessful endpoint restore: %v", nid, n.initErr)
n.initErr = nil
n.once = &sync.Once{}
}
}
return dc.RegisterDriver(networkType, d, c)
}
@ -151,14 +140,10 @@ func (d *driver) restoreEndpoints() error {
return fmt.Errorf("could not find subnet for endpoint %s", ep.id)
}
if err := n.joinSandbox(true); err != nil {
if err := n.joinSandbox(s, true, true); err != nil {
return fmt.Errorf("restore network sandbox failed: %v", err)
}
if err := n.joinSubnetSandbox(s, true); err != nil {
return fmt.Errorf("restore subnet sandbox failed for %q: %v", s.subnetIP.String(), err)
}
Ifaces := make(map[string][]osl.IfaceOption)
vethIfaceOption := make([]osl.IfaceOption, 1)
vethIfaceOption = append(vethIfaceOption, n.sbox.InterfaceOptions().Master(s.brName))
@ -166,10 +151,10 @@ func (d *driver) restoreEndpoints() error {
err := n.sbox.Restore(Ifaces, nil, nil, nil)
if err != nil {
n.leaveSandbox()
return fmt.Errorf("failed to restore overlay sandbox: %v", err)
}
n.incEndpointCount()
d.peerAdd(ep.nid, ep.id, ep.addr.IP, ep.addr.Mask, ep.mac, net.ParseIP(d.advertiseAddress), false, false, true)
}
return nil

View File

@ -7,7 +7,8 @@ import (
"sync"
"syscall"
"github.com/docker/libnetwork/common"
"github.com/docker/libnetwork/internal/caller"
"github.com/docker/libnetwork/internal/setmatrix"
"github.com/docker/libnetwork/osl"
"github.com/sirupsen/logrus"
)
@ -59,7 +60,7 @@ func (p *peerEntryDB) UnMarshalDB() peerEntry {
type peerMap struct {
// set of peerEntry, note they have to be objects and not pointers to maintain the proper equality checks
mp common.SetMatrix
mp setmatrix.SetMatrix
sync.Mutex
}
@ -170,7 +171,7 @@ func (d *driver) peerDbAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
pMap, ok := d.peerDb.mp[nid]
if !ok {
d.peerDb.mp[nid] = &peerMap{
mp: common.NewSetMatrix(),
mp: setmatrix.NewSetMatrix(),
}
pMap = d.peerDb.mp[nid]
@ -297,7 +298,7 @@ func (d *driver) peerOpRoutine(ctx context.Context, ch chan *peerOperation) {
}
func (d *driver) peerInit(nid string) {
callerName := common.CallerName(1)
callerName := caller.Name(1)
d.peerOpCh <- &peerOperation{
opType: peerOperationINIT,
networkID: nid,
@ -331,7 +332,7 @@ func (d *driver) peerAdd(nid, eid string, peerIP net.IP, peerIPMask net.IPMask,
l2Miss: l2Miss,
l3Miss: l3Miss,
localPeer: localPeer,
callerName: common.CallerName(1),
callerName: caller.Name(1),
}
}
@ -384,7 +385,7 @@ func (d *driver) peerAddOp(nid, eid string, peerIP net.IP, peerIPMask net.IPMask
return fmt.Errorf("couldn't get vxlan id for %q: %v", s.subnetIP.String(), err)
}
if err := n.joinSubnetSandbox(s, false); err != nil {
if err := n.joinSandbox(s, false, false); err != nil {
return fmt.Errorf("subnet sandbox join failed for %q: %v", s.subnetIP.String(), err)
}
@ -422,7 +423,7 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP, peerIPMask net.IPMas
peerIPMask: peerIPMask,
peerMac: peerMac,
vtepIP: vtep,
callerName: common.CallerName(1),
callerName: caller.Name(1),
localPeer: localPeer,
}
}
@ -491,7 +492,7 @@ func (d *driver) peerFlush(nid string) {
d.peerOpCh <- &peerOperation{
opType: peerOperationFLUSH,
networkID: nid,
callerName: common.CallerName(1),
callerName: caller.Name(1),
}
}

View File

@ -150,7 +150,7 @@ type JoinRequest struct {
Options map[string]interface{}
}
// InterfaceName is the struct represetation of a pair of devices with source
// InterfaceName is the struct representation of a pair of devices with source
// and destination, for the purposes of putting an endpoint into a container.
type InterfaceName struct {
SrcName string

View File

@ -54,7 +54,7 @@ type IPAMNotifyFunc func(name string, driver ipamapi.Ipam, cap *ipamapi.Capabili
// DriverNotifyFunc defines the notify function signature when a new network driver gets registered.
type DriverNotifyFunc func(name string, driver driverapi.Driver, capability driverapi.Capability) error
// New retruns a new driver registry handle.
// New returns a new driver registry handle.
func New(lDs, gDs interface{}, dfn DriverNotifyFunc, ifn IPAMNotifyFunc, pg plugingetter.PluginGetter) (*DrvRegistry, error) {
r := &DrvRegistry{
drivers: make(driverTable),

View File

@ -1,4 +1,4 @@
package common
package caller
import (
"runtime"
@ -11,7 +11,7 @@ func callerInfo(i int) string {
if ok {
f := runtime.FuncForPC(ptr)
if f != nil {
// f.Name() is like: github.com/docker/libnetwork/common.MethodName
// f.Name() is like: github.com/docker/libnetwork/caller.MethodName
tmp := strings.Split(f.Name(), ".")
if len(tmp) > 0 {
fName = tmp[len(tmp)-1]
@ -22,8 +22,8 @@ func callerInfo(i int) string {
return fName
}
// CallerName returns the name of the function at the specified level
// Name returns the name of the function at the specified level
// level == 0 means current method name
func CallerName(level int) string {
func Name(level int) string {
return callerInfo(2 + level)
}

View File

@ -66,7 +66,7 @@ func newConnection() (*Conn, error) {
return c, nil
}
// Innitialize D-Bus connection.
// Initialize D-Bus connection.
func (c *Conn) initConnection() error {
var err error

View File

@ -477,7 +477,7 @@ func raw(args ...string) ([]byte, error) {
return filterOutput(startTime, output, args...), err
}
// RawCombinedOutput inernally calls the Raw function and returns a non nil
// RawCombinedOutput internally calls the Raw function and returns a non nil
// error if Raw returned a non nil error or a non empty output
func RawCombinedOutput(args ...string) error {
if output, err := Raw(args...); err != nil || len(output) != 0 {

View File

@ -100,7 +100,7 @@ func fillService(s *Service) nl.NetlinkRequestData {
return cmdAttr
}
func fillDestinaton(d *Destination) nl.NetlinkRequestData {
func fillDestination(d *Destination) nl.NetlinkRequestData {
cmdAttr := nl.NewRtAttr(ipvsCmdAttrDest, nil)
nl.NewRtAttrChild(cmdAttr, ipvsDestAttrAddress, rawIPData(d.Address))
@ -134,7 +134,7 @@ func (i *Handle) doCmdwithResponse(s *Service, d *Destination, cmd uint8) ([][]b
}
} else {
req.AddData(fillDestinaton(d))
req.AddData(fillDestination(d))
}
res, err := execute(i.sock, req, 0)

View File

@ -9,11 +9,11 @@ import (
"time"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/libnetwork/common"
"github.com/docker/libnetwork/config"
"github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/etchosts"
"github.com/docker/libnetwork/internal/setmatrix"
"github.com/docker/libnetwork/ipamapi"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/netutils"
@ -88,7 +88,7 @@ type NetworkInfo interface {
type EndpointWalker func(ep Endpoint) bool
// ipInfo is the reverse mapping from IP to service name to serve the PTR query.
// extResolver is set if an externl server resolves a service name to this IP.
// extResolver is set if an external server resolves a service name to this IP.
// Its an indication to defer PTR queries also to that external server.
type ipInfo struct {
name string
@ -104,9 +104,9 @@ type svcMapEntry struct {
}
type svcInfo struct {
svcMap common.SetMatrix
svcIPv6Map common.SetMatrix
ipMap common.SetMatrix
svcMap setmatrix.SetMatrix
svcIPv6Map setmatrix.SetMatrix
ipMap setmatrix.SetMatrix
service map[string][]servicePorts
}
@ -1353,7 +1353,7 @@ func (n *network) updateSvcRecord(ep *endpoint, localEps []*endpoint, isAdd bool
}
}
func addIPToName(ipMap common.SetMatrix, name, serviceID string, ip net.IP) {
func addIPToName(ipMap setmatrix.SetMatrix, name, serviceID string, ip net.IP) {
reverseIP := netutils.ReverseIP(ip.String())
ipMap.Insert(reverseIP, ipInfo{
name: name,
@ -1361,7 +1361,7 @@ func addIPToName(ipMap common.SetMatrix, name, serviceID string, ip net.IP) {
})
}
func delIPToName(ipMap common.SetMatrix, name, serviceID string, ip net.IP) {
func delIPToName(ipMap setmatrix.SetMatrix, name, serviceID string, ip net.IP) {
reverseIP := netutils.ReverseIP(ip.String())
ipMap.Remove(reverseIP, ipInfo{
name: name,
@ -1369,14 +1369,14 @@ func delIPToName(ipMap common.SetMatrix, name, serviceID string, ip net.IP) {
})
}
func addNameToIP(svcMap common.SetMatrix, name, serviceID string, epIP net.IP) {
func addNameToIP(svcMap setmatrix.SetMatrix, name, serviceID string, epIP net.IP) {
svcMap.Insert(name, svcMapEntry{
ip: epIP.String(),
serviceID: serviceID,
})
}
func delNameToIP(svcMap common.SetMatrix, name, serviceID string, epIP net.IP) {
func delNameToIP(svcMap setmatrix.SetMatrix, name, serviceID string, epIP net.IP) {
svcMap.Remove(name, svcMapEntry{
ip: epIP.String(),
serviceID: serviceID,
@ -1399,9 +1399,9 @@ func (n *network) addSvcRecords(eID, name, serviceID string, epIP, epIPv6 net.IP
sr, ok := c.svcRecords[n.ID()]
if !ok {
sr = svcInfo{
svcMap: common.NewSetMatrix(),
svcIPv6Map: common.NewSetMatrix(),
ipMap: common.NewSetMatrix(),
svcMap: setmatrix.NewSetMatrix(),
svcIPv6Map: setmatrix.NewSetMatrix(),
ipMap: setmatrix.NewSetMatrix(),
}
c.svcRecords[n.ID()] = sr
}
@ -1654,7 +1654,7 @@ func (n *network) ipamAllocateVersion(ipVer int, ipam ipamapi.Ipam) error {
return types.BadRequestErrorf("non parsable secondary ip address (%s:%s) passed for network %s", k, v, n.Name())
}
if !d.Pool.Contains(ip) {
return types.ForbiddenErrorf("auxilairy address: (%s:%s) must belong to the master pool: %s", k, v, d.Pool)
return types.ForbiddenErrorf("auxiliary address: (%s:%s) must belong to the master pool: %s", k, v, d.Pool)
}
// Attempt reservation in the container addressable pool, silent the error if address does not belong to that pool
if d.IPAMData.AuxAddresses[k], _, err = ipam.RequestAddress(d.PoolID, ip, nil); err != nil && err != ipamapi.ErrIPOutOfRange {
@ -2036,7 +2036,7 @@ func (n *network) ResolveService(name string) ([]*net.SRV, []net.IP) {
logrus.Debugf("Service name To resolve: %v", name)
// There are DNS implementaions that allow SRV queries for names not in
// There are DNS implementations that allow SRV queries for names not in
// the format defined by RFC 2782. Hence specific validations checks are
// not done
parts := strings.Split(name, ".")
@ -2126,7 +2126,7 @@ func (n *network) lbEndpointName() string {
func (n *network) createLoadBalancerSandbox() (retErr error) {
sandboxName := n.lbSandboxName()
// Mark the sandbox to be a load balancer
sbOptions := []SandboxOption{OptionLoadBalancer()}
sbOptions := []SandboxOption{OptionLoadBalancer(n.id)}
if n.ingress {
sbOptions = append(sbOptions, OptionIngress())
}

View File

@ -243,7 +243,7 @@ func (nDB *NetworkDB) clusterLeave() error {
}
func (nDB *NetworkDB) triggerFunc(stagger time.Duration, C <-chan time.Time, f func()) {
// Use a random stagger to avoid syncronizing
// Use a random stagger to avoid synchronizing
randStagger := time.Duration(uint64(rnd.Int63()) % uint64(stagger))
select {
case <-time.After(randStagger):

View File

@ -58,7 +58,7 @@ type NetworkDB struct {
// List of all peer nodes which have left
leftNodes map[string]*node
// A multi-dimensional map of network/node attachmemts. The
// A multi-dimensional map of network/node attachments. The
// first key is a node name and the second key is a network ID
// for the network that node is participating in.
networks map[string]map[string]*network
@ -153,7 +153,7 @@ type network struct {
entriesNumber int
}
// Config represents the configuration of the networdb instance and
// Config represents the configuration of the networkdb instance and
// can be passed by the caller.
type Config struct {
// NodeID is the node unique identifier of the node when is part of the cluster

View File

@ -48,7 +48,7 @@ type MessageType int32
const (
MessageTypeInvalid MessageType = 0
// NetworEvent message type is used to communicate network
// NetworkEvent message type is used to communicate network
// attachments on the node.
MessageTypeNetworkEvent MessageType = 1
// TableEvent message type is used to communicate any table
@ -66,7 +66,7 @@ const (
// which is a pack of many message of above types, packed into
// a single compound message.
MessageTypeCompound MessageType = 5
// NodeEvent message type is used to communicare node
// NodeEvent message type is used to communicate node
// join/leave events in the cluster
MessageTypeNodeEvent MessageType = 6
)

View File

@ -19,7 +19,7 @@ enum MessageType {
INVALID = 0 [(gogoproto.enumvalue_customname) = "MessageTypeInvalid"];
// NetworEvent message type is used to communicate network
// NetworkEvent message type is used to communicate network
// attachments on the node.
NETWORK_EVENT = 1 [(gogoproto.enumvalue_customname) = "MessageTypeNetworkEvent"];
@ -42,7 +42,7 @@ enum MessageType {
// a single compound message.
COMPOUND = 5 [(gogoproto.enumvalue_customname) = "MessageTypeCompound"];
// NodeEvent message type is used to communicare node
// NodeEvent message type is used to communicate node
// join/leave events in the cluster
NODE_EVENT = 6 [(gogoproto.enumvalue_customname) = "MessageTypeNodeEvent"];
}

View File

@ -6,8 +6,8 @@ import (
"net/http"
"strings"
"github.com/docker/libnetwork/common"
"github.com/docker/libnetwork/diagnostic"
"github.com/docker/libnetwork/internal/caller"
"github.com/sirupsen/logrus"
)
@ -37,7 +37,7 @@ func dbJoin(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("join cluster")
if len(r.Form["members"]) < 1 {
@ -70,7 +70,7 @@ func dbPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("network peers")
if len(r.Form["nid"]) < 1 {
@ -104,7 +104,7 @@ func dbClusterPeers(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("cluster peers")
nDB, ok := ctx.(*NetworkDB)
@ -127,7 +127,7 @@ func dbCreateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
unsafe, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("create entry")
if len(r.Form["tname"]) < 1 ||
@ -176,7 +176,7 @@ func dbUpdateEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
unsafe, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("update entry")
if len(r.Form["tname"]) < 1 ||
@ -224,7 +224,7 @@ func dbDeleteEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("delete entry")
if len(r.Form["tname"]) < 1 ||
@ -261,7 +261,7 @@ func dbGetEntry(ctx interface{}, w http.ResponseWriter, r *http.Request) {
unsafe, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("get entry")
if len(r.Form["tname"]) < 1 ||
@ -307,7 +307,7 @@ func dbJoinNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("join network")
if len(r.Form["nid"]) < 1 {
@ -339,7 +339,7 @@ func dbLeaveNetwork(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("leave network")
if len(r.Form["nid"]) < 1 {
@ -371,7 +371,7 @@ func dbGetTable(ctx interface{}, w http.ResponseWriter, r *http.Request) {
unsafe, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("get table")
if len(r.Form["tname"]) < 1 ||
@ -419,7 +419,7 @@ func dbNetworkStats(ctx interface{}, w http.ResponseWriter, r *http.Request) {
_, json := diagnostic.ParseHTTPFormOptions(r)
// audit logs
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": common.CallerName(0), "url": r.URL.String()})
log := logrus.WithFields(logrus.Fields{"component": "diagnostic", "remoteIP": r.RemoteAddr, "method": caller.Name(0), "url": r.URL.String()})
log.Info("network stats")
if len(r.Form["nid"]) < 1 {

View File

@ -289,6 +289,16 @@ func (n *networkNamespace) AddInterface(srcName, dstPrefix string, options ...If
// Configure the interface now this is moved in the proper namespace.
if err := configureInterface(nlh, iface, i); err != nil {
// If configuring the device fails move it back to the host namespace
// and change the name back to the source name. This allows the caller
// to properly cleanup the interface. Its important especially for
// interfaces with global attributes, ex: vni id for vxlan interfaces.
if nerr := nlh.LinkSetName(iface, i.SrcName()); nerr != nil {
logrus.Errorf("renaming interface (%s->%s) failed, %v after config error %v", i.DstName(), i.SrcName(), nerr, err)
}
if nerr := nlh.LinkSetNsFd(iface, ns.ParseHandlerInt()); nerr != nil {
logrus.Errorf("moving inteface %s to host ns failed, %v, after config error %v", i.SrcName(), nerr, err)
}
return err
}

View File

@ -2,7 +2,7 @@ package kernel
type conditionalCheck func(val1, val2 string) bool
// OSValue represents a tuple, value defired, check function when to apply the value
// OSValue represents a tuple, value defined, check function when to apply the value
type OSValue struct {
Value string
CheckFn conditionalCheck

View File

@ -14,6 +14,11 @@ import (
"github.com/sirupsen/logrus"
)
const (
// DefaultResolvConf points to the default file used for dns configuration on a linux machine
DefaultResolvConf = "/etc/resolv.conf"
)
var (
// Note: the default IPv4 & IPv6 resolvers are set to Google's Public DNS
defaultIPv4Dns = []string{"nameserver 8.8.8.8", "nameserver 8.8.4.4"}
@ -50,15 +55,7 @@ type File struct {
// Get returns the contents of /etc/resolv.conf and its hash
func Get() (*File, error) {
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
return nil, err
}
hash, err := ioutils.HashData(bytes.NewReader(resolv))
if err != nil {
return nil, err
}
return &File{Content: resolv, Hash: hash}, nil
return GetSpecific(DefaultResolvConf)
}
// GetSpecific returns the contents of the user specified resolv.conf file and its hash

View File

@ -35,7 +35,7 @@ type Resolver interface {
}
// DNSBackend represents a backend DNS resolver used for DNS name
// resolution. All the queries to the resolver are forwared to the
// resolution. All the queries to the resolver are forwarded to the
// backend resolver.
type DNSBackend interface {
// ResolveName resolves a service name to an IPv4 or IPv6 address by searching

View File

@ -84,6 +84,7 @@ type sandbox struct {
ingress bool
ndotsSet bool
oslTypes []osl.SandboxType // slice of properties of this sandbox
loadBalancerNID string // NID that this SB is a load balancer for
sync.Mutex
// This mutex is used to serialize service related operation for an endpoint
// The lock is here because the endpoint is saved into the store so is not unique
@ -467,7 +468,7 @@ func (sb *sandbox) ResolveService(name string) ([]*net.SRV, []net.IP) {
logrus.Debugf("Service name To resolve: %v", name)
// There are DNS implementaions that allow SRV queries for names not in
// There are DNS implementations that allow SRV queries for names not in
// the format defined by RFC 2782. Hence specific validations checks are
// not done
parts := strings.Split(name, ".")
@ -1098,8 +1099,8 @@ func OptionDNSOptions(options string) SandboxOption {
}
}
// OptionUseDefaultSandbox function returns an option setter for using default sandbox to
// be passed to container Create method.
// OptionUseDefaultSandbox function returns an option setter for using default sandbox
// (host namespace) to be passed to container Create method.
func OptionUseDefaultSandbox() SandboxOption {
return func(sb *sandbox) {
sb.config.useDefaultSandBox = true
@ -1169,8 +1170,9 @@ func OptionIngress() SandboxOption {
// OptionLoadBalancer function returns an option setter for marking a
// sandbox as a load balancer sandbox.
func OptionLoadBalancer() SandboxOption {
func OptionLoadBalancer(nid string) SandboxOption {
return func(sb *sandbox) {
sb.loadBalancerNID = nid
sb.oslTypes = append(sb.oslTypes, osl.SandboxTypeLoadBalancer)
}
}

View File

@ -81,7 +81,9 @@ func (sb *sandbox) buildHostsFile() error {
}
// This is for the host mode networking
if sb.config.originHostsPath != "" {
if sb.config.useDefaultSandBox && len(sb.config.extraHosts) == 0 {
// We are working under the assumption that the origin file option had been properly expressed by the upper layer
// if not here we are going to error out
if err := copyFile(sb.config.originHostsPath, sb.config.hostsPath); err != nil && !os.IsNotExist(err) {
return types.InternalErrorf("could not copy source hosts file %s to %s: %v", sb.config.originHostsPath, sb.config.hostsPath, err)
}
@ -190,8 +192,13 @@ func (sb *sandbox) setupDNS() error {
return err
}
// This is for the host mode networking
if sb.config.originResolvConfPath != "" {
// When the user specify a conainter in the host namespace and do no have any dns option specified
// we just copy the host resolv.conf from the host itself
if sb.config.useDefaultSandBox &&
len(sb.config.dnsList) == 0 && len(sb.config.dnsSearchList) == 0 && len(sb.config.dnsOptionsList) == 0 {
// We are working under the assumption that the origin file option had been properly expressed by the upper layer
// if not here we are going to error out
if err := copyFile(sb.config.originResolvConfPath, sb.config.resolvConfPath); err != nil {
if !os.IsNotExist(err) {
return fmt.Errorf("could not copy source resolv.conf file %s to %s: %v", sb.config.originResolvConfPath, sb.config.resolvConfPath, err)
@ -204,7 +211,12 @@ func (sb *sandbox) setupDNS() error {
return nil
}
currRC, err := resolvconf.Get()
originResolvConfPath := sb.config.originResolvConfPath
if originResolvConfPath == "" {
// if not specified fallback to default /etc/resolv.conf
originResolvConfPath = resolvconf.DefaultResolvConf
}
currRC, err := resolvconf.GetSpecific(originResolvConfPath)
if err != nil {
if !os.IsNotExist(err) {
return err
@ -241,7 +253,7 @@ func (sb *sandbox) setupDNS() error {
sb.setExternalResolvers(newRC.Content, types.IPv4, false)
} else {
// If the host resolv.conf file has 127.0.0.x container should
// use the host restolver for queries. This is supported by the
// use the host resolver for queries. This is supported by the
// docker embedded DNS server. Hence save the external resolvers
// before filtering it out.
sb.setExternalResolvers(currRC.Content, types.IPv4, true)
@ -271,7 +283,7 @@ func (sb *sandbox) updateDNS(ipv6Enabled bool) error {
)
// This is for the host mode networking
if sb.config.originResolvConfPath != "" {
if sb.config.useDefaultSandBox {
return nil
}

View File

@ -5,7 +5,7 @@ import (
"net"
"sync"
"github.com/docker/libnetwork/common"
"github.com/docker/libnetwork/internal/setmatrix"
)
var (
@ -54,7 +54,7 @@ type service struct {
// associated with it. At stable state the endpoint ID expected is 1
// but during transition and service change it is possible to have
// temporary more than 1
ipToEndpoint common.SetMatrix
ipToEndpoint setmatrix.SetMatrix
deleted bool

View File

@ -5,7 +5,7 @@ package libnetwork
import (
"net"
"github.com/docker/libnetwork/common"
"github.com/docker/libnetwork/internal/setmatrix"
"github.com/sirupsen/logrus"
)
@ -139,7 +139,7 @@ func newService(name string, id string, ingressPorts []*PortConfig, serviceAlias
ingressPorts: ingressPorts,
loadBalancers: make(map[string]*loadBalancer),
aliases: serviceAliases,
ipToEndpoint: common.NewSetMatrix(),
ipToEndpoint: setmatrix.NewSetMatrix(),
}
}

View File

@ -27,7 +27,7 @@ import (
func init() {
reexec.Register("fwmarker", fwMarker)
reexec.Register("redirecter", redirecter)
reexec.Register("redirector", redirector)
}
// Populate all loadbalancers on the network that the passed endpoint
@ -431,7 +431,7 @@ func programIngress(gwIP net.IP, ingressPorts []*PortConfig, isDelete bool) erro
// DOCKER-USER so the user is able to filter packet first.
// The second rule should be jump to INGRESS-CHAIN.
// This chain has the rules to allow access to the published ports for swarm tasks
// from local bridge networks and docker_gwbridge (ie:taks on other swarm netwroks)
// from local bridge networks and docker_gwbridge (ie:taks on other swarm networks)
func arrangeIngressFilterRule() {
if iptables.ExistChain(ingressChain, iptables.Filter) {
if iptables.Exists(iptables.Filter, "FORWARD", "-j", ingressChain) {
@ -668,7 +668,7 @@ func addRedirectRules(path string, eIP *net.IPNet, ingressPorts []*PortConfig) e
cmd := &exec.Cmd{
Path: reexec.Self(),
Args: append([]string{"redirecter"}, path, eIP.String(), ingressPortsFile),
Args: append([]string{"redirector"}, path, eIP.String(), ingressPortsFile),
Stdout: os.Stdout,
Stderr: os.Stderr,
}
@ -680,8 +680,8 @@ func addRedirectRules(path string, eIP *net.IPNet, ingressPorts []*PortConfig) e
return nil
}
// Redirecter reexec function.
func redirecter() {
// Redirector reexec function.
func redirector() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()

View File

@ -36,7 +36,7 @@ func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
return c, nil
}
// Purge is used to completely clear the cache
// Purge is used to completely clear the cache.
func (c *LRU) Purge() {
for k, v := range c.items {
if c.onEvict != nil {
@ -47,8 +47,8 @@ func (c *LRU) Purge() {
c.evictList.Init()
}
// Add adds a value to the cache. Returns true if an eviction occured.
func (c *LRU) Add(key, value interface{}) bool {
// Add adds a value to the cache. Returns true if an eviction occurred.
func (c *LRU) Add(key, value interface{}) (evicted bool) {
// Check for existing item
if ent, ok := c.items[key]; ok {
c.evictList.MoveToFront(ent)
@ -78,17 +78,18 @@ func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
return
}
// Check if a key is in the cache, without updating the recent-ness
// Contains checks if a key is in the cache, without updating the recent-ness
// or deleting it for being stale.
func (c *LRU) Contains(key interface{}) (ok bool) {
_, ok = c.items[key]
return ok
}
// Returns the key value (or undefined if not found) without updating
// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
if ent, ok := c.items[key]; ok {
var ent *list.Element
if ent, ok = c.items[key]; ok {
return ent.Value.(*entry).value, true
}
return nil, ok
@ -96,7 +97,7 @@ func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
// Remove removes the provided key from the cache, returning if the
// key was contained.
func (c *LRU) Remove(key interface{}) bool {
func (c *LRU) Remove(key interface{}) (present bool) {
if ent, ok := c.items[key]; ok {
c.removeElement(ent)
return true
@ -105,7 +106,7 @@ func (c *LRU) Remove(key interface{}) bool {
}
// RemoveOldest removes the oldest item from the cache.
func (c *LRU) RemoveOldest() (interface{}, interface{}, bool) {
func (c *LRU) RemoveOldest() (key interface{}, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
c.removeElement(ent)
@ -116,7 +117,7 @@ func (c *LRU) RemoveOldest() (interface{}, interface{}, bool) {
}
// GetOldest returns the oldest entry
func (c *LRU) GetOldest() (interface{}, interface{}, bool) {
func (c *LRU) GetOldest() (key interface{}, value interface{}, ok bool) {
ent := c.evictList.Back()
if ent != nil {
kv := ent.Value.(*entry)

View File

@ -0,0 +1,37 @@
package simplelru
// LRUCache is the interface for simple LRU cache.
type LRUCache interface {
// Adds a value to the cache, returns true if an eviction occurred and
// updates the "recently used"-ness of the key.
Add(key, value interface{}) bool
// Returns key's value from the cache and
// updates the "recently used"-ness of the key. #value, isFound
Get(key interface{}) (value interface{}, ok bool)
// Check if a key exsists in cache without updating the recent-ness.
Contains(key interface{}) (ok bool)
// Returns key's value without updating the "recently used"-ness of the key.
Peek(key interface{}) (value interface{}, ok bool)
// Removes a key from the cache.
Remove(key interface{}) bool
// Removes the oldest entry from cache.
RemoveOldest() (interface{}, interface{}, bool)
// Returns the oldest entry from the cache. #key, value, isFound
GetOldest() (interface{}, interface{}, bool)
// Returns a slice of the keys in the cache, from oldest to newest.
Keys() []interface{}
// Returns the number of items in the cache.
Len() int
// Clear all cache entries
Purge()
}

View File

@ -27,7 +27,7 @@ It is ready for production use. [It is used in several projects by Docker, Googl
### Latest release
[Release v0.3.4](https://github.com/imdario/mergo/releases/tag/v0.3.4).
[Release v0.3.6](https://github.com/imdario/mergo/releases/tag/v0.3.6).
### Important note

View File

@ -9,6 +9,7 @@
package mergo
import (
"fmt"
"reflect"
)
@ -127,6 +128,9 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
dstSlice = srcSlice
} else if config.AppendSlice {
if srcSlice.Type() != dstSlice.Type() {
return fmt.Errorf("cannot append two slice with different type (%s, %s)", srcSlice.Type(), dstSlice.Type())
}
dstSlice = reflect.AppendSlice(dstSlice, srcSlice)
}
dst.SetMapIndex(key, dstSlice)
@ -150,6 +154,9 @@ func deepMerge(dst, src reflect.Value, visited map[uintptr]*visit, depth int, co
if !isEmptyValue(src) && (overwrite || isEmptyValue(dst)) && !config.AppendSlice {
dst.Set(src)
} else if config.AppendSlice {
if src.Type() != dst.Type() {
return fmt.Errorf("cannot append two slice with different type (%s, %s)", src.Type(), dst.Type())
}
dst.Set(reflect.AppendSlice(dst, src))
}
case reflect.Ptr:

View File

@ -220,7 +220,7 @@ Logrus comes with [built-in hooks](hooks/). Add those, or your custom hook, in
```go
import (
log "github.com/sirupsen/logrus"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "aibrake"
"gopkg.in/gemnasium/logrus-airbrake-hook.v2" // the package is named "airbrake"
logrus_syslog "github.com/sirupsen/logrus/hooks/syslog"
"log/syslog"
)
@ -241,54 +241,8 @@ func init() {
```
Note: Syslog hook also support connecting to local syslog (Ex. "/dev/log" or "/var/run/syslog" or "/var/run/log"). For the detail, please check the [syslog hook README](hooks/syslog/README.md).
| Hook | Description |
| ----- | ----------- |
| [Airbrake "legacy"](https://github.com/gemnasium/logrus-airbrake-legacy-hook) | Send errors to an exception tracking service compatible with the Airbrake API V2. Uses [`airbrake-go`](https://github.com/tobi/airbrake-go) behind the scenes. |
| [Airbrake](https://github.com/gemnasium/logrus-airbrake-hook) | Send errors to the Airbrake API V3. Uses the official [`gobrake`](https://github.com/airbrake/gobrake) behind the scenes. |
| [Amazon Kinesis](https://github.com/evalphobia/logrus_kinesis) | Hook for logging to [Amazon Kinesis](https://aws.amazon.com/kinesis/) |
| [Amqp-Hook](https://github.com/vladoatanasov/logrus_amqp) | Hook for logging to Amqp broker (Like RabbitMQ) |
| [Bugsnag](https://github.com/Shopify/logrus-bugsnag/blob/master/bugsnag.go) | Send errors to the Bugsnag exception tracking service. |
| [DeferPanic](https://github.com/deferpanic/dp-logrus) | Hook for logging to DeferPanic |
| [Discordrus](https://github.com/kz/discordrus) | Hook for logging to [Discord](https://discordapp.com/) |
| [ElasticSearch](https://github.com/sohlich/elogrus) | Hook for logging to ElasticSearch|
| [Firehose](https://github.com/beaubrewer/logrus_firehose) | Hook for logging to [Amazon Firehose](https://aws.amazon.com/kinesis/firehose/)
| [Fluentd](https://github.com/evalphobia/logrus_fluent) | Hook for logging to fluentd |
| [Go-Slack](https://github.com/multiplay/go-slack) | Hook for logging to [Slack](https://slack.com) |
| [Graylog](https://github.com/gemnasium/logrus-graylog-hook) | Hook for logging to [Graylog](http://graylog2.org/) |
| [Hiprus](https://github.com/nubo/hiprus) | Send errors to a channel in hipchat. |
| [Honeybadger](https://github.com/agonzalezro/logrus_honeybadger) | Hook for sending exceptions to Honeybadger |
| [InfluxDB](https://github.com/Abramovic/logrus_influxdb) | Hook for logging to influxdb |
| [Influxus](http://github.com/vlad-doru/influxus) | Hook for concurrently logging to [InfluxDB](http://influxdata.com/) |
| [Journalhook](https://github.com/wercker/journalhook) | Hook for logging to `systemd-journald` |
| [KafkaLogrus](https://github.com/goibibo/KafkaLogrus) | Hook for logging to kafka |
| [LFShook](https://github.com/rifflock/lfshook) | Hook for logging to the local filesystem |
| [Logentries](https://github.com/jcftang/logentriesrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logentrus](https://github.com/puddingfactory/logentrus) | Hook for logging to [Logentries](https://logentries.com/) |
| [Logmatic.io](https://github.com/logmatic/logmatic-go) | Hook for logging to [Logmatic.io](http://logmatic.io/) |
| [Logrusly](https://github.com/sebest/logrusly) | Send logs to [Loggly](https://www.loggly.com/) |
| [Logstash](https://github.com/bshuster-repo/logrus-logstash-hook) | Hook for logging to [Logstash](https://www.elastic.co/products/logstash) |
| [Mail](https://github.com/zbindenren/logrus_mail) | Hook for sending exceptions via mail |
| [Mattermost](https://github.com/shuLhan/mattermost-integration/tree/master/hooks/logrus) | Hook for logging to [Mattermost](https://mattermost.com/) |
| [Mongodb](https://github.com/weekface/mgorus) | Hook for logging to mongodb |
| [NATS-Hook](https://github.com/rybit/nats_logrus_hook) | Hook for logging to [NATS](https://nats.io) |
| [Octokit](https://github.com/dorajistyle/logrus-octokit-hook) | Hook for logging to github via octokit |
| [Papertrail](https://github.com/polds/logrus-papertrail-hook) | Send errors to the [Papertrail](https://papertrailapp.com) hosted logging service via UDP. |
| [PostgreSQL](https://github.com/gemnasium/logrus-postgresql-hook) | Send logs to [PostgreSQL](http://postgresql.org) |
| [Pushover](https://github.com/toorop/logrus_pushover) | Send error via [Pushover](https://pushover.net) |
| [Raygun](https://github.com/squirkle/logrus-raygun-hook) | Hook for logging to [Raygun.io](http://raygun.io/) |
| [Redis-Hook](https://github.com/rogierlommers/logrus-redis-hook) | Hook for logging to a ELK stack (through Redis) |
| [Rollrus](https://github.com/heroku/rollrus) | Hook for sending errors to rollbar |
| [Scribe](https://github.com/sagar8192/logrus-scribe-hook) | Hook for logging to [Scribe](https://github.com/facebookarchive/scribe)|
| [Sentry](https://github.com/evalphobia/logrus_sentry) | Send errors to the Sentry error logging and aggregation service. |
| [Slackrus](https://github.com/johntdyer/slackrus) | Hook for Slack chat. |
| [Stackdriver](https://github.com/knq/sdhook) | Hook for logging to [Google Stackdriver](https://cloud.google.com/logging/) |
| [Sumorus](https://github.com/doublefree/sumorus) | Hook for logging to [SumoLogic](https://www.sumologic.com/)|
| [Syslog](https://github.com/sirupsen/logrus/blob/master/hooks/syslog/syslog.go) | Send errors to remote syslog server. Uses standard library `log/syslog` behind the scenes. |
| [Syslog TLS](https://github.com/shinji62/logrus-syslog-ng) | Send errors to remote syslog server with TLS support. |
| [TraceView](https://github.com/evalphobia/logrus_appneta) | Hook for logging to [AppNeta TraceView](https://www.appneta.com/products/traceview/) |
| [Typetalk](https://github.com/dragon3/logrus-typetalk-hook) | Hook for logging to [Typetalk](https://www.typetalk.in/) |
| [logz.io](https://github.com/ripcurld00d/logrus-logzio-hook) | Hook for logging to [logz.io](https://logz.io), a Log as a Service using Logstash |
| [SQS-Hook](https://github.com/tsarpaul/logrus_sqs) | Hook for logging to [Amazon Simple Queue Service (SQS)](https://aws.amazon.com/sqs/) |
A list of currently known of service hook can be found in this wiki [page](https://github.com/sirupsen/logrus/wiki/Hooks)
#### Level logging
@ -366,13 +320,15 @@ The built-in logging formatters are:
field to `true`. To force no colored output even if there is a TTY set the
`DisableColors` field to `true`. For Windows, see
[github.com/mattn/go-colorable](https://github.com/mattn/go-colorable).
* When colors are enabled, levels are truncated to 4 characters by default. To disable
truncation set the `DisableLevelTruncation` field to `true`.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#TextFormatter).
* `logrus.JSONFormatter`. Logs fields as JSON.
* All options are listed in the [generated docs](https://godoc.org/github.com/sirupsen/logrus#JSONFormatter).
Third party logging formatters:
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can by parsed by Kubernetes and Google Container Engine.
* [`FluentdFormatter`](https://github.com/joonix/log). Formats entries that can be parsed by Kubernetes and Google Container Engine.
* [`logstash`](https://github.com/bshuster-repo/logrus-logstash-hook). Logs fields as [Logstash](http://logstash.net) Events.
* [`prefixed`](https://github.com/x-cray/logrus-prefixed-formatter). Displays log entry source along with alternative layout.
* [`zalgo`](https://github.com/aybabtme/logzalgo). Invoking the P͉̫o̳̼̊w̖͈̰͎e̬͔̭͂r͚̼̹̲ ̫͓͉̳͈ō̠͕͖̚f̝͍̠ ͕̲̞͖͑Z̖̫̤̫ͪa͉̬͈̗l͖͎g̳̥o̰̥̅!̣͔̲̻͊̄ ̙̘̦̹̦.
@ -489,7 +445,7 @@ logrus.RegisterExitHandler(handler)
#### Thread safety
By default Logger is protected by mutex for concurrent writes, this mutex is invoked when calling hooks and writing logs.
By default, Logger is protected by a mutex for concurrent writes. The mutex is held when calling hooks and writing logs.
If you are sure such locking is not needed, you can call logger.SetNoLock() to disable the locking.
Situation when locking is not needed includes:

View File

@ -48,7 +48,7 @@ type Entry struct {
func NewEntry(logger *Logger) *Entry {
return &Entry{
Logger: logger,
// Default is three fields, give a little extra room
// Default is five fields, give a little extra room
Data: make(Fields, 5),
}
}
@ -83,40 +83,41 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
for k, v := range fields {
data[k] = v
}
return &Entry{Logger: entry.Logger, Data: data}
return &Entry{Logger: entry.Logger, Data: data, Time: entry.Time}
}
// Overrides the time of the Entry.
func (entry *Entry) WithTime(t time.Time) *Entry {
return &Entry{Logger: entry.Logger, Data: entry.Data, Time: t}
}
// This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) {
var buffer *bytes.Buffer
entry.Time = time.Now()
// Default to now, but allow users to override if they want.
//
// We don't have to worry about polluting future calls to Entry#log()
// with this assignment because this function is declared with a
// non-pointer receiver.
if entry.Time.IsZero() {
entry.Time = time.Now()
}
entry.Level = level
entry.Message = msg
if err := entry.Logger.Hooks.Fire(level, &entry); err != nil {
entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
entry.Logger.mu.Unlock()
}
entry.fireHooks()
buffer = bufferPool.Get().(*bytes.Buffer)
buffer.Reset()
defer bufferPool.Put(buffer)
entry.Buffer = buffer
serialized, err := entry.Logger.Formatter.Format(&entry)
entry.write()
entry.Buffer = nil
if err != nil {
entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
entry.Logger.mu.Unlock()
} else {
entry.Logger.mu.Lock()
_, err = entry.Logger.Out.Write(serialized)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
entry.Logger.mu.Unlock()
}
// To avoid Entry#log() returning a value that only would make sense for
// panic() to use in Entry#Panic(), we avoid the allocation by checking
@ -126,6 +127,29 @@ func (entry Entry) log(level Level, msg string) {
}
}
func (entry *Entry) fireHooks() {
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
err := entry.Logger.Hooks.Fire(entry.Level, entry)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
}
}
func (entry *Entry) write() {
serialized, err := entry.Logger.Formatter.Format(entry)
entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
} else {
_, err = entry.Logger.Out.Write(serialized)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
}
}
}
func (entry *Entry) Debug(args ...interface{}) {
if entry.Logger.level() >= DebugLevel {
entry.log(DebugLevel, fmt.Sprint(args...))

View File

@ -2,6 +2,7 @@ package logrus
import (
"io"
"time"
)
var (
@ -15,9 +16,7 @@ func StandardLogger() *Logger {
// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
std.mu.Lock()
defer std.mu.Unlock()
std.Out = out
std.SetOutput(out)
}
// SetFormatter sets the standard logger formatter.
@ -72,6 +71,15 @@ func WithFields(fields Fields) *Entry {
return std.WithFields(fields)
}
// WithTime creats an entry from the standard logger and overrides the time of
// logs generated with it.
//
// Note that it doesn't log until you call Debug, Print, Info, Warn, Fatal
// or Panic on the Entry it returns.
func WithTime(t time.Time) *Entry {
return std.WithTime(t)
}
// Debug logs a message at level Debug on the standard logger.
func Debug(args ...interface{}) {
std.Debug(args...)
@ -107,7 +115,7 @@ func Panic(args ...interface{}) {
std.Panic(args...)
}
// Fatal logs a message at level Fatal on the standard logger.
// Fatal logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatal(args ...interface{}) {
std.Fatal(args...)
}
@ -147,7 +155,7 @@ func Panicf(format string, args ...interface{}) {
std.Panicf(format, args...)
}
// Fatalf logs a message at level Fatal on the standard logger.
// Fatalf logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatalf(format string, args ...interface{}) {
std.Fatalf(format, args...)
}
@ -187,7 +195,7 @@ func Panicln(args ...interface{}) {
std.Panicln(args...)
}
// Fatalln logs a message at level Fatal on the standard logger.
// Fatalln logs a message at level Fatal on the standard logger then the process will exit with status set to 1.
func Fatalln(args ...interface{}) {
std.Fatalln(args...)
}

View File

@ -30,16 +30,22 @@ type Formatter interface {
//
// It's not exported because it's still using Data in an opinionated way. It's to
// avoid code duplication between the two default formatters.
func prefixFieldClashes(data Fields) {
if t, ok := data["time"]; ok {
data["fields.time"] = t
func prefixFieldClashes(data Fields, fieldMap FieldMap) {
timeKey := fieldMap.resolve(FieldKeyTime)
if t, ok := data[timeKey]; ok {
data["fields."+timeKey] = t
delete(data, timeKey)
}
if m, ok := data["msg"]; ok {
data["fields.msg"] = m
msgKey := fieldMap.resolve(FieldKeyMsg)
if m, ok := data[msgKey]; ok {
data["fields."+msgKey] = m
delete(data, msgKey)
}
if l, ok := data["level"]; ok {
data["fields.level"] = l
levelKey := fieldMap.resolve(FieldKeyLevel)
if l, ok := data[levelKey]; ok {
data["fields."+levelKey] = l
delete(data, levelKey)
}
}

View File

@ -33,6 +33,9 @@ type JSONFormatter struct {
// DisableTimestamp allows disabling automatic timestamps in output
DisableTimestamp bool
// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.
DataKey string
// FieldMap allows users to customize the names of keys for default fields.
// As an example:
// formatter := &JSONFormatter{
@ -58,7 +61,14 @@ func (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {
data[k] = v
}
}
prefixFieldClashes(data)
if f.DataKey != "" {
newData := make(Fields, 4)
newData[f.DataKey] = data
data = newData
}
prefixFieldClashes(data, f.FieldMap)
timestampFormat := f.TimestampFormat
if timestampFormat == "" {

View File

@ -5,6 +5,7 @@ import (
"os"
"sync"
"sync/atomic"
"time"
)
type Logger struct {
@ -88,7 +89,7 @@ func (logger *Logger) releaseEntry(entry *Entry) {
}
// Adds a field to the log entry, note that it doesn't log until you call
// Debug, Print, Info, Warn, Fatal or Panic. It only creates a log entry.
// Debug, Print, Info, Warn, Error, Fatal or Panic. It only creates a log entry.
// If you want multiple fields, use `WithFields`.
func (logger *Logger) WithField(key string, value interface{}) *Entry {
entry := logger.newEntry()
@ -112,6 +113,13 @@ func (logger *Logger) WithError(err error) *Entry {
return entry.WithError(err)
}
// Overrides the time of the log entry.
func (logger *Logger) WithTime(t time.Time) *Entry {
entry := logger.newEntry()
defer logger.releaseEntry(entry)
return entry.WithTime(t)
}
func (logger *Logger) Debugf(format string, args ...interface{}) {
if logger.level() >= DebugLevel {
entry := logger.newEntry()
@ -315,3 +323,15 @@ func (logger *Logger) level() Level {
func (logger *Logger) SetLevel(level Level) {
atomic.StoreUint32((*uint32)(&logger.Level), uint32(level))
}
func (logger *Logger) SetOutput(out io.Writer) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Out = out
}
func (logger *Logger) AddHook(hook Hook) {
logger.mu.Lock()
defer logger.mu.Unlock()
logger.Hooks.Add(hook)
}

View File

@ -1,5 +1,5 @@
// +build darwin freebsd openbsd netbsd dragonfly
// +build !appengine
// +build !appengine,!gopherjs
package logrus

View File

@ -0,0 +1,11 @@
// +build appengine gopherjs
package logrus
import (
"io"
)
func checkIfTerminal(w io.Writer) bool {
return true
}

View File

@ -0,0 +1,19 @@
// +build !appengine,!gopherjs
package logrus
import (
"io"
"os"
"golang.org/x/crypto/ssh/terminal"
)
func checkIfTerminal(w io.Writer) bool {
switch v := w.(type) {
case *os.File:
return terminal.IsTerminal(int(v.Fd()))
default:
return false
}
}

View File

@ -3,7 +3,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !appengine
// +build !appengine,!gopherjs
package logrus

View File

@ -3,14 +3,10 @@ package logrus
import (
"bytes"
"fmt"
"io"
"os"
"sort"
"strings"
"sync"
"time"
"golang.org/x/crypto/ssh/terminal"
)
const (
@ -24,6 +20,7 @@ const (
var (
baseTimestamp time.Time
emptyFieldMap FieldMap
)
func init() {
@ -54,33 +51,37 @@ type TextFormatter struct {
// be desired.
DisableSorting bool
// Disables the truncation of the level text to 4 characters.
DisableLevelTruncation bool
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// Whether the logger's out is to a terminal
isTerminal bool
// FieldMap allows users to customize the names of keys for default fields.
// As an example:
// formatter := &TextFormatter{
// FieldMap: FieldMap{
// FieldKeyTime: "@timestamp",
// FieldKeyLevel: "@level",
// FieldKeyMsg: "@message"}}
FieldMap FieldMap
sync.Once
}
func (f *TextFormatter) init(entry *Entry) {
if entry.Logger != nil {
f.isTerminal = f.checkIfTerminal(entry.Logger.Out)
}
}
func (f *TextFormatter) checkIfTerminal(w io.Writer) bool {
switch v := w.(type) {
case *os.File:
return terminal.IsTerminal(int(v.Fd()))
default:
return false
f.isTerminal = checkIfTerminal(entry.Logger.Out)
}
}
// Format renders a single log entry
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer
prefixFieldClashes(entry.Data, f.FieldMap)
keys := make([]string, 0, len(entry.Data))
for k := range entry.Data {
keys = append(keys, k)
@ -89,14 +90,14 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
if !f.DisableSorting {
sort.Strings(keys)
}
var b *bytes.Buffer
if entry.Buffer != nil {
b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
prefixFieldClashes(entry.Data)
f.Do(func() { f.init(entry) })
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
@ -109,11 +110,11 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
f.printColored(b, entry, keys, timestampFormat)
} else {
if !f.DisableTimestamp {
f.appendKeyValue(b, "time", entry.Time.Format(timestampFormat))
f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyTime), entry.Time.Format(timestampFormat))
}
f.appendKeyValue(b, "level", entry.Level.String())
f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyLevel), entry.Level.String())
if entry.Message != "" {
f.appendKeyValue(b, "msg", entry.Message)
f.appendKeyValue(b, f.FieldMap.resolve(FieldKeyMsg), entry.Message)
}
for _, key := range keys {
f.appendKeyValue(b, key, entry.Data[key])
@ -137,7 +138,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
levelColor = blue
}
levelText := strings.ToUpper(entry.Level.String())[0:4]
levelText := strings.ToUpper(entry.Level.String())
if !f.DisableLevelTruncation {
levelText = levelText[0:4]
}
if f.DisableTimestamp {
fmt.Fprintf(b, "\x1b[%dm%s\x1b[0m %-44s ", levelColor, levelText, entry.Message)

View File

@ -6,7 +6,10 @@
// https://ed25519.cr.yp.to/.
//
// These functions are also compatible with the “Ed25519” function defined in
// RFC 8032.
// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
// representation includes a public key suffix to make multiple signing
// operations with the same key more efficient. This package refers to the RFC
// 8032 private key as the “seed”.
package ed25519
// This code is a port of the public domain, “ref10” implementation of ed25519
@ -31,6 +34,8 @@ const (
PrivateKeySize = 64
// SignatureSize is the size, in bytes, of signatures generated and verified by this package.
SignatureSize = 64
// SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
SeedSize = 32
)
// PublicKey is the type of Ed25519 public keys.
@ -46,6 +51,15 @@ func (priv PrivateKey) Public() crypto.PublicKey {
return PublicKey(publicKey)
}
// Seed returns the private key seed corresponding to priv. It is provided for
// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
// in this package.
func (priv PrivateKey) Seed() []byte {
seed := make([]byte, SeedSize)
copy(seed, priv[:32])
return seed
}
// Sign signs the given message with priv.
// Ed25519 performs two passes over messages to be signed and therefore cannot
// handle pre-hashed messages. Thus opts.HashFunc() must return zero to
@ -61,19 +75,33 @@ func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOp
// GenerateKey generates a public/private key pair using entropy from rand.
// If rand is nil, crypto/rand.Reader will be used.
func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, err error) {
func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
if rand == nil {
rand = cryptorand.Reader
}
privateKey = make([]byte, PrivateKeySize)
publicKey = make([]byte, PublicKeySize)
_, err = io.ReadFull(rand, privateKey[:32])
if err != nil {
seed := make([]byte, SeedSize)
if _, err := io.ReadFull(rand, seed); err != nil {
return nil, nil, err
}
digest := sha512.Sum512(privateKey[:32])
privateKey := NewKeyFromSeed(seed)
publicKey := make([]byte, PublicKeySize)
copy(publicKey, privateKey[32:])
return publicKey, privateKey, nil
}
// NewKeyFromSeed calculates a private key from a seed. It will panic if
// len(seed) is not SeedSize. This function is provided for interoperability
// with RFC 8032. RFC 8032's private keys correspond to seeds in this
// package.
func NewKeyFromSeed(seed []byte) PrivateKey {
if l := len(seed); l != SeedSize {
panic("ed25519: bad seed length: " + strconv.Itoa(l))
}
digest := sha512.Sum512(seed)
digest[0] &= 248
digest[31] &= 127
digest[31] |= 64
@ -85,10 +113,11 @@ func GenerateKey(rand io.Reader) (publicKey PublicKey, privateKey PrivateKey, er
var publicKeyBytes [32]byte
A.ToBytes(&publicKeyBytes)
privateKey := make([]byte, PrivateKeySize)
copy(privateKey, seed)
copy(privateKey[32:], publicKeyBytes[:])
copy(publicKey, publicKeyBytes[:])
return publicKey, privateKey, nil
return privateKey
}
// Sign signs the message with privateKey and returns a signature. It will

View File

@ -0,0 +1,32 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !appengine
// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.
package subtle // import "golang.org/x/crypto/internal/subtle"
import "unsafe"
// AnyOverlap reports whether x and y share memory at any (not necessarily
// corresponding) index. The memory beyond the slice length is ignored.
func AnyOverlap(x, y []byte) bool {
return len(x) > 0 && len(y) > 0 &&
uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
}
// InexactOverlap reports whether x and y share memory at any non-corresponding
// index. The memory beyond the slice length is ignored. Note that x and y can
// have different lengths and still not have any inexact overlap.
//
// InexactOverlap can be used to implement the requirements of the crypto/cipher
// AEAD, Block, BlockMode and Stream interfaces.
func InexactOverlap(x, y []byte) bool {
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
return false
}
return AnyOverlap(x, y)
}

View File

@ -0,0 +1,35 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build appengine
// Package subtle implements functions that are often useful in cryptographic
// code but require careful thought to use correctly.
package subtle // import "golang.org/x/crypto/internal/subtle"
// This is the Google App Engine standard variant based on reflect
// because the unsafe package and cgo are disallowed.
import "reflect"
// AnyOverlap reports whether x and y share memory at any (not necessarily
// corresponding) index. The memory beyond the slice length is ignored.
func AnyOverlap(x, y []byte) bool {
return len(x) > 0 && len(y) > 0 &&
reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() &&
reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer()
}
// InexactOverlap reports whether x and y share memory at any non-corresponding
// index. The memory beyond the slice length is ignored. Note that x and y can
// have different lengths and still not have any inexact overlap.
//
// InexactOverlap can be used to implement the requirements of the crypto/cipher
// AEAD, Block, BlockMode and Stream interfaces.
func InexactOverlap(x, y []byte) bool {
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
return false
}
return AnyOverlap(x, y)
}

Some files were not shown because too many files have changed in this diff Show More